Skip to content

Instantly share code, notes, and snippets.

@cordt-sei
Last active December 9, 2024 04:34
Show Gist options
  • Save cordt-sei/d3db7b9433b9b7f79ace1cdd5076998c to your computer and use it in GitHub Desktop.
Save cordt-sei/d3db7b9433b9b7f79ace1cdd5076998c to your computer and use it in GitHub Desktop.

Quick dive into wasm contract queries

They are all fairly straightforward, since everything is human-readable and all the functions and methods are returned by simply sending an "invalid" payload in a query.

The REST API method is simple:

/cosmwasm/wasm/v1/contract/${contractAddress}/smart/${payLoad_base64}

Quick queries

Here is a pretty basic script for exploring these queries, [or you can just use https://seiscan.app]

[click to expand]
#!/bin/bash

# accepts 3 args: REST URL, contract address, payload [json string]
# remembers last-entered values for first 2 args
# payload "test" set as alias for '{"a":"b"}' to return valid query methods

# File to store the last used values
config_file="last_run.conf"

# Load previous values if the file exists
if [ -f "$config_file" ]; then
    source $config_file
fi

# Function to get user input with default
function get_input() {
    local input
    local default_value=$2
    read -p "$1 [$default_value]: " input
    echo "${input:-$default_value}"
}

# Prompt for restAddress
restAddress=$(get_input "Enter the REST API address" "$restAddress")

# Prompt for contractAddress
contractAddress=$(get_input "Enter the contract address" "$contractAddress")

# Prompt for payload and check if input is 'test'
payLoad=$(get_input "Enter the payload (or 'test' for default)" "$payLoad")
if [ "$payLoad" == "test" ]; then
    payLoad='{"a":"b"}'
fi

# Prompt for block height (optional)
blockHeight=$(get_input "Enter the block height (optional)" "") # Default is empty

# Encode payload to base64
payLoad_base64=$(echo "$payLoad" | base64 -w 0) # -w 0 to disable line wrapping

# Save the latest inputs, excluding blockHeight
echo "restAddress='$restAddress'" > $config_file
echo "contractAddress='$contractAddress'" >> $config_file
echo "payLoad='$payLoad'" >> $config_file

# Build the URL
url="${restAddress}/cosmwasm/wasm/v1/contract/${contractAddress}/smart/${payLoad_base64}"

# Add header if block height is provided
if [ -n "$blockHeight" ]; then
    response=$(curl -s --write-out "\n%{http_code}" --url "$url" -H "x-cosmos-block-height: $blockHeight")
else
    response=$(curl -s --write-out "\n%{http_code}" --url "$url")
fi

# Separate the status code from the response body
http_code=$(echo "$response" | tail -n1)  # Last line of output is the HTTP status code
response_body=$(echo "$response" | head -n -1)  # Remove the last line (status code)

# Check if the response is successful or expected (200 or 400)
if [ "$http_code" -eq 200 ] || [ "$http_code" -eq 400 ]; then
    # Print pretty JSON
    echo "$response_body" | jq .
else
    echo "Error: HTTP status $http_code"
    echo "$response_body"
fi

The script will save your most recently used selections in a temporary file so you don't have to enter them again for repeated queries. Everything is in interactive promptss. Give it a REST address, followed by the contract address, then a query method (or just test to send the "invalid" payload and discover the available methods as reported by the contract itself) Finally (optional) a block height. Leaving this one null will just default to "latest" height.


General procedure

Query the collection itself to see ownership

payload:

{
  "ownership": {}
}

response:

{
  "data": {
    "owner": "sei1hjsqrfdg2hvwl3gacg4fkznurf36usrv7rkzkyh29wz3guuzeh0snslz7d",
    "pending_owner": null,
    "pending_expiry": null
  }
}

Check into this contract

payload:

{"a":"b"}

response:

{
  "code": 3,
  "message": "Error parsing into type lighthouse::msg::QueryMsg: unknown variant `a`, expected one of `get_config`, `get_collection`, `balance_of`, `get_collections`, `get_minter_of`, `is_collection_renounced`: query wasm contract failed: invalid request",
  "details": []
}

From this we can tell this is the "lighthouse" contract which is a marketplace or launchpad of some kind

Now we query this using one of the above methods

payload:

{
  "get_collection": {
    "collection": "sei1lsde7r5mgjaxw7gtae7tadmpprz05qg3rkpalrwxy3kuvesf0k5q5wqepf"
  }
}

and just out of sheer luck, this one happens to contain the royalties info:

[click to expand]
{
  "data": {
    "admin": "sei19c7a9uccaw9y0q6jz90nk69e8jt3kdq4rtw8c0",
    "cw721_address": "sei1lsde7r5mgjaxw7gtae7tadmpprz05qg3rkpalrwxy3kuvesf0k5q5wqepf",
    "name": "SEITAN",
    "symbol": "SEITAN",
    "supply": 6666,
    "token_uri": "https://arweave.net/7Ftj2FmIzzTtJBY55hSPxAr6zui5FAkuFFpz1HYPBu0",
    "royalty_percent": 9,
    "royalty_wallet": "sei1sqfnzezu55ectwwunt6nmjcelkyk0qru9wmhgh",
    "next_token_id": 6666,
    "mint_groups": [
      {
        "name": "team",
        "merkle_root": [
          3,
          246,
          111,
          97,
          101,
          144,
          222,
          165,
          174,
          77,
          12,
          252,
          47,
          200,
          167,
          82,
          197,
          216,
          174,
          75,
          169,
          135,
          148,
          13,
          105,
          181,
          89,
          243,
          133,
          87,
          105,
          148
        ],
        "max_tokens": 0,
        "unit_price": "0",
        "creators": [
          {
            "address": "sei1sqfnzezu55ectwwunt6nmjcelkyk0qru9wmhgh",
            "share": 100
          }
        ],
        "start_time": 1674500400,
        "end_time": 1737659700
      },
      {
        "name": "OG",
        "merkle_root": [
          206,
          195,
          66,
          6,
          168,
          143,
          26,
          222,
          59,
          185,
          209,
          39,
          211,
          206,
          204,
          58,
          84,
          27,
          24,
          236,
          113,
          12,
          255,
          51,
          75,
          220,
          250,
          157,
          74,
          77,
          130,
          148
        ],
        "max_tokens": 2,
        "unit_price": "0",
        "creators": [
          {
            "address": "sei1sqfnzezu55ectwwunt6nmjcelkyk0qru9wmhgh",
            "share": 100
          }
        ],
        "start_time": 1706037300,
        "end_time": 1706038200
      },
      {
        "name": "Whitelist",
        "merkle_root": [
          31,
          1,
          242,
          183,
          77,
          216,
          92,
          133,
          175,
          79,
          219,
          180,
          18,
          161,
          63,
          173,
          225,
          213,
          253,
          179,
          7,
          179,
          216,
          143,
          158,
          161,
          94,
          144,
          246,
          180,
          53,
          71
        ],
        "max_tokens": 1,
        "unit_price": "0",
        "creators": [
          {
            "address": "sei1sqfnzezu55ectwwunt6nmjcelkyk0qru9wmhgh",
            "share": 100
          }
        ],
        "start_time": 1706038200,
        "end_time": 1706040000
      },
      {
        "name": "Public",
        "merkle_root": null,
        "max_tokens": 5,
        "unit_price": "16660000",
        "creators": [
          {
            "address": "sei1v9dlnmfhzfvk2wyj38f0e3w6557xhv7js7q736",
            "share": 8
          },
          {
            "address": "sei1sqfnzezu55ectwwunt6nmjcelkyk0qru9wmhgh",
            "share": 92
          }
        ],
        "start_time": 1737662400,
        "end_time": 0
      }
    ],
    "iterated_uri": false,
    "start_order": null,
    "frozen": false,
    "hidden_metadata": false,
    "placeholder_token_uri": null
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment