diff --git a/.gitignore b/.gitignore index 391d7b76..724df8a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ .direnv +.vscode target/ +artifacts/bin/ tarpaulin-report.html -artifacts # TS node_modules @@ -12,9 +13,7 @@ flow-report.json .envrc bin -packages-ts/gauntlet-terra-contracts/artifacts/bin - # test packages-ts/gauntlet-terra-contracts/codeIds/test* tests/e2e/logs -packages-ts/gauntlet-terra-contracts/networks/.env.test* \ No newline at end of file +networks/.env.test* diff --git a/packages-ts/gauntlet-terra-contracts/README.md b/packages-ts/gauntlet-terra-contracts/README.md index f89a8c7a..fbb2eb03 100644 --- a/packages-ts/gauntlet-terra-contracts/README.md +++ b/packages-ts/gauntlet-terra-contracts/README.md @@ -35,7 +35,7 @@ The command follows the same style: For our Access Controller contract, we could perform: -- Deploy +- Deploy chainlink contract ``` ./bin/gauntlet-terra-macos access_controller:deploy --network=bombay-testnet ``` @@ -62,4 +62,25 @@ The following contracts have the previous actions available: - `access_controller` - `flags` - `ocr2` -- `deviation_flagging_validator` \ No newline at end of file +- `deviation_flagging_validator` + +## Multisig Commands + +- Create a cw4 group + +This instantiates a group with 3 members, each having equal voting power, for a total of 1+1+1=3 votes: (passing admin address is optional) + +``` +yarn gauntlet cw4_group:deploy --members='[terra1pl4k5rj2jv6phm2vvhkttju7px6va2ja2v3haw,terra1tsxn3zzp09kvwpx03gzwquhc6nn794vvznuhzr,terra1s66cck3sxacdc2jfpdd4t4pk4yzc60pa72ssdr]' --admin=terra1pl4k5rj2jv6phm2vvhkttju7px6va2ja2v3haw --network=bombay-testnet +``` +- Create a cw3 flex multisig wallet + +This instantiates a multisig wallet, for the group above... with a max voting period of 28800s (8 hours) and an threshold of 100 percent of the vote: + +``` +yarn gauntlet cw3_flex_multisig:deploy --network=bombay-testnet --group=terra1wx0ahe6gpeyyh0wtq3cyc26f2wyk08kjtndxhf --time=28800 --threshold=3 +``` + +You may also specify the threshold as an absolute number of votes, or even a quorum combined with a threshold percentage. +( See https://docs.cosmwasm.com/cw-plus/0.9.0/cw3/cw3-flex-spec for details ) + diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/all_accounts_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/all_accounts_response.json new file mode 100644 index 00000000..cea50fba --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/all_accounts_response.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AllAccountsResponse", + "type": "object", + "required": [ + "accounts" + ], + "properties": { + "accounts": { + "type": "array", + "items": { + "type": "string" + } + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/all_allowances_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/all_allowances_response.json new file mode 100644 index 00000000..a8a11a55 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/all_allowances_response.json @@ -0,0 +1,99 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AllAllowancesResponse", + "type": "object", + "required": [ + "allowances" + ], + "properties": { + "allowances": { + "type": "array", + "items": { + "$ref": "#/definitions/AllowanceInfo" + } + } + }, + "definitions": { + "AllowanceInfo": { + "type": "object", + "required": [ + "allowance", + "expires", + "spender" + ], + "properties": { + "allowance": { + "$ref": "#/definitions/Uint128" + }, + "expires": { + "$ref": "#/definitions/Expiration" + }, + "spender": { + "type": "string" + } + } + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "anyOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/allowance_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/allowance_response.json new file mode 100644 index 00000000..71b49adf --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/allowance_response.json @@ -0,0 +1,81 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AllowanceResponse", + "type": "object", + "required": [ + "allowance", + "expires" + ], + "properties": { + "allowance": { + "$ref": "#/definitions/Uint128" + }, + "expires": { + "$ref": "#/definitions/Expiration" + } + }, + "definitions": { + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "anyOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/balance_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/balance_response.json new file mode 100644 index 00000000..4e1a0be2 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/balance_response.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "BalanceResponse", + "type": "object", + "required": [ + "balance" + ], + "properties": { + "balance": { + "$ref": "#/definitions/Uint128" + } + }, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/cw20_execute_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/cw20_execute_msg.json new file mode 100644 index 00000000..4dd7b8ad --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/cw20_execute_msg.json @@ -0,0 +1,442 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw20ExecuteMsg", + "anyOf": [ + { + "description": "Transfer is a base message to move tokens to another account without triggering actions", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "recipient" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "recipient": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Burn is a base message to destroy tokens forever", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Send is a base message to transfer tokens to a contract and trigger an action on the receiving contract.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "contract", + "msg" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "contract": { + "type": "string" + }, + "msg": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"approval\" extension. Allows spender to access an additional amount tokens from the owner's (env.sender) account. If expires is Some(), overwrites current allowance expiration with this one.", + "type": "object", + "required": [ + "increase_allowance" + ], + "properties": { + "increase_allowance": { + "type": "object", + "required": [ + "amount", + "spender" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "expires": { + "anyOf": [ + { + "$ref": "#/definitions/Expiration" + }, + { + "type": "null" + } + ] + }, + "spender": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"approval\" extension. Lowers the spender's access of tokens from the owner's (env.sender) account by amount. If expires is Some(), overwrites current allowance expiration with this one.", + "type": "object", + "required": [ + "decrease_allowance" + ], + "properties": { + "decrease_allowance": { + "type": "object", + "required": [ + "amount", + "spender" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "expires": { + "anyOf": [ + { + "$ref": "#/definitions/Expiration" + }, + { + "type": "null" + } + ] + }, + "spender": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"approval\" extension. Transfers amount tokens from owner -> recipient if `env.sender` has sufficient pre-approval.", + "type": "object", + "required": [ + "transfer_from" + ], + "properties": { + "transfer_from": { + "type": "object", + "required": [ + "amount", + "owner", + "recipient" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "owner": { + "type": "string" + }, + "recipient": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"approval\" extension. Sends amount tokens from owner -> contract if `env.sender` has sufficient pre-approval.", + "type": "object", + "required": [ + "send_from" + ], + "properties": { + "send_from": { + "type": "object", + "required": [ + "amount", + "contract", + "msg", + "owner" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "contract": { + "type": "string" + }, + "msg": { + "$ref": "#/definitions/Binary" + }, + "owner": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"approval\" extension. Destroys tokens forever", + "type": "object", + "required": [ + "burn_from" + ], + "properties": { + "burn_from": { + "type": "object", + "required": [ + "amount", + "owner" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "owner": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with the \"mintable\" extension. If authorized, creates amount new tokens and adds to the recipient balance.", + "type": "object", + "required": [ + "mint" + ], + "properties": { + "mint": { + "type": "object", + "required": [ + "amount", + "recipient" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "recipient": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with the \"marketing\" extension. If authorized, updates marketing metadata. Setting None/null for any of these will leave it unchanged. Setting Some(\"\") will clear this field on the contract storage", + "type": "object", + "required": [ + "update_marketing" + ], + "properties": { + "update_marketing": { + "type": "object", + "properties": { + "description": { + "description": "A longer description of the token and it's utility. Designed for tooltips or such", + "type": [ + "string", + "null" + ] + }, + "marketing": { + "description": "The address (if any) who can update this data structure", + "type": [ + "string", + "null" + ] + }, + "project": { + "description": "A URL pointing to the project behind this token.", + "type": [ + "string", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "If set as the \"marketing\" role on the contract, upload a new URL, SVG, or PNG for the token", + "type": "object", + "required": [ + "upload_logo" + ], + "properties": { + "upload_logo": { + "$ref": "#/definitions/Logo" + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec", + "type": "string" + }, + "EmbeddedLogo": { + "description": "This is used to store the logo on the blockchain in an accepted format. Enforce maximum size of 5KB on all variants.", + "anyOf": [ + { + "description": "Store the Logo as an SVG file. The content must conform to the spec at https://en.wikipedia.org/wiki/Scalable_Vector_Graphics (The contract should do some light-weight sanity-check validation)", + "type": "object", + "required": [ + "svg" + ], + "properties": { + "svg": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + }, + { + "description": "Store the Logo as a PNG file. This will likely only support up to 64x64 or so within the 5KB limit.", + "type": "object", + "required": [ + "png" + ], + "properties": { + "png": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + } + ] + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "anyOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + }, + "Logo": { + "description": "This is used for uploading logo data, or setting it in InstantiateData", + "anyOf": [ + { + "description": "A reference to an externally hosted logo. Must be a valid HTTP or HTTPS URL.", + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + { + "description": "Logo content stored on the blockchain. Enforce maximum size of 5KB on all variants", + "type": "object", + "required": [ + "embedded" + ], + "properties": { + "embedded": { + "$ref": "#/definitions/EmbeddedLogo" + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/instantiate_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/instantiate_msg.json new file mode 100644 index 00000000..c8a3fcaf --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/instantiate_msg.json @@ -0,0 +1,192 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "decimals", + "initial_balances", + "name", + "symbol" + ], + "properties": { + "decimals": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "initial_balances": { + "type": "array", + "items": { + "$ref": "#/definitions/Cw20Coin" + } + }, + "marketing": { + "anyOf": [ + { + "$ref": "#/definitions/InstantiateMarketingInfo" + }, + { + "type": "null" + } + ] + }, + "mint": { + "anyOf": [ + { + "$ref": "#/definitions/MinterResponse" + }, + { + "type": "null" + } + ] + }, + "name": { + "type": "string" + }, + "symbol": { + "type": "string" + } + }, + "definitions": { + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec", + "type": "string" + }, + "Cw20Coin": { + "type": "object", + "required": [ + "address", + "amount" + ], + "properties": { + "address": { + "type": "string" + }, + "amount": { + "$ref": "#/definitions/Uint128" + } + } + }, + "EmbeddedLogo": { + "description": "This is used to store the logo on the blockchain in an accepted format. Enforce maximum size of 5KB on all variants.", + "anyOf": [ + { + "description": "Store the Logo as an SVG file. The content must conform to the spec at https://en.wikipedia.org/wiki/Scalable_Vector_Graphics (The contract should do some light-weight sanity-check validation)", + "type": "object", + "required": [ + "svg" + ], + "properties": { + "svg": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + }, + { + "description": "Store the Logo as a PNG file. This will likely only support up to 64x64 or so within the 5KB limit.", + "type": "object", + "required": [ + "png" + ], + "properties": { + "png": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + } + ] + }, + "InstantiateMarketingInfo": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "logo": { + "anyOf": [ + { + "$ref": "#/definitions/Logo" + }, + { + "type": "null" + } + ] + }, + "marketing": { + "type": [ + "string", + "null" + ] + }, + "project": { + "type": [ + "string", + "null" + ] + } + } + }, + "Logo": { + "description": "This is used for uploading logo data, or setting it in InstantiateData", + "anyOf": [ + { + "description": "A reference to an externally hosted logo. Must be a valid HTTP or HTTPS URL.", + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + { + "description": "Logo content stored on the blockchain. Enforce maximum size of 5KB on all variants", + "type": "object", + "required": [ + "embedded" + ], + "properties": { + "embedded": { + "$ref": "#/definitions/EmbeddedLogo" + } + }, + "additionalProperties": false + } + ] + }, + "MinterResponse": { + "type": "object", + "required": [ + "minter" + ], + "properties": { + "cap": { + "description": "cap is a hard cap on total supply that can be achieved by minting. Note that this refers to total_supply. If None, there is unlimited cap.", + "anyOf": [ + { + "$ref": "#/definitions/Uint128" + }, + { + "type": "null" + } + ] + }, + "minter": { + "type": "string" + } + } + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/query_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/query_msg.json new file mode 100644 index 00000000..60aac9e1 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/query_msg.json @@ -0,0 +1,168 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "anyOf": [ + { + "description": "Returns the current balance of the given address, 0 if unset. Return type: BalanceResponse.", + "type": "object", + "required": [ + "balance" + ], + "properties": { + "balance": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns metadata on the contract - name, decimals, supply, etc. Return type: TokenInfoResponse.", + "type": "object", + "required": [ + "token_info" + ], + "properties": { + "token_info": { + "type": "object" + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"mintable\" extension. Returns who can mint and the hard cap on maximum tokens after minting. Return type: MinterResponse.", + "type": "object", + "required": [ + "minter" + ], + "properties": { + "minter": { + "type": "object" + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"allowance\" extension. Returns how much spender can use from owner account, 0 if unset. Return type: AllowanceResponse.", + "type": "object", + "required": [ + "allowance" + ], + "properties": { + "allowance": { + "type": "object", + "required": [ + "owner", + "spender" + ], + "properties": { + "owner": { + "type": "string" + }, + "spender": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"enumerable\" extension (and \"allowances\") Returns all allowances this owner has approved. Supports pagination. Return type: AllAllowancesResponse.", + "type": "object", + "required": [ + "all_allowances" + ], + "properties": { + "all_allowances": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "owner": { + "type": "string" + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"enumerable\" extension Returns all accounts that have balances. Supports pagination. Return type: AllAccountsResponse.", + "type": "object", + "required": [ + "all_accounts" + ], + "properties": { + "all_accounts": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"marketing\" extension Returns more metadata on the contract to display in the client: - description, logo, project url, etc. Return type: MarketingInfoResponse", + "type": "object", + "required": [ + "marketing_info" + ], + "properties": { + "marketing_info": { + "type": "object" + } + }, + "additionalProperties": false + }, + { + "description": "Only with \"marketing\" extension Downloads the mbeded logo data (if stored on chain). Errors if no logo data ftored for this contract. Return type: DownloadLogoResponse.", + "type": "object", + "required": [ + "download_logo" + ], + "properties": { + "download_logo": { + "type": "object" + } + }, + "additionalProperties": false + } + ] +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/token_info_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/token_info_response.json new file mode 100644 index 00000000..9920c841 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw20_base/schema/token_info_response.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TokenInfoResponse", + "type": "object", + "required": [ + "decimals", + "name", + "symbol", + "total_supply" + ], + "properties": { + "decimals": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "name": { + "type": "string" + }, + "symbol": { + "type": "string" + }, + "total_supply": { + "$ref": "#/definitions/Uint128" + } + }, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/execute_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/execute_msg.json new file mode 100644 index 00000000..62a31181 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/execute_msg.json @@ -0,0 +1,698 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "propose" + ], + "properties": { + "propose": { + "type": "object", + "required": [ + "description", + "msgs", + "title" + ], + "properties": { + "description": { + "type": "string" + }, + "latest": { + "anyOf": [ + { + "$ref": "#/definitions/Expiration" + }, + { + "type": "null" + } + ] + }, + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_Empty" + } + }, + "title": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/Vote" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "proposal_id" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "close" + ], + "properties": { + "close": { + "type": "object", + "required": [ + "proposal_id" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Handles update hook messages from the group contract", + "type": "object", + "required": [ + "member_changed_hook" + ], + "properties": { + "member_changed_hook": { + "$ref": "#/definitions/MemberChangedHookMsg" + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_Empty": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/Empty" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + }, + "MemberChangedHookMsg": { + "description": "MemberChangedHookMsg should be de/serialized under `MemberChangedHook()` variant in a ExecuteMsg. This contains a list of all diffs on the given transaction.", + "type": "object", + "required": [ + "diffs" + ], + "properties": { + "diffs": { + "type": "array", + "items": { + "$ref": "#/definitions/MemberDiff" + } + } + } + }, + "MemberDiff": { + "description": "MemberDiff shows the old and new states for a given cw4 member They cannot both be None. old = None, new = Some -> Insert old = Some, new = Some -> Update old = Some, new = None -> Delete", + "type": "object", + "required": [ + "key" + ], + "properties": { + "key": { + "type": "string" + }, + "new": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "old": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "Vote": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/instantiate_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/instantiate_msg.json new file mode 100644 index 00000000..42c078f6 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/instantiate_msg.json @@ -0,0 +1,135 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "group_addr", + "max_voting_period", + "threshold" + ], + "properties": { + "group_addr": { + "type": "string" + }, + "max_voting_period": { + "$ref": "#/definitions/Duration" + }, + "threshold": { + "$ref": "#/definitions/Threshold" + } + }, + "definitions": { + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, + "Duration": { + "description": "Duration is a delta of time. You can add it to a BlockInfo or Expiration to move that further in the future. Note that an height-based Duration and a time-based Expiration cannot be combined", + "oneOf": [ + { + "type": "object", + "required": [ + "height" + ], + "properties": { + "height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "Time in seconds", + "type": "object", + "required": [ + "time" + ], + "properties": { + "time": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + ] + }, + "Threshold": { + "description": "This defines the different ways tallies can happen.\n\nThe total_weight used for calculating success as well as the weights of each individual voter used in tallying should be snapshotted at the beginning of the block at which the proposal starts (this is likely the responsibility of a correct cw4 implementation). See also `ThresholdResponse` in the cw3 spec.", + "oneOf": [ + { + "description": "Declares that a fixed weight of Yes votes is needed to pass. See `ThresholdResponse.AbsoluteCount` in the cw3 spec for details.", + "type": "object", + "required": [ + "absolute_count" + ], + "properties": { + "absolute_count": { + "type": "object", + "required": [ + "weight" + ], + "properties": { + "weight": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Declares a percentage of the total weight that must cast Yes votes in order for a proposal to pass. See `ThresholdResponse.AbsolutePercentage` in the cw3 spec for details.", + "type": "object", + "required": [ + "absolute_percentage" + ], + "properties": { + "absolute_percentage": { + "type": "object", + "required": [ + "percentage" + ], + "properties": { + "percentage": { + "$ref": "#/definitions/Decimal" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Declares a `quorum` of the total votes that must participate in the election in order for the vote to be considered at all. See `ThresholdResponse.ThresholdQuorum` in the cw3 spec for details.", + "type": "object", + "required": [ + "threshold_quorum" + ], + "properties": { + "threshold_quorum": { + "type": "object", + "required": [ + "quorum", + "threshold" + ], + "properties": { + "quorum": { + "$ref": "#/definitions/Decimal" + }, + "threshold": { + "$ref": "#/definitions/Decimal" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/query_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/query_msg.json new file mode 100644 index 00000000..42aea714 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw3_flex_multisig/schema/query_msg.json @@ -0,0 +1,218 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "oneOf": [ + { + "description": "Return ThresholdResponse", + "type": "object", + "required": [ + "threshold" + ], + "properties": { + "threshold": { + "type": "object" + } + }, + "additionalProperties": false + }, + { + "description": "Returns ProposalResponse", + "type": "object", + "required": [ + "proposal" + ], + "properties": { + "proposal": { + "type": "object", + "required": [ + "proposal_id" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns ProposalListResponse", + "type": "object", + "required": [ + "list_proposals" + ], + "properties": { + "list_proposals": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "start_after": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns ProposalListResponse", + "type": "object", + "required": [ + "reverse_proposals" + ], + "properties": { + "reverse_proposals": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "start_before": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns VoteResponse", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "voter" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "voter": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns VoteListResponse", + "type": "object", + "required": [ + "list_votes" + ], + "properties": { + "list_votes": { + "type": "object", + "required": [ + "proposal_id" + ], + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns VoterInfo", + "type": "object", + "required": [ + "voter" + ], + "properties": { + "voter": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns VoterListResponse", + "type": "object", + "required": [ + "list_voters" + ], + "properties": { + "list_voters": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "additionalProperties": false + } + ] +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/admin_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/admin_response.json new file mode 100644 index 00000000..82bf62a3 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/admin_response.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AdminResponse", + "type": "object", + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/execute_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/execute_msg.json new file mode 100644 index 00000000..58442460 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/execute_msg.json @@ -0,0 +1,120 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "anyOf": [ + { + "description": "Change the admin", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "apply a diff to the existing members. remove is applied after add, so if an address is in both, it is removed", + "type": "object", + "required": [ + "update_members" + ], + "properties": { + "update_members": { + "type": "object", + "required": [ + "add", + "remove" + ], + "properties": { + "add": { + "type": "array", + "items": { + "$ref": "#/definitions/Member" + } + }, + "remove": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Add a new hook to be informed of all membership changes. Must be called by Admin", + "type": "object", + "required": [ + "add_hook" + ], + "properties": { + "add_hook": { + "type": "object", + "required": [ + "addr" + ], + "properties": { + "addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Remove a hook. Must be called by Admin", + "type": "object", + "required": [ + "remove_hook" + ], + "properties": { + "remove_hook": { + "type": "object", + "required": [ + "addr" + ], + "properties": { + "addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Member": { + "description": "A group member has a weight associated with them. This may all be equal, or may have meaning in the app that makes use of the group (eg. voting power)", + "type": "object", + "required": [ + "addr", + "weight" + ], + "properties": { + "addr": { + "type": "string" + }, + "weight": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/instantiate_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/instantiate_msg.json new file mode 100644 index 00000000..efa676c0 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/instantiate_msg.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "members" + ], + "properties": { + "admin": { + "description": "The admin is the only account that can update the group state. Omit it to make the group immutable.", + "type": [ + "string", + "null" + ] + }, + "members": { + "type": "array", + "items": { + "$ref": "#/definitions/Member" + } + } + }, + "definitions": { + "Member": { + "description": "A group member has a weight associated with them. This may all be equal, or may have meaning in the app that makes use of the group (eg. voting power)", + "type": "object", + "required": [ + "addr", + "weight" + ], + "properties": { + "addr": { + "type": "string" + }, + "weight": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/member_list_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/member_list_response.json new file mode 100644 index 00000000..ae09f9bb --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/member_list_response.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MemberListResponse", + "type": "object", + "required": [ + "members" + ], + "properties": { + "members": { + "type": "array", + "items": { + "$ref": "#/definitions/Member" + } + } + }, + "definitions": { + "Member": { + "description": "A group member has a weight associated with them. This may all be equal, or may have meaning in the app that makes use of the group (eg. voting power)", + "type": "object", + "required": [ + "addr", + "weight" + ], + "properties": { + "addr": { + "type": "string" + }, + "weight": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/member_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/member_response.json new file mode 100644 index 00000000..c78ed862 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/member_response.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MemberResponse", + "type": "object", + "properties": { + "weight": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/query_msg.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/query_msg.json new file mode 100644 index 00000000..8f994c9c --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/query_msg.json @@ -0,0 +1,103 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "anyOf": [ + { + "description": "Return AdminResponse", + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "object" + } + }, + "additionalProperties": false + }, + { + "description": "Return TotalWeightResponse", + "type": "object", + "required": [ + "total_weight" + ], + "properties": { + "total_weight": { + "type": "object" + } + }, + "additionalProperties": false + }, + { + "description": "Returns MembersListResponse", + "type": "object", + "required": [ + "list_members" + ], + "properties": { + "list_members": { + "type": "object", + "properties": { + "limit": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "start_after": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns MemberResponse", + "type": "object", + "required": [ + "member" + ], + "properties": { + "member": { + "type": "object", + "required": [ + "addr" + ], + "properties": { + "addr": { + "type": "string" + }, + "at_height": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Shows all registered hooks. Returns HooksResponse.", + "type": "object", + "required": [ + "hooks" + ], + "properties": { + "hooks": { + "type": "object" + } + }, + "additionalProperties": false + } + ] +} diff --git a/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/total_weight_response.json b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/total_weight_response.json new file mode 100644 index 00000000..61db7a99 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/artifacts/contracts/cw4_group/schema/total_weight_response.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TotalWeightResponse", + "type": "object", + "required": [ + "weight" + ], + "properties": { + "weight": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } +} diff --git a/packages-ts/gauntlet-terra-contracts/codeIds/bombay-testnet.json b/packages-ts/gauntlet-terra-contracts/codeIds/bombay-testnet.json index 6c917353..08f1fecd 100644 --- a/packages-ts/gauntlet-terra-contracts/codeIds/bombay-testnet.json +++ b/packages-ts/gauntlet-terra-contracts/codeIds/bombay-testnet.json @@ -2,5 +2,8 @@ "flags": 39112, "ocr2": 39113, "access_controller": 39116, - "deviation_flagging_validator": 39115 + "deviation_flagging_validator": 39115, + "cw3_flex_multisig": 36059, + "cw4_group": 36895, + "cw20_base": 41738 } \ No newline at end of file diff --git a/packages-ts/gauntlet-terra-contracts/codeIds/local.json b/packages-ts/gauntlet-terra-contracts/codeIds/local.json index 9e26dfee..5c2a01ca 100644 --- a/packages-ts/gauntlet-terra-contracts/codeIds/local.json +++ b/packages-ts/gauntlet-terra-contracts/codeIds/local.json @@ -1 +1,8 @@ -{} \ No newline at end of file +{ + "flags": 40, + "deviation_flagging_validator": 41, + "ocr2": 42, + "access_controller": 43, + "cw3_flex_multisig": 44, + "cw4_group": 45 +} \ No newline at end of file diff --git a/packages-ts/gauntlet-terra-contracts/codeIds/localterra.json b/packages-ts/gauntlet-terra-contracts/codeIds/localterra.json deleted file mode 100644 index 0967ef42..00000000 --- a/packages-ts/gauntlet-terra-contracts/codeIds/localterra.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/packages-ts/gauntlet-terra-contracts/networks/.env.bombay-testnet b/packages-ts/gauntlet-terra-contracts/networks/.env.bombay-testnet index a1ebd160..15fc2f61 100644 --- a/packages-ts/gauntlet-terra-contracts/networks/.env.bombay-testnet +++ b/packages-ts/gauntlet-terra-contracts/networks/.env.bombay-testnet @@ -1,7 +1,8 @@ NODE_URL=https://bombay-lcd.terra.dev CHAIN_ID=bombay-12 DEFAULT_GAS_PRICE=0.5 - LINK=terra1fcksmfjncl6m7apvpalvhwv5jxd9djv5lwyu82 BILLING_ACCESS_CONTROLLER=terra1trcufj64y53hxk7g8cra33xw3jkyvlr9lu99eu -REQUESTER_ACCESS_CONTROLLER=terra1s38kfu4qp0ttwxkka9zupaysefl5qruhv5rc0z \ No newline at end of file +REQUESTER_ACCESS_CONTROLLER=terra1s38kfu4qp0ttwxkka9zupaysefl5qruhv5rc0z +MULTISIG_GROUP=terra168lv95kfm49y9zu0409jmplj756ukxdrew7uta +MULTISIG_WALLET=terra1u89pduw4enewduy9qydj925738cyn9juszgj54 diff --git a/packages-ts/gauntlet-terra-contracts/networks/.env.local b/packages-ts/gauntlet-terra-contracts/networks/.env.local index bd900ff5..e65e90f2 100644 --- a/packages-ts/gauntlet-terra-contracts/networks/.env.local +++ b/packages-ts/gauntlet-terra-contracts/networks/.env.local @@ -1,3 +1,6 @@ NODE_URL=http://localhost:1317 CHAIN_ID=localterra DEFAULT_GAS_PRICE=1000000 +LINK=terra13mrd0njt2q5rq0nv294wgcqk9v83nuuja6wyvy +BILLING_ACCESS_CONTROLLER=terra1gqq4k5wsvmsk3gflnpmfv6fpaxdsgsq4utyh79 +REQUESTER_ACCESS_CONTROLLER=terra1qhzkf9c8m75xyw8x773378t4cyuk8jm29maflh diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/abstract/executionWrapper.ts b/packages-ts/gauntlet-terra-contracts/src/commands/abstract/executionWrapper.ts index a62371c2..0325c322 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/abstract/executionWrapper.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/abstract/executionWrapper.ts @@ -4,6 +4,7 @@ import { TerraCommand, TransactionResponse } from '@chainlink/gauntlet-terra' export interface AbstractInstruction { instruction: { + category: string contract: string function: string } @@ -14,8 +15,10 @@ export interface AbstractInstruction { export const instructionToCommand = (instruction: AbstractInstruction) => { const id = `${instruction.instruction.contract}:${instruction.instruction.function}` + const category = `${instruction.instruction.category}` return class Command extends TerraCommand { static id = id + static category = category command: AbstractCommand constructor(flags, args) { @@ -24,7 +27,9 @@ export const instructionToCommand = (instruction: AbstractInstruction) execute = async (): Promise> => { const commandInput = await instruction.makeInput(this.flags, this.args) - instruction.validateInput(commandInput) + if (!instruction.validateInput(commandInput)) { + throw new Error(`Invalid input params: ${JSON.stringify(commandInput)}`) + } const input = await instruction.makeContractInput(commandInput) const abstractCommand = await makeAbstractCommand(id, this.flags, this.args, input) await abstractCommand.invokeMiddlewares(abstractCommand, abstractCommand.middlewares) diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/abstract/inspectionWrapper.ts b/packages-ts/gauntlet-terra-contracts/src/commands/abstract/inspectionWrapper.ts index 143d8b48..af08a195 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/abstract/inspectionWrapper.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/abstract/inspectionWrapper.ts @@ -2,6 +2,8 @@ import AbstractCommand, { makeAbstractCommand } from '.' import { Result } from '@chainlink/gauntlet-core' import { TerraCommand, TransactionResponse } from '@chainlink/gauntlet-terra' import { logger } from '@chainlink/gauntlet-core/dist/utils' +import { CATEGORIES } from '../../lib/constants' +import { CONTRACT_LIST } from '../../lib/contracts' export type InspectionInput = { commandInput?: CommandInput @@ -21,7 +23,8 @@ export type InspectionInput = { */ export interface InspectInstruction { command: { - contract: 'ocr2' + category: CATEGORIES + contract: CONTRACT_LIST id: 'inspect' } instructions: { diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/access_controller/addAccess.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/access_controller/addAccess.ts index f1b592f0..6fe6a768 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/access_controller/addAccess.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/access_controller/addAccess.ts @@ -1,6 +1,8 @@ import { BN } from '@chainlink/gauntlet-core/dist/utils' import { AccAddress } from '@terra-money/terra.js' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { address: string @@ -32,6 +34,7 @@ const validateInput = (input: CommandInput): boolean => { const addAccess: AbstractInstruction = { instruction: { + category: CATEGORIES.ACCESS_CONTROLLER, contract: 'access_controller', function: 'add_access', }, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/access_controller/removeAccess.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/access_controller/removeAccess.ts index f46914c0..242c8ff9 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/access_controller/removeAccess.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/access_controller/removeAccess.ts @@ -1,6 +1,8 @@ import { BN } from '@chainlink/gauntlet-core/dist/utils' import { AccAddress } from '@terra-money/terra.js' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { address: string @@ -32,6 +34,7 @@ const validateInput = (input: CommandInput): boolean => { const removeAccess: AbstractInstruction = { instruction: { + category: CATEGORIES.ACCESS_CONTROLLER, contract: 'access_controller', function: 'remove_access', }, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/deviation_flagging_validator/deploy.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/deviation_flagging_validator/deploy.ts index 863ad0ee..b8366ce4 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/deviation_flagging_validator/deploy.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/deviation_flagging_validator/deploy.ts @@ -1,6 +1,8 @@ import { BN } from '@chainlink/gauntlet-core/dist/utils' import { AccAddress } from '@terra-money/terra.js' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { address: string @@ -38,7 +40,8 @@ const validateInput = (input: CommandInput): boolean => { const deploy: AbstractInstruction = { instruction: { - contract: 'deviation_flagging_validator', + category: CATEGORIES.DEVIATION_FLAGGING_VALIDATOR, + contract: CONTRACT_LIST.DEVIATION_FLAGGING_VALIDATOR, function: 'deploy', }, makeInput: makeCommandInput, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/flags/deploy.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/flags/deploy.ts index 9be73a89..d8f27be3 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/flags/deploy.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/flags/deploy.ts @@ -1,6 +1,8 @@ import { BN } from '@chainlink/gauntlet-core/dist/utils' import { AccAddress } from '@terra-money/terra.js' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { raisingAccessController: string @@ -35,7 +37,8 @@ const validateInput = (input: CommandInput): boolean => { const deploy: AbstractInstruction = { instruction: { - contract: 'flags', + category: CATEGORIES.FLAGS, + contract: CONTRACT_LIST.FLAGS, function: 'deploy', }, makeInput: makeCommandInput, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/group.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/group.ts new file mode 100644 index 00000000..d204a41f --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/group.ts @@ -0,0 +1,58 @@ +import { CATEGORIES } from '../../../lib/constants' +import { isValidAddress } from '../../../lib/utils' +import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' + +type CommandInput = { + owners: string[] + admin?: string +} + +type ContractInput = { + members: { + addr: string + weight: number + }[] + admin?: string +} + +const makeCommandInput = async (flags: any, args: any[]): Promise => { + if (flags.input) return flags.input as CommandInput + return { + owners: args, + admin: flags.admin, + } +} +const validateInput = (input: CommandInput): boolean => { + if (input.owners.length === 0) { + throw new Error(`You must specify at least one group member (wallet owner)`) + } + const areValidOwners = input.owners.filter((owner) => !isValidAddress(owner)).length === 0 + if (!areValidOwners) throw new Error('Owners are not valid') + if (input.admin && !isValidAddress(input.admin)) throw new Error('Admin is not valid') + return true +} + +const makeContractInput = async (input: CommandInput): Promise => { + return { + members: input.owners.map((owner) => ({ + addr: owner, + // Same weight for every owner + weight: 1, + })), + admin: input.admin, + } +} + +// yarn gauntlet cw4_group:deploy --network=bombay-testnet +const createGroupInstruction: AbstractInstruction = { + instruction: { + category: CATEGORIES.MULTISIG, + contract: 'cw4_group', + function: 'deploy', + }, + makeInput: makeCommandInput, + validateInput, + makeContractInput, +} + +export const CreateGroup = instructionToCommand(createGroupInstruction) diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/index.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/index.ts new file mode 100644 index 00000000..ba1d8907 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/index.ts @@ -0,0 +1,4 @@ +import { CreateGroup } from './group' +import { CreateWallet } from './wallet' + +export default [CreateGroup, CreateWallet] diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/wallet.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/wallet.ts new file mode 100644 index 00000000..ae4d5680 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/multisig/wallet.ts @@ -0,0 +1,100 @@ +import { CATEGORIES } from '../../../lib/constants' +import { isValidAddress } from '../../../lib/utils' +import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' + +type Duration = { + height?: number // block height + time?: number // length of time in seconds +} + +type CommandInput = { + group: string + threshold: number + votingPeriod?: { + height?: number + time?: number + } +} + +type ContractInput = { + group_addr: string + max_voting_period: Duration + threshold: Threshold +} + +type Threshold = { + absolute_count?: { + weight: number + } + absolute_percentage?: { + percentage: number + } + threshold_quorum?: { + threshold: number + quorum: number + } +} + +const makeCommandInput = async (flags: any): Promise => { + if (flags.input) return flags.input as CommandInput + return { + group: flags.group, + threshold: Number(flags.threshold), + votingPeriod: { + height: flags.height, + time: flags.time, + }, + } +} + +const validateInput = (input: CommandInput): boolean => { + // TODO: Add time validation + const isValidTime = (a: any) => true + if (!isValidAddress(input.group)) { + throw new Error(`group ${input.group} is not a valid terra address`) + } + + if (input.threshold === 0) { + throw new Error(`Threshold ${input.threshold} is invalid. Should be higher than zero`) + } + + if (input.votingPeriod?.height && isNaN(input.votingPeriod?.height)) { + throw new Error(`Voting period height ${input.votingPeriod.height} is not a valid Block`) + } + + if (input.votingPeriod?.time && !isValidTime(input.votingPeriod?.time)) { + throw new Error(`Voting period time ${input.votingPeriod?.time} is not a valid time`) + } + + return true +} + +const makeContractInput = async (input: CommandInput): Promise => { + return { + group_addr: input.group, + max_voting_period: { + ...(input.votingPeriod?.height && { height: Number(input.votingPeriod?.height) }), + ...(input.votingPeriod?.time && { time: Number(input.votingPeriod?.time) }), + }, + threshold: { + absolute_count: { + weight: input.threshold, + }, + }, + } +} + +// Creates a multisig wallet backed by a previously created cw4_group +// yarn gauntlet cw3_flex_multisig:deploy --network=bombay-testnet --group= --threshold= --height=10000100 +const createWalletInstruction: AbstractInstruction = { + instruction: { + category: CATEGORIES.MULTISIG, + contract: 'cw3_flex_multisig', + function: 'deploy', + }, + makeInput: makeCommandInput, + validateInput, + makeContractInput: makeContractInput, +} + +export const CreateWallet = instructionToCommand(createWalletInstruction) diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/deploy.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/deploy.ts index 213231b1..3d6a00ba 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/deploy.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/deploy.ts @@ -1,5 +1,7 @@ import { getRDD } from '../../../lib/rdd' import { instructionToCommand, AbstractInstruction } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { billingAccessController: string @@ -54,6 +56,7 @@ const validateInput = (input: CommandInput): boolean => { const deployInstruction: AbstractInstruction = { instruction: { + category: CATEGORIES.OCR, contract: 'ocr2', function: 'deploy', }, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/initialize.flow.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/initialize.flow.ts index f04822f4..eb574667 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/initialize.flow.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/initialize.flow.ts @@ -1,5 +1,5 @@ import { FlowCommand } from '@chainlink/gauntlet-core' -import { CONTRACT_LIST } from '../../../lib/contracts' +import { CATEGORIES } from '../../../lib/constants' import { waitExecute, TransactionResponse } from '@chainlink/gauntlet-terra' import { logger, prompt } from '@chainlink/gauntlet-core/dist/utils' @@ -12,7 +12,7 @@ import Inspect from './inspection/inspect' export default class OCR2InitializeFlow extends FlowCommand { static id = 'ocr2:initialize:flow' - static category = CONTRACT_LIST.OCR_2 + static category = CATEGORIES.OCR static examples = ['yarn gauntlet ocr2:initialize:flow --network=local --id=[ID] --rdd=[PATH_TO_RDD]'] constructor(flags, args) { diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/inspection/inspect.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/inspection/inspect.ts index c3048cf3..e5a8ab71 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/inspection/inspect.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/inspection/inspect.ts @@ -1,4 +1,6 @@ import { inspection } from '@chainlink/gauntlet-core/dist/utils' +import { CONTRACT_LIST } from '../../../../lib/contracts' +import { CATEGORIES } from '../../../../lib/constants' import { getRDD } from '../../../../lib/rdd' import { InspectInstruction, InspectionInput, instructionToInspectCommand } from '../../../abstract/inspectionWrapper' import { getOffchainConfigInput, OffchainConfig } from '../setConfig' @@ -127,7 +129,8 @@ const inspect = (expected: Expected, onchainData: Expected): boolean => { const instruction: InspectInstruction = { command: { - contract: 'ocr2', + category: CATEGORIES.OCR, + contract: CONTRACT_LIST.OCR_2, id: 'inspect', }, instructions: [ diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setBilling.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setBilling.ts index 5fe78367..afd0ff10 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setBilling.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setBilling.ts @@ -1,6 +1,8 @@ import { BN } from '@chainlink/gauntlet-core/dist/utils' import { getRDD } from '../../../lib/rdd' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { recommendedGasPriceUluna: string @@ -71,6 +73,7 @@ const validateInput = (input: CommandInput): boolean => { const setBillingInstruction: AbstractInstruction = { instruction: { + category: CATEGORIES.OCR, contract: 'ocr2', function: 'set_billing', }, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setConfig.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setConfig.ts index f9b2ead8..120cd7bf 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setConfig.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setConfig.ts @@ -3,6 +3,8 @@ import { AbstractInstruction, instructionToCommand } from '../../abstract/execut import { time, BN } from '@chainlink/gauntlet-core/dist/utils' import { serializeOffchainConfig } from '../../../lib/encoding' import { ORACLES_MAX_LENGTH } from '../../../lib/constants' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type ContractInput = { signers: string[] @@ -191,6 +193,7 @@ const validateInput = (input: CommandInput): boolean => { const instruction: AbstractInstruction = { instruction: { + category: CATEGORIES.OCR, contract: 'ocr2', function: 'set_config', }, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setPayees.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setPayees.ts index 386659ad..bb2acf5d 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setPayees.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/ocr2/setPayees.ts @@ -1,5 +1,7 @@ import { getRDD } from '../../../lib/rdd' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { payees: string[] @@ -37,6 +39,7 @@ const validateInput = (input: CommandInput): boolean => { const instruction: AbstractInstruction = { instruction: { + category: CATEGORIES.OCR, contract: 'ocr2', function: 'set_payees', }, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/confirmContract.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/confirmContract.ts index 78c8333d..521d5104 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/confirmContract.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/confirmContract.ts @@ -1,6 +1,8 @@ import { BN } from '@chainlink/gauntlet-core/dist/utils' import { AccAddress } from '@terra-money/terra.js' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { address: string @@ -31,7 +33,8 @@ const validateInput = (input: CommandInput): boolean => { const confirmContract: AbstractInstruction = { instruction: { - contract: 'proxy_ocr2', + category: CATEGORIES.PROXIES, + contract: CONTRACT_LIST.PROXY_OCR_2, function: 'confirm_contract', }, makeInput: makeCommandInput, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/deploy.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/deploy.ts index aa9608e6..06b5f7db 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/deploy.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/deploy.ts @@ -1,6 +1,8 @@ import { BN } from '@chainlink/gauntlet-core/dist/utils' import { AccAddress } from '@terra-money/terra.js' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' type CommandInput = { address: string @@ -31,7 +33,8 @@ const validateInput = (input: CommandInput): boolean => { const deploy: AbstractInstruction = { instruction: { - contract: 'proxy_ocr2', + category: CATEGORIES.PROXIES, + contract: CONTRACT_LIST.PROXY_OCR_2, function: 'deploy', }, makeInput: makeCommandInput, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/proposeContract.ts b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/proposeContract.ts index efa94311..6574262c 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/proposeContract.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/contracts/proxy_ocr2/proposeContract.ts @@ -1,5 +1,7 @@ import { BN } from '@chainlink/gauntlet-core/dist/utils' import { AccAddress } from '@terra-money/terra.js' +import { CATEGORIES } from '../../../lib/constants' +import { CONTRACT_LIST } from '../../../lib/contracts' import { AbstractInstruction, instructionToCommand } from '../../abstract/executionWrapper' type CommandInput = { @@ -31,7 +33,8 @@ const validateInput = (input: CommandInput): boolean => { const proposeContract: AbstractInstruction = { instruction: { - contract: 'proxy_ocr2', + category: CATEGORIES.PROXIES, + contract: CONTRACT_LIST.PROXY_OCR_2, function: 'propose_contract', }, makeInput: makeCommandInput, diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/index.ts b/packages-ts/gauntlet-terra-contracts/src/commands/index.ts index 52ded7b6..fd024096 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/index.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/index.ts @@ -6,6 +6,7 @@ import AccessController from './contracts/access_controller' import Flags from './contracts/flags' import Proxy_OCR2 from './contracts/proxy_ocr2' import DeviationFlaggingValidator from './contracts/deviation_flagging_validator' +import Multisig from './contracts/multisig' export default [ Upload, @@ -16,4 +17,5 @@ export default [ ...Flags, ...DeviationFlaggingValidator, ...Proxy_OCR2, + ...Multisig, ] diff --git a/packages-ts/gauntlet-terra-contracts/src/commands/tooling/upload.ts b/packages-ts/gauntlet-terra-contracts/src/commands/tooling/upload.ts index 5a5f6afc..2ce9d6bb 100644 --- a/packages-ts/gauntlet-terra-contracts/src/commands/tooling/upload.ts +++ b/packages-ts/gauntlet-terra-contracts/src/commands/tooling/upload.ts @@ -1,14 +1,14 @@ import { logger, io, prompt } from '@chainlink/gauntlet-core/dist/utils' import { TerraCommand } from '@chainlink/gauntlet-terra' import { CONTRACT_LIST, getContract } from '../../lib/contracts' -import { CATEGORIES, DEFAULT_RELEASE_VERSION } from '../../lib/constants' +import { CATEGORIES } from '../../lib/constants' import path from 'path' export default class UploadContractCode extends TerraCommand { static description = 'Upload cosmwasm contract artifacts' static examples = [ `yarn gauntlet upload --network=bombay-testnet`, `yarn gauntlet upload --network=bombay-testnet [contract names]`, - `yarn gauntlet upload --network=bombay-testnet flags link_token`, + `yarn gauntlet upload --network=bombay-testnet flags cw20_base`, ] static id = 'upload' @@ -16,8 +16,6 @@ export default class UploadContractCode extends TerraCommand { static flags = { version: { description: 'The version to retrieve artifacts from (Defaults to v0.0.4)' }, - codeIDs: { description: 'The path to contract code IDs file' }, - artifacts: { description: 'The path to contract artifacts folder' }, } constructor(flags, args: string[]) { @@ -44,11 +42,9 @@ export default class UploadContractCode extends TerraCommand { const contractReceipts = {} const responses: any[] = [] - for (const contractName of askedContracts) { - const version = this.flags.version ? this.flags.version : DEFAULT_RELEASE_VERSION - const contract = await getContract(contractName, version) + for (let contractName of askedContracts) { + const contract = await getContract(contractName, this.flags.version) console.log('CONTRACT Bytecode exists:', !!contract.bytecode) - try { const res = await this.upload(contract.bytecode, contractName) diff --git a/packages-ts/gauntlet-terra-contracts/src/lib/constants.ts b/packages-ts/gauntlet-terra-contracts/src/lib/constants.ts index 2541e874..20cb82fe 100644 --- a/packages-ts/gauntlet-terra-contracts/src/lib/constants.ts +++ b/packages-ts/gauntlet-terra-contracts/src/lib/constants.ts @@ -1,19 +1,35 @@ -export const CATEGORIES = { - OWNERSHIP: 'Ownership', - PROXIES: 'Proxies', - TOOLING: 'Tooling', - V3: 'V3', - LINK: 'LINK', - FLAGS: 'Flags', - OCR: 'OCR', - ACCESS_CONTROLLER: 'Access Controller', +export const enum CATEGORIES { + OWNERSHIP = 'Ownership', + PROXIES = 'Proxies', + TOOLING = 'Tooling', + V3 = 'V3', + LINK = 'LINK', + FLAGS = 'Flags', + OCR = 'OCR', + ACCESS_CONTROLLER = 'Access Controller', + MULTISIG = 'Multisig', + DEVIATION_FLAGGING_VALIDATOR = 'Devaiation Flagging Validator', } export const DEFAULT_RELEASE_VERSION = 'v0.0.4' +export const DEFAULT_CWPLUS_VERSION = 'v0.9.1' export const ORACLES_MAX_LENGTH = 31 export const CW20_BASE_CODE_IDs = { mainnet: 3, + local: 32, 'bombay-testnet': 148, } + +export const CW4_GROUP_CODE_IDs = { + mainnet: -1, + local: -1, + 'bombay-testnet': 36895, +} + +export const CW3_FLEX_MULTISIG_CODE_IDs = { + mainnet: -1, + local: -1, + 'bombay-testnet': 36059, +} diff --git a/packages-ts/gauntlet-terra-contracts/src/lib/contracts.ts b/packages-ts/gauntlet-terra-contracts/src/lib/contracts.ts index 04b86a05..b1caadb1 100644 --- a/packages-ts/gauntlet-terra-contracts/src/lib/contracts.ts +++ b/packages-ts/gauntlet-terra-contracts/src/lib/contracts.ts @@ -3,6 +3,7 @@ import { JSONSchemaType } from 'ajv' import { existsSync, readFileSync } from 'fs' import path from 'path' import fetch from 'node-fetch' +import { DEFAULT_RELEASE_VERSION, DEFAULT_CWPLUS_VERSION } from './constants' export enum CONTRACT_LIST { FLAGS = 'flags', @@ -10,6 +11,9 @@ export enum CONTRACT_LIST { OCR_2 = 'ocr2', PROXY_OCR_2 = 'proxy_ocr2', ACCESS_CONTROLLER = 'access_controller', + CW20_BASE = 'cw20_base', + MULTISIG = 'cw3_flex_multisig', + CW4_GROUP = 'cw4_group', } export enum TERRA_OPERATIONS { @@ -36,8 +40,9 @@ export const getContractCode = async (contractId: CONTRACT_LIST, version): Promi if (version === 'local') { // Possible paths depending on how/where gauntlet is being executed const possibleContractPaths = [ - path.join(__dirname, '../..', './artifacts/bin'), + path.join(__dirname, '../../artifacts/bin'), path.join(process.cwd(), './artifacts/bin'), + path.join(process.cwd(), './tests/e2e/common_artifacts'), path.join(process.cwd(), './packages-ts/gauntlet-terra-contracts/artifacts/bin'), ] @@ -49,11 +54,20 @@ export const getContractCode = async (contractId: CONTRACT_LIST, version): Promi }) return codes[0] } else { - const response = await fetch( - `https://github.com/smartcontractkit/chainlink-terra/releases/download/${version}/${contractId}.wasm`, - ) - const body = await response.text() - return body.toString(`base64`) + let url + switch (contractId) { + case CONTRACT_LIST.CW20_BASE: + case CONTRACT_LIST.CW4_GROUP: + case CONTRACT_LIST.MULTISIG: + url = `https://github.com/CosmWasm/cw-plus/releases/download/${version}/${contractId}.wasm` + break + default: + url = `https://github.com/smartcontractkit/chainlink-terra/releases/download/${version}/${contractId}.wasm` + } + console.log(`Fetching ${url}...`) + const response = await fetch(url) + const body = await response.arrayBuffer() + return Buffer.from(body).toString('base64') } } @@ -63,14 +77,27 @@ const contractDirName = { [CONTRACT_LIST.OCR_2]: 'ocr2', [CONTRACT_LIST.PROXY_OCR_2]: 'proxy-ocr2', [CONTRACT_LIST.ACCESS_CONTROLLER]: 'access-controller', + [CONTRACT_LIST.CW20_BASE]: 'cw20_base', + [CONTRACT_LIST.CW4_GROUP]: 'cw4_group', + [CONTRACT_LIST.MULTISIG]: 'cw3_flex_multisig', } +const defaultContractVersions = { + [CONTRACT_LIST.FLAGS]: DEFAULT_RELEASE_VERSION, + [CONTRACT_LIST.DEVIATION_FLAGGING_VALIDATOR]: DEFAULT_RELEASE_VERSION, + [CONTRACT_LIST.OCR_2]: DEFAULT_RELEASE_VERSION, + [CONTRACT_LIST.ACCESS_CONTROLLER]: DEFAULT_RELEASE_VERSION, + [CONTRACT_LIST.CW20_BASE]: DEFAULT_CWPLUS_VERSION, + [CONTRACT_LIST.CW4_GROUP]: DEFAULT_CWPLUS_VERSION, + [CONTRACT_LIST.MULTISIG]: DEFAULT_CWPLUS_VERSION, +} export const getContractABI = (contractId: CONTRACT_LIST): TerraABI => { // Possible paths depending on how/where gauntlet is being executed const possibleContractPaths = [ - path.join(__dirname, '../../../..', './contracts'), + path.join(__dirname, './artifacts/contracts'), path.join(process.cwd(), './contracts'), - path.join(process.cwd(), '../..', './contracts'), + path.join(process.cwd(), '../../contracts'), + path.join(process.cwd(), './packages-ts/gauntlet-terra-contracts/artifacts/contracts'), ] const toDirName = (contractId: CONTRACT_LIST) => contractDirName[contractId] @@ -78,7 +105,13 @@ export const getContractABI = (contractId: CONTRACT_LIST): TerraABI => { const abi = possibleContractPaths .filter((path) => existsSync(`${path}/${toDirName(contractId)}/schema`)) .map((contractPath) => { - const toPath = (type) => path.join(contractPath, `./${toDirName(contractId)}/schema/${type}`) + const toPath = (type) => { + if (contractId == CONTRACT_LIST.CW20_BASE && type == 'execute_msg') { + return path.join(contractPath, `./${toDirName(contractId)}/schema/cw20_${type}`) + } else { + return path.join(contractPath, `./${toDirName(contractId)}/schema/${type}`) + } + } return { execute: io.readJSON(toPath('execute_msg')), query: io.readJSON(toPath('query_msg')), @@ -93,6 +126,7 @@ export const getContractABI = (contractId: CONTRACT_LIST): TerraABI => { } export const getContract = async (id: CONTRACT_LIST, version): Promise => { + version = version ? version : defaultContractVersions[id] // Preload contracts return { id, diff --git a/packages-ts/gauntlet-terra-contracts/src/lib/schema.ts b/packages-ts/gauntlet-terra-contracts/src/lib/schema.ts index 6789d127..1d116a89 100644 --- a/packages-ts/gauntlet-terra-contracts/src/lib/schema.ts +++ b/packages-ts/gauntlet-terra-contracts/src/lib/schema.ts @@ -1,5 +1,4 @@ import Ajv from 'ajv' - import JTD from 'ajv/dist/jtd' const ajv = new Ajv().addFormat('uint8', (value: any) => !isNaN(value)) diff --git a/packages-ts/gauntlet-terra-contracts/src/lib/utils.ts b/packages-ts/gauntlet-terra-contracts/src/lib/utils.ts new file mode 100644 index 00000000..ed2b66e3 --- /dev/null +++ b/packages-ts/gauntlet-terra-contracts/src/lib/utils.ts @@ -0,0 +1,13 @@ +import { bech32 } from 'bech32' + +// https://docs.terra.money/docs/develop/sdks/terra-js/common-examples.html +export function isValidAddress(address) { + try { + const { prefix: decodedPrefix } = bech32.decode(address) // throw error if checksum is invalid + // verify address prefix + return decodedPrefix === 'terra' + } catch { + // invalid checksum + return false + } +} diff --git a/scripts/show_contract_instantiations.sh b/scripts/show_contract_instantiations.sh new file mode 100755 index 00000000..afda90f6 --- /dev/null +++ b/scripts/show_contract_instantiations.sh @@ -0,0 +1 @@ +terrad query txs --events instantiate_contract.creator=terra1pl4k5rj2jv6phm2vvhkttju7px6va2ja2v3haw $@ diff --git a/scripts/terrad_env.sh b/scripts/terrad_env.sh new file mode 100755 index 00000000..fbcc509d --- /dev/null +++ b/scripts/terrad_env.sh @@ -0,0 +1,15 @@ +# Uncomment relevant section to make terrad CLI more usable. +# Add $NODE on command line for any commands, $TXFLAGS for tx commands + +#export CHAIN_ID=localterra +#export RPC=tcp://localhost:26657 + +#export CHAIN_ID=mainnet +#export RPC=http://public-node.terra.dev:26657 + +export CHAIN_ID="bombay-12" +export RPC=https://terra-testnet-1.simply-vc.com.mt:443/345DKJ45F6G5/rpc/ + +export NODE="--node $RPC" +export TXFLAG="${NODE} --chain-id $CHAIN_ID --fees 100000uluna --gas auto --gas-adjustment 1.2 --broadcast-mode=block" +#export TXFLAG="${NODE} --chain-id $CHAIN_ID --gas-prices 0.50luna --gas auto --gas-adjustment 1.2" diff --git a/scripts/upload_wasm.sh b/scripts/upload_wasm.sh new file mode 100755 index 00000000..16786dfb --- /dev/null +++ b/scripts/upload_wasm.sh @@ -0,0 +1,11 @@ +if [ -z "$2" ] +then + echo "Usage: $0 WALLET WASM_FILE" + exit -1 +fi +CMD="terrad tx wasm store $2 --from $1 $TXFLAG -y --output json" +echo "$CMD" +RES=$($CMD) && + echo "Uploaded $2" && + echo $Result: $RES" && + echo "Code ID: "$(echo $RES | jq -r '.logs[0].events[-1].attributes[0].value')" diff --git a/tests/e2e/common_artifacts/cw3_flex_multisig.wasm b/tests/e2e/common_artifacts/cw3_flex_multisig.wasm new file mode 100644 index 00000000..1dd355e1 Binary files /dev/null and b/tests/e2e/common_artifacts/cw3_flex_multisig.wasm differ diff --git a/tests/e2e/common_artifacts/cw4_group.wasm b/tests/e2e/common_artifacts/cw4_group.wasm new file mode 100644 index 00000000..29c0df08 Binary files /dev/null and b/tests/e2e/common_artifacts/cw4_group.wasm differ