├── img └── gh_template.png ├── foundry.toml ├── remappings.txt ├── .gitmodules ├── .gitignore ├── scripts ├── private │ ├── _sanity-check.js │ ├── _send-packet-config.js │ ├── _set-contracts-config.js │ ├── _send-vote-info-config.js │ ├── _deploy-config.js │ ├── _create-channel-config.js │ ├── _update-vibc-address.js │ ├── _sanity-check-custom.js │ ├── _create-channel.js │ ├── _switch-clients.js │ ├── _helpers.js │ ├── _vibc-helpers.js │ ├── _sanity-check-universal.js │ └── _events.js ├── send-packet.js ├── send-universal-packet.js ├── x-ballot-nft │ ├── send-vote-info.js │ ├── send-universal-vote-info.js │ ├── _app-events-UC.js │ └── _app-events.js └── deploy.js ├── ibc.json ├── contracts ├── arguments.js ├── x-ballot-nft │ ├── XProofOfVoteNFT.sol │ └── XBallot.sol ├── x-ballot-nft-UC │ ├── XProofOfVoteNFTUC.sol │ └── XBallotUC.sol ├── XCounter.sol ├── XCounterUC.sol └── base │ ├── UniversalChanIbcApp.sol │ ├── GeneralMiddleware.sol │ └── CustomChanIbcApp.sol ├── package.json ├── .env.example ├── config.json ├── config ├── x-ballot-nft-UC.json └── x-ballot-nft.json ├── hardhat.config.js ├── Justfile ├── README.md └── ibc-app-template.md /img/gh_template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polymerdao/demo-dapps/HEAD/img/gh_template.png -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'contracts' 3 | out = 'out' 4 | libs = ['node_modules', 'lib'] 5 | test = 'test' 6 | cache_path = 'cache_forge' -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | @open-ibc/vibc-core-smart-contracts/=lib/vibc-core-smart-contracts/ 2 | @lazyledger/protobuf3-solidity-lib/=lib/protobuf3-solidity-lib/ 3 | ds-test/=lib/forge-std/lib/ds-test/src/ 4 | forge-std/=lib/forge-std/src/ 5 | 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/vibc-core-smart-contracts"] 2 | path = lib/vibc-core-smart-contracts 3 | url = https://github.com/open-ibc/vibc-core-smart-contracts 4 | [submodule "lib/forge-std"] 5 | path = lib/forge-std 6 | url = https://github.com/foundry-rs/forge-std 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | # Hardhat files 5 | /cache 6 | /artifacts 7 | 8 | # TypeChain files 9 | /typechain 10 | /typechain-types 11 | 12 | # solidity-coverage files 13 | /coverage 14 | /coverage.json 15 | 16 | # Foundry files 17 | /out 18 | /cache_forge -------------------------------------------------------------------------------- /scripts/private/_sanity-check.js: -------------------------------------------------------------------------------- 1 | // Example: 2 | // $ node scripts/sanity-check.js 3 | const { exec } = require("child_process"); 4 | const { getConfigPath } = require('./_helpers.js'); 5 | 6 | function runSanityCheck(network) { 7 | const config = require(getConfigPath()); 8 | const scriptSuffix = config.isUniversal ? 'universal' : 'custom'; 9 | 10 | exec(`npx hardhat run scripts/private/_sanity-check-${scriptSuffix}.js --network ${network}`, (error, stdout, stderr) => { 11 | if (error) { 12 | console.error(`exec error: ${error}`); 13 | return; 14 | } 15 | console.log(stdout); 16 | }); 17 | } 18 | 19 | // TODO: EXTEND THIS TO SUPPORT MULTIPLE NETWORKS 20 | runSanityCheck('optimism'); 21 | runSanityCheck('base'); -------------------------------------------------------------------------------- /ibc.json: -------------------------------------------------------------------------------- 1 | { 2 | "optimism": { 3 | "sim-client": { 4 | "canonConnFrom": "connection-0", 5 | "canonConnTo": "connection-1", 6 | "universalChannel": "channel-10" 7 | }, 8 | "op-client": { 9 | "canonConnFrom": "connection-8", 10 | "canonConnTo": "connection-9", 11 | "universalChannel": "channel-16" 12 | } 13 | }, 14 | "base": { 15 | "sim-client" : { 16 | "canonConnFrom": "connection-4", 17 | "canonConnTo": "connection-5", 18 | "universalChannel": "channel-11" 19 | }, 20 | "op-client": { 21 | "canonConnFrom": "connection-10", 22 | "canonConnTo": "connection-11", 23 | "universalChannel": "channel-17" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /contracts/arguments.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "XCounter": [], 3 | "XCounterUC": [], 4 | // Add your contract types here, along with the list of custom constructor arguments 5 | // DO NOT ADD THE DISPATCHER OR UNIVERSAL CHANNEL HANDLER ADDRESSES HERE!!! 6 | // These will be added in the deploy script at $ROOT/scripts/deploy.js 7 | "XBallot": [ 8 | [ 9 | '0x506f6c796d657220697320612062726964676500000000000000000000000000', // "Polymer is a bridge" 10 | '0x506f6c796d6572206973206e6f74206120627269646765000000000000000000' // "Polymer is not a bridge" 11 | ] 12 | ], 13 | "XProofOfVoteNFT": [ 14 | 'https://picsum.photos/id/' 15 | ], 16 | "XBallotUC": [ 17 | [ 18 | '0x506f6c796d657220697320612062726964676500000000000000000000000000', // "Polymer is a bridge" 19 | '0x506f6c796d6572206973206e6f74206120627269646765000000000000000000' // "Polymer is not a bridge" 20 | ] 21 | ], 22 | "XProofOfVoteNFTUC": [ 23 | 'https://picsum.photos/id/' 24 | ] 25 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ibc-app-solidity-template", 3 | "version": "1.0.0", 4 | "description": "Template project to start building IBC enabled Solidity contracts, with Hardhat and Foundry support", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/open-ibc/ibc-app-solidity-template.git" 12 | }, 13 | "keywords": [ 14 | "IBC", 15 | "Solidity" 16 | ], 17 | "author": "Polymer Labs", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/open-ibc/ibc-app-solidity-template/issues" 21 | }, 22 | "homepage": "https://github.com/open-ibc/ibc-app-solidity-template#readme", 23 | "devDependencies": { 24 | "@nomicfoundation/hardhat-foundry": "^1.1.1", 25 | "@nomicfoundation/hardhat-toolbox": "^4.0.0", 26 | "hardhat": "^2.19.5" 27 | }, 28 | "dependencies": { 29 | "@openzeppelin/contracts": "^4.7.6", 30 | "axios": "^1.6.7", 31 | "dotenv": "^16.4.1", 32 | "hardhat-verify": "^1.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Make sure to rename this file to .env before adding your private keys!!! 2 | PRIVATE_KEY_1='' 3 | PRIVATE_KEY_2='' 4 | PRIVATE_KEY_3='' 5 | # Add more if your project requires more private keys 6 | 7 | # API keys for developer tooling and infra 8 | OP_ALCHEMY_API_KEY='' 9 | BASE_ALCHEMY_API_KEY='' 10 | OP_BLOCKSCOUT_API_KEY='' 11 | BASE_BLOCKSCOUT_API_KEY='' 12 | # TENDERLY_TOKEN='' 13 | 14 | # Contract addresses last updated on 2024-03-05, for public testnet launch 15 | OP_DISPATCHER='0x58f1863f75c9db1c7266dc3d7b43832b58f35e83' 16 | BASE_DISPATCHER='0xfc1d3e02e00e0077628e8cc9edb6812f95db05dc' 17 | 18 | OP_UC_MW='0x34a0e37cCCEdaC70EC1807e5a1f6A4a91D4AE0Ce' 19 | BASE_UC_MW='0x50E32e236bfE4d514f786C9bC80061637dd5AF98' 20 | 21 | # Contract addresses for the sim-client 22 | OP_DISPATCHER_SIM="0x6C9427E8d770Ad9e5a493D201280Cc178125CEc0" 23 | BASE_DISPATCHER_SIM="0x0dE926fE2001B2c96e9cA6b79089CEB276325E9F" 24 | 25 | OP_UC_MW_SIM='0xC3318ce027C560B559b09b1aA9cA4FEBDDF252F5' 26 | BASE_UC_MW_SIM='0x5031fb609569b67608Ffb9e224754bb317f174cD' 27 | 28 | # Configuration file the scripts will use, defaulting to config.json when not set 29 | CONFIG_PATH='config.json' -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "proofsEnabled": false, 3 | "deploy": { 4 | "optimism": "XCounterUC", 5 | "base": "XCounterUC" 6 | }, 7 | "isUniversal": true, 8 | "createChannel": { 9 | "srcChain": "optimism", 10 | "srcAddr": "0x1234567890AbCdEf1234567890aBcDeF12345678", 11 | "dstChain": "base", 12 | "dstAddr": "0x1234567890AbCdEf1234567890aBcDeF12345678", 13 | "version": "1.0", 14 | "ordering": 0, 15 | "fees": false 16 | }, 17 | "sendPacket": { 18 | "optimism": { 19 | "portAddr": "0x1234567890abcdef1234567890abcdef12345678", 20 | "channelId": "channel-n", 21 | "timeout": 36000 22 | }, 23 | "base": { 24 | "portAddr": "0x1234567890abcdef1234567890abcdef12345678", 25 | "channelId": "channel-n", 26 | "timeout": 36000 27 | } 28 | }, 29 | "sendUniversalPacket": { 30 | "optimism": { 31 | "portAddr": "0x1234567890abcdef1234567890abcdef12345678", 32 | "channelId": "channel-x", 33 | "timeout": 36000 34 | }, 35 | "base": { 36 | "portAddr": "0x1234567890abcdef1234567890abcdef12345678", 37 | "channelId": "channel-y", 38 | "timeout": 36000 39 | } 40 | }, 41 | "backup": {} 42 | } -------------------------------------------------------------------------------- /config/x-ballot-nft-UC.json: -------------------------------------------------------------------------------- 1 | { 2 | "proofsEnabled": false, 3 | "deploy": { 4 | "optimism": "XBallotUC", 5 | "base": "XProofOfVoteNFTUC" 6 | }, 7 | "isUniversal": true, 8 | "createChannel": { 9 | "srcChain": "optimism", 10 | "srcAddr": "0x1234567890AbCdEf1234567890aBcDeF12345678", 11 | "dstChain": "base", 12 | "dstAddr": "0x1234567890AbCdEf1234567890aBcDeF12345678", 13 | "version": "1.0", 14 | "ordering": 0, 15 | "fees": false 16 | }, 17 | "sendPacket": { 18 | "optimism": { 19 | "portAddr": "0x1234567890abcdef1234567890abcdef12345678", 20 | "channelId": "channel-n", 21 | "timeout": 36000 22 | }, 23 | "base": { 24 | "portAddr": "0x1234567890abcdef1234567890abcdef12345678", 25 | "channelId": "channel-n", 26 | "timeout": 36000 27 | } 28 | }, 29 | "sendUniversalPacket": { 30 | "optimism": { 31 | "portAddr": "0x80FA9cB428b3873df748628Ca992194451473159", 32 | "channelId": "channel-10", 33 | "timeout": 36000 34 | }, 35 | "base": { 36 | "portAddr": "0x4EF4C3C0Fe45a24b531e36C53e1AbF962eDBCFEb", 37 | "channelId": "channel-11", 38 | "timeout": 36000 39 | } 40 | }, 41 | "backup": {} 42 | } -------------------------------------------------------------------------------- /config/x-ballot-nft.json: -------------------------------------------------------------------------------- 1 | { 2 | "proofsEnabled": false, 3 | "deploy": { 4 | "optimism": "XBallot", 5 | "base": "XProofOfVoteNFT" 6 | }, 7 | "isUniversal": false, 8 | "createChannel": { 9 | "srcChain": "optimism", 10 | "srcAddr": "0xC4B32EE322beA5F48b59b7B3A13B2281B7BA6244", 11 | "dstChain": "base", 12 | "dstAddr": "0x051A88c9fBe5934dfE3Af835D23592C2d8cca1fF", 13 | "version": "1.0", 14 | "ordering": 0, 15 | "fees": false 16 | }, 17 | "sendPacket": { 18 | "optimism": { 19 | "portAddr": "0xC4B32EE322beA5F48b59b7B3A13B2281B7BA6244", 20 | "channelId": "channel-37224", 21 | "timeout": 36000 22 | }, 23 | "base": { 24 | "portAddr": "0x051A88c9fBe5934dfE3Af835D23592C2d8cca1fF", 25 | "channelId": "channel-37225", 26 | "timeout": 36000 27 | } 28 | }, 29 | "sendUniversalPacket": { 30 | "optimism": { 31 | "portAddr": "0x1234567890abcdef1234567890abcdef12345678", 32 | "channelId": "channel-x", 33 | "timeout": 36000 34 | }, 35 | "base": { 36 | "portAddr": "0x1234567890abcdef1234567890abcdef12345678", 37 | "channelId": "channel-y", 38 | "timeout": 36000 39 | } 40 | }, 41 | "backup": {} 42 | } -------------------------------------------------------------------------------- /scripts/send-packet.js: -------------------------------------------------------------------------------- 1 | // We require the Hardhat Runtime Environment explicitly here. This is optional 2 | // but useful for running the script in a standalone fashion through `node