-
Notifications
You must be signed in to change notification settings - Fork 9
How to use Polytone
In Polytone we have 2 chains and 3 contracts
- ChainA - the controller chain, the chain which controls accounts on ChainB
- ChainB - the host chain, the chain that host accounts that are controlled by ChainA
Contracts
:
- Note - Deployed on ChainA to handle calls
to
ChainB - Voice - Deployed on chainB to handle calls
from
ChainA - Proxy - Deployed on chainB, is an account instantiated by the voice and only controlled by a single wallet from chainA
- ChainA - upload Note
- ChainB - Upload Voice and Proxy
- ChainA - Instantiate Note contract
- ChainB - Instantiate Voice contract (and pass Proxy code id)
A controlled Note allows instantiating a Note which can only be controlled by a single entity, this allows outposts to instantiate their own private Note and execute calls on behalf of its users.
To instantiate a controlled Note, pass an address in the controller
parameter when instantiating a Note.
Open a channel between your Note and Voice contracts, make sure the version is correct.
You can execute a msg on Note on ChainA from any wallet you want (remember that any address on ChainA creates a 1 of 1 unique account on ChainB)
'{ "execute" : { "msgs" : [], callback: null, "timeout_seconds" : "600", "on_behalf_of" : null }}'
Execute {
msgs: Vec<CosmosMsg<Empty>>,
callback: Option<CallbackRequest>,
timeout_seconds: Uint64,
on_behalf_of: Option<String>, // only used on controlled Note
}
msgs: Vec<CosmosMsg<Empty>>
- Array of cosmos messages to be executed on ChainB.
callback: Option<CallbackRequest>,
- A callback to be executed with the responses.
receiver - contract address to execute the callback on
msg - your custom message to send with the callback
pub struct CallbackRequest {
pub receiver: String,
pub msg: Binary,
}
timeout_seconds: Uint64
- timeout in seconds for IBC packet.
on_behalf_of: Option<String>
- Only used on controlled Note, to allow the controller to specify the original caller, and execute messages on his behalf on ChainB.
Query {
msgs: Vec<QueryRequest<Empty>>,
callback: CallbackRequest,
timeout_seconds: Uint64,
},
msgs: Vec<QueryRequest<Empty>>
- queries to execute on ChainB
callback: CallbackRequest
- callback to execute with the queries responses.
timeout_seconds: Uint64
- timeout in seconds for IBC packet.
When we execute or query something on ChainB, we usually want to do something with the response we get, this is what callbacks are for.
CallbackRequest
has 2 fields needed for a callback:
- receiver - contract address to execute the callback message
- msg - a custom msg you want to pass to the callback.
Here is the callback format we will send:
pub struct CallbackMessage {
pub initiator: Addr,
pub initiator_msg: Binary,
pub result: Callback,
}
initiator
- the original caller (in case of controlled note, this field will be the on_behalf_of
field pass from the controller)
initiator_msg
- the custom msg sent from the caller
result
- the result
The sent execute message will look like this:
// '{ "callback": { "initiator": ..., "initiator_msg": ..., "result": ... }}'
ExecuteMsg::Callback( CallbackMessage { initiator, initiator_msg, result } ) => { ... }
The result in the callback will look like this:
pub enum Callback {
Query(Result<Vec<Binary>, ErrorResponse>),
Execute(Result<ExecutionResponse, String>),
FatalError(String),
}
FatalError
- will be returned when something bad happened, like out of gas, or timeout.
Query
- will be returned if original message was Query, if successful a vector of query responses will be returned in Binary format, if any query errored, a ErrorResponse
will be return with the index of the errored query, and the error msg
pub struct ErrorResponse {
pub message_index: Uint64,
pub error: String,
}
Execute
- will be returned if original message was Execute, if any execute message errored, you will get the error string, if successful, you will get ExecutionResponse
which contains the address on ChainB that executed the message (the account address for the original sender), and the result which is a vector of SubMsgResponse
(same struct returned to you in reply if you executed a subMsg)
pub struct ExecutionResponse {
pub executed_by: String,
pub result: Vec<SubMsgResponse>,
}
- All returned vector indexes in result correspond to the original messages vector sent.
Sometimes you will need the account address on ChainB before executing something on Note ChainA, the accounts are created on first execute message sent on the Note, there are 2 ways to receive the account address on ChainB from Note ChainA:
- Query Note contract for the address:
RemoteAddress { local_address: String },
if the response is empty or null, there is no address associated to the requested address, if the response is not empty, the returned string is the account address on ChainB. - In callback as part of the result, you get
ExecutionResponse
which contains theexecuted_by
field which contains the account address on ChainB.