Interaction with testnet

Blockchain interaction is performed using the wasmd command-line tool. To start working with the testnet, we need to upload some smart contract code. For now, we would use an example cw4-group from the cw-plus repository. Start with cloning it:

$ git clone git@github.com:CosmWasm/cw-plus.git

Now go to cloned repo and run Rust optimizer on it:

$ docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  cosmwasm/workspace-optimizer:0.12.6

After a couple of minutes - it can take some for the first time - you should have an artifact directory in your repo, and there should be a cw4-group.wasm file being the contract we want to upload. To do so, run - note that wallet is name of the key you created in the previous chapter:

$ wasmd tx wasm store ./artifacts/cw4_group.wasm --from wallet $TXFLAG -y -b block

...
logs:
- events:
  - attributes:
    - key: action
      value: /cosmwasm.wasm.v1.MsgStoreCode
    - key: module
      value: wasm
    - key: sender
      value: wasm1wukxp2kldxae36rgjz28umqtq792twtxdfe6ux
    type: message
  - attributes:
    - key: code_id
      value: "12"
    type: store_code
...

As a result of execution, you should get a pretty long output with information about what happened. Most of this is an ancient cipher (aka base64) with execution metadata, but what we are looking for is the logs section. There should be an event called store_code, with a single attribute code_id - its value field is the code id of our uploaded contract - 12 in my case.

Now, when we have our code uploaded, we can go forward and instantiate a contract to create its new instance:

$ wasmd tx wasm instantiate 12 \
  '{ "admin": "wasm1wukxp2kldxae36rgjz28umqtq792twtxdfe6ux", "members": [] }' \
  --from wallet --label "Group" --no-admin $TXFLAG -y

...
logs:
- events:
  - attributes:
    - key: _contract_address
      value: wasm18yn206ypuxay79gjqv6msvd9t2y49w4fz8q7fyenx5aggj0ua37q3h7kwz
    - key: code_id
      value: "12"
    type: instantiate
  - attributes:
    - key: action
      value: /cosmwasm.wasm.v1.MsgInstantiateContract
    - key: module
      value: wasm
    - key: sender
      value: wasm1wukxp2kldxae36rgjz28umqtq792twtxdfe6ux
    type: message
...

In this command, the 12 is the code id - the result of uploading the code. After that, a JSON is an instantiation message - I will talk about this later. Just think about it as a message requiring fields to create a new contract. Every contract has its instantiation message format. For cw4-group, there are two fields: admin is an address that would be eligible to execute messages on this contract. It is crucial to set it to your address, as we will want to learn how to execute contracts. members is an array of addresses that are initial members of the group. We leave it empty for now, but you can put any addresses you want there. Here, I put one hint about messages inline into the command line, but I often put messages to be sent to the file and embed them via $(cat msg.json). It is fish syntax, but every shell provides a syntax for this.

Then after the message, you need to add a couple of additional flags. The --from wallet is the same as before - the name of the key you created earlier. --label "Group" is just an arbitrary name for your contract. An important one is a --no-admin flag - keep in mind that it is a different "admin" that we set in the instantiation message. This flag is relevant only for contract migrations, but we won't cover them right now, so leave this flag as it is.

Now, look at the result of the execution. It is very similar to before - much data about the execution process. And again, we need to take a closer look into the logs section of the response. This time we are looking at an event with type instantiate, and the _contract_address attribute - its value is newly created contract address - wasm1wukxp2kldxae36rgjz28umqtq792twtxdfe6ux in an example.

Now let's go forward with querying our contract:

$ wasmd query wasm contract-state smart \
  wasm18yn206ypuxay79gjqv6msvd9t2y49w4fz8q7fyenx5aggj0ua37q3h7kwz \
  '{ "list_members": {} }'

data:
  members: []

Remember to change the address (right after smart) with your contract address. After that, there is another message - this time the query message - which is sent to the contract. This query should return a list of group members. And in fact, it does - response is a single data object with a single field - empty members list. That was easy, now let's try the last thing: the execution:

$ wasmd tx wasm execute \
  wasm18yn206ypuxay79gjqv6msvd9t2y49w4fz8q7fyenx5aggj0ua37q3h7kwz \
  '{ "update_members": { "add": [{ "addr": "wasm1wukxp2kldxae36rgjz28umqtq792twtxdfe6ux", "weight": 1 }], "remove": [] } }' \
  --from wallet $TXFLAG

As you can see, execution is very similar to instantiation. The differences are, that instantiation is called just once, and execution needs a contract address. It is fair to say that instantiation is a particular case for first execution, which returns the contract address. Just like before we can see that we got some log output - you can analyze it to see that something probably happened. But to ensure that there is an effect on blockchain, the best way would be to query it once again:

$ wasmd query wasm contract-state smart \
  wasm18yn206ypuxay79gjqv6msvd9t2y49w4fz8q7fyenx5aggj0ua37q3h7kwz \
  '{ "list_members": {} }'

data:
  members:
  - addr: wasm1wukxp2kldxae36rgjz28umqtq792twtxdfe6ux
    weight: 1

For the time being, this is all you need to know about wasmd basics in order to be able to play with your simple contracts. We would focus on testing them locally, but if you want to check in real life, you have some basics now. We will take a closer look at wasmd later when we would talk about the architecture of the actor model defining communication between smart contracts.