To implement the gate
contract interface on your own contract, add the gate-pkg
on your Cargo.toml
:
[dependencies]
gate-pkg = {version = "0.1.0"}
It is necessary to register the permission
on the Gate
for each contract that wants to receive requests from a specific chain
.
The gate
contract will block incoming messages from unwanted addresses.
There are two types of permissions:
pub enum Permission {
Permissioned { addresses: Vec<String> }, // Only addresses in this list can send msgs to your contract
Permissionless, // All address can send msgs to your contract
}
There are two ways to register permission
:
- Send a
SetPermission
msg from the contract to thegate
; - Send a
SetPermissionFromAdmin
msg from the contractadmin
to thegate
;
pub enum ExecuteMsg {
...
SetPermission {
permission: Permission, // Type of permission
chain: String, // Remote chain name, you can query the gate for the registered chain
},
SetPermissionFromAdmin {
contract:Addr, // Contract to register permission, the sender must be the admin
permission: Permission,
chain: String,
},
}
Currently, the gate
supports the following requests
:
pub enum GateRequest {
/// Send a msg to a specific contract in a remote chain.
/// The contract that should receive the msg has to:
/// - Set the `Permission` in the `gate` contract (if Permission::Permissioned, the remote `gate` assert if the contract allows to receive msg from the `sender`);
/// - Handle the `ReceiveGateMsg(GateMsg::ReceviedMsg)` in its `ExecuteMsg` variant
SendMsg {
msg: Binary, // Binary msg to send
to_contract: String, // Remote contract address to send the msg
send_native: Option<SendNativeInfo>, // Information about native token to been sent within the request
},
/// Perform a list queries in a remote chain.
/// Once the result returns to the source chain, the gate sends an ExecuteMsg to the requesting contract.
/// The requesting contract must hanlde the `ReceiveGateMsg(GateMsg::QueryResponse)` in its `ExecuteMsg` variant.
Query {
queries: Vec<QueryRequest<Empty>>, // List of queries to be performed
callback_msg: Option<Binary>, // Callback msgs that will be return with the QueryResult
},
}
To send a request
to the gate
, use the following ExecuteMsg
variant:
pub enum ExecuteMsg {
...
/// Send a list of `GateRequests` to a specific chain.
SendRequests {
requests: Vec<GateRequest>, // List of requests
chain: String, // Destination chain name saved on gate contract
timeout: Option<u64>, // Timeout delta (in seconds)
},
}
To send native token
within a request (if the request type support native token
), you have to specify the SendNativeInfo
:
pub struct SendNativeInfo {
pub coin: Coin, // Amount of coin to be forwarded
pub path_middle_forward: Vec<PacketPath>, // List of path for middle packet forwarding
pub dest_denom: String, // Destination denom
pub channel_id: String, // Last channel-id to use to arrive at the destination chain
pub timeout: Option<u64>, // Timeout delta (in seconds)
}
In case a path_middle_forward
is set, the channel_id
is the last channel to use to send the token to the destination chain.
Example:
A
->B
->C
chain_id
is the channel used on chainB
to send to chainC
;path_middle_forward
will be:
vec![
PacketPath{
channel_id: "channel-A", // Channel on chain A used to transfer on chain B
address: "bech32ChainBAddress" // Valid bech32 Address on chain B (any valid address)
}
]
If Some native token
is sent within the requests, the gate contract perform the following checks:
- Calculate the remaining funds not specified in
send_native
field. - If the remaining
coins
is one and if the denom matches thebase_denom
of the local chain (information saved on the Config of thegate
).
If all check pass, the gate
interprets this amount as a fee
for the relayer
.
In your ExecuteMsg
enum of your contract, insert the following variant:
pub enum ExecuteMsg {
... // Your variants
ReceiveGateMsg(GateMsg),
}
This imports the msgs that the gate
will send to your contract.
You should save the correct gate
contract in your contract state and assert the info.sender
when this variant is executed.
GateMsg
is an enum has the following variations:
pub enum GateMsg {
// Called when a contract in a remote chain sends a msg
ReceiveMsg {
sender: String, // Sender address
msg: Binary, // Binary msg received
},
// Called when a request sent to the gate fails
RequestFailed {
request: GateRequest,
},
// Receive the responses of the requested queries
QueryResponse {
queries: Vec<GateQueryResponse>, // List of queries with the response
callback_msg: Option<Binary>, // Binary callback msg
},
// Advanced, see below for details
CollectMsgs {
sender: Addr,
msg: Binary,
},
}
-
ReceiveMsg
:Binary
msg received from a remotesender
(alredy filtered by thegate
contract). The sender is not the wallet that sign the tx, but the contract that send the msg to thegate
in the remote chain.You must to be able to deserialize the
Binary
msg to a known structure/enum. -
QueryResponse
: Response of the queries requested. Acallback_msg
can be set in the request and is returned to help the requesting contract to handle the response. -
RequestFailed
: A request sent to thegate
fails on destination chain.Since the execution on destination chain is not atomic (the
packet
needs to be relayed), if some states are changed within themsg
that sent therequest
to thegate
, the fact that the tx fails on the remote chain does not cancel any changes made in this chain. The sender must, therefore, know what to reverse in this case (if a reverse is needed). The sent request is passed to help the revers. -
CollectMsgs
: When thegate
trigger this GateMsg variant, all request that will be sent to the gate by this exection or any other msgs that this exection triggers, will be stored inside the gate contract instead of beign sent directly.Once the entire message is concluded, a single
ibc packet
is prepared containing all therequests
from the various contracts.This is used when your contract needs to send a
request
to a remote chain along withrequests
from other contracts.An example would be bridging a loan position with some CW20 tokens as collateral. The contract that stores the loan position needs to send a bridge request to all collaterals (assuming they are cw20-icg) and a
request
to thegate
containing the loan information.When the bridge
request
is sent to the cw20-icg, the token will send arequest
to thegate
, but it will be stored inside the gate. When allrequests
arrive, the gate sends all of them in oneibc packet
. This allows performing all therequests
atomically in the destination chain, and if onerequest
fails, all of them fail.To use this feature, similar to
ExecuteMsg::Send
for cw20 tokens, the user has to send the msg with the bridge position request (inbinary
) to thegate
contract. At this point, thegate
starts recording the requests and sends the collectMsg to the specified contract on behalf of the user.