diff --git a/.github/workflows/build_prod_wb-dashboard.yml b/.github/workflows/build_prod_wb-dashboard.yml new file mode 100644 index 00000000..fb2e1a6f --- /dev/null +++ b/.github/workflows/build_prod_wb-dashboard.yml @@ -0,0 +1,32 @@ +name: Build prod WB dashboard + +on: + pull_request: + branches: + - "main" + - "staging" + paths: + - ".github/workflows/build_prod_wb-dashboard.yml" + - "webapps/world-builder-dashboard/**" + +jobs: + build_prod_wb-dashboard: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository and main branch + uses: actions/checkout@v2 + + - name: Set up node.js + uses: actions/setup-node@v3 + with: + node-version: "20.14.0" + + - name: Build frontend + working-directory: ./webapps/world-builder-dashboard + env: + VITE_NB_JSON_RPC_URI: ${{ secrets.VITE_NB_JSON_RPC_URI }} + VITE_NB_WB_DASHBOARD_ACCESS_ID: ${{ secrets.VITE_NB_WB_DASHBOARD_ACCESS_ID }} + run: | + npm install + npm run build diff --git a/.github/workflows/build.yml b/.github/workflows/build_web3.yml similarity index 73% rename from .github/workflows/build.yml rename to .github/workflows/build_web3.yml index 88d91cca..1c567b7a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build_web3.yml @@ -1,15 +1,21 @@ -name: Build +name: Build Smart Contracts on: pull_request: branches: - main + paths: + - '.github/workflows/build_web3.yml' + - 'web3/**' jobs: - build: + build_web3: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: recursive # Ensure submodules are checked out and - name: Install Node.js uses: actions/setup-node@v3 with: @@ -31,4 +37,4 @@ jobs: run: go install github.com/G7DAO/seer@latest - name: Build everything run: | - make \ No newline at end of file + make diff --git a/.github/workflows/deploy_manual_branch_wb-dashboard.yml b/.github/workflows/deploy_manual_branch_wb-dashboard.yml new file mode 100644 index 00000000..db6cbb22 --- /dev/null +++ b/.github/workflows/deploy_manual_branch_wb-dashboard.yml @@ -0,0 +1,53 @@ +name: Manual Deploy branch WB dashboard + +on: + workflow_dispatch: # Allow manual trigger + inputs: + branch: + description: "Branch to deploy" + required: true + default: "staging" + +jobs: + deploy_manual_branch_wb-dashboard: + runs-on: ubuntu-latest + + steps: + - name: Show branch name + run: | + echo "Running manual deployment for ${{ github.event.inputs.branch || github.event.pull_request.head.ref }} branch" + + - name: Checkout repository and main branch + uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.branch || github.event.pull_request.head.ref }} + + - name: Set up node.js + uses: actions/setup-node@v3 + with: + node-version: "20.14.0" + + - name: Install and build staging app + working-directory: ./webapps/world-builder-dashboard + env: + VITE_NB_JSON_RPC_URI: ${{ secrets.VITE_NB_JSON_RPC_URI }} + VITE_NB_WB_DASHBOARD_ACCESS_ID: ${{ secrets.VITE_NB_WB_DASHBOARD_ACCESS_ID }} + VITE_BUILD_TARGET: ${{ github.event.inputs.branch || github.event.pull_request.head.ref }} + run: | + npm install + npm run build + + - name: Update robots.txt, block alpha for crawlers + working-directory: ./webapps/world-builder-dashboard/dist + run: | + sed -i "s/Disallow:.*/Disallow: \//" robots.txt + + - name: Upload static site to S3 bucket and invalidate CloudFront cache + working-directory: ./webapps/world-builder-dashboard + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + run: | + aws s3 sync ./dist ${{ secrets.AWS_FRONTEND_BUCKET_WB_DASHBOARD_BRANCH }}/${{ github.event.inputs.branch || github.event.pull_request.head.ref }} --delete + aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_DISTRIBUTION_ID_WB_DASHBOARD_BRANCH }} --paths '/${{ github.event.inputs.branch || github.event.pull_request.head.ref }}/*' diff --git a/.github/workflows/prod_deploy_protocol-api.yml b/.github/workflows/deploy_prod_protocol-api.yml similarity index 97% rename from .github/workflows/prod_deploy_protocol-api.yml rename to .github/workflows/deploy_prod_protocol-api.yml index 5aea5357..83cbef29 100644 --- a/.github/workflows/prod_deploy_protocol-api.yml +++ b/.github/workflows/deploy_prod_protocol-api.yml @@ -5,11 +5,11 @@ on: branches: - main paths: - - '.github/workflows/prod_deploy_protocol-api.yml' + - '.github/workflows/deploy_prod_protocol-api.yml' - "api/**" jobs: - prod_deploy_protocol-api: + deploy_prod_protocol-api: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/deploy_prod_wb-dashboard.yml b/.github/workflows/deploy_prod_wb-dashboard.yml new file mode 100644 index 00000000..95e71dfa --- /dev/null +++ b/.github/workflows/deploy_prod_wb-dashboard.yml @@ -0,0 +1,42 @@ +name: Deploy prod WB dashboard + +on: + push: + branches: + - main + paths: + - ".github/workflows/deploy_prod_wb-dashboard.yml" + - "webapps/world-builder-dashboard/**" + +jobs: + deploy_prod_wb-dashboard: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository and main branch + uses: actions/checkout@v2 + with: + ref: main + + - name: Set up node.js + uses: actions/setup-node@v3 + with: + node-version: "20.14.0" + + - name: Install and build production app + working-directory: ./webapps/world-builder-dashboard + env: + VITE_NB_JSON_RPC_URI: ${{ secrets.VITE_NB_JSON_RPC_URI }} + VITE_NB_WB_DASHBOARD_ACCESS_ID: ${{ secrets.VITE_NB_WB_DASHBOARD_ACCESS_ID }} + run: | + npm install + npm run build + + - name: Publish to CloudFlare Page + uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CF_API_TOKEN_PROD }} + accountId: ${{ secrets.CF_ACCOUNT_ID_PROD }} + projectName: ${{ secrets.CF_PROJECT_NAME_WB_DASHBOARD_PROD }} + directory: ./webapps/world-builder-dashboard/dist + gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/deploy_staging_wb-dashboard.yml b/.github/workflows/deploy_staging_wb-dashboard.yml new file mode 100644 index 00000000..00ea641a --- /dev/null +++ b/.github/workflows/deploy_staging_wb-dashboard.yml @@ -0,0 +1,48 @@ +name: Deploy staging WB dashboard + +on: + push: + branches: + - staging + paths: + - ".github/workflows/deploy_staging_wb-dashboard.yml" + - "webapps/world-builder-dashboard/**" + +jobs: + deploy_staging_wb-dashboard: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository and main branch + uses: actions/checkout@v2 + with: + ref: staging + + - name: Set up node.js + uses: actions/setup-node@v3 + with: + node-version: "20.14.0" + + - name: Install and build staging app + working-directory: ./webapps/world-builder-dashboard + env: + VITE_NB_JSON_RPC_URI: ${{ secrets.VITE_NB_JSON_RPC_URI }} + VITE_NB_WB_DASHBOARD_ACCESS_ID: ${{ secrets.VITE_NB_WB_DASHBOARD_ACCESS_ID }} + VITE_BUILD_TARGET: staging + run: | + npm install + npm run build + + - name: Update robots.txt, block alpha for crawlers + working-directory: ./webapps/world-builder-dashboard/dist + run: | + sed -i "s/Disallow:.*/Disallow: \//" robots.txt + + - name: Publish to CloudFlare Page + uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CF_API_TOKEN_STAGE }} + accountId: ${{ secrets.CF_ACCOUNT_ID_STAGE }} + projectName: ${{ secrets.CF_PROJECT_NAME_WB_DASHBOARD_STAGE }} + directory: ./webapps/world-builder-dashboard/dist + gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/prod_build_wb-dashboard.yml b/.github/workflows/prod_build_wb-dashboard.yml deleted file mode 100644 index 1b484678..00000000 --- a/.github/workflows/prod_build_wb-dashboard.yml +++ /dev/null @@ -1,26 +0,0 @@ -on: - pull_request: - branches: - - "main" - paths: - - '.github/workflows/prod_build_wb-dashboard.yml' - - 'webapps/world-builder-dashboard/**' - -jobs: - prod_build_wb-dashboard: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository and main branch - uses: actions/checkout@v2 - - - name: Set up node.js - uses: actions/setup-node@v3 - with: - node-version: "20.14.0" - - - name: Build frontend - working-directory: ./webapps/world-builder-dashboard - run: | - npm install - npm run build \ No newline at end of file diff --git a/.github/workflows/prod_deploy_wb-dashboard.yml b/.github/workflows/prod_deploy_wb-dashboard.yml deleted file mode 100644 index cfe4e1e6..00000000 --- a/.github/workflows/prod_deploy_wb-dashboard.yml +++ /dev/null @@ -1,37 +0,0 @@ -on: - push: - branches: - - main - paths: - - '.github/workflows/prod_deploy_wb-dashboard.yml' - - 'webapps/world-builder-dashboard/**' - -jobs: - prod_deploy_wb-dashboard: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository and main branch - uses: actions/checkout@v2 - with: - ref: main - - - name: Set up node.js - uses: actions/setup-node@v3 - with: - node-version: "20.14.0" - - - name: Install and build production app - working-directory: ./webapps/world-builder-dashboard - run: | - npm install - npm run build - - - name: Publish to CloudFlare Page - uses: cloudflare/pages-action@v1 - with: - apiToken: ${{ secrets.CF_API_TOKEN_PROD }} - accountId: ${{ secrets.CF_ACCOUNT_ID_PROD }} - projectName: ${{ secrets.CF_PROJECT_NAME_WB_DASHBOARD_PROD }} - directory: ./webapps/world-builder-dashboard/dist - gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-game7.yml b/.github/workflows/release-game7.yml index 7a8b902b..bb319362 100644 --- a/.github/workflows/release-game7.yml +++ b/.github/workflows/release-game7.yml @@ -1,4 +1,4 @@ -name: Prepare release +name: Prepare release game7 app on: push: @@ -6,7 +6,7 @@ on: - "game7-v*" jobs: - create_release: + release-game7: runs-on: ubuntu-20.04 steps: - uses: actions/create-release@v1 diff --git a/.github/workflows/staging_deploy_wb-dashboard.yml b/.github/workflows/staging_deploy_wb-dashboard.yml deleted file mode 100644 index 727bad76..00000000 --- a/.github/workflows/staging_deploy_wb-dashboard.yml +++ /dev/null @@ -1,42 +0,0 @@ -on: - push: - branches: - - staging - paths: - - '.github/workflows/staging_deploy_wb-dashboard.yml' - - 'webapps/world-builder-dashboard/**' - -jobs: - staging_deploy_wb-dashboard: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository and main branch - uses: actions/checkout@v2 - with: - ref: staging - - - name: Set up node.js - uses: actions/setup-node@v3 - with: - node-version: "20.14.0" - - - name: Install and build staging app - working-directory: ./webapps/world-builder-dashboard - run: | - npm install - npm run build - - - name: Update robots.txt, block alpha for crawlers - working-directory: ./webapps/world-builder-dashboard/dist - run: | - sed -i "s/Disallow:.*/Disallow: \//" robots.txt - - - name: Publish to CloudFlare Page - uses: cloudflare/pages-action@v1 - with: - apiToken: ${{ secrets.CF_API_TOKEN_STAGE }} - accountId: ${{ secrets.CF_ACCOUNT_ID_STAGE }} - projectName: ${{ secrets.CF_PROJECT_NAME_WB_DASHBOARD_STAGE }} - directory: ./webapps/world-builder-dashboard/dist - gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test_web3.yml b/.github/workflows/test_web3.yml index b3085341..17c572cf 100644 --- a/.github/workflows/test_web3.yml +++ b/.github/workflows/test_web3.yml @@ -1,4 +1,4 @@ -name: Smart Contracts Test +name: Test Smart Contracts on: pull_request: @@ -14,6 +14,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + submodules: recursive # Ensure submodules are checked out and - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 diff --git a/.gitmodules b/.gitmodules index 2861cd39..f8b6c10c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "web3/lib/forge-std"] path = web3/lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "web3/contracts/utils/diamonds"] + path = web3/contracts/utils/diamonds + url = https://github.com/mudgen/diamond-3-hardhat diff --git a/Makefile b/Makefile index 5e7b2f5f..4ba8b81a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -.PHONY: clean generate regenerate test docs redocs hardhat bindings test-graffiti test-web3 clean-web3 deepclean +.PHONY: clean generate regenerate test docs redocs hardhat bindings test-graffiti test-web3 clean-web3 deepclean gitmodule -build: hardhat bindings bin/game7 bin/graffiti bin/robognome +build: gitmodule hardhat bindings bin/game7 bin/graffiti bin/robognome rebuild: clean generate build @@ -59,12 +59,28 @@ bindings/Metronome/Metronome.go: hardhat mkdir -p bindings/Metronome seer evm generate --package Metronome --output bindings/Metronome/Metronome.go --hardhat web3/artifacts/contracts/metronome/Metronome.sol/Metronome.json --cli --struct Metronome +bindings/utils/diamonds/Diamonds.go: hardhat + mkdir -p bindings/utils/diamonds/Diamond + seer evm generate --package Diamond --output bindings/utils/diamonds/Diamond/Diamond.go --hardhat web3/artifacts/contracts/utils/diamonds/contracts/Diamond.sol/Diamond.json --cli --struct Diamond + mkdir -p bindings/utils/diamonds/DiamondCutFacet + seer evm generate --package DiamondCutFacet --output bindings/utils/diamonds/DiamondCutFacet/DiamondCutFacet.go --hardhat web3/artifacts/contracts/utils/diamonds/contracts/facets/DiamondCutFacet.sol/DiamondCutFacet.json --cli --struct DiamondCutFacet + mkdir -p bindings/utils/diamonds/DiamondLoupeFacet + seer evm generate --package DiamondLoupeFacet --output bindings/utils/diamonds/DiamondLoupeFacet/DiamondLoupeFacet.go --hardhat web3/artifacts/contracts/utils/diamonds/contracts/facets/DiamondLoupeFacet.sol/DiamondLoupeFacet.json --cli --struct DiamondLoupeFacet + mkdir -p bindings/utils/diamonds/OwnershipFacet + seer evm generate --package OwnershipFacet --output bindings/utils/diamonds/OwnershipFacet/OwnershipFacet.go --hardhat web3/artifacts/contracts/utils/diamonds/contracts/facets/OwnershipFacet.sol/OwnershipFacet.json --cli --struct OwnershipFacet + +bindings/utils/security/Terminus.go: hardhat + mkdir -p bindings/security/terminus/TerminusFacet + seer evm generate --package TerminusFacet --output bindings/security/terminus/TerminusFacet/TerminusFacet.go --hardhat web3/artifacts/contracts/security/terminus/TerminusFacet.sol/TerminusFacet.json --cli --struct TerminusFacet + mkdir -p bindings/security/terminus/TerminusInitializer + seer evm generate --package TerminusInitializer --output bindings/security/terminus/TerminusInitializer/TerminusInitializer.go --hardhat web3/artifacts/contracts/security/terminus/TerminusInitializer.sol/TerminusInitializer.json --cli --struct TerminusInitializer + bindings/TokenSender/TokenSender.go: hardhat mkdir -p bindings/TokenSender seer evm generate --package TokenSender --output bindings/TokenSender/TokenSender.go --hardhat web3/artifacts/contracts/faucet/TokenSender.sol/TokenSender.json --cli --struct TokenSender -bindings: bindings/ERC20/ERC20.go bindings/TokenFaucet/TokenFaucet.go bindings/WrappedNativeToken/WrappedNativeToken.go bindings/Staker/Staker.go bindings/MockERC20/MockERC20.go bindings/MockERC721/MockERC721.go bindings/MockERC1155/MockERC1155.go bindings/PositionMetadata/PositionMetadata.go bindings/Metronome/Metronome.go bindings/TokenSender/TokenSender.go +bindings: bindings/ERC20/ERC20.go bindings/TokenFaucet/TokenFaucet.go bindings/WrappedNativeToken/WrappedNativeToken.go bindings/Staker/Staker.go bindings/MockERC20/MockERC20.go bindings/MockERC721/MockERC721.go bindings/MockERC1155/MockERC1155.go bindings/PositionMetadata/PositionMetadata.go bindings/Metronome/Metronome.go bindings/TokenSender/TokenSender.go bindings/utils/diamonds/Diamonds.go bindings/utils/security/Terminus.go test-web3: cd web3 && npx hardhat test @@ -75,7 +91,7 @@ test-graffiti: test: test-web3 test-graffiti clean: - rm -rf bindings/ERC20/* bin/* bindings/TokenFaucet/* bindings/WrappedNativeToken/* bindings/Staker/* bindings/MockERC20/* bindings/MockERC721/* bindings/MockERC1155/* bindings/PositionMetadata/* bindings/TokenSender/* + rm -rf bindings/ERC20/* bin/* bindings/TokenFaucet/* bindings/WrappedNativeToken/* bindings/Staker/* bindings/MockERC20/* bindings/MockERC721/* bindings/MockERC1155/* bindings/PositionMetadata/* bindings/TokenSender/* bindings/utils/* bindings/security/* clean-web3: rm -rf web3/node_modules web3/artifacts @@ -84,3 +100,6 @@ deepclean: clean clean-web3 hardhat: cd web3 && npm install && npx hardhat compile + +gitmodule: + git submodule update --init --recursive diff --git a/api/package.json b/api/package.json index bc1a1e5a..4b793b16 100644 --- a/api/package.json +++ b/api/package.json @@ -1,6 +1,6 @@ { "name": "protocol-api", - "version": "1.0.1", + "version": "1.0.2", "description": "", "main": "index.js", "scripts": { diff --git a/api/src/config.ts b/api/src/config.ts index 6e99add6..e6549c2e 100644 --- a/api/src/config.ts +++ b/api/src/config.ts @@ -52,14 +52,71 @@ export const swaggerOptions: SwaggerOptions = { version: '1.0.0', }; -export const tableNameGame7 = 'game7_testnet_labels'; // Game7 table name -export const tableNameEthereum = 'sepolia_labels'; // Ethereum table name -export const tableNameArbitrum = 'arbitrum_sepolia_labels'; // Arbitrum table name -export const addressERC20Inbox = 'e6470bb72291c39073aed67a30ff93b69c1f47de'; // Arbitrum Deposit contract address -export const addressEthereumOutbox = '65f07C7D521164a4d5DaC6eB8Fac8DA067A3B78F' // Ethereum L1ERC20Gateway address -export const addressL2ERC20Gateway = '6e244cD02BBB8a6dbd7F626f05B2ef82151Ab502' // Arbitrum L2ERC20Gateway address -export const addressL2GatewayRouter = '9fDD1C4E4AA24EEc1d913FABea925594a20d43C7' // Arbitrum L2ERC20Gateway address -export const addressL1GatewayRouter = 'cE18836b233C83325Cc8848CA4487e94C6288264' // Ethereum deposit address -export const addressArbitrumOutBox = '64105c6C3D494469D5F21323F0E917563489d9f5' // Arbitrum outbox address -export const addressArbOSL2 = '0000000000000000000000000000000000000064' // Game7 ArbOS L2 address -export const addressL1Inbox = 'aAe29B0366299461418F5324a79Afc425BE5ae21' // Ethereum inbox address \ No newline at end of file + +interface chainsRleationship { + parentNetworkChainId: number; + childNetworkChainId: number; +} + +// map of chain name to map of address and tables names +// Map of chain name to a map of addresses and table names +export const bridgeConfig: { + [chainName: string]: { + addressERC20Inbox: string; + addressEthereumOutbox: string; + addressL2ERC20Gateway: string; + addressL2GatewayRouter: string; + addressL1GatewayRouter: string; + addressArbitrumOutBox: string; + addressArbOSL2: string; + addressL1Inbox: string; + l3TableName: string; + l2TableName: string; + l1TableName: string; + l2rleationship: chainsRleationship; + l3rleationship: chainsRleationship; + l3Token: string; + l2Token: string; + l1Token: string; + nativeToken: string; + }; +} = { + "game7-testnet": { + addressERC20Inbox: "e6470bb72291c39073aed67a30ff93b69c1f47de", // Arbitrum Deposit contract address + addressEthereumOutbox: "65f07C7D521164a4d5DaC6eB8Fac8DA067A3B78F", // Ethereum L1ERC20Gateway address + addressL2ERC20Gateway: "6e244cD02BBB8a6dbd7F626f05B2ef82151Ab502", // Arbitrum L2ERC20Gateway address + addressL2GatewayRouter: "9fDD1C4E4AA24EEc1d913FABea925594a20d43C7", // Arbitrum L2ERC20Gateway address + addressL1GatewayRouter: "cE18836b233C83325Cc8848CA4487e94C6288264", // Ethereum deposit address + addressArbitrumOutBox: "64105c6C3D494469D5F21323F0E917563489d9f5", // Arbitrum outbox address ?? + addressArbOSL2: "0000000000000000000000000000000000000064", // Game7 ArbOS L2 address + addressL1Inbox: "aAe29B0366299461418F5324a79Afc425BE5ae21", // Ethereum inbox address + l3TableName: "game7_testnet_labels", + l2TableName: "arbitrum_sepolia_labels", + l1TableName: "sepolia_labels", + l3rleationship: { parentNetworkChainId: 421614, childNetworkChainId: 13746 }, + l2rleationship: { parentNetworkChainId: 11155111, childNetworkChainId: 421614 }, + l3Token: "0x10adBf84548F923577Be12146eAc104C899D1E75", // l3 native token + l2Token: "0x10adBf84548F923577Be12146eAc104C899D1E75", // l2 l3 token + l1Token: "0x0000000000000000000000000000000000000000", // l1 l3 token + nativeToken: "0x0000000000000000000000000000000000000000" // native token + }, + "game7": { //0x096760F208390250649E3e8763348E783AEF5562 L2CustomGateway 0xe80eb0238029333e368e0bDDB7acDf1b9cb28278 L2GatewayRouter + addressERC20Inbox: "B1146A7eb098ECF46e8AAf695f4A960A963948d6", // Arbitrum Deposit contract address + addressEthereumOutbox: "0B9857ae2D4A3DBe74ffE1d7DF045bb7F96E4840", // Ethereum L1ERC20Gateway address + addressL2ERC20Gateway: "096760F208390250649E3e8763348E783AEF5562", // Arbitrum L2ERC20Gateway address L1OrbitERC20Gateway + addressL2GatewayRouter: "5288c571Fd7aD117beA99bF60FE0846C4E84F933", // Arbitrum L2ERC20Gateway address L1OrbitGatewayRouter + addressL1GatewayRouter: "72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef", // Ethereum deposit address + addressArbitrumOutBox: "fbe537816d181888fAbE52338a5D921eE131E9Db", // Arbitrum outbox address ?? + addressArbOSL2: "0000000000000000000000000000000000000064", // Game7 ArbOS L2 address + addressL1Inbox: "4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", // Ethereum inbox address + l3TableName: "game7_labels", + l2TableName: "arbitrum_one_labels", + l1TableName: "ethereum_labels", + l3rleationship: { parentNetworkChainId: 42161, childNetworkChainId: 2187 }, + l2rleationship: { parentNetworkChainId: 1, childNetworkChainId: 42161 }, + l3Token: "F18e4466F26B4cA55bbAb890b314a54976E45B17", // l3 native token + l2Token: "F18e4466F26B4cA55bbAb890b314a54976E45B17", // l2 l3 token + l1Token: "0x0000000000000000000000000000000000000000", // l1 l3 token + nativeToken: "0x0000000000000000000000000000000000000000" // native token + }, +}; \ No newline at end of file diff --git a/api/src/controllers/bridge.controller.ts b/api/src/controllers/bridge.controller.ts index 033570c7..ad953c81 100644 --- a/api/src/controllers/bridge.controller.ts +++ b/api/src/controllers/bridge.controller.ts @@ -7,7 +7,7 @@ export class BridgeController { try { const limit = req.query.limit ? parseInt(req.query.limit as string, 10) : 10; // Default limit value if not provided const offset = req.query.offset ? parseInt(req.query.offset as string, 10) : 0; // Default offset value if not provided - const transactions = await getTransactionHistory(req.params.address, limit, offset); + const transactions = await getTransactionHistory(req.params.chain, req.params.address, limit, offset); return res.status(200).json(transactions); } catch (error) { console.error('Error fetching transaction history:', error); diff --git a/api/src/controllers/faucet.controller.ts b/api/src/controllers/faucet.controller.ts index 10c10f2d..641a4aa0 100644 --- a/api/src/controllers/faucet.controller.ts +++ b/api/src/controllers/faucet.controller.ts @@ -70,4 +70,16 @@ export class FaucetController { return res.status(500).send({ status: 'error', result: "Internal server error" }); } } + async getBalance(req: Request, res: Response) { + try { + console.log(`[FaucetController::getBalance] Retrieving faucet balance`); + const { address, balance } = await this.faucetService.getBalance(); + console.log(`[FaucetController::getBalance] Signer Address: ${address}, Balance: ${balance} ETH`); + return res.status(200).send({ status: 'success', result: { address, balance } }); + } catch (error: any) { + const decodedError = await tokenSenderErrorDecoder.decode(error); + console.log(`[FaucetController::getBalance] Error retrieving balance: ${decodedError.name} - ${decodedError.args}`); + return res.status(500).send({ status: 'error', result: "Internal server error" }); + } + } } diff --git a/api/src/routes/bridge.router.ts b/api/src/routes/bridge.router.ts index b416fe6e..322a3f6e 100644 --- a/api/src/routes/bridge.router.ts +++ b/api/src/routes/bridge.router.ts @@ -30,7 +30,7 @@ const bridgeController = new BridgeController(); * '500': * description: Internal server error. */ -router.get('/:address/transactions', (req: Request, res: Response) => +router.get('/:chain/:address/transactions', (req: Request, res: Response) => bridgeController.getTransactionHistory(req, res) ); diff --git a/api/src/routes/faucet.router.ts b/api/src/routes/faucet.router.ts index 007de0c7..a92dd55e 100644 --- a/api/src/routes/faucet.router.ts +++ b/api/src/routes/faucet.router.ts @@ -100,6 +100,22 @@ const faucetRoutes = (): Router => { (req: Request, res: Response) => faucetController.getRemainingTime(req, res) ); + /** + * @swagger + * /faucet/balance: + * get: + * summary: Get the current balance of the faucet. + * description: Retrieve the current balance of the faucet contract in Ether. + * responses: + * '200': + * description: A successful response with the faucet balance. + * '500': + * description: Internal server error + */ + FaucetRouter.get('/balance', (req: Request, res: Response) => + faucetController.getBalance(req, res) + ); + return FaucetRouter; }; diff --git a/api/src/services/bridge.service.ts b/api/src/services/bridge.service.ts index 71c420ec..f4a9bc8c 100644 --- a/api/src/services/bridge.service.ts +++ b/api/src/services/bridge.service.ts @@ -1,12 +1,16 @@ // src/services/bridge.service.ts import { pool } from '../utils/db'; // Adjust the import path as necessary -import { tableNameGame7, tableNameEthereum, tableNameArbitrum, addressERC20Inbox, addressEthereumOutbox, addressL2ERC20Gateway, addressArbitrumOutBox, addressArbOSL2, addressL1GatewayRouter, addressL2GatewayRouter, addressL1Inbox } from '../config'; // Adjust the import path as necessary +import { bridgeConfig } from '../config'; // Adjust the import path as necessary +export async function getTransactionHistory(chain: string, address: string, limit: number, offset: number): Promise { + + // switch statement blockchains + + if (!bridgeConfig[chain]) { + chain = 'game7-testnet'; + } -/// 11155111 - sepolia -/// 13746 - game7 -export async function getTransactionHistory(address: string, limit: number, offset: number): Promise { try { const query = ` WITH game7_withdrawal AS ( @@ -14,16 +18,17 @@ export async function getTransactionHistory(address: string, limit: number, offs 'WITHDRAWAL' AS type, label_data->'args'->>'position' AS position, label_data->'args'->>'callvalue' AS amount, - 421614 AS parentNetworkChainId, - 13746 AS childNetworkChainId, + ${bridgeConfig[chain].l3rleationship.parentNetworkChainId} AS parentNetworkChainId, + ${bridgeConfig[chain].l3rleationship.childNetworkChainId} AS childNetworkChainId, transaction_hash AS childNetworkHash, block_timestamp AS childNetworkTimestamp, label_data->'args'->>'caller' AS from_address, label_data->'args'->>'destination' AS to_address, 3600 AS challengePeriod, block_timestamp + 3600 AS claimableTimestamp, + '${bridgeConfig[chain].l3Token}' AS token, block_timestamp AS block_timestamp - FROM ${tableNameGame7} + FROM ${bridgeConfig[chain].l3TableName} WHERE label = 'seer' AND address = DECODE($1, 'hex') AND -- '0000000000000000000000000000000000000064' -- Game7 ArbOS L2 address @@ -36,13 +41,13 @@ export async function getTransactionHistory(address: string, limit: number, offs label_data->'args'->>'transactionIndex' AS position, label_data->'args'->>'l2Sender' AS from_address, label_data->'args'->>'to' AS to_address, - '' AS token, + '${bridgeConfig[chain].l3Token}' AS token, label_data->'args'->>'value' AS amount, 'from_l3_to_l2 claim' AS type, block_number, block_timestamp, true AS status - FROM ${tableNameArbitrum} + FROM ${bridgeConfig[chain].l2TableName} WHERE label = 'seer' AND label_type = 'event' AND @@ -53,20 +58,21 @@ export async function getTransactionHistory(address: string, limit: number, offs 'WITHDRAWAL' AS type, null AS position, NULL AS amount, - 421614 AS parentNetworkChainId, - 13746 AS childNetworkChainId, + ${bridgeConfig[chain].l3rleationship.parentNetworkChainId} AS parentNetworkChainId, + ${bridgeConfig[chain].l3rleationship.childNetworkChainId} AS childNetworkChainId, transaction_hash AS childNetworkHash, block_timestamp AS childNetworkTimestamp, label_data->'args'->>'caller' AS from_address, null AS to_address, 3600 AS challengePeriod, block_timestamp + 3600 AS claimableTimestamp, + '${bridgeConfig[chain].l3Token}' AS token, NULL::double precision AS completionTimestamp, NULL::double precision AS parentNetworkTimestamp, NULL AS parentNetworkHash, false AS status, block_timestamp AS block_timestamp - FROM ${tableNameGame7} + FROM ${bridgeConfig[chain].l3TableName} WHERE label = 'seer' AND label_type = 'tx_call' AND @@ -86,6 +92,7 @@ export async function getTransactionHistory(address: string, limit: number, offs game7_withdrawal.to_address AS to_address, game7_withdrawal.challengePeriod AS challengePeriod, game7_withdrawal.claimableTimestamp AS claimableTimestamp, + game7_withdrawal.token as token, arbirtrum_claims.block_timestamp AS completionTimestamp, arbirtrum_claims.block_timestamp AS parentNetworkTimestamp, arbirtrum_claims.transaction_hash AS parentNetworkHash, @@ -104,17 +111,18 @@ export async function getTransactionHistory(address: string, limit: number, offs 'Withdrawal' AS type, label_data->'args'->>'_l2ToL1Id' AS position, label_data->'args'->>'_amount' AS amount, - 11155111 AS parentNetworkChainId, - 421614 AS childNetworkChainId, + ${bridgeConfig[chain].l2rleationship.parentNetworkChainId} AS parentNetworkChainId, + ${bridgeConfig[chain].l2rleationship.childNetworkChainId} AS childNetworkChainId, transaction_hash AS childNetworkHash, block_timestamp AS childNetworkTimestamp, label_data->'args'->>'_from' AS from_address, label_data->'args'->>'_to' AS to_address, 3600 AS challengePeriod, block_timestamp + 3600 AS claimableTimestamp, + label_data->'args'->>'l1Token' AS token, block_timestamp AS block_timestamp FROM - ${tableNameArbitrum} + ${bridgeConfig[chain].l2TableName} WHERE label = 'seer' AND label_type = 'event' @@ -130,7 +138,7 @@ export async function getTransactionHistory(address: string, limit: number, offs 'claim' AS type, block_number, block_timestamp - FROM ${tableNameEthereum} + FROM ${bridgeConfig[chain].l1TableName} WHERE label = 'seer' AND label_type = 'event' AND @@ -140,21 +148,22 @@ export async function getTransactionHistory(address: string, limit: number, offs SELECT 'WITHDRAWAL' AS type, null AS position, - NULL AS amount, - 11155111 AS parentNetworkChainId, - 421614 AS childNetworkChainId, + label_data->'args'->>'_amount' AS amount, + ${bridgeConfig[chain].l2rleationship.parentNetworkChainId} AS parentNetworkChainId, + ${bridgeConfig[chain].l2rleationship.childNetworkChainId} AS childNetworkChainId, transaction_hash AS childNetworkHash, block_timestamp AS childNetworkTimestamp, label_data->'args'->>'caller' AS from_address, - null AS to_address, + label_data->'args'->>'_to' as to_address, 3600 AS challengePeriod, block_timestamp + 3600 AS claimableTimestamp, + label_data->'args'->>'_l1Token' as token, NULL::double precision AS completionTimestamp, NULL::double precision AS parentNetworkTimestamp, NULL AS parentNetworkHash, false AS status, block_timestamp AS block_timestamp - FROM ${tableNameArbitrum} + FROM ${bridgeConfig[chain].l2TableName} WHERE label = 'seer' AND label_type = 'tx_call' AND @@ -174,6 +183,7 @@ export async function getTransactionHistory(address: string, limit: number, offs arbitrum_withdraw.to_address AS to_address, arbitrum_withdraw.challengePeriod AS challengePeriod, arbitrum_withdraw.claimableTimestamp AS claimableTimestamp, + arbitrum_withdraw.token as token, ethereum_claims.block_timestamp AS completionTimestamp, ethereum_claims.block_timestamp AS parentNetworkTimestamp, ethereum_claims.transaction_hash AS parentNetworkHash, @@ -190,21 +200,21 @@ export async function getTransactionHistory(address: string, limit: number, offs SELECT 'DEPOSIT' AS type, label_data -> 'args' ->> 'amount' AS amount, - 421614 AS parentNetworkChainId, - 13746 AS childNetworkChainId, + ${bridgeConfig[chain].l3rleationship.parentNetworkChainId} AS parentNetworkChainId, + ${bridgeConfig[chain].l3rleationship.childNetworkChainId} AS childNetworkChainId, transaction_hash AS parentNetworkHash, block_timestamp AS parentNetworkTimestamp, block_timestamp AS completionTimestamp, '0x' || ENCODE(origin_address, 'hex') AS from_address, '0x' || ENCODE(origin_address, 'hex') AS to_address, - '' AS token, + '${bridgeConfig[chain].l3Token}' AS token, CASE WHEN label_data ->> 'status' = '1' THEN true ELSE false END AS isDeposit, block_timestamp FROM - ${tableNameArbitrum} + ${bridgeConfig[chain].l2TableName} WHERE label = 'seer' AND label_type = 'tx_call' @@ -215,8 +225,8 @@ export async function getTransactionHistory(address: string, limit: number, offs SELECT 'DEPOSIT' AS type, label_data -> 'args' ->> '_amount' AS amount, - 11155111 AS parentNetworkChainId, - 421614 AS childNetworkChainId, + ${bridgeConfig[chain].l2rleationship.parentNetworkChainId} AS parentNetworkChainId, + ${bridgeConfig[chain].l2rleationship.childNetworkChainId} AS childNetworkChainId, transaction_hash AS parentNetworkHash, block_timestamp AS parentNetworkTimestamp, block_timestamp AS completionTimestamp, @@ -229,7 +239,7 @@ export async function getTransactionHistory(address: string, limit: number, offs END AS isDeposit, block_timestamp FROM - ${tableNameEthereum} + ${bridgeConfig[chain].l1TableName} WHERE label = 'seer' AND label_type = 'tx_call' @@ -239,21 +249,21 @@ export async function getTransactionHistory(address: string, limit: number, offs SELECT 'DEPOSIT' AS type, NULL AS amount, - 11155111 AS parentNetworkChainId, - 421614 AS childNetworkChainId, + ${bridgeConfig[chain].l2rleationship.parentNetworkChainId} AS parentNetworkChainId, + ${bridgeConfig[chain].l2rleationship.childNetworkChainId} AS childNetworkChainId, transaction_hash AS parentNetworkHash, block_timestamp AS parentNetworkTimestamp, block_timestamp AS completionTimestamp, '0x' || ENCODE(origin_address, 'hex') AS from_address, '0x' || ENCODE(origin_address, 'hex') AS to_address, - '' AS token, + '${bridgeConfig[chain].nativeToken}' AS token, CASE WHEN label_data ->> 'status' = '1' THEN true ELSE false END AS isDeposit, block_timestamp FROM - ${tableNameEthereum} + ${bridgeConfig[chain].l1TableName} WHERE label = 'seer' AND label_type = 'tx_call' @@ -318,6 +328,7 @@ export async function getTransactionHistory(address: string, limit: number, offs 'to_address', to_address, 'challengePeriod', challengePeriod, 'claimableTimestamp', claimableTimestamp, + 'token', token, 'status', status ) AS data, block_timestamp, @@ -342,6 +353,7 @@ export async function getTransactionHistory(address: string, limit: number, offs 'to_address', to_address, 'challengePeriod', challengePeriod, 'claimableTimestamp', claimableTimestamp, + 'token', token, 'status', status ) AS data, block_timestamp, @@ -364,14 +376,14 @@ export async function getTransactionHistory(address: string, limit: number, offs OFFSET $10 LIMIT $11 `; - const result = await pool.query(query, [addressArbOSL2, - addressArbitrumOutBox, - addressL2ERC20Gateway, - addressEthereumOutbox, - addressL2GatewayRouter, - addressERC20Inbox, - addressL1GatewayRouter, - addressL1Inbox, + const result = await pool.query(query, [bridgeConfig[chain].addressArbOSL2, + bridgeConfig[chain].addressArbitrumOutBox, + bridgeConfig[chain].addressL2ERC20Gateway, + bridgeConfig[chain].addressEthereumOutbox, + bridgeConfig[chain].addressL2GatewayRouter, + bridgeConfig[chain].addressERC20Inbox, + bridgeConfig[chain].addressL1GatewayRouter, + bridgeConfig[chain].addressL1Inbox, address, offset, limit]) // unpack the data from the result const data = result.rows.map((row: any) => row.data); diff --git a/api/src/services/faucet.service.ts b/api/src/services/faucet.service.ts index 7df6cd8a..d7fad26c 100644 --- a/api/src/services/faucet.service.ts +++ b/api/src/services/faucet.service.ts @@ -11,10 +11,12 @@ import { toUnixTimestamp } from '../utils/date'; export class FaucetService { tokenSender: ethers.Contract; + provider: ethers.JsonRpcProvider; + signer: AwsKmsSigner; constructor() { - const provider = new ethers.JsonRpcProvider(GAME7_TESTNET_RPC_URL); - const signer = new AwsKmsSigner( + this.provider = new ethers.JsonRpcProvider(GAME7_TESTNET_RPC_URL); + this.signer = new AwsKmsSigner( { region: KMS_CREDENTIALS.region, keyId: KMS_CREDENTIALS.keyId, @@ -23,12 +25,12 @@ export class FaucetService { secretAccessKey: KMS_CREDENTIALS.secretAccessKey, }, }, - provider + this.provider ); this.tokenSender = new ethers.Contract( TOKEN_SENDER_ADDRESS, TokenSenderABI, - signer + this.signer ); } @@ -58,4 +60,13 @@ export class FaucetService { if (remainingTime <= 0) return 0; else return remainingTime; } + async getBalance() { + const signerAddress = await this.signer.getAddress(); + const balance = await this.provider.getBalance(signerAddress); + + return { + address: signerAddress, + balance: ethers.formatEther(balance), + }; + } } diff --git a/bindings/Staker/Staker.go b/bindings/Staker/Staker.go index 0c5b8f7a..15d80126 100644 --- a/bindings/Staker/Staker.go +++ b/bindings/Staker/Staker.go @@ -57,7 +57,7 @@ var ( var StakerMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"positionMetadata\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ERC721EnumerableForbiddenBatchMint\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC721IncorrectOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721InsufficientApproval\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC721InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"ERC721InvalidOperator\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC721InvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC721InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC721InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721NonexistentToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"ERC721OutOfBoundsIndex\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"poolTokenType\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"tokenTypeArg\",\"type\":\"uint256\"}],\"name\":\"IncorrectTokenType\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"cooldownSeconds\",\"type\":\"uint256\"}],\"name\":\"InitiateUnstakeFirst\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfiguration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTokenType\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expiresAt\",\"type\":\"uint256\"}],\"name\":\"LockupNotExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MetadataError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonAdministrator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NothingToStake\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"}],\"name\":\"PositionNotTransferable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrancyGuardReentrantCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"UnauthorizedForPosition\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountOrTokenID\",\"type\":\"uint256\"}],\"name\":\"Staked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"administrator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"transferable\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lockupSeconds\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cooldownSeconds\",\"type\":\"uint256\"}],\"name\":\"StakingPoolConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenType\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenID\",\"type\":\"uint256\"}],\"name\":\"StakingPoolCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"UnstakeInitiated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountOrTokenID\",\"type\":\"uint256\"}],\"name\":\"Unstaked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"CurrentAmountInPool\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"CurrentPositionsInPool\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERC1155_TOKEN_TYPE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERC20_TOKEN_TYPE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ERC721_TOKEN_TYPE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_TOKEN_TYPE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"Pools\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"administrator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenType\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenID\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"transferable\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"lockupSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"cooldownSeconds\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"Positions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amountOrTokenID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stakeTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeInitiatedAt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TotalPools\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"TotalPositions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenType\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenID\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"transferable\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"lockupSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"cooldownSeconds\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"administrator\",\"type\":\"address\"}],\"name\":\"createPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"}],\"name\":\"initiateUnstake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC1155Received\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC721Received\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"positionMetadataAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"positionHolder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"stakeERC1155\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"positionHolder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"stakeERC20\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"positionHolder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"tokenID\",\"type\":\"uint256\"}],\"name\":\"stakeERC721\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"positionHolder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"}],\"name\":\"stakeNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newAdministrator\",\"type\":\"address\"}],\"name\":\"transferPoolAdministration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"positionTokenID\",\"type\":\"uint256\"}],\"name\":\"unstake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"changeTransferability\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"transferable\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"changeLockup\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"lockupSeconds\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"changeCooldown\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"cooldownSeconds\",\"type\":\"uint256\"}],\"name\":\"updatePoolConfiguration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162003c9938038062003c998339810160408190526200003491620000b4565b6040518060400160405280600c81526020016b23b0b6b29b9029ba30b5b2b960a11b81525060405180604001604052806008815260200167239ba9aa20a5a2a960c11b81525081600090816200008b91906200018d565b5060016200009a82826200018d565b50506001600a55506001600160a01b031660805262000259565b600060208284031215620000c757600080fd5b81516001600160a01b0381168114620000df57600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200011157607f821691505b6020821081036200013257634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000188576000816000526020600020601f850160051c81016020861015620001635750805b601f850160051c820191505b8181101562000184578281556001016200016f565b5050505b505050565b81516001600160401b03811115620001a957620001a9620000e6565b620001c181620001ba8454620000fc565b8462000138565b602080601f831160018114620001f95760008415620001e05750858301515b600019600386901b1c1916600185901b17855562000184565b600085815260208120601f198616915b828110156200022a5788860151825594840194600190910190840162000209565b5085821015620002495787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b608051613a1d6200027c600039600081816108080152611bea0152613a1d6000f3fe6080604052600436106102845760003560e01c806373dfccca11610153578063b0fe4a7e116100cb578063d693595d1161007f578063e985e9c511610064578063e985e9c51461084a578063f09e76a1146108a0578063f23a6e61146108b657600080fd5b8063d693595d146107f6578063df44bf761461082a57600080fd5b8063b88d4fde116100b0578063b88d4fde146107a1578063c87b56dd146107c1578063d2ba4409146107e157600080fd5b8063b0fe4a7e14610754578063b29087da1461077457600080fd5b806395d89b4111610122578063a22cb46511610107578063a22cb465146106fe578063abd4ce781461071e578063ae5ac9211461073457600080fd5b806395d89b41146106d6578063a1ed8fef146106eb57600080fd5b806373dfccca146105aa57806377bd2e781461067457806381c822e6146106895780638d4a9e85146106b657600080fd5b80632f745c59116102015780634f6ccce7116101b55780636352211e1161019a5780636352211e1461050857806370a082311461052857806373caf0f71461054857600080fd5b80634f6ccce7146104c8578063621519c0146104e857600080fd5b80633db26319116101e65780633db2631914610472578063424b93111461049257806342842e0e146104a857600080fd5b80632f745c591461043c5780633ab0f1c11461045c57600080fd5b8063095ea7b31161025857806318160ddd1161023d57806318160ddd146103dd57806323b872dd146103fc5780632e17de781461041c57600080fd5b8063095ea7b314610347578063150b7a021461036757600080fd5b80627d0cec1461028957806301ffc9a7146102ab57806306fdde03146102e0578063081812fc14610302575b600080fd5b34801561029557600080fd5b506102a96102a4366004613193565b6108fc565b005b3480156102b757600080fd5b506102cb6102c636600461323c565b610a27565b60405190151581526020015b60405180910390f35b3480156102ec57600080fd5b506102f5610a83565b6040516102d791906132c7565b34801561030e57600080fd5b5061032261031d3660046132da565b610b15565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102d7565b34801561035357600080fd5b506102a961036236600461331c565b610b4b565b34801561037357600080fd5b506103ac61038236600461338f565b7f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016102d7565b3480156103e957600080fd5b506008545b6040519081526020016102d7565b34801561040857600080fd5b506102a96104173660046133fe565b610b5a565b34801561042857600080fd5b506102a96104373660046132da565b610bcf565b34801561044857600080fd5b506103ee61045736600461331c565b611069565b34801561046857600080fd5b506103ee600c5481565b34801561047e57600080fd5b506102a961048d36600461343a565b611101565b34801561049e57600080fd5b506103ee600b5481565b3480156104b457600080fd5b506102a96104c33660046133fe565b6111fc565b3480156104d457600080fd5b506103ee6104e33660046132da565b61121c565b3480156104f457600080fd5b506103ee610503366004613466565b61128e565b34801561051457600080fd5b506103226105233660046132da565b61149b565b34801561053457600080fd5b506103ee610543366004613499565b6114a6565b34801561055457600080fd5b5061058a6105633660046132da565b60106020526000908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016102d7565b3480156105b657600080fd5b5061061f6105c53660046132da565b600f60205260009081526040902080546001820154600283015460038401546004850154600586015460069096015473ffffffffffffffffffffffffffffffffffffffff95861696949590931693919260ff909116919087565b6040805173ffffffffffffffffffffffffffffffffffffffff98891681526020810197909752949096169385019390935260608401919091521515608083015260a082015260c081019190915260e0016102d7565b34801561068057600080fd5b506103ee600181565b34801561069557600080fd5b506103ee6106a43660046132da565b600d6020526000908152604090205481565b3480156106c257600080fd5b506103ee6106d1366004613466565b611521565b3480156106e257600080fd5b506102f5611675565b6103ee6106f936600461331c565b611684565b34801561070a57600080fd5b506102a96107193660046134b4565b611834565b34801561072a57600080fd5b506103ee61048381565b34801561074057600080fd5b506102a961074f3660046132da565b61183f565b34801561076057600080fd5b506103ee61076f366004613466565b61199f565b34801561078057600080fd5b506103ee61078f3660046132da565b600e6020526000908152604090205481565b3480156107ad57600080fd5b506102a96107bc3660046135af565b611b06565b3480156107cd57600080fd5b506102f56107dc3660046132da565b611b23565b3480156107ed57600080fd5b506103ee601481565b34801561080257600080fd5b506103227f000000000000000000000000000000000000000000000000000000000000000081565b34801561083657600080fd5b506102a961084536600461365a565b611d2a565b34801561085657600080fd5b506102cb6108653660046136c6565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260056020908152604080832093909416825291909152205460ff1690565b3480156108ac57600080fd5b506103ee6102d181565b3480156108c257600080fd5b506103ac6108d13660046136f0565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b6000878152600f60205260409020805473ffffffffffffffffffffffffffffffffffffffff16331461095a576040517f29f9fc8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b861561098f576004810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168715151790555b841561099d57600581018490555b82156109ab57600681018290555b80546004820154600583015460068401546040805160ff9094161515845260208401929092529082015273ffffffffffffffffffffffffffffffffffffffff9091169089907f8587d3b7f5e8e73d0f5be513ce84b6c7c9497e221295d831f57ba7ecc36589b59060600160405180910390a35050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d63000000000000000000000000000000000000000000000000000000001480610a7d5750610a7d82612086565b92915050565b606060008054610a9290613768565b80601f0160208091040260200160405190810160405280929190818152602001828054610abe90613768565b8015610b0b5780601f10610ae057610100808354040283529160200191610b0b565b820191906000526020600020905b815481529060010190602001808311610aee57829003601f168201915b5050505050905090565b6000610b2082612169565b5060008281526004602052604090205473ffffffffffffffffffffffffffffffffffffffff16610a7d565b610b568282336121c8565b5050565b600081815260106020908152604080832080548452600f909252909120600481015460ff16610bbd576040517f2ed602a6000000000000000000000000000000000000000000000000000000008152600481018490526024015b60405180910390fd5b610bc88585856121d5565b5050505050565b610bd76122c0565b600081815260106020908152604080832080548452600f90925282209091610bfe8461149b565b905073ffffffffffffffffffffffffffffffffffffffff81163314801590610c3d5750815473ffffffffffffffffffffffffffffffffffffffff163314155b15610c92576040517f5a4c507400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152336024820152604401610bb4565b600682015415610d035760038301541580610cbf575081600601548360030154610cbc91906137ea565b42105b15610cfe5781600601546040517f2098e24d000000000000000000000000000000000000000000000000000000008152600401610bb491815260200190565b610d67565b81600501548360020154610d1791906137ea565b421015610d675781600501548360020154610d3291906137ea565b6040517f9dc1207c000000000000000000000000000000000000000000000000000000008152600401610bb491815260200190565b6102d1826001015403610d9a5782546000908152600d60205260408120805491610d90836137fd565b9190505550610dc5565b600183015483546000908152600d602052604081208054909190610dbf908490613832565b90915550505b82546000908152600e60205260408120805491610de1836137fd565b909155505060018301548354604080518781526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917fffdaf13b1d96bfc2213355f353f84c19493e0681eb0df26f83d862acd266750a910160405180910390a36000858152601060205260408120818155600181018290556002810182905560030155610e6a85612303565b6001836001015403610ebf5760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610eb9573d6000803e3d6000fd5b50611058565b6014836001015403610ef6576002830154610ef19073ffffffffffffffffffffffffffffffffffffffff168383612364565b611058565b6102d1836001015403610f9c5760028301546040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff848116602483015260448201849052909116906342842e0e90606401600060405180830381600087803b158015610f7f57600080fd5b505af1158015610f93573d6000803e3d6000fd5b50505050611058565b61048383600101540361105857600283015460038401546040517ff242432a00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff858116602483015260448201929092526064810184905260a06084820152600060a482015291169063f242432a9060c401600060405180830381600087803b15801561103f57600080fd5b505af1158015611053573d6000803e3d6000fd5b505050505b505050506110666001600a55565b50565b6000611074836114a6565b82106110cb576040517fa57d13dc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260248101839052604401610bb4565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600660209081526040808320938352929052205490565b6000828152600f60205260409020805473ffffffffffffffffffffffffffffffffffffffff16331461115f576040517f29f9fc8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811782556004820154600583015460068401546040805160ff9094161515845260208401929092529082015284907f8587d3b7f5e8e73d0f5be513ce84b6c7c9497e221295d831f57ba7ecc36589b5906060015b60405180910390a3505050565b61121783838360405180602001604052806000815250611b06565b505050565b600061122760085490565b8210611269576040517fa57d13dc0000000000000000000000000000000000000000000000000000000081526000600482015260248101839052604401610bb4565b6008828154811061127c5761127c613845565b90600052602060002001549050919050565b60006112986122c0565b6000838152600f6020526040902060018101546102d1146112fd5760018101546040517f323b95bb0000000000000000000000000000000000000000000000000000000081526004810186905260248101919091526102d16044820152606401610bb4565b60028101546040517f42842e0e0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810185905273ffffffffffffffffffffffffffffffffffffffff909116906342842e0e90606401600060405180830381600087803b15801561137757600080fd5b505af115801561138b573d6000803e3d6000fd5b5050600c80549250905060006113a083613874565b9190505591506113b085836123e5565b60408051608081018252858152602080820186815242838501908152600060608501818152888252601085528682209551865592516001860155905160028501559051600390930192909255868252600d905290812080549161141283613874565b90915550506000848152600e6020526040812080549161143183613874565b90915550506040805183815260208101859052859173ffffffffffffffffffffffffffffffffffffffff8816917f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a32910160405180910390a3506114946001600a55565b9392505050565b6000610a7d82612169565b600073ffffffffffffffffffffffffffffffffffffffff82166114f8576040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152602401610bb4565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b600061152b6122c0565b6000838152600f60205260409020600181015460141461158e5760018101546040517f323b95bb00000000000000000000000000000000000000000000000000000000815260048101869052602481019190915260146044820152606401610bb4565b826000036115c8576040517fd23fa2a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546115ef9073ffffffffffffffffffffffffffffffffffffffff16333086612496565b600c80549060006115ff83613874565b91905055915061160f85836123e5565b60408051608081018252858152602080820186815242838501908152600060608501818152888252601085528682209551865592516001860155905160028501559051600390930192909255868252600d905290812080548592906114129084906137ea565b606060018054610a9290613768565b600061168e6122c0565b6000828152600f60205260409020600180820154146116f2576001818101546040517f323b95bb0000000000000000000000000000000000000000000000000000000081526004810186905260248101919091526044810191909152606401610bb4565b3460000361172c576040517fd23fa2a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c805490600061173c83613874565b91905055915061174c84836123e5565b6040805160808101825284815234602080830182815242848601908152600060608601818152898252601085528782209651875592516001870155905160028601559051600390940193909355868352600d905291812080549091906117b39084906137ea565b90915550506000838152600e602052604081208054916117d283613874565b909155505060408051838152346020820152849173ffffffffffffffffffffffffffffffffffffffff8716917f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a32910160405180910390a350610a7d6001600a55565b610b563383836124dc565b6118476122c0565b60006118528261149b565b600083815260106020908152604080832080548452600f9092529091209192509073ffffffffffffffffffffffffffffffffffffffff831633148015906118b05750805473ffffffffffffffffffffffffffffffffffffffff163314155b15611905576040517f5a4c507400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152336024820152604401610bb4565b8060050154826002015461191991906137ea565b4210156119345780600501548260020154610d3291906137ea565b81600301546000036119925742600383015560405184815273ffffffffffffffffffffffffffffffffffffffff8416907fb88af44ff67f15b82bc60b5ecd6ac0f0c27da279a6c21b7d200174756ea5c5e49060200160405180910390a25b5050506110666001600a55565b60006119a96122c0565b6000838152600f60205260409020600181015461048314611a0e5760018101546040517f323b95bb0000000000000000000000000000000000000000000000000000000081526004810186905260248101919091526104836044820152606401610bb4565b82600003611a48576040517fd23fa2a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600281015460038201546040517ff242432a00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101919091526064810185905260a06084820152600060a482015273ffffffffffffffffffffffffffffffffffffffff9091169063f242432a9060c401600060405180830381600087803b158015611add57600080fd5b505af1158015611af1573d6000803e3d6000fd5b5050600c80549250905060006115ff83613874565b611b11848484610b5a565b611b1d848484846125d1565b50505050565b6060611b2e82612169565b5060008281526010602090815260408083208054808552600f90935281842091516024810187905260448101939093526001808201546064850152600280830154608486015260038084015460a4870152845473ffffffffffffffffffffffffffffffffffffffff90811660c48801529285015460e4870152908401548216610104860152830154610124850152600483015460ff161515610144850152600583015461016485015260068301546101848501529093919282917f000000000000000000000000000000000000000000000000000000000000000016906101a401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7b2f34ff0000000000000000000000000000000000000000000000000000000017905251611c9091906138ac565b600060405180830381855afa9150503d8060008114611ccb576040519150601f19603f3d011682016040523d82523d6000602084013e611cd0565b606091505b509150915081611d0c576040517f0e8d7e7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80806020019051810190611d2091906138c8565b9695505050505050565b60018703611d915773ffffffffffffffffffffffffffffffffffffffff8616151580611d5557508415155b15611d8c576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ed6565b60148703611def5773ffffffffffffffffffffffffffffffffffffffff86161580611d5557508415611d8c576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102d18703611e4e5773ffffffffffffffffffffffffffffffffffffffff86161580611d5557508415611d8c576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104838703611ea45773ffffffffffffffffffffffffffffffffffffffff8616611d8c576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa1e9dd9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff838116825260208083018b81528a8316848601818152606086018c81528b15156080880190815260a088018c815260c089018c8152600b80546000908152600f8a528c90209a518b547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116918c16919091178c55975160018c0155945160028b01805490981699169890981790955590516003880155516004870180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790559151600586015592516006909401939093559154925188815290928a9290917f36b06296d9441695787e7cbfc0b9cfc5deeeabec4406a3a90d30a222103c2dc8910160405180910390a4600b546040805186151581526020810186905290810184905273ffffffffffffffffffffffffffffffffffffffff831691907f8587d3b7f5e8e73d0f5be513ce84b6c7c9497e221295d831f57ba7ecc36589b59060600160405180910390a3600b805490600061207883613874565b919050555050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061211957507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610a7d57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610a7d565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610a7d576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101849052602401610bb4565b61121783838360016127c1565b73ffffffffffffffffffffffffffffffffffffffff8216612225576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260006004820152602401610bb4565b600061223283833361298c565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611b1d576040517f64283d7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80861660048301526024820184905282166044820152606401610bb4565b6002600a54036122fc576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600a55565b6000612312600083600061298c565b905073ffffffffffffffffffffffffffffffffffffffff8116610b56576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101839052602401610bb4565b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301526044820183905261121791859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612aaf565b73ffffffffffffffffffffffffffffffffffffffff8216612435576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260006004820152602401610bb4565b60006124438383600061298c565b905073ffffffffffffffffffffffffffffffffffffffff811615611217576040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152602401610bb4565b60405173ffffffffffffffffffffffffffffffffffffffff8481166024830152838116604483015260648201839052611b1d9186918216906323b872dd9060840161239e565b73ffffffffffffffffffffffffffffffffffffffff8216612541576040517f5b08ba1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610bb4565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3191016111ef565b73ffffffffffffffffffffffffffffffffffffffff83163b15611b1d576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84169063150b7a029061264690339088908790879060040161393f565b6020604051808303816000875af192505050801561269f575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261269c9181019061397e565b60015b61272e573d8080156126cd576040519150601f19603f3d011682016040523d82523d6000602084013e6126d2565b606091505b508051600003612726576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610bb4565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a020000000000000000000000000000000000000000000000000000000014610bc8576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610bb4565b80806127e2575073ffffffffffffffffffffffffffffffffffffffff821615155b156129375760006127f284612169565b905073ffffffffffffffffffffffffffffffffffffffff83161580159061284557508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015612884575073ffffffffffffffffffffffffffffffffffffffff80821660009081526005602090815260408083209387168352929052205460ff16155b156128d3576040517fa9fbf51f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610bb4565b811561293557838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008061299a858585612b45565b905073ffffffffffffffffffffffffffffffffffffffff8116612a04576129ff84600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b612a41565b8473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612a4157612a418185612cc2565b73ffffffffffffffffffffffffffffffffffffffff8516612a6a57612a6584612d6d565b612aa7565b8473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612aa757612aa78585612e1c565b949350505050565b6000612ad173ffffffffffffffffffffffffffffffffffffffff841683612e79565b90508051600014158015612af6575080806020019051810190612af4919061399b565b155b15611217576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610bb4565b60008281526002602052604081205473ffffffffffffffffffffffffffffffffffffffff90811690831615612b7f57612b7f818486612e87565b73ffffffffffffffffffffffffffffffffffffffff811615612bf557612ba96000856000806127c1565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555b73ffffffffffffffffffffffffffffffffffffffff851615612c3e5773ffffffffffffffffffffffffffffffffffffffff85166000908152600360205260409020805460010190555b60008481526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff89811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6000612ccd836114a6565b600083815260076020526040902054909150808214612d2d5773ffffffffffffffffffffffffffffffffffffffff841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b50600091825260076020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600681528383209183525290812055565b600854600090612d7f90600190613832565b60008381526009602052604081205460088054939450909284908110612da757612da7613845565b906000526020600020015490508060088381548110612dc857612dc8613845565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480612e0057612e006139b8565b6001900381819060005260206000200160009055905550505050565b60006001612e29846114a6565b612e339190613832565b73ffffffffffffffffffffffffffffffffffffffff9093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b606061149483836000612f37565b612e92838383612ff0565b6112175773ffffffffffffffffffffffffffffffffffffffff8316612ee6576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101829052602401610bb4565b6040517f177e802f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260248101829052604401610bb4565b606081471015612f75576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610bb4565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051612f9e91906138ac565b60006040518083038185875af1925050503d8060008114612fdb576040519150601f19603f3d011682016040523d82523d6000602084013e612fe0565b606091505b5091509150611d208683836130b4565b600073ffffffffffffffffffffffffffffffffffffffff831615801590612aa757508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061307e575073ffffffffffffffffffffffffffffffffffffffff80851660009081526005602090815260408083209387168352929052205460ff165b80612aa757505060009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff908116911614919050565b6060826130c9576130c482613143565b611494565b81511580156130ed575073ffffffffffffffffffffffffffffffffffffffff84163b155b1561313c576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610bb4565b5080611494565b8051156131535780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801515811461106657600080fd5b600080600080600080600060e0888a0312156131ae57600080fd5b8735965060208801356131c081613185565b955060408801356131d081613185565b945060608801356131e081613185565b93506080880135925060a08801356131f781613185565b8092505060c0880135905092959891949750929550565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461106657600080fd5b60006020828403121561324e57600080fd5b81356114948161320e565b60005b8381101561327457818101518382015260200161325c565b50506000910152565b60008151808452613295816020860160208601613259565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611494602083018461327d565b6000602082840312156132ec57600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461331757600080fd5b919050565b6000806040838503121561332f57600080fd5b613338836132f3565b946020939093013593505050565b60008083601f84011261335857600080fd5b50813567ffffffffffffffff81111561337057600080fd5b60208301915083602082850101111561338857600080fd5b9250929050565b6000806000806000608086880312156133a757600080fd5b6133b0866132f3565b94506133be602087016132f3565b935060408601359250606086013567ffffffffffffffff8111156133e157600080fd5b6133ed88828901613346565b969995985093965092949392505050565b60008060006060848603121561341357600080fd5b61341c846132f3565b925061342a602085016132f3565b9150604084013590509250925092565b6000806040838503121561344d57600080fd5b8235915061345d602084016132f3565b90509250929050565b60008060006060848603121561347b57600080fd5b613484846132f3565b95602085013595506040909401359392505050565b6000602082840312156134ab57600080fd5b611494826132f3565b600080604083850312156134c757600080fd5b6134d0836132f3565b915060208301356134e081613185565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613561576135616134eb565b604052919050565b600067ffffffffffffffff821115613583576135836134eb565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600080600080608085870312156135c557600080fd5b6135ce856132f3565b93506135dc602086016132f3565b925060408501359150606085013567ffffffffffffffff8111156135ff57600080fd5b8501601f8101871361361057600080fd5b803561362361361e82613569565b61351a565b81815288602083850101111561363857600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b600080600080600080600060e0888a03121561367557600080fd5b87359650613685602089016132f3565b955060408801359450606088013561369c81613185565b93506080880135925060a088013591506136b860c089016132f3565b905092959891949750929550565b600080604083850312156136d957600080fd5b6136e2836132f3565b915061345d602084016132f3565b60008060008060008060a0878903121561370957600080fd5b613712876132f3565b9550613720602088016132f3565b94506040870135935060608701359250608087013567ffffffffffffffff81111561374a57600080fd5b61375689828a01613346565b979a9699509497509295939492505050565b600181811c9082168061377c57607f821691505b6020821081036137b5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610a7d57610a7d6137bb565b60008161380c5761380c6137bb565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b81810381811115610a7d57610a7d6137bb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036138a5576138a56137bb565b5060010190565b600082516138be818460208701613259565b9190910192915050565b6000602082840312156138da57600080fd5b815167ffffffffffffffff8111156138f157600080fd5b8201601f8101841361390257600080fd5b805161391061361e82613569565b81815285602083850101111561392557600080fd5b613936826020830160208601613259565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152611d20608083018461327d565b60006020828403121561399057600080fd5b81516114948161320e565b6000602082840312156139ad57600080fd5b815161149481613185565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220f171df3ce47537d7dae23553696273e736d1aebf974e802e61c3b79a41d6b79a64736f6c63430008180033", + Bin: "0x60a06040523480156200001157600080fd5b5060405162003d2638038062003d268339810160408190526200003491620000b4565b6040518060400160405280600c81526020016b23b0b6b29b9029ba30b5b2b960a11b81525060405180604001604052806008815260200167239ba9aa20a5a2a960c11b81525081600090816200008b91906200018d565b5060016200009a82826200018d565b50506001600a55506001600160a01b031660805262000259565b600060208284031215620000c757600080fd5b81516001600160a01b0381168114620000df57600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200011157607f821691505b6020821081036200013257634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000188576000816000526020600020601f850160051c81016020861015620001635750805b601f850160051c820191505b8181101562000184578281556001016200016f565b5050505b505050565b81516001600160401b03811115620001a957620001a9620000e6565b620001c181620001ba8454620000fc565b8462000138565b602080601f831160018114620001f95760008415620001e05750858301515b600019600386901b1c1916600185901b17855562000184565b600085815260208120601f198616915b828110156200022a5788860151825594840194600190910190840162000209565b5085821015620002495787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b608051613aaa6200027c600039600081816108080152611c770152613aaa6000f3fe6080604052600436106102845760003560e01c806373dfccca11610153578063b0fe4a7e116100cb578063d693595d1161007f578063e985e9c511610064578063e985e9c51461084a578063f09e76a1146108a0578063f23a6e61146108b657600080fd5b8063d693595d146107f6578063df44bf761461082a57600080fd5b8063b88d4fde116100b0578063b88d4fde146107a1578063c87b56dd146107c1578063d2ba4409146107e157600080fd5b8063b0fe4a7e14610754578063b29087da1461077457600080fd5b806395d89b4111610122578063a22cb46511610107578063a22cb465146106fe578063abd4ce781461071e578063ae5ac9211461073457600080fd5b806395d89b41146106d6578063a1ed8fef146106eb57600080fd5b806373dfccca146105aa57806377bd2e781461067457806381c822e6146106895780638d4a9e85146106b657600080fd5b80632f745c59116102015780634f6ccce7116101b55780636352211e1161019a5780636352211e1461050857806370a082311461052857806373caf0f71461054857600080fd5b80634f6ccce7146104c8578063621519c0146104e857600080fd5b80633db26319116101e65780633db2631914610472578063424b93111461049257806342842e0e146104a857600080fd5b80632f745c591461043c5780633ab0f1c11461045c57600080fd5b8063095ea7b31161025857806318160ddd1161023d57806318160ddd146103dd57806323b872dd146103fc5780632e17de781461041c57600080fd5b8063095ea7b314610347578063150b7a021461036757600080fd5b80627d0cec1461028957806301ffc9a7146102ab57806306fdde03146102e0578063081812fc14610302575b600080fd5b34801561029557600080fd5b506102a96102a4366004613220565b6108fc565b005b3480156102b757600080fd5b506102cb6102c63660046132c9565b610a27565b60405190151581526020015b60405180910390f35b3480156102ec57600080fd5b506102f5610a83565b6040516102d79190613354565b34801561030e57600080fd5b5061032261031d366004613367565b610b15565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102d7565b34801561035357600080fd5b506102a96103623660046133a9565b610b4b565b34801561037357600080fd5b506103ac61038236600461341c565b7f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016102d7565b3480156103e957600080fd5b506008545b6040519081526020016102d7565b34801561040857600080fd5b506102a961041736600461348b565b610b5a565b34801561042857600080fd5b506102a9610437366004613367565b610bcf565b34801561044857600080fd5b506103ee6104573660046133a9565b611069565b34801561046857600080fd5b506103ee600c5481565b34801561047e57600080fd5b506102a961048d3660046134c7565b611101565b34801561049e57600080fd5b506103ee600b5481565b3480156104b457600080fd5b506102a96104c336600461348b565b6111fc565b3480156104d457600080fd5b506103ee6104e3366004613367565b61121c565b3480156104f457600080fd5b506103ee6105033660046134f3565b61128e565b34801561051457600080fd5b50610322610523366004613367565b61149c565b34801561053457600080fd5b506103ee610543366004613526565b6114a7565b34801561055457600080fd5b5061058a610563366004613367565b60106020526000908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016102d7565b3480156105b657600080fd5b5061061f6105c5366004613367565b600f60205260009081526040902080546001820154600283015460038401546004850154600586015460069096015473ffffffffffffffffffffffffffffffffffffffff95861696949590931693919260ff909116919087565b6040805173ffffffffffffffffffffffffffffffffffffffff98891681526020810197909752949096169385019390935260608401919091521515608083015260a082015260c081019190915260e0016102d7565b34801561068057600080fd5b506103ee600181565b34801561069557600080fd5b506103ee6106a4366004613367565b600d6020526000908152604090205481565b3480156106c257600080fd5b506103ee6106d13660046134f3565b611522565b3480156106e257600080fd5b506102f561169d565b6103ee6106f93660046133a9565b6116ac565b34801561070a57600080fd5b506102a9610719366004613541565b61185c565b34801561072a57600080fd5b506103ee61048381565b34801561074057600080fd5b506102a961074f366004613367565b611867565b34801561076057600080fd5b506103ee61076f3660046134f3565b6119c7565b34801561078057600080fd5b506103ee61078f366004613367565b600e6020526000908152604090205481565b3480156107ad57600080fd5b506102a96107bc36600461363c565b611b93565b3480156107cd57600080fd5b506102f56107dc366004613367565b611bb0565b3480156107ed57600080fd5b506103ee601481565b34801561080257600080fd5b506103227f000000000000000000000000000000000000000000000000000000000000000081565b34801561083657600080fd5b506102a96108453660046136e7565b611db7565b34801561085657600080fd5b506102cb610865366004613753565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260056020908152604080832093909416825291909152205460ff1690565b3480156108ac57600080fd5b506103ee6102d181565b3480156108c257600080fd5b506103ac6108d136600461377d565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b6000878152600f60205260409020805473ffffffffffffffffffffffffffffffffffffffff16331461095a576040517f29f9fc8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b861561098f576004810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168715151790555b841561099d57600581018490555b82156109ab57600681018290555b80546004820154600583015460068401546040805160ff9094161515845260208401929092529082015273ffffffffffffffffffffffffffffffffffffffff9091169089907f8587d3b7f5e8e73d0f5be513ce84b6c7c9497e221295d831f57ba7ecc36589b59060600160405180910390a35050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d63000000000000000000000000000000000000000000000000000000001480610a7d5750610a7d82612113565b92915050565b606060008054610a92906137f5565b80601f0160208091040260200160405190810160405280929190818152602001828054610abe906137f5565b8015610b0b5780601f10610ae057610100808354040283529160200191610b0b565b820191906000526020600020905b815481529060010190602001808311610aee57829003601f168201915b5050505050905090565b6000610b20826121f6565b5060008281526004602052604090205473ffffffffffffffffffffffffffffffffffffffff16610a7d565b610b56828233612255565b5050565b600081815260106020908152604080832080548452600f909252909120600481015460ff16610bbd576040517f2ed602a6000000000000000000000000000000000000000000000000000000008152600481018490526024015b60405180910390fd5b610bc8858585612262565b5050505050565b610bd761234d565b600081815260106020908152604080832080548452600f90925282209091610bfe8461149c565b905073ffffffffffffffffffffffffffffffffffffffff81163314801590610c3d5750815473ffffffffffffffffffffffffffffffffffffffff163314155b15610c92576040517f5a4c507400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152336024820152604401610bb4565b600682015415610d035760038301541580610cbf575081600601548360030154610cbc9190613877565b42105b15610cfe5781600601546040517f2098e24d000000000000000000000000000000000000000000000000000000008152600401610bb491815260200190565b610d67565b81600501548360020154610d179190613877565b421015610d675781600501548360020154610d329190613877565b6040517f9dc1207c000000000000000000000000000000000000000000000000000000008152600401610bb491815260200190565b6102d1826001015403610d9a5782546000908152600d60205260408120805491610d908361388a565b9190505550610dc5565b600183015483546000908152600d602052604081208054909190610dbf9084906138bf565b90915550505b82546000908152600e60205260408120805491610de18361388a565b909155505060018301548354604080518781526020810184905273ffffffffffffffffffffffffffffffffffffffff8516917fffdaf13b1d96bfc2213355f353f84c19493e0681eb0df26f83d862acd266750a910160405180910390a36000858152601060205260408120818155600181018290556002810182905560030155610e6a85612390565b6001836001015403610ebf5760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610eb9573d6000803e3d6000fd5b50611058565b6014836001015403610ef6576002830154610ef19073ffffffffffffffffffffffffffffffffffffffff1683836123f1565b611058565b6102d1836001015403610f9c5760028301546040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff848116602483015260448201849052909116906342842e0e90606401600060405180830381600087803b158015610f7f57600080fd5b505af1158015610f93573d6000803e3d6000fd5b50505050611058565b61048383600101540361105857600283015460038401546040517ff242432a00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff858116602483015260448201929092526064810184905260a06084820152600060a482015291169063f242432a9060c401600060405180830381600087803b15801561103f57600080fd5b505af1158015611053573d6000803e3d6000fd5b505050505b505050506110666001600a55565b50565b6000611074836114a7565b82106110cb576040517fa57d13dc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260248101839052604401610bb4565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600660209081526040808320938352929052205490565b6000828152600f60205260409020805473ffffffffffffffffffffffffffffffffffffffff16331461115f576040517f29f9fc8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811782556004820154600583015460068401546040805160ff9094161515845260208401929092529082015284907f8587d3b7f5e8e73d0f5be513ce84b6c7c9497e221295d831f57ba7ecc36589b5906060015b60405180910390a3505050565b61121783838360405180602001604052806000815250611b93565b505050565b600061122760085490565b8210611269576040517fa57d13dc0000000000000000000000000000000000000000000000000000000081526000600482015260248101839052604401610bb4565b6008828154811061127c5761127c6138d2565b90600052602060002001549050919050565b600061129861234d565b6000838152600f6020526040902060018101546102d1146112fd5760018101546040517f323b95bb0000000000000000000000000000000000000000000000000000000081526004810186905260248101919091526102d16044820152606401610bb4565b600c805490600061130d83613901565b9091555060408051608081018252868152602080820187815242838501908152600060608501818152878252601085528682209551865592516001860155905160028501559051600390930192909255878252600d905290812080549294509061137683613901565b90915550506000848152600e6020526040812080549161139583613901565b909155505060028101546040517f42842e0e0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810185905273ffffffffffffffffffffffffffffffffffffffff909116906342842e0e906064015b600060405180830381600087803b15801561141557600080fd5b505af1158015611429573d6000803e3d6000fd5b505050506114378583612472565b6040805183815260208101859052859173ffffffffffffffffffffffffffffffffffffffff8816917f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a32910160405180910390a3506114956001600a55565b9392505050565b6000610a7d826121f6565b600073ffffffffffffffffffffffffffffffffffffffff82166114f9576040517f89c62b6400000000000000000000000000000000000000000000000000000000815260006004820152602401610bb4565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b600061152c61234d565b6000838152600f60205260409020600181015460141461158f5760018101546040517f323b95bb00000000000000000000000000000000000000000000000000000000815260048101869052602481019190915260146044820152606401610bb4565b826000036115c9576040517fd23fa2a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c80549060006115d983613901565b9091555060408051608081018252868152602080820187815242838501908152600060608501818152878252601085528682209551865592516001860155905160028501559051600390930192909255878252600d905290812080549294508592909190611648908490613877565b90915550506000848152600e6020526040812080549161166783613901565b909155505060028101546116939073ffffffffffffffffffffffffffffffffffffffff16333086612523565b6114378583612472565b606060018054610a92906137f5565b60006116b661234d565b6000828152600f602052604090206001808201541461171a576001818101546040517f323b95bb0000000000000000000000000000000000000000000000000000000081526004810186905260248101919091526044810191909152606401610bb4565b34600003611754576040517fd23fa2a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c805490600061176483613901565b909155506040805160808101825285815234602080830182815242848601908152600060608601818152888252601085528782209651875592516001870155905160028601559051600390940193909355878352600d9052918120805493955091926117d1908490613877565b90915550506000838152600e602052604081208054916117f083613901565b91905055506117ff8483612472565b60408051838152346020820152849173ffffffffffffffffffffffffffffffffffffffff8716917f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a32910160405180910390a350610a7d6001600a55565b610b56338383612569565b61186f61234d565b600061187a8261149c565b600083815260106020908152604080832080548452600f9092529091209192509073ffffffffffffffffffffffffffffffffffffffff831633148015906118d85750805473ffffffffffffffffffffffffffffffffffffffff163314155b1561192d576040517f5a4c507400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152336024820152604401610bb4565b806005015482600201546119419190613877565b42101561195c5780600501548260020154610d329190613877565b81600301546000036119ba5742600383015560405184815273ffffffffffffffffffffffffffffffffffffffff8416907fb88af44ff67f15b82bc60b5ecd6ac0f0c27da279a6c21b7d200174756ea5c5e49060200160405180910390a25b5050506110666001600a55565b60006119d161234d565b6000838152600f60205260409020600181015461048314611a365760018101546040517f323b95bb0000000000000000000000000000000000000000000000000000000081526004810186905260248101919091526104836044820152606401610bb4565b82600003611a70576040517fd23fa2a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054906000611a8083613901565b9091555060408051608081018252868152602080820187815242838501908152600060608501818152878252601085528682209551865592516001860155905160028501559051600390930192909255878252600d905290812080549294508592909190611aef908490613877565b90915550506000848152600e60205260408120805491611b0e83613901565b9091555050600281015460038201546040517ff242432a00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101919091526064810185905260a06084820152600060a482015273ffffffffffffffffffffffffffffffffffffffff9091169063f242432a9060c4016113fb565b611b9e848484610b5a565b611baa8484848461265e565b50505050565b6060611bbb826121f6565b5060008281526010602090815260408083208054808552600f90935281842091516024810187905260448101939093526001808201546064850152600280830154608486015260038084015460a4870152845473ffffffffffffffffffffffffffffffffffffffff90811660c48801529285015460e4870152908401548216610104860152830154610124850152600483015460ff161515610144850152600583015461016485015260068301546101848501529093919282917f000000000000000000000000000000000000000000000000000000000000000016906101a401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7b2f34ff0000000000000000000000000000000000000000000000000000000017905251611d1d9190613939565b600060405180830381855afa9150503d8060008114611d58576040519150601f19603f3d011682016040523d82523d6000602084013e611d5d565b606091505b509150915081611d99576040517f0e8d7e7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80806020019051810190611dad9190613955565b9695505050505050565b60018703611e1e5773ffffffffffffffffffffffffffffffffffffffff8616151580611de257508415155b15611e19576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f63565b60148703611e7c5773ffffffffffffffffffffffffffffffffffffffff86161580611de257508415611e19576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102d18703611edb5773ffffffffffffffffffffffffffffffffffffffff86161580611de257508415611e19576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104838703611f315773ffffffffffffffffffffffffffffffffffffffff8616611e19576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa1e9dd9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff838116825260208083018b81528a8316848601818152606086018c81528b15156080880190815260a088018c815260c089018c8152600b80546000908152600f8a528c90209a518b547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116918c16919091178c55975160018c0155945160028b01805490981699169890981790955590516003880155516004870180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790559151600586015592516006909401939093559154925188815290928a9290917f36b06296d9441695787e7cbfc0b9cfc5deeeabec4406a3a90d30a222103c2dc8910160405180910390a4600b546040805186151581526020810186905290810184905273ffffffffffffffffffffffffffffffffffffffff831691907f8587d3b7f5e8e73d0f5be513ce84b6c7c9497e221295d831f57ba7ecc36589b59060600160405180910390a3600b805490600061210583613901565b919050555050505050505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd0000000000000000000000000000000000000000000000000000000014806121a657507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610a7d57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610a7d565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610a7d576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101849052602401610bb4565b611217838383600161284e565b73ffffffffffffffffffffffffffffffffffffffff82166122b2576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260006004820152602401610bb4565b60006122bf838333612a19565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611baa576040517f64283d7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80861660048301526024820184905282166044820152606401610bb4565b6002600a5403612389576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600a55565b600061239f6000836000612a19565b905073ffffffffffffffffffffffffffffffffffffffff8116610b56576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101839052602401610bb4565b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301526044820183905261121791859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b3c565b73ffffffffffffffffffffffffffffffffffffffff82166124c2576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260006004820152602401610bb4565b60006124d083836000612a19565b905073ffffffffffffffffffffffffffffffffffffffff811615611217576040517f73c6ac6e00000000000000000000000000000000000000000000000000000000815260006004820152602401610bb4565b60405173ffffffffffffffffffffffffffffffffffffffff8481166024830152838116604483015260648201839052611baa9186918216906323b872dd9060840161242b565b73ffffffffffffffffffffffffffffffffffffffff82166125ce576040517f5b08ba1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610bb4565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3191016111ef565b73ffffffffffffffffffffffffffffffffffffffff83163b15611baa576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84169063150b7a02906126d39033908890879087906004016139cc565b6020604051808303816000875af192505050801561272c575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261272991810190613a0b565b60015b6127bb573d80801561275a576040519150601f19603f3d011682016040523d82523d6000602084013e61275f565b606091505b5080516000036127b3576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610bb4565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a020000000000000000000000000000000000000000000000000000000014610bc8576040517f64a0ae9200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610bb4565b808061286f575073ffffffffffffffffffffffffffffffffffffffff821615155b156129c457600061287f846121f6565b905073ffffffffffffffffffffffffffffffffffffffff8316158015906128d257508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015612911575073ffffffffffffffffffffffffffffffffffffffff80821660009081526005602090815260408083209387168352929052205460ff16155b15612960576040517fa9fbf51f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610bb4565b81156129c257838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600080612a27858585612bd2565b905073ffffffffffffffffffffffffffffffffffffffff8116612a9157612a8c84600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b612ace565b8473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612ace57612ace8185612d4f565b73ffffffffffffffffffffffffffffffffffffffff8516612af757612af284612dfa565b612b34565b8473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612b3457612b348585612ea9565b949350505050565b6000612b5e73ffffffffffffffffffffffffffffffffffffffff841683612f06565b90508051600014158015612b83575080806020019051810190612b819190613a28565b155b15611217576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610bb4565b60008281526002602052604081205473ffffffffffffffffffffffffffffffffffffffff90811690831615612c0c57612c0c818486612f14565b73ffffffffffffffffffffffffffffffffffffffff811615612c8257612c3660008560008061284e565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555b73ffffffffffffffffffffffffffffffffffffffff851615612ccb5773ffffffffffffffffffffffffffffffffffffffff85166000908152600360205260409020805460010190555b60008481526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff89811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6000612d5a836114a7565b600083815260076020526040902054909150808214612dba5773ffffffffffffffffffffffffffffffffffffffff841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b50600091825260076020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600681528383209183525290812055565b600854600090612e0c906001906138bf565b60008381526009602052604081205460088054939450909284908110612e3457612e346138d2565b906000526020600020015490508060088381548110612e5557612e556138d2565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480612e8d57612e8d613a45565b6001900381819060005260206000200160009055905550505050565b60006001612eb6846114a7565b612ec091906138bf565b73ffffffffffffffffffffffffffffffffffffffff9093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b606061149583836000612fc4565b612f1f83838361307d565b6112175773ffffffffffffffffffffffffffffffffffffffff8316612f73576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101829052602401610bb4565b6040517f177e802f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260248101829052604401610bb4565b606081471015613002576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401610bb4565b6000808573ffffffffffffffffffffffffffffffffffffffff16848660405161302b9190613939565b60006040518083038185875af1925050503d8060008114613068576040519150601f19603f3d011682016040523d82523d6000602084013e61306d565b606091505b5091509150611dad868383613141565b600073ffffffffffffffffffffffffffffffffffffffff831615801590612b3457508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061310b575073ffffffffffffffffffffffffffffffffffffffff80851660009081526005602090815260408083209387168352929052205460ff165b80612b3457505060009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff908116911614919050565b60608261315657613151826131d0565b611495565b815115801561317a575073ffffffffffffffffffffffffffffffffffffffff84163b155b156131c9576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610bb4565b5080611495565b8051156131e05780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801515811461106657600080fd5b600080600080600080600060e0888a03121561323b57600080fd5b87359650602088013561324d81613212565b9550604088013561325d81613212565b9450606088013561326d81613212565b93506080880135925060a088013561328481613212565b8092505060c0880135905092959891949750929550565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461106657600080fd5b6000602082840312156132db57600080fd5b81356114958161329b565b60005b838110156133015781810151838201526020016132e9565b50506000910152565b600081518084526133228160208601602086016132e6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611495602083018461330a565b60006020828403121561337957600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146133a457600080fd5b919050565b600080604083850312156133bc57600080fd5b6133c583613380565b946020939093013593505050565b60008083601f8401126133e557600080fd5b50813567ffffffffffffffff8111156133fd57600080fd5b60208301915083602082850101111561341557600080fd5b9250929050565b60008060008060006080868803121561343457600080fd5b61343d86613380565b945061344b60208701613380565b935060408601359250606086013567ffffffffffffffff81111561346e57600080fd5b61347a888289016133d3565b969995985093965092949392505050565b6000806000606084860312156134a057600080fd5b6134a984613380565b92506134b760208501613380565b9150604084013590509250925092565b600080604083850312156134da57600080fd5b823591506134ea60208401613380565b90509250929050565b60008060006060848603121561350857600080fd5b61351184613380565b95602085013595506040909401359392505050565b60006020828403121561353857600080fd5b61149582613380565b6000806040838503121561355457600080fd5b61355d83613380565b9150602083013561356d81613212565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156135ee576135ee613578565b604052919050565b600067ffffffffffffffff82111561361057613610613578565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000806000806080858703121561365257600080fd5b61365b85613380565b935061366960208601613380565b925060408501359150606085013567ffffffffffffffff81111561368c57600080fd5b8501601f8101871361369d57600080fd5b80356136b06136ab826135f6565b6135a7565b8181528860208385010111156136c557600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b600080600080600080600060e0888a03121561370257600080fd5b8735965061371260208901613380565b955060408801359450606088013561372981613212565b93506080880135925060a0880135915061374560c08901613380565b905092959891949750929550565b6000806040838503121561376657600080fd5b61376f83613380565b91506134ea60208401613380565b60008060008060008060a0878903121561379657600080fd5b61379f87613380565b95506137ad60208801613380565b94506040870135935060608701359250608087013567ffffffffffffffff8111156137d757600080fd5b6137e389828a016133d3565b979a9699509497509295939492505050565b600181811c9082168061380957607f821691505b602082108103613842577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610a7d57610a7d613848565b60008161389957613899613848565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b81810381811115610a7d57610a7d613848565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361393257613932613848565b5060010190565b6000825161394b8184602087016132e6565b9190910192915050565b60006020828403121561396757600080fd5b815167ffffffffffffffff81111561397e57600080fd5b8201601f8101841361398f57600080fd5b805161399d6136ab826135f6565b8181528560208385010111156139b257600080fd5b6139c38260208301602086016132e6565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152611dad608083018461330a565b600060208284031215613a1d57600080fd5b81516114958161329b565b600060208284031215613a3a57600080fd5b815161149581613212565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220e30d591d4f6478d3d1270fcdf8ad140982ae03d875a201932aa481aa07dd2a2764736f6c63430008180033", } // StakerABI is the input ABI used to generate the binding from. diff --git a/bindings/security/terminus/TerminusFacet/TerminusFacet.go b/bindings/security/terminus/TerminusFacet/TerminusFacet.go new file mode 100644 index 00000000..54358138 --- /dev/null +++ b/bindings/security/terminus/TerminusFacet/TerminusFacet.go @@ -0,0 +1,9153 @@ +// This file was generated by seer: https://github.com/G7DAO/seer. +// seer version: 0.3.5 +// seer command: seer evm generate --package TerminusFacet --cli --struct TerminusFacet --output bindings/security/terminus/TerminusFacet/TerminusFacet.go +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package TerminusFacet + +import ( + "bytes" + "crypto/rand" + "errors" + "math/big" + "net/http" + "strings" + + "context" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + + // Reference imports to suppress errors if they are not otherwise used. + "encoding/hex" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/G7DAO/seer/bindings/CreateCall" + "github.com/G7DAO/seer/bindings/GnosisSafe" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" + "golang.org/x/term" + + // TerminusFacetMetaData contains all meta data concerning the TerminusFacet contract. + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var TerminusFacetMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousController\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newController\",\"type\":\"address\"}],\"name\":\"ControlTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousController\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newController\",\"type\":\"address\"}],\"name\":\"PoolControlTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"toAddresses\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"PoolMintBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"approveForPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"contractURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_capacity\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_transferable\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_burnable\",\"type\":\"bool\"}],\"name\":\"createPoolV1\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_capacity\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_transferable\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_burnable\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"poolURI\",\"type\":\"string\"}],\"name\":\"createPoolV2\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_capacity\",\"type\":\"uint256\"}],\"name\":\"createSimplePool\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForPool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"poolIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"mintBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paymentToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"poolBasePrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"}],\"name\":\"poolIsBurnable\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"}],\"name\":\"poolIsTransferable\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"toAddresses\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"poolMintBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_contractURI\",\"type\":\"string\"}],\"name\":\"setContractURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newController\",\"type\":\"address\"}],\"name\":\"setController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newPaymentToken\",\"type\":\"address\"}],\"name\":\"setPaymentToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newBasePrice\",\"type\":\"uint256\"}],\"name\":\"setPoolBasePrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"burnable\",\"type\":\"bool\"}],\"name\":\"setPoolBurnable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newController\",\"type\":\"address\"}],\"name\":\"setPoolController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"transferable\",\"type\":\"bool\"}],\"name\":\"setPoolTransferable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"poolURI\",\"type\":\"string\"}],\"name\":\"setURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"terminusController\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"}],\"name\":\"terminusPoolCapacity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"}],\"name\":\"terminusPoolController\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"}],\"name\":\"terminusPoolSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalPools\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"unapproveForPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolID\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"toAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawPayments\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5060007ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1080546001600160a01b0319163317905550615180806100546000396000f3fe608060405234801561001057600080fd5b50600436106102915760003560e01c806378cf2e8411610160578063ab3c7e52116100d8578063e8a3d4851161008c578063f242432a11610071578063f242432a14610743578063f3dc0a8514610756578063f5298aca1461076957600080fd5b8063e8a3d485146106d3578063e985e9c5146106db57600080fd5b8063d0c402e5116100bd578063d0c402e514610663578063dc55d0b2146106b8578063e1c7392a146106cb57600080fd5b8063ab3c7e5214610629578063b507ef521461065057600080fd5b80638925d0131161012f578063938e3d7b11610114578063938e3d7b146105c4578063a22cb465146105d7578063a44cfc82146105ea57600080fd5b80638925d0131461058a57806392eefe9b146105b157600080fd5b806378cf2e841461053e57806384fa03a11461055157806385bc82e214610564578063862440e21461057757600080fd5b80632eb2c2d61161020e5780634e1273f4116101c257806369453ce9116101a757806369453ce9146104d55780636a326ab114610518578063731133e91461052b57600080fd5b80634e1273f4146104765780635dc8bdf81461049657600080fd5b8063366e59e3116101f3578063366e59e3146103e45780633bad2d82146104215780633c50a3c51461043457600080fd5b80632eb2c2d6146103735780633013ce291461038657600080fd5b80630e89341c116102655780631fbeae861161024a5780631fbeae861461033a57806321adca961461034d5780632365c8591461036057600080fd5b80630e89341c146103075780631f7fdffa1461032757600080fd5b8062fdd58e1461029657806301ffc9a7146102bc578063027b3fc2146102df5780630e7afec5146102f2575b600080fd5b6102a96102a436600461441f565b61077c565b6040519081526020015b60405180910390f35b6102cf6102ca366004614477565b61087d565b60405190151581526020016102b3565b6102cf6102ed366004614494565b610960565b61030561030036600461441f565b610973565b005b61031a6103153660046144c0565b610af3565b6040516102b3919061453d565b6103056103353660046146f6565b610bb4565b610305610348366004614494565b610c86565b61030561035b366004614801565b610d0c565b61030561036e36600461487c565b6111c4565b6103056103813660046148ac565b61122b565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd125473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102b3565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd105473ffffffffffffffffffffffffffffffffffffffff166103bf565b6102a961042f366004614956565b611364565b6102cf6104423660046144c0565b60009081527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1a602052604090205460ff1690565b610489610484366004614998565b611710565b6040516102b39190614a38565b6102a96104a43660046144c0565b60009081527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd16602052604090205490565b6102cf6104e33660046144c0565b60009081527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd19602052604090205460ff161590565b610305610526366004614a4b565b611860565b610305610539366004614a66565b6118ce565b61030561054c3660046144c0565b611970565b6102a961055f366004614abb565b61199c565b610305610572366004614494565b611d64565b610305610585366004614b0f565b611de9565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd13546102a9565b6103056105bf366004614a4b565b611e4c565b6103056105d2366004614b4c565b611e60565b6103056105e5366004614b81565b611eb9565b6102a96105f83660046144c0565b60009081527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd17602052604090205490565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd11546102a9565b6102a961065e3660046144c0565b611ec4565b6103bf6106713660046144c0565b60009081527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd14602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b6103056106c6366004614494565b6121eb565b6103056121ff565b61031a612313565b6102cf6106e9366004614bad565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1b6020908152604080832093909416825291909152205460ff1690565b610305610751366004614bd7565b6123c7565b61030561076436600461487c565b6124e3565b610305610777366004614c3c565b612549565b600073ffffffffffffffffffffffffffffffffffffffff8316610826576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f45524331313535576974685465726d696e757353746f726167653a2062616c6160448201527f6e636520717565727920666f7220746865207a65726f2061646472657373000060648201526084015b60405180910390fd5b5060008181527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd186020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091529020545b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fd9b67a2600000000000000000000000000000000000000000000000000000000148061091057507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e89341c00000000000000000000000000000000000000000000000000000000145b8061087757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610877565b600061096c838361260a565b9392505050565b61097b6126d2565b3373ffffffffffffffffffffffffffffffffffffffff831614610a46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604760248201527f5465726d696e757346616365743a2077697468647261775061796d656e74732060448201527f2d2d20436f6e74726f6c6c65722063616e206f6e6c792077697468647261772060648201527f746f2073656c6600000000000000000000000000000000000000000000000000608482015260a40161081d565b6000610a50612773565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018590529192509082169063a9059cbb906044016020604051808303816000875af1158015610ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aed9190614c6f565b50505050565b60008181527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1560205260409020805460609190610b2f90614c8c565b80601f0160208091040260200160405190810160405280929190818152602001828054610b5b90614c8c565b8015610ba85780601f10610b7d57610100808354040283529160200191610ba8565b820191906000526020600020905b815481529060010190602001808311610b8b57829003601f168201915b50505050509050919050565b60005b8351811015610c7957610be3848281518110610bd557610bd5614cdf565b602002602001015133610960565b610c7157604080517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482015260248101919091527f5465726d696e757346616365743a206d696e744261746368202d2d2063616c6c60448201527f6572206973206e656974686572206f776e6572206e6f7220617070726f766564606482015260840161081d565b600101610bb7565b50610aed84848484612840565b610c908233612c6e565b60008281527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1c6020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050565b5050565b8051825114610dc3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604860248201527f5465726d696e757346616365743a205f706f6f6c4d696e744261746368202d2d60448201527f20746f41646472657373657320616e6420616d6f756e7473206c656e6774682060648201527f6d69736d61746368000000000000000000000000000000000000000000000000608482015260a40161081d565b33610dce8482610960565b610e81576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526044602482018190527f5465726d696e757346616365743a20706f6f6c4d696e744261746368202d2d20908201527f63616c6c6572206973206e656974686572206f776e6572206e6f72206170707260648201527f6f76656400000000000000000000000000000000000000000000000000000000608482015260a40161081d565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd106000805b8551821015611062576000868381518110610ec357610ec3614cdf565b602002602001015190506000868481518110610ee157610ee1614cdf565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610fa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603c60248201527f5465726d696e757346616365743a205f706f6f6c4d696e744261746368202d2d60448201527f2063616e6e6f74206d696e7420746f207a65726f206164647265737300000000606482015260840161081d565b610fb18184614d3d565b60008a8152600887016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812080549295508392909190610ff7908490614d3d565b9091555050604080518a81526020810183905273ffffffffffffffffffffffffffffffffffffffff80851692600092918a16917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a45050600190910190610ea6565b6000878152600684016020908152604080832054600787019092529091205461108c908390614d3d565b1115611140576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f5465726d696e757346616365743a205f706f6f6c4d696e744261746368202d2d60448201527f204d696e74656420746f6b656e7320776f756c642065786365656420706f6f6c60648201527f2063617061636974790000000000000000000000000000000000000000000000608482015260a40161081d565b600087815260078401602052604081208054839290611160908490614d3d565b925050819055508373ffffffffffffffffffffffffffffffffffffffff16877fba62777935b5e992de16a785941daef9f13517ff268a40563288072025b50238600089896040516111b393929190614d50565b60405180910390a350505050505050565b6111ce8233612c6e565b60009182527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1a602052604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b73ffffffffffffffffffffffffffffffffffffffff851633148061129e575073ffffffffffffffffffffffffffffffffffffffff851660009081527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1b6020908152604080832033845290915290205460ff165b611350576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604560248201527f45524331313535576974685465726d696e757353746f726167653a207472616e60448201527f736665722063616c6c6572206973206e6f74206f776e6572206e6f722061707060648201527f726f766564000000000000000000000000000000000000000000000000000000608482015260a40161081d565b61135d8585858585612d64565b5050505050565b600061136e6126d2565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd13547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1090801561167a5760006113c2612773565b90508173ffffffffffffffffffffffffffffffffffffffff821663dd62ed3e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152306024820152604401602060405180830381865afa158015611451573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114759190614dcd565b1015611529576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f5465726d696e757346616365743a20637265617465506f6f6c5631202d2d204960448201527f6e73756666696369656e7420616c6c6f77616e6365206f6e207061796d656e7460648201527f20746f6b656e0000000000000000000000000000000000000000000000000000608482015260a40161081d565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810183905273ffffffffffffffffffffffffffffffffffffffff8216906323b872dd906064016020604051808303816000875af11580156115a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c69190614c6f565b611678576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f5465726d696e757346616365743a20637265617465506f6f6c5631202d2d205460448201527f72616e73666572206f66207061796d656e7420746f6b656e2077617320756e7360648201527f75636365737366756c0000000000000000000000000000000000000000000000608482015260a40161081d565b505b6000611685876131f6565b9050856116c6576000818152600984016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b8415611706576000818152600a84016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b9695505050505050565b606081518351146117a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603c60248201527f45524331313535576974685465726d696e757353746f726167653a206163636f60448201527f756e747320616e6420696473206c656e677468206d69736d6174636800000000606482015260840161081d565b6000835167ffffffffffffffff8111156117bf576117bf614550565b6040519080825280602002602001820160405280156117e8578160200160208202803683370190505b50905060005b84518110156118585761183385828151811061180c5761180c614cdf565b602002602001015185838151811061182657611826614cdf565b602002602001015161077c565b82828151811061184557611845614cdf565b60209081029190910101526001016117ee565b509392505050565b6118686126d2565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6118d88333610960565b611964576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f5465726d696e757346616365743a206d696e74202d2d2063616c6c657220697360448201527f206e656974686572206f776e6572206e6f7220617070726f7665640000000000606482015260840161081d565b610aed84848484613286565b6119786126d2565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1355565b60006119a66126d2565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd13547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd10908015611cb25760006119fa612773565b90508173ffffffffffffffffffffffffffffffffffffffff821663dd62ed3e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152306024820152604401602060405180830381865afa158015611a89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aad9190614dcd565b1015611b61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604660248201527f5465726d696e757346616365743a20637265617465506f6f6c5632202d2d204960448201527f6e73756666696369656e7420616c6c6f77616e6365206f6e207061796d656e7460648201527f20746f6b656e0000000000000000000000000000000000000000000000000000608482015260a40161081d565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810183905273ffffffffffffffffffffffffffffffffffffffff8216906323b872dd906064016020604051808303816000875af1158015611bda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfe9190614c6f565b611cb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f5465726d696e757346616365743a20637265617465506f6f6c5632202d2d205460448201527f72616e73666572206f66207061796d656e7420746f6b656e2077617320756e7360648201527f75636365737366756c0000000000000000000000000000000000000000000000608482015260a40161081d565b505b6000611cbd886131f6565b905086611cfe576000818152600984016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b8515611d3e576000818152600a84016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b60008181526005840160205260409020611d588682614e2e565b50979650505050505050565b611d6e8233612c6e565b60008281527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1c6020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555050565b611df38233612c6e565b60008281527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd15602052604090207ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1090610aed8382614e2e565b611e546126d2565b611e5d81613551565b50565b611e686126d2565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd107ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1d611eb48382614e2e565b505050565b610d083383836135e7565b6000611ece6126d2565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd13547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd109080156121da576000611f22612773565b90508173ffffffffffffffffffffffffffffffffffffffff821663dd62ed3e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152306024820152604401602060405180830381865afa158015611fb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd59190614dcd565b1015612089576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f5465726d696e757346616365743a2063726561746553696d706c65506f6f6c2060448201527f2d2d20496e73756666696369656e7420616c6c6f77616e6365206f6e2070617960648201527f6d656e7420746f6b656e00000000000000000000000000000000000000000000608482015260a40161081d565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810183905273ffffffffffffffffffffffffffffffffffffffff8216906323b872dd906064016020604051808303816000875af1158015612102573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121269190614c6f565b6121d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f5465726d696e757346616365743a2063726561746553696d706c65506f6f6c2060448201527f2d2d205472616e73666572206f66207061796d656e7420746f6b656e2077617360648201527f20756e7375636365737366756c00000000000000000000000000000000000000608482015260a40161081d565b505b6121e3846131f6565b949350505050565b6121f58233612c6e565b610d08828261377e565b612207613844565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f6020527f845f7f8d885943dffdc1524acbd9538b2923f93aad26d306df3b8982c7f0632d805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092557f0e89341c000000000000000000000000000000000000000000000000000000006000527fcda23395996795f7b8155822fcc6171125c877448c68566f10ccabd60b06eb27805490911690911790557ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055565b60607ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd10600d01805461234490614c8c565b80601f016020809104026020016040519081016040528092919081815260200182805461237090614c8c565b80156123bd5780601f10612392576101008083540402835291602001916123bd565b820191906000526020600020905b8154815290600101906020018083116123a057829003601f168201915b5050505050905090565b73ffffffffffffffffffffffffffffffffffffffff851633148061243a575073ffffffffffffffffffffffffffffffffffffffff851660009081527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1b6020908152604080832033845290915290205460ff165b8061244a575061244a8333610960565b6124d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603c60248201527f45524331313535576974685465726d696e757353746f726167653a2063616c6c60448201527f6572206973206e6f74206f776e6572206e6f7220617070726f76656400000000606482015260840161081d565b61135d858585858561390f565b6124ed8233612c6e565b60009182527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd19602052604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115919091179055565b3373ffffffffffffffffffffffffffffffffffffffff841681148061257357506125738382610960565b6125ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f5465726d696e757346616365743a206275726e202d2d2063616c6c657220697360448201527f206e656974686572206f776e6572206e6f7220617070726f7665640000000000606482015260840161081d565b610aed848484613c4f565b60008281527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1460205260408120547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd109073ffffffffffffffffffffffffffffffffffffffff90811690841603612684576001915050610877565b6000848152600c82016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915290205460ff16156126c8576001915050610877565b5060009392505050565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd10805473ffffffffffffffffffffffffffffffffffffffff163314611e5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4c69625465726d696e75733a204d75737420626520636f6e74726f6c6c657200604482015260640161081d565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd125460009073ffffffffffffffffffffffffffffffffffffffff168061283b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f5465726d696e757346616365743a205061796d656e7420746f6b656e2068617360448201527f206e6f74206265656e2073657400000000000000000000000000000000000000606482015260840161081d565b919050565b73ffffffffffffffffffffffffffffffffffffffff84166128e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f45524331313535576974685465726d696e757353746f726167653a206d696e7460448201527f20746f20746865207a65726f2061646472657373000000000000000000000000606482015260840161081d565b8151835114612974576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f45524331313535576974685465726d696e757353746f726167653a206964732060448201527f616e6420616d6f756e7473206c656e677468206d69736d617463680000000000606482015260840161081d565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd103360005b8551811015612bd7578260060160008783815181106129ba576129ba614cdf565b60200260200101518152602001908152602001600020548582815181106129e3576129e3614cdf565b6020026020010151846007016000898581518110612a0357612a03614cdf565b6020026020010151815260200190815260200160002054612a249190614d3d565b1115612ad8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605260248201527f45524331313535576974685465726d696e757353746f726167653a205f6d696e60448201527f744261746368202d2d204d696e74656420746f6b656e7320776f756c6420657860648201527f6365656420706f6f6c2063617061636974790000000000000000000000000000608482015260a40161081d565b848181518110612aea57612aea614cdf565b6020026020010151836007016000888481518110612b0a57612b0a614cdf565b602002602001015181526020019081526020016000206000828254612b2f9190614d3d565b92505081905550848181518110612b4857612b48614cdf565b6020026020010151836008016000888481518110612b6857612b68614cdf565b6020026020010151815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612bca9190614d3d565b9091555050600101612999565b508573ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8888604051612c4f929190614f48565b60405180910390a4612c6681600088888888613f53565b505050505050565b60008281527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1460205260409020547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd109073ffffffffffffffffffffffffffffffffffffffff838116911614611eb4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4c69625465726d696e75733a204d75737420626520706f6f6c20636f6e74726f60448201527f6c6c657200000000000000000000000000000000000000000000000000000000606482015260840161081d565b8151835114612df5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f45524331313535576974685465726d696e757353746f726167653a206964732060448201527f616e6420616d6f756e7473206c656e677468206d69736d617463680000000000606482015260840161081d565b73ffffffffffffffffffffffffffffffffffffffff8416612e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f45524331313535576974685465726d696e757353746f726167653a207472616e60448201527f7366657220746f20746865207a65726f20616464726573730000000000000000606482015260840161081d565b337ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1060005b8551811015613160576000868281518110612eda57612eda614cdf565b602002602001015190506000868381518110612ef857612ef8614cdf565b60209081029190910181015160008481526009870190925260409091205490915060ff1615612fcf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604e60248201527f45524331313535576974685465726d696e757353746f726167653a205f73616660448201527f6542617463685472616e7366657246726f6d202d2d20706f6f6c206973206e6f60648201527f74207472616e7366657261626c65000000000000000000000000000000000000608482015260a40161081d565b6000828152600885016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8e16845290915290205481811015613091576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f45524331313535576974685465726d696e757353746f726167653a20696e737560448201527f6666696369656e742062616c616e636520666f72207472616e73666572000000606482015260840161081d565b81810385600801600085815260200190815260200160002060008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508185600801600085815260200190815260200160002060008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461314c9190614d3d565b909155505060019093019250612ebd915050565b508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb88886040516131d7929190614f48565b60405180910390a46131ed828888888888613f53565b50505050505050565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd11546000907ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1090829061324a906001614d3d565b9050613256813361377e565b600081815260068301602052604081208590556001830180549161327983614f76565b9091555090949350505050565b73ffffffffffffffffffffffffffffffffffffffff8416613329576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f45524331313535576974685465726d696e757353746f726167653a206d696e7460448201527f20746f20746865207a65726f2061646472657373000000000000000000000000606482015260840161081d565b60008381527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1660209081526040808320547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd17909252909120547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1091906133b0908590614d3d565b1115613464576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f45524331313535576974685465726d696e757353746f726167653a205f6d696e60448201527f74202d2d204d696e74656420746f6b656e7320776f756c64206578636565642060648201527f706f6f6c20636170616369747900000000000000000000000000000000000000608482015260a40161081d565b3361347e8160008861347589614203565b61135d89614203565b60008581526007830160205260408120805486929061349e908490614d3d565b90915550506000858152600883016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8a168452909152812080548692906134e4908490614d3d565b9091555050604080518681526020810186905273ffffffffffffffffffffffffffffffffffffffff80891692600092918516917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4612c668160008888888861424e565b7ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1080547fffffffffffffffffffffffff0000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff848116918217845560405192169182907fa06677f7b64342b4bcbde423684dbdb5356acfe41ad0285b6ecbe6dc4bf427f290600090a3505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036136a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603c60248201527f45524331313535576974685465726d696e757353746f726167653a207365747460448201527f696e6720617070726f76616c2073746174757320666f722073656c6600000000606482015260840161081d565b73ffffffffffffffffffffffffffffffffffffffff83811660008181527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1b602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016861515908117909155825190815291517ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd109493927f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3192908290030190a350505050565b60008281527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd146020526040808220805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff00000000000000000000000000000000000000008316811790935592517ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd10949390911692839187917fbb8e9c3c4a526b28a6b555c4def50ebda6412e188a3836bb2fbe72fd3757844291a450505050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c6004015473ffffffffffffffffffffffffffffffffffffffff16331461390d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201527f6572000000000000000000000000000000000000000000000000000000000000606482015260840161081d565b565b73ffffffffffffffffffffffffffffffffffffffff84166139b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f45524331313535576974685465726d696e757353746f726167653a207472616e60448201527f7366657220746f20746865207a65726f20616464726573730000000000000000606482015260840161081d565b60008381527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1960205260409020547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd109060ff1615613ab8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604960248201527f45524331313535576974685465726d696e757353746f726167653a205f73616660448201527f655472616e7366657246726f6d202d2d20706f6f6c206973206e6f742074726160648201527f6e7366657261626c650000000000000000000000000000000000000000000000608482015260a40161081d565b33613ac881888861347589614203565b6000858152600883016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16845290915290205484811015613b8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603d60248201527f45524331313535576974685465726d696e757353746f726167653a20696e737560448201527f6666696369656e742062616c616e636520666f72207472616e73666572000000606482015260840161081d565b6000868152600884016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8c8116855292528083208885039055908916825281208054879290613bd8908490614d3d565b9091555050604080518781526020810187905273ffffffffffffffffffffffffffffffffffffffff808a16928b821692918616917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4613c4582898989898961424e565b5050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8316613cf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f45524331313535576974685465726d696e757353746f726167653a206275726e60448201527f2066726f6d20746865207a65726f206164647265737300000000000000000000606482015260840161081d565b60008281527ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1a60205260409020547ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd109060ff16613dd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f45524331313535576974685465726d696e757353746f726167653a205f62757260448201527f6e202d2d20706f6f6c206973206e6f74206275726e61626c6500000000000000606482015260840161081d565b33613e0181866000613de288614203565b613deb88614203565b5050604080516020810190915260009052505050565b6000848152600883016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8916845290915290205483811015613ec3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f45524331313535576974685465726d696e757353746f726167653a206275726e60448201527f20616d6f756e7420657863656564732062616c616e6365000000000000000000606482015260840161081d565b6000858152600884016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8a8116808652918452828520898703905589855260078801845282852080548a9003905582518a81529384018990529092908616917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4505050505050565b73ffffffffffffffffffffffffffffffffffffffff84163b15612c66576040517fbc197c8100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063bc197c8190613fca9089908990889088908890600401614fae565b6020604051808303816000875af1925050508015614023575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261402091810190615019565b60015b6141325761402f615036565b806308c379a0036140825750614043615052565b8061404e5750614084565b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081d919061453d565b505b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604760248201527f45524331313535576974685465726d696e757353746f726167653a207472616e60448201527f7366657220746f206e6f6e2045524331313535526563656976657220696d706c60648201527f656d656e74657200000000000000000000000000000000000000000000000000608482015260a40161081d565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fbc197c8100000000000000000000000000000000000000000000000000000000146131ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f45524331313535576974685465726d696e757353746f726167653a204552433160448201527f31353552656365697665722072656a656374656420746f6b656e730000000000606482015260840161081d565b6040805160018082528183019092526060916000919060208083019080368337019050509050828160008151811061423d5761423d614cdf565b602090810291909101015292915050565b73ffffffffffffffffffffffffffffffffffffffff84163b15612c66576040517ff23a6e6100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063f23a6e61906142c590899089908890889088906004016150fa565b6020604051808303816000875af192505050801561431e575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261431b91810190615019565b60015b61432a5761402f615036565b7fffffffff0000000000000000000000000000000000000000000000000000000081167ff23a6e6100000000000000000000000000000000000000000000000000000000146131ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f45524331313535576974685465726d696e757353746f726167653a204552433160448201527f31353552656365697665722072656a656374656420746f6b656e730000000000606482015260840161081d565b803573ffffffffffffffffffffffffffffffffffffffff8116811461283b57600080fd5b6000806040838503121561443257600080fd5b61443b836143fb565b946020939093013593505050565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114611e5d57600080fd5b60006020828403121561448957600080fd5b813561096c81614449565b600080604083850312156144a757600080fd5b823591506144b7602084016143fb565b90509250929050565b6000602082840312156144d257600080fd5b5035919050565b6000815180845260005b818110156144ff576020818501810151868301820152016144e3565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061096c60208301846144d9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff821117156145c3576145c3614550565b6040525050565b600067ffffffffffffffff8211156145e4576145e4614550565b5060051b60200190565b600082601f8301126145ff57600080fd5b8135602061460c826145ca565b604051614619828261457f565b80915083815260208101915060208460051b87010193508684111561463d57600080fd5b602086015b848110156146595780358352918301918301614642565b509695505050505050565b600082601f83011261467557600080fd5b813567ffffffffffffffff81111561468f5761468f614550565b6040516146c460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116018261457f565b8181528460208386010111156146d957600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806080858703121561470c57600080fd5b614715856143fb565b9350602085013567ffffffffffffffff8082111561473257600080fd5b61473e888389016145ee565b9450604087013591508082111561475457600080fd5b614760888389016145ee565b9350606087013591508082111561477657600080fd5b5061478387828801614664565b91505092959194509250565b600082601f8301126147a057600080fd5b813560206147ad826145ca565b6040516147ba828261457f565b80915083815260208101915060208460051b8701019350868411156147de57600080fd5b602086015b84811015614659576147f4816143fb565b83529183019183016147e3565b60008060006060848603121561481657600080fd5b83359250602084013567ffffffffffffffff8082111561483557600080fd5b6148418783880161478f565b9350604086013591508082111561485757600080fd5b50614864868287016145ee565b9150509250925092565b8015158114611e5d57600080fd5b6000806040838503121561488f57600080fd5b8235915060208301356148a18161486e565b809150509250929050565b600080600080600060a086880312156148c457600080fd5b6148cd866143fb565b94506148db602087016143fb565b9350604086013567ffffffffffffffff808211156148f857600080fd5b61490489838a016145ee565b9450606088013591508082111561491a57600080fd5b61492689838a016145ee565b9350608088013591508082111561493c57600080fd5b5061494988828901614664565b9150509295509295909350565b60008060006060848603121561496b57600080fd5b83359250602084013561497d8161486e565b9150604084013561498d8161486e565b809150509250925092565b600080604083850312156149ab57600080fd5b823567ffffffffffffffff808211156149c357600080fd5b6149cf8683870161478f565b935060208501359150808211156149e557600080fd5b506149f2858286016145ee565b9150509250929050565b60008151808452602080850194506020840160005b83811015614a2d57815187529582019590820190600101614a11565b509495945050505050565b60208152600061096c60208301846149fc565b600060208284031215614a5d57600080fd5b61096c826143fb565b60008060008060808587031215614a7c57600080fd5b614a85856143fb565b93506020850135925060408501359150606085013567ffffffffffffffff811115614aaf57600080fd5b61478387828801614664565b60008060008060808587031215614ad157600080fd5b843593506020850135614ae38161486e565b92506040850135614af38161486e565b9150606085013567ffffffffffffffff811115614aaf57600080fd5b60008060408385031215614b2257600080fd5b82359150602083013567ffffffffffffffff811115614b4057600080fd5b6149f285828601614664565b600060208284031215614b5e57600080fd5b813567ffffffffffffffff811115614b7557600080fd5b6121e384828501614664565b60008060408385031215614b9457600080fd5b614b9d836143fb565b915060208301356148a18161486e565b60008060408385031215614bc057600080fd5b614bc9836143fb565b91506144b7602084016143fb565b600080600080600060a08688031215614bef57600080fd5b614bf8866143fb565b9450614c06602087016143fb565b93506040860135925060608601359150608086013567ffffffffffffffff811115614c3057600080fd5b61494988828901614664565b600080600060608486031215614c5157600080fd5b614c5a846143fb565b95602085013595506040909401359392505050565b600060208284031215614c8157600080fd5b815161096c8161486e565b600181811c90821680614ca057607f821691505b602082108103614cd9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561087757610877614d0e565b60006060820173ffffffffffffffffffffffffffffffffffffffff808716845260206060602086015282875180855260808701915060208901945060005b81811015614dac578551851683529483019491830191600101614d8e565b50508581036040870152614dc081886149fc565b9998505050505050505050565b600060208284031215614ddf57600080fd5b5051919050565b601f821115611eb4576000816000526020600020601f850160051c81016020861015614e0f5750805b601f850160051c820191505b81811015612c6657828155600101614e1b565b815167ffffffffffffffff811115614e4857614e48614550565b614e5c81614e568454614c8c565b84614de6565b602080601f831160018114614eaf5760008415614e795750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555612c66565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614efc57888601518255948401946001909101908401614edd565b5085821015614f3857878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b604081526000614f5b60408301856149fc565b8281036020840152614f6d81856149fc565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614fa757614fa7614d0e565b5060010190565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a06040830152614fe760a08301866149fc565b8281036060840152614ff981866149fc565b9050828103608084015261500d81856144d9565b98975050505050505050565b60006020828403121561502b57600080fd5b815161096c81614449565b600060033d111561504f5760046000803e5060005160e01c5b90565b600060443d10156150605790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff81602484011181841117156150ae57505050505090565b82850191508151818111156150c65750505050505090565b843d87010160208285010111156150e05750505050505090565b6150ef6020828601018761457f565b509095945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a0608083015261513f60a08301846144d9565b97965050505050505056fea264697066735822122084f799d76969aef473ad088cc7281ebf31a7aeb376fc6118b23d91db6e7c26a264736f6c63430008180033", +} + +// TerminusFacetABI is the input ABI used to generate the binding from. +// Deprecated: Use TerminusFacetMetaData.ABI instead. +var TerminusFacetABI = TerminusFacetMetaData.ABI + +// TerminusFacetBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use TerminusFacetMetaData.Bin instead. +var TerminusFacetBin = TerminusFacetMetaData.Bin + +// DeployTerminusFacet deploys a new Ethereum contract, binding an instance of TerminusFacet to it. +func DeployTerminusFacet(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *TerminusFacet, error) { + parsed, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(TerminusFacetBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &TerminusFacet{TerminusFacetCaller: TerminusFacetCaller{contract: contract}, TerminusFacetTransactor: TerminusFacetTransactor{contract: contract}, TerminusFacetFilterer: TerminusFacetFilterer{contract: contract}}, nil +} + +// TerminusFacet is an auto generated Go binding around an Ethereum contract. +type TerminusFacet struct { + TerminusFacetCaller // Read-only binding to the contract + TerminusFacetTransactor // Write-only binding to the contract + TerminusFacetFilterer // Log filterer for contract events +} + +// TerminusFacetCaller is an auto generated read-only Go binding around an Ethereum contract. +type TerminusFacetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TerminusFacetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type TerminusFacetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TerminusFacetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type TerminusFacetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TerminusFacetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type TerminusFacetSession struct { + Contract *TerminusFacet // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TerminusFacetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type TerminusFacetCallerSession struct { + Contract *TerminusFacetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// TerminusFacetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type TerminusFacetTransactorSession struct { + Contract *TerminusFacetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TerminusFacetRaw is an auto generated low-level Go binding around an Ethereum contract. +type TerminusFacetRaw struct { + Contract *TerminusFacet // Generic contract binding to access the raw methods on +} + +// TerminusFacetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type TerminusFacetCallerRaw struct { + Contract *TerminusFacetCaller // Generic read-only contract binding to access the raw methods on +} + +// TerminusFacetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type TerminusFacetTransactorRaw struct { + Contract *TerminusFacetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewTerminusFacet creates a new instance of TerminusFacet, bound to a specific deployed contract. +func NewTerminusFacet(address common.Address, backend bind.ContractBackend) (*TerminusFacet, error) { + contract, err := bindTerminusFacet(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &TerminusFacet{TerminusFacetCaller: TerminusFacetCaller{contract: contract}, TerminusFacetTransactor: TerminusFacetTransactor{contract: contract}, TerminusFacetFilterer: TerminusFacetFilterer{contract: contract}}, nil +} + +// NewTerminusFacetCaller creates a new read-only instance of TerminusFacet, bound to a specific deployed contract. +func NewTerminusFacetCaller(address common.Address, caller bind.ContractCaller) (*TerminusFacetCaller, error) { + contract, err := bindTerminusFacet(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &TerminusFacetCaller{contract: contract}, nil +} + +// NewTerminusFacetTransactor creates a new write-only instance of TerminusFacet, bound to a specific deployed contract. +func NewTerminusFacetTransactor(address common.Address, transactor bind.ContractTransactor) (*TerminusFacetTransactor, error) { + contract, err := bindTerminusFacet(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &TerminusFacetTransactor{contract: contract}, nil +} + +// NewTerminusFacetFilterer creates a new log filterer instance of TerminusFacet, bound to a specific deployed contract. +func NewTerminusFacetFilterer(address common.Address, filterer bind.ContractFilterer) (*TerminusFacetFilterer, error) { + contract, err := bindTerminusFacet(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &TerminusFacetFilterer{contract: contract}, nil +} + +// bindTerminusFacet binds a generic wrapper to an already deployed contract. +func bindTerminusFacet(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_TerminusFacet *TerminusFacetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _TerminusFacet.Contract.TerminusFacetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_TerminusFacet *TerminusFacetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _TerminusFacet.Contract.TerminusFacetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_TerminusFacet *TerminusFacetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _TerminusFacet.Contract.TerminusFacetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_TerminusFacet *TerminusFacetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _TerminusFacet.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_TerminusFacet *TerminusFacetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _TerminusFacet.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_TerminusFacet *TerminusFacetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _TerminusFacet.Contract.contract.Transact(opts, method, params...) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. +// +// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) +func (_TerminusFacet *TerminusFacetCaller) BalanceOf(opts *bind.CallOpts, account common.Address, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "balanceOf", account, id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. +// +// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) +func (_TerminusFacet *TerminusFacetSession) BalanceOf(account common.Address, id *big.Int) (*big.Int, error) { + return _TerminusFacet.Contract.BalanceOf(&_TerminusFacet.CallOpts, account, id) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x00fdd58e. +// +// Solidity: function balanceOf(address account, uint256 id) view returns(uint256) +func (_TerminusFacet *TerminusFacetCallerSession) BalanceOf(account common.Address, id *big.Int) (*big.Int, error) { + return _TerminusFacet.Contract.BalanceOf(&_TerminusFacet.CallOpts, account, id) +} + +// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. +// +// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) +func (_TerminusFacet *TerminusFacetCaller) BalanceOfBatch(opts *bind.CallOpts, accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "balanceOfBatch", accounts, ids) + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. +// +// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) +func (_TerminusFacet *TerminusFacetSession) BalanceOfBatch(accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { + return _TerminusFacet.Contract.BalanceOfBatch(&_TerminusFacet.CallOpts, accounts, ids) +} + +// BalanceOfBatch is a free data retrieval call binding the contract method 0x4e1273f4. +// +// Solidity: function balanceOfBatch(address[] accounts, uint256[] ids) view returns(uint256[]) +func (_TerminusFacet *TerminusFacetCallerSession) BalanceOfBatch(accounts []common.Address, ids []*big.Int) ([]*big.Int, error) { + return _TerminusFacet.Contract.BalanceOfBatch(&_TerminusFacet.CallOpts, accounts, ids) +} + +// ContractURI is a free data retrieval call binding the contract method 0xe8a3d485. +// +// Solidity: function contractURI() view returns(string) +func (_TerminusFacet *TerminusFacetCaller) ContractURI(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "contractURI") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// ContractURI is a free data retrieval call binding the contract method 0xe8a3d485. +// +// Solidity: function contractURI() view returns(string) +func (_TerminusFacet *TerminusFacetSession) ContractURI() (string, error) { + return _TerminusFacet.Contract.ContractURI(&_TerminusFacet.CallOpts) +} + +// ContractURI is a free data retrieval call binding the contract method 0xe8a3d485. +// +// Solidity: function contractURI() view returns(string) +func (_TerminusFacet *TerminusFacetCallerSession) ContractURI() (string, error) { + return _TerminusFacet.Contract.ContractURI(&_TerminusFacet.CallOpts) +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) +func (_TerminusFacet *TerminusFacetCaller) IsApprovedForAll(opts *bind.CallOpts, account common.Address, operator common.Address) (bool, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "isApprovedForAll", account, operator) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) +func (_TerminusFacet *TerminusFacetSession) IsApprovedForAll(account common.Address, operator common.Address) (bool, error) { + return _TerminusFacet.Contract.IsApprovedForAll(&_TerminusFacet.CallOpts, account, operator) +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address account, address operator) view returns(bool) +func (_TerminusFacet *TerminusFacetCallerSession) IsApprovedForAll(account common.Address, operator common.Address) (bool, error) { + return _TerminusFacet.Contract.IsApprovedForAll(&_TerminusFacet.CallOpts, account, operator) +} + +// IsApprovedForPool is a free data retrieval call binding the contract method 0x027b3fc2. +// +// Solidity: function isApprovedForPool(uint256 poolID, address operator) view returns(bool) +func (_TerminusFacet *TerminusFacetCaller) IsApprovedForPool(opts *bind.CallOpts, poolID *big.Int, operator common.Address) (bool, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "isApprovedForPool", poolID, operator) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsApprovedForPool is a free data retrieval call binding the contract method 0x027b3fc2. +// +// Solidity: function isApprovedForPool(uint256 poolID, address operator) view returns(bool) +func (_TerminusFacet *TerminusFacetSession) IsApprovedForPool(poolID *big.Int, operator common.Address) (bool, error) { + return _TerminusFacet.Contract.IsApprovedForPool(&_TerminusFacet.CallOpts, poolID, operator) +} + +// IsApprovedForPool is a free data retrieval call binding the contract method 0x027b3fc2. +// +// Solidity: function isApprovedForPool(uint256 poolID, address operator) view returns(bool) +func (_TerminusFacet *TerminusFacetCallerSession) IsApprovedForPool(poolID *big.Int, operator common.Address) (bool, error) { + return _TerminusFacet.Contract.IsApprovedForPool(&_TerminusFacet.CallOpts, poolID, operator) +} + +// PaymentToken is a free data retrieval call binding the contract method 0x3013ce29. +// +// Solidity: function paymentToken() view returns(address) +func (_TerminusFacet *TerminusFacetCaller) PaymentToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "paymentToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// PaymentToken is a free data retrieval call binding the contract method 0x3013ce29. +// +// Solidity: function paymentToken() view returns(address) +func (_TerminusFacet *TerminusFacetSession) PaymentToken() (common.Address, error) { + return _TerminusFacet.Contract.PaymentToken(&_TerminusFacet.CallOpts) +} + +// PaymentToken is a free data retrieval call binding the contract method 0x3013ce29. +// +// Solidity: function paymentToken() view returns(address) +func (_TerminusFacet *TerminusFacetCallerSession) PaymentToken() (common.Address, error) { + return _TerminusFacet.Contract.PaymentToken(&_TerminusFacet.CallOpts) +} + +// PoolBasePrice is a free data retrieval call binding the contract method 0x8925d013. +// +// Solidity: function poolBasePrice() view returns(uint256) +func (_TerminusFacet *TerminusFacetCaller) PoolBasePrice(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "poolBasePrice") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// PoolBasePrice is a free data retrieval call binding the contract method 0x8925d013. +// +// Solidity: function poolBasePrice() view returns(uint256) +func (_TerminusFacet *TerminusFacetSession) PoolBasePrice() (*big.Int, error) { + return _TerminusFacet.Contract.PoolBasePrice(&_TerminusFacet.CallOpts) +} + +// PoolBasePrice is a free data retrieval call binding the contract method 0x8925d013. +// +// Solidity: function poolBasePrice() view returns(uint256) +func (_TerminusFacet *TerminusFacetCallerSession) PoolBasePrice() (*big.Int, error) { + return _TerminusFacet.Contract.PoolBasePrice(&_TerminusFacet.CallOpts) +} + +// PoolIsBurnable is a free data retrieval call binding the contract method 0x3c50a3c5. +// +// Solidity: function poolIsBurnable(uint256 poolID) view returns(bool) +func (_TerminusFacet *TerminusFacetCaller) PoolIsBurnable(opts *bind.CallOpts, poolID *big.Int) (bool, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "poolIsBurnable", poolID) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// PoolIsBurnable is a free data retrieval call binding the contract method 0x3c50a3c5. +// +// Solidity: function poolIsBurnable(uint256 poolID) view returns(bool) +func (_TerminusFacet *TerminusFacetSession) PoolIsBurnable(poolID *big.Int) (bool, error) { + return _TerminusFacet.Contract.PoolIsBurnable(&_TerminusFacet.CallOpts, poolID) +} + +// PoolIsBurnable is a free data retrieval call binding the contract method 0x3c50a3c5. +// +// Solidity: function poolIsBurnable(uint256 poolID) view returns(bool) +func (_TerminusFacet *TerminusFacetCallerSession) PoolIsBurnable(poolID *big.Int) (bool, error) { + return _TerminusFacet.Contract.PoolIsBurnable(&_TerminusFacet.CallOpts, poolID) +} + +// PoolIsTransferable is a free data retrieval call binding the contract method 0x69453ce9. +// +// Solidity: function poolIsTransferable(uint256 poolID) view returns(bool) +func (_TerminusFacet *TerminusFacetCaller) PoolIsTransferable(opts *bind.CallOpts, poolID *big.Int) (bool, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "poolIsTransferable", poolID) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// PoolIsTransferable is a free data retrieval call binding the contract method 0x69453ce9. +// +// Solidity: function poolIsTransferable(uint256 poolID) view returns(bool) +func (_TerminusFacet *TerminusFacetSession) PoolIsTransferable(poolID *big.Int) (bool, error) { + return _TerminusFacet.Contract.PoolIsTransferable(&_TerminusFacet.CallOpts, poolID) +} + +// PoolIsTransferable is a free data retrieval call binding the contract method 0x69453ce9. +// +// Solidity: function poolIsTransferable(uint256 poolID) view returns(bool) +func (_TerminusFacet *TerminusFacetCallerSession) PoolIsTransferable(poolID *big.Int) (bool, error) { + return _TerminusFacet.Contract.PoolIsTransferable(&_TerminusFacet.CallOpts, poolID) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_TerminusFacet *TerminusFacetCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_TerminusFacet *TerminusFacetSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _TerminusFacet.Contract.SupportsInterface(&_TerminusFacet.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_TerminusFacet *TerminusFacetCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _TerminusFacet.Contract.SupportsInterface(&_TerminusFacet.CallOpts, interfaceId) +} + +// TerminusController is a free data retrieval call binding the contract method 0x366e59e3. +// +// Solidity: function terminusController() view returns(address) +func (_TerminusFacet *TerminusFacetCaller) TerminusController(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "terminusController") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// TerminusController is a free data retrieval call binding the contract method 0x366e59e3. +// +// Solidity: function terminusController() view returns(address) +func (_TerminusFacet *TerminusFacetSession) TerminusController() (common.Address, error) { + return _TerminusFacet.Contract.TerminusController(&_TerminusFacet.CallOpts) +} + +// TerminusController is a free data retrieval call binding the contract method 0x366e59e3. +// +// Solidity: function terminusController() view returns(address) +func (_TerminusFacet *TerminusFacetCallerSession) TerminusController() (common.Address, error) { + return _TerminusFacet.Contract.TerminusController(&_TerminusFacet.CallOpts) +} + +// TerminusPoolCapacity is a free data retrieval call binding the contract method 0x5dc8bdf8. +// +// Solidity: function terminusPoolCapacity(uint256 poolID) view returns(uint256) +func (_TerminusFacet *TerminusFacetCaller) TerminusPoolCapacity(opts *bind.CallOpts, poolID *big.Int) (*big.Int, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "terminusPoolCapacity", poolID) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TerminusPoolCapacity is a free data retrieval call binding the contract method 0x5dc8bdf8. +// +// Solidity: function terminusPoolCapacity(uint256 poolID) view returns(uint256) +func (_TerminusFacet *TerminusFacetSession) TerminusPoolCapacity(poolID *big.Int) (*big.Int, error) { + return _TerminusFacet.Contract.TerminusPoolCapacity(&_TerminusFacet.CallOpts, poolID) +} + +// TerminusPoolCapacity is a free data retrieval call binding the contract method 0x5dc8bdf8. +// +// Solidity: function terminusPoolCapacity(uint256 poolID) view returns(uint256) +func (_TerminusFacet *TerminusFacetCallerSession) TerminusPoolCapacity(poolID *big.Int) (*big.Int, error) { + return _TerminusFacet.Contract.TerminusPoolCapacity(&_TerminusFacet.CallOpts, poolID) +} + +// TerminusPoolController is a free data retrieval call binding the contract method 0xd0c402e5. +// +// Solidity: function terminusPoolController(uint256 poolID) view returns(address) +func (_TerminusFacet *TerminusFacetCaller) TerminusPoolController(opts *bind.CallOpts, poolID *big.Int) (common.Address, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "terminusPoolController", poolID) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// TerminusPoolController is a free data retrieval call binding the contract method 0xd0c402e5. +// +// Solidity: function terminusPoolController(uint256 poolID) view returns(address) +func (_TerminusFacet *TerminusFacetSession) TerminusPoolController(poolID *big.Int) (common.Address, error) { + return _TerminusFacet.Contract.TerminusPoolController(&_TerminusFacet.CallOpts, poolID) +} + +// TerminusPoolController is a free data retrieval call binding the contract method 0xd0c402e5. +// +// Solidity: function terminusPoolController(uint256 poolID) view returns(address) +func (_TerminusFacet *TerminusFacetCallerSession) TerminusPoolController(poolID *big.Int) (common.Address, error) { + return _TerminusFacet.Contract.TerminusPoolController(&_TerminusFacet.CallOpts, poolID) +} + +// TerminusPoolSupply is a free data retrieval call binding the contract method 0xa44cfc82. +// +// Solidity: function terminusPoolSupply(uint256 poolID) view returns(uint256) +func (_TerminusFacet *TerminusFacetCaller) TerminusPoolSupply(opts *bind.CallOpts, poolID *big.Int) (*big.Int, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "terminusPoolSupply", poolID) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TerminusPoolSupply is a free data retrieval call binding the contract method 0xa44cfc82. +// +// Solidity: function terminusPoolSupply(uint256 poolID) view returns(uint256) +func (_TerminusFacet *TerminusFacetSession) TerminusPoolSupply(poolID *big.Int) (*big.Int, error) { + return _TerminusFacet.Contract.TerminusPoolSupply(&_TerminusFacet.CallOpts, poolID) +} + +// TerminusPoolSupply is a free data retrieval call binding the contract method 0xa44cfc82. +// +// Solidity: function terminusPoolSupply(uint256 poolID) view returns(uint256) +func (_TerminusFacet *TerminusFacetCallerSession) TerminusPoolSupply(poolID *big.Int) (*big.Int, error) { + return _TerminusFacet.Contract.TerminusPoolSupply(&_TerminusFacet.CallOpts, poolID) +} + +// TotalPools is a free data retrieval call binding the contract method 0xab3c7e52. +// +// Solidity: function totalPools() view returns(uint256) +func (_TerminusFacet *TerminusFacetCaller) TotalPools(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "totalPools") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalPools is a free data retrieval call binding the contract method 0xab3c7e52. +// +// Solidity: function totalPools() view returns(uint256) +func (_TerminusFacet *TerminusFacetSession) TotalPools() (*big.Int, error) { + return _TerminusFacet.Contract.TotalPools(&_TerminusFacet.CallOpts) +} + +// TotalPools is a free data retrieval call binding the contract method 0xab3c7e52. +// +// Solidity: function totalPools() view returns(uint256) +func (_TerminusFacet *TerminusFacetCallerSession) TotalPools() (*big.Int, error) { + return _TerminusFacet.Contract.TotalPools(&_TerminusFacet.CallOpts) +} + +// Uri is a free data retrieval call binding the contract method 0x0e89341c. +// +// Solidity: function uri(uint256 poolID) view returns(string) +func (_TerminusFacet *TerminusFacetCaller) Uri(opts *bind.CallOpts, poolID *big.Int) (string, error) { + var out []interface{} + err := _TerminusFacet.contract.Call(opts, &out, "uri", poolID) + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Uri is a free data retrieval call binding the contract method 0x0e89341c. +// +// Solidity: function uri(uint256 poolID) view returns(string) +func (_TerminusFacet *TerminusFacetSession) Uri(poolID *big.Int) (string, error) { + return _TerminusFacet.Contract.Uri(&_TerminusFacet.CallOpts, poolID) +} + +// Uri is a free data retrieval call binding the contract method 0x0e89341c. +// +// Solidity: function uri(uint256 poolID) view returns(string) +func (_TerminusFacet *TerminusFacetCallerSession) Uri(poolID *big.Int) (string, error) { + return _TerminusFacet.Contract.Uri(&_TerminusFacet.CallOpts, poolID) +} + +// ApproveForPool is a paid mutator transaction binding the contract method 0x85bc82e2. +// +// Solidity: function approveForPool(uint256 poolID, address operator) returns() +func (_TerminusFacet *TerminusFacetTransactor) ApproveForPool(opts *bind.TransactOpts, poolID *big.Int, operator common.Address) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "approveForPool", poolID, operator) +} + +// ApproveForPool is a paid mutator transaction binding the contract method 0x85bc82e2. +// +// Solidity: function approveForPool(uint256 poolID, address operator) returns() +func (_TerminusFacet *TerminusFacetSession) ApproveForPool(poolID *big.Int, operator common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.ApproveForPool(&_TerminusFacet.TransactOpts, poolID, operator) +} + +// ApproveForPool is a paid mutator transaction binding the contract method 0x85bc82e2. +// +// Solidity: function approveForPool(uint256 poolID, address operator) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) ApproveForPool(poolID *big.Int, operator common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.ApproveForPool(&_TerminusFacet.TransactOpts, poolID, operator) +} + +// Burn is a paid mutator transaction binding the contract method 0xf5298aca. +// +// Solidity: function burn(address from, uint256 poolID, uint256 amount) returns() +func (_TerminusFacet *TerminusFacetTransactor) Burn(opts *bind.TransactOpts, from common.Address, poolID *big.Int, amount *big.Int) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "burn", from, poolID, amount) +} + +// Burn is a paid mutator transaction binding the contract method 0xf5298aca. +// +// Solidity: function burn(address from, uint256 poolID, uint256 amount) returns() +func (_TerminusFacet *TerminusFacetSession) Burn(from common.Address, poolID *big.Int, amount *big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.Burn(&_TerminusFacet.TransactOpts, from, poolID, amount) +} + +// Burn is a paid mutator transaction binding the contract method 0xf5298aca. +// +// Solidity: function burn(address from, uint256 poolID, uint256 amount) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) Burn(from common.Address, poolID *big.Int, amount *big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.Burn(&_TerminusFacet.TransactOpts, from, poolID, amount) +} + +// CreatePoolV1 is a paid mutator transaction binding the contract method 0x3bad2d82. +// +// Solidity: function createPoolV1(uint256 _capacity, bool _transferable, bool _burnable) returns(uint256) +func (_TerminusFacet *TerminusFacetTransactor) CreatePoolV1(opts *bind.TransactOpts, _capacity *big.Int, _transferable bool, _burnable bool) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "createPoolV1", _capacity, _transferable, _burnable) +} + +// CreatePoolV1 is a paid mutator transaction binding the contract method 0x3bad2d82. +// +// Solidity: function createPoolV1(uint256 _capacity, bool _transferable, bool _burnable) returns(uint256) +func (_TerminusFacet *TerminusFacetSession) CreatePoolV1(_capacity *big.Int, _transferable bool, _burnable bool) (*types.Transaction, error) { + return _TerminusFacet.Contract.CreatePoolV1(&_TerminusFacet.TransactOpts, _capacity, _transferable, _burnable) +} + +// CreatePoolV1 is a paid mutator transaction binding the contract method 0x3bad2d82. +// +// Solidity: function createPoolV1(uint256 _capacity, bool _transferable, bool _burnable) returns(uint256) +func (_TerminusFacet *TerminusFacetTransactorSession) CreatePoolV1(_capacity *big.Int, _transferable bool, _burnable bool) (*types.Transaction, error) { + return _TerminusFacet.Contract.CreatePoolV1(&_TerminusFacet.TransactOpts, _capacity, _transferable, _burnable) +} + +// CreatePoolV2 is a paid mutator transaction binding the contract method 0x84fa03a1. +// +// Solidity: function createPoolV2(uint256 _capacity, bool _transferable, bool _burnable, string poolURI) returns(uint256) +func (_TerminusFacet *TerminusFacetTransactor) CreatePoolV2(opts *bind.TransactOpts, _capacity *big.Int, _transferable bool, _burnable bool, poolURI string) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "createPoolV2", _capacity, _transferable, _burnable, poolURI) +} + +// CreatePoolV2 is a paid mutator transaction binding the contract method 0x84fa03a1. +// +// Solidity: function createPoolV2(uint256 _capacity, bool _transferable, bool _burnable, string poolURI) returns(uint256) +func (_TerminusFacet *TerminusFacetSession) CreatePoolV2(_capacity *big.Int, _transferable bool, _burnable bool, poolURI string) (*types.Transaction, error) { + return _TerminusFacet.Contract.CreatePoolV2(&_TerminusFacet.TransactOpts, _capacity, _transferable, _burnable, poolURI) +} + +// CreatePoolV2 is a paid mutator transaction binding the contract method 0x84fa03a1. +// +// Solidity: function createPoolV2(uint256 _capacity, bool _transferable, bool _burnable, string poolURI) returns(uint256) +func (_TerminusFacet *TerminusFacetTransactorSession) CreatePoolV2(_capacity *big.Int, _transferable bool, _burnable bool, poolURI string) (*types.Transaction, error) { + return _TerminusFacet.Contract.CreatePoolV2(&_TerminusFacet.TransactOpts, _capacity, _transferable, _burnable, poolURI) +} + +// CreateSimplePool is a paid mutator transaction binding the contract method 0xb507ef52. +// +// Solidity: function createSimplePool(uint256 _capacity) returns(uint256) +func (_TerminusFacet *TerminusFacetTransactor) CreateSimplePool(opts *bind.TransactOpts, _capacity *big.Int) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "createSimplePool", _capacity) +} + +// CreateSimplePool is a paid mutator transaction binding the contract method 0xb507ef52. +// +// Solidity: function createSimplePool(uint256 _capacity) returns(uint256) +func (_TerminusFacet *TerminusFacetSession) CreateSimplePool(_capacity *big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.CreateSimplePool(&_TerminusFacet.TransactOpts, _capacity) +} + +// CreateSimplePool is a paid mutator transaction binding the contract method 0xb507ef52. +// +// Solidity: function createSimplePool(uint256 _capacity) returns(uint256) +func (_TerminusFacet *TerminusFacetTransactorSession) CreateSimplePool(_capacity *big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.CreateSimplePool(&_TerminusFacet.TransactOpts, _capacity) +} + +// Init is a paid mutator transaction binding the contract method 0xe1c7392a. +// +// Solidity: function init() returns() +func (_TerminusFacet *TerminusFacetTransactor) Init(opts *bind.TransactOpts) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "init") +} + +// Init is a paid mutator transaction binding the contract method 0xe1c7392a. +// +// Solidity: function init() returns() +func (_TerminusFacet *TerminusFacetSession) Init() (*types.Transaction, error) { + return _TerminusFacet.Contract.Init(&_TerminusFacet.TransactOpts) +} + +// Init is a paid mutator transaction binding the contract method 0xe1c7392a. +// +// Solidity: function init() returns() +func (_TerminusFacet *TerminusFacetTransactorSession) Init() (*types.Transaction, error) { + return _TerminusFacet.Contract.Init(&_TerminusFacet.TransactOpts) +} + +// Mint is a paid mutator transaction binding the contract method 0x731133e9. +// +// Solidity: function mint(address to, uint256 poolID, uint256 amount, bytes data) returns() +func (_TerminusFacet *TerminusFacetTransactor) Mint(opts *bind.TransactOpts, to common.Address, poolID *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "mint", to, poolID, amount, data) +} + +// Mint is a paid mutator transaction binding the contract method 0x731133e9. +// +// Solidity: function mint(address to, uint256 poolID, uint256 amount, bytes data) returns() +func (_TerminusFacet *TerminusFacetSession) Mint(to common.Address, poolID *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.Contract.Mint(&_TerminusFacet.TransactOpts, to, poolID, amount, data) +} + +// Mint is a paid mutator transaction binding the contract method 0x731133e9. +// +// Solidity: function mint(address to, uint256 poolID, uint256 amount, bytes data) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) Mint(to common.Address, poolID *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.Contract.Mint(&_TerminusFacet.TransactOpts, to, poolID, amount, data) +} + +// MintBatch is a paid mutator transaction binding the contract method 0x1f7fdffa. +// +// Solidity: function mintBatch(address to, uint256[] poolIDs, uint256[] amounts, bytes data) returns() +func (_TerminusFacet *TerminusFacetTransactor) MintBatch(opts *bind.TransactOpts, to common.Address, poolIDs []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "mintBatch", to, poolIDs, amounts, data) +} + +// MintBatch is a paid mutator transaction binding the contract method 0x1f7fdffa. +// +// Solidity: function mintBatch(address to, uint256[] poolIDs, uint256[] amounts, bytes data) returns() +func (_TerminusFacet *TerminusFacetSession) MintBatch(to common.Address, poolIDs []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.Contract.MintBatch(&_TerminusFacet.TransactOpts, to, poolIDs, amounts, data) +} + +// MintBatch is a paid mutator transaction binding the contract method 0x1f7fdffa. +// +// Solidity: function mintBatch(address to, uint256[] poolIDs, uint256[] amounts, bytes data) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) MintBatch(to common.Address, poolIDs []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.Contract.MintBatch(&_TerminusFacet.TransactOpts, to, poolIDs, amounts, data) +} + +// PoolMintBatch is a paid mutator transaction binding the contract method 0x21adca96. +// +// Solidity: function poolMintBatch(uint256 id, address[] toAddresses, uint256[] amounts) returns() +func (_TerminusFacet *TerminusFacetTransactor) PoolMintBatch(opts *bind.TransactOpts, id *big.Int, toAddresses []common.Address, amounts []*big.Int) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "poolMintBatch", id, toAddresses, amounts) +} + +// PoolMintBatch is a paid mutator transaction binding the contract method 0x21adca96. +// +// Solidity: function poolMintBatch(uint256 id, address[] toAddresses, uint256[] amounts) returns() +func (_TerminusFacet *TerminusFacetSession) PoolMintBatch(id *big.Int, toAddresses []common.Address, amounts []*big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.PoolMintBatch(&_TerminusFacet.TransactOpts, id, toAddresses, amounts) +} + +// PoolMintBatch is a paid mutator transaction binding the contract method 0x21adca96. +// +// Solidity: function poolMintBatch(uint256 id, address[] toAddresses, uint256[] amounts) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) PoolMintBatch(id *big.Int, toAddresses []common.Address, amounts []*big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.PoolMintBatch(&_TerminusFacet.TransactOpts, id, toAddresses, amounts) +} + +// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. +// +// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() +func (_TerminusFacet *TerminusFacetTransactor) SafeBatchTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "safeBatchTransferFrom", from, to, ids, amounts, data) +} + +// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. +// +// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() +func (_TerminusFacet *TerminusFacetSession) SafeBatchTransferFrom(from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.Contract.SafeBatchTransferFrom(&_TerminusFacet.TransactOpts, from, to, ids, amounts, data) +} + +// SafeBatchTransferFrom is a paid mutator transaction binding the contract method 0x2eb2c2d6. +// +// Solidity: function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SafeBatchTransferFrom(from common.Address, to common.Address, ids []*big.Int, amounts []*big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.Contract.SafeBatchTransferFrom(&_TerminusFacet.TransactOpts, from, to, ids, amounts, data) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() +func (_TerminusFacet *TerminusFacetTransactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "safeTransferFrom", from, to, id, amount, data) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() +func (_TerminusFacet *TerminusFacetSession) SafeTransferFrom(from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.Contract.SafeTransferFrom(&_TerminusFacet.TransactOpts, from, to, id, amount, data) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0xf242432a. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SafeTransferFrom(from common.Address, to common.Address, id *big.Int, amount *big.Int, data []byte) (*types.Transaction, error) { + return _TerminusFacet.Contract.SafeTransferFrom(&_TerminusFacet.TransactOpts, from, to, id, amount, data) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetApprovalForAll(opts *bind.TransactOpts, operator common.Address, approved bool) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setApprovalForAll", operator, approved) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_TerminusFacet *TerminusFacetSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetApprovalForAll(&_TerminusFacet.TransactOpts, operator, approved) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetApprovalForAll(&_TerminusFacet.TransactOpts, operator, approved) +} + +// SetContractURI is a paid mutator transaction binding the contract method 0x938e3d7b. +// +// Solidity: function setContractURI(string _contractURI) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetContractURI(opts *bind.TransactOpts, _contractURI string) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setContractURI", _contractURI) +} + +// SetContractURI is a paid mutator transaction binding the contract method 0x938e3d7b. +// +// Solidity: function setContractURI(string _contractURI) returns() +func (_TerminusFacet *TerminusFacetSession) SetContractURI(_contractURI string) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetContractURI(&_TerminusFacet.TransactOpts, _contractURI) +} + +// SetContractURI is a paid mutator transaction binding the contract method 0x938e3d7b. +// +// Solidity: function setContractURI(string _contractURI) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetContractURI(_contractURI string) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetContractURI(&_TerminusFacet.TransactOpts, _contractURI) +} + +// SetController is a paid mutator transaction binding the contract method 0x92eefe9b. +// +// Solidity: function setController(address newController) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetController(opts *bind.TransactOpts, newController common.Address) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setController", newController) +} + +// SetController is a paid mutator transaction binding the contract method 0x92eefe9b. +// +// Solidity: function setController(address newController) returns() +func (_TerminusFacet *TerminusFacetSession) SetController(newController common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetController(&_TerminusFacet.TransactOpts, newController) +} + +// SetController is a paid mutator transaction binding the contract method 0x92eefe9b. +// +// Solidity: function setController(address newController) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetController(newController common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetController(&_TerminusFacet.TransactOpts, newController) +} + +// SetPaymentToken is a paid mutator transaction binding the contract method 0x6a326ab1. +// +// Solidity: function setPaymentToken(address newPaymentToken) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetPaymentToken(opts *bind.TransactOpts, newPaymentToken common.Address) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setPaymentToken", newPaymentToken) +} + +// SetPaymentToken is a paid mutator transaction binding the contract method 0x6a326ab1. +// +// Solidity: function setPaymentToken(address newPaymentToken) returns() +func (_TerminusFacet *TerminusFacetSession) SetPaymentToken(newPaymentToken common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPaymentToken(&_TerminusFacet.TransactOpts, newPaymentToken) +} + +// SetPaymentToken is a paid mutator transaction binding the contract method 0x6a326ab1. +// +// Solidity: function setPaymentToken(address newPaymentToken) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetPaymentToken(newPaymentToken common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPaymentToken(&_TerminusFacet.TransactOpts, newPaymentToken) +} + +// SetPoolBasePrice is a paid mutator transaction binding the contract method 0x78cf2e84. +// +// Solidity: function setPoolBasePrice(uint256 newBasePrice) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetPoolBasePrice(opts *bind.TransactOpts, newBasePrice *big.Int) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setPoolBasePrice", newBasePrice) +} + +// SetPoolBasePrice is a paid mutator transaction binding the contract method 0x78cf2e84. +// +// Solidity: function setPoolBasePrice(uint256 newBasePrice) returns() +func (_TerminusFacet *TerminusFacetSession) SetPoolBasePrice(newBasePrice *big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPoolBasePrice(&_TerminusFacet.TransactOpts, newBasePrice) +} + +// SetPoolBasePrice is a paid mutator transaction binding the contract method 0x78cf2e84. +// +// Solidity: function setPoolBasePrice(uint256 newBasePrice) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetPoolBasePrice(newBasePrice *big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPoolBasePrice(&_TerminusFacet.TransactOpts, newBasePrice) +} + +// SetPoolBurnable is a paid mutator transaction binding the contract method 0x2365c859. +// +// Solidity: function setPoolBurnable(uint256 poolID, bool burnable) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetPoolBurnable(opts *bind.TransactOpts, poolID *big.Int, burnable bool) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setPoolBurnable", poolID, burnable) +} + +// SetPoolBurnable is a paid mutator transaction binding the contract method 0x2365c859. +// +// Solidity: function setPoolBurnable(uint256 poolID, bool burnable) returns() +func (_TerminusFacet *TerminusFacetSession) SetPoolBurnable(poolID *big.Int, burnable bool) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPoolBurnable(&_TerminusFacet.TransactOpts, poolID, burnable) +} + +// SetPoolBurnable is a paid mutator transaction binding the contract method 0x2365c859. +// +// Solidity: function setPoolBurnable(uint256 poolID, bool burnable) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetPoolBurnable(poolID *big.Int, burnable bool) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPoolBurnable(&_TerminusFacet.TransactOpts, poolID, burnable) +} + +// SetPoolController is a paid mutator transaction binding the contract method 0xdc55d0b2. +// +// Solidity: function setPoolController(uint256 poolID, address newController) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetPoolController(opts *bind.TransactOpts, poolID *big.Int, newController common.Address) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setPoolController", poolID, newController) +} + +// SetPoolController is a paid mutator transaction binding the contract method 0xdc55d0b2. +// +// Solidity: function setPoolController(uint256 poolID, address newController) returns() +func (_TerminusFacet *TerminusFacetSession) SetPoolController(poolID *big.Int, newController common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPoolController(&_TerminusFacet.TransactOpts, poolID, newController) +} + +// SetPoolController is a paid mutator transaction binding the contract method 0xdc55d0b2. +// +// Solidity: function setPoolController(uint256 poolID, address newController) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetPoolController(poolID *big.Int, newController common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPoolController(&_TerminusFacet.TransactOpts, poolID, newController) +} + +// SetPoolTransferable is a paid mutator transaction binding the contract method 0xf3dc0a85. +// +// Solidity: function setPoolTransferable(uint256 poolID, bool transferable) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetPoolTransferable(opts *bind.TransactOpts, poolID *big.Int, transferable bool) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setPoolTransferable", poolID, transferable) +} + +// SetPoolTransferable is a paid mutator transaction binding the contract method 0xf3dc0a85. +// +// Solidity: function setPoolTransferable(uint256 poolID, bool transferable) returns() +func (_TerminusFacet *TerminusFacetSession) SetPoolTransferable(poolID *big.Int, transferable bool) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPoolTransferable(&_TerminusFacet.TransactOpts, poolID, transferable) +} + +// SetPoolTransferable is a paid mutator transaction binding the contract method 0xf3dc0a85. +// +// Solidity: function setPoolTransferable(uint256 poolID, bool transferable) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetPoolTransferable(poolID *big.Int, transferable bool) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetPoolTransferable(&_TerminusFacet.TransactOpts, poolID, transferable) +} + +// SetURI is a paid mutator transaction binding the contract method 0x862440e2. +// +// Solidity: function setURI(uint256 poolID, string poolURI) returns() +func (_TerminusFacet *TerminusFacetTransactor) SetURI(opts *bind.TransactOpts, poolID *big.Int, poolURI string) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "setURI", poolID, poolURI) +} + +// SetURI is a paid mutator transaction binding the contract method 0x862440e2. +// +// Solidity: function setURI(uint256 poolID, string poolURI) returns() +func (_TerminusFacet *TerminusFacetSession) SetURI(poolID *big.Int, poolURI string) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetURI(&_TerminusFacet.TransactOpts, poolID, poolURI) +} + +// SetURI is a paid mutator transaction binding the contract method 0x862440e2. +// +// Solidity: function setURI(uint256 poolID, string poolURI) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) SetURI(poolID *big.Int, poolURI string) (*types.Transaction, error) { + return _TerminusFacet.Contract.SetURI(&_TerminusFacet.TransactOpts, poolID, poolURI) +} + +// UnapproveForPool is a paid mutator transaction binding the contract method 0x1fbeae86. +// +// Solidity: function unapproveForPool(uint256 poolID, address operator) returns() +func (_TerminusFacet *TerminusFacetTransactor) UnapproveForPool(opts *bind.TransactOpts, poolID *big.Int, operator common.Address) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "unapproveForPool", poolID, operator) +} + +// UnapproveForPool is a paid mutator transaction binding the contract method 0x1fbeae86. +// +// Solidity: function unapproveForPool(uint256 poolID, address operator) returns() +func (_TerminusFacet *TerminusFacetSession) UnapproveForPool(poolID *big.Int, operator common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.UnapproveForPool(&_TerminusFacet.TransactOpts, poolID, operator) +} + +// UnapproveForPool is a paid mutator transaction binding the contract method 0x1fbeae86. +// +// Solidity: function unapproveForPool(uint256 poolID, address operator) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) UnapproveForPool(poolID *big.Int, operator common.Address) (*types.Transaction, error) { + return _TerminusFacet.Contract.UnapproveForPool(&_TerminusFacet.TransactOpts, poolID, operator) +} + +// WithdrawPayments is a paid mutator transaction binding the contract method 0x0e7afec5. +// +// Solidity: function withdrawPayments(address toAddress, uint256 amount) returns() +func (_TerminusFacet *TerminusFacetTransactor) WithdrawPayments(opts *bind.TransactOpts, toAddress common.Address, amount *big.Int) (*types.Transaction, error) { + return _TerminusFacet.contract.Transact(opts, "withdrawPayments", toAddress, amount) +} + +// WithdrawPayments is a paid mutator transaction binding the contract method 0x0e7afec5. +// +// Solidity: function withdrawPayments(address toAddress, uint256 amount) returns() +func (_TerminusFacet *TerminusFacetSession) WithdrawPayments(toAddress common.Address, amount *big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.WithdrawPayments(&_TerminusFacet.TransactOpts, toAddress, amount) +} + +// WithdrawPayments is a paid mutator transaction binding the contract method 0x0e7afec5. +// +// Solidity: function withdrawPayments(address toAddress, uint256 amount) returns() +func (_TerminusFacet *TerminusFacetTransactorSession) WithdrawPayments(toAddress common.Address, amount *big.Int) (*types.Transaction, error) { + return _TerminusFacet.Contract.WithdrawPayments(&_TerminusFacet.TransactOpts, toAddress, amount) +} + +// TerminusFacetApprovalForAllIterator is returned from FilterApprovalForAll and is used to iterate over the raw logs and unpacked data for ApprovalForAll events raised by the TerminusFacet contract. +type TerminusFacetApprovalForAllIterator struct { + Event *TerminusFacetApprovalForAll // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TerminusFacetApprovalForAllIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TerminusFacetApprovalForAll) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TerminusFacetApprovalForAll) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TerminusFacetApprovalForAllIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TerminusFacetApprovalForAllIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TerminusFacetApprovalForAll represents a ApprovalForAll event raised by the TerminusFacet contract. +type TerminusFacetApprovalForAll struct { + Account common.Address + Operator common.Address + Approved bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApprovalForAll is a free log retrieval operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) +func (_TerminusFacet *TerminusFacetFilterer) FilterApprovalForAll(opts *bind.FilterOpts, account []common.Address, operator []common.Address) (*TerminusFacetApprovalForAllIterator, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + + logs, sub, err := _TerminusFacet.contract.FilterLogs(opts, "ApprovalForAll", accountRule, operatorRule) + if err != nil { + return nil, err + } + return &TerminusFacetApprovalForAllIterator{contract: _TerminusFacet.contract, event: "ApprovalForAll", logs: logs, sub: sub}, nil +} + +// WatchApprovalForAll is a free log subscription operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) +func (_TerminusFacet *TerminusFacetFilterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *TerminusFacetApprovalForAll, account []common.Address, operator []common.Address) (event.Subscription, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + + logs, sub, err := _TerminusFacet.contract.WatchLogs(opts, "ApprovalForAll", accountRule, operatorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TerminusFacetApprovalForAll) + if err := _TerminusFacet.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApprovalForAll is a log parse operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed account, address indexed operator, bool approved) +func (_TerminusFacet *TerminusFacetFilterer) ParseApprovalForAll(log types.Log) (*TerminusFacetApprovalForAll, error) { + event := new(TerminusFacetApprovalForAll) + if err := _TerminusFacet.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TerminusFacetControlTransferredIterator is returned from FilterControlTransferred and is used to iterate over the raw logs and unpacked data for ControlTransferred events raised by the TerminusFacet contract. +type TerminusFacetControlTransferredIterator struct { + Event *TerminusFacetControlTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TerminusFacetControlTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TerminusFacetControlTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TerminusFacetControlTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TerminusFacetControlTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TerminusFacetControlTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TerminusFacetControlTransferred represents a ControlTransferred event raised by the TerminusFacet contract. +type TerminusFacetControlTransferred struct { + PreviousController common.Address + NewController common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterControlTransferred is a free log retrieval operation binding the contract event 0xa06677f7b64342b4bcbde423684dbdb5356acfe41ad0285b6ecbe6dc4bf427f2. +// +// Solidity: event ControlTransferred(address indexed previousController, address indexed newController) +func (_TerminusFacet *TerminusFacetFilterer) FilterControlTransferred(opts *bind.FilterOpts, previousController []common.Address, newController []common.Address) (*TerminusFacetControlTransferredIterator, error) { + + var previousControllerRule []interface{} + for _, previousControllerItem := range previousController { + previousControllerRule = append(previousControllerRule, previousControllerItem) + } + var newControllerRule []interface{} + for _, newControllerItem := range newController { + newControllerRule = append(newControllerRule, newControllerItem) + } + + logs, sub, err := _TerminusFacet.contract.FilterLogs(opts, "ControlTransferred", previousControllerRule, newControllerRule) + if err != nil { + return nil, err + } + return &TerminusFacetControlTransferredIterator{contract: _TerminusFacet.contract, event: "ControlTransferred", logs: logs, sub: sub}, nil +} + +// WatchControlTransferred is a free log subscription operation binding the contract event 0xa06677f7b64342b4bcbde423684dbdb5356acfe41ad0285b6ecbe6dc4bf427f2. +// +// Solidity: event ControlTransferred(address indexed previousController, address indexed newController) +func (_TerminusFacet *TerminusFacetFilterer) WatchControlTransferred(opts *bind.WatchOpts, sink chan<- *TerminusFacetControlTransferred, previousController []common.Address, newController []common.Address) (event.Subscription, error) { + + var previousControllerRule []interface{} + for _, previousControllerItem := range previousController { + previousControllerRule = append(previousControllerRule, previousControllerItem) + } + var newControllerRule []interface{} + for _, newControllerItem := range newController { + newControllerRule = append(newControllerRule, newControllerItem) + } + + logs, sub, err := _TerminusFacet.contract.WatchLogs(opts, "ControlTransferred", previousControllerRule, newControllerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TerminusFacetControlTransferred) + if err := _TerminusFacet.contract.UnpackLog(event, "ControlTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseControlTransferred is a log parse operation binding the contract event 0xa06677f7b64342b4bcbde423684dbdb5356acfe41ad0285b6ecbe6dc4bf427f2. +// +// Solidity: event ControlTransferred(address indexed previousController, address indexed newController) +func (_TerminusFacet *TerminusFacetFilterer) ParseControlTransferred(log types.Log) (*TerminusFacetControlTransferred, error) { + event := new(TerminusFacetControlTransferred) + if err := _TerminusFacet.contract.UnpackLog(event, "ControlTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TerminusFacetPoolControlTransferredIterator is returned from FilterPoolControlTransferred and is used to iterate over the raw logs and unpacked data for PoolControlTransferred events raised by the TerminusFacet contract. +type TerminusFacetPoolControlTransferredIterator struct { + Event *TerminusFacetPoolControlTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TerminusFacetPoolControlTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TerminusFacetPoolControlTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TerminusFacetPoolControlTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TerminusFacetPoolControlTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TerminusFacetPoolControlTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TerminusFacetPoolControlTransferred represents a PoolControlTransferred event raised by the TerminusFacet contract. +type TerminusFacetPoolControlTransferred struct { + PoolID *big.Int + PreviousController common.Address + NewController common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterPoolControlTransferred is a free log retrieval operation binding the contract event 0xbb8e9c3c4a526b28a6b555c4def50ebda6412e188a3836bb2fbe72fd37578442. +// +// Solidity: event PoolControlTransferred(uint256 indexed poolID, address indexed previousController, address indexed newController) +func (_TerminusFacet *TerminusFacetFilterer) FilterPoolControlTransferred(opts *bind.FilterOpts, poolID []*big.Int, previousController []common.Address, newController []common.Address) (*TerminusFacetPoolControlTransferredIterator, error) { + + var poolIDRule []interface{} + for _, poolIDItem := range poolID { + poolIDRule = append(poolIDRule, poolIDItem) + } + var previousControllerRule []interface{} + for _, previousControllerItem := range previousController { + previousControllerRule = append(previousControllerRule, previousControllerItem) + } + var newControllerRule []interface{} + for _, newControllerItem := range newController { + newControllerRule = append(newControllerRule, newControllerItem) + } + + logs, sub, err := _TerminusFacet.contract.FilterLogs(opts, "PoolControlTransferred", poolIDRule, previousControllerRule, newControllerRule) + if err != nil { + return nil, err + } + return &TerminusFacetPoolControlTransferredIterator{contract: _TerminusFacet.contract, event: "PoolControlTransferred", logs: logs, sub: sub}, nil +} + +// WatchPoolControlTransferred is a free log subscription operation binding the contract event 0xbb8e9c3c4a526b28a6b555c4def50ebda6412e188a3836bb2fbe72fd37578442. +// +// Solidity: event PoolControlTransferred(uint256 indexed poolID, address indexed previousController, address indexed newController) +func (_TerminusFacet *TerminusFacetFilterer) WatchPoolControlTransferred(opts *bind.WatchOpts, sink chan<- *TerminusFacetPoolControlTransferred, poolID []*big.Int, previousController []common.Address, newController []common.Address) (event.Subscription, error) { + + var poolIDRule []interface{} + for _, poolIDItem := range poolID { + poolIDRule = append(poolIDRule, poolIDItem) + } + var previousControllerRule []interface{} + for _, previousControllerItem := range previousController { + previousControllerRule = append(previousControllerRule, previousControllerItem) + } + var newControllerRule []interface{} + for _, newControllerItem := range newController { + newControllerRule = append(newControllerRule, newControllerItem) + } + + logs, sub, err := _TerminusFacet.contract.WatchLogs(opts, "PoolControlTransferred", poolIDRule, previousControllerRule, newControllerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TerminusFacetPoolControlTransferred) + if err := _TerminusFacet.contract.UnpackLog(event, "PoolControlTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParsePoolControlTransferred is a log parse operation binding the contract event 0xbb8e9c3c4a526b28a6b555c4def50ebda6412e188a3836bb2fbe72fd37578442. +// +// Solidity: event PoolControlTransferred(uint256 indexed poolID, address indexed previousController, address indexed newController) +func (_TerminusFacet *TerminusFacetFilterer) ParsePoolControlTransferred(log types.Log) (*TerminusFacetPoolControlTransferred, error) { + event := new(TerminusFacetPoolControlTransferred) + if err := _TerminusFacet.contract.UnpackLog(event, "PoolControlTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TerminusFacetPoolMintBatchIterator is returned from FilterPoolMintBatch and is used to iterate over the raw logs and unpacked data for PoolMintBatch events raised by the TerminusFacet contract. +type TerminusFacetPoolMintBatchIterator struct { + Event *TerminusFacetPoolMintBatch // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TerminusFacetPoolMintBatchIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TerminusFacetPoolMintBatch) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TerminusFacetPoolMintBatch) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TerminusFacetPoolMintBatchIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TerminusFacetPoolMintBatchIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TerminusFacetPoolMintBatch represents a PoolMintBatch event raised by the TerminusFacet contract. +type TerminusFacetPoolMintBatch struct { + Id *big.Int + Operator common.Address + From common.Address + ToAddresses []common.Address + Amounts []*big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterPoolMintBatch is a free log retrieval operation binding the contract event 0xba62777935b5e992de16a785941daef9f13517ff268a40563288072025b50238. +// +// Solidity: event PoolMintBatch(uint256 indexed id, address indexed operator, address from, address[] toAddresses, uint256[] amounts) +func (_TerminusFacet *TerminusFacetFilterer) FilterPoolMintBatch(opts *bind.FilterOpts, id []*big.Int, operator []common.Address) (*TerminusFacetPoolMintBatchIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + + logs, sub, err := _TerminusFacet.contract.FilterLogs(opts, "PoolMintBatch", idRule, operatorRule) + if err != nil { + return nil, err + } + return &TerminusFacetPoolMintBatchIterator{contract: _TerminusFacet.contract, event: "PoolMintBatch", logs: logs, sub: sub}, nil +} + +// WatchPoolMintBatch is a free log subscription operation binding the contract event 0xba62777935b5e992de16a785941daef9f13517ff268a40563288072025b50238. +// +// Solidity: event PoolMintBatch(uint256 indexed id, address indexed operator, address from, address[] toAddresses, uint256[] amounts) +func (_TerminusFacet *TerminusFacetFilterer) WatchPoolMintBatch(opts *bind.WatchOpts, sink chan<- *TerminusFacetPoolMintBatch, id []*big.Int, operator []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + + logs, sub, err := _TerminusFacet.contract.WatchLogs(opts, "PoolMintBatch", idRule, operatorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TerminusFacetPoolMintBatch) + if err := _TerminusFacet.contract.UnpackLog(event, "PoolMintBatch", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParsePoolMintBatch is a log parse operation binding the contract event 0xba62777935b5e992de16a785941daef9f13517ff268a40563288072025b50238. +// +// Solidity: event PoolMintBatch(uint256 indexed id, address indexed operator, address from, address[] toAddresses, uint256[] amounts) +func (_TerminusFacet *TerminusFacetFilterer) ParsePoolMintBatch(log types.Log) (*TerminusFacetPoolMintBatch, error) { + event := new(TerminusFacetPoolMintBatch) + if err := _TerminusFacet.contract.UnpackLog(event, "PoolMintBatch", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TerminusFacetTransferBatchIterator is returned from FilterTransferBatch and is used to iterate over the raw logs and unpacked data for TransferBatch events raised by the TerminusFacet contract. +type TerminusFacetTransferBatchIterator struct { + Event *TerminusFacetTransferBatch // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TerminusFacetTransferBatchIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TerminusFacetTransferBatch) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TerminusFacetTransferBatch) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TerminusFacetTransferBatchIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TerminusFacetTransferBatchIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TerminusFacetTransferBatch represents a TransferBatch event raised by the TerminusFacet contract. +type TerminusFacetTransferBatch struct { + Operator common.Address + From common.Address + To common.Address + Ids []*big.Int + Values []*big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransferBatch is a free log retrieval operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. +// +// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) +func (_TerminusFacet *TerminusFacetFilterer) FilterTransferBatch(opts *bind.FilterOpts, operator []common.Address, from []common.Address, to []common.Address) (*TerminusFacetTransferBatchIterator, error) { + + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _TerminusFacet.contract.FilterLogs(opts, "TransferBatch", operatorRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &TerminusFacetTransferBatchIterator{contract: _TerminusFacet.contract, event: "TransferBatch", logs: logs, sub: sub}, nil +} + +// WatchTransferBatch is a free log subscription operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. +// +// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) +func (_TerminusFacet *TerminusFacetFilterer) WatchTransferBatch(opts *bind.WatchOpts, sink chan<- *TerminusFacetTransferBatch, operator []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _TerminusFacet.contract.WatchLogs(opts, "TransferBatch", operatorRule, fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TerminusFacetTransferBatch) + if err := _TerminusFacet.contract.UnpackLog(event, "TransferBatch", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransferBatch is a log parse operation binding the contract event 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb. +// +// Solidity: event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values) +func (_TerminusFacet *TerminusFacetFilterer) ParseTransferBatch(log types.Log) (*TerminusFacetTransferBatch, error) { + event := new(TerminusFacetTransferBatch) + if err := _TerminusFacet.contract.UnpackLog(event, "TransferBatch", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TerminusFacetTransferSingleIterator is returned from FilterTransferSingle and is used to iterate over the raw logs and unpacked data for TransferSingle events raised by the TerminusFacet contract. +type TerminusFacetTransferSingleIterator struct { + Event *TerminusFacetTransferSingle // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TerminusFacetTransferSingleIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TerminusFacetTransferSingle) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TerminusFacetTransferSingle) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TerminusFacetTransferSingleIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TerminusFacetTransferSingleIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TerminusFacetTransferSingle represents a TransferSingle event raised by the TerminusFacet contract. +type TerminusFacetTransferSingle struct { + Operator common.Address + From common.Address + To common.Address + Id *big.Int + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransferSingle is a free log retrieval operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. +// +// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) +func (_TerminusFacet *TerminusFacetFilterer) FilterTransferSingle(opts *bind.FilterOpts, operator []common.Address, from []common.Address, to []common.Address) (*TerminusFacetTransferSingleIterator, error) { + + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _TerminusFacet.contract.FilterLogs(opts, "TransferSingle", operatorRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &TerminusFacetTransferSingleIterator{contract: _TerminusFacet.contract, event: "TransferSingle", logs: logs, sub: sub}, nil +} + +// WatchTransferSingle is a free log subscription operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. +// +// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) +func (_TerminusFacet *TerminusFacetFilterer) WatchTransferSingle(opts *bind.WatchOpts, sink chan<- *TerminusFacetTransferSingle, operator []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _TerminusFacet.contract.WatchLogs(opts, "TransferSingle", operatorRule, fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TerminusFacetTransferSingle) + if err := _TerminusFacet.contract.UnpackLog(event, "TransferSingle", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransferSingle is a log parse operation binding the contract event 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62. +// +// Solidity: event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value) +func (_TerminusFacet *TerminusFacetFilterer) ParseTransferSingle(log types.Log) (*TerminusFacetTransferSingle, error) { + event := new(TerminusFacetTransferSingle) + if err := _TerminusFacet.contract.UnpackLog(event, "TransferSingle", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TerminusFacetURIIterator is returned from FilterURI and is used to iterate over the raw logs and unpacked data for URI events raised by the TerminusFacet contract. +type TerminusFacetURIIterator struct { + Event *TerminusFacetURI // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *TerminusFacetURIIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(TerminusFacetURI) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(TerminusFacetURI) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *TerminusFacetURIIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TerminusFacetURIIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TerminusFacetURI represents a URI event raised by the TerminusFacet contract. +type TerminusFacetURI struct { + Value string + Id *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterURI is a free log retrieval operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. +// +// Solidity: event URI(string value, uint256 indexed id) +func (_TerminusFacet *TerminusFacetFilterer) FilterURI(opts *bind.FilterOpts, id []*big.Int) (*TerminusFacetURIIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _TerminusFacet.contract.FilterLogs(opts, "URI", idRule) + if err != nil { + return nil, err + } + return &TerminusFacetURIIterator{contract: _TerminusFacet.contract, event: "URI", logs: logs, sub: sub}, nil +} + +// WatchURI is a free log subscription operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. +// +// Solidity: event URI(string value, uint256 indexed id) +func (_TerminusFacet *TerminusFacetFilterer) WatchURI(opts *bind.WatchOpts, sink chan<- *TerminusFacetURI, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _TerminusFacet.contract.WatchLogs(opts, "URI", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(TerminusFacetURI) + if err := _TerminusFacet.contract.UnpackLog(event, "URI", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseURI is a log parse operation binding the contract event 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b. +// +// Solidity: event URI(string value, uint256 indexed id) +func (_TerminusFacet *TerminusFacetFilterer) ParseURI(log types.Log) (*TerminusFacetURI, error) { + event := new(TerminusFacetURI) + if err := _TerminusFacet.contract.UnpackLog(event, "URI", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func CreateTerminusFacetDeploymentCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc string + var gasLimit uint64 + var simulate bool + var timeout uint + var safeAddress, safeApi, safeCreateCall, safeSaltRaw, safeNonceRaw string + var safeOperationType uint8 + var salt [32]byte + var predictAddress bool + var safeNonce *big.Int + + cmd := &cobra.Command{ + Use: "deploy", + Short: "Deploy a new TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if safeCreateCall == "" { + fmt.Println("--safe-create-call not specified, using default (0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4)") + safeCreateCall = "0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4" + } + if !common.IsHexAddress(safeCreateCall) { + return fmt.Errorf("--safe-create-call is not a valid Ethereum address") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeSaltRaw == "" { + fmt.Println("--safe-salt not specified, generating random salt") + _, err := rand.Read(salt[:]) + if err != nil { + return fmt.Errorf("failed to generate random salt: %v", err) + } + // prompt user to accept random salt + fmt.Println("Generated salt:", common.Bytes2Hex(salt[:])) + fmt.Println("Please check the salt and confirm (y/n)") + var confirm string + fmt.Scanln(&confirm) + if confirm != "y" && confirm != "Y" && confirm != "\n" && confirm != "" { + return fmt.Errorf("salt not accepted, please specify a valid salt") + } + } else { + copy(salt[:], safeSaltRaw) + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + if safeAddress != "" { + // Generate deploy bytecode with constructor arguments + deployBytecode, err := generateTerminusFacetDeployBytecode() + if err != nil { + return fmt.Errorf("failed to generate deploy bytecode: %v", err) + } + + // Create Safe proposal for deployment + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + if predictAddress { + fmt.Println("Predicting deployment address...") + from := common.HexToAddress(safeAddress) + if safeOperationType == 0 { + from = common.HexToAddress(safeCreateCall) + } + deploymentAddress, err := PredictDeploymentAddressSafe(from, salt, deployBytecode) + if err != nil { + return fmt.Errorf("failed to predict deployment address: %v", err) + } + fmt.Println("Predicted deployment address:", deploymentAddress.Hex()) + return nil + } else { + fmt.Println("Creating Safe proposal...") + err = DeployWithSafe(client, key, common.HexToAddress(safeAddress), common.HexToAddress(safeCreateCall), value, safeApi, deployBytecode, SafeOperationType(safeOperationType), salt, safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + } + + return nil + } + + address, deploymentTransaction, _, deploymentErr := DeployTerminusFacet( + transactionOpts, + client, + ) + if deploymentErr != nil { + return deploymentErr + } + + cmd.Printf("Transaction hash: %s\nContract address: %s\n", deploymentTransaction.Hash().Hex(), address.Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + Data: deploymentTransaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := deploymentTransaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().StringVar(&safeCreateCall, "safe-create-call", "", "Address of the CreateCall contract (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 1, "Safe operation type: 0 (Call) or 1 (DelegateCall) - default is 1") + cmd.Flags().StringVar(&safeSaltRaw, "safe-salt", "", "Salt to use for the Safe transaction") + cmd.Flags().BoolVar(&predictAddress, "safe-predict-address", false, "Predict the deployment address (only works for Safe transactions)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + return cmd +} + +func generateTerminusFacetDeployBytecode() ([]byte, error) { + abiPacked, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return nil, fmt.Errorf("failed to get ABI: %v", err) + } + + constructorArguments, err := abiPacked.Pack("") + if err != nil { + return nil, fmt.Errorf("failed to pack constructor arguments: %v", err) + } + + deployBytecode := append(common.FromHex(TerminusFacetMetaData.Bin), constructorArguments...) + return deployBytecode, nil +} + +func CreateBalanceOfCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var account common.Address + var accountRaw string + var id *big.Int + var idRaw string + + var capture0 *big.Int + + cmd := &cobra.Command{ + Use: "balance-of", + Short: "Call the BalanceOf view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if accountRaw == "" { + return fmt.Errorf("--account argument not specified") + } else if !common.IsHexAddress(accountRaw) { + return fmt.Errorf("--account argument is not a valid Ethereum address") + } + account = common.HexToAddress(accountRaw) + + if idRaw == "" { + return fmt.Errorf("--id argument not specified") + } + id = new(big.Int) + id.SetString(idRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.BalanceOf( + account, + id, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.String()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&accountRaw, "account", "", "account argument (common.Address)") + cmd.Flags().StringVar(&idRaw, "id", "", "id argument") + + return cmd +} +func CreateBalanceOfBatchCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var accounts []common.Address + var accountsRaw string + var ids []*big.Int + var idsRaw string + + var capture0 []*big.Int + + cmd := &cobra.Command{ + Use: "balance-of-batch", + Short: "Call the BalanceOfBatch view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if accountsRaw == "" { + return fmt.Errorf("--accounts argument not specified") + } else if strings.HasPrefix(accountsRaw, "@") { + filename := strings.TrimPrefix(accountsRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &accounts) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(accountsRaw), &accounts) + if unmarshalErr != nil { + return unmarshalErr + } + } + + if idsRaw == "" { + return fmt.Errorf("--ids argument not specified") + } else if strings.HasPrefix(idsRaw, "@") { + filename := strings.TrimPrefix(idsRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &ids) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(idsRaw), &ids) + if unmarshalErr != nil { + return unmarshalErr + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.BalanceOfBatch( + accounts, + ids, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %v\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&accountsRaw, "accounts", "", "accounts argument ([]common.Address)") + cmd.Flags().StringVar(&idsRaw, "ids", "", "ids argument ([]*big.Int)") + + return cmd +} +func CreateContractUriCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var capture0 string + + cmd := &cobra.Command{ + Use: "contract-uri", + Short: "Call the ContractURI view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.ContractURI() + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + return cmd +} +func CreateIsApprovedForAllCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var account common.Address + var accountRaw string + var operator common.Address + var operatorRaw string + + var capture0 bool + + cmd := &cobra.Command{ + Use: "is-approved-for-all", + Short: "Call the IsApprovedForAll view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if accountRaw == "" { + return fmt.Errorf("--account argument not specified") + } else if !common.IsHexAddress(accountRaw) { + return fmt.Errorf("--account argument is not a valid Ethereum address") + } + account = common.HexToAddress(accountRaw) + + if operatorRaw == "" { + return fmt.Errorf("--operator argument not specified") + } else if !common.IsHexAddress(operatorRaw) { + return fmt.Errorf("--operator argument is not a valid Ethereum address") + } + operator = common.HexToAddress(operatorRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.IsApprovedForAll( + account, + operator, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %t\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&accountRaw, "account", "", "account argument (common.Address)") + cmd.Flags().StringVar(&operatorRaw, "operator", "", "operator argument (common.Address)") + + return cmd +} +func CreateIsApprovedForPoolCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var poolID *big.Int + var poolIDRaw string + var operator common.Address + var operatorRaw string + + var capture0 bool + + cmd := &cobra.Command{ + Use: "is-approved-for-pool", + Short: "Call the IsApprovedForPool view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + if operatorRaw == "" { + return fmt.Errorf("--operator argument not specified") + } else if !common.IsHexAddress(operatorRaw) { + return fmt.Errorf("--operator argument is not a valid Ethereum address") + } + operator = common.HexToAddress(operatorRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.IsApprovedForPool( + poolID, + operator, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %t\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&operatorRaw, "operator", "", "operator argument (common.Address)") + + return cmd +} +func CreatePaymentTokenCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var capture0 common.Address + + cmd := &cobra.Command{ + Use: "payment-token", + Short: "Call the PaymentToken view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.PaymentToken() + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.Hex()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + return cmd +} +func CreatePoolBasePriceCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var capture0 *big.Int + + cmd := &cobra.Command{ + Use: "pool-base-price", + Short: "Call the PoolBasePrice view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.PoolBasePrice() + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.String()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + return cmd +} +func CreatePoolIsBurnableCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var poolID *big.Int + var poolIDRaw string + + var capture0 bool + + cmd := &cobra.Command{ + Use: "pool-is-burnable", + Short: "Call the PoolIsBurnable view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.PoolIsBurnable( + poolID, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %t\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + + return cmd +} +func CreatePoolIsTransferableCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var poolID *big.Int + var poolIDRaw string + + var capture0 bool + + cmd := &cobra.Command{ + Use: "pool-is-transferable", + Short: "Call the PoolIsTransferable view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.PoolIsTransferable( + poolID, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %t\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + + return cmd +} +func CreateSupportsInterfaceCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var interfaceId [4]byte + var interfaceIdRaw string + + var capture0 bool + + cmd := &cobra.Command{ + Use: "supports-interface", + Short: "Call the SupportsInterface view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + var interfaceIdIntermediate []byte + + var interfaceIdIntermediateHexDecodeErr error + interfaceIdIntermediate, interfaceIdIntermediateHexDecodeErr = hex.DecodeString(interfaceIdRaw) + if interfaceIdIntermediateHexDecodeErr != nil { + return interfaceIdIntermediateHexDecodeErr + } + + copy(interfaceId[:], interfaceIdIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.SupportsInterface( + interfaceId, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %t\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&interfaceIdRaw, "interface-id", "", "interface-id argument ([4]byte)") + + return cmd +} +func CreateTerminusControllerCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var capture0 common.Address + + cmd := &cobra.Command{ + Use: "terminus-controller", + Short: "Call the TerminusController view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.TerminusController() + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.Hex()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + return cmd +} +func CreateTerminusPoolCapacityCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var poolID *big.Int + var poolIDRaw string + + var capture0 *big.Int + + cmd := &cobra.Command{ + Use: "terminus-pool-capacity", + Short: "Call the TerminusPoolCapacity view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.TerminusPoolCapacity( + poolID, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.String()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + + return cmd +} +func CreateTerminusPoolControllerCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var poolID *big.Int + var poolIDRaw string + + var capture0 common.Address + + cmd := &cobra.Command{ + Use: "terminus-pool-controller", + Short: "Call the TerminusPoolController view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.TerminusPoolController( + poolID, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.Hex()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + + return cmd +} +func CreateTerminusPoolSupplyCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var poolID *big.Int + var poolIDRaw string + + var capture0 *big.Int + + cmd := &cobra.Command{ + Use: "terminus-pool-supply", + Short: "Call the TerminusPoolSupply view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.TerminusPoolSupply( + poolID, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.String()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + + return cmd +} +func CreateTotalPoolsCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var capture0 *big.Int + + cmd := &cobra.Command{ + Use: "total-pools", + Short: "Call the TotalPools view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.TotalPools() + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.String()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + return cmd +} +func CreateUriCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var poolID *big.Int + var poolIDRaw string + + var capture0 string + + cmd := &cobra.Command{ + Use: "uri", + Short: "Call the Uri view method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := TerminusFacetCallerSession{ + Contract: &contract.TerminusFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.Uri( + poolID, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + + return cmd +} + +func CreateApproveForPoolCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var poolID *big.Int + var poolIDRaw string + var operator common.Address + var operatorRaw string + + cmd := &cobra.Command{ + Use: "approve-for-pool", + Short: "Execute the ApproveForPool method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + if operatorRaw == "" { + return fmt.Errorf("--operator argument not specified") + } else if !common.IsHexAddress(operatorRaw) { + return fmt.Errorf("--operator argument is not a valid Ethereum address") + } + operator = common.HexToAddress(operatorRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "approveForPool" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + poolID, + operator, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.ApproveForPool( + + poolID, + operator, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&operatorRaw, "operator", "", "operator argument (common.Address)") + + return cmd +} +func CreateBurnCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var from0 common.Address + var from0Raw string + var poolID *big.Int + var poolIDRaw string + var amount *big.Int + var amountRaw string + + cmd := &cobra.Command{ + Use: "burn", + Short: "Execute the Burn method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if from0Raw == "" { + return fmt.Errorf("--from-0 argument not specified") + } else if !common.IsHexAddress(from0Raw) { + return fmt.Errorf("--from-0 argument is not a valid Ethereum address") + } + from0 = common.HexToAddress(from0Raw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + if amountRaw == "" { + return fmt.Errorf("--amount argument not specified") + } + amount = new(big.Int) + amount.SetString(amountRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "burn" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + from0, + poolID, + amount, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.Burn( + + from0, + poolID, + amount, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&from0Raw, "from-0", "", "from-0 argument (common.Address)") + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&amountRaw, "amount", "", "amount argument") + + return cmd +} +func CreateCreatePoolV1Command() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var capacity *big.Int + var capacityRaw string + var transferable bool + var transferableRaw string + var burnable bool + var burnableRaw string + + cmd := &cobra.Command{ + Use: "create-pool-v-1", + Short: "Execute the CreatePoolV1 method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if capacityRaw == "" { + return fmt.Errorf("--capacity argument not specified") + } + capacity = new(big.Int) + capacity.SetString(capacityRaw, 0) + + transferableRawLower := strings.ToLower(transferableRaw) + switch transferableRawLower { + case "true", "t", "y", "yes", "1": + transferable = true + case "false", "f", "n", "no", "0": + transferable = false + default: + return fmt.Errorf("--transferable argument is not valid (value: %s)", transferableRaw) + } + + burnableRawLower := strings.ToLower(burnableRaw) + switch burnableRawLower { + case "true", "t", "y", "yes", "1": + burnable = true + case "false", "f", "n", "no", "0": + burnable = false + default: + return fmt.Errorf("--burnable argument is not valid (value: %s)", burnableRaw) + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "createPoolV1" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + capacity, + transferable, + burnable, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.CreatePoolV1( + + capacity, + transferable, + burnable, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&capacityRaw, "capacity", "", "capacity argument") + cmd.Flags().StringVar(&transferableRaw, "transferable", "", "transferable argument (true, t, y, yes, 1 OR false, f, n, no, 0)") + cmd.Flags().StringVar(&burnableRaw, "burnable", "", "burnable argument (true, t, y, yes, 1 OR false, f, n, no, 0)") + + return cmd +} +func CreateCreatePoolV2Command() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var capacity *big.Int + var capacityRaw string + var transferable bool + var transferableRaw string + var burnable bool + var burnableRaw string + var poolURI string + + cmd := &cobra.Command{ + Use: "create-pool-v-2", + Short: "Execute the CreatePoolV2 method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if capacityRaw == "" { + return fmt.Errorf("--capacity argument not specified") + } + capacity = new(big.Int) + capacity.SetString(capacityRaw, 0) + + transferableRawLower := strings.ToLower(transferableRaw) + switch transferableRawLower { + case "true", "t", "y", "yes", "1": + transferable = true + case "false", "f", "n", "no", "0": + transferable = false + default: + return fmt.Errorf("--transferable argument is not valid (value: %s)", transferableRaw) + } + + burnableRawLower := strings.ToLower(burnableRaw) + switch burnableRawLower { + case "true", "t", "y", "yes", "1": + burnable = true + case "false", "f", "n", "no", "0": + burnable = false + default: + return fmt.Errorf("--burnable argument is not valid (value: %s)", burnableRaw) + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "createPoolV2" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + capacity, + transferable, + burnable, + poolURI, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.CreatePoolV2( + + capacity, + transferable, + burnable, + poolURI, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&capacityRaw, "capacity", "", "capacity argument") + cmd.Flags().StringVar(&transferableRaw, "transferable", "", "transferable argument (true, t, y, yes, 1 OR false, f, n, no, 0)") + cmd.Flags().StringVar(&burnableRaw, "burnable", "", "burnable argument (true, t, y, yes, 1 OR false, f, n, no, 0)") + cmd.Flags().StringVar(&poolURI, "pool-uri", "", "pool-uri argument") + + return cmd +} +func CreateCreateSimplePoolCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var capacity *big.Int + var capacityRaw string + + cmd := &cobra.Command{ + Use: "create-simple-pool", + Short: "Execute the CreateSimplePool method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if capacityRaw == "" { + return fmt.Errorf("--capacity argument not specified") + } + capacity = new(big.Int) + capacity.SetString(capacityRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "createSimplePool" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + capacity, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.CreateSimplePool( + + capacity, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&capacityRaw, "capacity", "", "capacity argument") + + return cmd +} +func CreateInitCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + cmd := &cobra.Command{ + Use: "init", + Short: "Execute the Init method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "init" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.Init() + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + return cmd +} +func CreateMintCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var to0 common.Address + var to0Raw string + var poolID *big.Int + var poolIDRaw string + var amount *big.Int + var amountRaw string + var data []byte + var dataRaw string + + cmd := &cobra.Command{ + Use: "mint", + Short: "Execute the Mint method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if to0Raw == "" { + return fmt.Errorf("--to-0 argument not specified") + } else if !common.IsHexAddress(to0Raw) { + return fmt.Errorf("--to-0 argument is not a valid Ethereum address") + } + to0 = common.HexToAddress(to0Raw) + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + if amountRaw == "" { + return fmt.Errorf("--amount argument not specified") + } + amount = new(big.Int) + amount.SetString(amountRaw, 0) + + var dataIntermediate []byte + + var dataIntermediateHexDecodeErr error + dataIntermediate, dataIntermediateHexDecodeErr = hex.DecodeString(dataRaw) + if dataIntermediateHexDecodeErr != nil { + return dataIntermediateHexDecodeErr + } + + copy(data[:], dataIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "mint" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + to0, + poolID, + amount, + data, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.Mint( + + to0, + poolID, + amount, + data, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&to0Raw, "to-0", "", "to-0 argument (common.Address)") + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&amountRaw, "amount", "", "amount argument") + cmd.Flags().StringVar(&dataRaw, "data", "", "data argument ([]byte)") + + return cmd +} +func CreateMintBatchCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var to0 common.Address + var to0Raw string + var poolIDs []*big.Int + var poolIDsRaw string + var amounts []*big.Int + var amountsRaw string + var data []byte + var dataRaw string + + cmd := &cobra.Command{ + Use: "mint-batch", + Short: "Execute the MintBatch method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if to0Raw == "" { + return fmt.Errorf("--to-0 argument not specified") + } else if !common.IsHexAddress(to0Raw) { + return fmt.Errorf("--to-0 argument is not a valid Ethereum address") + } + to0 = common.HexToAddress(to0Raw) + + if poolIDsRaw == "" { + return fmt.Errorf("--pool-i-ds argument not specified") + } else if strings.HasPrefix(poolIDsRaw, "@") { + filename := strings.TrimPrefix(poolIDsRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &poolIDs) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(poolIDsRaw), &poolIDs) + if unmarshalErr != nil { + return unmarshalErr + } + } + + if amountsRaw == "" { + return fmt.Errorf("--amounts argument not specified") + } else if strings.HasPrefix(amountsRaw, "@") { + filename := strings.TrimPrefix(amountsRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &amounts) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(amountsRaw), &amounts) + if unmarshalErr != nil { + return unmarshalErr + } + } + + var dataIntermediate []byte + + var dataIntermediateHexDecodeErr error + dataIntermediate, dataIntermediateHexDecodeErr = hex.DecodeString(dataRaw) + if dataIntermediateHexDecodeErr != nil { + return dataIntermediateHexDecodeErr + } + + copy(data[:], dataIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "mintBatch" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + to0, + poolIDs, + amounts, + data, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.MintBatch( + + to0, + poolIDs, + amounts, + data, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&to0Raw, "to-0", "", "to-0 argument (common.Address)") + cmd.Flags().StringVar(&poolIDsRaw, "pool-i-ds", "", "pool-i-ds argument ([]*big.Int)") + cmd.Flags().StringVar(&amountsRaw, "amounts", "", "amounts argument ([]*big.Int)") + cmd.Flags().StringVar(&dataRaw, "data", "", "data argument ([]byte)") + + return cmd +} +func CreatePoolMintBatchCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var id *big.Int + var idRaw string + var toAddresses []common.Address + var toAddressesRaw string + var amounts []*big.Int + var amountsRaw string + + cmd := &cobra.Command{ + Use: "pool-mint-batch", + Short: "Execute the PoolMintBatch method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if idRaw == "" { + return fmt.Errorf("--id argument not specified") + } + id = new(big.Int) + id.SetString(idRaw, 0) + + if toAddressesRaw == "" { + return fmt.Errorf("--to-addresses argument not specified") + } else if strings.HasPrefix(toAddressesRaw, "@") { + filename := strings.TrimPrefix(toAddressesRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &toAddresses) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(toAddressesRaw), &toAddresses) + if unmarshalErr != nil { + return unmarshalErr + } + } + + if amountsRaw == "" { + return fmt.Errorf("--amounts argument not specified") + } else if strings.HasPrefix(amountsRaw, "@") { + filename := strings.TrimPrefix(amountsRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &amounts) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(amountsRaw), &amounts) + if unmarshalErr != nil { + return unmarshalErr + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "poolMintBatch" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + id, + toAddresses, + amounts, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.PoolMintBatch( + + id, + toAddresses, + amounts, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&idRaw, "id", "", "id argument") + cmd.Flags().StringVar(&toAddressesRaw, "to-addresses", "", "to-addresses argument ([]common.Address)") + cmd.Flags().StringVar(&amountsRaw, "amounts", "", "amounts argument ([]*big.Int)") + + return cmd +} +func CreateSafeBatchTransferFromCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var from0 common.Address + var from0Raw string + var to0 common.Address + var to0Raw string + var ids []*big.Int + var idsRaw string + var amounts []*big.Int + var amountsRaw string + var data []byte + var dataRaw string + + cmd := &cobra.Command{ + Use: "safe-batch-transfer-from", + Short: "Execute the SafeBatchTransferFrom method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if from0Raw == "" { + return fmt.Errorf("--from-0 argument not specified") + } else if !common.IsHexAddress(from0Raw) { + return fmt.Errorf("--from-0 argument is not a valid Ethereum address") + } + from0 = common.HexToAddress(from0Raw) + + if to0Raw == "" { + return fmt.Errorf("--to-0 argument not specified") + } else if !common.IsHexAddress(to0Raw) { + return fmt.Errorf("--to-0 argument is not a valid Ethereum address") + } + to0 = common.HexToAddress(to0Raw) + + if idsRaw == "" { + return fmt.Errorf("--ids argument not specified") + } else if strings.HasPrefix(idsRaw, "@") { + filename := strings.TrimPrefix(idsRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &ids) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(idsRaw), &ids) + if unmarshalErr != nil { + return unmarshalErr + } + } + + if amountsRaw == "" { + return fmt.Errorf("--amounts argument not specified") + } else if strings.HasPrefix(amountsRaw, "@") { + filename := strings.TrimPrefix(amountsRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &amounts) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(amountsRaw), &amounts) + if unmarshalErr != nil { + return unmarshalErr + } + } + + var dataIntermediate []byte + + var dataIntermediateHexDecodeErr error + dataIntermediate, dataIntermediateHexDecodeErr = hex.DecodeString(dataRaw) + if dataIntermediateHexDecodeErr != nil { + return dataIntermediateHexDecodeErr + } + + copy(data[:], dataIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "safeBatchTransferFrom" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + from0, + to0, + ids, + amounts, + data, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SafeBatchTransferFrom( + + from0, + to0, + ids, + amounts, + data, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&from0Raw, "from-0", "", "from-0 argument (common.Address)") + cmd.Flags().StringVar(&to0Raw, "to-0", "", "to-0 argument (common.Address)") + cmd.Flags().StringVar(&idsRaw, "ids", "", "ids argument ([]*big.Int)") + cmd.Flags().StringVar(&amountsRaw, "amounts", "", "amounts argument ([]*big.Int)") + cmd.Flags().StringVar(&dataRaw, "data", "", "data argument ([]byte)") + + return cmd +} +func CreateSafeTransferFromCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var from0 common.Address + var from0Raw string + var to0 common.Address + var to0Raw string + var id *big.Int + var idRaw string + var amount *big.Int + var amountRaw string + var data []byte + var dataRaw string + + cmd := &cobra.Command{ + Use: "safe-transfer-from", + Short: "Execute the SafeTransferFrom method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if from0Raw == "" { + return fmt.Errorf("--from-0 argument not specified") + } else if !common.IsHexAddress(from0Raw) { + return fmt.Errorf("--from-0 argument is not a valid Ethereum address") + } + from0 = common.HexToAddress(from0Raw) + + if to0Raw == "" { + return fmt.Errorf("--to-0 argument not specified") + } else if !common.IsHexAddress(to0Raw) { + return fmt.Errorf("--to-0 argument is not a valid Ethereum address") + } + to0 = common.HexToAddress(to0Raw) + + if idRaw == "" { + return fmt.Errorf("--id argument not specified") + } + id = new(big.Int) + id.SetString(idRaw, 0) + + if amountRaw == "" { + return fmt.Errorf("--amount argument not specified") + } + amount = new(big.Int) + amount.SetString(amountRaw, 0) + + var dataIntermediate []byte + + var dataIntermediateHexDecodeErr error + dataIntermediate, dataIntermediateHexDecodeErr = hex.DecodeString(dataRaw) + if dataIntermediateHexDecodeErr != nil { + return dataIntermediateHexDecodeErr + } + + copy(data[:], dataIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "safeTransferFrom" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + from0, + to0, + id, + amount, + data, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SafeTransferFrom( + + from0, + to0, + id, + amount, + data, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&from0Raw, "from-0", "", "from-0 argument (common.Address)") + cmd.Flags().StringVar(&to0Raw, "to-0", "", "to-0 argument (common.Address)") + cmd.Flags().StringVar(&idRaw, "id", "", "id argument") + cmd.Flags().StringVar(&amountRaw, "amount", "", "amount argument") + cmd.Flags().StringVar(&dataRaw, "data", "", "data argument ([]byte)") + + return cmd +} +func CreateSetApprovalForAllCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var operator common.Address + var operatorRaw string + var approved bool + var approvedRaw string + + cmd := &cobra.Command{ + Use: "set-approval-for-all", + Short: "Execute the SetApprovalForAll method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if operatorRaw == "" { + return fmt.Errorf("--operator argument not specified") + } else if !common.IsHexAddress(operatorRaw) { + return fmt.Errorf("--operator argument is not a valid Ethereum address") + } + operator = common.HexToAddress(operatorRaw) + + approvedRawLower := strings.ToLower(approvedRaw) + switch approvedRawLower { + case "true", "t", "y", "yes", "1": + approved = true + case "false", "f", "n", "no", "0": + approved = false + default: + return fmt.Errorf("--approved argument is not valid (value: %s)", approvedRaw) + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setApprovalForAll" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + operator, + approved, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetApprovalForAll( + + operator, + approved, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&operatorRaw, "operator", "", "operator argument (common.Address)") + cmd.Flags().StringVar(&approvedRaw, "approved", "", "approved argument (true, t, y, yes, 1 OR false, f, n, no, 0)") + + return cmd +} +func CreateSetContractUriCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var contractURI string + + cmd := &cobra.Command{ + Use: "set-contract-uri", + Short: "Execute the SetContractURI method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setContractUri" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + contractURI, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetContractURI( + + contractURI, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&contractURI, "contract-uri", "", "contract-uri argument") + + return cmd +} +func CreateSetControllerCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var newController common.Address + var newControllerRaw string + + cmd := &cobra.Command{ + Use: "set-controller", + Short: "Execute the SetController method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if newControllerRaw == "" { + return fmt.Errorf("--new-controller argument not specified") + } else if !common.IsHexAddress(newControllerRaw) { + return fmt.Errorf("--new-controller argument is not a valid Ethereum address") + } + newController = common.HexToAddress(newControllerRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setController" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + newController, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetController( + + newController, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&newControllerRaw, "new-controller", "", "new-controller argument (common.Address)") + + return cmd +} +func CreateSetPaymentTokenCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var newPaymentToken common.Address + var newPaymentTokenRaw string + + cmd := &cobra.Command{ + Use: "set-payment-token", + Short: "Execute the SetPaymentToken method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if newPaymentTokenRaw == "" { + return fmt.Errorf("--new-payment-token argument not specified") + } else if !common.IsHexAddress(newPaymentTokenRaw) { + return fmt.Errorf("--new-payment-token argument is not a valid Ethereum address") + } + newPaymentToken = common.HexToAddress(newPaymentTokenRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setPaymentToken" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + newPaymentToken, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetPaymentToken( + + newPaymentToken, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&newPaymentTokenRaw, "new-payment-token", "", "new-payment-token argument (common.Address)") + + return cmd +} +func CreateSetPoolBasePriceCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var newBasePrice *big.Int + var newBasePriceRaw string + + cmd := &cobra.Command{ + Use: "set-pool-base-price", + Short: "Execute the SetPoolBasePrice method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if newBasePriceRaw == "" { + return fmt.Errorf("--new-base-price argument not specified") + } + newBasePrice = new(big.Int) + newBasePrice.SetString(newBasePriceRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setPoolBasePrice" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + newBasePrice, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetPoolBasePrice( + + newBasePrice, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&newBasePriceRaw, "new-base-price", "", "new-base-price argument") + + return cmd +} +func CreateSetPoolBurnableCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var poolID *big.Int + var poolIDRaw string + var burnable bool + var burnableRaw string + + cmd := &cobra.Command{ + Use: "set-pool-burnable", + Short: "Execute the SetPoolBurnable method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + burnableRawLower := strings.ToLower(burnableRaw) + switch burnableRawLower { + case "true", "t", "y", "yes", "1": + burnable = true + case "false", "f", "n", "no", "0": + burnable = false + default: + return fmt.Errorf("--burnable argument is not valid (value: %s)", burnableRaw) + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setPoolBurnable" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + poolID, + burnable, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetPoolBurnable( + + poolID, + burnable, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&burnableRaw, "burnable", "", "burnable argument (true, t, y, yes, 1 OR false, f, n, no, 0)") + + return cmd +} +func CreateSetPoolControllerCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var poolID *big.Int + var poolIDRaw string + var newController common.Address + var newControllerRaw string + + cmd := &cobra.Command{ + Use: "set-pool-controller", + Short: "Execute the SetPoolController method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + if newControllerRaw == "" { + return fmt.Errorf("--new-controller argument not specified") + } else if !common.IsHexAddress(newControllerRaw) { + return fmt.Errorf("--new-controller argument is not a valid Ethereum address") + } + newController = common.HexToAddress(newControllerRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setPoolController" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + poolID, + newController, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetPoolController( + + poolID, + newController, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&newControllerRaw, "new-controller", "", "new-controller argument (common.Address)") + + return cmd +} +func CreateSetPoolTransferableCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var poolID *big.Int + var poolIDRaw string + var transferable bool + var transferableRaw string + + cmd := &cobra.Command{ + Use: "set-pool-transferable", + Short: "Execute the SetPoolTransferable method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + transferableRawLower := strings.ToLower(transferableRaw) + switch transferableRawLower { + case "true", "t", "y", "yes", "1": + transferable = true + case "false", "f", "n", "no", "0": + transferable = false + default: + return fmt.Errorf("--transferable argument is not valid (value: %s)", transferableRaw) + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setPoolTransferable" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + poolID, + transferable, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetPoolTransferable( + + poolID, + transferable, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&transferableRaw, "transferable", "", "transferable argument (true, t, y, yes, 1 OR false, f, n, no, 0)") + + return cmd +} +func CreateSetUriCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var poolID *big.Int + var poolIDRaw string + var poolURI string + + cmd := &cobra.Command{ + Use: "set-uri", + Short: "Execute the SetURI method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "setUri" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + poolID, + poolURI, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.SetURI( + + poolID, + poolURI, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&poolURI, "pool-uri", "", "pool-uri argument") + + return cmd +} +func CreateUnapproveForPoolCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var poolID *big.Int + var poolIDRaw string + var operator common.Address + var operatorRaw string + + cmd := &cobra.Command{ + Use: "unapprove-for-pool", + Short: "Execute the UnapproveForPool method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if poolIDRaw == "" { + return fmt.Errorf("--pool-id argument not specified") + } + poolID = new(big.Int) + poolID.SetString(poolIDRaw, 0) + + if operatorRaw == "" { + return fmt.Errorf("--operator argument not specified") + } else if !common.IsHexAddress(operatorRaw) { + return fmt.Errorf("--operator argument is not a valid Ethereum address") + } + operator = common.HexToAddress(operatorRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "unapproveForPool" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + poolID, + operator, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.UnapproveForPool( + + poolID, + operator, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&poolIDRaw, "pool-id", "", "pool-id argument") + cmd.Flags().StringVar(&operatorRaw, "operator", "", "operator argument (common.Address)") + + return cmd +} +func CreateWithdrawPaymentsCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var toAddress0 common.Address + var toAddress0Raw string + var amount *big.Int + var amountRaw string + + cmd := &cobra.Command{ + Use: "withdraw-payments", + Short: "Execute the WithdrawPayments method on a TerminusFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if toAddress0Raw == "" { + return fmt.Errorf("--to-address-0 argument not specified") + } else if !common.IsHexAddress(toAddress0Raw) { + return fmt.Errorf("--to-address-0 argument is not a valid Ethereum address") + } + toAddress0 = common.HexToAddress(toAddress0Raw) + + if amountRaw == "" { + return fmt.Errorf("--amount argument not specified") + } + amount = new(big.Int) + amount.SetString(amountRaw, 0) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusFacetTransactorSession{ + Contract: &contract.TerminusFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "withdrawPayments" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + toAddress0, + amount, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.WithdrawPayments( + + toAddress0, + amount, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&toAddress0Raw, "to-address-0", "", "to-address-0 argument (common.Address)") + cmd.Flags().StringVar(&amountRaw, "amount", "", "amount argument") + + return cmd +} + +var ErrNoRPCURL error = errors.New("no RPC URL provided -- please pass an RPC URL from the command line or set the TERMINUS_FACET_RPC_URL environment variable") + +// Generates an Ethereum client to the JSONRPC API at the given URL. If rpcURL is empty, then it +// attempts to read the RPC URL from the TERMINUS_FACET_RPC_URL environment variable. If that is empty, +// too, then it returns an error. +func NewClient(rpcURL string) (*ethclient.Client, error) { + if rpcURL == "" { + rpcURL = os.Getenv("TERMINUS_FACET_RPC_URL") + } + + if rpcURL == "" { + return nil, ErrNoRPCURL + } + + client, err := ethclient.Dial(rpcURL) + return client, err +} + +// Creates a new context to be used when interacting with the chain client. +func NewChainContext(timeout uint) (context.Context, context.CancelFunc) { + baseCtx := context.Background() + parsedTimeout := time.Duration(timeout) * time.Second + ctx, cancel := context.WithTimeout(baseCtx, parsedTimeout) + return ctx, cancel +} + +// Unlocks a key from a keystore (byte contents of a keystore file) with the given password. +func UnlockKeystore(keystoreData []byte, password string) (*keystore.Key, error) { + key, err := keystore.DecryptKey(keystoreData, password) + return key, err +} + +// Loads a key from file, prompting the user for the password if it is not provided as a function argument. +func KeyFromFile(keystoreFile string, password string) (*keystore.Key, error) { + var emptyKey *keystore.Key + keystoreContent, readErr := os.ReadFile(keystoreFile) + if readErr != nil { + return emptyKey, readErr + } + + // If password is "", prompt user for password. + if password == "" { + fmt.Printf("Please provide a password for keystore (%s): ", keystoreFile) + passwordRaw, inputErr := term.ReadPassword(int(os.Stdin.Fd())) + if inputErr != nil { + return emptyKey, fmt.Errorf("error reading password: %s", inputErr.Error()) + } + fmt.Print("\n") + password = string(passwordRaw) + } + + key, err := UnlockKeystore(keystoreContent, password) + return key, err +} + +// This method is used to set the parameters on a view call from command line arguments (represented mostly as +// strings). +func SetCallParametersFromArgs(opts *bind.CallOpts, pending bool, fromAddress, blockNumber string) { + if pending { + opts.Pending = true + } + + if fromAddress != "" { + opts.From = common.HexToAddress(fromAddress) + } + + if blockNumber != "" { + opts.BlockNumber = new(big.Int) + opts.BlockNumber.SetString(blockNumber, 0) + } +} + +// This method is used to set the parameters on a transaction from command line arguments (represented mostly as +// strings). +func SetTransactionParametersFromArgs(opts *bind.TransactOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas string, gasLimit uint64, noSend bool) { + if nonce != "" { + opts.Nonce = new(big.Int) + opts.Nonce.SetString(nonce, 0) + } + + if value != "" { + opts.Value = new(big.Int) + opts.Value.SetString(value, 0) + } + + if gasPrice != "" { + opts.GasPrice = new(big.Int) + opts.GasPrice.SetString(gasPrice, 0) + } + + if maxFeePerGas != "" { + opts.GasFeeCap = new(big.Int) + opts.GasFeeCap.SetString(maxFeePerGas, 0) + } + + if maxPriorityFeePerGas != "" { + opts.GasTipCap = new(big.Int) + opts.GasTipCap.SetString(maxPriorityFeePerGas, 0) + } + + if gasLimit != 0 { + opts.GasLimit = gasLimit + } + + opts.NoSend = noSend +} + +func CreateTerminusFacetCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "terminus-facet", + Short: "Interact with the TerminusFacet contract", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + + cmd.SetOut(os.Stdout) + + DeployGroup := &cobra.Group{ + ID: "deploy", Title: "Commands which deploy contracts", + } + cmd.AddGroup(DeployGroup) + ViewGroup := &cobra.Group{ + ID: "view", Title: "Commands which view contract state", + } + TransactGroup := &cobra.Group{ + ID: "transact", Title: "Commands which submit transactions", + } + cmd.AddGroup(ViewGroup, TransactGroup) + + cmdDeployTerminusFacet := CreateTerminusFacetDeploymentCommand() + cmdDeployTerminusFacet.GroupID = DeployGroup.ID + cmd.AddCommand(cmdDeployTerminusFacet) + + cmdViewBalanceOf := CreateBalanceOfCommand() + cmdViewBalanceOf.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewBalanceOf) + cmdViewBalanceOfBatch := CreateBalanceOfBatchCommand() + cmdViewBalanceOfBatch.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewBalanceOfBatch) + cmdViewContractURI := CreateContractUriCommand() + cmdViewContractURI.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewContractURI) + cmdViewIsApprovedForAll := CreateIsApprovedForAllCommand() + cmdViewIsApprovedForAll.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewIsApprovedForAll) + cmdViewIsApprovedForPool := CreateIsApprovedForPoolCommand() + cmdViewIsApprovedForPool.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewIsApprovedForPool) + cmdViewPaymentToken := CreatePaymentTokenCommand() + cmdViewPaymentToken.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewPaymentToken) + cmdViewPoolBasePrice := CreatePoolBasePriceCommand() + cmdViewPoolBasePrice.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewPoolBasePrice) + cmdViewPoolIsBurnable := CreatePoolIsBurnableCommand() + cmdViewPoolIsBurnable.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewPoolIsBurnable) + cmdViewPoolIsTransferable := CreatePoolIsTransferableCommand() + cmdViewPoolIsTransferable.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewPoolIsTransferable) + cmdViewSupportsInterface := CreateSupportsInterfaceCommand() + cmdViewSupportsInterface.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewSupportsInterface) + cmdViewTerminusController := CreateTerminusControllerCommand() + cmdViewTerminusController.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewTerminusController) + cmdViewTerminusPoolCapacity := CreateTerminusPoolCapacityCommand() + cmdViewTerminusPoolCapacity.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewTerminusPoolCapacity) + cmdViewTerminusPoolController := CreateTerminusPoolControllerCommand() + cmdViewTerminusPoolController.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewTerminusPoolController) + cmdViewTerminusPoolSupply := CreateTerminusPoolSupplyCommand() + cmdViewTerminusPoolSupply.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewTerminusPoolSupply) + cmdViewTotalPools := CreateTotalPoolsCommand() + cmdViewTotalPools.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewTotalPools) + cmdViewUri := CreateUriCommand() + cmdViewUri.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewUri) + + cmdTransactApproveForPool := CreateApproveForPoolCommand() + cmdTransactApproveForPool.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactApproveForPool) + cmdTransactBurn := CreateBurnCommand() + cmdTransactBurn.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactBurn) + cmdTransactCreatePoolV1 := CreateCreatePoolV1Command() + cmdTransactCreatePoolV1.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactCreatePoolV1) + cmdTransactCreatePoolV2 := CreateCreatePoolV2Command() + cmdTransactCreatePoolV2.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactCreatePoolV2) + cmdTransactCreateSimplePool := CreateCreateSimplePoolCommand() + cmdTransactCreateSimplePool.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactCreateSimplePool) + cmdTransactInit := CreateInitCommand() + cmdTransactInit.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactInit) + cmdTransactMint := CreateMintCommand() + cmdTransactMint.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactMint) + cmdTransactMintBatch := CreateMintBatchCommand() + cmdTransactMintBatch.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactMintBatch) + cmdTransactPoolMintBatch := CreatePoolMintBatchCommand() + cmdTransactPoolMintBatch.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactPoolMintBatch) + cmdTransactSafeBatchTransferFrom := CreateSafeBatchTransferFromCommand() + cmdTransactSafeBatchTransferFrom.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSafeBatchTransferFrom) + cmdTransactSafeTransferFrom := CreateSafeTransferFromCommand() + cmdTransactSafeTransferFrom.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSafeTransferFrom) + cmdTransactSetApprovalForAll := CreateSetApprovalForAllCommand() + cmdTransactSetApprovalForAll.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetApprovalForAll) + cmdTransactSetContractURI := CreateSetContractUriCommand() + cmdTransactSetContractURI.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetContractURI) + cmdTransactSetController := CreateSetControllerCommand() + cmdTransactSetController.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetController) + cmdTransactSetPaymentToken := CreateSetPaymentTokenCommand() + cmdTransactSetPaymentToken.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetPaymentToken) + cmdTransactSetPoolBasePrice := CreateSetPoolBasePriceCommand() + cmdTransactSetPoolBasePrice.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetPoolBasePrice) + cmdTransactSetPoolBurnable := CreateSetPoolBurnableCommand() + cmdTransactSetPoolBurnable.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetPoolBurnable) + cmdTransactSetPoolController := CreateSetPoolControllerCommand() + cmdTransactSetPoolController.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetPoolController) + cmdTransactSetPoolTransferable := CreateSetPoolTransferableCommand() + cmdTransactSetPoolTransferable.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetPoolTransferable) + cmdTransactSetURI := CreateSetUriCommand() + cmdTransactSetURI.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactSetURI) + cmdTransactUnapproveForPool := CreateUnapproveForPoolCommand() + cmdTransactUnapproveForPool.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactUnapproveForPool) + cmdTransactWithdrawPayments := CreateWithdrawPaymentsCommand() + cmdTransactWithdrawPayments.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactWithdrawPayments) + + return cmd +} + +// SafeOperationType represents the type of operation for a Safe transaction +type SafeOperationType uint8 + +const ( + Call SafeOperationType = 0 + DelegateCall SafeOperationType = 1 +) + +// String returns the string representation of the SafeOperationType +func (o SafeOperationType) String() string { + switch o { + case Call: + return "Call" + case DelegateCall: + return "DelegateCall" + default: + return "Unknown" + } +} + +// SafeTransactionData represents the data for a Safe transaction +type SafeTransactionData struct { + To string `json:"to"` + Value string `json:"value"` + Data string `json:"data"` + Operation SafeOperationType `json:"operation"` + SafeTxGas uint64 `json:"safeTxGas"` + BaseGas uint64 `json:"baseGas"` + GasPrice string `json:"gasPrice"` + GasToken string `json:"gasToken"` + RefundReceiver string `json:"refundReceiver"` + Nonce *big.Int `json:"nonce"` + SafeTxHash string `json:"safeTxHash"` + Sender string `json:"sender"` + Signature string `json:"signature"` + Origin string `json:"origin"` +} + +const ( + NativeTokenAddress = "0x0000000000000000000000000000000000000000" +) + +func DeployWithSafe(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, factoryAddress common.Address, value *big.Int, safeApi string, deployBytecode []byte, safeOperationType SafeOperationType, salt [32]byte, safeNonce *big.Int) error { + abi, err := CreateCall.CreateCallMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + safeCreateCallTxData, err := abi.Pack("performCreate2", value, deployBytecode, salt) + if err != nil { + return fmt.Errorf("failed to pack performCreate2 transaction: %v", err) + } + + return CreateSafeProposal(client, key, safeAddress, factoryAddress, safeCreateCallTxData, value, safeApi, SafeOperationType(safeOperationType), safeNonce) +} + +func PredictDeploymentAddressSafe(from common.Address, salt [32]byte, deployBytecode []byte) (common.Address, error) { + // Calculate the hash of the init code (deployment bytecode) + initCodeHash := crypto.Keccak256(deployBytecode) + + // Calculate the CREATE2 address + deployedAddress := crypto.CreateAddress2(from, salt, initCodeHash) + + return deployedAddress, nil +} + +func CreateSafeProposal(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, to common.Address, data []byte, value *big.Int, safeApi string, safeOperationType SafeOperationType, safeNonce *big.Int) error { + chainID, err := client.ChainID(context.Background()) + if err != nil { + return fmt.Errorf("failed to get chain ID: %v", err) + } + + // Create a new instance of the GnosisSafe contract + safeInstance, err := GnosisSafe.NewGnosisSafe(safeAddress, client) + if err != nil { + return fmt.Errorf("failed to create GnosisSafe instance: %v", err) + } + + nonce := safeNonce + if safeNonce == nil { + // Fetch the current nonce from the Safe contract + fetchedNonce, err := safeInstance.Nonce(&bind.CallOpts{}) + if err != nil { + return fmt.Errorf("failed to fetch nonce from Safe contract: %v", err) + } + nonce = fetchedNonce + } else { + nonce = safeNonce + } + + safeTransactionData := SafeTransactionData{ + To: to.Hex(), + Value: value.String(), + Data: common.Bytes2Hex(data), + Operation: safeOperationType, + SafeTxGas: 0, + BaseGas: 0, + GasPrice: "0", + GasToken: NativeTokenAddress, + RefundReceiver: NativeTokenAddress, + Nonce: nonce, + } + + // Calculate SafeTxHash + safeTxHash, err := CalculateSafeTxHash(safeAddress, safeTransactionData, chainID) + if err != nil { + return fmt.Errorf("failed to calculate SafeTxHash: %v", err) + } + + // Sign the SafeTxHash + signature, err := crypto.Sign(safeTxHash.Bytes(), key.PrivateKey) + if err != nil { + return fmt.Errorf("failed to sign SafeTxHash: %v", err) + } + + // Adjust V value for Ethereum's replay protection + signature[64] += 27 + + // Convert signature to hex + senderSignature := "0x" + common.Bytes2Hex(signature) + + // Prepare the request body + requestBody := map[string]interface{}{ + "to": safeTransactionData.To, + "value": safeTransactionData.Value, + "data": "0x" + safeTransactionData.Data, + "operation": int(safeTransactionData.Operation), + "safeTxGas": fmt.Sprintf("%d", safeTransactionData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", safeTransactionData.BaseGas), + "gasPrice": safeTransactionData.GasPrice, + "gasToken": safeTransactionData.GasToken, + "refundReceiver": safeTransactionData.RefundReceiver, + "nonce": fmt.Sprintf("%d", safeTransactionData.Nonce), + "safeTxHash": safeTxHash.Hex(), + "sender": key.Address.Hex(), + "signature": senderSignature, + "origin": fmt.Sprintf("{\"url\":\"%s\",\"name\":\"TokenSender Deployment\"}", safeApi), + } + + // Marshal the request body to JSON + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("failed to marshal request body: %v", err) + } + + // Send the request to the Safe Transaction Service + req, err := http.NewRequest("POST", safeApi, bytes.NewBuffer(jsonBody)) + if err != nil { + return fmt.Errorf("failed to create request: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + fmt.Println("Safe proposal created successfully") + return nil +} + +func CalculateSafeTxHash(safeAddress common.Address, txData SafeTransactionData, chainID *big.Int) (common.Hash, error) { + domainSeparator := apitypes.TypedDataDomain{ + ChainId: (*math.HexOrDecimal256)(chainID), + VerifyingContract: safeAddress.Hex(), + } + + typedData := apitypes.TypedData{ + Types: apitypes.Types{ + "EIP712Domain": []apitypes.Type{ + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "SafeTx": []apitypes.Type{ + {Name: "to", Type: "address"}, + {Name: "value", Type: "uint256"}, + {Name: "data", Type: "bytes"}, + {Name: "operation", Type: "uint8"}, + {Name: "safeTxGas", Type: "uint256"}, + {Name: "baseGas", Type: "uint256"}, + {Name: "gasPrice", Type: "uint256"}, + {Name: "gasToken", Type: "address"}, + {Name: "refundReceiver", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + }, + }, + Domain: domainSeparator, + PrimaryType: "SafeTx", + Message: apitypes.TypedDataMessage{ + "to": txData.To, + "value": txData.Value, + "data": "0x" + txData.Data, + "operation": fmt.Sprintf("%d", txData.Operation), + "safeTxGas": fmt.Sprintf("%d", txData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", txData.BaseGas), + "gasPrice": txData.GasPrice, + "gasToken": txData.GasToken, + "refundReceiver": txData.RefundReceiver, + "nonce": fmt.Sprintf("%d", txData.Nonce), + }, + } + + typedDataHash, _, err := apitypes.TypedDataAndHash(typedData) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to hash typed data: %v", err) + } + + return common.BytesToHash(typedDataHash), nil +} diff --git a/bindings/security/terminus/TerminusInitializer/TerminusInitializer.go b/bindings/security/terminus/TerminusInitializer/TerminusInitializer.go new file mode 100644 index 00000000..e8400830 --- /dev/null +++ b/bindings/security/terminus/TerminusInitializer/TerminusInitializer.go @@ -0,0 +1,1019 @@ +// This file was generated by seer: https://github.com/G7DAO/seer. +// seer version: 0.3.5 +// seer command: seer evm generate --package TerminusInitializer --cli --struct TerminusInitializer --output bindings/security/terminus/TerminusInitializer/TerminusInitializer.go +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package TerminusInitializer + +import ( + "bytes" + "crypto/rand" + "errors" + "math/big" + "net/http" + "strings" + + "context" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + + // Reference imports to suppress errors if they are not otherwise used. + "encoding/hex" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/G7DAO/seer/bindings/CreateCall" + "github.com/G7DAO/seer/bindings/GnosisSafe" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" + "golang.org/x/term" + + // TerminusInitializerMetaData contains all meta data concerning the TerminusInitializer contract. + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var TerminusInitializerMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50610253806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063e1c7392a14610030575b600080fd5b61003861003a565b005b61004261014e565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f6020527f845f7f8d885943dffdc1524acbd9538b2923f93aad26d306df3b8982c7f0632d805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092557f0e89341c000000000000000000000000000000000000000000000000000000006000527fcda23395996795f7b8155822fcc6171125c877448c68566f10ccabd60b06eb27805490911690911790557ffa8518a280120fdfaeca1e01615627dc31290bf234dcd1969ba07a186c72dd1080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c6004015473ffffffffffffffffffffffffffffffffffffffff16331461021b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201527f6572000000000000000000000000000000000000000000000000000000000000606482015260840160405180910390fd5b56fea2646970667358221220ad68b921c981f3d9da3e07b73bddf2b0de8d657e445945dba4d928852f33f94264736f6c63430008180033", +} + +// TerminusInitializerABI is the input ABI used to generate the binding from. +// Deprecated: Use TerminusInitializerMetaData.ABI instead. +var TerminusInitializerABI = TerminusInitializerMetaData.ABI + +// TerminusInitializerBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use TerminusInitializerMetaData.Bin instead. +var TerminusInitializerBin = TerminusInitializerMetaData.Bin + +// DeployTerminusInitializer deploys a new Ethereum contract, binding an instance of TerminusInitializer to it. +func DeployTerminusInitializer(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *TerminusInitializer, error) { + parsed, err := TerminusInitializerMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(TerminusInitializerBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &TerminusInitializer{TerminusInitializerCaller: TerminusInitializerCaller{contract: contract}, TerminusInitializerTransactor: TerminusInitializerTransactor{contract: contract}, TerminusInitializerFilterer: TerminusInitializerFilterer{contract: contract}}, nil +} + +// TerminusInitializer is an auto generated Go binding around an Ethereum contract. +type TerminusInitializer struct { + TerminusInitializerCaller // Read-only binding to the contract + TerminusInitializerTransactor // Write-only binding to the contract + TerminusInitializerFilterer // Log filterer for contract events +} + +// TerminusInitializerCaller is an auto generated read-only Go binding around an Ethereum contract. +type TerminusInitializerCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TerminusInitializerTransactor is an auto generated write-only Go binding around an Ethereum contract. +type TerminusInitializerTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TerminusInitializerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type TerminusInitializerFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// TerminusInitializerSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type TerminusInitializerSession struct { + Contract *TerminusInitializer // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TerminusInitializerCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type TerminusInitializerCallerSession struct { + Contract *TerminusInitializerCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// TerminusInitializerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type TerminusInitializerTransactorSession struct { + Contract *TerminusInitializerTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// TerminusInitializerRaw is an auto generated low-level Go binding around an Ethereum contract. +type TerminusInitializerRaw struct { + Contract *TerminusInitializer // Generic contract binding to access the raw methods on +} + +// TerminusInitializerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type TerminusInitializerCallerRaw struct { + Contract *TerminusInitializerCaller // Generic read-only contract binding to access the raw methods on +} + +// TerminusInitializerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type TerminusInitializerTransactorRaw struct { + Contract *TerminusInitializerTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewTerminusInitializer creates a new instance of TerminusInitializer, bound to a specific deployed contract. +func NewTerminusInitializer(address common.Address, backend bind.ContractBackend) (*TerminusInitializer, error) { + contract, err := bindTerminusInitializer(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &TerminusInitializer{TerminusInitializerCaller: TerminusInitializerCaller{contract: contract}, TerminusInitializerTransactor: TerminusInitializerTransactor{contract: contract}, TerminusInitializerFilterer: TerminusInitializerFilterer{contract: contract}}, nil +} + +// NewTerminusInitializerCaller creates a new read-only instance of TerminusInitializer, bound to a specific deployed contract. +func NewTerminusInitializerCaller(address common.Address, caller bind.ContractCaller) (*TerminusInitializerCaller, error) { + contract, err := bindTerminusInitializer(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &TerminusInitializerCaller{contract: contract}, nil +} + +// NewTerminusInitializerTransactor creates a new write-only instance of TerminusInitializer, bound to a specific deployed contract. +func NewTerminusInitializerTransactor(address common.Address, transactor bind.ContractTransactor) (*TerminusInitializerTransactor, error) { + contract, err := bindTerminusInitializer(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &TerminusInitializerTransactor{contract: contract}, nil +} + +// NewTerminusInitializerFilterer creates a new log filterer instance of TerminusInitializer, bound to a specific deployed contract. +func NewTerminusInitializerFilterer(address common.Address, filterer bind.ContractFilterer) (*TerminusInitializerFilterer, error) { + contract, err := bindTerminusInitializer(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &TerminusInitializerFilterer{contract: contract}, nil +} + +// bindTerminusInitializer binds a generic wrapper to an already deployed contract. +func bindTerminusInitializer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := TerminusInitializerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_TerminusInitializer *TerminusInitializerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _TerminusInitializer.Contract.TerminusInitializerCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_TerminusInitializer *TerminusInitializerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _TerminusInitializer.Contract.TerminusInitializerTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_TerminusInitializer *TerminusInitializerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _TerminusInitializer.Contract.TerminusInitializerTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_TerminusInitializer *TerminusInitializerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _TerminusInitializer.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_TerminusInitializer *TerminusInitializerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _TerminusInitializer.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_TerminusInitializer *TerminusInitializerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _TerminusInitializer.Contract.contract.Transact(opts, method, params...) +} + +// Init is a paid mutator transaction binding the contract method 0xe1c7392a. +// +// Solidity: function init() returns() +func (_TerminusInitializer *TerminusInitializerTransactor) Init(opts *bind.TransactOpts) (*types.Transaction, error) { + return _TerminusInitializer.contract.Transact(opts, "init") +} + +// Init is a paid mutator transaction binding the contract method 0xe1c7392a. +// +// Solidity: function init() returns() +func (_TerminusInitializer *TerminusInitializerSession) Init() (*types.Transaction, error) { + return _TerminusInitializer.Contract.Init(&_TerminusInitializer.TransactOpts) +} + +// Init is a paid mutator transaction binding the contract method 0xe1c7392a. +// +// Solidity: function init() returns() +func (_TerminusInitializer *TerminusInitializerTransactorSession) Init() (*types.Transaction, error) { + return _TerminusInitializer.Contract.Init(&_TerminusInitializer.TransactOpts) +} + +func CreateTerminusInitializerDeploymentCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc string + var gasLimit uint64 + var simulate bool + var timeout uint + var safeAddress, safeApi, safeCreateCall, safeSaltRaw, safeNonceRaw string + var safeOperationType uint8 + var salt [32]byte + var predictAddress bool + var safeNonce *big.Int + + cmd := &cobra.Command{ + Use: "deploy", + Short: "Deploy a new TerminusInitializer contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if safeCreateCall == "" { + fmt.Println("--safe-create-call not specified, using default (0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4)") + safeCreateCall = "0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4" + } + if !common.IsHexAddress(safeCreateCall) { + return fmt.Errorf("--safe-create-call is not a valid Ethereum address") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeSaltRaw == "" { + fmt.Println("--safe-salt not specified, generating random salt") + _, err := rand.Read(salt[:]) + if err != nil { + return fmt.Errorf("failed to generate random salt: %v", err) + } + // prompt user to accept random salt + fmt.Println("Generated salt:", common.Bytes2Hex(salt[:])) + fmt.Println("Please check the salt and confirm (y/n)") + var confirm string + fmt.Scanln(&confirm) + if confirm != "y" && confirm != "Y" && confirm != "\n" && confirm != "" { + return fmt.Errorf("salt not accepted, please specify a valid salt") + } + } else { + copy(salt[:], safeSaltRaw) + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + if safeAddress != "" { + // Generate deploy bytecode with constructor arguments + deployBytecode, err := generateTerminusInitializerDeployBytecode() + if err != nil { + return fmt.Errorf("failed to generate deploy bytecode: %v", err) + } + + // Create Safe proposal for deployment + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + if predictAddress { + fmt.Println("Predicting deployment address...") + from := common.HexToAddress(safeAddress) + if safeOperationType == 0 { + from = common.HexToAddress(safeCreateCall) + } + deploymentAddress, err := PredictDeploymentAddressSafe(from, salt, deployBytecode) + if err != nil { + return fmt.Errorf("failed to predict deployment address: %v", err) + } + fmt.Println("Predicted deployment address:", deploymentAddress.Hex()) + return nil + } else { + fmt.Println("Creating Safe proposal...") + err = DeployWithSafe(client, key, common.HexToAddress(safeAddress), common.HexToAddress(safeCreateCall), value, safeApi, deployBytecode, SafeOperationType(safeOperationType), salt, safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + } + + return nil + } + + address, deploymentTransaction, _, deploymentErr := DeployTerminusInitializer( + transactionOpts, + client, + ) + if deploymentErr != nil { + return deploymentErr + } + + cmd.Printf("Transaction hash: %s\nContract address: %s\n", deploymentTransaction.Hash().Hex(), address.Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + Data: deploymentTransaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := deploymentTransaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().StringVar(&safeCreateCall, "safe-create-call", "", "Address of the CreateCall contract (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 1, "Safe operation type: 0 (Call) or 1 (DelegateCall) - default is 1") + cmd.Flags().StringVar(&safeSaltRaw, "safe-salt", "", "Salt to use for the Safe transaction") + cmd.Flags().BoolVar(&predictAddress, "safe-predict-address", false, "Predict the deployment address (only works for Safe transactions)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + return cmd +} + +func generateTerminusInitializerDeployBytecode() ([]byte, error) { + abiPacked, err := TerminusInitializerMetaData.GetAbi() + if err != nil { + return nil, fmt.Errorf("failed to get ABI: %v", err) + } + + constructorArguments, err := abiPacked.Pack("") + if err != nil { + return nil, fmt.Errorf("failed to pack constructor arguments: %v", err) + } + + deployBytecode := append(common.FromHex(TerminusInitializerMetaData.Bin), constructorArguments...) + return deployBytecode, nil +} + +func CreateInitCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + cmd := &cobra.Command{ + Use: "init", + Short: "Execute the Init method on a TerminusInitializer contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewTerminusInitializer(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := TerminusInitializerTransactorSession{ + Contract: &contract.TerminusInitializerTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := TerminusInitializerMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "init" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.Init() + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + return cmd +} + +var ErrNoRPCURL error = errors.New("no RPC URL provided -- please pass an RPC URL from the command line or set the TERMINUS_INITIALIZER_RPC_URL environment variable") + +// Generates an Ethereum client to the JSONRPC API at the given URL. If rpcURL is empty, then it +// attempts to read the RPC URL from the TERMINUS_INITIALIZER_RPC_URL environment variable. If that is empty, +// too, then it returns an error. +func NewClient(rpcURL string) (*ethclient.Client, error) { + if rpcURL == "" { + rpcURL = os.Getenv("TERMINUS_INITIALIZER_RPC_URL") + } + + if rpcURL == "" { + return nil, ErrNoRPCURL + } + + client, err := ethclient.Dial(rpcURL) + return client, err +} + +// Creates a new context to be used when interacting with the chain client. +func NewChainContext(timeout uint) (context.Context, context.CancelFunc) { + baseCtx := context.Background() + parsedTimeout := time.Duration(timeout) * time.Second + ctx, cancel := context.WithTimeout(baseCtx, parsedTimeout) + return ctx, cancel +} + +// Unlocks a key from a keystore (byte contents of a keystore file) with the given password. +func UnlockKeystore(keystoreData []byte, password string) (*keystore.Key, error) { + key, err := keystore.DecryptKey(keystoreData, password) + return key, err +} + +// Loads a key from file, prompting the user for the password if it is not provided as a function argument. +func KeyFromFile(keystoreFile string, password string) (*keystore.Key, error) { + var emptyKey *keystore.Key + keystoreContent, readErr := os.ReadFile(keystoreFile) + if readErr != nil { + return emptyKey, readErr + } + + // If password is "", prompt user for password. + if password == "" { + fmt.Printf("Please provide a password for keystore (%s): ", keystoreFile) + passwordRaw, inputErr := term.ReadPassword(int(os.Stdin.Fd())) + if inputErr != nil { + return emptyKey, fmt.Errorf("error reading password: %s", inputErr.Error()) + } + fmt.Print("\n") + password = string(passwordRaw) + } + + key, err := UnlockKeystore(keystoreContent, password) + return key, err +} + +// This method is used to set the parameters on a view call from command line arguments (represented mostly as +// strings). +func SetCallParametersFromArgs(opts *bind.CallOpts, pending bool, fromAddress, blockNumber string) { + if pending { + opts.Pending = true + } + + if fromAddress != "" { + opts.From = common.HexToAddress(fromAddress) + } + + if blockNumber != "" { + opts.BlockNumber = new(big.Int) + opts.BlockNumber.SetString(blockNumber, 0) + } +} + +// This method is used to set the parameters on a transaction from command line arguments (represented mostly as +// strings). +func SetTransactionParametersFromArgs(opts *bind.TransactOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas string, gasLimit uint64, noSend bool) { + if nonce != "" { + opts.Nonce = new(big.Int) + opts.Nonce.SetString(nonce, 0) + } + + if value != "" { + opts.Value = new(big.Int) + opts.Value.SetString(value, 0) + } + + if gasPrice != "" { + opts.GasPrice = new(big.Int) + opts.GasPrice.SetString(gasPrice, 0) + } + + if maxFeePerGas != "" { + opts.GasFeeCap = new(big.Int) + opts.GasFeeCap.SetString(maxFeePerGas, 0) + } + + if maxPriorityFeePerGas != "" { + opts.GasTipCap = new(big.Int) + opts.GasTipCap.SetString(maxPriorityFeePerGas, 0) + } + + if gasLimit != 0 { + opts.GasLimit = gasLimit + } + + opts.NoSend = noSend +} + +func CreateTerminusInitializerCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "terminus-initializer", + Short: "Interact with the TerminusInitializer contract", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + + cmd.SetOut(os.Stdout) + + DeployGroup := &cobra.Group{ + ID: "deploy", Title: "Commands which deploy contracts", + } + cmd.AddGroup(DeployGroup) + ViewGroup := &cobra.Group{ + ID: "view", Title: "Commands which view contract state", + } + TransactGroup := &cobra.Group{ + ID: "transact", Title: "Commands which submit transactions", + } + cmd.AddGroup(ViewGroup, TransactGroup) + + cmdDeployTerminusInitializer := CreateTerminusInitializerDeploymentCommand() + cmdDeployTerminusInitializer.GroupID = DeployGroup.ID + cmd.AddCommand(cmdDeployTerminusInitializer) + + cmdTransactInit := CreateInitCommand() + cmdTransactInit.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactInit) + + return cmd +} + +// SafeOperationType represents the type of operation for a Safe transaction +type SafeOperationType uint8 + +const ( + Call SafeOperationType = 0 + DelegateCall SafeOperationType = 1 +) + +// String returns the string representation of the SafeOperationType +func (o SafeOperationType) String() string { + switch o { + case Call: + return "Call" + case DelegateCall: + return "DelegateCall" + default: + return "Unknown" + } +} + +// SafeTransactionData represents the data for a Safe transaction +type SafeTransactionData struct { + To string `json:"to"` + Value string `json:"value"` + Data string `json:"data"` + Operation SafeOperationType `json:"operation"` + SafeTxGas uint64 `json:"safeTxGas"` + BaseGas uint64 `json:"baseGas"` + GasPrice string `json:"gasPrice"` + GasToken string `json:"gasToken"` + RefundReceiver string `json:"refundReceiver"` + Nonce *big.Int `json:"nonce"` + SafeTxHash string `json:"safeTxHash"` + Sender string `json:"sender"` + Signature string `json:"signature"` + Origin string `json:"origin"` +} + +const ( + NativeTokenAddress = "0x0000000000000000000000000000000000000000" +) + +func DeployWithSafe(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, factoryAddress common.Address, value *big.Int, safeApi string, deployBytecode []byte, safeOperationType SafeOperationType, salt [32]byte, safeNonce *big.Int) error { + abi, err := CreateCall.CreateCallMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + safeCreateCallTxData, err := abi.Pack("performCreate2", value, deployBytecode, salt) + if err != nil { + return fmt.Errorf("failed to pack performCreate2 transaction: %v", err) + } + + return CreateSafeProposal(client, key, safeAddress, factoryAddress, safeCreateCallTxData, value, safeApi, SafeOperationType(safeOperationType), safeNonce) +} + +func PredictDeploymentAddressSafe(from common.Address, salt [32]byte, deployBytecode []byte) (common.Address, error) { + // Calculate the hash of the init code (deployment bytecode) + initCodeHash := crypto.Keccak256(deployBytecode) + + // Calculate the CREATE2 address + deployedAddress := crypto.CreateAddress2(from, salt, initCodeHash) + + return deployedAddress, nil +} + +func CreateSafeProposal(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, to common.Address, data []byte, value *big.Int, safeApi string, safeOperationType SafeOperationType, safeNonce *big.Int) error { + chainID, err := client.ChainID(context.Background()) + if err != nil { + return fmt.Errorf("failed to get chain ID: %v", err) + } + + // Create a new instance of the GnosisSafe contract + safeInstance, err := GnosisSafe.NewGnosisSafe(safeAddress, client) + if err != nil { + return fmt.Errorf("failed to create GnosisSafe instance: %v", err) + } + + nonce := safeNonce + if safeNonce == nil { + // Fetch the current nonce from the Safe contract + fetchedNonce, err := safeInstance.Nonce(&bind.CallOpts{}) + if err != nil { + return fmt.Errorf("failed to fetch nonce from Safe contract: %v", err) + } + nonce = fetchedNonce + } else { + nonce = safeNonce + } + + safeTransactionData := SafeTransactionData{ + To: to.Hex(), + Value: value.String(), + Data: common.Bytes2Hex(data), + Operation: safeOperationType, + SafeTxGas: 0, + BaseGas: 0, + GasPrice: "0", + GasToken: NativeTokenAddress, + RefundReceiver: NativeTokenAddress, + Nonce: nonce, + } + + // Calculate SafeTxHash + safeTxHash, err := CalculateSafeTxHash(safeAddress, safeTransactionData, chainID) + if err != nil { + return fmt.Errorf("failed to calculate SafeTxHash: %v", err) + } + + // Sign the SafeTxHash + signature, err := crypto.Sign(safeTxHash.Bytes(), key.PrivateKey) + if err != nil { + return fmt.Errorf("failed to sign SafeTxHash: %v", err) + } + + // Adjust V value for Ethereum's replay protection + signature[64] += 27 + + // Convert signature to hex + senderSignature := "0x" + common.Bytes2Hex(signature) + + // Prepare the request body + requestBody := map[string]interface{}{ + "to": safeTransactionData.To, + "value": safeTransactionData.Value, + "data": "0x" + safeTransactionData.Data, + "operation": int(safeTransactionData.Operation), + "safeTxGas": fmt.Sprintf("%d", safeTransactionData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", safeTransactionData.BaseGas), + "gasPrice": safeTransactionData.GasPrice, + "gasToken": safeTransactionData.GasToken, + "refundReceiver": safeTransactionData.RefundReceiver, + "nonce": fmt.Sprintf("%d", safeTransactionData.Nonce), + "safeTxHash": safeTxHash.Hex(), + "sender": key.Address.Hex(), + "signature": senderSignature, + "origin": fmt.Sprintf("{\"url\":\"%s\",\"name\":\"TokenSender Deployment\"}", safeApi), + } + + // Marshal the request body to JSON + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("failed to marshal request body: %v", err) + } + + // Send the request to the Safe Transaction Service + req, err := http.NewRequest("POST", safeApi, bytes.NewBuffer(jsonBody)) + if err != nil { + return fmt.Errorf("failed to create request: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + fmt.Println("Safe proposal created successfully") + return nil +} + +func CalculateSafeTxHash(safeAddress common.Address, txData SafeTransactionData, chainID *big.Int) (common.Hash, error) { + domainSeparator := apitypes.TypedDataDomain{ + ChainId: (*math.HexOrDecimal256)(chainID), + VerifyingContract: safeAddress.Hex(), + } + + typedData := apitypes.TypedData{ + Types: apitypes.Types{ + "EIP712Domain": []apitypes.Type{ + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "SafeTx": []apitypes.Type{ + {Name: "to", Type: "address"}, + {Name: "value", Type: "uint256"}, + {Name: "data", Type: "bytes"}, + {Name: "operation", Type: "uint8"}, + {Name: "safeTxGas", Type: "uint256"}, + {Name: "baseGas", Type: "uint256"}, + {Name: "gasPrice", Type: "uint256"}, + {Name: "gasToken", Type: "address"}, + {Name: "refundReceiver", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + }, + }, + Domain: domainSeparator, + PrimaryType: "SafeTx", + Message: apitypes.TypedDataMessage{ + "to": txData.To, + "value": txData.Value, + "data": "0x" + txData.Data, + "operation": fmt.Sprintf("%d", txData.Operation), + "safeTxGas": fmt.Sprintf("%d", txData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", txData.BaseGas), + "gasPrice": txData.GasPrice, + "gasToken": txData.GasToken, + "refundReceiver": txData.RefundReceiver, + "nonce": fmt.Sprintf("%d", txData.Nonce), + }, + } + + typedDataHash, _, err := apitypes.TypedDataAndHash(typedData) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to hash typed data: %v", err) + } + + return common.BytesToHash(typedDataHash), nil +} diff --git a/bindings/utils/diamonds/Diamond/Diamond.go b/bindings/utils/diamonds/Diamond/Diamond.go new file mode 100644 index 00000000..f802e3f6 --- /dev/null +++ b/bindings/utils/diamonds/Diamond/Diamond.go @@ -0,0 +1,1581 @@ +// This file was generated by seer: https://github.com/G7DAO/seer. +// seer version: 0.3.5 +// seer command: seer evm generate --package Diamond --cli --struct Diamond --output bindings/utils/diamonds/Diamond/Diamond.go +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package Diamond + +import ( + "bytes" + "crypto/rand" + "errors" + "math/big" + "net/http" + "strings" + + "context" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + + // Reference imports to suppress errors if they are not otherwise used. + "encoding/hex" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/G7DAO/seer/bindings/CreateCall" + "github.com/G7DAO/seer/bindings/GnosisSafe" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" + "golang.org/x/term" + + // IDiamondCutFacetCut is an auto generated low-level Go binding around an user-defined struct. + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +type IDiamondCutFacetCut struct { + FacetAddress common.Address + Action uint8 + FunctionSelectors [][4]byte +} + +// DiamondMetaData contains all meta data concerning the Diamond contract. +var DiamondMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_contractOwner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_diamondCutFacet\",\"type\":\"address\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_initializationContractAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_calldata\",\"type\":\"bytes\"}],\"name\":\"InitializationFunctionReverted\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"facetAddress\",\"type\":\"address\"},{\"internalType\":\"enumIDiamondCut.FacetCutAction\",\"name\":\"action\",\"type\":\"uint8\"},{\"internalType\":\"bytes4[]\",\"name\":\"functionSelectors\",\"type\":\"bytes4[]\"}],\"indexed\":false,\"internalType\":\"structIDiamondCut.FacetCut[]\",\"name\":\"_diamondCut\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_init\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_calldata\",\"type\":\"bytes\"}],\"name\":\"DiamondCut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60806040526040516113bc3803806113bc83398101604081905261002291610f3e565b61002b82610136565b604080516001808252818301909252600091816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816100425750506040805160018082528183019092529192506000919060208083019080368337019050509050631f931c1c60e01b816000815181106100b1576100b1610f71565b6001600160e01b031990921660209283029190910182015260408051606081019091526001600160a01b038516815290810160008152602001828152508260008151811061010157610101610f71565b602002602001018190525061012d826000604051806020016040528060008152506101b960201b60201c565b505050506111c5565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c132080546001600160a01b031981166001600160a01b03848116918217909355604051600080516020611310833981519152939092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b60005b835181101561038c5760008482815181106101d9576101d9610f71565b6020026020010151602001519050600060028111156101fa576101fa610f87565b81600281111561020c5761020c610f87565b036102605761025b85838151811061022657610226610f71565b60200260200101516000015186848151811061024457610244610f71565b6020026020010151604001516103d760201b60201c565b610383565b600181600281111561027457610274610f87565b036102c35761025b85838151811061028e5761028e610f71565b6020026020010151600001518684815181106102ac576102ac610f71565b60200260200101516040015161064860201b60201c565b60028160028111156102d7576102d7610f87565b036103265761025b8583815181106102f1576102f1610f71565b60200260200101516000015186848151811061030f5761030f610f71565b6020026020010151604001516108c260201b60201c565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b60648201526084015b60405180910390fd5b506001016101bc565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738383836040516103c093929190610fed565b60405180910390a16103d28282610a0e565b505050565b600081511161042a5760405162461bcd60e51b815260206004820152602b602482015260008051602061139c83398151915260448201526a1858d95d081d1bc818dd5d60aa1b606482015260840161037a565b6000805160206113108339815191526001600160a01b0383166104925760405162461bcd60e51b815260206004820152602c602482015260008051602061135883398151915260448201526b65206164647265737328302960a01b606482015260840161037a565b6001600160a01b0383166000908152600182016020526040812054906001600160601b03821690036104c8576104c88285610ad4565b60005b83518110156106415760008482815181106104e8576104e8610f71565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0316801561058e5760405162461bcd60e51b815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f60448201527f6e207468617420616c7265616479206578697374730000000000000000000000606482015260840161037a565b6001600160e01b0319821660008181526020878152604080832080546001600160a01b03908116600160a01b6001600160601b038c16021782558c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b0319161790558361063081611106565b945050600190920191506104cb9050565b5050505050565b600081511161069b5760405162461bcd60e51b815260206004820152602b602482015260008051602061139c83398151915260448201526a1858d95d081d1bc818dd5d60aa1b606482015260840161037a565b6000805160206113108339815191526001600160a01b0383166107035760405162461bcd60e51b815260206004820152602c602482015260008051602061135883398151915260448201526b65206164647265737328302960a01b606482015260840161037a565b6001600160a01b0383166000908152600182016020526040812054906001600160601b0382169003610739576107398285610ad4565b60005b835181101561064157600084828151811061075957610759610f71565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b0390811690871681036108045760405162461bcd60e51b815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e0000000000000000606482015260840161037a565b61080f858284610b3e565b6001600160e01b0319821660008181526020878152604080832080546001600160a01b03908116600160a01b6001600160601b038c16021782558c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b031916179055836108b181611106565b9450506001909201915061073c9050565b60008151116109155760405162461bcd60e51b815260206004820152602b602482015260008051602061139c83398151915260448201526a1858d95d081d1bc818dd5d60aa1b606482015260840161037a565b6000805160206113108339815191526001600160a01b038316156109a15760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f7665206661636574206164647260448201527f657373206d757374206265206164647265737328302900000000000000000000606482015260840161037a565b60005b8251811015610a085760008382815181106109c1576109c1610f71565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b03166109fe848284610b3e565b50506001016109a4565b50505050565b6001600160a01b038216610a20575050565b610a428260405180606001604052806028815260200161133060289139610f01565b600080836001600160a01b031683604051610a5d9190611134565b600060405180830381855af49150503d8060008114610a98576040519150601f19603f3d011682016040523d82523d6000602084013e610a9d565b606091505b509150915081610a0857805115610ab75780518082602001fd5b838360405163192105d760e01b815260040161037a929190611150565b610af68160405180606001604052806024815260200161137860249139610f01565b6002820180546001600160a01b0390921660008181526001948501602090815260408220860185905594840183559182529290200180546001600160a01b0319169091179055565b6001600160a01b038216610bba5760405162461bcd60e51b815260206004820152603760248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360448201527f74696f6e207468617420646f65736e2774206578697374000000000000000000606482015260840161037a565b306001600160a01b03831603610c295760405162461bcd60e51b815260206004820152602e60248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560448201526d3a30b1363290333ab731ba34b7b760911b606482015260840161037a565b6001600160e01b03198116600090815260208481526040808320546001600160a01b0386168452600180880190935290832054600160a01b9091046001600160601b03169291610c789161117c565b9050808214610d6a576001600160a01b03841660009081526001860160205260408120805483908110610cad57610cad610f71565b600091825260208083206008830401546001600160a01b038916845260018a019091526040909220805460079092166004026101000a90920460e01b925082919085908110610cfe57610cfe610f71565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b03199290921682528690526040902080546001600160a01b0316600160a01b6001600160601b038516021790555b6001600160a01b03841660009081526001860160205260409020805480610d9357610d93611195565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b03198516825286905260408120819055819003610641576002850154600090610df69060019061117c565b6001600160a01b0386166000908152600180890160205260409091200154909150808214610ea5576000876002018381548110610e3557610e35610f71565b6000918252602090912001546002890180546001600160a01b039092169250829184908110610e6657610e66610f71565b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055929091168152600189810190925260409020018190555b86600201805480610eb857610eb8611195565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220015550505050505050565b813b8181610a085760405162461bcd60e51b815260040161037a91906111ab565b80516001600160a01b0381168114610f3957600080fd5b919050565b60008060408385031215610f5157600080fd5b610f5a83610f22565b9150610f6860208401610f22565b90509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60005b83811015610fb8578181015183820152602001610fa0565b50506000910152565b60008151808452610fd9816020860160208601610f9d565b601f01601f19169290920160200192915050565b60006060808301606084528087518083526080925060808601915060808160051b8701016020808b0160005b848110156110c057898403607f19018652815180516001600160a01b0316855283810151898601906003811061105f57634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b808310156110ab5783516001600160e01b0319168252928601926001929092019190860190611081565b50978501979550505090820190600101611019565b50506001600160a01b038a169088015286810360408801526110e28189610fc1565b9a9950505050505050505050565b634e487b7160e01b600052601160045260246000fd5b60006001600160601b038281166002600160601b0319810161112a5761112a6110f0565b6001019392505050565b60008251611146818460208701610f9d565b9190910192915050565b6001600160a01b038316815260406020820181905260009061117490830184610fc1565b949350505050565b8181038181111561118f5761118f6110f0565b92915050565b634e487b7160e01b600052603160045260246000fd5b6020815260006111be6020830184610fc1565b9392505050565b61013c806111d46000396000f3fe60806040523661000b57005b600080357fffffffff000000000000000000000000000000000000000000000000000000001681527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c6020819052604090912054819073ffffffffffffffffffffffffffffffffffffffff16806100e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f74206578697374604482015260640160405180910390fd5b3660008037600080366000845af43d6000803e808015610101573d6000f35b3d6000fdfea2646970667358221220e3c581e77f71961aaa955f019d2f5f5311cd665e5f77ba4c93545267db575d0c64736f6c63430008180033c8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204164642066616365742063616e277420624c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f64654c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e2066", +} + +// DiamondABI is the input ABI used to generate the binding from. +// Deprecated: Use DiamondMetaData.ABI instead. +var DiamondABI = DiamondMetaData.ABI + +// DiamondBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use DiamondMetaData.Bin instead. +var DiamondBin = DiamondMetaData.Bin + +// DeployDiamond deploys a new Ethereum contract, binding an instance of Diamond to it. +func DeployDiamond(auth *bind.TransactOpts, backend bind.ContractBackend, _contractOwner common.Address, _diamondCutFacet common.Address) (common.Address, *types.Transaction, *Diamond, error) { + parsed, err := DiamondMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DiamondBin), backend, _contractOwner, _diamondCutFacet) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Diamond{DiamondCaller: DiamondCaller{contract: contract}, DiamondTransactor: DiamondTransactor{contract: contract}, DiamondFilterer: DiamondFilterer{contract: contract}}, nil +} + +// Diamond is an auto generated Go binding around an Ethereum contract. +type Diamond struct { + DiamondCaller // Read-only binding to the contract + DiamondTransactor // Write-only binding to the contract + DiamondFilterer // Log filterer for contract events +} + +// DiamondCaller is an auto generated read-only Go binding around an Ethereum contract. +type DiamondCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondTransactor is an auto generated write-only Go binding around an Ethereum contract. +type DiamondTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type DiamondFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type DiamondSession struct { + Contract *Diamond // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DiamondCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type DiamondCallerSession struct { + Contract *DiamondCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// DiamondTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type DiamondTransactorSession struct { + Contract *DiamondTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DiamondRaw is an auto generated low-level Go binding around an Ethereum contract. +type DiamondRaw struct { + Contract *Diamond // Generic contract binding to access the raw methods on +} + +// DiamondCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type DiamondCallerRaw struct { + Contract *DiamondCaller // Generic read-only contract binding to access the raw methods on +} + +// DiamondTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type DiamondTransactorRaw struct { + Contract *DiamondTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewDiamond creates a new instance of Diamond, bound to a specific deployed contract. +func NewDiamond(address common.Address, backend bind.ContractBackend) (*Diamond, error) { + contract, err := bindDiamond(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Diamond{DiamondCaller: DiamondCaller{contract: contract}, DiamondTransactor: DiamondTransactor{contract: contract}, DiamondFilterer: DiamondFilterer{contract: contract}}, nil +} + +// NewDiamondCaller creates a new read-only instance of Diamond, bound to a specific deployed contract. +func NewDiamondCaller(address common.Address, caller bind.ContractCaller) (*DiamondCaller, error) { + contract, err := bindDiamond(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &DiamondCaller{contract: contract}, nil +} + +// NewDiamondTransactor creates a new write-only instance of Diamond, bound to a specific deployed contract. +func NewDiamondTransactor(address common.Address, transactor bind.ContractTransactor) (*DiamondTransactor, error) { + contract, err := bindDiamond(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &DiamondTransactor{contract: contract}, nil +} + +// NewDiamondFilterer creates a new log filterer instance of Diamond, bound to a specific deployed contract. +func NewDiamondFilterer(address common.Address, filterer bind.ContractFilterer) (*DiamondFilterer, error) { + contract, err := bindDiamond(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &DiamondFilterer{contract: contract}, nil +} + +// bindDiamond binds a generic wrapper to an already deployed contract. +func bindDiamond(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := DiamondMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Diamond *DiamondRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Diamond.Contract.DiamondCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Diamond *DiamondRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Diamond.Contract.DiamondTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Diamond *DiamondRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Diamond.Contract.DiamondTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Diamond *DiamondCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Diamond.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Diamond *DiamondTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Diamond.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Diamond *DiamondTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Diamond.Contract.contract.Transact(opts, method, params...) +} + +// Fallback is a paid mutator transaction binding the contract fallback function. +// +// Solidity: fallback() payable returns() +func (_Diamond *DiamondTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _Diamond.contract.RawTransact(opts, calldata) +} + +// Fallback is a paid mutator transaction binding the contract fallback function. +// +// Solidity: fallback() payable returns() +func (_Diamond *DiamondSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _Diamond.Contract.Fallback(&_Diamond.TransactOpts, calldata) +} + +// Fallback is a paid mutator transaction binding the contract fallback function. +// +// Solidity: fallback() payable returns() +func (_Diamond *DiamondTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _Diamond.Contract.Fallback(&_Diamond.TransactOpts, calldata) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_Diamond *DiamondTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Diamond.contract.RawTransact(opts, nil) // calldata is disallowed for receive function +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_Diamond *DiamondSession) Receive() (*types.Transaction, error) { + return _Diamond.Contract.Receive(&_Diamond.TransactOpts) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_Diamond *DiamondTransactorSession) Receive() (*types.Transaction, error) { + return _Diamond.Contract.Receive(&_Diamond.TransactOpts) +} + +// DiamondDiamondCutIterator is returned from FilterDiamondCut and is used to iterate over the raw logs and unpacked data for DiamondCut events raised by the Diamond contract. +type DiamondDiamondCutIterator struct { + Event *DiamondDiamondCut // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DiamondDiamondCutIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DiamondDiamondCut) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DiamondDiamondCut) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DiamondDiamondCutIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DiamondDiamondCutIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DiamondDiamondCut represents a DiamondCut event raised by the Diamond contract. +type DiamondDiamondCut struct { + DiamondCut []IDiamondCutFacetCut + Init common.Address + Calldata []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterDiamondCut is a free log retrieval operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_Diamond *DiamondFilterer) FilterDiamondCut(opts *bind.FilterOpts) (*DiamondDiamondCutIterator, error) { + + logs, sub, err := _Diamond.contract.FilterLogs(opts, "DiamondCut") + if err != nil { + return nil, err + } + return &DiamondDiamondCutIterator{contract: _Diamond.contract, event: "DiamondCut", logs: logs, sub: sub}, nil +} + +// WatchDiamondCut is a free log subscription operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_Diamond *DiamondFilterer) WatchDiamondCut(opts *bind.WatchOpts, sink chan<- *DiamondDiamondCut) (event.Subscription, error) { + + logs, sub, err := _Diamond.contract.WatchLogs(opts, "DiamondCut") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DiamondDiamondCut) + if err := _Diamond.contract.UnpackLog(event, "DiamondCut", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseDiamondCut is a log parse operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_Diamond *DiamondFilterer) ParseDiamondCut(log types.Log) (*DiamondDiamondCut, error) { + event := new(DiamondDiamondCut) + if err := _Diamond.contract.UnpackLog(event, "DiamondCut", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DiamondOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Diamond contract. +type DiamondOwnershipTransferredIterator struct { + Event *DiamondOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DiamondOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DiamondOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DiamondOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DiamondOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DiamondOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DiamondOwnershipTransferred represents a OwnershipTransferred event raised by the Diamond contract. +type DiamondOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Diamond *DiamondFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*DiamondOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Diamond.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &DiamondOwnershipTransferredIterator{contract: _Diamond.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Diamond *DiamondFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DiamondOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _Diamond.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DiamondOwnershipTransferred) + if err := _Diamond.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_Diamond *DiamondFilterer) ParseOwnershipTransferred(log types.Log) (*DiamondOwnershipTransferred, error) { + event := new(DiamondOwnershipTransferred) + if err := _Diamond.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func CreateDiamondDeploymentCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc string + var gasLimit uint64 + var simulate bool + var timeout uint + var safeAddress, safeApi, safeCreateCall, safeSaltRaw, safeNonceRaw string + var safeOperationType uint8 + var salt [32]byte + var predictAddress bool + var safeNonce *big.Int + + var contractOwner common.Address + var contractOwnerRaw string + var diamondCutFacet common.Address + var diamondCutFacetRaw string + + cmd := &cobra.Command{ + Use: "deploy", + Short: "Deploy a new Diamond contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if safeCreateCall == "" { + fmt.Println("--safe-create-call not specified, using default (0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4)") + safeCreateCall = "0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4" + } + if !common.IsHexAddress(safeCreateCall) { + return fmt.Errorf("--safe-create-call is not a valid Ethereum address") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeSaltRaw == "" { + fmt.Println("--safe-salt not specified, generating random salt") + _, err := rand.Read(salt[:]) + if err != nil { + return fmt.Errorf("failed to generate random salt: %v", err) + } + // prompt user to accept random salt + fmt.Println("Generated salt:", common.Bytes2Hex(salt[:])) + fmt.Println("Please check the salt and confirm (y/n)") + var confirm string + fmt.Scanln(&confirm) + if confirm != "y" && confirm != "Y" && confirm != "\n" && confirm != "" { + return fmt.Errorf("salt not accepted, please specify a valid salt") + } + } else { + copy(salt[:], safeSaltRaw) + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if contractOwnerRaw == "" { + return fmt.Errorf("--contract-owner argument not specified") + } else if !common.IsHexAddress(contractOwnerRaw) { + return fmt.Errorf("--contract-owner argument is not a valid Ethereum address") + } + contractOwner = common.HexToAddress(contractOwnerRaw) + + if diamondCutFacetRaw == "" { + return fmt.Errorf("--diamond-cut-facet argument not specified") + } else if !common.IsHexAddress(diamondCutFacetRaw) { + return fmt.Errorf("--diamond-cut-facet argument is not a valid Ethereum address") + } + diamondCutFacet = common.HexToAddress(diamondCutFacetRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + if safeAddress != "" { + // Generate deploy bytecode with constructor arguments + deployBytecode, err := generateDiamondDeployBytecode( + contractOwner, + diamondCutFacet, + ) + if err != nil { + return fmt.Errorf("failed to generate deploy bytecode: %v", err) + } + + // Create Safe proposal for deployment + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + if predictAddress { + fmt.Println("Predicting deployment address...") + from := common.HexToAddress(safeAddress) + if safeOperationType == 0 { + from = common.HexToAddress(safeCreateCall) + } + deploymentAddress, err := PredictDeploymentAddressSafe(from, salt, deployBytecode) + if err != nil { + return fmt.Errorf("failed to predict deployment address: %v", err) + } + fmt.Println("Predicted deployment address:", deploymentAddress.Hex()) + return nil + } else { + fmt.Println("Creating Safe proposal...") + err = DeployWithSafe(client, key, common.HexToAddress(safeAddress), common.HexToAddress(safeCreateCall), value, safeApi, deployBytecode, SafeOperationType(safeOperationType), salt, safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + } + + return nil + } + + address, deploymentTransaction, _, deploymentErr := DeployDiamond( + transactionOpts, + client, + contractOwner, + diamondCutFacet, + ) + if deploymentErr != nil { + return deploymentErr + } + + cmd.Printf("Transaction hash: %s\nContract address: %s\n", deploymentTransaction.Hash().Hex(), address.Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + Data: deploymentTransaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := deploymentTransaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().StringVar(&safeCreateCall, "safe-create-call", "", "Address of the CreateCall contract (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 1, "Safe operation type: 0 (Call) or 1 (DelegateCall) - default is 1") + cmd.Flags().StringVar(&safeSaltRaw, "safe-salt", "", "Salt to use for the Safe transaction") + cmd.Flags().BoolVar(&predictAddress, "safe-predict-address", false, "Predict the deployment address (only works for Safe transactions)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&contractOwnerRaw, "contract-owner", "", "contract-owner argument (common.Address)") + cmd.Flags().StringVar(&diamondCutFacetRaw, "diamond-cut-facet", "", "diamond-cut-facet argument (common.Address)") + + return cmd +} + +func generateDiamondDeployBytecode( + contractOwner common.Address, + diamondCutFacet common.Address, +) ([]byte, error) { + abiPacked, err := DiamondMetaData.GetAbi() + if err != nil { + return nil, fmt.Errorf("failed to get ABI: %v", err) + } + + constructorArguments, err := abiPacked.Pack("", + contractOwner, + diamondCutFacet, + ) + if err != nil { + return nil, fmt.Errorf("failed to pack constructor arguments: %v", err) + } + + deployBytecode := append(common.FromHex(DiamondMetaData.Bin), constructorArguments...) + return deployBytecode, nil +} + +func CreateFallbackCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var calldata []byte + var calldataRaw string + + cmd := &cobra.Command{ + Use: "fallback", + Short: "Execute the Fallback method on a Diamond contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + var calldataIntermediate []byte + + var calldataIntermediateHexDecodeErr error + calldataIntermediate, calldataIntermediateHexDecodeErr = hex.DecodeString(calldataRaw) + if calldataIntermediateHexDecodeErr != nil { + return calldataIntermediateHexDecodeErr + } + + copy(calldata[:], calldataIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewDiamond(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := DiamondTransactorSession{ + Contract: &contract.DiamondTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := DiamondMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "fallback" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + calldata, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.Fallback( + + calldata, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&calldataRaw, "calldata", "", "calldata argument ([]byte)") + + return cmd +} +func CreateReceiveCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + cmd := &cobra.Command{ + Use: "receive", + Short: "Execute the Receive method on a Diamond contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewDiamond(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := DiamondTransactorSession{ + Contract: &contract.DiamondTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := DiamondMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "receive" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.Receive() + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + return cmd +} + +var ErrNoRPCURL error = errors.New("no RPC URL provided -- please pass an RPC URL from the command line or set the DIAMOND_RPC_URL environment variable") + +// Generates an Ethereum client to the JSONRPC API at the given URL. If rpcURL is empty, then it +// attempts to read the RPC URL from the DIAMOND_RPC_URL environment variable. If that is empty, +// too, then it returns an error. +func NewClient(rpcURL string) (*ethclient.Client, error) { + if rpcURL == "" { + rpcURL = os.Getenv("DIAMOND_RPC_URL") + } + + if rpcURL == "" { + return nil, ErrNoRPCURL + } + + client, err := ethclient.Dial(rpcURL) + return client, err +} + +// Creates a new context to be used when interacting with the chain client. +func NewChainContext(timeout uint) (context.Context, context.CancelFunc) { + baseCtx := context.Background() + parsedTimeout := time.Duration(timeout) * time.Second + ctx, cancel := context.WithTimeout(baseCtx, parsedTimeout) + return ctx, cancel +} + +// Unlocks a key from a keystore (byte contents of a keystore file) with the given password. +func UnlockKeystore(keystoreData []byte, password string) (*keystore.Key, error) { + key, err := keystore.DecryptKey(keystoreData, password) + return key, err +} + +// Loads a key from file, prompting the user for the password if it is not provided as a function argument. +func KeyFromFile(keystoreFile string, password string) (*keystore.Key, error) { + var emptyKey *keystore.Key + keystoreContent, readErr := os.ReadFile(keystoreFile) + if readErr != nil { + return emptyKey, readErr + } + + // If password is "", prompt user for password. + if password == "" { + fmt.Printf("Please provide a password for keystore (%s): ", keystoreFile) + passwordRaw, inputErr := term.ReadPassword(int(os.Stdin.Fd())) + if inputErr != nil { + return emptyKey, fmt.Errorf("error reading password: %s", inputErr.Error()) + } + fmt.Print("\n") + password = string(passwordRaw) + } + + key, err := UnlockKeystore(keystoreContent, password) + return key, err +} + +// This method is used to set the parameters on a view call from command line arguments (represented mostly as +// strings). +func SetCallParametersFromArgs(opts *bind.CallOpts, pending bool, fromAddress, blockNumber string) { + if pending { + opts.Pending = true + } + + if fromAddress != "" { + opts.From = common.HexToAddress(fromAddress) + } + + if blockNumber != "" { + opts.BlockNumber = new(big.Int) + opts.BlockNumber.SetString(blockNumber, 0) + } +} + +// This method is used to set the parameters on a transaction from command line arguments (represented mostly as +// strings). +func SetTransactionParametersFromArgs(opts *bind.TransactOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas string, gasLimit uint64, noSend bool) { + if nonce != "" { + opts.Nonce = new(big.Int) + opts.Nonce.SetString(nonce, 0) + } + + if value != "" { + opts.Value = new(big.Int) + opts.Value.SetString(value, 0) + } + + if gasPrice != "" { + opts.GasPrice = new(big.Int) + opts.GasPrice.SetString(gasPrice, 0) + } + + if maxFeePerGas != "" { + opts.GasFeeCap = new(big.Int) + opts.GasFeeCap.SetString(maxFeePerGas, 0) + } + + if maxPriorityFeePerGas != "" { + opts.GasTipCap = new(big.Int) + opts.GasTipCap.SetString(maxPriorityFeePerGas, 0) + } + + if gasLimit != 0 { + opts.GasLimit = gasLimit + } + + opts.NoSend = noSend +} + +func CreateDiamondCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "diamond", + Short: "Interact with the Diamond contract", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + + cmd.SetOut(os.Stdout) + + DeployGroup := &cobra.Group{ + ID: "deploy", Title: "Commands which deploy contracts", + } + cmd.AddGroup(DeployGroup) + ViewGroup := &cobra.Group{ + ID: "view", Title: "Commands which view contract state", + } + TransactGroup := &cobra.Group{ + ID: "transact", Title: "Commands which submit transactions", + } + cmd.AddGroup(ViewGroup, TransactGroup) + + cmdDeployDiamond := CreateDiamondDeploymentCommand() + cmdDeployDiamond.GroupID = DeployGroup.ID + cmd.AddCommand(cmdDeployDiamond) + + cmdTransactFallback := CreateFallbackCommand() + cmdTransactFallback.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactFallback) + cmdTransactReceive := CreateReceiveCommand() + cmdTransactReceive.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactReceive) + + return cmd +} + +// SafeOperationType represents the type of operation for a Safe transaction +type SafeOperationType uint8 + +const ( + Call SafeOperationType = 0 + DelegateCall SafeOperationType = 1 +) + +// String returns the string representation of the SafeOperationType +func (o SafeOperationType) String() string { + switch o { + case Call: + return "Call" + case DelegateCall: + return "DelegateCall" + default: + return "Unknown" + } +} + +// SafeTransactionData represents the data for a Safe transaction +type SafeTransactionData struct { + To string `json:"to"` + Value string `json:"value"` + Data string `json:"data"` + Operation SafeOperationType `json:"operation"` + SafeTxGas uint64 `json:"safeTxGas"` + BaseGas uint64 `json:"baseGas"` + GasPrice string `json:"gasPrice"` + GasToken string `json:"gasToken"` + RefundReceiver string `json:"refundReceiver"` + Nonce *big.Int `json:"nonce"` + SafeTxHash string `json:"safeTxHash"` + Sender string `json:"sender"` + Signature string `json:"signature"` + Origin string `json:"origin"` +} + +const ( + NativeTokenAddress = "0x0000000000000000000000000000000000000000" +) + +func DeployWithSafe(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, factoryAddress common.Address, value *big.Int, safeApi string, deployBytecode []byte, safeOperationType SafeOperationType, salt [32]byte, safeNonce *big.Int) error { + abi, err := CreateCall.CreateCallMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + safeCreateCallTxData, err := abi.Pack("performCreate2", value, deployBytecode, salt) + if err != nil { + return fmt.Errorf("failed to pack performCreate2 transaction: %v", err) + } + + return CreateSafeProposal(client, key, safeAddress, factoryAddress, safeCreateCallTxData, value, safeApi, SafeOperationType(safeOperationType), safeNonce) +} + +func PredictDeploymentAddressSafe(from common.Address, salt [32]byte, deployBytecode []byte) (common.Address, error) { + // Calculate the hash of the init code (deployment bytecode) + initCodeHash := crypto.Keccak256(deployBytecode) + + // Calculate the CREATE2 address + deployedAddress := crypto.CreateAddress2(from, salt, initCodeHash) + + return deployedAddress, nil +} + +func CreateSafeProposal(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, to common.Address, data []byte, value *big.Int, safeApi string, safeOperationType SafeOperationType, safeNonce *big.Int) error { + chainID, err := client.ChainID(context.Background()) + if err != nil { + return fmt.Errorf("failed to get chain ID: %v", err) + } + + // Create a new instance of the GnosisSafe contract + safeInstance, err := GnosisSafe.NewGnosisSafe(safeAddress, client) + if err != nil { + return fmt.Errorf("failed to create GnosisSafe instance: %v", err) + } + + nonce := safeNonce + if safeNonce == nil { + // Fetch the current nonce from the Safe contract + fetchedNonce, err := safeInstance.Nonce(&bind.CallOpts{}) + if err != nil { + return fmt.Errorf("failed to fetch nonce from Safe contract: %v", err) + } + nonce = fetchedNonce + } else { + nonce = safeNonce + } + + safeTransactionData := SafeTransactionData{ + To: to.Hex(), + Value: value.String(), + Data: common.Bytes2Hex(data), + Operation: safeOperationType, + SafeTxGas: 0, + BaseGas: 0, + GasPrice: "0", + GasToken: NativeTokenAddress, + RefundReceiver: NativeTokenAddress, + Nonce: nonce, + } + + // Calculate SafeTxHash + safeTxHash, err := CalculateSafeTxHash(safeAddress, safeTransactionData, chainID) + if err != nil { + return fmt.Errorf("failed to calculate SafeTxHash: %v", err) + } + + // Sign the SafeTxHash + signature, err := crypto.Sign(safeTxHash.Bytes(), key.PrivateKey) + if err != nil { + return fmt.Errorf("failed to sign SafeTxHash: %v", err) + } + + // Adjust V value for Ethereum's replay protection + signature[64] += 27 + + // Convert signature to hex + senderSignature := "0x" + common.Bytes2Hex(signature) + + // Prepare the request body + requestBody := map[string]interface{}{ + "to": safeTransactionData.To, + "value": safeTransactionData.Value, + "data": "0x" + safeTransactionData.Data, + "operation": int(safeTransactionData.Operation), + "safeTxGas": fmt.Sprintf("%d", safeTransactionData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", safeTransactionData.BaseGas), + "gasPrice": safeTransactionData.GasPrice, + "gasToken": safeTransactionData.GasToken, + "refundReceiver": safeTransactionData.RefundReceiver, + "nonce": fmt.Sprintf("%d", safeTransactionData.Nonce), + "safeTxHash": safeTxHash.Hex(), + "sender": key.Address.Hex(), + "signature": senderSignature, + "origin": fmt.Sprintf("{\"url\":\"%s\",\"name\":\"TokenSender Deployment\"}", safeApi), + } + + // Marshal the request body to JSON + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("failed to marshal request body: %v", err) + } + + // Send the request to the Safe Transaction Service + req, err := http.NewRequest("POST", safeApi, bytes.NewBuffer(jsonBody)) + if err != nil { + return fmt.Errorf("failed to create request: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + fmt.Println("Safe proposal created successfully") + return nil +} + +func CalculateSafeTxHash(safeAddress common.Address, txData SafeTransactionData, chainID *big.Int) (common.Hash, error) { + domainSeparator := apitypes.TypedDataDomain{ + ChainId: (*math.HexOrDecimal256)(chainID), + VerifyingContract: safeAddress.Hex(), + } + + typedData := apitypes.TypedData{ + Types: apitypes.Types{ + "EIP712Domain": []apitypes.Type{ + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "SafeTx": []apitypes.Type{ + {Name: "to", Type: "address"}, + {Name: "value", Type: "uint256"}, + {Name: "data", Type: "bytes"}, + {Name: "operation", Type: "uint8"}, + {Name: "safeTxGas", Type: "uint256"}, + {Name: "baseGas", Type: "uint256"}, + {Name: "gasPrice", Type: "uint256"}, + {Name: "gasToken", Type: "address"}, + {Name: "refundReceiver", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + }, + }, + Domain: domainSeparator, + PrimaryType: "SafeTx", + Message: apitypes.TypedDataMessage{ + "to": txData.To, + "value": txData.Value, + "data": "0x" + txData.Data, + "operation": fmt.Sprintf("%d", txData.Operation), + "safeTxGas": fmt.Sprintf("%d", txData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", txData.BaseGas), + "gasPrice": txData.GasPrice, + "gasToken": txData.GasToken, + "refundReceiver": txData.RefundReceiver, + "nonce": fmt.Sprintf("%d", txData.Nonce), + }, + } + + typedDataHash, _, err := apitypes.TypedDataAndHash(typedData) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to hash typed data: %v", err) + } + + return common.BytesToHash(typedDataHash), nil +} diff --git a/bindings/utils/diamonds/DiamondCutFacet/DiamondCutFacet.go b/bindings/utils/diamonds/DiamondCutFacet/DiamondCutFacet.go new file mode 100644 index 00000000..ac2abad6 --- /dev/null +++ b/bindings/utils/diamonds/DiamondCutFacet/DiamondCutFacet.go @@ -0,0 +1,1353 @@ +// This file was generated by seer: https://github.com/G7DAO/seer. +// seer version: 0.3.5 +// seer command: seer evm generate --package DiamondCutFacet --cli --struct DiamondCutFacet --output bindings/utils/diamonds/DiamondCutFacet/DiamondCutFacet.go +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package DiamondCutFacet + +import ( + "bytes" + "crypto/rand" + "errors" + "math/big" + "net/http" + "strings" + + "context" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + + // Reference imports to suppress errors if they are not otherwise used. + "encoding/hex" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/G7DAO/seer/bindings/CreateCall" + "github.com/G7DAO/seer/bindings/GnosisSafe" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" + "golang.org/x/term" + + // IDiamondCutFacetCut is an auto generated low-level Go binding around an user-defined struct. + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +type IDiamondCutFacetCut struct { + FacetAddress common.Address + Action uint8 + FunctionSelectors [][4]byte +} + +// DiamondCutFacetMetaData contains all meta data concerning the DiamondCutFacet contract. +var DiamondCutFacetMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_initializationContractAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_calldata\",\"type\":\"bytes\"}],\"name\":\"InitializationFunctionReverted\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"facetAddress\",\"type\":\"address\"},{\"internalType\":\"enumIDiamondCut.FacetCutAction\",\"name\":\"action\",\"type\":\"uint8\"},{\"internalType\":\"bytes4[]\",\"name\":\"functionSelectors\",\"type\":\"bytes4[]\"}],\"indexed\":false,\"internalType\":\"structIDiamondCut.FacetCut[]\",\"name\":\"_diamondCut\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_init\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_calldata\",\"type\":\"bytes\"}],\"name\":\"DiamondCut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"facetAddress\",\"type\":\"address\"},{\"internalType\":\"enumIDiamondCut.FacetCutAction\",\"name\":\"action\",\"type\":\"uint8\"},{\"internalType\":\"bytes4[]\",\"name\":\"functionSelectors\",\"type\":\"bytes4[]\"}],\"indexed\":false,\"internalType\":\"structIDiamondCut.FacetCut[]\",\"name\":\"_diamondCut\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_init\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_calldata\",\"type\":\"bytes\"}],\"name\":\"DiamondCut\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"facetAddress\",\"type\":\"address\"},{\"internalType\":\"enumIDiamondCut.FacetCutAction\",\"name\":\"action\",\"type\":\"uint8\"},{\"internalType\":\"bytes4[]\",\"name\":\"functionSelectors\",\"type\":\"bytes4[]\"}],\"internalType\":\"structIDiamondCut.FacetCut[]\",\"name\":\"_diamondCut\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"_init\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_calldata\",\"type\":\"bytes\"}],\"name\":\"diamondCut\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50611b38806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80631f931c1c14610030575b600080fd5b61004361003e366004611497565b610045565b005b61004d61009e565b61009761005a8587611614565b8484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061016e92505050565b5050505050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c6004015473ffffffffffffffffffffffffffffffffffffffff16331461016c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201527f657200000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b565b60005b835181101561035a57600084828151811061018e5761018e611770565b6020026020010151602001519050600060028111156101af576101af61179f565b8160028111156101c1576101c161179f565b0361020f5761020a8583815181106101db576101db611770565b6020026020010151600001518684815181106101f9576101f9611770565b6020026020010151604001516103a5565b610351565b60018160028111156102235761022361179f565b0361026c5761020a85838151811061023d5761023d611770565b60200260200101516000015186848151811061025b5761025b611770565b60200260200101516040015161074d565b60028160028111156102805761028061179f565b036102c95761020a85838151811061029a5761029a611770565b6020026020010151600001518684815181106102b8576102b8611770565b602002602001015160400151610b05565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f7272656374204661636574437560448201527f74416374696f6e000000000000000000000000000000000000000000000000006064820152608401610163565b50600101610171565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb67383838360405161038e9392919061183c565b60405180910390a16103a08282610ced565b505050565b6000815111610436576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660448201527f6163657420746f206375740000000000000000000000000000000000000000006064820152608401610163565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c73ffffffffffffffffffffffffffffffffffffffff83166104fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260448201527f65206164647265737328302900000000000000000000000000000000000000006064820152608401610163565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600182016020526040812054906bffffffffffffffffffffffff82169003610542576105428285610de6565b60005b835181101561009757600084828151811061056257610562611770565b6020908102919091018101517fffffffff00000000000000000000000000000000000000000000000000000000811660009081529186905260409091205490915073ffffffffffffffffffffffffffffffffffffffff168015610647576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f60448201527f6e207468617420616c72656164792065786973747300000000000000000000006064820152608401610163565b7fffffffff000000000000000000000000000000000000000000000000000000008216600081815260208781526040808320805473ffffffffffffffffffffffffffffffffffffffff908116740100000000000000000000000000000000000000006bffffffffffffffffffffffff8c16021782558c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281547fffffffffffffffffffffffff0000000000000000000000000000000000000000161790558361073c816119d6565b945050600190920191506105459050565b60008151116107de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660448201527f6163657420746f206375740000000000000000000000000000000000000000006064820152608401610163565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c73ffffffffffffffffffffffffffffffffffffffff83166108a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260448201527f65206164647265737328302900000000000000000000000000000000000000006064820152608401610163565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600182016020526040812054906bffffffffffffffffffffffff821690036108ea576108ea8285610de6565b60005b835181101561009757600084828151811061090a5761090a611770565b6020908102919091018101517fffffffff00000000000000000000000000000000000000000000000000000000811660009081529186905260409091205490915073ffffffffffffffffffffffffffffffffffffffff90811690871681036109f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e00000000000000006064820152608401610163565b6109ff858284610e75565b7fffffffff000000000000000000000000000000000000000000000000000000008216600081815260208781526040808320805473ffffffffffffffffffffffffffffffffffffffff908116740100000000000000000000000000000000000000006bffffffffffffffffffffffff8c16021782558c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281547fffffffffffffffffffffffff00000000000000000000000000000000000000001617905583610af4816119d6565b945050600190920191506108ed9050565b6000815111610b96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660448201527f6163657420746f206375740000000000000000000000000000000000000000006064820152608401610163565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c73ffffffffffffffffffffffffffffffffffffffff831615610c5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f7665206661636574206164647260448201527f657373206d7573742062652061646472657373283029000000000000000000006064820152608401610163565b60005b8251811015610ce7576000838281518110610c7b57610c7b611770565b6020908102919091018101517fffffffff00000000000000000000000000000000000000000000000000000000811660009081529185905260409091205490915073ffffffffffffffffffffffffffffffffffffffff16610cdd848284610e75565b5050600101610c5e565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8216610d0c575050565b610d2e82604051806060016040528060288152602001611ab7602891396113ea565b6000808373ffffffffffffffffffffffffffffffffffffffff1683604051610d569190611a01565b600060405180830381855af49150503d8060008114610d91576040519150601f19603f3d011682016040523d82523d6000602084013e610d96565b606091505b509150915081610ce757805115610db05780518082602001fd5b83836040517f192105d7000000000000000000000000000000000000000000000000000000008152600401610163929190611a1d565b610e0881604051806060016040528060248152602001611adf602491396113ea565b60028201805473ffffffffffffffffffffffffffffffffffffffff90921660008181526001948501602090815260408220860185905594840183559182529290200180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169091179055565b73ffffffffffffffffffffffffffffffffffffffff8216610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360448201527f74696f6e207468617420646f65736e27742065786973740000000000000000006064820152608401610163565b3073ffffffffffffffffffffffffffffffffffffffff831603610fbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560448201527f7461626c652066756e6374696f6e0000000000000000000000000000000000006064820152608401610163565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152602084815260408083205473ffffffffffffffffffffffffffffffffffffffff86168452600180880190935290832054740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16929161104791611a54565b905080821461118e5773ffffffffffffffffffffffffffffffffffffffff84166000908152600186016020526040812080548390811061108957611089611770565b6000918252602080832060088304015473ffffffffffffffffffffffffffffffffffffffff8916845260018a019091526040909220805460079092166004026101000a90920460e01b9250829190859081106110e7576110e7611770565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790557fffffffff0000000000000000000000000000000000000000000000000000000092909216825286905260409020805473ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000006bffffffffffffffffffffffff8516021790555b73ffffffffffffffffffffffffffffffffffffffff8416600090815260018601602052604090208054806111c4576111c4611a6d565b6000828152602080822060087fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90940193840401805463ffffffff600460078716026101000a0219169055919092557fffffffff00000000000000000000000000000000000000000000000000000000851682528690526040812081905581900361009757600285015460009061125d90600190611a54565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260018089016020526040909120015490915080821461134b5760008760020183815481106112a9576112a9611770565b60009182526020909120015460028901805473ffffffffffffffffffffffffffffffffffffffff90921692508291849081106112e7576112e7611770565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055929091168152600189810190925260409020018190555b8660020180548061135e5761135e611a6d565b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff88168252600189810190915260408220015550505050505050565b813b8181610ce7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101639190611a9c565b803573ffffffffffffffffffffffffffffffffffffffff8116811461144957600080fd5b919050565b60008083601f84011261146057600080fd5b50813567ffffffffffffffff81111561147857600080fd5b60208301915083602082850101111561149057600080fd5b9250929050565b6000806000806000606086880312156114af57600080fd5b853567ffffffffffffffff808211156114c757600080fd5b818801915088601f8301126114db57600080fd5b8135818111156114ea57600080fd5b8960208260051b85010111156114ff57600080fd5b6020830197508096505061151560208901611425565b9450604088013591508082111561152b57600080fd5b506115388882890161144e565b969995985093965092949392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561159b5761159b611549565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156115e8576115e8611549565b604052919050565b600067ffffffffffffffff82111561160a5761160a611549565b5060051b60200190565b6000611627611622846115f0565b6115a1565b83815260208082019190600586811b86013681111561164557600080fd5b865b8181101561176357803567ffffffffffffffff808211156116685760008081fd5b818a0191506060823603121561167e5760008081fd5b611686611578565b61168f83611425565b815286830135600381106116a35760008081fd5b81880152604083810135838111156116bb5760008081fd5b939093019236601f8501126116d257600092508283fd5b833592506116e2611622846115f0565b83815292871b840188019288810190368511156116ff5760008081fd5b948901945b8486101561174c5785357fffffffff000000000000000000000000000000000000000000000000000000008116811461173d5760008081fd5b82529489019490890190611704565b918301919091525088525050948301948301611647565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60005b838110156117e95781810151838201526020016117d1565b50506000910152565b6000815180845261180a8160208601602086016117ce565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60006060808301606084528087518083526080925060808601915060808160051b8701016020808b0160005b8481101561196a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808a8503018652815188850173ffffffffffffffffffffffffffffffffffffffff825116865284820151600381106118f1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b808310156119555783517fffffffff00000000000000000000000000000000000000000000000000000000168252928601926001929092019190860190611913565b50978501979550505090820190600101611868565b505073ffffffffffffffffffffffffffffffffffffffff8a1690880152868103604088015261199981896117f2565b9a9950505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff8083168181036119f7576119f76119a7565b6001019392505050565b60008251611a138184602087016117ce565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000611a4c60408301846117f2565b949350505050565b81810381811115611a6757611a676119a7565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b602081526000611aaf60208301846117f2565b939250505056fe4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a2646970667358221220937034f955c150355ba27117f2cd205e2f3951ba62bb161fabee7d4bf9705bfa64736f6c63430008180033", +} + +// DiamondCutFacetABI is the input ABI used to generate the binding from. +// Deprecated: Use DiamondCutFacetMetaData.ABI instead. +var DiamondCutFacetABI = DiamondCutFacetMetaData.ABI + +// DiamondCutFacetBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use DiamondCutFacetMetaData.Bin instead. +var DiamondCutFacetBin = DiamondCutFacetMetaData.Bin + +// DeployDiamondCutFacet deploys a new Ethereum contract, binding an instance of DiamondCutFacet to it. +func DeployDiamondCutFacet(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *DiamondCutFacet, error) { + parsed, err := DiamondCutFacetMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DiamondCutFacetBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &DiamondCutFacet{DiamondCutFacetCaller: DiamondCutFacetCaller{contract: contract}, DiamondCutFacetTransactor: DiamondCutFacetTransactor{contract: contract}, DiamondCutFacetFilterer: DiamondCutFacetFilterer{contract: contract}}, nil +} + +// DiamondCutFacet is an auto generated Go binding around an Ethereum contract. +type DiamondCutFacet struct { + DiamondCutFacetCaller // Read-only binding to the contract + DiamondCutFacetTransactor // Write-only binding to the contract + DiamondCutFacetFilterer // Log filterer for contract events +} + +// DiamondCutFacetCaller is an auto generated read-only Go binding around an Ethereum contract. +type DiamondCutFacetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondCutFacetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type DiamondCutFacetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondCutFacetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type DiamondCutFacetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondCutFacetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type DiamondCutFacetSession struct { + Contract *DiamondCutFacet // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DiamondCutFacetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type DiamondCutFacetCallerSession struct { + Contract *DiamondCutFacetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// DiamondCutFacetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type DiamondCutFacetTransactorSession struct { + Contract *DiamondCutFacetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DiamondCutFacetRaw is an auto generated low-level Go binding around an Ethereum contract. +type DiamondCutFacetRaw struct { + Contract *DiamondCutFacet // Generic contract binding to access the raw methods on +} + +// DiamondCutFacetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type DiamondCutFacetCallerRaw struct { + Contract *DiamondCutFacetCaller // Generic read-only contract binding to access the raw methods on +} + +// DiamondCutFacetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type DiamondCutFacetTransactorRaw struct { + Contract *DiamondCutFacetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewDiamondCutFacet creates a new instance of DiamondCutFacet, bound to a specific deployed contract. +func NewDiamondCutFacet(address common.Address, backend bind.ContractBackend) (*DiamondCutFacet, error) { + contract, err := bindDiamondCutFacet(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &DiamondCutFacet{DiamondCutFacetCaller: DiamondCutFacetCaller{contract: contract}, DiamondCutFacetTransactor: DiamondCutFacetTransactor{contract: contract}, DiamondCutFacetFilterer: DiamondCutFacetFilterer{contract: contract}}, nil +} + +// NewDiamondCutFacetCaller creates a new read-only instance of DiamondCutFacet, bound to a specific deployed contract. +func NewDiamondCutFacetCaller(address common.Address, caller bind.ContractCaller) (*DiamondCutFacetCaller, error) { + contract, err := bindDiamondCutFacet(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &DiamondCutFacetCaller{contract: contract}, nil +} + +// NewDiamondCutFacetTransactor creates a new write-only instance of DiamondCutFacet, bound to a specific deployed contract. +func NewDiamondCutFacetTransactor(address common.Address, transactor bind.ContractTransactor) (*DiamondCutFacetTransactor, error) { + contract, err := bindDiamondCutFacet(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &DiamondCutFacetTransactor{contract: contract}, nil +} + +// NewDiamondCutFacetFilterer creates a new log filterer instance of DiamondCutFacet, bound to a specific deployed contract. +func NewDiamondCutFacetFilterer(address common.Address, filterer bind.ContractFilterer) (*DiamondCutFacetFilterer, error) { + contract, err := bindDiamondCutFacet(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &DiamondCutFacetFilterer{contract: contract}, nil +} + +// bindDiamondCutFacet binds a generic wrapper to an already deployed contract. +func bindDiamondCutFacet(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := DiamondCutFacetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_DiamondCutFacet *DiamondCutFacetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _DiamondCutFacet.Contract.DiamondCutFacetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_DiamondCutFacet *DiamondCutFacetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _DiamondCutFacet.Contract.DiamondCutFacetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_DiamondCutFacet *DiamondCutFacetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _DiamondCutFacet.Contract.DiamondCutFacetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_DiamondCutFacet *DiamondCutFacetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _DiamondCutFacet.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_DiamondCutFacet *DiamondCutFacetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _DiamondCutFacet.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_DiamondCutFacet *DiamondCutFacetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _DiamondCutFacet.Contract.contract.Transact(opts, method, params...) +} + +// DiamondCut is a paid mutator transaction binding the contract method 0x1f931c1c. +// +// Solidity: function diamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) returns() +func (_DiamondCutFacet *DiamondCutFacetTransactor) DiamondCut(opts *bind.TransactOpts, _diamondCut []IDiamondCutFacetCut, _init common.Address, _calldata []byte) (*types.Transaction, error) { + return _DiamondCutFacet.contract.Transact(opts, "diamondCut", _diamondCut, _init, _calldata) +} + +// DiamondCut is a paid mutator transaction binding the contract method 0x1f931c1c. +// +// Solidity: function diamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) returns() +func (_DiamondCutFacet *DiamondCutFacetSession) DiamondCut(_diamondCut []IDiamondCutFacetCut, _init common.Address, _calldata []byte) (*types.Transaction, error) { + return _DiamondCutFacet.Contract.DiamondCut(&_DiamondCutFacet.TransactOpts, _diamondCut, _init, _calldata) +} + +// DiamondCut is a paid mutator transaction binding the contract method 0x1f931c1c. +// +// Solidity: function diamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) returns() +func (_DiamondCutFacet *DiamondCutFacetTransactorSession) DiamondCut(_diamondCut []IDiamondCutFacetCut, _init common.Address, _calldata []byte) (*types.Transaction, error) { + return _DiamondCutFacet.Contract.DiamondCut(&_DiamondCutFacet.TransactOpts, _diamondCut, _init, _calldata) +} + +// DiamondCutFacetDiamondCutIterator is returned from FilterDiamondCut and is used to iterate over the raw logs and unpacked data for DiamondCut events raised by the DiamondCutFacet contract. +type DiamondCutFacetDiamondCutIterator struct { + Event *DiamondCutFacetDiamondCut // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DiamondCutFacetDiamondCutIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DiamondCutFacetDiamondCut) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DiamondCutFacetDiamondCut) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DiamondCutFacetDiamondCutIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DiamondCutFacetDiamondCutIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DiamondCutFacetDiamondCut represents a DiamondCut event raised by the DiamondCutFacet contract. +type DiamondCutFacetDiamondCut struct { + DiamondCut []IDiamondCutFacetCut + Init common.Address + Calldata []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterDiamondCut is a free log retrieval operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_DiamondCutFacet *DiamondCutFacetFilterer) FilterDiamondCut(opts *bind.FilterOpts) (*DiamondCutFacetDiamondCutIterator, error) { + + logs, sub, err := _DiamondCutFacet.contract.FilterLogs(opts, "DiamondCut") + if err != nil { + return nil, err + } + return &DiamondCutFacetDiamondCutIterator{contract: _DiamondCutFacet.contract, event: "DiamondCut", logs: logs, sub: sub}, nil +} + +// WatchDiamondCut is a free log subscription operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_DiamondCutFacet *DiamondCutFacetFilterer) WatchDiamondCut(opts *bind.WatchOpts, sink chan<- *DiamondCutFacetDiamondCut) (event.Subscription, error) { + + logs, sub, err := _DiamondCutFacet.contract.WatchLogs(opts, "DiamondCut") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DiamondCutFacetDiamondCut) + if err := _DiamondCutFacet.contract.UnpackLog(event, "DiamondCut", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseDiamondCut is a log parse operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_DiamondCutFacet *DiamondCutFacetFilterer) ParseDiamondCut(log types.Log) (*DiamondCutFacetDiamondCut, error) { + event := new(DiamondCutFacetDiamondCut) + if err := _DiamondCutFacet.contract.UnpackLog(event, "DiamondCut", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// DiamondCutFacetDiamondCut0Iterator is returned from FilterDiamondCut0 and is used to iterate over the raw logs and unpacked data for DiamondCut0 events raised by the DiamondCutFacet contract. +type DiamondCutFacetDiamondCut0Iterator struct { + Event *DiamondCutFacetDiamondCut0 // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *DiamondCutFacetDiamondCut0Iterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(DiamondCutFacetDiamondCut0) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(DiamondCutFacetDiamondCut0) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *DiamondCutFacetDiamondCut0Iterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *DiamondCutFacetDiamondCut0Iterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// DiamondCutFacetDiamondCut0 represents a DiamondCut0 event raised by the DiamondCutFacet contract. +type DiamondCutFacetDiamondCut0 struct { + DiamondCut []IDiamondCutFacetCut + Init common.Address + Calldata []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterDiamondCut0 is a free log retrieval operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_DiamondCutFacet *DiamondCutFacetFilterer) FilterDiamondCut0(opts *bind.FilterOpts) (*DiamondCutFacetDiamondCut0Iterator, error) { + + logs, sub, err := _DiamondCutFacet.contract.FilterLogs(opts, "DiamondCut0") + if err != nil { + return nil, err + } + return &DiamondCutFacetDiamondCut0Iterator{contract: _DiamondCutFacet.contract, event: "DiamondCut0", logs: logs, sub: sub}, nil +} + +// WatchDiamondCut0 is a free log subscription operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_DiamondCutFacet *DiamondCutFacetFilterer) WatchDiamondCut0(opts *bind.WatchOpts, sink chan<- *DiamondCutFacetDiamondCut0) (event.Subscription, error) { + + logs, sub, err := _DiamondCutFacet.contract.WatchLogs(opts, "DiamondCut0") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(DiamondCutFacetDiamondCut0) + if err := _DiamondCutFacet.contract.UnpackLog(event, "DiamondCut0", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseDiamondCut0 is a log parse operation binding the contract event 0x8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb673. +// +// Solidity: event DiamondCut((address,uint8,bytes4[])[] _diamondCut, address _init, bytes _calldata) +func (_DiamondCutFacet *DiamondCutFacetFilterer) ParseDiamondCut0(log types.Log) (*DiamondCutFacetDiamondCut0, error) { + event := new(DiamondCutFacetDiamondCut0) + if err := _DiamondCutFacet.contract.UnpackLog(event, "DiamondCut0", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func CreateDiamondCutFacetDeploymentCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc string + var gasLimit uint64 + var simulate bool + var timeout uint + var safeAddress, safeApi, safeCreateCall, safeSaltRaw, safeNonceRaw string + var safeOperationType uint8 + var salt [32]byte + var predictAddress bool + var safeNonce *big.Int + + cmd := &cobra.Command{ + Use: "deploy", + Short: "Deploy a new DiamondCutFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if safeCreateCall == "" { + fmt.Println("--safe-create-call not specified, using default (0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4)") + safeCreateCall = "0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4" + } + if !common.IsHexAddress(safeCreateCall) { + return fmt.Errorf("--safe-create-call is not a valid Ethereum address") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeSaltRaw == "" { + fmt.Println("--safe-salt not specified, generating random salt") + _, err := rand.Read(salt[:]) + if err != nil { + return fmt.Errorf("failed to generate random salt: %v", err) + } + // prompt user to accept random salt + fmt.Println("Generated salt:", common.Bytes2Hex(salt[:])) + fmt.Println("Please check the salt and confirm (y/n)") + var confirm string + fmt.Scanln(&confirm) + if confirm != "y" && confirm != "Y" && confirm != "\n" && confirm != "" { + return fmt.Errorf("salt not accepted, please specify a valid salt") + } + } else { + copy(salt[:], safeSaltRaw) + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + if safeAddress != "" { + // Generate deploy bytecode with constructor arguments + deployBytecode, err := generateDiamondCutFacetDeployBytecode() + if err != nil { + return fmt.Errorf("failed to generate deploy bytecode: %v", err) + } + + // Create Safe proposal for deployment + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + if predictAddress { + fmt.Println("Predicting deployment address...") + from := common.HexToAddress(safeAddress) + if safeOperationType == 0 { + from = common.HexToAddress(safeCreateCall) + } + deploymentAddress, err := PredictDeploymentAddressSafe(from, salt, deployBytecode) + if err != nil { + return fmt.Errorf("failed to predict deployment address: %v", err) + } + fmt.Println("Predicted deployment address:", deploymentAddress.Hex()) + return nil + } else { + fmt.Println("Creating Safe proposal...") + err = DeployWithSafe(client, key, common.HexToAddress(safeAddress), common.HexToAddress(safeCreateCall), value, safeApi, deployBytecode, SafeOperationType(safeOperationType), salt, safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + } + + return nil + } + + address, deploymentTransaction, _, deploymentErr := DeployDiamondCutFacet( + transactionOpts, + client, + ) + if deploymentErr != nil { + return deploymentErr + } + + cmd.Printf("Transaction hash: %s\nContract address: %s\n", deploymentTransaction.Hash().Hex(), address.Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + Data: deploymentTransaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := deploymentTransaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().StringVar(&safeCreateCall, "safe-create-call", "", "Address of the CreateCall contract (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 1, "Safe operation type: 0 (Call) or 1 (DelegateCall) - default is 1") + cmd.Flags().StringVar(&safeSaltRaw, "safe-salt", "", "Salt to use for the Safe transaction") + cmd.Flags().BoolVar(&predictAddress, "safe-predict-address", false, "Predict the deployment address (only works for Safe transactions)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + return cmd +} + +func generateDiamondCutFacetDeployBytecode() ([]byte, error) { + abiPacked, err := DiamondCutFacetMetaData.GetAbi() + if err != nil { + return nil, fmt.Errorf("failed to get ABI: %v", err) + } + + constructorArguments, err := abiPacked.Pack("") + if err != nil { + return nil, fmt.Errorf("failed to pack constructor arguments: %v", err) + } + + deployBytecode := append(common.FromHex(DiamondCutFacetMetaData.Bin), constructorArguments...) + return deployBytecode, nil +} + +func CreateDiamondCutCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var diamondCut []IDiamondCutFacetCut + var diamondCutRaw string + var init common.Address + var initRaw string + var calldata []byte + var calldataRaw string + + cmd := &cobra.Command{ + Use: "diamond-cut", + Short: "Execute the DiamondCut method on a DiamondCutFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if diamondCutRaw == "" { + return fmt.Errorf("--diamond-cut argument not specified") + } else if strings.HasPrefix(diamondCutRaw, "@") { + filename := strings.TrimPrefix(diamondCutRaw, "@") + contents, readErr := os.ReadFile(filename) + if readErr != nil { + return readErr + } + unmarshalErr := json.Unmarshal(contents, &diamondCut) + if unmarshalErr != nil { + return unmarshalErr + } + } else { + unmarshalErr := json.Unmarshal([]byte(diamondCutRaw), &diamondCut) + if unmarshalErr != nil { + return unmarshalErr + } + } + + if initRaw == "" { + return fmt.Errorf("--init argument not specified") + } else if !common.IsHexAddress(initRaw) { + return fmt.Errorf("--init argument is not a valid Ethereum address") + } + init = common.HexToAddress(initRaw) + + var calldataIntermediate []byte + + var calldataIntermediateHexDecodeErr error + calldataIntermediate, calldataIntermediateHexDecodeErr = hex.DecodeString(calldataRaw) + if calldataIntermediateHexDecodeErr != nil { + return calldataIntermediateHexDecodeErr + } + + copy(calldata[:], calldataIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewDiamondCutFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := DiamondCutFacetTransactorSession{ + Contract: &contract.DiamondCutFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := DiamondCutFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "diamondCut" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + diamondCut, + init, + calldata, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.DiamondCut( + + diamondCut, + init, + calldata, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&diamondCutRaw, "diamond-cut", "", "diamond-cut argument ([]IDiamondCutFacetCut)") + cmd.Flags().StringVar(&initRaw, "init", "", "init argument (common.Address)") + cmd.Flags().StringVar(&calldataRaw, "calldata", "", "calldata argument ([]byte)") + + return cmd +} + +var ErrNoRPCURL error = errors.New("no RPC URL provided -- please pass an RPC URL from the command line or set the DIAMOND_CUT_FACET_RPC_URL environment variable") + +// Generates an Ethereum client to the JSONRPC API at the given URL. If rpcURL is empty, then it +// attempts to read the RPC URL from the DIAMOND_CUT_FACET_RPC_URL environment variable. If that is empty, +// too, then it returns an error. +func NewClient(rpcURL string) (*ethclient.Client, error) { + if rpcURL == "" { + rpcURL = os.Getenv("DIAMOND_CUT_FACET_RPC_URL") + } + + if rpcURL == "" { + return nil, ErrNoRPCURL + } + + client, err := ethclient.Dial(rpcURL) + return client, err +} + +// Creates a new context to be used when interacting with the chain client. +func NewChainContext(timeout uint) (context.Context, context.CancelFunc) { + baseCtx := context.Background() + parsedTimeout := time.Duration(timeout) * time.Second + ctx, cancel := context.WithTimeout(baseCtx, parsedTimeout) + return ctx, cancel +} + +// Unlocks a key from a keystore (byte contents of a keystore file) with the given password. +func UnlockKeystore(keystoreData []byte, password string) (*keystore.Key, error) { + key, err := keystore.DecryptKey(keystoreData, password) + return key, err +} + +// Loads a key from file, prompting the user for the password if it is not provided as a function argument. +func KeyFromFile(keystoreFile string, password string) (*keystore.Key, error) { + var emptyKey *keystore.Key + keystoreContent, readErr := os.ReadFile(keystoreFile) + if readErr != nil { + return emptyKey, readErr + } + + // If password is "", prompt user for password. + if password == "" { + fmt.Printf("Please provide a password for keystore (%s): ", keystoreFile) + passwordRaw, inputErr := term.ReadPassword(int(os.Stdin.Fd())) + if inputErr != nil { + return emptyKey, fmt.Errorf("error reading password: %s", inputErr.Error()) + } + fmt.Print("\n") + password = string(passwordRaw) + } + + key, err := UnlockKeystore(keystoreContent, password) + return key, err +} + +// This method is used to set the parameters on a view call from command line arguments (represented mostly as +// strings). +func SetCallParametersFromArgs(opts *bind.CallOpts, pending bool, fromAddress, blockNumber string) { + if pending { + opts.Pending = true + } + + if fromAddress != "" { + opts.From = common.HexToAddress(fromAddress) + } + + if blockNumber != "" { + opts.BlockNumber = new(big.Int) + opts.BlockNumber.SetString(blockNumber, 0) + } +} + +// This method is used to set the parameters on a transaction from command line arguments (represented mostly as +// strings). +func SetTransactionParametersFromArgs(opts *bind.TransactOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas string, gasLimit uint64, noSend bool) { + if nonce != "" { + opts.Nonce = new(big.Int) + opts.Nonce.SetString(nonce, 0) + } + + if value != "" { + opts.Value = new(big.Int) + opts.Value.SetString(value, 0) + } + + if gasPrice != "" { + opts.GasPrice = new(big.Int) + opts.GasPrice.SetString(gasPrice, 0) + } + + if maxFeePerGas != "" { + opts.GasFeeCap = new(big.Int) + opts.GasFeeCap.SetString(maxFeePerGas, 0) + } + + if maxPriorityFeePerGas != "" { + opts.GasTipCap = new(big.Int) + opts.GasTipCap.SetString(maxPriorityFeePerGas, 0) + } + + if gasLimit != 0 { + opts.GasLimit = gasLimit + } + + opts.NoSend = noSend +} + +func CreateDiamondCutFacetCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "diamond-cut-facet", + Short: "Interact with the DiamondCutFacet contract", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + + cmd.SetOut(os.Stdout) + + DeployGroup := &cobra.Group{ + ID: "deploy", Title: "Commands which deploy contracts", + } + cmd.AddGroup(DeployGroup) + ViewGroup := &cobra.Group{ + ID: "view", Title: "Commands which view contract state", + } + TransactGroup := &cobra.Group{ + ID: "transact", Title: "Commands which submit transactions", + } + cmd.AddGroup(ViewGroup, TransactGroup) + + cmdDeployDiamondCutFacet := CreateDiamondCutFacetDeploymentCommand() + cmdDeployDiamondCutFacet.GroupID = DeployGroup.ID + cmd.AddCommand(cmdDeployDiamondCutFacet) + + cmdTransactDiamondCut := CreateDiamondCutCommand() + cmdTransactDiamondCut.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactDiamondCut) + + return cmd +} + +// SafeOperationType represents the type of operation for a Safe transaction +type SafeOperationType uint8 + +const ( + Call SafeOperationType = 0 + DelegateCall SafeOperationType = 1 +) + +// String returns the string representation of the SafeOperationType +func (o SafeOperationType) String() string { + switch o { + case Call: + return "Call" + case DelegateCall: + return "DelegateCall" + default: + return "Unknown" + } +} + +// SafeTransactionData represents the data for a Safe transaction +type SafeTransactionData struct { + To string `json:"to"` + Value string `json:"value"` + Data string `json:"data"` + Operation SafeOperationType `json:"operation"` + SafeTxGas uint64 `json:"safeTxGas"` + BaseGas uint64 `json:"baseGas"` + GasPrice string `json:"gasPrice"` + GasToken string `json:"gasToken"` + RefundReceiver string `json:"refundReceiver"` + Nonce *big.Int `json:"nonce"` + SafeTxHash string `json:"safeTxHash"` + Sender string `json:"sender"` + Signature string `json:"signature"` + Origin string `json:"origin"` +} + +const ( + NativeTokenAddress = "0x0000000000000000000000000000000000000000" +) + +func DeployWithSafe(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, factoryAddress common.Address, value *big.Int, safeApi string, deployBytecode []byte, safeOperationType SafeOperationType, salt [32]byte, safeNonce *big.Int) error { + abi, err := CreateCall.CreateCallMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + safeCreateCallTxData, err := abi.Pack("performCreate2", value, deployBytecode, salt) + if err != nil { + return fmt.Errorf("failed to pack performCreate2 transaction: %v", err) + } + + return CreateSafeProposal(client, key, safeAddress, factoryAddress, safeCreateCallTxData, value, safeApi, SafeOperationType(safeOperationType), safeNonce) +} + +func PredictDeploymentAddressSafe(from common.Address, salt [32]byte, deployBytecode []byte) (common.Address, error) { + // Calculate the hash of the init code (deployment bytecode) + initCodeHash := crypto.Keccak256(deployBytecode) + + // Calculate the CREATE2 address + deployedAddress := crypto.CreateAddress2(from, salt, initCodeHash) + + return deployedAddress, nil +} + +func CreateSafeProposal(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, to common.Address, data []byte, value *big.Int, safeApi string, safeOperationType SafeOperationType, safeNonce *big.Int) error { + chainID, err := client.ChainID(context.Background()) + if err != nil { + return fmt.Errorf("failed to get chain ID: %v", err) + } + + // Create a new instance of the GnosisSafe contract + safeInstance, err := GnosisSafe.NewGnosisSafe(safeAddress, client) + if err != nil { + return fmt.Errorf("failed to create GnosisSafe instance: %v", err) + } + + nonce := safeNonce + if safeNonce == nil { + // Fetch the current nonce from the Safe contract + fetchedNonce, err := safeInstance.Nonce(&bind.CallOpts{}) + if err != nil { + return fmt.Errorf("failed to fetch nonce from Safe contract: %v", err) + } + nonce = fetchedNonce + } else { + nonce = safeNonce + } + + safeTransactionData := SafeTransactionData{ + To: to.Hex(), + Value: value.String(), + Data: common.Bytes2Hex(data), + Operation: safeOperationType, + SafeTxGas: 0, + BaseGas: 0, + GasPrice: "0", + GasToken: NativeTokenAddress, + RefundReceiver: NativeTokenAddress, + Nonce: nonce, + } + + // Calculate SafeTxHash + safeTxHash, err := CalculateSafeTxHash(safeAddress, safeTransactionData, chainID) + if err != nil { + return fmt.Errorf("failed to calculate SafeTxHash: %v", err) + } + + // Sign the SafeTxHash + signature, err := crypto.Sign(safeTxHash.Bytes(), key.PrivateKey) + if err != nil { + return fmt.Errorf("failed to sign SafeTxHash: %v", err) + } + + // Adjust V value for Ethereum's replay protection + signature[64] += 27 + + // Convert signature to hex + senderSignature := "0x" + common.Bytes2Hex(signature) + + // Prepare the request body + requestBody := map[string]interface{}{ + "to": safeTransactionData.To, + "value": safeTransactionData.Value, + "data": "0x" + safeTransactionData.Data, + "operation": int(safeTransactionData.Operation), + "safeTxGas": fmt.Sprintf("%d", safeTransactionData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", safeTransactionData.BaseGas), + "gasPrice": safeTransactionData.GasPrice, + "gasToken": safeTransactionData.GasToken, + "refundReceiver": safeTransactionData.RefundReceiver, + "nonce": fmt.Sprintf("%d", safeTransactionData.Nonce), + "safeTxHash": safeTxHash.Hex(), + "sender": key.Address.Hex(), + "signature": senderSignature, + "origin": fmt.Sprintf("{\"url\":\"%s\",\"name\":\"TokenSender Deployment\"}", safeApi), + } + + // Marshal the request body to JSON + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("failed to marshal request body: %v", err) + } + + // Send the request to the Safe Transaction Service + req, err := http.NewRequest("POST", safeApi, bytes.NewBuffer(jsonBody)) + if err != nil { + return fmt.Errorf("failed to create request: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + fmt.Println("Safe proposal created successfully") + return nil +} + +func CalculateSafeTxHash(safeAddress common.Address, txData SafeTransactionData, chainID *big.Int) (common.Hash, error) { + domainSeparator := apitypes.TypedDataDomain{ + ChainId: (*math.HexOrDecimal256)(chainID), + VerifyingContract: safeAddress.Hex(), + } + + typedData := apitypes.TypedData{ + Types: apitypes.Types{ + "EIP712Domain": []apitypes.Type{ + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "SafeTx": []apitypes.Type{ + {Name: "to", Type: "address"}, + {Name: "value", Type: "uint256"}, + {Name: "data", Type: "bytes"}, + {Name: "operation", Type: "uint8"}, + {Name: "safeTxGas", Type: "uint256"}, + {Name: "baseGas", Type: "uint256"}, + {Name: "gasPrice", Type: "uint256"}, + {Name: "gasToken", Type: "address"}, + {Name: "refundReceiver", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + }, + }, + Domain: domainSeparator, + PrimaryType: "SafeTx", + Message: apitypes.TypedDataMessage{ + "to": txData.To, + "value": txData.Value, + "data": "0x" + txData.Data, + "operation": fmt.Sprintf("%d", txData.Operation), + "safeTxGas": fmt.Sprintf("%d", txData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", txData.BaseGas), + "gasPrice": txData.GasPrice, + "gasToken": txData.GasToken, + "refundReceiver": txData.RefundReceiver, + "nonce": fmt.Sprintf("%d", txData.Nonce), + }, + } + + typedDataHash, _, err := apitypes.TypedDataAndHash(typedData) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to hash typed data: %v", err) + } + + return common.BytesToHash(typedDataHash), nil +} diff --git a/bindings/utils/diamonds/DiamondLoupeFacet/DiamondLoupeFacet.go b/bindings/utils/diamonds/DiamondLoupeFacet/DiamondLoupeFacet.go new file mode 100644 index 00000000..b0bea3ee --- /dev/null +++ b/bindings/utils/diamonds/DiamondLoupeFacet/DiamondLoupeFacet.go @@ -0,0 +1,1344 @@ +// This file was generated by seer: https://github.com/G7DAO/seer. +// seer version: 0.3.5 +// seer command: seer evm generate --package DiamondLoupeFacet --cli --struct DiamondLoupeFacet --output bindings/utils/diamonds/DiamondLoupeFacet/DiamondLoupeFacet.go +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package DiamondLoupeFacet + +import ( + "bytes" + "crypto/rand" + "errors" + "math/big" + "net/http" + "strings" + + "context" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + + // Reference imports to suppress errors if they are not otherwise used. + "encoding/hex" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/G7DAO/seer/bindings/CreateCall" + "github.com/G7DAO/seer/bindings/GnosisSafe" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" + "golang.org/x/term" + + // IDiamondLoupeFacet is an auto generated low-level Go binding around an user-defined struct. + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +type IDiamondLoupeFacet struct { + FacetAddress common.Address + FunctionSelectors [][4]byte +} + +// DiamondLoupeFacetMetaData contains all meta data concerning the DiamondLoupeFacet contract. +var DiamondLoupeFacetMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"_functionSelector\",\"type\":\"bytes4\"}],\"name\":\"facetAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"facetAddress_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"facetAddresses\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"facetAddresses_\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_facet\",\"type\":\"address\"}],\"name\":\"facetFunctionSelectors\",\"outputs\":[{\"internalType\":\"bytes4[]\",\"name\":\"facetFunctionSelectors_\",\"type\":\"bytes4[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"facets\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"facetAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"functionSelectors\",\"type\":\"bytes4[]\"}],\"internalType\":\"structIDiamondLoupe.Facet[]\",\"name\":\"facets_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"_interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b506107e5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637a0ed627116100505780637a0ed627146100fa578063adfca15e1461010f578063cdffacc61461012f57600080fd5b806301ffc9a71461006c57806352ef6b2c146100e5575b600080fd5b6100d061007a36600461055d565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f602052604090205460ff1690565b60405190151581526020015b60405180910390f35b6100ed6101cb565b6040516100dc91906105a6565b61010261025d565b6040516100dc919061065e565b61012261011d366004610708565b61045d565b6040516100dc919061073e565b6101a661013d36600461055d565b7fffffffff000000000000000000000000000000000000000000000000000000001660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100dc565b606060007fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c6002810180546040805160208084028201810190925282815293945083018282801561025257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610227575b505050505091505090565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131e546060907fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c908067ffffffffffffffff8111156102bd576102bd610751565b60405190808252806020026020018201604052801561030357816020015b6040805180820190915260008152606060208201528152602001906001900390816102db5790505b50925060005b8181101561045757600083600201828154811061032857610328610780565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508085838151811061036857610368610780565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff928316905290821660009081526001860182526040908190208054825181850281018501909352808352919290919083018282801561042957602002820191906000526020600020906000905b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600401906020826003010492830192600103820291508084116103d65790505b505050505085838151811061044057610440610780565b602090810291909101810151015250600101610309565b50505090565b73ffffffffffffffffffffffffffffffffffffffff811660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131d602090815260409182902080548351818402810184019094528084526060937fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c939092919083018282801561055057602002820191906000526020600020906000905b82829054906101000a900460e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600401906020826003010492830192600103820291508084116104fd5790505b5050505050915050919050565b60006020828403121561056f57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461059f57600080fd5b9392505050565b6020808252825182820181905260009190848201906040850190845b818110156105f457835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016105c2565b50909695505050505050565b60008151808452602080850194506020840160005b838110156106535781517fffffffff000000000000000000000000000000000000000000000000000000001687529582019590820190600101610615565b509495945050505050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b838110156106fa578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00185528151805173ffffffffffffffffffffffffffffffffffffffff1684528701518784018790526106e787850182610600565b9588019593505090860190600101610687565b509098975050505050505050565b60006020828403121561071a57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461059f57600080fd5b60208152600061059f6020830184610600565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea26469706673582212201bafae2f6abe644137f2e27e24ccdac3736d5ecff5c3ca33b4b02a597967d09764736f6c63430008180033", +} + +// DiamondLoupeFacetABI is the input ABI used to generate the binding from. +// Deprecated: Use DiamondLoupeFacetMetaData.ABI instead. +var DiamondLoupeFacetABI = DiamondLoupeFacetMetaData.ABI + +// DiamondLoupeFacetBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use DiamondLoupeFacetMetaData.Bin instead. +var DiamondLoupeFacetBin = DiamondLoupeFacetMetaData.Bin + +// DeployDiamondLoupeFacet deploys a new Ethereum contract, binding an instance of DiamondLoupeFacet to it. +func DeployDiamondLoupeFacet(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *DiamondLoupeFacet, error) { + parsed, err := DiamondLoupeFacetMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DiamondLoupeFacetBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &DiamondLoupeFacet{DiamondLoupeFacetCaller: DiamondLoupeFacetCaller{contract: contract}, DiamondLoupeFacetTransactor: DiamondLoupeFacetTransactor{contract: contract}, DiamondLoupeFacetFilterer: DiamondLoupeFacetFilterer{contract: contract}}, nil +} + +// DiamondLoupeFacet is an auto generated Go binding around an Ethereum contract. +type DiamondLoupeFacet struct { + DiamondLoupeFacetCaller // Read-only binding to the contract + DiamondLoupeFacetTransactor // Write-only binding to the contract + DiamondLoupeFacetFilterer // Log filterer for contract events +} + +// DiamondLoupeFacetCaller is an auto generated read-only Go binding around an Ethereum contract. +type DiamondLoupeFacetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondLoupeFacetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type DiamondLoupeFacetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondLoupeFacetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type DiamondLoupeFacetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// DiamondLoupeFacetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type DiamondLoupeFacetSession struct { + Contract *DiamondLoupeFacet // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DiamondLoupeFacetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type DiamondLoupeFacetCallerSession struct { + Contract *DiamondLoupeFacetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// DiamondLoupeFacetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type DiamondLoupeFacetTransactorSession struct { + Contract *DiamondLoupeFacetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// DiamondLoupeFacetRaw is an auto generated low-level Go binding around an Ethereum contract. +type DiamondLoupeFacetRaw struct { + Contract *DiamondLoupeFacet // Generic contract binding to access the raw methods on +} + +// DiamondLoupeFacetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type DiamondLoupeFacetCallerRaw struct { + Contract *DiamondLoupeFacetCaller // Generic read-only contract binding to access the raw methods on +} + +// DiamondLoupeFacetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type DiamondLoupeFacetTransactorRaw struct { + Contract *DiamondLoupeFacetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewDiamondLoupeFacet creates a new instance of DiamondLoupeFacet, bound to a specific deployed contract. +func NewDiamondLoupeFacet(address common.Address, backend bind.ContractBackend) (*DiamondLoupeFacet, error) { + contract, err := bindDiamondLoupeFacet(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &DiamondLoupeFacet{DiamondLoupeFacetCaller: DiamondLoupeFacetCaller{contract: contract}, DiamondLoupeFacetTransactor: DiamondLoupeFacetTransactor{contract: contract}, DiamondLoupeFacetFilterer: DiamondLoupeFacetFilterer{contract: contract}}, nil +} + +// NewDiamondLoupeFacetCaller creates a new read-only instance of DiamondLoupeFacet, bound to a specific deployed contract. +func NewDiamondLoupeFacetCaller(address common.Address, caller bind.ContractCaller) (*DiamondLoupeFacetCaller, error) { + contract, err := bindDiamondLoupeFacet(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &DiamondLoupeFacetCaller{contract: contract}, nil +} + +// NewDiamondLoupeFacetTransactor creates a new write-only instance of DiamondLoupeFacet, bound to a specific deployed contract. +func NewDiamondLoupeFacetTransactor(address common.Address, transactor bind.ContractTransactor) (*DiamondLoupeFacetTransactor, error) { + contract, err := bindDiamondLoupeFacet(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &DiamondLoupeFacetTransactor{contract: contract}, nil +} + +// NewDiamondLoupeFacetFilterer creates a new log filterer instance of DiamondLoupeFacet, bound to a specific deployed contract. +func NewDiamondLoupeFacetFilterer(address common.Address, filterer bind.ContractFilterer) (*DiamondLoupeFacetFilterer, error) { + contract, err := bindDiamondLoupeFacet(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &DiamondLoupeFacetFilterer{contract: contract}, nil +} + +// bindDiamondLoupeFacet binds a generic wrapper to an already deployed contract. +func bindDiamondLoupeFacet(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := DiamondLoupeFacetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_DiamondLoupeFacet *DiamondLoupeFacetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _DiamondLoupeFacet.Contract.DiamondLoupeFacetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_DiamondLoupeFacet *DiamondLoupeFacetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _DiamondLoupeFacet.Contract.DiamondLoupeFacetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_DiamondLoupeFacet *DiamondLoupeFacetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _DiamondLoupeFacet.Contract.DiamondLoupeFacetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_DiamondLoupeFacet *DiamondLoupeFacetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _DiamondLoupeFacet.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_DiamondLoupeFacet *DiamondLoupeFacetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _DiamondLoupeFacet.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_DiamondLoupeFacet *DiamondLoupeFacetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _DiamondLoupeFacet.Contract.contract.Transact(opts, method, params...) +} + +// FacetAddress is a free data retrieval call binding the contract method 0xcdffacc6. +// +// Solidity: function facetAddress(bytes4 _functionSelector) view returns(address facetAddress_) +func (_DiamondLoupeFacet *DiamondLoupeFacetCaller) FacetAddress(opts *bind.CallOpts, _functionSelector [4]byte) (common.Address, error) { + var out []interface{} + err := _DiamondLoupeFacet.contract.Call(opts, &out, "facetAddress", _functionSelector) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// FacetAddress is a free data retrieval call binding the contract method 0xcdffacc6. +// +// Solidity: function facetAddress(bytes4 _functionSelector) view returns(address facetAddress_) +func (_DiamondLoupeFacet *DiamondLoupeFacetSession) FacetAddress(_functionSelector [4]byte) (common.Address, error) { + return _DiamondLoupeFacet.Contract.FacetAddress(&_DiamondLoupeFacet.CallOpts, _functionSelector) +} + +// FacetAddress is a free data retrieval call binding the contract method 0xcdffacc6. +// +// Solidity: function facetAddress(bytes4 _functionSelector) view returns(address facetAddress_) +func (_DiamondLoupeFacet *DiamondLoupeFacetCallerSession) FacetAddress(_functionSelector [4]byte) (common.Address, error) { + return _DiamondLoupeFacet.Contract.FacetAddress(&_DiamondLoupeFacet.CallOpts, _functionSelector) +} + +// FacetAddresses is a free data retrieval call binding the contract method 0x52ef6b2c. +// +// Solidity: function facetAddresses() view returns(address[] facetAddresses_) +func (_DiamondLoupeFacet *DiamondLoupeFacetCaller) FacetAddresses(opts *bind.CallOpts) ([]common.Address, error) { + var out []interface{} + err := _DiamondLoupeFacet.contract.Call(opts, &out, "facetAddresses") + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +// FacetAddresses is a free data retrieval call binding the contract method 0x52ef6b2c. +// +// Solidity: function facetAddresses() view returns(address[] facetAddresses_) +func (_DiamondLoupeFacet *DiamondLoupeFacetSession) FacetAddresses() ([]common.Address, error) { + return _DiamondLoupeFacet.Contract.FacetAddresses(&_DiamondLoupeFacet.CallOpts) +} + +// FacetAddresses is a free data retrieval call binding the contract method 0x52ef6b2c. +// +// Solidity: function facetAddresses() view returns(address[] facetAddresses_) +func (_DiamondLoupeFacet *DiamondLoupeFacetCallerSession) FacetAddresses() ([]common.Address, error) { + return _DiamondLoupeFacet.Contract.FacetAddresses(&_DiamondLoupeFacet.CallOpts) +} + +// FacetFunctionSelectors is a free data retrieval call binding the contract method 0xadfca15e. +// +// Solidity: function facetFunctionSelectors(address _facet) view returns(bytes4[] facetFunctionSelectors_) +func (_DiamondLoupeFacet *DiamondLoupeFacetCaller) FacetFunctionSelectors(opts *bind.CallOpts, _facet common.Address) ([][4]byte, error) { + var out []interface{} + err := _DiamondLoupeFacet.contract.Call(opts, &out, "facetFunctionSelectors", _facet) + + if err != nil { + return *new([][4]byte), err + } + + out0 := *abi.ConvertType(out[0], new([][4]byte)).(*[][4]byte) + + return out0, err + +} + +// FacetFunctionSelectors is a free data retrieval call binding the contract method 0xadfca15e. +// +// Solidity: function facetFunctionSelectors(address _facet) view returns(bytes4[] facetFunctionSelectors_) +func (_DiamondLoupeFacet *DiamondLoupeFacetSession) FacetFunctionSelectors(_facet common.Address) ([][4]byte, error) { + return _DiamondLoupeFacet.Contract.FacetFunctionSelectors(&_DiamondLoupeFacet.CallOpts, _facet) +} + +// FacetFunctionSelectors is a free data retrieval call binding the contract method 0xadfca15e. +// +// Solidity: function facetFunctionSelectors(address _facet) view returns(bytes4[] facetFunctionSelectors_) +func (_DiamondLoupeFacet *DiamondLoupeFacetCallerSession) FacetFunctionSelectors(_facet common.Address) ([][4]byte, error) { + return _DiamondLoupeFacet.Contract.FacetFunctionSelectors(&_DiamondLoupeFacet.CallOpts, _facet) +} + +// Facets is a free data retrieval call binding the contract method 0x7a0ed627. +// +// Solidity: function facets() view returns((address,bytes4[])[] facets_) +func (_DiamondLoupeFacet *DiamondLoupeFacetCaller) Facets(opts *bind.CallOpts) ([]IDiamondLoupeFacet, error) { + var out []interface{} + err := _DiamondLoupeFacet.contract.Call(opts, &out, "facets") + + if err != nil { + return *new([]IDiamondLoupeFacet), err + } + + out0 := *abi.ConvertType(out[0], new([]IDiamondLoupeFacet)).(*[]IDiamondLoupeFacet) + + return out0, err + +} + +// Facets is a free data retrieval call binding the contract method 0x7a0ed627. +// +// Solidity: function facets() view returns((address,bytes4[])[] facets_) +func (_DiamondLoupeFacet *DiamondLoupeFacetSession) Facets() ([]IDiamondLoupeFacet, error) { + return _DiamondLoupeFacet.Contract.Facets(&_DiamondLoupeFacet.CallOpts) +} + +// Facets is a free data retrieval call binding the contract method 0x7a0ed627. +// +// Solidity: function facets() view returns((address,bytes4[])[] facets_) +func (_DiamondLoupeFacet *DiamondLoupeFacetCallerSession) Facets() ([]IDiamondLoupeFacet, error) { + return _DiamondLoupeFacet.Contract.Facets(&_DiamondLoupeFacet.CallOpts) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 _interfaceId) view returns(bool) +func (_DiamondLoupeFacet *DiamondLoupeFacetCaller) SupportsInterface(opts *bind.CallOpts, _interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _DiamondLoupeFacet.contract.Call(opts, &out, "supportsInterface", _interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 _interfaceId) view returns(bool) +func (_DiamondLoupeFacet *DiamondLoupeFacetSession) SupportsInterface(_interfaceId [4]byte) (bool, error) { + return _DiamondLoupeFacet.Contract.SupportsInterface(&_DiamondLoupeFacet.CallOpts, _interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 _interfaceId) view returns(bool) +func (_DiamondLoupeFacet *DiamondLoupeFacetCallerSession) SupportsInterface(_interfaceId [4]byte) (bool, error) { + return _DiamondLoupeFacet.Contract.SupportsInterface(&_DiamondLoupeFacet.CallOpts, _interfaceId) +} + +func CreateDiamondLoupeFacetDeploymentCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc string + var gasLimit uint64 + var simulate bool + var timeout uint + var safeAddress, safeApi, safeCreateCall, safeSaltRaw, safeNonceRaw string + var safeOperationType uint8 + var salt [32]byte + var predictAddress bool + var safeNonce *big.Int + + cmd := &cobra.Command{ + Use: "deploy", + Short: "Deploy a new DiamondLoupeFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if safeCreateCall == "" { + fmt.Println("--safe-create-call not specified, using default (0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4)") + safeCreateCall = "0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4" + } + if !common.IsHexAddress(safeCreateCall) { + return fmt.Errorf("--safe-create-call is not a valid Ethereum address") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeSaltRaw == "" { + fmt.Println("--safe-salt not specified, generating random salt") + _, err := rand.Read(salt[:]) + if err != nil { + return fmt.Errorf("failed to generate random salt: %v", err) + } + // prompt user to accept random salt + fmt.Println("Generated salt:", common.Bytes2Hex(salt[:])) + fmt.Println("Please check the salt and confirm (y/n)") + var confirm string + fmt.Scanln(&confirm) + if confirm != "y" && confirm != "Y" && confirm != "\n" && confirm != "" { + return fmt.Errorf("salt not accepted, please specify a valid salt") + } + } else { + copy(salt[:], safeSaltRaw) + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + if safeAddress != "" { + // Generate deploy bytecode with constructor arguments + deployBytecode, err := generateDiamondLoupeFacetDeployBytecode() + if err != nil { + return fmt.Errorf("failed to generate deploy bytecode: %v", err) + } + + // Create Safe proposal for deployment + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + if predictAddress { + fmt.Println("Predicting deployment address...") + from := common.HexToAddress(safeAddress) + if safeOperationType == 0 { + from = common.HexToAddress(safeCreateCall) + } + deploymentAddress, err := PredictDeploymentAddressSafe(from, salt, deployBytecode) + if err != nil { + return fmt.Errorf("failed to predict deployment address: %v", err) + } + fmt.Println("Predicted deployment address:", deploymentAddress.Hex()) + return nil + } else { + fmt.Println("Creating Safe proposal...") + err = DeployWithSafe(client, key, common.HexToAddress(safeAddress), common.HexToAddress(safeCreateCall), value, safeApi, deployBytecode, SafeOperationType(safeOperationType), salt, safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + } + + return nil + } + + address, deploymentTransaction, _, deploymentErr := DeployDiamondLoupeFacet( + transactionOpts, + client, + ) + if deploymentErr != nil { + return deploymentErr + } + + cmd.Printf("Transaction hash: %s\nContract address: %s\n", deploymentTransaction.Hash().Hex(), address.Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + Data: deploymentTransaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := deploymentTransaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().StringVar(&safeCreateCall, "safe-create-call", "", "Address of the CreateCall contract (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 1, "Safe operation type: 0 (Call) or 1 (DelegateCall) - default is 1") + cmd.Flags().StringVar(&safeSaltRaw, "safe-salt", "", "Salt to use for the Safe transaction") + cmd.Flags().BoolVar(&predictAddress, "safe-predict-address", false, "Predict the deployment address (only works for Safe transactions)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + return cmd +} + +func generateDiamondLoupeFacetDeployBytecode() ([]byte, error) { + abiPacked, err := DiamondLoupeFacetMetaData.GetAbi() + if err != nil { + return nil, fmt.Errorf("failed to get ABI: %v", err) + } + + constructorArguments, err := abiPacked.Pack("") + if err != nil { + return nil, fmt.Errorf("failed to pack constructor arguments: %v", err) + } + + deployBytecode := append(common.FromHex(DiamondLoupeFacetMetaData.Bin), constructorArguments...) + return deployBytecode, nil +} + +func CreateFacetAddressCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var functionSelector [4]byte + var functionSelectorRaw string + + var capture0 common.Address + + cmd := &cobra.Command{ + Use: "facet-address", + Short: "Call the FacetAddress view method on a DiamondLoupeFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + var functionSelectorIntermediate []byte + + var functionSelectorIntermediateHexDecodeErr error + functionSelectorIntermediate, functionSelectorIntermediateHexDecodeErr = hex.DecodeString(functionSelectorRaw) + if functionSelectorIntermediateHexDecodeErr != nil { + return functionSelectorIntermediateHexDecodeErr + } + + copy(functionSelector[:], functionSelectorIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewDiamondLoupeFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := DiamondLoupeFacetCallerSession{ + Contract: &contract.DiamondLoupeFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.FacetAddress( + functionSelector, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.Hex()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&functionSelectorRaw, "function-selector", "", "function-selector argument ([4]byte)") + + return cmd +} +func CreateFacetAddressesCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var capture0 []common.Address + + cmd := &cobra.Command{ + Use: "facet-addresses", + Short: "Call the FacetAddresses view method on a DiamondLoupeFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewDiamondLoupeFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := DiamondLoupeFacetCallerSession{ + Contract: &contract.DiamondLoupeFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.FacetAddresses() + if callErr != nil { + return callErr + } + + cmd.Printf("0: %v\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + return cmd +} +func CreateFacetFunctionSelectorsCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var facet common.Address + var facetRaw string + + var capture0 [][4]byte + + cmd := &cobra.Command{ + Use: "facet-function-selectors", + Short: "Call the FacetFunctionSelectors view method on a DiamondLoupeFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if facetRaw == "" { + return fmt.Errorf("--facet argument not specified") + } else if !common.IsHexAddress(facetRaw) { + return fmt.Errorf("--facet argument is not a valid Ethereum address") + } + facet = common.HexToAddress(facetRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewDiamondLoupeFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := DiamondLoupeFacetCallerSession{ + Contract: &contract.DiamondLoupeFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.FacetFunctionSelectors( + facet, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %v\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&facetRaw, "facet", "", "facet argument (common.Address)") + + return cmd +} +func CreateFacetsCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var capture0 []IDiamondLoupeFacet + + cmd := &cobra.Command{ + Use: "facets", + Short: "Call the Facets view method on a DiamondLoupeFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewDiamondLoupeFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := DiamondLoupeFacetCallerSession{ + Contract: &contract.DiamondLoupeFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.Facets() + if callErr != nil { + return callErr + } + + cmd.Printf("0: %v\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + return cmd +} +func CreateSupportsInterfaceCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var interfaceId [4]byte + var interfaceIdRaw string + + var capture0 bool + + cmd := &cobra.Command{ + Use: "supports-interface", + Short: "Call the SupportsInterface view method on a DiamondLoupeFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + var interfaceIdIntermediate []byte + + var interfaceIdIntermediateHexDecodeErr error + interfaceIdIntermediate, interfaceIdIntermediateHexDecodeErr = hex.DecodeString(interfaceIdRaw) + if interfaceIdIntermediateHexDecodeErr != nil { + return interfaceIdIntermediateHexDecodeErr + } + + copy(interfaceId[:], interfaceIdIntermediate) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewDiamondLoupeFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := DiamondLoupeFacetCallerSession{ + Contract: &contract.DiamondLoupeFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.SupportsInterface( + interfaceId, + ) + if callErr != nil { + return callErr + } + + cmd.Printf("0: %t\n", capture0) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + cmd.Flags().StringVar(&interfaceIdRaw, "interface-id", "", "interface-id argument ([4]byte)") + + return cmd +} + +var ErrNoRPCURL error = errors.New("no RPC URL provided -- please pass an RPC URL from the command line or set the DIAMOND_LOUPE_FACET_RPC_URL environment variable") + +// Generates an Ethereum client to the JSONRPC API at the given URL. If rpcURL is empty, then it +// attempts to read the RPC URL from the DIAMOND_LOUPE_FACET_RPC_URL environment variable. If that is empty, +// too, then it returns an error. +func NewClient(rpcURL string) (*ethclient.Client, error) { + if rpcURL == "" { + rpcURL = os.Getenv("DIAMOND_LOUPE_FACET_RPC_URL") + } + + if rpcURL == "" { + return nil, ErrNoRPCURL + } + + client, err := ethclient.Dial(rpcURL) + return client, err +} + +// Creates a new context to be used when interacting with the chain client. +func NewChainContext(timeout uint) (context.Context, context.CancelFunc) { + baseCtx := context.Background() + parsedTimeout := time.Duration(timeout) * time.Second + ctx, cancel := context.WithTimeout(baseCtx, parsedTimeout) + return ctx, cancel +} + +// Unlocks a key from a keystore (byte contents of a keystore file) with the given password. +func UnlockKeystore(keystoreData []byte, password string) (*keystore.Key, error) { + key, err := keystore.DecryptKey(keystoreData, password) + return key, err +} + +// Loads a key from file, prompting the user for the password if it is not provided as a function argument. +func KeyFromFile(keystoreFile string, password string) (*keystore.Key, error) { + var emptyKey *keystore.Key + keystoreContent, readErr := os.ReadFile(keystoreFile) + if readErr != nil { + return emptyKey, readErr + } + + // If password is "", prompt user for password. + if password == "" { + fmt.Printf("Please provide a password for keystore (%s): ", keystoreFile) + passwordRaw, inputErr := term.ReadPassword(int(os.Stdin.Fd())) + if inputErr != nil { + return emptyKey, fmt.Errorf("error reading password: %s", inputErr.Error()) + } + fmt.Print("\n") + password = string(passwordRaw) + } + + key, err := UnlockKeystore(keystoreContent, password) + return key, err +} + +// This method is used to set the parameters on a view call from command line arguments (represented mostly as +// strings). +func SetCallParametersFromArgs(opts *bind.CallOpts, pending bool, fromAddress, blockNumber string) { + if pending { + opts.Pending = true + } + + if fromAddress != "" { + opts.From = common.HexToAddress(fromAddress) + } + + if blockNumber != "" { + opts.BlockNumber = new(big.Int) + opts.BlockNumber.SetString(blockNumber, 0) + } +} + +// This method is used to set the parameters on a transaction from command line arguments (represented mostly as +// strings). +func SetTransactionParametersFromArgs(opts *bind.TransactOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas string, gasLimit uint64, noSend bool) { + if nonce != "" { + opts.Nonce = new(big.Int) + opts.Nonce.SetString(nonce, 0) + } + + if value != "" { + opts.Value = new(big.Int) + opts.Value.SetString(value, 0) + } + + if gasPrice != "" { + opts.GasPrice = new(big.Int) + opts.GasPrice.SetString(gasPrice, 0) + } + + if maxFeePerGas != "" { + opts.GasFeeCap = new(big.Int) + opts.GasFeeCap.SetString(maxFeePerGas, 0) + } + + if maxPriorityFeePerGas != "" { + opts.GasTipCap = new(big.Int) + opts.GasTipCap.SetString(maxPriorityFeePerGas, 0) + } + + if gasLimit != 0 { + opts.GasLimit = gasLimit + } + + opts.NoSend = noSend +} + +func CreateDiamondLoupeFacetCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "diamond-loupe-facet", + Short: "Interact with the DiamondLoupeFacet contract", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + + cmd.SetOut(os.Stdout) + + DeployGroup := &cobra.Group{ + ID: "deploy", Title: "Commands which deploy contracts", + } + cmd.AddGroup(DeployGroup) + ViewGroup := &cobra.Group{ + ID: "view", Title: "Commands which view contract state", + } + TransactGroup := &cobra.Group{ + ID: "transact", Title: "Commands which submit transactions", + } + cmd.AddGroup(ViewGroup, TransactGroup) + + cmdDeployDiamondLoupeFacet := CreateDiamondLoupeFacetDeploymentCommand() + cmdDeployDiamondLoupeFacet.GroupID = DeployGroup.ID + cmd.AddCommand(cmdDeployDiamondLoupeFacet) + + cmdViewFacetAddress := CreateFacetAddressCommand() + cmdViewFacetAddress.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewFacetAddress) + cmdViewFacetAddresses := CreateFacetAddressesCommand() + cmdViewFacetAddresses.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewFacetAddresses) + cmdViewFacetFunctionSelectors := CreateFacetFunctionSelectorsCommand() + cmdViewFacetFunctionSelectors.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewFacetFunctionSelectors) + cmdViewFacets := CreateFacetsCommand() + cmdViewFacets.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewFacets) + cmdViewSupportsInterface := CreateSupportsInterfaceCommand() + cmdViewSupportsInterface.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewSupportsInterface) + + return cmd +} + +// SafeOperationType represents the type of operation for a Safe transaction +type SafeOperationType uint8 + +const ( + Call SafeOperationType = 0 + DelegateCall SafeOperationType = 1 +) + +// String returns the string representation of the SafeOperationType +func (o SafeOperationType) String() string { + switch o { + case Call: + return "Call" + case DelegateCall: + return "DelegateCall" + default: + return "Unknown" + } +} + +// SafeTransactionData represents the data for a Safe transaction +type SafeTransactionData struct { + To string `json:"to"` + Value string `json:"value"` + Data string `json:"data"` + Operation SafeOperationType `json:"operation"` + SafeTxGas uint64 `json:"safeTxGas"` + BaseGas uint64 `json:"baseGas"` + GasPrice string `json:"gasPrice"` + GasToken string `json:"gasToken"` + RefundReceiver string `json:"refundReceiver"` + Nonce *big.Int `json:"nonce"` + SafeTxHash string `json:"safeTxHash"` + Sender string `json:"sender"` + Signature string `json:"signature"` + Origin string `json:"origin"` +} + +const ( + NativeTokenAddress = "0x0000000000000000000000000000000000000000" +) + +func DeployWithSafe(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, factoryAddress common.Address, value *big.Int, safeApi string, deployBytecode []byte, safeOperationType SafeOperationType, salt [32]byte, safeNonce *big.Int) error { + abi, err := CreateCall.CreateCallMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + safeCreateCallTxData, err := abi.Pack("performCreate2", value, deployBytecode, salt) + if err != nil { + return fmt.Errorf("failed to pack performCreate2 transaction: %v", err) + } + + return CreateSafeProposal(client, key, safeAddress, factoryAddress, safeCreateCallTxData, value, safeApi, SafeOperationType(safeOperationType), safeNonce) +} + +func PredictDeploymentAddressSafe(from common.Address, salt [32]byte, deployBytecode []byte) (common.Address, error) { + // Calculate the hash of the init code (deployment bytecode) + initCodeHash := crypto.Keccak256(deployBytecode) + + // Calculate the CREATE2 address + deployedAddress := crypto.CreateAddress2(from, salt, initCodeHash) + + return deployedAddress, nil +} + +func CreateSafeProposal(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, to common.Address, data []byte, value *big.Int, safeApi string, safeOperationType SafeOperationType, safeNonce *big.Int) error { + chainID, err := client.ChainID(context.Background()) + if err != nil { + return fmt.Errorf("failed to get chain ID: %v", err) + } + + // Create a new instance of the GnosisSafe contract + safeInstance, err := GnosisSafe.NewGnosisSafe(safeAddress, client) + if err != nil { + return fmt.Errorf("failed to create GnosisSafe instance: %v", err) + } + + nonce := safeNonce + if safeNonce == nil { + // Fetch the current nonce from the Safe contract + fetchedNonce, err := safeInstance.Nonce(&bind.CallOpts{}) + if err != nil { + return fmt.Errorf("failed to fetch nonce from Safe contract: %v", err) + } + nonce = fetchedNonce + } else { + nonce = safeNonce + } + + safeTransactionData := SafeTransactionData{ + To: to.Hex(), + Value: value.String(), + Data: common.Bytes2Hex(data), + Operation: safeOperationType, + SafeTxGas: 0, + BaseGas: 0, + GasPrice: "0", + GasToken: NativeTokenAddress, + RefundReceiver: NativeTokenAddress, + Nonce: nonce, + } + + // Calculate SafeTxHash + safeTxHash, err := CalculateSafeTxHash(safeAddress, safeTransactionData, chainID) + if err != nil { + return fmt.Errorf("failed to calculate SafeTxHash: %v", err) + } + + // Sign the SafeTxHash + signature, err := crypto.Sign(safeTxHash.Bytes(), key.PrivateKey) + if err != nil { + return fmt.Errorf("failed to sign SafeTxHash: %v", err) + } + + // Adjust V value for Ethereum's replay protection + signature[64] += 27 + + // Convert signature to hex + senderSignature := "0x" + common.Bytes2Hex(signature) + + // Prepare the request body + requestBody := map[string]interface{}{ + "to": safeTransactionData.To, + "value": safeTransactionData.Value, + "data": "0x" + safeTransactionData.Data, + "operation": int(safeTransactionData.Operation), + "safeTxGas": fmt.Sprintf("%d", safeTransactionData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", safeTransactionData.BaseGas), + "gasPrice": safeTransactionData.GasPrice, + "gasToken": safeTransactionData.GasToken, + "refundReceiver": safeTransactionData.RefundReceiver, + "nonce": fmt.Sprintf("%d", safeTransactionData.Nonce), + "safeTxHash": safeTxHash.Hex(), + "sender": key.Address.Hex(), + "signature": senderSignature, + "origin": fmt.Sprintf("{\"url\":\"%s\",\"name\":\"TokenSender Deployment\"}", safeApi), + } + + // Marshal the request body to JSON + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("failed to marshal request body: %v", err) + } + + // Send the request to the Safe Transaction Service + req, err := http.NewRequest("POST", safeApi, bytes.NewBuffer(jsonBody)) + if err != nil { + return fmt.Errorf("failed to create request: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + fmt.Println("Safe proposal created successfully") + return nil +} + +func CalculateSafeTxHash(safeAddress common.Address, txData SafeTransactionData, chainID *big.Int) (common.Hash, error) { + domainSeparator := apitypes.TypedDataDomain{ + ChainId: (*math.HexOrDecimal256)(chainID), + VerifyingContract: safeAddress.Hex(), + } + + typedData := apitypes.TypedData{ + Types: apitypes.Types{ + "EIP712Domain": []apitypes.Type{ + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "SafeTx": []apitypes.Type{ + {Name: "to", Type: "address"}, + {Name: "value", Type: "uint256"}, + {Name: "data", Type: "bytes"}, + {Name: "operation", Type: "uint8"}, + {Name: "safeTxGas", Type: "uint256"}, + {Name: "baseGas", Type: "uint256"}, + {Name: "gasPrice", Type: "uint256"}, + {Name: "gasToken", Type: "address"}, + {Name: "refundReceiver", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + }, + }, + Domain: domainSeparator, + PrimaryType: "SafeTx", + Message: apitypes.TypedDataMessage{ + "to": txData.To, + "value": txData.Value, + "data": "0x" + txData.Data, + "operation": fmt.Sprintf("%d", txData.Operation), + "safeTxGas": fmt.Sprintf("%d", txData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", txData.BaseGas), + "gasPrice": txData.GasPrice, + "gasToken": txData.GasToken, + "refundReceiver": txData.RefundReceiver, + "nonce": fmt.Sprintf("%d", txData.Nonce), + }, + } + + typedDataHash, _, err := apitypes.TypedDataAndHash(typedData) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to hash typed data: %v", err) + } + + return common.BytesToHash(typedDataHash), nil +} diff --git a/bindings/utils/diamonds/OwnershipFacet/OwnershipFacet.go b/bindings/utils/diamonds/OwnershipFacet/OwnershipFacet.go new file mode 100644 index 00000000..b94fb90e --- /dev/null +++ b/bindings/utils/diamonds/OwnershipFacet/OwnershipFacet.go @@ -0,0 +1,1440 @@ +// This file was generated by seer: https://github.com/G7DAO/seer. +// seer version: 0.3.5 +// seer command: seer evm generate --package OwnershipFacet --cli --struct OwnershipFacet --output bindings/utils/diamonds/OwnershipFacet/OwnershipFacet.go +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package OwnershipFacet + +import ( + "bytes" + "crypto/rand" + "errors" + "math/big" + "net/http" + "strings" + + "context" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + + // Reference imports to suppress errors if they are not otherwise used. + "encoding/hex" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/G7DAO/seer/bindings/CreateCall" + "github.com/G7DAO/seer/bindings/GnosisSafe" + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" + "golang.org/x/term" + + // OwnershipFacetMetaData contains all meta data concerning the OwnershipFacet contract. + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var OwnershipFacetMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"owner_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b506102d6806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80638da5cb5b1461003b578063f2fde38b1461006c575b600080fd5b610043610081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61007f61007a366004610263565b6100c6565b005b60006100c17fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c13205473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b6100ce6100da565b6100d7816101a9565b50565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c6004015473ffffffffffffffffffffffffffffffffffffffff1633146101a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201527f6572000000000000000000000000000000000000000000000000000000000000606482015260840160405180910390fd5b565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c132080547fffffffffffffffffffffffff0000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff8481169182179093556040517fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c939092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b60006020828403121561027557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461029957600080fd5b939250505056fea26469706673582212201d113009651e13be03a689969cebf47f0157c540f3e46bcf5f2492156d131dfe64736f6c63430008180033", +} + +// OwnershipFacetABI is the input ABI used to generate the binding from. +// Deprecated: Use OwnershipFacetMetaData.ABI instead. +var OwnershipFacetABI = OwnershipFacetMetaData.ABI + +// OwnershipFacetBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use OwnershipFacetMetaData.Bin instead. +var OwnershipFacetBin = OwnershipFacetMetaData.Bin + +// DeployOwnershipFacet deploys a new Ethereum contract, binding an instance of OwnershipFacet to it. +func DeployOwnershipFacet(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *OwnershipFacet, error) { + parsed, err := OwnershipFacetMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(OwnershipFacetBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &OwnershipFacet{OwnershipFacetCaller: OwnershipFacetCaller{contract: contract}, OwnershipFacetTransactor: OwnershipFacetTransactor{contract: contract}, OwnershipFacetFilterer: OwnershipFacetFilterer{contract: contract}}, nil +} + +// OwnershipFacet is an auto generated Go binding around an Ethereum contract. +type OwnershipFacet struct { + OwnershipFacetCaller // Read-only binding to the contract + OwnershipFacetTransactor // Write-only binding to the contract + OwnershipFacetFilterer // Log filterer for contract events +} + +// OwnershipFacetCaller is an auto generated read-only Go binding around an Ethereum contract. +type OwnershipFacetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OwnershipFacetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type OwnershipFacetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OwnershipFacetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type OwnershipFacetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// OwnershipFacetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type OwnershipFacetSession struct { + Contract *OwnershipFacet // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// OwnershipFacetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type OwnershipFacetCallerSession struct { + Contract *OwnershipFacetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// OwnershipFacetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type OwnershipFacetTransactorSession struct { + Contract *OwnershipFacetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// OwnershipFacetRaw is an auto generated low-level Go binding around an Ethereum contract. +type OwnershipFacetRaw struct { + Contract *OwnershipFacet // Generic contract binding to access the raw methods on +} + +// OwnershipFacetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type OwnershipFacetCallerRaw struct { + Contract *OwnershipFacetCaller // Generic read-only contract binding to access the raw methods on +} + +// OwnershipFacetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type OwnershipFacetTransactorRaw struct { + Contract *OwnershipFacetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewOwnershipFacet creates a new instance of OwnershipFacet, bound to a specific deployed contract. +func NewOwnershipFacet(address common.Address, backend bind.ContractBackend) (*OwnershipFacet, error) { + contract, err := bindOwnershipFacet(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &OwnershipFacet{OwnershipFacetCaller: OwnershipFacetCaller{contract: contract}, OwnershipFacetTransactor: OwnershipFacetTransactor{contract: contract}, OwnershipFacetFilterer: OwnershipFacetFilterer{contract: contract}}, nil +} + +// NewOwnershipFacetCaller creates a new read-only instance of OwnershipFacet, bound to a specific deployed contract. +func NewOwnershipFacetCaller(address common.Address, caller bind.ContractCaller) (*OwnershipFacetCaller, error) { + contract, err := bindOwnershipFacet(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &OwnershipFacetCaller{contract: contract}, nil +} + +// NewOwnershipFacetTransactor creates a new write-only instance of OwnershipFacet, bound to a specific deployed contract. +func NewOwnershipFacetTransactor(address common.Address, transactor bind.ContractTransactor) (*OwnershipFacetTransactor, error) { + contract, err := bindOwnershipFacet(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &OwnershipFacetTransactor{contract: contract}, nil +} + +// NewOwnershipFacetFilterer creates a new log filterer instance of OwnershipFacet, bound to a specific deployed contract. +func NewOwnershipFacetFilterer(address common.Address, filterer bind.ContractFilterer) (*OwnershipFacetFilterer, error) { + contract, err := bindOwnershipFacet(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &OwnershipFacetFilterer{contract: contract}, nil +} + +// bindOwnershipFacet binds a generic wrapper to an already deployed contract. +func bindOwnershipFacet(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := OwnershipFacetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_OwnershipFacet *OwnershipFacetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _OwnershipFacet.Contract.OwnershipFacetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_OwnershipFacet *OwnershipFacetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _OwnershipFacet.Contract.OwnershipFacetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_OwnershipFacet *OwnershipFacetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _OwnershipFacet.Contract.OwnershipFacetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_OwnershipFacet *OwnershipFacetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _OwnershipFacet.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_OwnershipFacet *OwnershipFacetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _OwnershipFacet.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_OwnershipFacet *OwnershipFacetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _OwnershipFacet.Contract.contract.Transact(opts, method, params...) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address owner_) +func (_OwnershipFacet *OwnershipFacetCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _OwnershipFacet.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address owner_) +func (_OwnershipFacet *OwnershipFacetSession) Owner() (common.Address, error) { + return _OwnershipFacet.Contract.Owner(&_OwnershipFacet.CallOpts) +} + +// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. +// +// Solidity: function owner() view returns(address owner_) +func (_OwnershipFacet *OwnershipFacetCallerSession) Owner() (common.Address, error) { + return _OwnershipFacet.Contract.Owner(&_OwnershipFacet.CallOpts) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address _newOwner) returns() +func (_OwnershipFacet *OwnershipFacetTransactor) TransferOwnership(opts *bind.TransactOpts, _newOwner common.Address) (*types.Transaction, error) { + return _OwnershipFacet.contract.Transact(opts, "transferOwnership", _newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address _newOwner) returns() +func (_OwnershipFacet *OwnershipFacetSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { + return _OwnershipFacet.Contract.TransferOwnership(&_OwnershipFacet.TransactOpts, _newOwner) +} + +// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. +// +// Solidity: function transferOwnership(address _newOwner) returns() +func (_OwnershipFacet *OwnershipFacetTransactorSession) TransferOwnership(_newOwner common.Address) (*types.Transaction, error) { + return _OwnershipFacet.Contract.TransferOwnership(&_OwnershipFacet.TransactOpts, _newOwner) +} + +// OwnershipFacetOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the OwnershipFacet contract. +type OwnershipFacetOwnershipTransferredIterator struct { + Event *OwnershipFacetOwnershipTransferred // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OwnershipFacetOwnershipTransferredIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OwnershipFacetOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OwnershipFacetOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OwnershipFacetOwnershipTransferredIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OwnershipFacetOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OwnershipFacetOwnershipTransferred represents a OwnershipTransferred event raised by the OwnershipFacet contract. +type OwnershipFacetOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_OwnershipFacet *OwnershipFacetFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*OwnershipFacetOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _OwnershipFacet.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &OwnershipFacetOwnershipTransferredIterator{contract: _OwnershipFacet.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_OwnershipFacet *OwnershipFacetFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *OwnershipFacetOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _OwnershipFacet.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OwnershipFacetOwnershipTransferred) + if err := _OwnershipFacet.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_OwnershipFacet *OwnershipFacetFilterer) ParseOwnershipTransferred(log types.Log) (*OwnershipFacetOwnershipTransferred, error) { + event := new(OwnershipFacetOwnershipTransferred) + if err := _OwnershipFacet.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// OwnershipFacetOwnershipTransferred0Iterator is returned from FilterOwnershipTransferred0 and is used to iterate over the raw logs and unpacked data for OwnershipTransferred0 events raised by the OwnershipFacet contract. +type OwnershipFacetOwnershipTransferred0Iterator struct { + Event *OwnershipFacetOwnershipTransferred0 // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *OwnershipFacetOwnershipTransferred0Iterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(OwnershipFacetOwnershipTransferred0) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(OwnershipFacetOwnershipTransferred0) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *OwnershipFacetOwnershipTransferred0Iterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *OwnershipFacetOwnershipTransferred0Iterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// OwnershipFacetOwnershipTransferred0 represents a OwnershipTransferred0 event raised by the OwnershipFacet contract. +type OwnershipFacetOwnershipTransferred0 struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterOwnershipTransferred0 is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_OwnershipFacet *OwnershipFacetFilterer) FilterOwnershipTransferred0(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*OwnershipFacetOwnershipTransferred0Iterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _OwnershipFacet.contract.FilterLogs(opts, "OwnershipTransferred0", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &OwnershipFacetOwnershipTransferred0Iterator{contract: _OwnershipFacet.contract, event: "OwnershipTransferred0", logs: logs, sub: sub}, nil +} + +// WatchOwnershipTransferred0 is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_OwnershipFacet *OwnershipFacetFilterer) WatchOwnershipTransferred0(opts *bind.WatchOpts, sink chan<- *OwnershipFacetOwnershipTransferred0, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _OwnershipFacet.contract.WatchLogs(opts, "OwnershipTransferred0", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(OwnershipFacetOwnershipTransferred0) + if err := _OwnershipFacet.contract.UnpackLog(event, "OwnershipTransferred0", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseOwnershipTransferred0 is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. +// +// Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) +func (_OwnershipFacet *OwnershipFacetFilterer) ParseOwnershipTransferred0(log types.Log) (*OwnershipFacetOwnershipTransferred0, error) { + event := new(OwnershipFacetOwnershipTransferred0) + if err := _OwnershipFacet.contract.UnpackLog(event, "OwnershipTransferred0", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func CreateOwnershipFacetDeploymentCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc string + var gasLimit uint64 + var simulate bool + var timeout uint + var safeAddress, safeApi, safeCreateCall, safeSaltRaw, safeNonceRaw string + var safeOperationType uint8 + var salt [32]byte + var predictAddress bool + var safeNonce *big.Int + + cmd := &cobra.Command{ + Use: "deploy", + Short: "Deploy a new OwnershipFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if safeCreateCall == "" { + fmt.Println("--safe-create-call not specified, using default (0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4)") + safeCreateCall = "0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4" + } + if !common.IsHexAddress(safeCreateCall) { + return fmt.Errorf("--safe-create-call is not a valid Ethereum address") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeSaltRaw == "" { + fmt.Println("--safe-salt not specified, generating random salt") + _, err := rand.Read(salt[:]) + if err != nil { + return fmt.Errorf("failed to generate random salt: %v", err) + } + // prompt user to accept random salt + fmt.Println("Generated salt:", common.Bytes2Hex(salt[:])) + fmt.Println("Please check the salt and confirm (y/n)") + var confirm string + fmt.Scanln(&confirm) + if confirm != "y" && confirm != "Y" && confirm != "\n" && confirm != "" { + return fmt.Errorf("salt not accepted, please specify a valid salt") + } + } else { + copy(salt[:], safeSaltRaw) + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + if safeAddress != "" { + // Generate deploy bytecode with constructor arguments + deployBytecode, err := generateOwnershipFacetDeployBytecode() + if err != nil { + return fmt.Errorf("failed to generate deploy bytecode: %v", err) + } + + // Create Safe proposal for deployment + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + if predictAddress { + fmt.Println("Predicting deployment address...") + from := common.HexToAddress(safeAddress) + if safeOperationType == 0 { + from = common.HexToAddress(safeCreateCall) + } + deploymentAddress, err := PredictDeploymentAddressSafe(from, salt, deployBytecode) + if err != nil { + return fmt.Errorf("failed to predict deployment address: %v", err) + } + fmt.Println("Predicted deployment address:", deploymentAddress.Hex()) + return nil + } else { + fmt.Println("Creating Safe proposal...") + err = DeployWithSafe(client, key, common.HexToAddress(safeAddress), common.HexToAddress(safeCreateCall), value, safeApi, deployBytecode, SafeOperationType(safeOperationType), salt, safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + } + + return nil + } + + address, deploymentTransaction, _, deploymentErr := DeployOwnershipFacet( + transactionOpts, + client, + ) + if deploymentErr != nil { + return deploymentErr + } + + cmd.Printf("Transaction hash: %s\nContract address: %s\n", deploymentTransaction.Hash().Hex(), address.Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + Data: deploymentTransaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := deploymentTransaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().StringVar(&safeCreateCall, "safe-create-call", "", "Address of the CreateCall contract (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 1, "Safe operation type: 0 (Call) or 1 (DelegateCall) - default is 1") + cmd.Flags().StringVar(&safeSaltRaw, "safe-salt", "", "Salt to use for the Safe transaction") + cmd.Flags().BoolVar(&predictAddress, "safe-predict-address", false, "Predict the deployment address (only works for Safe transactions)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + return cmd +} + +func generateOwnershipFacetDeployBytecode() ([]byte, error) { + abiPacked, err := OwnershipFacetMetaData.GetAbi() + if err != nil { + return nil, fmt.Errorf("failed to get ABI: %v", err) + } + + constructorArguments, err := abiPacked.Pack("") + if err != nil { + return nil, fmt.Errorf("failed to pack constructor arguments: %v", err) + } + + deployBytecode := append(common.FromHex(OwnershipFacetMetaData.Bin), constructorArguments...) + return deployBytecode, nil +} + +func CreateOwnerCommand() *cobra.Command { + var contractAddressRaw, rpc string + var contractAddress common.Address + var timeout uint + + var blockNumberRaw, fromAddressRaw string + var pending bool + + var capture0 common.Address + + cmd := &cobra.Command{ + Use: "owner", + Short: "Call the Owner view method on a OwnershipFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + contract, contractErr := NewOwnershipFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + callOpts := bind.CallOpts{} + SetCallParametersFromArgs(&callOpts, pending, fromAddressRaw, blockNumberRaw) + + session := OwnershipFacetCallerSession{ + Contract: &contract.OwnershipFacetCaller, + CallOpts: callOpts, + } + + var callErr error + capture0, callErr = session.Owner() + if callErr != nil { + return callErr + } + + cmd.Printf("0: %s\n", capture0.Hex()) + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&blockNumberRaw, "block", "", "Block number at which to call the view method") + cmd.Flags().BoolVar(&pending, "pending", false, "Set this flag if it's ok to call the view method against pending state") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&fromAddressRaw, "from", "", "Optional address for caller of the view method") + + return cmd +} + +func CreateTransferOwnershipCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, contractAddressRaw, safeFunction, safeNonceRaw string + var gasLimit uint64 + var simulate bool + var timeout uint + var contractAddress common.Address + var safeAddress, safeApi string + var safeOperationType uint8 + var safeNonce *big.Int + + var newOwner common.Address + var newOwnerRaw string + + cmd := &cobra.Command{ + Use: "transfer-ownership", + Short: "Execute the TransferOwnership method on a OwnershipFacet contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if contractAddressRaw == "" { + return fmt.Errorf("--contract not specified") + } else if !common.IsHexAddress(contractAddressRaw) { + return fmt.Errorf("--contract is not a valid Ethereum address") + } + contractAddress = common.HexToAddress(contractAddressRaw) + + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if rpc == "" { + return fmt.Errorf("--rpc not specified (this should be a URL to an Ethereum JSONRPC API)") + } + + if safeAddress != "" { + if !common.IsHexAddress(safeAddress) { + return fmt.Errorf("--safe is not a valid Ethereum address") + } + if safeApi == "" { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + safeApi = fmt.Sprintf("https://safe-client.safe.global/v1/chains/%s/transactions/%s/propose", chainID.String(), safeAddress) + fmt.Println("--safe-api not specified, using default (", safeApi, ")") + } + + if SafeOperationType(safeOperationType).String() == "Unknown" { + return fmt.Errorf("--safe-operation must be 0 (Call) or 1 (DelegateCall)") + } + + if safeNonceRaw == "" { + fmt.Println("--safe-nonce not specified, fetching nonce from Safe contract") + } else { + safeNonce = new(big.Int) + _, ok := safeNonce.SetString(safeNonceRaw, 0) + if !ok { + return fmt.Errorf("--safe-nonce is not a valid big integer") + } + } + } + + if newOwnerRaw == "" { + return fmt.Errorf("--new-owner argument not specified") + } else if !common.IsHexAddress(newOwnerRaw) { + return fmt.Errorf("--new-owner argument is not a valid Ethereum address") + } + newOwner = common.HexToAddress(newOwnerRaw) + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + contract, contractErr := NewOwnershipFacet(contractAddress, client) + if contractErr != nil { + return contractErr + } + + session := OwnershipFacetTransactorSession{ + Contract: &contract.OwnershipFacetTransactor, + TransactOpts: *transactionOpts, + } + + if safeAddress != "" { + abi, err := OwnershipFacetMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + // Generate transaction data (override method name if safe function is specified) + methodName := "transferOwnership" + if safeFunction != "" { + methodName = safeFunction + } + + transaction, err := abi.Pack( + methodName, + newOwner, + ) + + if err != nil { + return err + } + + // Create Safe proposal for transaction + value := transactionOpts.Value + if value == nil { + value = big.NewInt(0) + } + + err = CreateSafeProposal(client, key, common.HexToAddress(safeAddress), contractAddress, transaction, value, safeApi, SafeOperationType(safeOperationType), safeNonce) + if err != nil { + return fmt.Errorf("failed to create Safe proposal: %v", err) + } + + return nil + } + + transaction, err := session.TransferOwnership( + + newOwner, + ) + if err != nil { + return err + } + + cmd.Printf("Transaction hash: %s\n", transaction.Hash().Hex()) + if transactionOpts.NoSend { + estimationMessage := ethereum.CallMsg{ + From: transactionOpts.From, + To: &contractAddress, + Data: transaction.Data(), + } + + gasEstimationCtx, cancelGasEstimationCtx := NewChainContext(timeout) + defer cancelGasEstimationCtx() + + gasEstimate, gasEstimateErr := client.EstimateGas(gasEstimationCtx, estimationMessage) + if gasEstimateErr != nil { + return gasEstimateErr + } + + transactionBinary, transactionBinaryErr := transaction.MarshalBinary() + if transactionBinaryErr != nil { + return transactionBinaryErr + } + transactionBinaryHex := hex.EncodeToString(transactionBinary) + + cmd.Printf("Transaction: %s\nEstimated gas: %d\n", transactionBinaryHex, gasEstimate) + } else { + cmd.Println("Transaction submitted") + } + + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + cmd.Flags().StringVar(&contractAddressRaw, "contract", "", "Address of the contract to interact with") + cmd.Flags().StringVar(&safeAddress, "safe", "", "Address of the Safe contract") + cmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") + cmd.Flags().Uint8Var(&safeOperationType, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") + cmd.Flags().StringVar(&safeFunction, "safe-function", "", "Safe function overrider to use for the transaction (optional)") + cmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce overrider for the transaction (optional)") + + cmd.Flags().StringVar(&newOwnerRaw, "new-owner", "", "new-owner argument (common.Address)") + + return cmd +} + +var ErrNoRPCURL error = errors.New("no RPC URL provided -- please pass an RPC URL from the command line or set the OWNERSHIP_FACET_RPC_URL environment variable") + +// Generates an Ethereum client to the JSONRPC API at the given URL. If rpcURL is empty, then it +// attempts to read the RPC URL from the OWNERSHIP_FACET_RPC_URL environment variable. If that is empty, +// too, then it returns an error. +func NewClient(rpcURL string) (*ethclient.Client, error) { + if rpcURL == "" { + rpcURL = os.Getenv("OWNERSHIP_FACET_RPC_URL") + } + + if rpcURL == "" { + return nil, ErrNoRPCURL + } + + client, err := ethclient.Dial(rpcURL) + return client, err +} + +// Creates a new context to be used when interacting with the chain client. +func NewChainContext(timeout uint) (context.Context, context.CancelFunc) { + baseCtx := context.Background() + parsedTimeout := time.Duration(timeout) * time.Second + ctx, cancel := context.WithTimeout(baseCtx, parsedTimeout) + return ctx, cancel +} + +// Unlocks a key from a keystore (byte contents of a keystore file) with the given password. +func UnlockKeystore(keystoreData []byte, password string) (*keystore.Key, error) { + key, err := keystore.DecryptKey(keystoreData, password) + return key, err +} + +// Loads a key from file, prompting the user for the password if it is not provided as a function argument. +func KeyFromFile(keystoreFile string, password string) (*keystore.Key, error) { + var emptyKey *keystore.Key + keystoreContent, readErr := os.ReadFile(keystoreFile) + if readErr != nil { + return emptyKey, readErr + } + + // If password is "", prompt user for password. + if password == "" { + fmt.Printf("Please provide a password for keystore (%s): ", keystoreFile) + passwordRaw, inputErr := term.ReadPassword(int(os.Stdin.Fd())) + if inputErr != nil { + return emptyKey, fmt.Errorf("error reading password: %s", inputErr.Error()) + } + fmt.Print("\n") + password = string(passwordRaw) + } + + key, err := UnlockKeystore(keystoreContent, password) + return key, err +} + +// This method is used to set the parameters on a view call from command line arguments (represented mostly as +// strings). +func SetCallParametersFromArgs(opts *bind.CallOpts, pending bool, fromAddress, blockNumber string) { + if pending { + opts.Pending = true + } + + if fromAddress != "" { + opts.From = common.HexToAddress(fromAddress) + } + + if blockNumber != "" { + opts.BlockNumber = new(big.Int) + opts.BlockNumber.SetString(blockNumber, 0) + } +} + +// This method is used to set the parameters on a transaction from command line arguments (represented mostly as +// strings). +func SetTransactionParametersFromArgs(opts *bind.TransactOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas string, gasLimit uint64, noSend bool) { + if nonce != "" { + opts.Nonce = new(big.Int) + opts.Nonce.SetString(nonce, 0) + } + + if value != "" { + opts.Value = new(big.Int) + opts.Value.SetString(value, 0) + } + + if gasPrice != "" { + opts.GasPrice = new(big.Int) + opts.GasPrice.SetString(gasPrice, 0) + } + + if maxFeePerGas != "" { + opts.GasFeeCap = new(big.Int) + opts.GasFeeCap.SetString(maxFeePerGas, 0) + } + + if maxPriorityFeePerGas != "" { + opts.GasTipCap = new(big.Int) + opts.GasTipCap.SetString(maxPriorityFeePerGas, 0) + } + + if gasLimit != 0 { + opts.GasLimit = gasLimit + } + + opts.NoSend = noSend +} + +func CreateOwnershipFacetCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "ownership-facet", + Short: "Interact with the OwnershipFacet contract", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + + cmd.SetOut(os.Stdout) + + DeployGroup := &cobra.Group{ + ID: "deploy", Title: "Commands which deploy contracts", + } + cmd.AddGroup(DeployGroup) + ViewGroup := &cobra.Group{ + ID: "view", Title: "Commands which view contract state", + } + TransactGroup := &cobra.Group{ + ID: "transact", Title: "Commands which submit transactions", + } + cmd.AddGroup(ViewGroup, TransactGroup) + + cmdDeployOwnershipFacet := CreateOwnershipFacetDeploymentCommand() + cmdDeployOwnershipFacet.GroupID = DeployGroup.ID + cmd.AddCommand(cmdDeployOwnershipFacet) + + cmdViewOwner := CreateOwnerCommand() + cmdViewOwner.GroupID = ViewGroup.ID + cmd.AddCommand(cmdViewOwner) + + cmdTransactTransferOwnership := CreateTransferOwnershipCommand() + cmdTransactTransferOwnership.GroupID = TransactGroup.ID + cmd.AddCommand(cmdTransactTransferOwnership) + + return cmd +} + +// SafeOperationType represents the type of operation for a Safe transaction +type SafeOperationType uint8 + +const ( + Call SafeOperationType = 0 + DelegateCall SafeOperationType = 1 +) + +// String returns the string representation of the SafeOperationType +func (o SafeOperationType) String() string { + switch o { + case Call: + return "Call" + case DelegateCall: + return "DelegateCall" + default: + return "Unknown" + } +} + +// SafeTransactionData represents the data for a Safe transaction +type SafeTransactionData struct { + To string `json:"to"` + Value string `json:"value"` + Data string `json:"data"` + Operation SafeOperationType `json:"operation"` + SafeTxGas uint64 `json:"safeTxGas"` + BaseGas uint64 `json:"baseGas"` + GasPrice string `json:"gasPrice"` + GasToken string `json:"gasToken"` + RefundReceiver string `json:"refundReceiver"` + Nonce *big.Int `json:"nonce"` + SafeTxHash string `json:"safeTxHash"` + Sender string `json:"sender"` + Signature string `json:"signature"` + Origin string `json:"origin"` +} + +const ( + NativeTokenAddress = "0x0000000000000000000000000000000000000000" +) + +func DeployWithSafe(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, factoryAddress common.Address, value *big.Int, safeApi string, deployBytecode []byte, safeOperationType SafeOperationType, salt [32]byte, safeNonce *big.Int) error { + abi, err := CreateCall.CreateCallMetaData.GetAbi() + if err != nil { + return fmt.Errorf("failed to get ABI: %v", err) + } + + safeCreateCallTxData, err := abi.Pack("performCreate2", value, deployBytecode, salt) + if err != nil { + return fmt.Errorf("failed to pack performCreate2 transaction: %v", err) + } + + return CreateSafeProposal(client, key, safeAddress, factoryAddress, safeCreateCallTxData, value, safeApi, SafeOperationType(safeOperationType), safeNonce) +} + +func PredictDeploymentAddressSafe(from common.Address, salt [32]byte, deployBytecode []byte) (common.Address, error) { + // Calculate the hash of the init code (deployment bytecode) + initCodeHash := crypto.Keccak256(deployBytecode) + + // Calculate the CREATE2 address + deployedAddress := crypto.CreateAddress2(from, salt, initCodeHash) + + return deployedAddress, nil +} + +func CreateSafeProposal(client *ethclient.Client, key *keystore.Key, safeAddress common.Address, to common.Address, data []byte, value *big.Int, safeApi string, safeOperationType SafeOperationType, safeNonce *big.Int) error { + chainID, err := client.ChainID(context.Background()) + if err != nil { + return fmt.Errorf("failed to get chain ID: %v", err) + } + + // Create a new instance of the GnosisSafe contract + safeInstance, err := GnosisSafe.NewGnosisSafe(safeAddress, client) + if err != nil { + return fmt.Errorf("failed to create GnosisSafe instance: %v", err) + } + + nonce := safeNonce + if safeNonce == nil { + // Fetch the current nonce from the Safe contract + fetchedNonce, err := safeInstance.Nonce(&bind.CallOpts{}) + if err != nil { + return fmt.Errorf("failed to fetch nonce from Safe contract: %v", err) + } + nonce = fetchedNonce + } else { + nonce = safeNonce + } + + safeTransactionData := SafeTransactionData{ + To: to.Hex(), + Value: value.String(), + Data: common.Bytes2Hex(data), + Operation: safeOperationType, + SafeTxGas: 0, + BaseGas: 0, + GasPrice: "0", + GasToken: NativeTokenAddress, + RefundReceiver: NativeTokenAddress, + Nonce: nonce, + } + + // Calculate SafeTxHash + safeTxHash, err := CalculateSafeTxHash(safeAddress, safeTransactionData, chainID) + if err != nil { + return fmt.Errorf("failed to calculate SafeTxHash: %v", err) + } + + // Sign the SafeTxHash + signature, err := crypto.Sign(safeTxHash.Bytes(), key.PrivateKey) + if err != nil { + return fmt.Errorf("failed to sign SafeTxHash: %v", err) + } + + // Adjust V value for Ethereum's replay protection + signature[64] += 27 + + // Convert signature to hex + senderSignature := "0x" + common.Bytes2Hex(signature) + + // Prepare the request body + requestBody := map[string]interface{}{ + "to": safeTransactionData.To, + "value": safeTransactionData.Value, + "data": "0x" + safeTransactionData.Data, + "operation": int(safeTransactionData.Operation), + "safeTxGas": fmt.Sprintf("%d", safeTransactionData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", safeTransactionData.BaseGas), + "gasPrice": safeTransactionData.GasPrice, + "gasToken": safeTransactionData.GasToken, + "refundReceiver": safeTransactionData.RefundReceiver, + "nonce": fmt.Sprintf("%d", safeTransactionData.Nonce), + "safeTxHash": safeTxHash.Hex(), + "sender": key.Address.Hex(), + "signature": senderSignature, + "origin": fmt.Sprintf("{\"url\":\"%s\",\"name\":\"TokenSender Deployment\"}", safeApi), + } + + // Marshal the request body to JSON + jsonBody, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("failed to marshal request body: %v", err) + } + + // Send the request to the Safe Transaction Service + req, err := http.NewRequest("POST", safeApi, bytes.NewBuffer(jsonBody)) + if err != nil { + return fmt.Errorf("failed to create request: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to send request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + return fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + fmt.Println("Safe proposal created successfully") + return nil +} + +func CalculateSafeTxHash(safeAddress common.Address, txData SafeTransactionData, chainID *big.Int) (common.Hash, error) { + domainSeparator := apitypes.TypedDataDomain{ + ChainId: (*math.HexOrDecimal256)(chainID), + VerifyingContract: safeAddress.Hex(), + } + + typedData := apitypes.TypedData{ + Types: apitypes.Types{ + "EIP712Domain": []apitypes.Type{ + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "SafeTx": []apitypes.Type{ + {Name: "to", Type: "address"}, + {Name: "value", Type: "uint256"}, + {Name: "data", Type: "bytes"}, + {Name: "operation", Type: "uint8"}, + {Name: "safeTxGas", Type: "uint256"}, + {Name: "baseGas", Type: "uint256"}, + {Name: "gasPrice", Type: "uint256"}, + {Name: "gasToken", Type: "address"}, + {Name: "refundReceiver", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + }, + }, + Domain: domainSeparator, + PrimaryType: "SafeTx", + Message: apitypes.TypedDataMessage{ + "to": txData.To, + "value": txData.Value, + "data": "0x" + txData.Data, + "operation": fmt.Sprintf("%d", txData.Operation), + "safeTxGas": fmt.Sprintf("%d", txData.SafeTxGas), + "baseGas": fmt.Sprintf("%d", txData.BaseGas), + "gasPrice": txData.GasPrice, + "gasToken": txData.GasToken, + "refundReceiver": txData.RefundReceiver, + "nonce": fmt.Sprintf("%d", txData.Nonce), + }, + } + + typedDataHash, _, err := apitypes.TypedDataAndHash(typedData) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to hash typed data: %v", err) + } + + return common.BytesToHash(typedDataHash), nil +} diff --git a/bridge/bridge.go b/bridge/bridge.go index 59f4aeb1..0660c9cb 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -124,13 +124,7 @@ func NativeTokenBridgePropose(inboxAddress common.Address, keyFile string, passw return CreateSafeProposal(l1Client, key, safeAddress, inboxAddress, createRetryableTicketData, big.NewInt(0), safeApi, OperationType(safeOperation), safeNonce) } -func GetERC20BridgeCalldataAndValue(routerAddress common.Address, keyFile string, password string, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int) ([]byte, *big.Int, error) { - key, keyErr := NodeInterface.KeyFromFile(keyFile, password) - if keyErr != nil { - fmt.Fprintln(os.Stderr, "keyErr", keyErr.Error()) - return nil, nil, keyErr - } - +func GetERC20BridgeCalldataAndValue(routerAddress common.Address, key *keystore.Key, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int) ([]byte, *big.Int, error) { l1Client, l1ClientErr := ethclient.DialContext(context.Background(), l1Rpc) if l1ClientErr != nil { fmt.Fprintln(os.Stderr, "l1ClientErr", l1ClientErr.Error()) @@ -222,8 +216,14 @@ func GetERC20BridgeCalldataAndValue(routerAddress common.Address, keyFile string return callData, tokenTotalFeeAmount, nil } -func ERC20BridgeCall(routerAddress common.Address, keyFile string, password string, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { - callData, tokenTotalFeeAmount, callDataErr := GetERC20BridgeCalldataAndValue(routerAddress, keyFile, password, l1Rpc, l2Rpc, tokenAddress, to, amount) +func ERC20BridgeCall(routerAddress common.Address, keyFile string, password string, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int, customNativeToken bool) (*types.Transaction, error) { + key, keyErr := NodeInterface.KeyFromFile(keyFile, password) + if keyErr != nil { + fmt.Fprintln(os.Stderr, "keyErr", keyErr.Error()) + return nil, keyErr + } + + callData, tokenTotalFeeAmount, callDataErr := GetERC20BridgeCalldataAndValue(routerAddress, key, l1Rpc, l2Rpc, tokenAddress, to, amount) if callDataErr != nil { fmt.Fprintln(os.Stderr, "callDataErr", callDataErr.Error()) return nil, callDataErr @@ -235,13 +235,12 @@ func ERC20BridgeCall(routerAddress common.Address, keyFile string, password stri return nil, l1ClientErr } - key, keyErr := NodeInterface.KeyFromFile(keyFile, password) - if keyErr != nil { - fmt.Fprintln(os.Stderr, "keyErr", keyErr.Error()) - return nil, keyErr - } + fmt.Println(key.Address.Hex()) fmt.Println("Sending transaction...") + if customNativeToken { + tokenTotalFeeAmount = big.NewInt(0) + } transaction, transactionErr := SendTransaction(l1Client, key, password, callData, routerAddress.Hex(), tokenTotalFeeAmount) if transactionErr != nil { fmt.Fprintln(os.Stderr, "transactionErr", transactionErr.Error()) @@ -260,8 +259,14 @@ func ERC20BridgeCall(routerAddress common.Address, keyFile string, password stri return transaction, nil } -func ERC20BridgePropose(routerAddress common.Address, keyFile string, password string, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int, safeAddress common.Address, safeApi string, safeOperation uint8, safeNonce *big.Int) error { - callData, tokenTotalFeeAmount, callDataErr := GetERC20BridgeCalldataAndValue(routerAddress, keyFile, password, l1Rpc, l2Rpc, tokenAddress, to, amount) +func ERC20BridgePropose(routerAddress common.Address, keyFile string, password string, l1Rpc string, l2Rpc string, tokenAddress common.Address, to common.Address, amount *big.Int, safeAddress common.Address, safeApi string, safeOperation uint8, safeNonce *big.Int, customNativeToken bool) error { + key, keyErr := NodeInterface.KeyFromFile(keyFile, password) + if keyErr != nil { + fmt.Fprintln(os.Stderr, "keyErr", keyErr.Error()) + return keyErr + } + + callData, tokenTotalFeeAmount, callDataErr := GetERC20BridgeCalldataAndValue(routerAddress, key, l1Rpc, l2Rpc, tokenAddress, to, amount) if callDataErr != nil { fmt.Fprintln(os.Stderr, "callDataErr", callDataErr.Error()) return callDataErr @@ -273,10 +278,8 @@ func ERC20BridgePropose(routerAddress common.Address, keyFile string, password s return l1ClientErr } - key, keyErr := NodeInterface.KeyFromFile(keyFile, password) - if keyErr != nil { - fmt.Fprintln(os.Stderr, "keyErr", keyErr.Error()) - return keyErr + if customNativeToken { + tokenTotalFeeAmount = big.NewInt(0) } return CreateSafeProposal(l1Client, key, safeAddress, routerAddress, callData, tokenTotalFeeAmount, safeApi, OperationType(safeOperation), safeNonce) diff --git a/bridge/cmd.go b/bridge/cmd.go index 9c4071f0..8ed45ee8 100644 --- a/bridge/cmd.go +++ b/bridge/cmd.go @@ -122,7 +122,6 @@ func CreateBridgeNativeTokenL1ToL2Command() *cobra.Command { } } else { fmt.Println("--safe-nonce not specified, fetching from Safe") - safeNonce = big.NewInt(0) } } @@ -283,6 +282,7 @@ func CreateBridgeERC20L1ToL2Command() *cobra.Command { var amount *big.Int var safeOperation uint8 var safeNonce *big.Int + var isCustomNativeToken bool createCmd := &cobra.Command{ Use: "l1-to-l2", @@ -353,7 +353,6 @@ func CreateBridgeERC20L1ToL2Command() *cobra.Command { } } else { fmt.Println("--safe-nonce not specified, fetching from Safe") - safeNonce = big.NewInt(0) } if l1Rpc == "" { @@ -370,14 +369,14 @@ func CreateBridgeERC20L1ToL2Command() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { fmt.Println("Bridging", tokenAddress.Hex(), "to", to.Hex()) if safeAddressRaw == "" { - transaction, transactionErr := ERC20BridgeCall(routerAddress, keyFile, password, l1Rpc, l2Rpc, tokenAddress, to, amount) + transaction, transactionErr := ERC20BridgeCall(routerAddress, keyFile, password, l1Rpc, l2Rpc, tokenAddress, to, amount, isCustomNativeToken) if transactionErr != nil { fmt.Fprintln(cmd.ErrOrStderr(), transactionErr.Error()) return transactionErr } fmt.Println("Transaction sent:", transaction.Hash().Hex()) } else { - proposeErr := ERC20BridgePropose(routerAddress, keyFile, password, l1Rpc, l2Rpc, tokenAddress, to, amount, safeAddress, safeApi, safeOperation, safeNonce) + proposeErr := ERC20BridgePropose(routerAddress, keyFile, password, l1Rpc, l2Rpc, tokenAddress, to, amount, safeAddress, safeApi, safeOperation, safeNonce, isCustomNativeToken) if proposeErr != nil { fmt.Fprintln(cmd.ErrOrStderr(), proposeErr.Error()) return proposeErr @@ -400,6 +399,7 @@ func CreateBridgeERC20L1ToL2Command() *cobra.Command { createCmd.Flags().StringVar(&safeApi, "safe-api", "", "Safe API for the Safe Transaction Service (optional)") createCmd.Flags().Uint8Var(&safeOperation, "safe-operation", 0, "Safe operation type: 0 (Call) or 1 (DelegateCall)") createCmd.Flags().StringVar(&safeNonceRaw, "safe-nonce", "", "Safe nonce") + createCmd.Flags().BoolVar(&isCustomNativeToken, "custom-native-token", false, "Is custom native token") return createCmd } diff --git a/cmd/game7/cmd.go b/cmd/game7/cmd.go index f8fd8beb..03f5cc20 100644 --- a/cmd/game7/cmd.go +++ b/cmd/game7/cmd.go @@ -24,6 +24,7 @@ import ( "github.com/G7DAO/protocol/bindings/TokenFaucet" "github.com/G7DAO/protocol/bindings/WrappedNativeToken" "github.com/G7DAO/protocol/bridge" + terminus "github.com/G7DAO/protocol/cmd/game7/diamondLaunch" "github.com/G7DAO/protocol/cmd/game7/version" ) @@ -87,7 +88,9 @@ func CreateRootCommand() *cobra.Command { mockCmd := CreateMockCommand() - rootCmd.AddCommand(completionCmd, versionCmd, tokenCmd, arbitrumL1OrbitCustomGatewayCmd, arbitrumL2CustomGatewayCmd, arbitrumUpgradeExecutorCmd, arbitrumL1OrbitGatewayRouterCmd, arbSysCmd, erc20InboxCmd, bridgeCmd, faucetCmd, accountsCmd, wrappedNativeTokenCmd, stakerCmd, mockCmd, positionMetadataCmd, tokenSenderCmd, metronomeCmd) + terminusCMD := terminus.CreateTerminusDeployCommand() + + rootCmd.AddCommand(completionCmd, versionCmd, tokenCmd, arbitrumL1OrbitCustomGatewayCmd, arbitrumL2CustomGatewayCmd, arbitrumUpgradeExecutorCmd, arbitrumL1OrbitGatewayRouterCmd, arbSysCmd, erc20InboxCmd, bridgeCmd, faucetCmd, accountsCmd, wrappedNativeTokenCmd, stakerCmd, mockCmd, positionMetadataCmd, tokenSenderCmd, metronomeCmd, terminusCMD) // By default, cobra Command objects write to stderr. We have to forcibly set them to output to // stdout. diff --git a/cmd/game7/diamondLaunch/terminusDeploy.go b/cmd/game7/diamondLaunch/terminusDeploy.go new file mode 100644 index 00000000..3779235a --- /dev/null +++ b/cmd/game7/diamondLaunch/terminusDeploy.go @@ -0,0 +1,365 @@ +package terminus + +import ( + "encoding/json" + "fmt" + "math/big" + "os" + "strings" + + "github.com/G7DAO/protocol/bindings/security/terminus/TerminusFacet" + "github.com/G7DAO/protocol/bindings/security/terminus/TerminusInitializer" + "github.com/G7DAO/protocol/bindings/utils/diamonds/Diamond" + "github.com/G7DAO/protocol/bindings/utils/diamonds/DiamondCutFacet" + "github.com/G7DAO/protocol/bindings/utils/diamonds/DiamondLoupeFacet" + "github.com/G7DAO/protocol/bindings/utils/diamonds/OwnershipFacet" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" +) + +type TerminusDiamondConfiguration struct { + Diamond string + DiamondCutFacet string + DiamondLoupeFacet string + OwnershipFacet string + TerminusFacet string + TerminusInitializer string + Transactions map[string]string +} + +// Returns true if the given address is the zero address and false otherwise. +func addressIsZero(address common.Address) bool { + zero := big.NewInt(0) + return zero.Cmp(address.Big()) == 0 +} + +func TerminusDiamondSetup( + txOpts *bind.TransactOpts, + client *ethclient.Client, + owner common.Address, + diamondCutAddress common.Address, + diamondLoupeAddress common.Address, + ownershipAddress common.Address, + terminusFacetAddress common.Address, + terminusInitializerAddress common.Address, +) (TerminusDiamondConfiguration, error) { + deployedConfiguration := TerminusDiamondConfiguration{} + deployedConfiguration.Transactions = make(map[string]string) + + // If diamondCutAddress is not provided, we must deploy a new DiamondCutFacet. + if addressIsZero(diamondCutAddress) { + address, diamondCutTransaction, _, diamondCutErr := DiamondCutFacet.DeployDiamondCutFacet(txOpts, client) + if diamondCutErr != nil { + return deployedConfiguration, diamondCutErr + } + diamondCutAddress = address + deployedConfiguration.DiamondCutFacet = address.Hex() + deployedConfiguration.Transactions["DiamondCutFacetDeployment"] = diamondCutTransaction.Hash().Hex() + } else { + deployedConfiguration.DiamondCutFacet = diamondCutAddress.Hex() + } + + // Now we deploy a Diamond contract which uses the given DiamondCutFacet. + diamondAddress, diamondTransaction, _, diamondErr := Diamond.DeployDiamond(txOpts, client, owner, diamondCutAddress) + if diamondErr != nil { + return deployedConfiguration, diamondErr + } + deployedConfiguration.Diamond = diamondAddress.Hex() + deployedConfiguration.Transactions["DiamondDeployment"] = diamondTransaction.Hash().Hex() + + // If diamondLoupeAddress is not provided, we must deploy a new DiamondLoupeFacet. + if addressIsZero(diamondLoupeAddress) { + address, diamondLoupeTransaction, _, diamondLoupeErr := DiamondLoupeFacet.DeployDiamondLoupeFacet(txOpts, client) + if diamondLoupeErr != nil { + return deployedConfiguration, diamondLoupeErr + } + diamondLoupeAddress = address + deployedConfiguration.DiamondLoupeFacet = address.Hex() + deployedConfiguration.Transactions["DiamondLoupeFacetDeployment"] = diamondLoupeTransaction.Hash().Hex() + } else { + deployedConfiguration.DiamondLoupeFacet = diamondLoupeAddress.Hex() + } + + // If ownershipAddress is not provided, we must deploy a new OwnershipFacet. + if addressIsZero(ownershipAddress) { + address, ownershipTransaction, _, ownershipErr := OwnershipFacet.DeployOwnershipFacet(txOpts, client) + if ownershipErr != nil { + return deployedConfiguration, ownershipErr + } + ownershipAddress = address + deployedConfiguration.OwnershipFacet = address.Hex() + deployedConfiguration.Transactions["OwnershipFacetDeployment"] = ownershipTransaction.Hash().Hex() + } else { + deployedConfiguration.OwnershipFacet = ownershipAddress.Hex() + } + + // If fullcountPlayerAddress is not provided, we must deploy a new FullcountPlayerFacet. + if addressIsZero(terminusFacetAddress) { + address, terminusFacetTransaction, _, terminusFacetErr := TerminusFacet.DeployTerminusFacet(txOpts, client) + if terminusFacetErr != nil { + return deployedConfiguration, terminusFacetErr + } + terminusFacetAddress = address + deployedConfiguration.TerminusFacet = address.Hex() + deployedConfiguration.Transactions["TerminusFacetDeployment"] = terminusFacetTransaction.Hash().Hex() + } else { + deployedConfiguration.TerminusFacet = terminusFacetAddress.Hex() + } + + if addressIsZero(terminusInitializerAddress) { + address, terminusInitializerTransaction, _, terminusInitializerErr := TerminusInitializer.DeployTerminusInitializer(txOpts, client) + if terminusInitializerErr != nil { + return deployedConfiguration, terminusInitializerErr + } + terminusInitializerAddress = address + deployedConfiguration.TerminusInitializer = address.Hex() + deployedConfiguration.Transactions["TerminusInitializerDeployment"] = terminusInitializerTransaction.Hash().Hex() + } else { + deployedConfiguration.TerminusInitializer = terminusInitializerAddress.Hex() + } + + // Method signature: true if it's already attached and false otherwise + attachedMethods := make(map[string]bool) + + diamondCutABI, diamondCutABIErr := DiamondCutFacet.DiamondCutFacetMetaData.GetAbi() + if diamondCutABIErr != nil { + return deployedConfiguration, diamondCutABIErr + } + for _, method := range diamondCutABI.Methods { + attachedMethods[method.Sig] = true + } + + // Facet cut actions: Add = 0, Replace = 1, Remove = 2 + + diamondLoupeCut := DiamondCutFacet.IDiamondCutFacetCut{FacetAddress: diamondLoupeAddress, Action: 0, FunctionSelectors: make([][4]byte, 0)} + diamondLoupeABI, diamondLoupeABIErr := DiamondLoupeFacet.DiamondLoupeFacetMetaData.GetAbi() + if diamondLoupeABIErr != nil { + return deployedConfiguration, diamondLoupeABIErr + } + for _, method := range diamondLoupeABI.Methods { + _, ok := attachedMethods[method.Sig] + if !ok { + diamondLoupeCut.FunctionSelectors = append(diamondLoupeCut.FunctionSelectors, [4]byte(method.ID[:4])) + attachedMethods[method.Sig] = true + } + } + + ownershipCut := DiamondCutFacet.IDiamondCutFacetCut{FacetAddress: ownershipAddress, Action: 0, FunctionSelectors: make([][4]byte, 0)} + ownershipABI, ownershipABIErr := OwnershipFacet.OwnershipFacetMetaData.GetAbi() + if ownershipABIErr != nil { + return deployedConfiguration, ownershipABIErr + } + for _, method := range ownershipABI.Methods { + _, ok := attachedMethods[method.Sig] + if !ok { + ownershipCut.FunctionSelectors = append(ownershipCut.FunctionSelectors, [4]byte(method.ID[:4])) + attachedMethods[method.Sig] = true + } + } + + // Call data for contract initialization + var initCalldata []byte + var initCalldataError error + + terminusFacetCut := DiamondCutFacet.IDiamondCutFacetCut{FacetAddress: terminusFacetAddress, Action: 0, FunctionSelectors: make([][4]byte, 0)} + terminusFacetABI, terminusFacetABIErr := TerminusFacet.TerminusFacetMetaData.GetAbi() + if terminusFacetABIErr != nil { + return deployedConfiguration, terminusFacetABIErr + } + for _, method := range terminusFacetABI.Methods { + _, ok := attachedMethods[method.Sig] + if !ok { + terminusFacetCut.FunctionSelectors = append(terminusFacetCut.FunctionSelectors, [4]byte(method.ID[:4])) + attachedMethods[method.Sig] = true + } + } + + terminusInitializerABI, terminusInitializerAbiErr := abi.JSON(strings.NewReader(TerminusInitializer.TerminusInitializerMetaData.ABI)) + if terminusInitializerAbiErr != nil { + fmt.Fprintln(os.Stderr, "terminusInitializerAbiErr", terminusInitializerAbiErr.Error()) + } + + initCalldata, initCalldataError = terminusInitializerABI.Pack("init") + if initCalldataError != nil { + fmt.Fprintln(os.Stderr, "initCalldataError", initCalldataError.Error()) + } + + diamondForCut, diamondForCutErr := DiamondCutFacet.NewDiamondCutFacet(diamondAddress, client) + if diamondForCutErr != nil { + return deployedConfiguration, diamondForCutErr + } + + cuts := []DiamondCutFacet.IDiamondCutFacetCut{diamondLoupeCut, ownershipCut, terminusFacetCut} + + cutTransaction, cutTransactionErr := diamondForCut.DiamondCut(txOpts, cuts, terminusInitializerAddress, initCalldata) + if cutTransactionErr != nil { + return deployedConfiguration, cutTransactionErr + } + deployedConfiguration.Transactions["Cut"] = cutTransaction.Hash().Hex() + + return deployedConfiguration, nil +} + +func CreateTerminusDeployCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "terminus", + Short: "Deploy new Termiuns diamond contract", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + + gogogoCmd := CreateTerminusGogogoCommand() + TerminusFacetCmd := TerminusFacet.CreateTerminusFacetCommand() + + cmd.AddCommand(gogogoCmd, TerminusFacetCmd) + + return cmd +} + +func CreateTerminusGogogoCommand() *cobra.Command { + var keyfile, nonce, password, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, rpc, outfile string + var gasLimit uint64 + var simulate bool + var timeout uint + + var contractOwner common.Address + var contractOwnerRaw string + var diamondCutFacet, diamondLoupeFacet, ownershipFacet, terminusFacet, terminusInitializer common.Address + var diamondCutFacetRaw, diamondLoupeFacetRaw, ownershipFacetRaw, terminusFacetRaw, terminusInitializerRaw string + + cmd := &cobra.Command{ + Use: "gogogo", + Short: "Deploy a new Terminus diamond contract", + PreRunE: func(cmd *cobra.Command, args []string) error { + if keyfile == "" { + return fmt.Errorf("--keystore not specified (this should be a path to an Ethereum account keystore file)") + } + + if contractOwnerRaw == "" { + return fmt.Errorf("--contract-owner argument not specified") + } else if !common.IsHexAddress(contractOwnerRaw) { + return fmt.Errorf("--contract-owner argument is not a valid Ethereum address") + } + contractOwner = common.HexToAddress(contractOwnerRaw) + + if diamondCutFacetRaw != "" { + if !common.IsHexAddress(diamondCutFacetRaw) { + return fmt.Errorf("--diamond-cut-facet argument is not a valid Ethereum address") + } + diamondCutFacet = common.HexToAddress(diamondCutFacetRaw) + } else { + diamondCutFacet = common.BigToAddress(big.NewInt(0)) + } + + if diamondLoupeFacetRaw != "" { + if !common.IsHexAddress(diamondLoupeFacetRaw) { + return fmt.Errorf("--diamond-loupe-facet argument is not a valid Ethereum address") + } + diamondLoupeFacet = common.HexToAddress(diamondLoupeFacetRaw) + } else { + diamondLoupeFacet = common.BigToAddress(big.NewInt(0)) + } + + if ownershipFacetRaw != "" { + if !common.IsHexAddress(ownershipFacetRaw) { + return fmt.Errorf("--ownership-facet argument is not a valid Ethereum address") + } + ownershipFacet = common.HexToAddress(ownershipFacetRaw) + } else { + ownershipFacet = common.BigToAddress(big.NewInt(0)) + } + + if terminusFacetRaw != "" { + if !common.IsHexAddress(terminusFacetRaw) { + return fmt.Errorf("--terminus-facet argument is not a valid Ethereum address") + } + terminusFacet = common.HexToAddress(terminusFacetRaw) + } else { + terminusFacet = common.BigToAddress(big.NewInt(0)) + } + + if terminusInitializerRaw != "" { + if !common.IsHexAddress(terminusInitializerRaw) { + return fmt.Errorf("--terminus-initializer argument is not a valid Ethereum address") + } + terminusInitializer = common.HexToAddress(terminusInitializerRaw) + } else { + terminusInitializer = common.BigToAddress(big.NewInt(0)) + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, clientErr := Diamond.NewClient(rpc) + if clientErr != nil { + return clientErr + } + + key, keyErr := Diamond.KeyFromFile(keyfile, password) + if keyErr != nil { + return keyErr + } + + chainIDCtx, cancelChainIDCtx := Diamond.NewChainContext(timeout) + defer cancelChainIDCtx() + chainID, chainIDErr := client.ChainID(chainIDCtx) + if chainIDErr != nil { + return chainIDErr + } + + transactionOpts, transactionOptsErr := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) + if transactionOptsErr != nil { + return transactionOptsErr + } + + Diamond.SetTransactionParametersFromArgs(transactionOpts, nonce, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, simulate) + + deployedConfiguration, setupErr := TerminusDiamondSetup(transactionOpts, client, contractOwner, diamondCutFacet, diamondLoupeFacet, ownershipFacet, terminusFacet, terminusInitializer) + if setupErr != nil { + return setupErr + } + + deployedConfigurationJSON, marshalErr := json.Marshal(deployedConfiguration) + if marshalErr != nil { + return marshalErr + } + + if outfile != "" { + writeErr := os.WriteFile(outfile, deployedConfigurationJSON, 0644) + if writeErr != nil { + return writeErr + } + } else { + cmd.Println(string(deployedConfigurationJSON)) + } + return nil + }, + } + + cmd.Flags().StringVar(&rpc, "rpc", "", "URL of the JSONRPC API to use") + cmd.Flags().StringVar(&keyfile, "keyfile", "", "Path to the keystore file to use for the transaction") + cmd.Flags().StringVar(&password, "password", "", "Password to use to unlock the keystore (if not specified, you will be prompted for the password when the command executes)") + cmd.Flags().StringVar(&nonce, "nonce", "", "Nonce to use for the transaction") + cmd.Flags().StringVar(&value, "value", "", "Value to send with the transaction") + cmd.Flags().StringVar(&gasPrice, "gas-price", "", "Gas price to use for the transaction") + cmd.Flags().StringVar(&maxFeePerGas, "max-fee-per-gas", "", "Maximum fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().StringVar(&maxPriorityFeePerGas, "max-priority-fee-per-gas", "", "Maximum priority fee per gas to use for the (EIP-1559) transaction") + cmd.Flags().Uint64Var(&gasLimit, "gas-limit", 0, "Gas limit for the transaction") + cmd.Flags().BoolVar(&simulate, "simulate", false, "Simulate the transaction without sending it") + cmd.Flags().UintVar(&timeout, "timeout", 60, "Timeout (in seconds) for interactions with the JSONRPC API") + + cmd.Flags().StringVar(&contractOwnerRaw, "contract-owner", "", "Address of account which should own the Diamond") + cmd.Flags().StringVar(&diamondCutFacetRaw, "diamond-cut-facet", "", "(Optional) address of pre-existing DiamondCutFacet that should be mounted onto the Diamond") + cmd.Flags().StringVar(&diamondLoupeFacetRaw, "diamond-loupe-facet", "", "(Optional) address of pre-existing DiamondLoupeFacet that should be mounted onto the Diamond") + cmd.Flags().StringVar(&ownershipFacetRaw, "ownership-facet", "", "(Optional) address of pre-existing OwnershipFacet that should be mounted onto the Diamond") + cmd.Flags().StringVar(&terminusFacetRaw, "terminus-facet", "", "(Optional) address of pre-existing TerminusFacet that should be mounted onto the Diamond") + cmd.Flags().StringVar(&terminusInitializerRaw, "terminus-initializer", "", "(Optional) address of pre-existing TerminusInitializer") + cmd.Flags().StringVarP(&outfile, "output", "o", "", "Path to the file where the deployment configuration should be written") + + return cmd +} diff --git a/web3/contracts/interfaces/IStaker.sol b/web3/contracts/interfaces/IStaker.sol index 77765205..27f54104 100644 --- a/web3/contracts/interfaces/IStaker.sol +++ b/web3/contracts/interfaces/IStaker.sol @@ -1,12 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; - import { StakingPool, Position } from "../staking/data.sol"; import { PositionMetadata } from "../staking/PositionMetadata.sol"; interface IStaker { - function positionMetadataAddress() external view returns (address); function TotalPools() external view returns (uint256); @@ -17,22 +15,27 @@ interface IStaker { function CurrentPositionsInPool(uint256 poolID) external view returns (uint256); - function Pools(uint256 poolID) external view returns ( - address administrator, - uint256 tokenType, - address tokenAddress, - uint256 tokenID, - bool transferable, - uint256 lockupSeconds, - uint256 cooldownSeconds - ); - - function Positions(uint256 positionTokenID) external view returns ( - uint256 poolID, - uint256 amountOrTokenID, - uint256 stakeTimestamp, - uint256 unstakeInitiatedAt - ); + function Pools( + uint256 poolID + ) + external + view + returns ( + address administrator, + uint256 tokenType, + address tokenAddress, + uint256 tokenID, + bool transferable, + uint256 lockupSeconds, + uint256 cooldownSeconds + ); + + function Positions( + uint256 positionTokenID + ) + external + view + returns (uint256 poolID, uint256 amountOrTokenID, uint256 stakeTimestamp, uint256 unstakeInitiatedAt); event StakingPoolCreated( uint256 indexed poolID, @@ -49,21 +52,11 @@ interface IStaker { uint256 cooldownSeconds ); - event Staked( - uint256 positionTokenID, - address indexed owner, - uint256 indexed poolID, - uint256 amountOrTokenID - ); + event Staked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID); event UnstakeInitiated(uint256 positionTokenID, address indexed owner); - event Unstaked( - uint256 positionTokenID, - address indexed owner, - uint256 indexed poolID, - uint256 amountOrTokenID - ); + event Unstaked(uint256 positionTokenID, address indexed owner, uint256 indexed poolID, uint256 amountOrTokenID); function createPool( uint256 tokenType, @@ -71,7 +64,8 @@ interface IStaker { uint256 tokenID, bool transferable, uint256 lockupSeconds, - uint256 cooldownSeconds + uint256 cooldownSeconds, + address adminstrator ) external; function updatePoolConfiguration( @@ -86,17 +80,29 @@ interface IStaker { function transferPoolAdministration(uint256 poolID, address newAdministrator) external; - function stakeNative(address user, uint256 poolID) external payable returns (uint256 positionTokenID); + function stakeNative(address positionHolder, uint256 poolID) external payable returns (uint256 positionTokenID); - function stakeERC20(address user, uint256 poolID, uint256 amount) external returns (uint256 positionTokenID); + function stakeERC20( + address positionHolder, + uint256 poolID, + uint256 amount + ) external returns (uint256 positionTokenID); - function stakeERC721(address user, uint256 poolID, uint256 tokenID) external returns (uint256 positionTokenID); + function stakeERC721( + address positionHolder, + uint256 poolID, + uint256 tokenID + ) external returns (uint256 positionTokenID); - function stakeERC1155(address user, uint256 poolID, uint256 amount) external returns (uint256 positionTokenID); + function stakeERC1155( + address positionHolder, + uint256 poolID, + uint256 amount + ) external returns (uint256 positionTokenID); function initiateUnstake(uint256 positionTokenID) external; function unstake(uint256 positionTokenID) external; function tokenURI(uint256 tokenId) external view returns (string memory); -} \ No newline at end of file +} diff --git a/web3/contracts/security/terminus/ControllableWithTerminus.sol b/web3/contracts/security/terminus/ControllableWithTerminus.sol new file mode 100644 index 00000000..4a6bec9d --- /dev/null +++ b/web3/contracts/security/terminus/ControllableWithTerminus.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + */ + +pragma solidity ^0.8.9; +import { TerminusFacet } from "./TerminusFacet.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +abstract contract ControllableWithTerminus is Ownable { + TerminusFacet private terminus; + uint256 public administratorPoolId; + + constructor(address _terminusContractAddress, uint256 _administratorPoolId) Ownable(msg.sender) { + terminus = TerminusFacet(_terminusContractAddress); + administratorPoolId = _administratorPoolId; + } + + /** + * @dev throws if called by account that doesn't hold the administrator pool token + * or is the contract owner + */ + modifier onlyAdministrator() { + require( + terminus.balanceOf(msg.sender, administratorPoolId) > 0 || msg.sender == owner(), + "Lootbox.sol: Sender is not an administrator" + ); + _; + } + + function changeAdministratorPoolId(uint256 _administratorPoolId) public onlyOwner { + administratorPoolId = _administratorPoolId; + } + + function grantAdminRole(address to) public onlyOwner { + require( + address(this) == terminus.terminusPoolController(administratorPoolId), + "The contract is not the pool controller for the administrator pool. Please transfer the controller role to the contract." + ); + terminus.mint(to, administratorPoolId, 1, ""); + } + + function revokeAdminRole(address from) public onlyOwner { + TerminusFacet terminusContract = TerminusFacet(terminus); + require( + address(this) == terminusContract.terminusPoolController(administratorPoolId), + "The contract is not the pool controller for the administrator pool. Please transfer the controller role to the contract." + ); + + uint256 balance = terminusContract.balanceOf(from, administratorPoolId); + terminusContract.burn(from, administratorPoolId, balance); + } +} diff --git a/web3/contracts/security/terminus/ERC1155WithTerminusStorage.sol b/web3/contracts/security/terminus/ERC1155WithTerminusStorage.sol new file mode 100644 index 00000000..bd054213 --- /dev/null +++ b/web3/contracts/security/terminus/ERC1155WithTerminusStorage.sol @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: MIT + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + * An ERC1155 implementation which uses the Moonstream DAO common storage structure for proxies. + * EIP1155: https://eips.ethereum.org/EIPS/eip-1155 + * + * The Moonstream contract is used to delegate calls from an EIP2535 Diamond proxy. + * + * This implementation is adapted from the OpenZeppelin ERC1155 implementation: + * https://github.com/OpenZeppelin/openzeppelin-contracts/tree/6bd6b76d1156e20e45d1016f355d154141c7e5b9/contracts/token/ERC1155 + */ + +pragma solidity ^0.8.9; + +import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; +import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; +import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import "./LibTerminus.sol"; + +contract ERC1155WithTerminusStorage is Context, ERC165, IERC1155, IERC1155MetadataURI { + constructor() {} + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC1155).interfaceId || + interfaceId == type(IERC1155MetadataURI).interfaceId || + super.supportsInterface(interfaceId); + } + + function uri(uint256 poolID) public view virtual override returns (string memory) { + return LibTerminus.terminusStorage().poolURI[poolID]; + } + + /** + * @dev See {IERC1155-balanceOf}. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { + require(account != address(0), "ERC1155WithTerminusStorage: balance query for the zero address"); + return LibTerminus.terminusStorage().poolBalances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] memory accounts, + uint256[] memory ids + ) public view virtual override returns (uint256[] memory) { + require(accounts.length == ids.length, "ERC1155WithTerminusStorage: accounts and ids length mismatch"); + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts[i], ids[i]); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { + return LibTerminus.terminusStorage().globalOperatorApprovals[account][operator]; + } + + function isApprovedForPool(uint256 poolID, address operator) public view returns (bool) { + return LibTerminus._isApprovedForPool(poolID, operator); + } + + function approveForPool(uint256 poolID, address operator) external { + LibTerminus.enforcePoolIsController(poolID, _msgSender()); + LibTerminus._approveForPool(poolID, operator); + } + + function unapproveForPool(uint256 poolID, address operator) external { + LibTerminus.enforcePoolIsController(poolID, _msgSender()); + LibTerminus._unapproveForPool(poolID, operator); + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()) || isApprovedForPool(id, _msgSender()), + "ERC1155WithTerminusStorage: caller is not owner nor approved" + ); + _safeTransferFrom(from, to, id, amount, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155WithTerminusStorage: transfer caller is not owner nor approved" + ); + _safeBatchTransferFrom(from, to, ids, amounts, data); + } + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155WithTerminusStorage: transfer to the zero address"); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + require( + !ts.poolNotTransferable[id], + "ERC1155WithTerminusStorage: _safeTransferFrom -- pool is not transferable" + ); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); + + uint256 fromBalance = ts.poolBalances[id][from]; + require(fromBalance >= amount, "ERC1155WithTerminusStorage: insufficient balance for transfer"); + unchecked { + ts.poolBalances[id][from] = fromBalance - amount; + } + ts.poolBalances[id][to] += amount; + + emit TransferSingle(operator, from, to, id, amount); + + _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(ids.length == amounts.length, "ERC1155WithTerminusStorage: ids and amounts length mismatch"); + require(to != address(0), "ERC1155WithTerminusStorage: transfer to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + require( + !ts.poolNotTransferable[id], + "ERC1155WithTerminusStorage: _safeBatchTransferFrom -- pool is not transferable" + ); + + uint256 fromBalance = ts.poolBalances[id][from]; + require(fromBalance >= amount, "ERC1155WithTerminusStorage: insufficient balance for transfer"); + unchecked { + ts.poolBalances[id][from] = fromBalance - amount; + } + ts.poolBalances[id][to] += amount; + } + + emit TransferBatch(operator, from, to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + } + + /** + * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { + require(to != address(0), "ERC1155WithTerminusStorage: mint to the zero address"); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + require( + ts.poolSupply[id] + amount <= ts.poolCapacity[id], + "ERC1155WithTerminusStorage: _mint -- Minted tokens would exceed pool capacity" + ); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), to, _asSingletonArray(id), _asSingletonArray(amount), data); + + ts.poolSupply[id] += amount; + ts.poolBalances[id][to] += amount; + emit TransferSingle(operator, address(0), to, id, amount); + + _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155WithTerminusStorage: mint to the zero address"); + require(ids.length == amounts.length, "ERC1155WithTerminusStorage: ids and amounts length mismatch"); + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; i++) { + require( + ts.poolSupply[ids[i]] + amounts[i] <= ts.poolCapacity[ids[i]], + "ERC1155WithTerminusStorage: _mintBatch -- Minted tokens would exceed pool capacity" + ); + ts.poolSupply[ids[i]] += amounts[i]; + ts.poolBalances[ids[i]][to] += amounts[i]; + } + + emit TransferBatch(operator, address(0), to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + + /** + * @dev Destroys `amount` tokens of token type `id` from `from` + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `amount` tokens of token type `id`. + */ + function _burn(address from, uint256 id, uint256 amount) internal virtual { + require(from != address(0), "ERC1155WithTerminusStorage: burn from the zero address"); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + require(ts.poolBurnable[id], "ERC1155WithTerminusStorage: _burn -- pool is not burnable"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); + + uint256 fromBalance = ts.poolBalances[id][from]; + require(fromBalance >= amount, "ERC1155WithTerminusStorage: burn amount exceeds balance"); + unchecked { + ts.poolBalances[id][from] = fromBalance - amount; + ts.poolSupply[id] -= amount; + } + + emit TransferSingle(operator, from, address(0), id, amount); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + */ + function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { + require(from != address(0), "ERC1155WithTerminusStorage: burn from the zero address"); + require(ids.length == amounts.length, "ERC1155WithTerminusStorage: ids and amounts length mismatch"); + + address operator = _msgSender(); + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + for (uint256 i = 0; i < ids.length; i++) { + require(ts.poolBurnable[ids[i]], "ERC1155WithTerminusStorage: _burnBatch -- pool is not burnable"); + } + + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); + + for (uint256 i = 0; i < ids.length; i++) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = ts.poolBalances[id][from]; + require(fromBalance >= amount, "ERC1155WithTerminusStorage: burn amount exceeds balance"); + unchecked { + ts.poolBalances[id][from] = fromBalance - amount; + ts.poolSupply[id] -= amount; + } + } + + emit TransferBatch(operator, from, address(0), ids, amounts); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits a {ApprovalForAll} event. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + require(owner != operator, "ERC1155WithTerminusStorage: setting approval status for self"); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.globalOperatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) private { + if (to.code.length > 0) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + revert("ERC1155WithTerminusStorage: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155WithTerminusStorage: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) private { + if (to.code.length > 0) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( + bytes4 response + ) { + if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + revert("ERC1155WithTerminusStorage: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155WithTerminusStorage: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { + uint256[] memory array = new uint256[](1); + array[0] = element; + + return array; + } +} diff --git a/web3/contracts/security/terminus/LibTerminus.sol b/web3/contracts/security/terminus/LibTerminus.sol new file mode 100644 index 00000000..b83c3305 --- /dev/null +++ b/web3/contracts/security/terminus/LibTerminus.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + * Common storage structure and internal methods for Moonstream DAO Terminus contracts. + * As Terminus is an extension of ERC1155, this library can also be used to implement bare ERC1155 contracts + * using the common storage pattern (e.g. for use in diamond proxies). + */ + +pragma solidity ^0.8.9; + +library LibTerminus { + bytes32 constant TERMINUS_STORAGE_POSITION = keccak256("game7.storage.terminus"); + + struct TerminusStorage { + // Terminus administration + address controller; + bool isTerminusActive; + uint256 currentPoolID; + address paymentToken; + uint256 poolBasePrice; + // Terminus pools + mapping(uint256 => address) poolController; + mapping(uint256 => string) poolURI; + mapping(uint256 => uint256) poolCapacity; + mapping(uint256 => uint256) poolSupply; + mapping(uint256 => mapping(address => uint256)) poolBalances; + mapping(uint256 => bool) poolNotTransferable; + mapping(uint256 => bool) poolBurnable; + mapping(address => mapping(address => bool)) globalOperatorApprovals; + mapping(uint256 => mapping(address => bool)) globalPoolOperatorApprovals; + // Contract metadata + string contractURI; + } + + function terminusStorage() internal pure returns (TerminusStorage storage es) { + bytes32 position = TERMINUS_STORAGE_POSITION; + assembly { + es.slot := position + } + } + + event ControlTransferred(address indexed previousController, address indexed newController); + + event PoolControlTransferred( + uint256 indexed poolID, + address indexed previousController, + address indexed newController + ); + + function setController(address newController) internal { + TerminusStorage storage ts = terminusStorage(); + address previousController = ts.controller; + ts.controller = newController; + emit ControlTransferred(previousController, newController); + } + + function enforceIsController() internal view { + TerminusStorage storage ts = terminusStorage(); + require(msg.sender == ts.controller, "LibTerminus: Must be controller"); + } + + function setTerminusActive(bool active) internal { + TerminusStorage storage ts = terminusStorage(); + ts.isTerminusActive = active; + } + + function setPoolController(uint256 poolID, address newController) internal { + TerminusStorage storage ts = terminusStorage(); + address previousController = ts.poolController[poolID]; + ts.poolController[poolID] = newController; + emit PoolControlTransferred(poolID, previousController, newController); + } + + function createSimplePool(uint256 _capacity) internal returns (uint256) { + TerminusStorage storage ts = terminusStorage(); + uint256 poolID = ts.currentPoolID + 1; + setPoolController(poolID, msg.sender); + ts.poolCapacity[poolID] = _capacity; + ts.currentPoolID++; + return poolID; + } + + function enforcePoolIsController(uint256 poolID, address maybeController) internal view { + TerminusStorage storage ts = terminusStorage(); + require(ts.poolController[poolID] == maybeController, "LibTerminus: Must be pool controller"); + } + + function _isApprovedForPool(uint256 poolID, address operator) internal view returns (bool) { + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + if (operator == ts.poolController[poolID]) { + return true; + } else if (ts.globalPoolOperatorApprovals[poolID][operator]) { + return true; + } + return false; + } + + function _approveForPool(uint256 poolID, address operator) internal { + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.globalPoolOperatorApprovals[poolID][operator] = true; + } + + function _unapproveForPool(uint256 poolID, address operator) internal { + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.globalPoolOperatorApprovals[poolID][operator] = false; + } +} diff --git a/web3/contracts/security/terminus/TerminusFacet.sol b/web3/contracts/security/terminus/TerminusFacet.sol new file mode 100644 index 00000000..070e6755 --- /dev/null +++ b/web3/contracts/security/terminus/TerminusFacet.sol @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: MIT + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + * This is an implementation of the Terminus decentralized authorization contract. + * + * Terminus users can create authorization pools. Each authorization pool has the following properties: + * 1. Controller: The address that controls the pool. Initially set to be the address of the pool creator. + * 2. Pool URI: Metadata URI for the authorization pool. + * 3. Pool capacity: The total number of tokens that can be minted in that authorization pool. + * 4. Pool supply: The number of tokens that have actually been minted in that authorization pool. + * 5. Transferable: A boolean value which denotes whether or not tokens from that pool can be transfered + * between addresses. (Note: Implemented by TerminusStorage.poolNotTransferable since we expect most + * pools to be transferable. This negation is better for storage + gas since false is default value + * in map to bool.) + * 6. Burnable: A boolean value which denotes whether or not tokens from that pool can be burned. + */ + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./ERC1155WithTerminusStorage.sol"; +import "./LibTerminus.sol"; +import "./TerminusInitializer.sol"; +import { LibDiamond } from "../../utils/diamonds/contracts/libraries/LibDiamond.sol"; + +contract TerminusFacet is ERC1155WithTerminusStorage, TerminusInitializer { + constructor() { + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.controller = msg.sender; + } + + event PoolMintBatch( + uint256 indexed id, + address indexed operator, + address from, + address[] toAddresses, + uint256[] amounts + ); + + function setController(address newController) external { + LibTerminus.enforceIsController(); + LibTerminus.setController(newController); + } + + function poolMintBatch(uint256 id, address[] memory toAddresses, uint256[] memory amounts) public { + require( + toAddresses.length == amounts.length, + "TerminusFacet: _poolMintBatch -- toAddresses and amounts length mismatch" + ); + address operator = _msgSender(); + require( + isApprovedForPool(id, operator), + "TerminusFacet: poolMintBatch -- caller is neither owner nor approved" + ); + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + + uint256 i = 0; + uint256 totalAmount = 0; + + for (i = 0; i < toAddresses.length; i++) { + address to = toAddresses[i]; + uint256 amount = amounts[i]; + require(to != address(0), "TerminusFacet: _poolMintBatch -- cannot mint to zero address"); + totalAmount += amount; + ts.poolBalances[id][to] += amount; + emit TransferSingle(operator, address(0), to, id, amount); + } + + require( + ts.poolSupply[id] + totalAmount <= ts.poolCapacity[id], + "TerminusFacet: _poolMintBatch -- Minted tokens would exceed pool capacity" + ); + ts.poolSupply[id] += totalAmount; + + emit PoolMintBatch(id, operator, address(0), toAddresses, amounts); + } + + function terminusController() external view returns (address) { + return LibTerminus.terminusStorage().controller; + } + + function paymentToken() external view returns (address) { + return LibTerminus.terminusStorage().paymentToken; + } + + function setPaymentToken(address newPaymentToken) external { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.paymentToken = newPaymentToken; + } + + function poolBasePrice() external view returns (uint256) { + return LibTerminus.terminusStorage().poolBasePrice; + } + + function setPoolBasePrice(uint256 newBasePrice) external { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.poolBasePrice = newBasePrice; + } + + function _paymentTokenContract() internal view returns (IERC20) { + address paymentTokenAddress = LibTerminus.terminusStorage().paymentToken; + require(paymentTokenAddress != address(0), "TerminusFacet: Payment token has not been set"); + return IERC20(paymentTokenAddress); + } + + function withdrawPayments(address toAddress, uint256 amount) external { + LibTerminus.enforceIsController(); + require(_msgSender() == toAddress, "TerminusFacet: withdrawPayments -- Controller can only withdraw to self"); + IERC20 paymentTokenContract = _paymentTokenContract(); + paymentTokenContract.transfer(toAddress, amount); + } + + function contractURI() public view returns (string memory) { + return LibTerminus.terminusStorage().contractURI; + } + + function setContractURI(string memory _contractURI) external { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.contractURI = _contractURI; + } + + function setURI(uint256 poolID, string memory poolURI) external { + LibTerminus.enforcePoolIsController(poolID, _msgSender()); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.poolURI[poolID] = poolURI; + } + + function totalPools() external view returns (uint256) { + return LibTerminus.terminusStorage().currentPoolID; + } + + function setPoolController(uint256 poolID, address newController) external { + LibTerminus.enforcePoolIsController(poolID, msg.sender); + LibTerminus.setPoolController(poolID, newController); + } + + function terminusPoolController(uint256 poolID) external view returns (address) { + return LibTerminus.terminusStorage().poolController[poolID]; + } + + function terminusPoolCapacity(uint256 poolID) external view returns (uint256) { + return LibTerminus.terminusStorage().poolCapacity[poolID]; + } + + function terminusPoolSupply(uint256 poolID) external view returns (uint256) { + return LibTerminus.terminusStorage().poolSupply[poolID]; + } + + function poolIsTransferable(uint256 poolID) external view returns (bool) { + return !LibTerminus.terminusStorage().poolNotTransferable[poolID]; + } + + function poolIsBurnable(uint256 poolID) external view returns (bool) { + return LibTerminus.terminusStorage().poolBurnable[poolID]; + } + + function setPoolTransferable(uint256 poolID, bool transferable) external { + LibTerminus.enforcePoolIsController(poolID, msg.sender); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.poolNotTransferable[poolID] = !transferable; + } + + function setPoolBurnable(uint256 poolID, bool burnable) external { + LibTerminus.enforcePoolIsController(poolID, msg.sender); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.poolBurnable[poolID] = burnable; + } + + function createSimplePool(uint256 _capacity) external returns (uint256) { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + uint256 requiredPayment = ts.poolBasePrice; + + if (requiredPayment > 0) { + IERC20 paymentTokenContract = _paymentTokenContract(); + require( + paymentTokenContract.allowance(_msgSender(), address(this)) >= requiredPayment, + "TerminusFacet: createSimplePool -- Insufficient allowance on payment token" + ); + require( + paymentTokenContract.transferFrom(msg.sender, address(this), requiredPayment), + "TerminusFacet: createSimplePool -- Transfer of payment token was unsuccessful" + ); + } + return LibTerminus.createSimplePool(_capacity); + } + + function createPoolV1(uint256 _capacity, bool _transferable, bool _burnable) external returns (uint256) { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + uint256 requiredPayment = ts.poolBasePrice; + if (requiredPayment > 0) { + IERC20 paymentTokenContract = _paymentTokenContract(); + require( + paymentTokenContract.allowance(_msgSender(), address(this)) >= requiredPayment, + "TerminusFacet: createPoolV1 -- Insufficient allowance on payment token" + ); + require( + paymentTokenContract.transferFrom(msg.sender, address(this), requiredPayment), + "TerminusFacet: createPoolV1 -- Transfer of payment token was unsuccessful" + ); + } + uint256 poolID = LibTerminus.createSimplePool(_capacity); + if (!_transferable) { + ts.poolNotTransferable[poolID] = true; + } + if (_burnable) { + ts.poolBurnable[poolID] = true; + } + return poolID; + } + + function createPoolV2( + uint256 _capacity, + bool _transferable, + bool _burnable, + string memory poolURI + ) external returns (uint256) { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + uint256 requiredPayment = ts.poolBasePrice; + if (requiredPayment > 0) { + IERC20 paymentTokenContract = _paymentTokenContract(); + require( + paymentTokenContract.allowance(_msgSender(), address(this)) >= requiredPayment, + "TerminusFacet: createPoolV2 -- Insufficient allowance on payment token" + ); + require( + paymentTokenContract.transferFrom(msg.sender, address(this), requiredPayment), + "TerminusFacet: createPoolV2 -- Transfer of payment token was unsuccessful" + ); + } + uint256 poolID = LibTerminus.createSimplePool(_capacity); + if (!_transferable) { + ts.poolNotTransferable[poolID] = true; + } + if (_burnable) { + ts.poolBurnable[poolID] = true; + } + ts.poolURI[poolID] = poolURI; + return poolID; + } + + function mint(address to, uint256 poolID, uint256 amount, bytes memory data) external { + require(isApprovedForPool(poolID, msg.sender), "TerminusFacet: mint -- caller is neither owner nor approved"); + _mint(to, poolID, amount, data); + } + + function mintBatch(address to, uint256[] memory poolIDs, uint256[] memory amounts, bytes memory data) external { + for (uint256 i = 0; i < poolIDs.length; i++) { + require( + isApprovedForPool(poolIDs[i], msg.sender), + "TerminusFacet: mintBatch -- caller is neither owner nor approved" + ); + } + _mintBatch(to, poolIDs, amounts, data); + } + + function burn(address from, uint256 poolID, uint256 amount) external { + address operator = _msgSender(); + require( + operator == from || isApprovedForPool(poolID, operator), + "TerminusFacet: burn -- caller is neither owner nor approved" + ); + _burn(from, poolID, amount); + } +} diff --git a/web3/contracts/security/terminus/TerminusInitializer.sol b/web3/contracts/security/terminus/TerminusInitializer.sol new file mode 100644 index 00000000..5678d9d2 --- /dev/null +++ b/web3/contracts/security/terminus/TerminusInitializer.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +/** + * Authors: Game7 Engineering + * + * Initializer for Terminus contract. Used when mounting a new TerminusFacet onto its diamond proxy. + */ + +pragma solidity ^0.8.9; + +import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; +import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol"; +import { LibDiamond as LibDiamond } from "../../utils/diamonds/contracts/libraries/LibDiamond.sol"; +import "./LibTerminus.sol"; + +contract TerminusInitializer { + function init() external { + LibDiamond.enforceIsContractOwner(); + LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); + ds.supportedInterfaces[type(IERC1155).interfaceId] = true; + ds.supportedInterfaces[type(IERC1155MetadataURI).interfaceId] = true; + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.controller = msg.sender; + } +} diff --git a/web3/contracts/security/terminus/TerminusPermissions.sol b/web3/contracts/security/terminus/TerminusPermissions.sol new file mode 100644 index 00000000..b96a7309 --- /dev/null +++ b/web3/contracts/security/terminus/TerminusPermissions.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +/** + * Authors: Game7 Engineering + */ + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "./interfaces/ITerminus.sol"; + + +pragma solidity ^0.8.9; + +abstract contract TerminusPermissions { + function _holdsPoolToken(address terminusAddress, uint256 poolId, uint256 _amount) internal view returns (bool) { + return ITerminus(terminusAddress).balanceOf(msg.sender, poolId) >= _amount; + } + + modifier holdsPoolToken(address terminusAddress, uint256 poolId) { + require( + _holdsPoolToken(terminusAddress, poolId, 1), + "TerminusPermissions.holdsPoolToken: Sender doens't hold pool tokens" + ); + _; + } + + modifier spendsPoolToken(address terminusAddress, uint256 poolId) { + require( + _holdsPoolToken(terminusAddress, poolId, 1), + "TerminusPermissions.spendsPoolToken: Sender doens't hold pool tokens" + ); + ITerminus(terminusAddress).burn(msg.sender, poolId, 1); + _; + } +} diff --git a/web3/contracts/security/terminus/interfaces/ITerminus.sol b/web3/contracts/security/terminus/interfaces/ITerminus.sol new file mode 100644 index 00000000..55615f7c --- /dev/null +++ b/web3/contracts/security/terminus/interfaces/ITerminus.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.9; + +// Interface generated by solface: https://github.com/moonstream-to/solface +// solface version: 0.1.0 +// Interface ID: dbbee324 +interface ITerminus { + // structs + + // events + event ApprovalForAll(address account, address operator, bool approved); + event PoolMintBatch(uint256 id, address operator, address from, address[] toAddresses, uint256[] amounts); + event TransferBatch(address operator, address from, address to, uint256[] ids, uint256[] values); + event TransferSingle(address operator, address from, address to, uint256 id, uint256 value); + event URI(string value, uint256 id); + + // functions + // Selector: 85bc82e2 + function approveForPool(uint256 poolID, address operator) external; + // Selector: 00fdd58e + function balanceOf(address account, uint256 id) external view returns (uint256); + // Selector: 4e1273f4 + function balanceOfBatch(address[] memory accounts, uint256[] memory ids) external view returns (uint256[] memory); + // Selector: f5298aca + function burn(address from, uint256 poolID, uint256 amount) external; + // Selector: e8a3d485 + function contractURI() external view returns (string memory); + // Selector: 3bad2d82 + function createPoolV1(uint256 _capacity, bool _transferable, bool _burnable) external returns (uint256); + // Selector: 84fa03a1 + function createPoolV2( + uint256 _capacity, + bool _transferable, + bool _burnable, + string memory poolURI + ) external returns (uint256); + // Selector: b507ef52 + function createSimplePool(uint256 _capacity) external returns (uint256); + // Selector: e985e9c5 + function isApprovedForAll(address account, address operator) external view returns (bool); + // Selector: 027b3fc2 + function isApprovedForPool(uint256 poolID, address operator) external view returns (bool); + // Selector: 731133e9 + function mint(address to, uint256 poolID, uint256 amount, bytes memory data) external; + // Selector: 1f7fdffa + function mintBatch(address to, uint256[] memory poolIDs, uint256[] memory amounts, bytes memory data) external; + // Selector: 3013ce29 + function paymentToken() external view returns (address); + // Selector: 8925d013 + function poolBasePrice() external view returns (uint256); + // Selector: 3c50a3c5 + function poolIsBurnable(uint256 poolID) external view returns (bool); + // Selector: 69453ce9 + function poolIsTransferable(uint256 poolID) external view returns (bool); + // Selector: 21adca96 + function poolMintBatch(uint256 id, address[] memory toAddresses, uint256[] memory amounts) external; + // Selector: 2eb2c2d6 + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) external; + // Selector: f242432a + function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) external; + // Selector: a22cb465 + function setApprovalForAll(address operator, bool approved) external; + // Selector: 938e3d7b + function setContractURI(string memory _contractURI) external; + // Selector: 92eefe9b + function setController(address newController) external; + // Selector: 6a326ab1 + function setPaymentToken(address newPaymentToken) external; + // Selector: 78cf2e84 + function setPoolBasePrice(uint256 newBasePrice) external; + // Selector: 2365c859 + function setPoolBurnable(uint256 poolID, bool burnable) external; + // Selector: dc55d0b2 + function setPoolController(uint256 poolID, address newController) external; + // Selector: f3dc0a85 + function setPoolTransferable(uint256 poolID, bool transferable) external; + // Selector: 862440e2 + function setURI(uint256 poolID, string memory poolURI) external; + // Selector: 01ffc9a7 + function supportsInterface(bytes4 interfaceId) external view returns (bool); + // Selector: 366e59e3 + function terminusController() external view returns (address); + // Selector: 5dc8bdf8 + function terminusPoolCapacity(uint256 poolID) external view returns (uint256); + // Selector: d0c402e5 + function terminusPoolController(uint256 poolID) external view returns (address); + // Selector: a44cfc82 + function terminusPoolSupply(uint256 poolID) external view returns (uint256); + // Selector: ab3c7e52 + function totalPools() external view returns (uint256); + // Selector: 1fbeae86 + function unapproveForPool(uint256 poolID, address operator) external; + // Selector: 0e89341c + function uri(uint256 poolID) external view returns (string memory); + // Selector: 0e7afec5 + function withdrawPayments(address toAddress, uint256 amount) external; + + // errors +} diff --git a/web3/contracts/utils/diamonds b/web3/contracts/utils/diamonds new file mode 160000 index 00000000..08d415c7 --- /dev/null +++ b/web3/contracts/utils/diamonds @@ -0,0 +1 @@ +Subproject commit 08d415c7e1a27c811c34875d9263a90bc719cee3 diff --git a/web3/scripts/deploy-terminus.md b/web3/scripts/deploy-terminus.md new file mode 100644 index 00000000..32694ba0 --- /dev/null +++ b/web3/scripts/deploy-terminus.md @@ -0,0 +1,71 @@ +# Deploy terminus diamond contract + +This checklist describes how to deploy the Terminus diamond contract. + +## RPC urls + +```json +{ + "rpcUrls": { + "ArbitrumSepolia": "https://sepolia-rollup.arbitrum.io/rpc", + "ArbitrumOrbitConduit": "https://rpc-game7-arb-anytrust-wcj9hysn7y.t.conduit.xyz", + "ArbitrumOrbitCaldera": "https://game7-testnet.hub.caldera.xyz/", + }, +} +``` + +## Environment variables + +- [ ] `export RPC=` +- [ ] `export KEY=` +- [ ] `export OWNER=` +- [ ] `export BADGE=` +- [ ] `export TERMINUS=` + +## Deploy Terminus contract + +- [ ] Deploy Terminus contract + +```bash +bin/game7 terminus deploy \ + --rpc $RPC \ + --keyfile $KEY \ + --contract-owner $OWNER + +``` + +- [ ] Create admin pool + +```bash +bin/game7 terminus terminus-facet create-pool-v-2 \ + --rpc $RPC \ + --keyfile $KEY \ + --contract $TERMINUS \ + --burnable 1 \ + --capacity $(python3 -c "print(2**256 -1)") \ + --transferable 0 \ + --pool-uri $BADGE +``` + +- [ ] Confirm Admin pool id + +```bash +bin/game7 terminus terminus-facet total-pools \ + --rpc $RPC \ + --contract $TERMINUS +``` +Output: 1 + + +- [ ] Mint admin badage to OWNER + +```bash +bin/game7 terminus terminus-facet mint \ + --rpc $RPC \ + --keyfile $KEY \ + --contract $TERMINUS \ + --to-0 $OWNER \ + --pool-id 1 \ + --amount 1 \ + --data "" +``` \ No newline at end of file diff --git a/web3/scripts/staker.game7-testnet.md b/web3/scripts/staker.game7-testnet.md index 2c385cd5..ff29ee6e 100644 --- a/web3/scripts/staker.game7-testnet.md +++ b/web3/scripts/staker.game7-testnet.md @@ -2,9 +2,13 @@ ### Details -`Staker` contract address on Game7 testnet is `0xA1D917972df7E88904A2aaFd92f5c0dF16ABA77e`. +`Staker` contract address on Game7 testnet is `0x3aFE96deaA3559405F865F32c0d979b20EC8753b`. -Deployed in transaction [`0xfaaf6455fa781fb85e4dde990ffb951b7e367245817e5ad5cf5f36e93346dff7`](https://explorer-game7-testnet-0ilneybprf.t.conduit.xyz/tx/0xfaaf6455fa781fb85e4dde990ffb951b7e367245817e5ad5cf5f36e93346dff7). +Deployed in transaction [`0x981775334b3b80fd70c2278f7bc4dc05dc9f16be3579b47f173467df44104fd2`](https://explorer-game7-testnet-0ilneybprf.t.conduit.xyz/tx/0x981775334b3b80fd70c2278f7bc4dc05dc9f16be3579b47f173467df44104fd2). + +`PositionMetadata` contract address on Game7 testnet is `0x5dF0f705864980Ee890FeBEF0C67c41e7fc5F791` + +Deployed in transaction [`0xc6f5c2533b55ab8161538a6a74d2146e123740077c77b85cf901bcbe8ee537da`](https://explorer-game7-testnet-0ilneybprf.t.conduit.xyz/tx/0xc6f5c2533b55ab8161538a6a74d2146e123740077c77b85cf901bcbe8ee537da). Staking pool for native token with a 60 second lockup and no cooldown has pool ID `0`. Positions in this staking pool are transferable. This pool is owned by the zero address, and cannot be modified. @@ -13,26 +17,74 @@ staking pool are transferable. This pool is owned by the zero address, and canno ```bash export RPC="https://testnet-rpc.game7.io" -export SENDER="" +export KEYFILE="" # The following lines were added in the course of this script export STAKER="0xA1D917972df7E88904A2aaFd92f5c0dF16ABA77e" export NATIVE_TOKEN_STAKING_POOL_ID="0" +export POSITION_METADATA='0x5dF0f705864980Ee890FeBEF0C67c41e7fc5F791' +export ADMINISTRATOR='0xfbca6f618bf24eb5fc1ac544ae2f70b24ffd0e15' +``` + +### Deploy Staker Metadata contract + +- [x] Deploy contract +- [x] Verify contract + +```bash +bin/game7 staker-metadata deploy \ + --rpc $RPC \ + --keyfile $KEYFILE +``` + +```bash +cd web3 +forge verify-contract \ + --rpc-url https://testnet-rpc.game7.io \ + --verifier blockscout \ + --verifier-url 'https://testnet.game7.io/api/' \ + --compiler-version '0.8.24' \ + --optimizer-runs '99999' \ + 0x5dF0f705864980Ee890FeBEF0C67c41e7fc5F791 \ + contracts/staking/PositionMetadata.sol:PositionMetadata +cd .. +``` +- [x] Record `PositionMetadata` contract address + +```bash +export POSITION_METADATA='0x5dF0f705864980Ee890FeBEF0C67c41e7fc5F791' ``` -### Deploy contract +- [x] Update `PositionMetadata` contract address and deployment transaction hash at top of the file. + +### Deploy Staker contract - [x] Deploy contract +- [x] Verify contract ```bash bin/game7 staker deploy \ --rpc $RPC \ - --sender $SENDER + --keyfile $KEYFILE \ + --position-metadata $POSITION_METADATA +``` + +```bash +cd web3 +forge verify-contract \ + --rpc-url https://testnet-rpc.game7.io \ + --verifier blockscout \ + --verifier-url 'https://testnet.game7.io/api/' \ + --compiler-version '0.8.24' \ + --optimizer-runs '99999' \ + 0x3aFE96deaA3559405F865F32c0d979b20EC8753b \ + contracts/staking/Staker.sol:Staker +cd .. ``` - [x] Record `Staker` contract address ```bash -export STAKER="0xA1D917972df7E88904A2aaFd92f5c0dF16ABA77e" +export STAKER="0x3aFE96deaA3559405F865F32c0d979b20EC8753b" ``` - [x] Update `Staker` contract address and deployment transaction hash at top of the file. @@ -45,13 +97,14 @@ export STAKER="0xA1D917972df7E88904A2aaFd92f5c0dF16ABA77e" bin/game7 staker create-pool \ --contract $STAKER \ --rpc $RPC \ - --keyfile $SENDER \ + --keyfile $KEYFILE \ --token-address 0x0000000000000000000000000000000000000000 \ --token-id 0 \ --token-type 1 \ --transferable y \ --lockup-seconds 60 \ - --cooldown-seconds 0 + --cooldown-seconds 0 \ + --administrator $ADMINISTRATOR ``` - [x] Total number of pools should now be 1 @@ -80,12 +133,12 @@ bin/game7 staker pools \ Result: ``` -0: {0x9ed191DB1829371F116Deb9748c26B49467a592A 1 0x0000000000000000000000000000000000000000 0 true 60 0} +0: {0xfBca6F618BF24eB5FC1aC544ae2F70b24fFD0e15 1 0x0000000000000000000000000000000000000000 0 true 60 0} ``` - [x] Export default native token staking pool ID -``` +```bash export NATIVE_TOKEN_STAKING_POOL_ID="0" ``` @@ -97,7 +150,7 @@ export NATIVE_TOKEN_STAKING_POOL_ID="0" bin/game7 staker transfer-pool-administration \ --contract $STAKER \ --rpc $RPC \ - --keyfile $SENDER \ + --keyfile $KEYFILE \ --pool-id 0 \ --new-administrator 0x0000000000000000000000000000000000000000 ``` @@ -133,18 +186,24 @@ Result: 0: 0 ``` -- [x] Stake 1000000000000000000 wei worth of TG7 into the pool +- [x] Stake 100000000000000000 wei worth of TG7 into the pool + +```bash +export POSITION_HOLDER='0xfbca6f618bf24eb5fc1ac544ae2f70b24ffd0e15' +``` + ```bash bin/game7 staker stake-native \ --contract $STAKER \ --rpc $RPC \ - --keyfile $SENDER \ + --keyfile $KEYFILE \ --pool-id $NATIVE_TOKEN_STAKING_POOL_ID \ - --value 1000000000000000000 + --position-holder $POSITION_HOLDER \ + --value 100000000000000000 ``` -Transaction: [`0x54c29d4bb3c7aff7e290a0fcdf9b07eba2fabfbda3c09201ecb9f127d4851e1d`](https://explorer-game7-testnet-0ilneybprf.t.conduit.xyz/tx/0x54c29d4bb3c7aff7e290a0fcdf9b07eba2fabfbda3c09201ecb9f127d4851e1d) +Transaction: [`0x26f0b702bdbef7d34aa5021e9c32e940ebbae0426f9d2214d8f105a8f5606beb`](https://explorer-game7-testnet-0ilneybprf.t.conduit.xyz/tx/0x26f0b702bdbef7d34aa5021e9c32e940ebbae0426f9d2214d8f105a8f5606beb) - [x] Check the number of staking positions that exist on the contract @@ -172,7 +231,7 @@ bin/game7 staker owner-of \ Result: ``` -0: 0x9ed191DB1829371F116Deb9748c26B49467a592A +0: 0xfBca6F618BF24eB5FC1aC544ae2F70b24fFD0e15 ``` - [x] Read the position information for this position @@ -187,7 +246,7 @@ bin/game7 staker positions \ Result: ``` -0: {0 1000000000000000000 1721529000 0} +0: {0 100000000000000000 1732046370 0} ``` - [x] Unstake the position @@ -196,8 +255,8 @@ Result: bin/game7 staker unstake \ --contract $STAKER \ --rpc $RPC \ - --keyfile $SENDER \ + --keyfile $KEYFILE \ --position-token-id 0 ``` -Transaction: [`0xb6e7968c15e651fbd0055bb3a7fc1d8f5d2affaa7c5b9942a979e8f0b4d8918d`](https://explorer-game7-testnet-0ilneybprf.t.conduit.xyz/tx/0xb6e7968c15e651fbd0055bb3a7fc1d8f5d2affaa7c5b9942a979e8f0b4d8918d) +Transaction: [`0xc164c8f5db6a197577f44018daee43ba9b67c4d43080e2e41cb63fb02c123c3a`](https://explorer-game7-testnet-0ilneybprf.t.conduit.xyz/tx/0xc164c8f5db6a197577f44018daee43ba9b67c4d43080e2e41cb63fb02c123c3a) diff --git a/web3/test/Terminus.test.ts b/web3/test/Terminus.test.ts new file mode 100644 index 00000000..ea45751b --- /dev/null +++ b/web3/test/Terminus.test.ts @@ -0,0 +1,1221 @@ +import { ethers } from 'hardhat'; +import { expect } from 'chai'; +import { HardhatEthersSigner } from '../helpers/type'; +import { deployTerminusDiamond } from './fixtures/terminus.fixture'; + + +describe('Terminus', async function () { + + let terminusFacet: any; + let terminusFacetAddress: string; + let erc20: any; + let erc20Address: string; + let admin0: HardhatEthersSigner; + let admin1: HardhatEthersSigner; + let user0: HardhatEthersSigner; + let user1: HardhatEthersSigner; + let user2: HardhatEthersSigner; + + beforeEach(async function () { + [admin0, admin1, user0, user1, user2] = await ethers.getSigners(); + terminusFacet = await deployTerminusDiamond(); + terminusFacetAddress = await terminusFacet.getAddress(); + const ERC20 = await ethers.getContractFactory('MockERC20'); + erc20 = await ERC20.deploy(); + erc20.waitForDeployment(); + erc20Address = erc20.getAddress(); + await terminusFacet.connect(admin0).setPaymentToken(erc20Address); + await terminusFacet.connect(admin0).setPoolBasePrice(1000); + await erc20.mint(admin0.address, 1000) + await erc20.connect(admin0).approve(terminusFacetAddress, 1000); + }); + describe('Terminus Deployment and Set up', async function () { + it('Terminus-1: Anyone should be able to deploy Terminus and be admin0', async function () { + expect(terminusFacetAddress).to.be.properAddress; + const controller = await terminusFacet.terminusController(); + expect(controller).to.equal(admin0.address); + }) + it('Terminus-2: Can set new admin0', async function () { + await terminusFacet.setController(admin1); + const controller = await terminusFacet.terminusController(); + expect(controller).to.equal(admin1.address); + }) + it('Terminus-3: Non-admin0 attempts to set new admin0', async function () { + await expect(await terminusFacet.terminusController()).to.equal(admin0.address); + await expect(terminusFacet.connect(admin1).setController(admin1.address)).to.be.reverted; + }) + it('Terminus-4: Set contract URI', async function () { + let contractURI = await terminusFacet.contractURI(); + expect(contractURI).to.equal(""); + + await terminusFacet.connect(admin0).setContractURI("https://example.com"); + + contractURI = await terminusFacet.contractURI(); + + expect(contractURI).to.equal("https://example.com"); + + }) + }) + + + + describe('Terminus Pool Creation', async function () { + + //test written with aid chat gpt-4 + it('Terminus-5: Simple Pool Creation and validate balance', async function () { + + const poolBasePrice = await terminusFacet.connect(admin0).poolBasePrice(); + expect(poolBasePrice).to.equal(1000); + + // Store initial values + const initialAdmin0Balance = await erc20.balanceOf(admin0.address); + const initialTerminusBalance = await erc20.balanceOf(terminusFacetAddress); + const initialTotalPools = await terminusFacet.totalPools(); + + // Create a simple pool + await terminusFacet.connect(admin0).createSimplePool(10); + + // Verify that the total pool count increased by 1 + const finalTotalPools = await terminusFacet.totalPools(); + expect(finalTotalPools).to.equal(initialTotalPools + BigInt(1)); + + // Verify balances after creating the pool + const intermediateTerminusBalance = await erc20.balanceOf(terminusFacetAddress); + const intermediateAdmin0Balance = await erc20.balanceOf(admin0.address); + expect(intermediateAdmin0Balance).to.equal(initialAdmin0Balance - poolBasePrice); + expect(intermediateTerminusBalance).to.equal(initialTerminusBalance + poolBasePrice); + + // Unauthorized withdrawals should revert + await expect( + terminusFacet.connect(admin0).withdrawPayments(admin1.address, 1000) + ).to.be.reverted; + await expect( + terminusFacet.connect(admin1).withdrawPayments(admin0.address, 1000) + ).to.be.reverted; + await expect( + terminusFacet.connect(admin1).withdrawPayments(admin1.address, 1000) + ).to.be.reverted; + + // Authorized withdrawal by the admin0 + await terminusFacet.connect(admin0).withdrawPayments(admin0.address, 1000); + + // Verify balances after withdrawal + const finalAdmin0Balance = await erc20.balanceOf(admin0.address); + const finalTerminusBalance = await erc20.balanceOf(terminusFacetAddress); + expect(finalTerminusBalance).to.equal(intermediateTerminusBalance - poolBasePrice); + expect(finalAdmin0Balance).to.equal(intermediateAdmin0Balance + poolBasePrice); + + // Attempt to overdraw should revert + await expect( + terminusFacet.connect(admin0).withdrawPayments(admin0.address, poolBasePrice) + ).to.be.reverted; + + // Check the pool admin0 and capacity + const pooladmin0 = await terminusFacet.terminusPoolController(finalTotalPools); + expect(pooladmin0).to.equal(admin0.address); + const poolCapacity = await terminusFacet.terminusPoolCapacity(finalTotalPools); + expect(poolCapacity).to.equal(10); + }) + }) + + describe('Test Pool Operations', async function () { + + + + it("Terminus-6: Should correctly set and revert pool controller changes", async function () { + + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + + // Set the initial controller for the pool to `admin1` + await terminusFacet.connect(admin0).setPoolController(poolId, admin1.address); + + // Verify that the current pool controller is `oldController` + let currentControllerAddress = await terminusFacet.terminusPoolController(poolId); + expect(currentControllerAddress).to.equal(admin1.address); + + // Attempting to set a new controller from `newController` (unauthorized) + await expect( + terminusFacet.connect(user0).setPoolController(poolId, user0.address) + ).to.be.reverted; + + // Verify that the pool controller hasn't changed + currentControllerAddress = await terminusFacet.terminusPoolController(poolId); + expect(currentControllerAddress).to.equal(admin1.address); + + // Authorized change of pool controller from `admin1` to `user0` + await terminusFacet.connect(admin1).setPoolController(poolId, user0.address); + + // Verify the pool controller has been updated to `user0` + currentControllerAddress = await terminusFacet.terminusPoolController(poolId); + expect(currentControllerAddress).to.equal(user0.address); + + // Attempting to set the controller back to `admin1` by `admin1` (unauthorized) + await expect( + terminusFacet.connect(admin1).setPoolController(poolId, admin1.address) + ).to.be.reverted; + + // Verify that the controller remains `user0` + currentControllerAddress = await terminusFacet.terminusPoolController(poolId); + expect(currentControllerAddress).to.equal(user0.address); + + // Authorized change of pool controller back to `admin1` by `user0` + await terminusFacet.connect(user0).setPoolController(poolId, admin1.address); + + // Verify the controller has reverted back to `admin1` + currentControllerAddress = await terminusFacet.terminusPoolController(poolId); + expect(currentControllerAddress).to.equal(admin1.address); + }); + + it("Terminus-7: Should mint tokens to a specified account and update supply", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to the recipient in the specified pool + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Check the recipient's balance in the pool + const balance = await terminusFacet.balanceOf(user0.address, poolId); + expect(balance).to.equal(1); + + // Verify the total supply in the pool + const supply = await terminusFacet.terminusPoolSupply(poolId); + expect(supply).to.equal(1); + }); + + it("Terminus-8: Should fail to mint if it exceeds pool capacity", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + + // Attempt to mint more than the pool's capacity (11 tokens in this case) + await expect( + terminusFacet.connect(admin0).mint(admin1.address, poolId, 11, "0x") + ).to.be.reverted; + + // Check that the recipient's balance and total pool supply remain at 0 + const balance = await terminusFacet.balanceOf(admin1.address, poolId); + expect(balance).to.equal(0); + + const supply = await terminusFacet.terminusPoolSupply(poolId); + expect(supply).to.equal(0); + }); + + it("Terminus-9: Should mint tokens in batch to the specified account and update supply", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + + // Batch mint 1 token to the recipient in the specified pool + await terminusFacet.connect(admin0).mintBatch( + admin1.address, + [poolId], // Array of pool IDs + [1], // Array of amounts corresponding to each pool ID + "0x" // Optional data parameter + ); + + // Check the recipient's balance in the pool + const balance = await terminusFacet.balanceOf(admin1.address, poolId); + expect(balance).to.equal(1); + + // Verify the total supply in the pool + const supply = await terminusFacet.terminusPoolSupply(poolId); + expect(supply).to.equal(1); + }); + + it("Terminus-10: Should only allow minting to approved pools in batch", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const previousPoolId = await terminusFacet.totalPools(); + await erc20.connect(admin0).mint(admin0.address, 1000); + await erc20.connect(admin0).approve(terminusFacetAddress, 1000); + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + + + // Check initial approval status (should be false) + expect(await terminusFacet.isApprovedForPool(poolId, admin1.address)).to.be.false; + expect(await terminusFacet.isApprovedForPool(previousPoolId, admin1.address)).to.be.false; + + // Initial balances and supplies for the user0 in each pool + const balancesBefore = [ + await terminusFacet.balanceOf(user0.address, poolId), + await terminusFacet.balanceOf(user0.address, previousPoolId), + ]; + const suppliesBefore = [ + await terminusFacet.terminusPoolSupply(poolId), + await terminusFacet.terminusPoolSupply(previousPoolId), + ]; + + // Approve the admin1 for one of the pools (poolId) + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + + // Attempt batch minting; should revert because previousPoolId is not approved for admin1 + await expect( + terminusFacet.connect(admin1).mintBatch( + user0.address, + [poolId, previousPoolId], + [1, 1], + "0x" + ) + ).to.be.reverted; + + // Approve the minter for the second pool (previousPoolId) + await terminusFacet.connect(admin0).approveForPool(previousPoolId, admin1.address); + + // Now attempt the batch minting, which should succeed + await terminusFacet.connect(admin1).mintBatch( + user0.address, + [poolId, previousPoolId], + [1, 1], + "0x" + ); + + // Verify updated balances for user0 + const balanceAfterPool1 = await terminusFacet.balanceOf(user0.address, poolId); + const balanceAfterPool2 = await terminusFacet.balanceOf(user0.address, previousPoolId); + expect(balanceAfterPool1).to.equal(balancesBefore[0] + BigInt(1)); + expect(balanceAfterPool2).to.equal(balancesBefore[1] + BigInt(1)); + + // Verify updated supplies for each pool + const supplyAfterPool1 = await terminusFacet.terminusPoolSupply(poolId); + const supplyAfterPool2 = await terminusFacet.terminusPoolSupply(previousPoolId); + expect(supplyAfterPool1).to.equal(suppliesBefore[0] + BigInt(1)); + expect(supplyAfterPool2).to.equal(suppliesBefore[1] + BigInt(1)); + }); + + it("Terminus-11: Should fail batch minting if it exceeds the pool capacity", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const previousPoolId = await terminusFacet.totalPools(); + await erc20.connect(admin0).mint(admin0.address, 1000); + await erc20.connect(admin0).approve(terminusFacetAddress, 1000); + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + await terminusFacet.connect(admin0).approveForPool(previousPoolId, admin1.address); + + // Attempt batch minting that exceeds pool capacity + await expect( + terminusFacet.connect(admin0).mintBatch( + user0.address, + [poolId, previousPoolId], // Same pool ID twice + [11, 11], // Amounts that together exceed capacity + "0x" // Optional data + ) + ).to.be.reverted; + + // Verify that the recipient's balance and total pool supply remain at 0 + const balance = await terminusFacet.balanceOf(user0.address, poolId); + expect(balance).to.equal(0); + + const supply = await terminusFacet.terminusPoolSupply(poolId); + expect(supply).to.equal(0); + }); + it("Terminus-12: Should fail batch minting if it exceeds the pool capacity with single-token mints", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const previousPoolId = await terminusFacet.totalPools(); + await erc20.connect(admin0).mint(admin0.address, 1000); + await erc20.connect(admin0).approve(terminusFacetAddress, 1000); + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + await terminusFacet.connect(admin0).approveForPool(previousPoolId, admin1.address); + + await expect( + terminusFacet.connect(admin0).mintBatch( + user0.address, + [poolId, previousPoolId], // Array of pool IDs + [1, 11], // Array of amounts corresponding to each pool ID + "0x" // Optional data parameter + ) + ).to.be.reverted; + + // Verify that the recipient's balance and total pool supply remain at 0 after the failed mint attempt + const balance = await terminusFacet.balanceOf(user0.address, poolId); + expect(balance).to.equal(0); + + const supply = await terminusFacet.terminusPoolSupply(poolId); + expect(supply).to.equal(0); + }); + + it("Terminus-13: Should mint tokens in batch to multiple accounts and update their balances and supply", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + + + const targetAddresses = [user0.address, user1.address]; + + // Record initial balances and supply for verification + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialBalances = [ + await terminusFacet.balanceOf(user0.address, poolId), + await terminusFacet.balanceOf(user1.address, poolId), + ]; + + // Perform batch minting to multiple accounts + await terminusFacet.connect(admin0).poolMintBatch( + poolId, + targetAddresses, + [1, 1] + ); + + // Verify the final pool supply + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + expect(finalPoolSupply).to.equal(2); + + // Verify final balances for each account + for (let i = 0; i < 2; i++) { + const finalBalance = await terminusFacet.balanceOf(targetAddresses[i], poolId); + expect(finalBalance).to.equal(1); + } + }); + + it("Terminus-14: Should fail batch minting if attempted by the contract controller instead of the pool controller", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).setPoolController(poolId, admin1.address); + + // Prepare target addresses and mint amounts + const targetAddresses = [user0.address, user1.address, user2.address] + const targetAmounts = [1, 1, 1]; + + // Record initial balances and supply for verification + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialBalances = [await terminusFacet.balanceOf(user0.address, poolId), + await terminusFacet.balanceOf(user1.address, poolId), + await terminusFacet.balanceOf(user2.address, poolId)] + + // Attempt batch minting by the contract controller instead of the pool controller + await expect( + terminusFacet.connect(admin0).poolMintBatch( + poolId, + targetAddresses, + targetAmounts + ) + ).to.be.reverted; + + // Verify that the pool supply and target accounts' balances remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + expect(finalPoolSupply).to.equal(initialPoolSupply); + + for (let i = 0; i < targetAddresses.length; i++) { + const finalBalance = await terminusFacet.balanceOf(targetAddresses[i], poolId); + expect(finalBalance).to.equal(initialBalances[i]); + } + }); + it("Terminus-15: Should fail batch minting if attempted by an unauthorized third party", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).setPoolController(poolId, admin1.address); + + // Prepare target addresses and mint amounts + const targetAddresses = [user0.address, user1.address, user2.address] + const targetAmounts = [1, 1, 1]; + + // Record initial balances and supply for verification + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialBalances = [await terminusFacet.balanceOf(user0.address, poolId), + await terminusFacet.balanceOf(user1.address, poolId), + await terminusFacet.balanceOf(user2.address, poolId)] + + // Attempt batch minting by an unauthorized user + await expect( + terminusFacet.connect(user2).poolMintBatch( + poolId, + targetAddresses, + targetAmounts + ) + ).to.be.reverted; + + // Verify that the pool supply and target accounts' balances remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + expect(finalPoolSupply).to.equal(initialPoolSupply); + + for (let i = 0; i < targetAddresses.length; i++) { + const finalBalance = await terminusFacet.balanceOf(targetAddresses[i], poolId); + expect(finalBalance).to.equal(initialBalances[i]); + } + }); + + it("Terminus-16: Should allow minting with pool approval", async function () { + // Create a new pool with controlled minting and without default approval + await terminusFacet.connect(admin0).createPoolV1(10, false, false); + const poolId = await terminusFacet.totalPools(); + + // Verify that the unauthorized user is initially not approved + expect(await terminusFacet.isApprovedForPool(poolId, admin1.address)).to.be.false; + + // Attempt minting by unauthorized user, expecting it to fail + await expect( + terminusFacet.connect(admin1).mint( + admin1.address, + poolId, + 1, + "0x" + ) + ).to.be.reverted; + + // Approve the unauthorized user for minting in the pool + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + + // Record initial balance and supply for verification + const initialSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialBalance = await terminusFacet.balanceOf(admin1.address, poolId); + + // Perform minting with the approved user + await terminusFacet.connect(admin1).mint( + admin1.address, + poolId, + 1, + "0x" + ); + + // Verify final balance and supply are updated as expected + const finalBalance = await terminusFacet.balanceOf(admin1.address, poolId); + const finalSupply = await terminusFacet.terminusPoolSupply(poolId); + expect(finalBalance).to.equal(initialBalance + BigInt(1)); + expect(finalSupply).to.equal(initialSupply + BigInt(1)); + }); + + it("Terminus-17: Should allow transfer of tokens by the pool controller", async function () { + await terminusFacet.connect(admin0).createSimplePool(10); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).setPoolController(poolId, admin1.address); + + // Mint 1 token to recipient1 + await terminusFacet.connect(admin1).mint(user0.address, poolId, 1, "0x"); + + // Record initial balances for sender and receiver + const initialSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + // Pool controller initiates transfer from recipient1 to recipient2 + await terminusFacet.connect(admin1).safeTransferFrom( + user0.address, + user1.address, + poolId, + 1, + "0x" + ); + + // Verify final balances after transfer + const finalSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + expect(finalSenderBalance).to.equal(initialSenderBalance - BigInt(1)); + expect(finalReceiverBalance).to.equal(initialReceiverBalance + BigInt(1)); + }); + + it("Terminus-18: Should prevent unauthorized transfer by controller of a different pool", async function () { + // First, ensure `admin1` controls another separate pool + await terminusFacet.connect(admin0).createPoolV1(100, true, true); + const controlledPoolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).setPoolController(controlledPoolId, admin1.address) + + // Verify that `poolController` is the controller of this new pool + expect(await terminusFacet.terminusPoolController(controlledPoolId)).to.equal(admin1.address); + + // Create another pool to perform unauthorized transfer test + await erc20.connect(admin0).mint(admin0.address, 1000); + await erc20.connect(admin0).approve(terminusFacetAddress, 1000); + await terminusFacet.connect(admin0).createPoolV1(100, true, true); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Transfer control of `poolId` to `user1` + await terminusFacet.connect(admin0).setPoolController(poolId, user1.address); + + // Record initial balances for sender and receiver + const initialSenderBalance = await terminusFacet.balanceOf(user1.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user2.address, poolId); + + // Attempt transfer by original pool controller, expecting it to fail + await expect( + terminusFacet.connect(admin1).safeTransferFrom( + user1.address, + user2.address, + poolId, + 1, + "0x" + ) + ).to.be.reverted; + + // Verify balances remain unchanged after the failed transfer + const finalSenderBalance = await terminusFacet.balanceOf(user1.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user2.address, poolId); + + expect(finalSenderBalance).to.equal(initialSenderBalance); + expect(finalReceiverBalance).to.equal(initialReceiverBalance); + }); + it("Terminus-19: Should fail transfer as Terminus controller without approval", async function () { + // Create a new pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(100, true, true); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Remove control from the terminusController + await terminusFacet.connect(admin0).setPoolController(poolId, admin1.address); + + // Record initial balances for sender and receiver + const initialSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + // Attempt transfer by terminusController without approval, expecting it to fail + await expect( + terminusFacet.connect(admin0).safeTransferFrom( + user1.address, + user2.address, + poolId, + 1, + "0x" + ) + ).to.be.reverted; + + // Verify balances remain unchanged + const finalSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + expect(finalSenderBalance).to.equal(initialSenderBalance); + expect(finalReceiverBalance).to.equal(initialReceiverBalance); + }); + + it("Terminus-20: Should fail transfer by unauthorized recipient", async function () { + // Create a new pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, true); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial balances for sender and receiver + const initialSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + // Attempt transfer by unauthorized recipient, expecting it to fail + await expect( + terminusFacet.connect(user1).safeTransferFrom( + user0.address, + user1.address, + poolId, + 1, + "0x" + ) + ).to.be.reverted; + + // Verify balances remain unchanged + const finalSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + expect(finalSenderBalance).to.equal(initialSenderBalance); + expect(finalReceiverBalance).to.equal(initialReceiverBalance); + }); + + it("Terminus-21: Should allow transfer by authorized recipient", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, true); + const poolId = await terminusFacet.totalPools(); + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial balances for sender and receiver + const initialSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + // Approve recipient2 for the pool + await terminusFacet.connect(admin0).approveForPool(poolId, user1.address); + + // Perform the transfer by recipient2 + await terminusFacet.connect(user1).safeTransferFrom( + user0.address, + user1.address, + poolId, + 1, + "0x" + ); + + // Verify final balances after transfer + const finalSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + expect(finalSenderBalance).to.equal(initialSenderBalance - BigInt(1)); + expect(finalReceiverBalance).to.equal(initialReceiverBalance + BigInt(1)); + }); + + it("Terminus-22: Should allow transfer as an approved operator", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, true); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to user0 + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial balances + const initialSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + // Approve the operator for all pools for recipient1 + await terminusFacet.connect(user0).setApprovalForAll(admin1.address, true); + + // Perform the transfer by the approved operator + await terminusFacet.connect(admin1).safeTransferFrom( + user0.address, + user1.address, + poolId, + 1, + "0x" + ); + + // Revoke the approval to reset state + await terminusFacet.connect(user0).setApprovalForAll(admin1.address, false); + + // Verify final balances after transfer + const finalSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + expect(finalSenderBalance).to.equal(initialSenderBalance - BigInt(1)); + expect(finalReceiverBalance).to.equal(initialReceiverBalance + BigInt(1)); + + // Verify approval is revoked + expect(await terminusFacet.isApprovedForAll(user0.address, admin1.address)).to.be.false; + }); + + it("Terminus-23: Should fail transfer by unauthorized unrelated party", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, true); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to user0 + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial balances + const initialSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + // Attempt transfer by unauthorizedUser, expecting it to fail + await expect( + terminusFacet.connect(admin1).safeTransferFrom( + user0.address, + user1.address, + poolId, + 1, + "0x" + ) + ).to.be.reverted; + + // Verify balances remain unchanged after the failed transfer + const finalSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + expect(finalSenderBalance).to.equal(initialSenderBalance); + expect(finalReceiverBalance).to.equal(initialReceiverBalance); + }); + + it("Terminus-24: Should allow transfer by authorized unrelated party", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, true); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to user0 + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial balances + const initialSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + // Approve unauthorizedUser for the pool + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + + // Perform the transfer by the authorized unrelated party + await terminusFacet.connect(admin1).safeTransferFrom( + user0.address, + user1.address, + poolId, + 1, + "0x" + ); + + // Verify final balances after transfer + const finalSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + expect(finalSenderBalance).to.equal(initialSenderBalance - BigInt(1)); + expect(finalReceiverBalance).to.equal(initialReceiverBalance + BigInt(1)); + }); + + it("Terminus-25: Should fail burn as token owner", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, false); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to user0 + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Attempt to burn by token owner, expecting it to fail + await expect( + terminusFacet.connect(user0).burn(user0.address, poolId, 1) + ).to.be.reverted; + + // Verify final supply and owner balance remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply); + expect(finalOwnerBalance).to.equal(initialOwnerBalance); + }); + + it("Terminus-26: Should fail burn as pool controller", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, false); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to user0 + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Attempt to burn by pool controller, expecting it to fail + await expect( + terminusFacet.connect(admin0).burn(user0.address, poolId, 1) + ).to.be.reverted; + + // Verify final supply and owner balance remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply); + expect(finalOwnerBalance).to.equal(initialOwnerBalance); + }); + + it("Terminus-27: Should fail burn as an unauthorized third party", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, false); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to user0 + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Attempt to burn by an unauthorized user, expecting it to fail + await expect( + terminusFacet.connect(admin1).burn(user0.address, poolId, 1) + ).to.be.reverted; + + // Verify final supply and owner balance remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply); + expect(finalOwnerBalance).to.equal(initialOwnerBalance); + }); + + it("Terminus-28: Should fail burn as an authorized third party", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, false); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to user0 + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Approve a third party for the pool + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + + // Attempt to burn by the authorized third party, expecting it to fail + await expect( + terminusFacet.connect(admin1).burn(user0.address, poolId, 1) + ).to.be.reverted; + + // Verify final supply and owner balance remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply); + expect(finalOwnerBalance).to.equal(initialOwnerBalance); + }); + + it("Terminus-29: Should test pool approval for minting and burning permissions", async function () { + // Create a pool and set the pool controller + await terminusFacet.connect(admin0).createPoolV1(ethers.MaxUint256, true, true); + const poolId = await terminusFacet.totalPools(); + + // Mint tokens to controller, operator, and user + await terminusFacet.connect(admin0).mint(admin0.address, poolId, 5, "0x"); + await terminusFacet.connect(admin0).mint(admin1.address, poolId, 5, "0x"); + await terminusFacet.connect(admin0).mint(user0.address, poolId, 5, "0x"); + + const initialControllerBalance = await terminusFacet.balanceOf(admin0.address, poolId); + const initialOperatorBalance = await terminusFacet.balanceOf(admin1.address, poolId); + const initialUserBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(await terminusFacet.isApprovedForPool(poolId, admin1.address)).to.be.false; + + // Ensure minting fails when attempted by the operator without approval + await expect( + terminusFacet.connect(admin1).mint(admin0.address, poolId, 1, "0x") + ).to.be.reverted; + await expect( + terminusFacet.connect(admin1).mint(admin1.address, poolId, 1, "0x") + ).to.be.reverted; + await expect( + terminusFacet.connect(admin1).mint(user0.address, poolId, 1, "0x") + ).to.be.reverted; + + // Ensure balances remain unchanged after failed minting attempts + expect(await terminusFacet.balanceOf(admin0.address, poolId)).to.equal(initialControllerBalance); + expect(await terminusFacet.balanceOf(admin1.address, poolId)).to.equal(initialOperatorBalance); + expect(await terminusFacet.balanceOf(user0.address, poolId)).to.equal(initialUserBalance); + + // Ensure burning fails when attempted by the operator without approval + await expect( + terminusFacet.connect(admin1).burn(admin0.address, poolId, 1) + ).to.be.reverted; + + // Burn one token from operator's balance + await terminusFacet.connect(admin1).burn(admin1.address, poolId, 1); + + expect(await terminusFacet.balanceOf(admin1.address, poolId)).to.equal(initialOperatorBalance - BigInt(1)); + + // Attempt to burn user’s token by operator without approval, expecting failure + await expect( + terminusFacet.connect(admin1).burn(user0.address, poolId, 1) + ).to.be.reverted; + + // Approve operator for pool + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + expect(await terminusFacet.isApprovedForPool(poolId, admin1.address)).to.be.true; + + // Now operator can mint tokens on behalf of others + await terminusFacet.connect(admin1).mint(admin0.address, poolId, 1, "0x"); + await terminusFacet.connect(admin1).mint(admin1.address, poolId, 1, "0x"); + await terminusFacet.connect(admin1).mint(user0.address, poolId, 1, "0x"); + + // Check updated balances after successful minting + expect(await terminusFacet.balanceOf(admin0.address, poolId)).to.equal(initialControllerBalance + BigInt(1)); + expect(await terminusFacet.balanceOf(admin1.address, poolId)).to.equal(initialOperatorBalance); + expect(await terminusFacet.balanceOf(user0.address, poolId)).to.equal(initialUserBalance + BigInt(1)); + + // Operator can also burn tokens from any account + await terminusFacet.connect(admin1).burn(admin0.address, poolId, 1); + await terminusFacet.connect(admin1).burn(admin1.address, poolId, 1); + await terminusFacet.connect(admin1).burn(user0.address, poolId, 1); + + expect(await terminusFacet.balanceOf(admin0.address, poolId)).to.equal(initialControllerBalance); + expect(await terminusFacet.balanceOf(admin1.address, poolId)).to.equal(initialOperatorBalance - BigInt(1)); + expect(await terminusFacet.balanceOf(user0.address, poolId)).to.equal(initialUserBalance); + + // Revoke pool approval from operator + await terminusFacet.connect(admin0).unapproveForPool(poolId, admin1.address); + expect(await terminusFacet.isApprovedForPool(poolId, admin1.address)).to.be.false; + + // Ensure minting and burning fail again after revoking approval + await expect( + terminusFacet.connect(admin1).mint(admin0.address, poolId, 1, "0x") + ).to.be.reverted; + await expect( + terminusFacet.connect(admin1).mint(admin1.address, poolId, 1, "0x") + ).to.be.reverted; + await expect( + terminusFacet.connect(admin1).mint(user0.address, poolId, 1, "0x") + ).to.be.reverted; + + await expect( + terminusFacet.connect(admin1).burn(admin0.address, poolId, 1) + ).to.be.reverted; + + // Operator can only burn its own tokens + await terminusFacet.connect(admin1).burn(admin1.address, poolId, 1); + + // Verify final balances remain consistent with allowed actions + expect(await terminusFacet.balanceOf(admin0.address, poolId)).to.equal(initialControllerBalance); + expect(await terminusFacet.balanceOf(admin1.address, poolId)).to.equal(initialOperatorBalance - BigInt(2)); + expect(await terminusFacet.balanceOf(user0.address, poolId)).to.equal(initialUserBalance); + }); + }) + describe("Pool Creation and State View Tests", async function () { + + it("Termiuns-30: Should prevent transfers for a nontransferable pool", async function () { + // Create a nontransferable, nonburnable pool + await terminusFacet.connect(admin0).createPoolV1(10, false, false); + const poolId = await terminusFacet.totalPools(); + + // Mint 1 token to sender in the newly created pool + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial balances + const initialSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const initialReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + // Attempt to transfer from sender to receiver, expecting it to fail + await expect( + terminusFacet.connect(user0).safeTransferFrom( + user0.address, + user1.address, + poolId, + 1, + "0x" + ) + ).to.be.reverted; + + // Verify balances remain unchanged + const finalSenderBalance = await terminusFacet.balanceOf(user0.address, poolId); + const finalReceiverBalance = await terminusFacet.balanceOf(user1.address, poolId); + + expect(finalSenderBalance).to.equal(initialSenderBalance); + expect(finalReceiverBalance).to.equal(initialReceiverBalance); + }); + + it("Terminus-31: Should check pool properties for transferability, burnability, and URI", async function () { + await erc20.connect(admin0).mint(admin0, 4000); + await erc20.connect(admin0).approve(terminusFacetAddress, 4000); + // Nontransferable, nonburnable pool + const nontransferableNonburnableUri = "https://example.com/ff.json"; + await terminusFacet.connect(admin0).createPoolV2(10, false, false, nontransferableNonburnableUri); + const nontransferableNonburnablePoolId = await terminusFacet.totalPools(); + + expect(await terminusFacet.poolIsTransferable(nontransferableNonburnablePoolId)).to.be.false; + expect(await terminusFacet.poolIsBurnable(nontransferableNonburnablePoolId)).to.be.false; + expect(await terminusFacet.uri(nontransferableNonburnablePoolId)).to.equal(nontransferableNonburnableUri); + + // Transferable, nonburnable pool + const transferableNonburnableUri = "https://example.com/tf.json"; + await terminusFacet.connect(admin0).createPoolV2(10, true, false, transferableNonburnableUri); + const transferableNonburnablePoolId = await terminusFacet.totalPools(); + + expect(await terminusFacet.poolIsTransferable(transferableNonburnablePoolId)).to.be.true; + expect(await terminusFacet.poolIsBurnable(transferableNonburnablePoolId)).to.be.false; + expect(await terminusFacet.uri(transferableNonburnablePoolId)).to.equal(transferableNonburnableUri); + + // Transferable, burnable pool + const transferableBurnableUri = "https://example.com/tt.json"; + await terminusFacet.connect(admin0).createPoolV2(10, true, true, transferableBurnableUri); + const transferableBurnablePoolId = await terminusFacet.totalPools(); + + expect(await terminusFacet.poolIsTransferable(transferableBurnablePoolId)).to.be.true; + expect(await terminusFacet.poolIsBurnable(transferableBurnablePoolId)).to.be.true; + expect(await terminusFacet.uri(transferableBurnablePoolId)).to.equal(transferableBurnableUri); + + // Nontransferable, burnable pool + const nontransferableBurnableUri = "https://example.com/ft.json"; + await terminusFacet.connect(admin0).createPoolV2(10, false, true, nontransferableBurnableUri); + const nontransferableBurnablePoolId = await terminusFacet.totalPools(); + + expect(await terminusFacet.poolIsTransferable(nontransferableBurnablePoolId)).to.be.false; + expect(await terminusFacet.poolIsBurnable(nontransferableBurnablePoolId)).to.be.true; + expect(await terminusFacet.uri(nontransferableBurnablePoolId)).to.equal(nontransferableBurnableUri); + }); + + it("Terminus-32: Should allow pool state to be set by the controller only", async function () { + // Create a nontransferable, nonburnable pool + await terminusFacet.connect(admin0).createPoolV1(10, false, false); + const poolId = await terminusFacet.totalPools(); + + // Verify initial state + expect(await terminusFacet.terminusPoolController(poolId)).to.equal(admin0.address); + expect(await terminusFacet.poolIsTransferable(poolId)).to.be.false; + expect(await terminusFacet.poolIsBurnable(poolId)).to.be.false; + + // Set pool as transferable + await terminusFacet.connect(admin0).setPoolTransferable(poolId, true); + expect(await terminusFacet.poolIsTransferable(poolId)).to.be.true; + expect(await terminusFacet.poolIsBurnable(poolId)).to.be.false; + + // Set pool as burnable + await terminusFacet.connect(admin0).setPoolBurnable(poolId, true); + expect(await terminusFacet.poolIsTransferable(poolId)).to.be.true; + expect(await terminusFacet.poolIsBurnable(poolId)).to.be.true; + + // Reset pool state back to nontransferable and nonburnable + await terminusFacet.connect(admin0).setPoolTransferable(poolId, false); + await terminusFacet.connect(admin0).setPoolBurnable(poolId, false); + expect(await terminusFacet.poolIsTransferable(poolId)).to.be.false; + expect(await terminusFacet.poolIsBurnable(poolId)).to.be.false; + }); + + it("Terminus-33: Should prevent non-controller from setting pool state parameters", async function () { + // Create a nontransferable, nonburnable pool + await terminusFacet.connect(admin0).createPoolV1(10, false, false); + const poolId = await terminusFacet.totalPools(); + + // Verify initial state + expect(await terminusFacet.terminusPoolController(poolId)).to.equal(admin0.address); + expect(await terminusFacet.poolIsTransferable(poolId)).to.be.false; + expect(await terminusFacet.poolIsBurnable(poolId)).to.be.false; + + // Attempt to set state by a non-controller, expecting failures + await expect( + terminusFacet.connect(admin1).setPoolTransferable(poolId, true) + ).to.be.reverted; + await expect( + terminusFacet.connect(admin1).setPoolBurnable(poolId, true) + ).to.be.reverted; + + // Verify state remains unchanged + expect(await terminusFacet.poolIsTransferable(poolId)).to.be.false; + expect(await terminusFacet.poolIsBurnable(poolId)).to.be.false; + }); + + it("Terminus-34: Should allow token owner to burn in a burnable pool", async function () { + // Create a transferable, burnable pool + await terminusFacet.connect(admin0).createPoolV1(10, true, true); + const poolId = await terminusFacet.totalPools(); + + // Mint a token to the token owner + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial pool supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Token owner burns their token + await terminusFacet.connect(user0).burn(user0.address, poolId, 1); + + // Verify final supply and owner balance after burn + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply - BigInt(1)); + expect(finalOwnerBalance).to.equal(initialOwnerBalance - BigInt(1)); + }); + + it("Terminus-35: Should allow pool controller to burn tokens in a burnable pool", async function () { + // Create a transferable, burnable pool + await terminusFacet.connect(admin0).createPoolV1(10, true, true); + const poolId = await terminusFacet.totalPools(); + + // Mint a token to the token owner + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial pool supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Pool controller burns the token owned by tokenOwner + await terminusFacet.connect(admin0).burn(user0.address, poolId, 1); + + // Verify final supply and owner balance after burn + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply - BigInt(1)); + expect(finalOwnerBalance).to.equal(initialOwnerBalance - BigInt(1)); + }); + + it("Termins-36: Should allow authorized third party to burn tokens in a burnable pool", async function () { + // Create a transferable, burnable pool + await terminusFacet.connect(admin0).createPoolV1(10, true, true); + const poolId = await terminusFacet.totalPools(); + + // Mint a token to the token owner + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial pool supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Authorize third party for the pool + await terminusFacet.connect(admin0).approveForPool(poolId, admin1.address); + + // Authorized third party burns the token + await terminusFacet.connect(admin1).burn(user0.address, poolId, 1); + + // Verify final supply and owner balance after burn + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply - BigInt(1)); + expect(finalOwnerBalance).to.equal(initialOwnerBalance - BigInt(1)); + }); + + it("Terminus-37: Should prevent unauthorized third party from burning tokens in a burnable pool", async function () { + // Create a transferable, burnable pool + await terminusFacet.connect(admin0).createPoolV1(10, true, true); + const poolId = await terminusFacet.totalPools(); + + // Mint a token to the token owner + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial pool supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Attempt to burn by unauthorized third party, expecting failure + await expect( + terminusFacet.connect(user1).burn(user0.address, poolId, 1) + ).to.be.reverted; + + // Verify pool supply and owner balance remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply); + expect(finalOwnerBalance).to.equal(initialOwnerBalance); + }); + + it("Terminus-38: Should prevent transfers in a nontransferable pool", async function () { + // Create a nontransferable, nonburnable pool + await terminusFacet.connect(admin0).createPoolV1(10, false, false); + const poolId = await terminusFacet.totalPools(); + + // Mint a token to the token owner + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial pool supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Attempt to transfer token to receiver, expecting it to fail + await expect( + terminusFacet.connect(user0).safeTransferFrom( + user0.address, + user1.address, + poolId, + 1, + "0x" + ) + ).to.be.reverted; + + // Verify pool supply and owner balance remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply); + expect(finalOwnerBalance).to.equal(initialOwnerBalance); + }); + + it("Terminus-39: Should prevent batch transfers in a nontransferable pool", async function () { + // Create a nontransferable, nonburnable pool + await terminusFacet.connect(admin0).createPoolV1(10, false, false); + const poolId = await terminusFacet.totalPools(); + + // Mint a token to the token owner + await terminusFacet.connect(admin0).mint(user0.address, poolId, 1, "0x"); + + // Record initial pool supply and owner balance + const initialPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const initialOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + // Attempt to batch transfer token to receiver, expecting it to fail + await expect( + terminusFacet.connect(user0).safeBatchTransferFrom( + user0.address, + user1.address, + [poolId], + [1], + "0x" + ) + ).to.be.reverted; + + // Verify pool supply and owner balance remain unchanged + const finalPoolSupply = await terminusFacet.terminusPoolSupply(poolId); + const finalOwnerBalance = await terminusFacet.balanceOf(user0.address, poolId); + + expect(finalPoolSupply).to.equal(initialPoolSupply); + expect(finalOwnerBalance).to.equal(initialOwnerBalance); + }); + }) +}) \ No newline at end of file diff --git a/web3/test/fixtures/terminus.fixture.ts b/web3/test/fixtures/terminus.fixture.ts new file mode 100644 index 00000000..a9490f9a --- /dev/null +++ b/web3/test/fixtures/terminus.fixture.ts @@ -0,0 +1,15 @@ +import { ethers } from "hardhat"; +import { deployDiamond } from "../utils/diamond"; +import { encodeFunctionWithArgs } from "../utils/encode"; + +/** + * @notice Deploy the Terminus diamond + * @dev Deploys the Terminus diamond and returns the contract instance + * @returns Contract instance of the Terminus diamond + */ +export async function deployTerminusDiamond() { + const initCalldata = await encodeFunctionWithArgs("TerminusFacet", "init", []); + const diamond = await deployDiamond(["TerminusFacet"], initCalldata); + const terminusFacet = await ethers.getContractAt("TerminusFacet", diamond); + return terminusFacet +} \ No newline at end of file diff --git a/web3/test/utils/diamond.ts b/web3/test/utils/diamond.ts new file mode 100644 index 00000000..11f28ef2 --- /dev/null +++ b/web3/test/utils/diamond.ts @@ -0,0 +1,45 @@ +import { ethers } from 'hardhat'; +import { FacetCut, FacetCutAction } from './types/diamond.types'; +import { getContractFunctionSelectors } from './encode'; + +/** + * Deploys a diamond contract with the given contract name and initializes it with the given function name and arguments. + * @param contractName - The name of the contract to deploy. + * @param init - The initialization function name and arguments. If not provided, the contract will be initialized with the default constructor. + * @returns The address of the deployed diamond contract. + */ +export async function deployDiamond( + facetsNames: string[], + initCalldata: string +) { + const facetCut: FacetCut[] = []; + const deployer = (await ethers.getSigners())[0]; + for (const facetName of facetsNames) { + const FacetFactory = await ethers.getContractFactory(facetName); + const facet = await FacetFactory.connect(deployer).deploy(); + await facet.waitForDeployment(); + const facetAddress = await facet.getAddress(); + const selectors = await getContractFunctionSelectors(facetName); + facetCut.push({ + facetAddress: facetAddress, + action: FacetCutAction.Add, + functionSelectors: selectors, + }); + } + + const DiamondCutFacetFactory = await ethers.getContractFactory('DiamondCutFacet'); + const diamondCutFacet = await DiamondCutFacetFactory.connect(deployer).deploy(); + await diamondCutFacet.waitForDeployment; + const diamondCutFacetAddress = await diamondCutFacet.getAddress(); + + const contractOwner = deployer.address; + const DiamondFactory = await ethers.getContractFactory('Diamond'); + const diamond = await DiamondFactory.connect(deployer).deploy(contractOwner, diamondCutFacetAddress); + await diamond.waitForDeployment(); + const diamondAddress = await diamond.getAddress(); + + const cutContract = await ethers.getContractAt('DiamondCutFacet', diamondAddress); + await cutContract.diamondCut(facetCut, diamondAddress, initCalldata); + + return diamondAddress; +} \ No newline at end of file diff --git a/web3/test/utils/encode.ts b/web3/test/utils/encode.ts new file mode 100644 index 00000000..8e6ff544 --- /dev/null +++ b/web3/test/utils/encode.ts @@ -0,0 +1,61 @@ +import { ethers } from "hardhat"; + +/** + * Get the function selectors for a given contract + * @param contractName The name of the contract + * @returns The function selectors + */ +export async function getContractFunctionSelectors(contractName: string) { + const factory = await ethers.getContractFactory(contractName); + //console.log(`${contractName}`); + const functionSelectors = factory.interface.fragments + .filter(fragment => fragment.type === 'function') + .map((fragment: any) => { + const signature = `${fragment.name}(${fragment.inputs.map(encodeParameter).join(',')})`; + //console.log(signature, ethers.id(signature).slice(0, 10)); + const selector = ethers.id(signature).slice(0, 10); // The function selector is the first 4 bytes (8 hex chars) of the keccak256 hash + return selector; + }); + //console.log('\n'); + return functionSelectors; +} + +/** + * Encode a parameter for a function + * @param input The parameter to encode + * @returns The encoded parameter + */ +function encodeParameter(input: any): string { + if (input.type === 'tuple') { + return `(${input.components.map(encodeParameter).join(',')})`; + } else if (input.type === 'tuple[]') { + return `(${input.components.map(encodeParameter).join(',')})[]`; + } else { + return input.type; + } +} + +/** + * Get the function selector for a given contract and function + * @param contractName The name of the contract + * @param functionName The name of the function + * @returns The function selector + */ +export async function getFunctionSelector(contractName: string, functionName: string) { + const factory = await ethers.getContractFactory(contractName); + const functionSelector = factory.interface.getFunction(functionName)?.selector; + return functionSelector || "0x"; +} + +/** + * Encode function data for a given contract and function + * @param contractName The name of the contract + * @param functionName The name of the function + * @param args The arguments to pass to the function + * @returns The encoded function data + */ +export async function encodeFunctionWithArgs(contractName: string, functionName: string, args: any[]) { + const factory = await ethers.getContractFactory(contractName); + const iface = new ethers.Interface(factory.interface.format()); + return iface.encodeFunctionData(functionName, args); +} \ No newline at end of file diff --git a/web3/test/utils/types/diamond.types.ts b/web3/test/utils/types/diamond.types.ts new file mode 100644 index 00000000..b02dd91d --- /dev/null +++ b/web3/test/utils/types/diamond.types.ts @@ -0,0 +1,6 @@ +export enum FacetCutAction {Add, Replace, Remove} +export type FacetCut = { + facetAddress: string; // address + action: FacetCutAction; // uint8 + functionSelectors: string[]; // bytes4[] +} \ No newline at end of file diff --git a/webapps/world-builder-dashboard/.env.example b/webapps/world-builder-dashboard/.env.example new file mode 100644 index 00000000..b366510b --- /dev/null +++ b/webapps/world-builder-dashboard/.env.example @@ -0,0 +1,2 @@ +VITE_NB_JSON_RPC_URI="ADD_URI_HERE" +VITE_NB_WB_DASHBOARD_ACCESS_ID="ADD_ACCESS_ID_HERE" \ No newline at end of file diff --git a/webapps/world-builder-dashboard/constants.ts b/webapps/world-builder-dashboard/constants.ts index cfab2fe9..b27ca2e9 100644 --- a/webapps/world-builder-dashboard/constants.ts +++ b/webapps/world-builder-dashboard/constants.ts @@ -1,11 +1,13 @@ -import { NetworkInterface, HighNetworkInterface, NetworkType } from '@/contexts/BlockchainContext' import { TokenAddressMap } from 'game7-bridge-sdk' +import { NetworkInterface, HighNetworkInterface, NetworkType } from '@/contexts/BlockchainContext' export const L1_NETWORK: NetworkInterface = { chainId: 11155111, name: 'sepolia', displayName: 'Sepolia', - rpcs: ['https://eth-sepolia.g.alchemy.com/v2/C-njXZM_UTlPbC2ukOvg4ojFz2V9yCS6'], + rpcs: [ + `${import.meta.env.VITE_NB_JSON_RPC_URI}/sepolia/jsonrpc/${import.meta.env.VITE_NB_WB_DASHBOARD_ACCESS_ID}` + ], blockExplorerUrls: ['https://sepolia.etherscan.io'], nativeCurrency: { decimals: 18, @@ -21,7 +23,9 @@ export const L2_NETWORK: HighNetworkInterface = { chainId: 421614, name: 'arbitrumSepolia', displayName: 'Arbitrum Sepolia', - rpcs: ['https://nb.moonstream.to/nb/arbitrum-sepolia/jsonrpc/36c13893-c382-405b-a73c-1af3e9e25700'], + rpcs: [ + `${import.meta.env.VITE_NB_JSON_RPC_URI}/arbitrum-sepolia/jsonrpc/${import.meta.env.VITE_NB_WB_DASHBOARD_ACCESS_ID}` + ], blockExplorerUrls: ['https://sepolia.arbiscan.io'], nativeCurrency: { decimals: 18, @@ -57,7 +61,9 @@ export const L1_MAIN_NETWORK: NetworkInterface = { chainId: 1, name: 'ethereum', displayName: 'Ethereum', - rpcs: ['https://eth-mainnet.g.alchemy.com/v2/C-njXZM_UTlPbC2ukOvg4ojFz2V9yCS6'], + rpcs: [ + `${import.meta.env.VITE_NB_JSON_RPC_URI}/ethereum/jsonrpc/${import.meta.env.VITE_NB_WB_DASHBOARD_ACCESS_ID}` + ], blockExplorerUrls: ['https://etherscan.io'], nativeCurrency: { decimals: 18, @@ -73,7 +79,9 @@ export const L2_MAIN_NETWORK: NetworkInterface = { chainId: 42161, name: 'arbitrumOne', displayName: 'Arbitrum One', - rpcs: ['https://arb-mainnet.g.alchemy.com/v2/C-njXZM_UTlPbC2ukOvg4ojFz2V9yCS6'], + rpcs: [ + `${import.meta.env.VITE_NB_JSON_RPC_URI}/arbitrum-one/jsonrpc/${import.meta.env.VITE_NB_WB_DASHBOARD_ACCESS_ID}` + ], blockExplorerUrls: ['https://arbiscan.io'], nativeCurrency: { decimals: 18, @@ -107,7 +115,6 @@ export const ALL_LOW_TESTNET_NETWORKS = [L1_NETWORK, L2_NETWORK] export const ALL_HIGH_MAINNET_NETWORKS = [L2_MAIN_NETWORK, L3_MAIN_NETWORK] export const ALL_LOW_MAINNET_NETWORKS = [L1_MAIN_NETWORK, L2_MAIN_NETWORK] - export const L3_NATIVE_TOKEN_SYMBOL = 'TG7T' export const DEFAULT_LOW_NETWORK = L1_NETWORK export const DEFAULT_HIGH_NETWORK = L2_NETWORK @@ -160,8 +167,6 @@ export const USDC_MAINNET: TokenAddressMap = { 1: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' } - - export const getNetworks = (selectedNetworkType: NetworkType) => { switch (selectedNetworkType) { case 'Mainnet':