Here we describe a simple system for interacting with CosmWasm contracts without paying gas. Instead of submitting transactions to a RPC node, addresses submit a signed ExecuteMsg
to a third party and that party relays those messages to the appropriate smart contract. This third party may censor but not forge messages, and messages may be submitted as regular transactions to circumvent any censorship by the third party.
Messages have the format:
{
"payload": {
"nonce": u64,
"msg": ExecuteMsg,
"expiration": Timestamp | null,
"bech32_prefix": String,
"to": Addr,
"version": String
},
"signature": Binary,
"pk": secp256,
}
To accept one of these messages from a smart contract:
- Validate that the payload is validly signed, or error.
- Validate that the payload has the correct nonce, or error.
- Validate that the payload has not expired, or error.
- Validate that the
to
field corresponds with the current contract. - Validate that the
version
field corresponds to the verifier version. - Set the message sender to the address corresponding to the provided public key.
- Call back into the contract's execute handler with this new sender and message.
let nonces: Map<String, u64> = Map::new("nonces");
let nonce = nonces.load(deps.storage, msg.pk)?;
deps.api.secp256k1_verify(msg.payload, msg.signature, msg.pk)?;
if msg.payload.nonce != nonce {
return Err(NogasError::InvalidNonce)
}
if msg.payload.expiration.is_expired(&env.block) {
return Err(NogasError::ExpiredPayload)
}
if msg.payload.to != env.contract.address {
return Err(NoGasError::WrongReceiver)
}
if msg.payload.version != VERIFIER_VERSION {
return Err(NoGasError::WrongVersion)
}
nonces.save(deps.storage, msg.pk, nonce + 1)?;
// call back into execute
info.sender = pk_to_addr(msg.pk)?;
execute(deps, info, env, msg.payload.msg)
This is permissionless in that any address may submit these signed messages.
The simplest design has a single web2 server with a private key submit messages on behalf of users. This server would likely be run by the developers. We are exploring designs for decentralizing execution:
We expect that executors will want to filter messages. For example, DAO DAO may start by only making votes free. This filtering should only happen on the executor, and not in contracts.
This system provides the same security and availability as an RPC node. The web2 server committing your signed messages to the chain may censor you, like an RPC node. No party can execute messages on your behalf so long so your private key is kept private.
As far as the public key goes, are we going to be passing a compressed on uncompressed one?