diff --git a/contracts/forwarder/CrossExecutor.sol b/contracts/forwarder/CrossExecutor.sol index d75e51f..a7bdbb2 100644 --- a/contracts/forwarder/CrossExecutor.sol +++ b/contracts/forwarder/CrossExecutor.sol @@ -37,9 +37,9 @@ contract CrossExecutor is IERC777Recipient, Context, Ownable { bytes calldata /*_operatorData*/ ) external override { if (_msgSender() == token && _from == sender) { - (, bytes memory callsAndTargets, , address originAddress, , , , ) = abi.decode( + (, bytes memory callsAndTargets, , address originAddress) = abi.decode( _metaData, - (bytes1, bytes, bytes4, address, bytes4, address, bytes, bytes) + (bytes1, bytes, bytes4, address) ); if (!_whitelistedOriginAddresses[originAddress]) { @@ -74,4 +74,8 @@ contract CrossExecutor is IERC777Recipient, Context, Ownable { function whitelistOriginAddress(address originAddress) external onlyOwner { _whitelistedOriginAddresses[originAddress] = true; } + + function dewhitelistOriginAddress(address originAddress) external onlyOwner { + delete _whitelistedOriginAddresses[originAddress]; + } } diff --git a/contracts/forwarder/ForwarderNative.sol b/contracts/forwarder/ForwarderNative.sol index b3e72fd..c15b68c 100644 --- a/contracts/forwarder/ForwarderNative.sol +++ b/contracts/forwarder/ForwarderNative.sol @@ -46,9 +46,9 @@ contract ForwarderNative is IForwarder, IERC777Recipient, Context, Ownable { bytes calldata /*_operatorData*/ ) external override { if (_msgSender() == token && _from == vault) { - (, bytes memory userData, , address originAddress, , , , ) = abi.decode( + (, bytes memory userData, , address originAddress) = abi.decode( _userData, - (bytes1, bytes, bytes4, address, bytes4, address, bytes, bytes) + (bytes1, bytes, bytes4, address) ); (bytes memory callsAndTargets, address caller) = abi.decode( diff --git a/hardhat.config.js b/hardhat.config.js index 7de2752..cc3cf38 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -83,7 +83,8 @@ module.exports = { apiKey: { mainnet: getEnvironmentVariable('ETHERSCAN_API_KEY'), polygon: getEnvironmentVariable('POLYGONSCAN_API_KEY'), - xdai: getEnvironmentVariable('GNOSISSCAN_API_KEY') + xdai: getEnvironmentVariable('GNOSISSCAN_API_KEY'), + bsc: getEnvironmentVariable('BSCSCAN_API_KEY') } }, gasReporter: { diff --git a/lib/abi/pBTConEthereum.json b/lib/abi/pBTConEthereum.json new file mode 100644 index 0000000..9e34769 --- /dev/null +++ b/lib/abi/pBTConEthereum.json @@ -0,0 +1,1507 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldOperator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newOperator", + "type": "address" + } + ], + "name": "AdminOperatorChange", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "AdminTransferInvoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenHolder", + "type": "address" + } + ], + "name": "AuthorizedOperator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "operatorData", + "type": "bytes" + } + ], + "name": "Burned", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "operatorData", + "type": "bytes" + } + ], + "name": "Minted", + "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" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "underlyingAssetRecipient", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "originChainId", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "destinationChainId", + "type": "bytes4" + } + ], + "name": "Redeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldRelayHub", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newRelayHub", + "type": "address" + } + ], + "name": "RelayHubChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenHolder", + "type": "address" + } + ], + "name": "RevokedOperator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "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": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "operatorData", + "type": "bytes" + } + ], + "name": "Sent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINTER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ORIGIN_CHAIN_ID", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gsnTrustedSigner", + "type": "address" + }, + { + "internalType": "address", + "name": "_gsnFeeTarget", + "type": "address" + } + ], + "name": "__ERC777GSNUpgradeable_init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_adminOperator", + "type": "address" + } + ], + "name": "__ERC777WithAdminOperatorUpgradeable_init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "relay", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "bytes", + "name": "encodedFunction", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "transactionFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "approvalData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "acceptRelayedCall", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "adminOperator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "operatorData", + "type": "bytes" + } + ], + "name": "adminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "authorizeOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenHolder", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_newOriginChainId", + "type": "bytes4" + } + ], + "name": "changeOriginChainId", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "defaultOperators", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getHubAddr", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getRoleMember", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleMemberCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "grantMinterRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "granularity", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gsnExtraGas", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gsnFeeTarget", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gsnTrustedSigner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "hasMinterRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "tokenName", + "type": "string" + }, + { + "internalType": "string", + "name": "tokenSymbol", + "type": "string" + }, + { + "internalType": "address", + "name": "defaultAdmin", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "originChainId", + "type": "bytes4" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenHolder", + "type": "address" + } + ], + "name": "isOperatorFor", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "operatorData", + "type": "bytes" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "operatorData", + "type": "bytes" + } + ], + "name": "operatorBurn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "operatorData", + "type": "bytes" + }, + { + "internalType": "string", + "name": "underlyingAssetRecipient", + "type": "string" + }, + { + "internalType": "bytes4", + "name": "destinationChainId", + "type": "bytes4" + } + ], + "name": "operatorRedeem", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "operatorData", + "type": "bytes" + } + ], + "name": "operatorSend", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "context", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "actualCharge", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "preRetVal", + "type": "bytes32" + } + ], + "name": "postRelayedCall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "context", + "type": "bytes" + } + ], + "name": "preRelayedCall", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "string", + "name": "underlyingAssetRecipient", + "type": "string" + }, + { + "internalType": "bytes4", + "name": "destinationChainId", + "type": "bytes4" + } + ], + "name": "redeem", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "underlyingAssetRecipient", + "type": "string" + }, + { + "internalType": "bytes4", + "name": "destinationChainId", + "type": "bytes4" + } + ], + "name": "redeem", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "relayHubVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "revokeMinterRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "revokeOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "send", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adminOperator_", + "type": "address" + } + ], + "name": "setAdminOperator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gsnFeeTarget", + "type": "address" + } + ], + "name": "setFeeTarget", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_gsnExtraGas", + "type": "uint256" + } + ], + "name": "setGSNExtraGas", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_gsnTrustedSigner", + "type": "address" + } + ], + "name": "setTrustedSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "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": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/lib/constants.js b/lib/constants.js index ce63712..688b6c4 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -14,7 +14,7 @@ module.exports = { SAFE: '0xfE8BCE5b156D9bCD28b5373CDC6b4F08B4b9646a', FINANCE_VAULT: '0x6239968e6231164687CB40f8389d933dD7f7e0A5', FINANCE: '0x3d749Bc0eb27795Da58d2f67a2D6527A95567aEC', - FORWARDER: '0x49157Ddc1cA1907AC7b1f6e871Aa90e93567aDa4', + FORWARDER: '0x99405B4E46256dD28e424A0EDf296A28e2aE32a0', PNT: '0x8805Aa0C1a8e59b03fA95740F691E28942Cf44f6', DAOPNT: '0xFF8Ce5Aca26251Cc3f31e597291c71794C06092a', TOKEN_MANAGER: '0xCec0058735D50de98d3715792569921FEb9EfDC1', @@ -23,21 +23,28 @@ module.exports = { POLYGON: { PNT: '0xb6bcae6468760bc0cdfb9c8ef4ee75c9dd23e1ed', FORWARDER: '0xC85cd78555DF9991245F15c7AA6c4eDBb7791c19', - PNT_MINTER: '0x66917DDA63bC429AE6555e6a2ec17f583FeA732a' + PNT_MINTER: '0x66917DDA63bC429AE6555e6a2ec17f583FeA732a', + SAFE: '0x9203CD49BAb23Ed6e1EE8D6AB376DD5A9CA8486B' }, BSC: { PNT: '0xdaacB0Ab6Fb34d24E8a67BfA14BF4D95D4C7aF92', - FORWARDER: '0x0000000000000000000000000000000000000000' + FORWARDER: '0x23bAa1e6572233f3cf02a002db865FCa495f2926', + SAFE: '0x9203CD49BAb23Ed6e1EE8D6AB376DD5A9CA8486B' }, MAINNET: { PNT: '0x89Ab32156e46F46D02ade3FEcbe5Fc4243B9AAeD', ETHPNT: '0xf4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2', - FORWARDER: '0x0000000000000000000000000000000000000000', + PBTC: '0x62199b909fb8b8cf870f97bef2ce6783493c4908', + FORWARDER: '0x4200Bf8D6eEb6D7EA46b9C99564cCb4246416412', + CROSS_EXECUTOR: '0xE0bFE5Ae5ceBbf666C381f267187379117d0dA73', ERC20_VAULT: '0xe396757EC7E6aC7C8E5ABE7285dde47b98F22db8', DANDELION_VOTING: '0x2211bFD97b1c02aE8Ac305d206e9780ba7D8BfF4', + FINANCE_VAULT: '0xdd92eb1478d3189707ab7f4a5ace3a615cdd0476', ACL: '0xFDcae423E5e92B76FE7D1e2bcabd36fca8a6a8Fe', PNETWORK: '0x341aA660fD5c280F5a9501E3822bB4a98E816D1b', - ASSOCIATION: '0xf1f6568a76559d85cF68E6597fA587544184dD46' + ASSOCIATION: '0xf1f6568a76559d85cF68E6597fA587544184dD46', + PBTC_MINTER: '0x0E3bDe3d39ded57813f0D0727e574D16D675938b', + SAFE: '0xBF828b541593AeFC98a65F15b70209151E7d67a2' } }, VOTE_STATUS: { diff --git a/tasks/check-forwarder.js b/tasks/check-forwarder.js new file mode 100644 index 0000000..05e9665 --- /dev/null +++ b/tasks/check-forwarder.js @@ -0,0 +1,22 @@ +const { task } = require('hardhat/config') + +const { ADDRESSES: _ADDRESSES } = require('../lib/constants') + +const main = async (_args, _hre) => { + if (!(_hre.network.name.toUpperCase() in _ADDRESSES)) { + console.warn('No addresses!') + return + } + const ADDRESSES = _ADDRESSES[_hre.network.name.toUpperCase()] + for (const entry of Object.entries(ADDRESSES)) { + console.log(`Checking ${entry[0]} @ ${entry[1]}`) + const c = await _hre.ethers.getContractAt(['function forwarder() view returns(address)'], entry[1]) + try { + console.log('Forwarder', await c.forwarder()) + } catch (_) { + console.log('No forwarder') + } + } +} + +task('permissions:check-forwarder').setAction(main) diff --git a/tasks/index.js b/tasks/index.js index 79a591f..65ce202 100644 --- a/tasks/index.js +++ b/tasks/index.js @@ -1,6 +1,7 @@ require('./acl-permission') require('./decode-forwarder-metadata') require('./check-all-permissions') +require('./check-forwarder') require('./check-permissions') require('./deploy-dao') require('./deploy_forwarder_bsc') diff --git a/test/fork/dao.test.js b/test/fork/dao.test.js index 39a35b3..1e3c340 100644 --- a/test/fork/dao.test.js +++ b/test/fork/dao.test.js @@ -8,13 +8,14 @@ const DaoPntAbi = require('../../lib/abi/daoPNT.json') const ERC20VaultAbi = require('../../lib/abi/ERC20Vault.json') const EthPntAbi = require('../../lib/abi/ethPNT.json') const FinanceAbi = require('../../lib/abi/Finance.json') +const pBTConEthereumAbi = require('../../lib/abi/pBTConEthereum.json') const pntOnGnosisAbi = require('../../lib/abi/PNTonGnosis.json') const pntOnPolygonAbi = require('../../lib/abi/PNTonPolygon.json') const VaultAbi = require('../../lib/abi/Vault.json') const { ADDRESSES: { GNOSIS: { - SAFE, + SAFE: SAFE_ON_GNOSIS, EPOCHS_MANAGER, STAKING_MANAGER, STAKING_MANAGER_LM, @@ -32,7 +33,19 @@ const { PNT_MINTER: PNT_MINTER_ON_GNOSIS, FORWARDER: FORWARDER_ON_GNOSIS }, - MAINNET: { ERC20_VAULT, DANDELION_VOTING: DANDELION_VOTING_V1, PNT: PNT_ON_ETH, ETHPNT, PNETWORK, ASSOCIATION }, + MAINNET: { + ERC20_VAULT, + DANDELION_VOTING: DANDELION_VOTING_V1, + PNT: PNT_ON_ETH, + ETHPNT, + PNETWORK, + ASSOCIATION, + FINANCE_VAULT: FINANCE_VAULT_V1, + PBTC: PBTC_ON_ETHEREUM, + PBTC_MINTER, + CROSS_EXECUTOR, + SAFE: SAFE_ON_ETH + }, POLYGON: { PNT: PNT_ON_POLYGON, FORWARDER: FORWARDER_ON_POLYGON, PNT_MINTER: PNT_MINTER_ON_POLYGON } }, MISC: { ONE_DAY }, @@ -56,9 +69,12 @@ const FORWARDER_DELEGATE_VOTE_USER_DATA = const FORWARDER_STAKE_USER_DATA = // secretlint-disable-next-line '0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000ddb5f4535123daa5ae343c24006f4075abaf5f7b0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000123456789012345678901234567890123456789000000000000000000000000dee8ebe2b7152eccd935fd67134bf1bad55302bc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000dee8ebe2b7152eccd935fd67134bf1bad55302bc0000000000000000000000000000000000000000000000000162ea854d0fc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642b54f551000000000000000000000000ddb5f4535123daa5ae343c24006f4075abaf5f7b0000000000000000000000000000000000000000000000000162ea854d0fc0000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000' +const FORWARDER_STAKE_USER_DATA_2 = + // secretlint-disable-next-line + '0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000ddb5f4535123daa5ae343c24006f4075abaf5f7b0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000008805aa0c1a8e59b03fa95740f691e28942cf44f6000000000000000000000000dee8ebe2b7152eccd935fd67134bf1bad55302bc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000dee8ebe2b7152eccd935fd67134bf1bad55302bc0000000000000000000000000000000000000000000000000b0bfa54806c1db90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642b54f551000000000000000000000000ddb5f4535123daa5ae343c24006f4075abaf5f7b0000000000000000000000000000000000000000000000000b0bfa54806c1db90000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000' const WITHDRAW_INFLATION_FROM_GNOSIS_USER_DATA = // secretlint-disable-next-line - '0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000443352d49b0000000000000000000000000123456789012345678901234567890123456789000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db8000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000124c322525d000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a30783632333939363865363233313136343638374342343066383338396439333364443766376530413500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + '0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000443352d49b000000000000000000000000e0bfe5ae5cebbf666c381f267187379117d0da73000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db8000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000124c322525d000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a30783632333939363865363233313136343638374342343066383338396439333364443766376530413500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' const WITHDRAW_INFLATION_FROM_GNOSIS_USER_DATA_2 = // secretlint-disable-next-line '0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000443352d49b00000000000000000000000001234567890123456789012345678901234567890000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000124c322525d0000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a30786631663635363861373635353964383563463638453635393766413538373534343138346444343600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' @@ -152,7 +168,6 @@ describe('Integration tests on Gnosis deployment', () => { feesManager, RewardsManager, rewardsManager, - ForwarderHost, forwarder, daoPNT, daoTreasury, @@ -166,10 +181,6 @@ describe('Integration tests on Gnosis deployment', () => { ] const missingSteps = async () => { - ForwarderHost = await ethers.getContractFactory('ForwarderHost') - forwarder = await ForwarderHost.deploy(pntOnGnosis.target) - await forwarder.whitelistOriginAddress(FORWARDER_ON_POLYGON) - await daoVoting.connect(daoOwner).changeForwarder(forwarder.target) await mintPntOnGnosis(forwarder.target, ethers.parseUnits('1')) await mintPntOnGnosis(daoVoting.target, ethers.parseUnits('1')) } @@ -240,7 +251,7 @@ describe('Integration tests on Gnosis deployment', () => { ;[faucet] = await ethers.getSigners() tokenHolders = await Promise.all(TOKEN_HOLDERS_ADDRESSES.map(ethers.getImpersonatedSigner)) user = await ethers.getImpersonatedSigner(USER_ADDRESS) - daoOwner = await ethers.getImpersonatedSigner(SAFE) + daoOwner = await ethers.getImpersonatedSigner(SAFE_ON_GNOSIS) await sendEth(ethers, faucet, daoOwner.address, '5') pntMinter = await ethers.getImpersonatedSigner(PNT_MINTER_ON_GNOSIS) @@ -266,6 +277,7 @@ describe('Integration tests on Gnosis deployment', () => { registrationManager = RegistrationManager.attach(REGISTRATION_MANAGER) feesManager = EpochsManager.attach(FEES_MANAGER) rewardsManager = RewardsManager.attach(REWARDS_MANAGER) + forwarder = await ethers.getContractAt('ForwarderHost', FORWARDER_ON_GNOSIS) await missingSteps() @@ -467,7 +479,6 @@ describe('Integration tests on Gnosis deployment', () => { // this test is coupled with Integration tests on Ethereum deployment -> should process pegOut, withdrawInflation, and pegIn to treasury it('should call withdrawInflation from Gnosis', async () => { - const CROSS_EXECUTOR_ETH = ADDRESS_PLACEHOLDER const ETH_PTN_ADDRESS = ETHPNT const amount = 10 @@ -478,7 +489,7 @@ describe('Integration tests on Gnosis deployment', () => { [ [ETH_PTN_ADDRESS, ETH_PTN_ADDRESS, ERC20_VAULT], [ - new ethers.Interface(EthPntAbi).encodeFunctionData('withdrawInflation', [CROSS_EXECUTOR_ETH, amount]), + new ethers.Interface(EthPntAbi).encodeFunctionData('withdrawInflation', [CROSS_EXECUTOR, amount]), new ethers.Interface(EthPntAbi).encodeFunctionData('approve', [ERC20_VAULT, amount]), new ethers.Interface(ERC20VaultAbi).encodeFunctionData('pegIn(uint256,address,string,bytes,bytes4)', [ amount, @@ -497,7 +508,7 @@ describe('Integration tests on Gnosis deployment', () => { pntOnGnosis.interface.encodeFunctionData('redeem(uint256,bytes,string,bytes4)', [ 1, userData, - CROSS_EXECUTOR_ETH, + CROSS_EXECUTOR, PNETWORK_NETWORK_IDS.MAINNET ]) ] @@ -519,7 +530,7 @@ describe('Integration tests on Gnosis deployment', () => { .withArgs( DANDELION_VOTING, 1, - CROSS_EXECUTOR_ETH, + CROSS_EXECUTOR, // secretlint-disable-next-line WITHDRAW_INFLATION_FROM_GNOSIS_USER_DATA, PNETWORK_NETWORK_IDS.GNOSIS, @@ -783,6 +794,42 @@ describe('Integration tests on Gnosis deployment', () => { expect(await pntOnGnosis.balanceOf(STAKING_MANAGER)).to.be.eq(smBalance + ethers.parseUnits('0.0999')) }) + it('[dapp] should stake from forwarder call (2)', async () => { + expect(await daoPNT.balanceOf(USER_ADDRESS)).to.be.eq(ethers.parseUnits('0')) + const smBalance = await pntOnGnosis.balanceOf(STAKING_MANAGER) + const metadata = encodeMetadata(ethers, { + userData: + // secretlint-disable-next-line + FORWARDER_STAKE_USER_DATA_2, + sourceNetworkId: PNETWORK_NETWORK_IDS.POLYGON, + senderAddress: FORWARDER_ON_POLYGON, + destinationNetworkId: PNETWORK_NETWORK_IDS.GNOSIS, + receiverAddress: forwarder.target + }) + await expect( + mintPToken( + pntOnGnosis, + pntMinter, + forwarder.target, + (ethers.parseUnits('0.797999999999789996') * (1000000n - 2500n)) / 1000000n, + metadata + ) + ) + .to.emit(pntOnGnosis, 'Approval') + .withArgs( + forwarder.target, + stakingManager.target, + (ethers.parseUnits('0.797999999999789996') * (1000000n - 2500n)) / 1000000n + ) + .to.emit(stakingManager, 'Staked') + expect(await daoPNT.balanceOf(USER_ADDRESS)).to.be.eq( + (ethers.parseUnits('0.797999999999789996') * (1000000n - 2500n)) / 1000000n + ) + expect(await pntOnGnosis.balanceOf(STAKING_MANAGER)).to.be.eq( + smBalance + (ethers.parseUnits('0.797999999999789996') * (1000000n - 2500n)) / 1000000n + ) + }) + it('[dapp] should delegateVote from forwarder call', async () => { const stakedAmount = ethers.parseUnits('10') await mintPntOnGnosis(user.address, stakedAmount) @@ -831,9 +878,8 @@ describe('Integration tests on Gnosis deployment', () => { }) it('[dapp] should open a vote to transfer from vault', async () => { - await mintPntOnGnosis(tokenHolders[0], ethers.parseUnits('200000')) await mintPntOnGnosis(daoTreasury.target, ethers.parseUnits('1000000')) - await stake(tokenHolders[0], ethers.parseUnits('200000')) + await grantCreateVotesPermission(acl, daoOwner, tokenHolders[0]) await daoVoting .connect(tokenHolders[0]) .newVote( @@ -857,9 +903,8 @@ describe('Integration tests on Gnosis deployment', () => { }) it('[dapp] should open a vote to withdraw inflation', async () => { - await mintPntOnGnosis(tokenHolders[0], ethers.parseUnits('200000')) await mintPntOnGnosis(daoTreasury.target, ethers.parseUnits('1000000')) - await stake(tokenHolders[0], ethers.parseUnits('200000')) + await grantCreateVotesPermission(acl, daoOwner, tokenHolders[0]) await daoVoting.connect(tokenHolders[0]).newVote( // secretlint-disable-next-line '0x000000010259461eed4d76d4f0f900f9035f6c4dfb39159a000004a408e1e4d3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000440005fe7f90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b2000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000443352d49b00000000000000000000000001234567890123456789012345678901234567890000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000124c322525d0000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a30786631663635363861373635353964383563463638453635393766413538373534343138346444343600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a30783031323334353637383930313233343536373839303132333435363738393031323334353637383900000000000000000000000000000000000000000000'.replace( @@ -905,6 +950,16 @@ describe('Integration tests on Gnosis deployment', () => { }) ).to.be.eq(expectedMetadata) }) + + it('should not permit to open a vote even when staking a lot', async () => { + const amount = ethers.parseUnits('10000000') + await mintPntOnGnosis(tokenHolders[0].address, amount) + await stake(tokenHolders[0], amount) + expect(await daoPNT.balanceOf(tokenHolders[0])).to.be.gte(amount) + await expect( + daoVoting.connect(tokenHolders[0]).newVote('0x', 'Should I become the owner?', true) + ).to.be.revertedWith('DANDELION_VOTING_CAN_NOT_OPEN_VOTE') + }) }) describe('Integration tests on Ethereum deployment', () => { @@ -921,10 +976,6 @@ describe('Integration tests on Ethereum deployment', () => { pegoutToken(vault, pnetwork, _recipient, PNT_ON_ETH, _value, _metadata) const missingSteps = async () => { - const CrossExecutor = await ethers.getContractFactory('CrossExecutor') - crossExecutor = await CrossExecutor.connect(safe).deploy(PNT_ON_ETH, ERC20_VAULT) - expect(await crossExecutor.owner()).to.be.eq(SAFE) - await crossExecutor.whitelistOriginAddress(DANDELION_VOTING) daoVotingV1 = await ethers.getContractAt(DandelionVotingAbi, DANDELION_VOTING_V1) // open vote to change inflationOwner const executionScript = encodeCallScript( @@ -960,7 +1011,9 @@ describe('Integration tests on Ethereum deployment', () => { association = await ethers.getImpersonatedSigner(ASSOCIATION) ethPnt = await ethers.getContractAt(EthPntAbi, ETHPNT) vault = await ethers.getContractAt('IErc20Vault', ERC20_VAULT) - safe = await ethers.getImpersonatedSigner(SAFE) + safe = await ethers.getImpersonatedSigner(SAFE_ON_ETH) + crossExecutor = await ethers.getContractAt('CrossExecutor', CROSS_EXECUTOR) + expect(await crossExecutor.owner()).to.be.eq(SAFE_ON_ETH) await sendEth(ethers, faucet, pnetwork.address, '10') await sendEth(ethers, faucet, association.address, '10') await sendEth(ethers, faucet, safe.address, '10') @@ -971,12 +1024,7 @@ describe('Integration tests on Ethereum deployment', () => { // this test is coupled with Integration tests on Gnosis deployment -> should call withdrawInflation from Gnosis it('should process pegOut, withdrawInflation, and pegIn to treasury', async () => { const metadata = encodeMetadata(ethers, { - userData: - // secretlint-disable-next-line - WITHDRAW_INFLATION_FROM_GNOSIS_USER_DATA.replaceAll( - ADDRESS_PLACEHOLDER.slice(2), - crossExecutor.target.slice(2) - ), + userData: WITHDRAW_INFLATION_FROM_GNOSIS_USER_DATA, sourceNetworkId: PNETWORK_NETWORK_IDS.GNOSIS, senderAddress: DANDELION_VOTING, destinationNetworkId: PNETWORK_NETWORK_IDS.MAINNET, @@ -1069,6 +1117,133 @@ describe('Integration tests on Ethereum deployment', () => { .withArgs(ADDRESS_PLACEHOLDER) }) + it('[dapp] should open a vote for migrating ethPNT treasury funds (1)', async () => { + await daoVotingV1.connect(association).newVote( + // secretlint-disable-next-line + '0x00000001dd92eb1478d3189707ab7f4a5ace3a615cdd047600000064beabacc8000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b20000000000000000000000002211bfd97b1c02ae8ac305d206e9780ba7d8bff40000000000000000000000000000000000000000000000056bc75e2d63100000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000056bc75e2d63100000e396757ec7e6ac7c8e5abe7285dde47b98f22db800000124c322525d0000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307866316636353638613736353539643835634636384536353937664135383735343431383464443436000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'shall we move ethPNT to v3 vault?', + false + ) + const voteId = await daoVotingV1.votesLength() + await Promise.all(tokenHolders.map((_holder) => daoVotingV1.connect(_holder).vote(voteId, true))) + const vote = await daoVotingV1.getVote(voteId) + await mineUpTo(vote[3] + 1n) + await expect(daoVotingV1.connect(association).executeVote(voteId)) + .to.emit(daoVotingV1, 'ExecuteVote') + .withArgs(voteId) + .and.to.emit(vault, 'PegIn') + .withArgs( + PNT_ON_ETH, + daoVotingV1.target, + ethers.parseUnits('100'), + ASSOCIATION, + '0x', + PNETWORK_NETWORK_IDS.MAINNET, + PNETWORK_NETWORK_IDS.GNOSIS + ) + }) + + it('[dapp] should open a vote for migrating ethPNT treasury funds (2)', async () => { + await daoVotingV1.connect(association).newVote( + // secretlint-disable-next-line + '0x00000001dd92eb1478d3189707ab7f4a5ace3a615cdd047600000064beabacc8000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b20000000000000000000000002211bfd97b1c02ae8ac305d206e9780ba7d8bff40000000000000000000000000000000000000000000000056bc75e2d63100000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000056bc75e2d63100000e396757ec7e6ac7c8e5abe7285dde47b98f22db800000144c322525d0000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307866316636353638613736353539643835634636384536353937664135383735343431383464443436000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004f00dbabe00000000000000000000000000000000000000000000000000000000', + 'shall we move ethPNT to v3 vault?', + false + ) + const voteId = await daoVotingV1.votesLength() + await Promise.all(tokenHolders.map((_holder) => daoVotingV1.connect(_holder).vote(voteId, true))) + const vote = await daoVotingV1.getVote(voteId) + await mineUpTo(vote[3] + 1n) + await expect(daoVotingV1.connect(association).executeVote(voteId)) + .to.emit(daoVotingV1, 'ExecuteVote') + .withArgs(voteId) + .and.to.emit(vault, 'PegIn') + .withArgs( + PNT_ON_ETH, + daoVotingV1.target, + ethers.parseUnits('100'), + ASSOCIATION, + '0xf00dbabe', + PNETWORK_NETWORK_IDS.MAINNET, + PNETWORK_NETWORK_IDS.GNOSIS + ) + }) + + it('[dapp] should open a vote for migrating ethPNT treasury funds (3)', async () => { + await crossExecutor + .connect(safe) + .call( + ethPnt.target, + ethPnt.interface.encodeFunctionData('withdrawInflation', [crossExecutor.target, ethers.parseUnits('100')]) + ) + await crossExecutor + .connect(safe) + .call( + ethPnt.target, + ethPnt.interface.encodeFunctionData('transfer', [FINANCE_VAULT_V1, ethers.parseUnits('100')]) + ) + await daoVotingV1.connect(association).newVote( + // secretlint-disable-next-line + '0x00000001dd92eb1478d3189707ab7f4a5ace3a615cdd047600000064beabacc8000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b20000000000000000000000002211bfd97b1c02ae8ac305d206e9780ba7d8bff40000000000000000000000000000000000000000000000056bc75e2d63100000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000056bc75e2d63100000e396757ec7e6ac7c8e5abe7285dde47b98f22db800000124c322525d0000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000f4ea6b892853413bd9d9f1a5d3a620a0ba39c5b200000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307866316636353638613736353539643835634636384536353937664135383735343431383464443436000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'shall we move ethPNT to v3 vault?', + false + ) + const voteId = await daoVotingV1.votesLength() + await Promise.all(tokenHolders.map((_holder) => daoVotingV1.connect(_holder).vote(voteId, true))) + const vote = await daoVotingV1.getVote(voteId) + await mineUpTo(vote[3] + 1n) + await expect(daoVotingV1.connect(association).executeVote(voteId)) + .to.emit(daoVotingV1, 'ExecuteVote') + .withArgs(voteId) + .and.to.emit(ethPnt, 'Transfer') + .withArgs(daoVotingV1.target, vault.target, ethers.parseUnits('100')) + .and.to.emit(vault, 'PegIn') + .withArgs( + PNT_ON_ETH, + daoVotingV1.target, + ethers.parseUnits('100'), + ASSOCIATION, + '0x', + PNETWORK_NETWORK_IDS.MAINNET, + PNETWORK_NETWORK_IDS.GNOSIS + ) + }) + + // pBTC is not native! so the execution script should not peg-in + it.skip('[dapp] should open a vote for migrating pBTC treasury funds (4', async () => { + const amount = ethers.parseEther('100') + const pbtc = await ethers.getContractAt(pBTConEthereumAbi, PBTC_ON_ETHEREUM) + const minter = await ethers.getImpersonatedSigner(PBTC_MINTER) + await sendEth(ethers, faucet, minter.address, amount) + await pbtc.connect(minter).mint(minter, amount) + await pbtc.connect(minter).transfer(FINANCE_VAULT_V1, amount) + await daoVotingV1.connect(association).newVote( + // secretlint-disable-next-line + '0x00000001dd92eb1478d3189707ab7f4a5ace3a615cdd047600000064beabacc800000000000000000000000062199b909fb8b8cf870f97bef2ce6783493c49080000000000000000000000002211bfd97b1c02ae8ac305d206e9780ba7d8bff40000000000000000000000000000000000000000000000056bc75e2d6310000062199b909fb8b8cf870f97bef2ce6783493c490800000044095ea7b3000000000000000000000000e396757ec7e6ac7c8e5abe7285dde47b98f22db80000000000000000000000000000000000000000000000056bc75e2d63100000e396757ec7e6ac7c8e5abe7285dde47b98f22db800000144c322525d0000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000062199b909fb8b8cf870f97bef2ce6783493c490800000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000f1918e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307830313233343536373839303132333435363738393031323334353637383930313233343536373839000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004f00dbabe00000000000000000000000000000000000000000000000000000000', + 'shall we move pBTC to v3 vault?', + false + ) + const voteId = await daoVotingV1.votesLength() + await Promise.all(tokenHolders.map((_holder) => daoVotingV1.connect(_holder).vote(voteId, true))) + const vote = await daoVotingV1.getVote(voteId) + await mineUpTo(vote[3] + 1n) + await expect(daoVotingV1.connect(association).executeVote(voteId)) + .to.emit(daoVotingV1, 'ExecuteVote') + .withArgs(voteId) + .and.to.emit(ethPnt, 'Transfer') + .withArgs(daoVotingV1.target, vault.target, ethers.parseUnits('100')) + .and.to.emit(vault, 'PegIn') + .withArgs( + PNT_ON_ETH, + daoVotingV1.target, + ethers.parseUnits('100'), + ASSOCIATION, + '0x', + PNETWORK_NETWORK_IDS.MAINNET, + PNETWORK_NETWORK_IDS.GNOSIS + ) + }) + it('should be able to change inflationOwner from CrossExecutor', async () => { await expect( crossExecutor @@ -1129,6 +1304,26 @@ describe('Integration tests on Polygon deployment', () => { ) }) + it('[dapp] should call forwarder for staking (2)', async () => { + await expect( + user.sendTransaction({ + to: '0xC85cd78555DF9991245F15c7AA6c4eDBb7791c19', + // secretlint-disable-next-line + data: '0x996adf550000000000000000000000000000000000000000000000000b1310c5a2bfcbac00000000000000000000000099405b4e46256dd28e424a0edf296a28e2ae32a0000000000000000000000000000000000000000000000000000000000000008000f1918e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000008805aa0c1a8e59b03fa95740f691e28942cf44f6000000000000000000000000dee8ebe2b7152eccd935fd67134bf1bad55302bc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000dee8ebe2b7152eccd935fd67134bf1bad55302bc0000000000000000000000000000000000000000000000000b0bfa54806c1db90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642b54f551000000000000000000000000ddb5f4535123daa5ae343c24006f4075abaf5f7b0000000000000000000000000000000000000000000000000b0bfa54806c1db90000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000' + }) + ) + .to.emit(pntOnPolygon, 'Redeem') + .withArgs( + forwarder.target, + ethers.parseUnits('0.797999999999789996'), + FORWARDER_ON_GNOSIS.toLowerCase().slice(2), + // secretlint-disable-next-line + FORWARDER_STAKE_USER_DATA_2, + PNETWORK_NETWORK_IDS.POLYGON, + PNETWORK_NETWORK_IDS.GNOSIS + ) + }) + it('[dapp] should call forwarder for voting', async () => { await expect( forwarder.connect(user).call(