diff --git a/abi/CraftingFacet.json b/abi/CraftingFacet.json new file mode 100644 index 00000000..5a10fd2e --- /dev/null +++ b/abi/CraftingFacet.json @@ -0,0 +1,351 @@ +[ + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAction", + "type": "uint256" + } + ], + "internalType": "struct CraftingInputItem[]", + "name": "inputs", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAction", + "type": "uint256" + } + ], + "internalType": "struct CraftingOutputItem[]", + "name": "outputs", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "internalType": "struct Recipe", + "name": "recipe", + "type": "tuple" + } + ], + "name": "addRecipe", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "recipeId", + "type": "uint256" + } + ], + "name": "craft", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "recipeId", + "type": "uint256" + } + ], + "name": "getRecipe", + "outputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAction", + "type": "uint256" + } + ], + "internalType": "struct CraftingInputItem[]", + "name": "inputs", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenAction", + "type": "uint256" + } + ], + "internalType": "struct CraftingOutputItem[]", + "name": "outputs", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "internalType": "struct Recipe", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numRecipes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "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": "nonpayable", + "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": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "setTerminusAuth", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/Diamond.json b/abi/Diamond.json new file mode 100644 index 00000000..19d7fa92 --- /dev/null +++ b/abi/Diamond.json @@ -0,0 +1,26 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_contractOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "_diamondCutFacet", + "type": "address" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] \ No newline at end of file diff --git a/abi/DiamondCutFacet.json b/abi/DiamondCutFacet.json new file mode 100644 index 00000000..07b52176 --- /dev/null +++ b/abi/DiamondCutFacet.json @@ -0,0 +1,84 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamondCut.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamondCut.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": "enum IDiamondCut.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondCut.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/DiamondLoupeFacet.json b/abi/DiamondLoupeFacet.json new file mode 100644 index 00000000..d3251465 --- /dev/null +++ b/abi/DiamondLoupeFacet.json @@ -0,0 +1,97 @@ +[ + { + "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": "struct IDiamondLoupe.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" + } +] \ No newline at end of file diff --git a/abi/DiamondReentrancyGuard.json b/abi/DiamondReentrancyGuard.json new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/abi/DiamondReentrancyGuard.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/abi/DropperFacet.json b/abi/DropperFacet.json new file mode 100644 index 00000000..02bc44e4 --- /dev/null +++ b/abi/DropperFacet.json @@ -0,0 +1,809 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "claimant", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "requestID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Claimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "poolId", + "type": "uint256" + } + ], + "name": "DropAuthorizationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DropCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "DropStatusChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "DropURIChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockDeadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "claim", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "claimant", + "type": "address" + }, + { + "internalType": "uint256", + "name": "blockDeadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "claimMessageHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "claimStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "authorizationTokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "authorizationPoolId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "createDrop", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + } + ], + "name": "dropStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + } + ], + "name": "dropUri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dropperVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + }, + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "erc1155_type", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "erc20_type", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "erc721_type", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + } + ], + "name": "getDrop", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct DroppableToken", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + } + ], + "name": "getDropAuthorization", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "poolId", + "type": "uint256" + } + ], + "internalType": "struct TerminusAuthorization", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "terminusAdminContractAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "terminusAdminPoolID", + "type": "uint256" + } + ], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "numDrops", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "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": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "poolId", + "type": "uint256" + } + ], + "name": "setDropAuthorization", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "setDropStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "setDropUri", + "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": [ + { + "internalType": "uint256", + "name": "poolId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "newPoolController", + "type": "address" + } + ], + "name": "surrenderPoolControl", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "terminus_mintable_type", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdrawERC1155", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdrawERC20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "withdrawERC721", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/ExploitContract.json b/abi/ExploitContract.json new file mode 100644 index 00000000..a365e2cd --- /dev/null +++ b/abi/ExploitContract.json @@ -0,0 +1,87 @@ +[ + { + "inputs": [], + "name": "didExploit", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "exploitableContractAddress", + "type": "address" + } + ], + "name": "exploit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "notify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_shouldCall", + "type": "bool" + } + ], + "name": "setShouldCallExploitableFunction", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_shouldExploit", + "type": "bool" + } + ], + "name": "setShouldExploit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "shouldCallExploitableFunction", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "shouldExploit", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/GOFPFacet.json b/abi/GOFPFacet.json new file mode 100644 index 00000000..19433558 --- /dev/null +++ b/abi/GOFPFacet.json @@ -0,0 +1,878 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "path", + "type": "uint256" + } + ], + "name": "PathChosen", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "path", + "type": "uint256" + } + ], + "name": "PathRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "name": "SessionActivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isChoosingActive", + "type": "bool" + } + ], + "name": "SessionChoosingActivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "playerTokenAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "paymentTokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "paymentAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "indexed": false, + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isForgiving", + "type": "bool" + } + ], + "name": "SessionCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "SessionUriChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "terminusPoolId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "name": "StageRewardChanged", + "type": "event" + }, + { + "inputs": [], + "name": "adminTerminusInfo", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "paths", + "type": "uint256[]" + } + ], + "name": "chooseCurrentStagePaths", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "playerTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "paymentTokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paymentAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "internalType": "uint256[]", + "name": "stages", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "isForgiving", + "type": "bool" + } + ], + "name": "createSession", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + } + ], + "name": "getCorrectPathForStage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + } + ], + "name": "getCurrentStage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + } + ], + "name": "getPathChoice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + } + ], + "name": "getSession", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "playerTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "paymentTokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paymentAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isChoosingActive", + "type": "bool" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "internalType": "uint256[]", + "name": "stages", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "isForgiving", + "type": "bool" + } + ], + "internalType": "struct Session", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getSessionTokenStakeGuard", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + } + ], + "name": "getStageReward", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "terminusPoolId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "internalType": "struct StageReward", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nftAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getStakedTokenInfo", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adminTerminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "adminTerminusPoolID", + "type": "uint256" + } + ], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "numSessions", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "numTokensStakedIntoSession", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "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": "nonpayable", + "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": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "path", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "setIsChoosingActive", + "type": "bool" + } + ], + "name": "setCorrectPathForStage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "name": "setSessionActive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isChoosingActive", + "type": "bool" + } + ], + "name": "setSessionChoosingActive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "setSessionUri", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "stages", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "terminusAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "terminusPoolIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "rewardAmounts", + "type": "uint256[]" + } + ], + "name": "setStageRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "stakeTokensIntoSession", + "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": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfStakerInSessionByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "unstakeTokensFromSession", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/IDiamondCut.json b/abi/IDiamondCut.json new file mode 100644 index 00000000..07b52176 --- /dev/null +++ b/abi/IDiamondCut.json @@ -0,0 +1,84 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamondCut.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamondCut.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": "enum IDiamondCut.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondCut.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "_init", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "diamondCut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/IDiamondLoupe.json b/abi/IDiamondLoupe.json new file mode 100644 index 00000000..4fafd7b7 --- /dev/null +++ b/abi/IDiamondLoupe.json @@ -0,0 +1,78 @@ +[ + { + "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": "struct IDiamondLoupe.Facet[]", + "name": "facets_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/IDropper.json b/abi/IDropper.json new file mode 100644 index 00000000..7d8003b6 --- /dev/null +++ b/abi/IDropper.json @@ -0,0 +1,809 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "claimant", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "requestID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Claimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "poolId", + "type": "uint256" + } + ], + "name": "DropAuthorizationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DropCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "DropStatusChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "DropURIChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockDeadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "claim", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "claimant", + "type": "address" + }, + { + "internalType": "uint256", + "name": "blockDeadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "claimMessageHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "claimStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "authorizationTokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "authorizationPoolId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "createDrop", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + } + ], + "name": "dropStatus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + } + ], + "name": "dropUri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dropperVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + }, + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "erc1155_type", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "erc20_type", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "erc721_type", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + } + ], + "name": "getDrop", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "tokenType", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct IDropper.Compound0", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + } + ], + "name": "getDropAuthorization", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "poolId", + "type": "uint256" + } + ], + "internalType": "struct IDropper.Compound1", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "terminusAdminContractAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "terminusAdminPoolID", + "type": "uint256" + } + ], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "numDrops", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "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": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "poolId", + "type": "uint256" + } + ], + "name": "setDropAuthorization", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "setDropStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "dropId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "setDropUri", + "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": [ + { + "internalType": "uint256", + "name": "poolId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "newPoolController", + "type": "address" + } + ], + "name": "surrenderPoolControl", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "terminus_mintable_type", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdrawERC1155", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdrawERC20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "withdrawERC721", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/IERC165.json b/abi/IERC165.json new file mode 100644 index 00000000..bd6b6e2d --- /dev/null +++ b/abi/IERC165.json @@ -0,0 +1,21 @@ +[ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/IERC173.json b/abi/IERC173.json new file mode 100644 index 00000000..087cf1c7 --- /dev/null +++ b/abi/IERC173.json @@ -0,0 +1,47 @@ +[ + { + "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" + } +] \ No newline at end of file diff --git a/abi/IERC721Mint.json b/abi/IERC721Mint.json new file mode 100644 index 00000000..992fe489 --- /dev/null +++ b/abi/IERC721Mint.json @@ -0,0 +1,318 @@ +[ + { + "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": 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" + }, + { + "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": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "stateMutability": "view", + "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": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "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": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "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" + } +] \ No newline at end of file diff --git a/abi/IMockContract.json b/abi/IMockContract.json new file mode 100644 index 00000000..49d11f67 --- /dev/null +++ b/abi/IMockContract.json @@ -0,0 +1,9 @@ +[ + { + "inputs": [], + "name": "notify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/ITerminus.json b/abi/ITerminus.json new file mode 100644 index 00000000..87dff1a2 --- /dev/null +++ b/abi/ITerminus.json @@ -0,0 +1,771 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "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": "id", + "type": "uint256" + }, + { + "indexed": false, + "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": false, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "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": false, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "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": false, + "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" + } + ], + "name": "createSimplePool", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "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": "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": "address", + "name": "newController", + "type": "address" + } + ], + "name": "setPoolController", + "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" + } + ], + "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" + } +] \ No newline at end of file diff --git a/abi/LibCrafting.json b/abi/LibCrafting.json new file mode 100644 index 00000000..a14e948c --- /dev/null +++ b/abi/LibCrafting.json @@ -0,0 +1,93 @@ +[ + { + "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": "INPUT_TOKEN_ACTION_BURN", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INPUT_TOKEN_ACTION_HOLD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INPUT_TOKEN_ACTION_TRANSFER", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OUTPUT_TOKEN_ACTION_MINT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OUTPUT_TOKEN_ACTION_TRANSFER", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/LibDiamond.json b/abi/LibDiamond.json new file mode 100644 index 00000000..e5d83ad3 --- /dev/null +++ b/abi/LibDiamond.json @@ -0,0 +1,63 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamondCut.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamondCut.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" + } +] \ No newline at end of file diff --git a/abi/LibDropper.json b/abi/LibDropper.json new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/abi/LibDropper.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/abi/LibGOFP.json b/abi/LibGOFP.json new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/abi/LibGOFP.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/abi/LibReentrancyGuard.json b/abi/LibReentrancyGuard.json new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/abi/LibReentrancyGuard.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/abi/LibSignatures.json b/abi/LibSignatures.json new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/abi/LibSignatures.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/abi/MockERC1155.json b/abi/MockERC1155.json new file mode 100644 index 00000000..a6a9e2d4 --- /dev/null +++ b/abi/MockERC1155.json @@ -0,0 +1,421 @@ +[ + { + "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": "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": "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": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "burnBatch", + "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": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "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": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "mintBatch", + "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": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "uri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/MockErc20.json b/abi/MockErc20.json index 3cb0065d..44b28f22 100644 --- a/abi/MockErc20.json +++ b/abi/MockErc20.json @@ -132,6 +132,37 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "decimals", diff --git a/abi/MockLinkToken.json b/abi/MockLinkToken.json index ad371d12..dc672d8d 100644 --- a/abi/MockLinkToken.json +++ b/abi/MockLinkToken.json @@ -121,6 +121,37 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "decimals", diff --git a/abi/MockTerminus.json b/abi/MockTerminus.json index 04729780..cb1f6654 100644 --- a/abi/MockTerminus.json +++ b/abi/MockTerminus.json @@ -439,6 +439,44 @@ "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": [ { @@ -598,6 +636,24 @@ "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": [ { @@ -616,6 +672,24 @@ "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": [ { diff --git a/abi/OwnershipFacet.json b/abi/OwnershipFacet.json new file mode 100644 index 00000000..087cf1c7 --- /dev/null +++ b/abi/OwnershipFacet.json @@ -0,0 +1,47 @@ +[ + { + "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" + } +] \ No newline at end of file diff --git a/abi/ReentrancyExploitable.json b/abi/ReentrancyExploitable.json new file mode 100644 index 00000000..cc2aea2a --- /dev/null +++ b/abi/ReentrancyExploitable.json @@ -0,0 +1,29 @@ +[ + { + "inputs": [], + "name": "claimWithGuard", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimWithoutGuard", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getCounter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/alembic.sample.ini b/api/alembic.sample.ini similarity index 100% rename from alembic.sample.ini rename to api/alembic.sample.ini diff --git a/alembic.sh b/api/alembic.sh similarity index 100% rename from alembic.sh rename to api/alembic.sh diff --git a/alembic/README b/api/alembic/README similarity index 100% rename from alembic/README rename to api/alembic/README diff --git a/alembic/env.py b/api/alembic/env.py similarity index 89% rename from alembic/env.py rename to api/alembic/env.py index a9289ca6..ddb3925c 100644 --- a/alembic/env.py +++ b/api/alembic/env.py @@ -18,10 +18,11 @@ # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata -#from lootbox.models import Base as LootboxBase +# from lootbox.models import Base as LootboxBase -from engineapi.models import Base as LootboxBase -target_metadata = LootboxBase.metadata +from engineapi.models import Base as EngineBase + +target_metadata = EngineBase.metadata # other values from the config, defined by the needs of env.py, # can be acquired: @@ -48,7 +49,7 @@ def run_migrations_offline(): literal_binds=True, dialect_opts={"paramstyle": "named"}, version_table="alembic_version", - version_table_schema=LootboxBase.metadata.schema, + version_table_schema=EngineBase.metadata.schema, ) with context.begin_transaction(): @@ -73,7 +74,7 @@ def run_migrations_online(): connection=connection, target_metadata=target_metadata, version_table="alembic_version", - version_table_schema=LootboxBase.metadata.schema, + version_table_schema=EngineBase.metadata.schema, ) with context.begin_transaction(): diff --git a/alembic/script.py.mako b/api/alembic/script.py.mako similarity index 100% rename from alembic/script.py.mako rename to api/alembic/script.py.mako diff --git a/alembic/versions/04e9f9125c90_initial.py b/api/alembic/versions/04e9f9125c90_initial.py similarity index 100% rename from alembic/versions/04e9f9125c90_initial.py rename to api/alembic/versions/04e9f9125c90_initial.py diff --git a/alembic/versions/3f2ec6253b7e_unique_constraints_contract_metadata.py b/api/alembic/versions/3f2ec6253b7e_unique_constraints_contract_metadata.py similarity index 100% rename from alembic/versions/3f2ec6253b7e_unique_constraints_contract_metadata.py rename to api/alembic/versions/3f2ec6253b7e_unique_constraints_contract_metadata.py diff --git a/alembic/versions/6b45cfe1799c_add_leaderboard_table_add_.py b/api/alembic/versions/6b45cfe1799c_add_leaderboard_table_add_.py similarity index 100% rename from alembic/versions/6b45cfe1799c_add_leaderboard_table_add_.py rename to api/alembic/versions/6b45cfe1799c_add_leaderboard_table_add_.py diff --git a/alembic/versions/782ac8fe23c8_add_resource_id_column.py b/api/alembic/versions/782ac8fe23c8_add_resource_id_column.py similarity index 100% rename from alembic/versions/782ac8fe23c8_add_resource_id_column.py rename to api/alembic/versions/782ac8fe23c8_add_resource_id_column.py diff --git a/alembic/versions/815ae0983ef1_add_raw_amount_column.py b/api/alembic/versions/815ae0983ef1_add_raw_amount_column.py similarity index 100% rename from alembic/versions/815ae0983ef1_add_raw_amount_column.py rename to api/alembic/versions/815ae0983ef1_add_raw_amount_column.py diff --git a/api/alembic/versions/d1be5f227664_registered_contract_and_call_requests.py b/api/alembic/versions/d1be5f227664_registered_contract_and_call_requests.py new file mode 100644 index 00000000..a8874899 --- /dev/null +++ b/api/alembic/versions/d1be5f227664_registered_contract_and_call_requests.py @@ -0,0 +1,154 @@ +"""registered_contracts and call_requests + +Revision ID: d1be5f227664 +Revises: 782ac8fe23c8 +Create Date: 2023-04-10 06:37:44.812202 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = "d1be5f227664" +down_revision = "782ac8fe23c8" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "registered_contracts", + sa.Column("id", postgresql.UUID(as_uuid=True), nullable=False), + sa.Column("blockchain", sa.VARCHAR(length=128), nullable=False), + sa.Column("address", sa.VARCHAR(length=256), nullable=False), + sa.Column("contract_type", sa.VARCHAR(length=128), nullable=False), + sa.Column("title", sa.VARCHAR(length=128), nullable=False), + sa.Column("description", sa.String(), nullable=True), + sa.Column("image_uri", sa.String(), nullable=True), + sa.Column("moonstream_user_id", postgresql.UUID(as_uuid=True), nullable=False), + sa.Column( + "created_at", + sa.DateTime(timezone=True), + server_default=sa.text("TIMEZONE('utc', statement_timestamp())"), + nullable=False, + ), + sa.Column( + "updated_at", + sa.DateTime(timezone=True), + server_default=sa.text("TIMEZONE('utc', statement_timestamp())"), + nullable=False, + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_registered_contracts")), + sa.UniqueConstraint( + "blockchain", + "address", + "contract_type", + name=op.f("uq_registered_contracts_blockchain"), + ), + sa.UniqueConstraint("id", name=op.f("uq_registered_contracts_id")), + ) + op.create_index( + op.f("ix_registered_contracts_address"), + "registered_contracts", + ["address"], + unique=False, + ) + op.create_index( + op.f("ix_registered_contracts_blockchain"), + "registered_contracts", + ["blockchain"], + unique=False, + ) + op.create_index( + op.f("ix_registered_contracts_contract_type"), + "registered_contracts", + ["contract_type"], + unique=False, + ) + op.create_index( + op.f("ix_registered_contracts_moonstream_user_id"), + "registered_contracts", + ["moonstream_user_id"], + unique=False, + ) + op.create_table( + "call_requests", + sa.Column("id", postgresql.UUID(as_uuid=True), nullable=False), + sa.Column( + "registered_contract_id", postgresql.UUID(as_uuid=True), nullable=False + ), + sa.Column("caller", sa.VARCHAR(length=256), nullable=False), + sa.Column("moonstream_user_id", postgresql.UUID(as_uuid=True), nullable=False), + sa.Column("method", sa.String(), nullable=False), + sa.Column( + "parameters", postgresql.JSONB(astext_type=sa.Text()), nullable=False + ), + sa.Column("expires_at", sa.DateTime(timezone=True), nullable=True), + sa.Column( + "created_at", + sa.DateTime(timezone=True), + server_default=sa.text("TIMEZONE('utc', statement_timestamp())"), + nullable=False, + ), + sa.Column( + "updated_at", + sa.DateTime(timezone=True), + server_default=sa.text("TIMEZONE('utc', statement_timestamp())"), + nullable=False, + ), + sa.ForeignKeyConstraint( + ["registered_contract_id"], + ["registered_contracts.id"], + name=op.f("fk_call_requests_registered_contract_id_registered_contracts"), + ondelete="CASCADE", + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_call_requests")), + sa.UniqueConstraint("id", name=op.f("uq_call_requests_id")), + ) + op.create_index( + op.f("ix_call_requests_caller"), "call_requests", ["caller"], unique=False + ) + op.create_index( + op.f("ix_call_requests_expires_at"), + "call_requests", + ["expires_at"], + unique=False, + ) + op.create_index( + op.f("ix_call_requests_method"), "call_requests", ["method"], unique=False + ) + op.create_index( + op.f("ix_call_requests_moonstream_user_id"), + "call_requests", + ["moonstream_user_id"], + unique=False, + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index( + op.f("ix_call_requests_moonstream_user_id"), table_name="call_requests" + ) + op.drop_index(op.f("ix_call_requests_method"), table_name="call_requests") + op.drop_index(op.f("ix_call_requests_expires_at"), table_name="call_requests") + op.drop_index(op.f("ix_call_requests_caller"), table_name="call_requests") + op.drop_table("call_requests") + op.drop_index( + op.f("ix_registered_contracts_moonstream_user_id"), + table_name="registered_contracts", + ) + op.drop_index( + op.f("ix_registered_contracts_contract_type"), table_name="registered_contracts" + ) + op.drop_index( + op.f("ix_registered_contracts_blockchain"), table_name="registered_contracts" + ) + op.drop_index( + op.f("ix_registered_contracts_address"), table_name="registered_contracts" + ) + op.drop_table("registered_contracts") + # ### end Alembic commands ### diff --git a/alembic/versions/f0e8022dc814_added_column_for_signatures.py b/api/alembic/versions/f0e8022dc814_added_column_for_signatures.py similarity index 100% rename from alembic/versions/f0e8022dc814_added_column_for_signatures.py rename to api/alembic/versions/f0e8022dc814_added_column_for_signatures.py diff --git a/api/engineapi/api.py b/api/engineapi/api.py index e3aa6491..45fdcb1d 100644 --- a/api/engineapi/api.py +++ b/api/engineapi/api.py @@ -15,6 +15,7 @@ from .routes.leaderboard import app as leaderboard_app from .routes.admin import app as admin_app from .routes.play import app as play_app +from .routes.contracts import app as contracts_app from .version import VERSION logging.basicConfig(level=logging.INFO) @@ -61,3 +62,4 @@ async def now_handler() -> data.NowResponse: app.mount("/drops", dropper_app) app.mount("/admin", admin_app) app.mount("/play", play_app) +app.mount("/contracts", contracts_app) diff --git a/api/engineapi/cli.py b/api/engineapi/cli.py index 8ea49195..6d7814c9 100644 --- a/api/engineapi/cli.py +++ b/api/engineapi/cli.py @@ -1,6 +1,6 @@ import argparse -from ast import arg import csv +import getpass import json import logging from uuid import UUID @@ -12,10 +12,7 @@ from . import signatures from . import data from . import auth - -# from .settings import BLOCKCHAINS_TO_BROWNIE_NETWORKS -from .models import DropperClaim, DropperContract - +from . import contracts_actions logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @@ -218,7 +215,6 @@ def dropper_delete_drop_handler(args: argparse.Namespace) -> None: def add_claimants_handler(args: argparse.Namespace) -> None: - """ Load list of claimats from csv file and add them to the database. """ @@ -226,11 +222,9 @@ def add_claimants_handler(args: argparse.Namespace) -> None: claimants = [] with open(args.claimants_file, "r") as f: - reader = csv.DictReader(f) for row in reader: - if len(row) != 2: logger.error(f"Invalid row: {row}") raise Exception("Invalid row") @@ -243,7 +237,6 @@ def add_claimants_handler(args: argparse.Namespace) -> None: ) with db.yield_db_session_ctx() as db_session: - try: claimants = actions.add_claimants( db_session=db_session, @@ -267,11 +260,9 @@ def delete_claimants_handler(args: argparse.Namespace) -> None: addresses = [] with open(args.claimants_file, "r") as f: - reader = csv.DictReader(f) for row in reader: - if len(row) != 1: logger.error(f"Invalid row: {row}") raise Exception("Invalid row") @@ -284,7 +275,6 @@ def delete_claimants_handler(args: argparse.Namespace) -> None: ) with db.yield_db_session_ctx() as db_session: - try: addresses = actions.delete_claimants( db_session=db_session, @@ -303,7 +293,6 @@ def list_claimants_handler(args: argparse.Namespace) -> None: """ with db.yield_db_session_ctx() as db_session: - try: claimants = actions.get_claimants( db_session=db_session, dropper_claim_id=args.dropper_claim_id @@ -315,12 +304,10 @@ def list_claimants_handler(args: argparse.Namespace) -> None: def add_scores_handler(args: argparse.Namespace) -> None: - """ Adding scores to leaderboard """ with open(args.input_file, "r") as f: - json_input = json.load(f) try: @@ -331,7 +318,6 @@ def add_scores_handler(args: argparse.Namespace) -> None: return with db.yield_db_session_ctx() as db_session: - try: scores = actions.add_scores( db_session=db_session, @@ -345,7 +331,6 @@ def add_scores_handler(args: argparse.Namespace) -> None: def list_leaderboards_handler(args: argparse.Namespace) -> None: - with db.yield_db_session_ctx() as db_session: Leaderboards = actions.list_leaderboards( db_session=db_session, @@ -357,7 +342,6 @@ def list_leaderboards_handler(args: argparse.Namespace) -> None: def create_leaderboard_handler(args: argparse.Namespace) -> None: - with db.yield_db_session_ctx() as db_session: Leaderboard = actions.create_leaderboard( db_session=db_session, @@ -368,31 +352,8 @@ def create_leaderboard_handler(args: argparse.Namespace) -> None: print(Leaderboard) -# def claimant_signature_refetch_handler(args: argparse.Namespace) -> None: - -# with db.yield_db_session_ctx() as db_session: - -# blockchain = ( -# db_session.query(DropperContract.blockchain) -# .join(DropperClaim, DropperClaim.dropper_contract_id == DropperContract.id) -# .filter(DropperClaim.id == UUID(args.dropper_claim_id)) -# ).one() - -# network.connect(BLOCKCHAINS_TO_BROWNIE_NETWORKS[blockchain.blockchain]) - -# claimant_signature = actions.refetch_drop_signatures( -# db_session=db_session, -# dropper_claim_id=args.dropper_claim_id, -# added_by="cli", -# ) - -# print(f"Amount of updated claimants: {len(claimant_signature)}") - - def assign_resource_handler(args: argparse.Namespace) -> None: - with db.yield_db_session_ctx() as db_session: - try: resource_id = actions.assign_resource( db_session=db_session, @@ -408,7 +369,6 @@ def assign_resource_handler(args: argparse.Namespace) -> None: def list_resources_handler(args: argparse.Namespace) -> None: - with db.yield_db_session_ctx() as db_session: resources = actions.list_leaderboards_resources(db_session=db_session) @@ -444,17 +404,40 @@ def delete_user_handler(args: argparse.Namespace) -> None: pass -def main() -> None: +def sign_handler(args: argparse.Namespace) -> None: + # Prompt user to enter the password for their signing account + password_raw = getpass.getpass( + prompt=f"Enter password for signing account ({args.signer}): " + ) + password = password_raw.strip() + signer = signatures.create_account_signer(args.signer, password) + signed_message = signer.sign_message(args.message) + print(signed_message) + +def main() -> None: parser = argparse.ArgumentParser( - description="dao: The command line interface to Moonstream DAO" + description="engineapi: The command line interface to Moonstream Engine API" ) parser.set_defaults(func=lambda _: parser.print_help()) subparsers = parser.add_subparsers() + parser_sign = subparsers.add_parser("sign", description="Manually sign a message") + parser_sign.add_argument( + "-m", "--message", required=True, type=str, help="Message to sign (hex bytes)" + ) + parser_sign.add_argument( + "-s", + "--signer", + required=True, + type=str, + help="Path to keystore file for signer", + ) + parser_sign.set_defaults(func=sign_handler) + # Signing server parser parser_signing_server = subparsers.add_parser( - "signing", description="Signing server commands" + "signing-server", description="Signing server commands" ) parser_signing_server.set_defaults( func=lambda _: parser_signing_server.print_help() @@ -929,16 +912,10 @@ def main() -> None: ) parser_dropper_list_claimants.set_defaults(func=list_claimants_handler) - # parser_dropper_claimant_signature_refetch = subparsers_dropper.add_parser( - # "signature-refetch", description="Refetch signature for claimant" - # ) - # parser_dropper_claimant_signature_refetch.add_argument( - # "--dropper-claim-id", type=str, required=True - # ) - - # parser_dropper_claimant_signature_refetch.set_defaults( - # func=claimant_signature_refetch_handler - # ) + contracts_parser = contracts_actions.generate_cli() + subparsers_engine_database.add_parser( + "contracts", parents=[contracts_parser], add_help=False + ) args = parser.parse_args() args.func(args) diff --git a/api/engineapi/contracts_actions.py b/api/engineapi/contracts_actions.py new file mode 100644 index 00000000..3d2a7238 --- /dev/null +++ b/api/engineapi/contracts_actions.py @@ -0,0 +1,646 @@ +import argparse +import json +import logging +import uuid +from enum import Enum +from typing import Any, Dict, List, Optional + +from sqlalchemy import func, text +from sqlalchemy.exc import IntegrityError, NoResultFound +from sqlalchemy.orm import Session +from web3 import Web3 + +from . import data, db +from .models import RegisteredContract, CallRequest + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class ContractAlreadyRegistered(Exception): + pass + + +class ContractType(Enum): + raw = "raw" + dropper = "dropper-v0.2.0" + + +def validate_method_and_params( + contract_type: ContractType, method: str, parameters: Dict[str, Any] +) -> None: + """ + Validate the given method and parameters for the specified contract_type. + """ + if contract_type == ContractType.raw: + if method != "": + raise ValueError("Method must be empty string for raw contract type") + if set(parameters.keys()) != {"calldata"}: + raise ValueError( + "Parameters must have only 'calldata' key for raw contract type" + ) + elif contract_type == ContractType.dropper: + if method != "claim": + raise ValueError("Method must be 'claim' for dropper contract type") + required_params = { + "dropId", + "requestID", + "blockDeadline", + "amount", + "signer", + "signature", + } + if set(parameters.keys()) != required_params: + raise ValueError( + f"Parameters must have {required_params} keys for dropper contract type" + ) + else: + raise ValueError(f"Unknown contract type {contract_type}") + + +def register_contract( + db_session: Session, + blockchain: str, + address: str, + contract_type: ContractType, + moonstream_user_id: uuid.UUID, + title: Optional[str], + description: Optional[str], + image_uri: Optional[str], +) -> data.RegisteredContract: + """ + Register a contract against the Engine instance + """ + + # TODO(zomglings): Make it so that contract_type is passed as a string. Convert to + # ContractType here. That will mean there is a single point at which the validation is + # performed rather than relying on each entrypoint to register_contract having to implement + # their own validation. + + try: + contract = RegisteredContract( + blockchain=blockchain, + address=Web3.toChecksumAddress(address), + contract_type=contract_type.value, + moonstream_user_id=moonstream_user_id, + title=title, + description=description, + image_uri=image_uri, + ) + db_session.add(contract) + db_session.commit() + except IntegrityError as err: + db_session.rollback() + raise ContractAlreadyRegistered() + except Exception as err: + db_session.rollback() + logger.error(repr(err)) + raise + + return render_registered_contract(contract) + + +def lookup_registered_contracts( + db_session: Session, + moonstream_user_id: uuid.UUID, + blockchain: Optional[str] = None, + address: Optional[str] = None, + contract_type: Optional[ContractType] = None, + limit: int = 10, + offset: Optional[int] = None, +) -> List[RegisteredContract]: + """ + Lookup a registered contract + """ + query = db_session.query(RegisteredContract).filter( + RegisteredContract.moonstream_user_id == moonstream_user_id + ) + + if blockchain is not None: + query = query.filter(RegisteredContract.blockchain == blockchain) + + if address is not None: + query = query.filter( + RegisteredContract.address == Web3.toChecksumAddress(address) + ) + + if contract_type is not None: + query = query.filter(RegisteredContract.contract_type == contract_type.value) + + if offset is not None: + query = query.offset(offset) + + query = query.limit(limit) + + return query.all() + + +def delete_registered_contract( + db_session: Session, + moonstream_user_id: uuid.UUID, + registered_contract_id: uuid.UUID, +) -> RegisteredContract: + """ + Delete a registered contract + """ + try: + registered_contract = ( + db_session.query(RegisteredContract) + .filter(RegisteredContract.moonstream_user_id == moonstream_user_id) + .filter(RegisteredContract.id == registered_contract_id) + .one() + ) + + db_session.delete(registered_contract) + db_session.commit() + except Exception as err: + db_session.rollback() + logger.error(repr(err)) + raise + + return registered_contract + + +def request_calls( + db_session: Session, + moonstream_user_id: uuid.UUID, + registered_contract_id: uuid.UUID, + call_specs: List[data.CallSpecification], + ttl_days: Optional[int] = None, +) -> int: + """ + Batch creates call requests for the given registered contract. + """ + # TODO(zomglings): Do not pass raw ttl_days into SQL query - could be subject to SQL injection + # For now, in the interest of speed, let us just be super cautious with ttl_days. + # Check that the ttl_days is indeed an integer + if ttl_days is not None: + assert ttl_days == int(ttl_days), "ttl_days must be an integer" + if ttl_days <= 0: + raise ValueError("ttl_days must be positive") + + # Check that the moonstream_user_id matches the RegisteredContract + try: + registered_contract = ( + db_session.query(RegisteredContract) + .filter( + RegisteredContract.id == registered_contract_id, + RegisteredContract.moonstream_user_id == moonstream_user_id, + ) + .one() + ) + except NoResultFound: + raise ValueError("Invalid registered_contract_id or moonstream_user_id") + + # Normalize the caller argument using Web3.toChecksumAddress + contract_type = ContractType(registered_contract.contract_type) + for specification in call_specs: + normalized_caller = Web3.toChecksumAddress(specification.caller) + + # Validate the method and parameters for the contract_type + validate_method_and_params( + contract_type, specification.method, specification.parameters + ) + + # Calculate the expiration time (if ttl_days is specified) + expires_at_sql = None + if ttl_days is not None: + expires_at_sql = text(f"(NOW() + INTERVAL '{ttl_days} days')") + + request = CallRequest( + registered_contract_id=registered_contract.id, + caller=normalized_caller, + moonstream_user_id=moonstream_user_id, + method=specification.method, + parameters=specification.parameters, + expires_at=expires_at_sql, + ) + + db_session.add(request) + # Insert the new rows into the database in a single transaction + try: + db_session.commit() + except Exception as e: + db_session.rollback() + raise e + + return len(call_specs) + + +def list_call_requests( + db_session: Session, + registered_contract_id: uuid.UUID, + caller: str, + limit: int = 10, + offset: Optional[int] = None, + show_expired: bool = False, +) -> List[data.CallRequest]: + """ + List call requests for the given moonstream_user_id + """ + # If show_expired is False, filter out expired requests using current time on database server + query = db_session.query(CallRequest).filter( + CallRequest.registered_contract_id == registered_contract_id, + CallRequest.caller == Web3.toChecksumAddress(caller), + ) + + if not show_expired: + query = query.filter( + CallRequest.expires_at > func.now(), + ) + + if offset is not None: + query = query.offset(offset) + + query = query.limit(limit) + results = query.all() + return [render_call_request(call_request) for call_request in results] + + +# TODO(zomglings): What should the delete functionality for call requests look like? +# - Delete expired requests for a given caller? +# - Delete all requests for a given caller? +# - Delete all requests for a given contract? +# - Delete request by ID? +# Should we implement these all using a single delete method, or a different method for each +# use case? +# Will come back to this once API is live. + + +def render_registered_contract(contract: RegisteredContract) -> data.RegisteredContract: + return data.RegisteredContract( + id=contract.id, + blockchain=contract.blockchain, + address=contract.address, + contract_type=contract.contract_type, + moonstream_user_id=contract.moonstream_user_id, + title=contract.title, + description=contract.description, + image_uri=contract.image_uri, + created_at=contract.created_at, + updated_at=contract.updated_at, + ) + + +def render_call_request(call_request: CallRequest) -> data.CallRequest: + return data.CallRequest( + id=call_request.id, + registered_contract_id=call_request.registered_contract_id, + moonstream_user_id=call_request.moonstream_user_id, + caller=call_request.caller, + method=call_request.method, + parameters=call_request.parameters, + expires_at=call_request.expires_at, + created_at=call_request.created_at, + updated_at=call_request.updated_at, + ) + + +def handle_register(args: argparse.Namespace) -> None: + """ + Handles the register command. + """ + try: + with db.yield_db_session_ctx() as db_session: + contract = register_contract( + db_session=db_session, + blockchain=args.blockchain, + address=args.address, + contract_type=args.contract_type, + moonstream_user_id=args.user_id, + title=args.title, + description=args.description, + image_uri=args.image_uri, + ) + except Exception as err: + logger.error(err) + return + print(contract.json()) + + +def handle_list(args: argparse.Namespace) -> None: + """ + Handles the list command. + """ + try: + with db.yield_db_session_ctx() as db_session: + contracts = lookup_registered_contracts( + db_session=db_session, + moonstream_user_id=args.user_id, + blockchain=args.blockchain, + address=args.address, + contract_type=args.contract_type, + limit=args.limit, + offset=args.offset, + ) + except Exception as err: + logger.error(err) + return + + print( + json.dumps( + [render_registered_contract(contract).dict() for contract in contracts] + ) + ) + + +def handle_delete(args: argparse.Namespace) -> None: + """ + Handles the delete command. + """ + try: + with db.yield_db_session_ctx() as db_session: + deleted_contract = delete_registered_contract( + db_session=db_session, + registered_contract_id=args.id, + moonstream_user_id=args.user_id, + ) + except Exception as err: + logger.error(err) + return + + print(render_registered_contract(deleted_contract).json()) + + +def handle_request_calls(args: argparse.Namespace) -> None: + """ + Handles the request-calls command. + + Reads a file of JSON-formatted call specifications from `args.call_specs`, + validates them, and adds them to the call_requests table in the Engine database. + + :param args: The arguments passed to the CLI command. + """ + with args.call_specs as ifp: + try: + call_specs_raw = json.load(ifp) + except Exception as e: + logger.error(f"Failed to load call specs: {e}") + return + + call_specs = [data.CallSpecification(**spec) for spec in call_specs_raw] + + try: + with db.yield_db_session_ctx() as db_session: + request_calls( + db_session=db_session, + moonstream_user_id=args.moonstream_user_id, + registered_contract_id=args.registered_contract_id, + call_specs=call_specs, + ttl_days=args.ttl_days, + ) + except Exception as e: + logger.error(f"Failed to request calls: {e}") + return + + +def handle_list_requests(args: argparse.Namespace) -> None: + """ + Handles the requests command. + + :param args: The arguments passed to the CLI command. + """ + try: + with db.yield_db_session_ctx() as db_session: + call_requests = list_call_requests( + db_session=db_session, + registered_contract_id=args.registered_contract_id, + caller=args.caller, + limit=args.limit, + offset=args.offset, + show_expired=args.show_expired, + ) + except Exception as e: + logger.error(f"Failed to list call requests: {e}") + return + + print(json.dumps([request.dict() for request in call_requests])) + + +def generate_cli() -> argparse.ArgumentParser: + """ + Generates a CLI which can be used to manage registered contracts on an Engine instance. + """ + parser = argparse.ArgumentParser(description="Manage registered contracts") + parser.set_defaults(func=lambda _: parser.print_help()) + subparsers = parser.add_subparsers() + + register_usage = "Register a new contract" + register_parser = subparsers.add_parser( + "register", help=register_usage, description=register_usage + ) + register_parser.add_argument( + "-b", + "--blockchain", + type=str, + required=True, + help="The blockchain the contract is deployed on", + ) + register_parser.add_argument( + "-a", + "--address", + type=str, + required=True, + help="The address of the contract", + ) + register_parser.add_argument( + "-c", + "--contract-type", + type=ContractType, + choices=ContractType, + required=True, + help="The type of the contract", + ) + register_parser.add_argument( + "-u", + "--user-id", + type=uuid.UUID, + required=True, + help="The ID of the Moonstream user under whom to register the contract", + ) + register_parser.add_argument( + "-t", + "--title", + type=str, + required=False, + default=None, + help="The title of the contract", + ) + register_parser.add_argument( + "-d", + "--description", + type=str, + required=False, + default=None, + help="The description of the contract", + ) + register_parser.add_argument( + "-i", + "--image-uri", + type=str, + required=False, + default=None, + help="The image URI of the contract", + ) + register_parser.set_defaults(func=handle_register) + + list_contracts_usage = "List all contracts matching certain criteria" + list_contracts_parser = subparsers.add_parser( + "list", help=list_contracts_usage, description=list_contracts_usage + ) + list_contracts_parser.add_argument( + "-b", + "--blockchain", + type=str, + required=False, + default=None, + help="The blockchain the contract is deployed on", + ) + list_contracts_parser.add_argument( + "-a", + "--address", + type=str, + required=False, + default=None, + help="The address of the contract", + ) + list_contracts_parser.add_argument( + "-c", + "--contract-type", + type=ContractType, + choices=ContractType, + required=False, + default=None, + help="The type of the contract", + ) + list_contracts_parser.add_argument( + "-u", + "--user-id", + type=uuid.UUID, + required=True, + help="The ID of the Moonstream user whose contracts to list", + ) + list_contracts_parser.add_argument( + "-N", + "--limit", + type=int, + required=False, + default=10, + help="The number of contracts to return", + ) + list_contracts_parser.add_argument( + "-n", + "--offset", + type=int, + required=False, + default=0, + help="The offset to start returning contracts from", + ) + list_contracts_parser.set_defaults(func=handle_list) + + delete_usage = "Delete a registered contract from an Engine instance" + delete_parser = subparsers.add_parser( + "delete", help=delete_usage, description=delete_usage + ) + delete_parser.add_argument( + "--id", + type=uuid.UUID, + required=True, + help="The ID of the contract to delete", + ) + delete_parser.add_argument( + "-u", + "--user-id", + type=uuid.UUID, + required=True, + help="The ID of the Moonstream user whose contract to delete", + ) + delete_parser.set_defaults(func=handle_delete) + + request_calls_usage = "Create call requests for a registered contract" + request_calls_parser = subparsers.add_parser( + "request-calls", help=request_calls_usage, description=request_calls_usage + ) + request_calls_parser.add_argument( + "-i", + "--registered-contract-id", + type=uuid.UUID, + required=True, + help="The ID of the registered contract to create call requests for", + ) + request_calls_parser.add_argument( + "-u", + "--moonstream-user-id", + type=uuid.UUID, + required=True, + help="The ID of the Moonstream user who owns the contract", + ) + request_calls_parser.add_argument( + "-c", + "--calls", + type=argparse.FileType("r"), + required=True, + help="Path to the JSON file with call specifications", + ) + request_calls_parser.add_argument( + "-t", + "--ttl-days", + type=int, + required=False, + default=None, + help="The number of days until the call requests expire", + ) + request_calls_parser.set_defaults(func=handle_request_calls) + + list_requests_usage = "List requests for calls on a registered contract" + list_requests_parser = subparsers.add_parser( + "requests", help=list_requests_usage, description=list_requests_usage + ) + list_requests_parser.add_argument( + "-i", + "--registered-contract-id", + type=uuid.UUID, + required=True, + help="The ID of the registered contract to list call requests for", + ) + list_requests_parser.add_argument( + "-c", + "--caller", + type=Web3.toChecksumAddress, + required=True, + help="Caller's address", + ) + list_requests_parser.add_argument( + "-N", + "--limit", + type=int, + required=False, + default=10, + help="The number of call requests to return", + ) + list_requests_parser.add_argument( + "-n", + "--offset", + type=int, + required=False, + default=0, + help="The offset to start returning contracts from", + ) + list_requests_parser.add_argument( + "--show-expired", + action="store_true", + help="Set this flag to also show expired requests. Default behavior is to hide these.", + ) + list_requests_parser.set_defaults(func=handle_list_requests) + + return parser + + +def main() -> None: + parser = generate_cli() + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/api/engineapi/data.py b/api/engineapi/data.py index d3fb117a..3ee408f4 100644 --- a/api/engineapi/data.py +++ b/api/engineapi/data.py @@ -1,6 +1,7 @@ +from datetime import datetime from typing import Any, Dict, List, Optional -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, validator from uuid import UUID @@ -176,6 +177,67 @@ class DropUpdatedResponse(BaseModel): active: bool = True +class RegisterContractRequest(BaseModel): + blockchain: str + address: str + contract_type: str + title: Optional[str] = None + description: Optional[str] = None + image_uri: Optional[str] = None + + +class RegisteredContract(BaseModel): + id: UUID + blockchain: str + address: str + contract_type: str + moonstream_user_id: UUID + title: Optional[str] + description: Optional[str] + image_uri: Optional[str] + created_at: datetime + updated_at: datetime + + @validator("id", "moonstream_user_id") + def validate_uuids(cls, v): + return str(v) + + @validator("created_at", "updated_at") + def validate_datetimes(cls, v): + return v.isoformat() + + +class CallSpecification(BaseModel): + caller: str + method: str + parameters: Dict[str, Any] + + +class CreateCallRequestsAPIRequest(BaseModel): + specifications: List[CallSpecification] = Field(default_factory=list) + ttl_days: Optional[int] = None + + +class CallRequest(BaseModel): + id: UUID + registered_contract_id: UUID + moonstream_user_id: UUID + caller: str + method: str + parameters: Dict[str, Any] + expires_at: datetime + created_at: datetime + updated_at: datetime + + @validator("id", "registered_contract_id", "moonstream_user_id") + def validate_uuids(cls, v): + return str(v) + + @validator("created_at", "updated_at", "expires_at") + def validate_datetimes(cls, v): + return v.isoformat() + + class QuartilesResponse(BaseModel): percentile_25: Dict[str, Any] percentile_50: Dict[str, Any] diff --git a/api/engineapi/middleware.py b/api/engineapi/middleware.py index 6c3f99b8..9e4cc570 100644 --- a/api/engineapi/middleware.py +++ b/api/engineapi/middleware.py @@ -3,6 +3,8 @@ import logging from typing import Any, Awaitable, Callable, Dict, Optional +from bugout.data import BugoutUser +from bugout.exceptions import BugoutResponseException from fastapi import HTTPException, Request, Response from starlette.middleware.base import BaseHTTPMiddleware from web3 import Web3 @@ -17,6 +19,66 @@ logger = logging.getLogger(__name__) +class BroodAuthMiddleware(BaseHTTPMiddleware): + """ + Checks the authorization header on the request. If it represents a verified Brood user, + create another request and get groups user belongs to, after this + adds a brood_user attribute to the request.state. Otherwise raises a 403 error. + + Taken almost verbatim from the Moonstream repo: + https://github.com/bugout-dev/moonstream/blob/99504a431acdd903259d1c4014a2808ce5a104c1/backend/moonstreamapi/middleware.py + """ + + def __init__(self, app, whitelist: Optional[Dict[str, str]] = None): + self.whitelist: Dict[str, str] = {} + if whitelist is not None: + self.whitelist = whitelist + super().__init__(app) + + async def dispatch( + self, request: Request, call_next: Callable[[Request], Awaitable[Response]] + ): + # Filter out endpoints with proper method to work without Bearer token (as create_user, login, etc) + path = request.url.path.rstrip("/") + method = request.method + if path in self.whitelist.keys() and self.whitelist[path] == method: + return await call_next(request) + + authorization_header = request.headers.get("authorization") + if authorization_header is None: + return Response( + status_code=403, content="No authorization header passed with request" + ) + user_token_list = authorization_header.split() + if len(user_token_list) != 2: + return Response(status_code=403, content="Wrong authorization header") + user_token: str = user_token_list[-1] + + try: + user: BugoutUser = bc.get_user(user_token) + if not user.verified: + logger.info( + f"Attempted journal access by unverified Brood account: {user.id}" + ) + return Response( + status_code=403, + content="Only verified accounts can access journals", + ) + if str(user.application_id) != str(MOONSTREAM_APPLICATION_ID): + return Response( + status_code=403, content="User does not belong to this application" + ) + except BugoutResponseException as e: + return Response(status_code=e.status_code, content=e.detail) + except Exception as e: + logger.error(f"Error processing Brood response: {str(e)}") + return Response(status_code=500, content="Internal server error") + + request.state.user = user + request.state.token = user_token + return await call_next(request) + + class EngineAuthMiddleware(BaseHTTPMiddleware): """ Checks the authorization header on the request. It it represents diff --git a/api/engineapi/models.py b/api/engineapi/models.py index 06cba5fa..0d6af246 100644 --- a/api/engineapi/models.py +++ b/api/engineapi/models.py @@ -12,10 +12,10 @@ String, UniqueConstraint, ) -from sqlalchemy.dialects.postgresql import UUID, JSONB +from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.ext.compiler import compiles from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.sql import expression, and_ +from sqlalchemy.sql import and_, expression """ Naming conventions doc @@ -155,6 +155,82 @@ class DropperClaimant(Base): # type: ignore ) +class RegisteredContract(Base): # type: ignore + __tablename__ = "registered_contracts" + __table_args__ = ( + UniqueConstraint( + "blockchain", + "address", + "contract_type", + ), + ) + + id = Column( + UUID(as_uuid=True), + primary_key=True, + default=uuid.uuid4, + unique=True, + ) + blockchain = Column(VARCHAR(128), nullable=False, index=True) + address = Column(VARCHAR(256), nullable=False, index=True) + contract_type = Column(VARCHAR(128), nullable=False, index=True) + title = Column(VARCHAR(128), nullable=False) + description = Column(String, nullable=True) + image_uri = Column(String, nullable=True) + # User ID of the Moonstream user who registered this contract. + moonstream_user_id = Column(UUID(as_uuid=True), nullable=False, index=True) + + created_at = Column( + DateTime(timezone=True), server_default=utcnow(), nullable=False + ) + updated_at = Column( + DateTime(timezone=True), + server_default=utcnow(), + onupdate=utcnow(), + nullable=False, + ) + + +class CallRequest(Base): + __tablename__ = "call_requests" + + id = Column( + UUID(as_uuid=True), + primary_key=True, + default=uuid.uuid4, + unique=True, + nullable=False, + ) + + registered_contract_id = Column( + UUID(as_uuid=True), + ForeignKey("registered_contracts.id", ondelete="CASCADE"), + nullable=False, + ) + caller = Column(VARCHAR(256), nullable=False, index=True) + # User ID of the Moonstream user who requested this call. + # For now, this duplicates the moonstream_user_id in the registered_contracts table. Nevertheless, + # we keep this column here for auditing purposes. In the future, we will add a group_id column to + # the registered_contracts table, and this column will be used to track the user from that group + # who made each call request. + moonstream_user_id = Column(UUID(as_uuid=True), nullable=False, index=True) + method = Column(String, nullable=False, index=True) + # TODO(zomglings): Should we conditional indices on parameters depending on the contract type? + parameters = Column(JSONB, nullable=False) + + expires_at = Column(DateTime(timezone=True), nullable=True, index=True) + + created_at = Column( + DateTime(timezone=True), server_default=utcnow(), nullable=False + ) + updated_at = Column( + DateTime(timezone=True), + server_default=utcnow(), + onupdate=utcnow(), + nullable=False, + ) + + class Leaderboard(Base): # type: ignore __tablename__ = "leaderboards" # __table_args__ = (UniqueConstraint("dropper_contract_id", "address"),) diff --git a/api/engineapi/routes/contracts.py b/api/engineapi/routes/contracts.py new file mode 100644 index 00000000..3fc3a7d6 --- /dev/null +++ b/api/engineapi/routes/contracts.py @@ -0,0 +1,210 @@ +""" +Contract registration API + +Moonstream users can register contracts on Moonstream Engine. This allows them to use these contracts +as part of their chain-adjacent activities (like performing signature-based token distributions on the +Dropper contract). +""" +import logging +from typing import Dict, List, Optional +from uuid import UUID + +from fastapi import Body, Depends, FastAPI, Query, Request +from fastapi.middleware.cors import CORSMiddleware +from sqlalchemy.orm import Session + +from .. import data, db +from .. import contracts_actions +from ..middleware import BroodAuthMiddleware, EngineHTTPException +from ..settings import DOCS_TARGET_PATH, ORIGINS +from ..version import VERSION + +logger = logging.getLogger(__name__) + + +TITLE = "Moonstream Engine Contracts API" +DESCRIPTION = "Users can register contracts on the Moonstream Engine for use in chain-adjacent activities, like setting up signature-based token distributions." + + +tags_metadata = [ + { + "name": "contracts", + "description": DESCRIPTION, + } +] + + +whitelist_paths = { + "/contracts/openapi.json": "GET", + f"/contracts/{DOCS_TARGET_PATH}": "GET", + "/contracts/types": "GET", + "/contracts/requests": "GET", +} + +app = FastAPI( + title=TITLE, + description=DESCRIPTION, + version=VERSION, + openapi_tags=tags_metadata, + openapi_url="/openapi.json", + docs_url=None, + redoc_url=f"/{DOCS_TARGET_PATH}", +) + + +app.add_middleware(BroodAuthMiddleware, whitelist=whitelist_paths) + +app.add_middleware( + CORSMiddleware, + allow_origins=ORIGINS, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/types") +async def contract_types() -> Dict[str, str]: + """ + Describes the contract_types that users can register contracts as against this API. + """ + return { + contracts_actions.ContractType.raw.value: "A generic smart contract. You can ask users to submit arbitrary calldata to this contract.", + contracts_actions.ContractType.dropper.value: "A Dropper contract. You can authorize users to submit claims against this contract.", + } + + +@app.get("/") +async def list_registered_contracts( + request: Request, + blockchain: Optional[str] = Query(None), + address: Optional[str] = Query(None), + contract_type: Optional[contracts_actions.ContractType] = Query(None), + limit: int = Query(10), + offset: Optional[int] = Query(None), + db_session: Session = Depends(db.yield_db_read_only_session), +) -> List[data.RegisteredContract]: + """ + Users can use this endpoint to look up the contracts they have registered against this API. + """ + contracts = contracts_actions.lookup_registered_contracts( + db_session=db_session, + moonstream_user_id=request.state.user.id, + blockchain=blockchain, + address=address, + contract_type=contract_type, + limit=limit, + offset=offset, + ) + return [ + contracts_actions.render_registered_contract(contract) for contract in contracts + ] + + +@app.post("/register", response_model=data.RegisteredContract) +async def register_contract( + request: Request, + contract: data.RegisterContractRequest, + db_session: Session = Depends(db.yield_db_session), +) -> data.RegisteredContract: + """ + Allows users to register contracts. + """ + try: + contract_type = contracts_actions.ContractType(contract.contract_type) + except ValueError: + raise EngineHTTPException(status_code=404, detail="Invalid contract type") + try: + registered_contract = contracts_actions.register_contract( + db_session=db_session, + moonstream_user_id=request.state.user.id, + blockchain=contract.blockchain, + address=contract.address, + contract_type=contract_type, + title=contract.title, + description=contract.description, + image_uri=contract.image_uri, + ) + except contracts_actions.ContractAlreadyRegistered: + raise EngineHTTPException( + status_code=409, + detail="Contract already registered", + ) + return registered_contract + + +@app.delete("/{contract_id}", response_model=data.RegisteredContract) +async def delete_contract( + request: Request, + contract_id: UUID, + db_session: Session = Depends(db.yield_db_session), +) -> data.RegisteredContract: + """ + Allows users to delete contracts that they have registered. + """ + try: + deleted_contract = contracts_actions.delete_registered_contract( + db_session=db_session, + moonstream_user_id=request.state.user.id, + registered_contract_id=contract_id, + ) + except Exception as err: + logger.error(repr(err)) + raise EngineHTTPException(status_code=500) + + return contracts_actions.render_registered_contract(deleted_contract) + + +@app.get("/requests", response_model=List[data.CallRequest]) +async def list_requests( + contract_id: UUID = Query(...), + caller: str = Query(...), + limit: int = Query(100), + offset: Optional[int] = Query(None), + db_session: Session = Depends(db.yield_db_read_only_session), +) -> List[data.CallRequest]: + """ + Allows API user to see all unexpired call requests for a given caller against a given contract. + """ + try: + requests = contracts_actions.list_call_requests( + db_session=db_session, + registered_contract_id=contract_id, + caller=caller, + limit=limit, + offset=offset, + show_expired=False, + ) + except Exception as e: + logger.error(repr(e)) + raise EngineHTTPException(status_code=500) + + return requests + + +@app.post("/{contract_id}/requests") +async def create_requests( + request: Request, + contract_id: UUID, + data: data.CreateCallRequestsAPIRequest = Body(...), + db_session: Session = Depends(db.yield_db_session), +) -> int: + """ + Allows API user to register call requests from given call specifications. + """ + try: + num_requests = contracts_actions.request_calls( + db_session=db_session, + moonstream_user_id=request.state.user.id, + registered_contract_id=contract_id, + call_specs=data.specifications, + ttl_days=data.ttl_days, + ) + except Exception as e: + logger.error(repr(e)) + raise EngineHTTPException(status_code=500) + + return num_requests + + +# TODO(zomglings): Make it possible for users to delete call requests. diff --git a/api/engineapi/settings.py b/api/engineapi/settings.py index ec6ba4fb..be2de443 100644 --- a/api/engineapi/settings.py +++ b/api/engineapi/settings.py @@ -1,4 +1,5 @@ import os +import warnings from web3 import Web3, HTTPProvider from web3.middleware import geth_poa_middleware @@ -8,11 +9,13 @@ BUGOUT_BROOD_URL = os.environ.get("BUGOUT_BROOD_URL", "https://auth.bugout.dev") BUGOUT_SPIRE_URL = os.environ.get("BUGOUT_SPIRE_URL", "https://spire.bugout.dev") - bugout_client = Bugout(brood_api_url=BUGOUT_BROOD_URL, spire_api_url=BUGOUT_SPIRE_URL) -# Origin +ENGINE_DEV_RAW = os.environ.get("ENGINE_DEV", "") +ENGINE_DEV = True if ENGINE_DEV_RAW in {"1", "true", "yes", "t", "y"} else False + +# Authorized origins for CORS RAW_ORIGINS = os.environ.get("ENGINE_CORS_ALLOWED_ORIGINS") if RAW_ORIGINS is None: raise ValueError( @@ -20,39 +23,49 @@ ) ORIGINS = RAW_ORIGINS.split(",") -ENGINE_BROWNIE_NETWORK = os.environ.get("ENGINE_BROWNIE_NETWORK") -if ENGINE_BROWNIE_NETWORK is None: - raise ValueError("ENGINE_BROWNIE_NETWORK environment variable must be set") +# Open API documentation path +DOCS_TARGET_PATH = os.environ.get("DOCS_TARGET_PATH", "docs") -ENGINE_DROPPER_ADDRESS = os.environ.get("ENGINE_DROPPER_ADDRESS") -if ENGINE_DROPPER_ADDRESS is None: - raise ValueError("ENGINE_DROPPER_ADDRESS environment variable must be set") +# If SIGNER_KEYSTORE and SIGNER_PASSWORD are set, then we use the local signer. +# Otherwise, we use the AWS signer. SIGNER_KEYSTORE = os.environ.get("SIGNER_KEYSTORE") SIGNER_PASSWORD = os.environ.get("SIGNER_PASSWORD") MOONSTREAM_SIGNING_SERVER_IP = os.environ.get("MOONSTREAM_SIGNING_SERVER_IP", None) - -DOCS_TARGET_PATH = os.environ.get("DOCS_TARGET_PATH", "docs") - - -# AWS signer +# Settings related to the AWS signer AWS_DEFAULT_REGION = os.environ.get("AWS_DEFAULT_REGION") if AWS_DEFAULT_REGION is None: - raise ValueError("AWS_DEFAULT_REGION environment variable must be set") + if not ENGINE_DEV: + raise ValueError("AWS_DEFAULT_REGION environment variable must be set") + else: + warnings.warn( + 'AWS_DEFAULT_REGION environment variable is not set. Using "us-east-1".' + ) + AWS_DEFAULT_REGION = "us-east-1" MOONSTREAM_AWS_SIGNER_LAUNCH_TEMPLATE_ID = os.environ.get( "MOONSTREAM_AWS_SIGNER_LAUNCH_TEMPLATE_ID" ) if MOONSTREAM_AWS_SIGNER_LAUNCH_TEMPLATE_ID is None: - raise ValueError( - "MOONSTREAM_AWS_SIGNER_LAUNCH_TEMPLATE_ID environment variable must be set" - ) + if not ENGINE_DEV: + raise ValueError( + "MOONSTREAM_AWS_SIGNER_LAUNCH_TEMPLATE_ID environment variable must be set" + ) + else: + warnings.warn( + "MOONSTREAM_AWS_SIGNER_LAUNCH_TEMPLATE_ID environment variable is not set." + ) MOONSTREAM_AWS_SIGNER_IMAGE_ID = os.environ.get("MOONSTREAM_AWS_SIGNER_IMAGE_ID") if MOONSTREAM_AWS_SIGNER_IMAGE_ID is None: - raise ValueError("MOONSTREAM_AWS_SIGNER_IMAGE_ID environment variable must be set") + if not ENGINE_DEV: + raise ValueError( + "MOONSTREAM_AWS_SIGNER_IMAGE_ID environment variable must be set" + ) + else: + warnings.warn("MOONSTREAM_AWS_SIGNER_IMAGE_ID environment is not set.") MOONSTREAM_AWS_SIGNER_INSTANCE_PORT = 17181 @@ -126,7 +139,8 @@ if ENGINE_DB_URI_READ_ONLY is None: raise ValueError("ENGINE_DB_URI_READ_ONLY environment variable must be set") -ENGINE_POOL_SIZE_RAW = os.environ.get("ENGINE_POOL_SIZE", 0) +ENGINE_POOL_SIZE_RAW = os.environ.get("ENGINE_POOL_SIZE") +ENGINE_POOL_SIZE = 0 try: if ENGINE_POOL_SIZE_RAW is not None: ENGINE_POOL_SIZE = int(ENGINE_POOL_SIZE_RAW) diff --git a/api/engineapi/signatures.py b/api/engineapi/signatures.py index fb5ebdc7..b9a19c19 100644 --- a/api/engineapi/signatures.py +++ b/api/engineapi/signatures.py @@ -4,12 +4,13 @@ import abc import logging import json -from typing import Any, List, Optional +from typing import Any, List, Optional, Union import boto3 from web3 import Web3 from eth_account import Account +from eth_account.messages import encode_defunct from eth_account._utils.signing import sign_message_hash import eth_keys import requests @@ -111,8 +112,12 @@ def batch_sign_message(self, messages_list: List[str]): return signed_messages_list -def get_signing_account(raw_message: str, signature: str) -> str: - return Web3.eth.account.recover_message(raw_message, signature=signature) +def create_account_signer(keystore: str, password: str) -> AccountSigner: + with open(keystore) as keystore_file: + keystore_data = json.load(keystore_file) + private_key = Account.decrypt(keystore_data, password) + signer = AccountSigner(private_key) + return signer class InstanceSigner(Signer): @@ -217,10 +222,7 @@ def batch_sign_message(self, messages_list: List[str]): DROP_SIGNER: Optional[Signer] = None if SIGNER_KEYSTORE is not None and SIGNER_PASSWORD is not None: - with open(SIGNER_KEYSTORE) as keystore_file: - keystore_data = json.load(keystore_file) - private_key = Account.decrypt(keystore_data, SIGNER_PASSWORD) - DROP_SIGNER = AccountSigner(private_key) + DROP_SIGNER = create_account_signer(SIGNER_KEYSTORE, SIGNER_PASSWORD) if DROP_SIGNER is None: DROP_SIGNER = InstanceSigner(MOONSTREAM_SIGNING_SERVER_IP) diff --git a/api/engineapi/version.txt b/api/engineapi/version.txt index bcab45af..81340c7e 100644 --- a/api/engineapi/version.txt +++ b/api/engineapi/version.txt @@ -1 +1 @@ -0.0.3 +0.0.4 diff --git a/api/setup.py b/api/setup.py index 655fd0d5..173b8df0 100644 --- a/api/setup.py +++ b/api/setup.py @@ -14,7 +14,7 @@ install_requires=[ "boto3", "bugout>=0.2.2", - "eip712", + "eip712==0.1.0", "eth-typing>=2.3.0", "fastapi", "psycopg2-binary", @@ -22,11 +22,11 @@ "sqlalchemy", "tqdm", "uvicorn", - "web3>=5.30.0", + "web3>=5.30.0, <6", "tabulate", ], extras_require={ - "dev": ["alembic", "brownie", "black", "mypy", "isort"], + "dev": ["alembic", "black", "mypy", "isort"], "distribute": ["setuptools", "twine", "wheel"], }, description="Command line interface for Moonstream Engine API",