Fixes to VAA submission to Terra smart contract (#115)
* Terra smart contract binary interface changed from vector to base64 string * Added initial guardian set submission to Terra
This commit is contained in:
parent
e39fb2abec
commit
ee5d07c929
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/certusone/wormhole/bridge/pkg/devnet"
|
||||
gossipv1 "github.com/certusone/wormhole/bridge/pkg/proto/gossip/v1"
|
||||
"github.com/certusone/wormhole/bridge/pkg/supervisor"
|
||||
"github.com/certusone/wormhole/bridge/pkg/terra"
|
||||
"github.com/certusone/wormhole/bridge/pkg/vaa"
|
||||
)
|
||||
|
||||
|
@ -167,6 +168,15 @@ func (p *Processor) checkDevModeGuardianSetUpdate(ctx context.Context) error {
|
|||
|
||||
p.logger.Info("devnet guardian set change submitted to Ethereum", zap.Any("trx", trx), zap.Any("vaa", v))
|
||||
|
||||
if p.terraChaidID != "" {
|
||||
// Submit to Terra
|
||||
trxResponse, err := terra.SubmitVAA(timeout, p.terraLCD, p.terraChaidID, p.terraContract, p.terraFeePayer, v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to submit devnet guardian set change: %v", err)
|
||||
}
|
||||
p.logger.Info("devnet guardian set change submitted to Terra", zap.Any("trxResponse", trxResponse), zap.Any("vaa", v))
|
||||
}
|
||||
|
||||
// Submit VAA to Solana as well. This is asynchronous and can fail, leading to inconsistent devnet state.
|
||||
p.vaaC <- v
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ package terra
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/certusone/wormhole/bridge/pkg/vaa"
|
||||
|
@ -14,24 +12,12 @@ import (
|
|||
"github.com/terra-project/terra.go/tx"
|
||||
)
|
||||
|
||||
type JSONArraySlice []uint8
|
||||
|
||||
func (u JSONArraySlice) MarshalJSON() ([]uint8, error) {
|
||||
var result string
|
||||
if u == nil {
|
||||
result = "null"
|
||||
} else {
|
||||
result = strings.Join(strings.Fields(fmt.Sprintf("%d", u)), ",")
|
||||
}
|
||||
return []byte(result), nil
|
||||
}
|
||||
|
||||
type SubmitVAAMsg struct {
|
||||
Params SubmitVAAParams `json:"submit_v_a_a"`
|
||||
}
|
||||
|
||||
type SubmitVAAParams struct {
|
||||
VAA JSONArraySlice `json:"vaa"`
|
||||
VAA []byte `json:"vaa"`
|
||||
}
|
||||
|
||||
// SubmitVAA prepares transaction with signed VAA and sends it to the Terra blockchain
|
||||
|
|
|
@ -242,7 +242,7 @@ data:
|
|||
flush_throttle_timeout = "100ms"
|
||||
|
||||
# Maximum size of a message packet payload, in bytes
|
||||
max_packet_msg_payload_size = 1024
|
||||
max_packet_msg_payload_size = 4096
|
||||
|
||||
# Rate at which packets can be sent, in bytes/second
|
||||
send_rate = 5120000
|
||||
|
@ -776,7 +776,7 @@ data:
|
|||
"params": {
|
||||
"max_contract_size": "512000",
|
||||
"max_contract_gas": "100000000",
|
||||
"max_contract_msg_size": "1024"
|
||||
"max_contract_msg_size": "4096"
|
||||
},
|
||||
"last_code_id": "0",
|
||||
"last_instance_id": "0",
|
||||
|
@ -1279,7 +1279,7 @@ data:
|
|||
flush_throttle_timeout = "100ms"
|
||||
|
||||
# Maximum size of a message packet payload, in bytes
|
||||
max_packet_msg_payload_size = 1024
|
||||
max_packet_msg_payload_size = 4096
|
||||
|
||||
# Rate at which packets can be sent, in bytes/second
|
||||
send_rate = 5120000
|
||||
|
@ -1813,7 +1813,7 @@ data:
|
|||
"params": {
|
||||
"max_contract_size": "512000",
|
||||
"max_contract_gas": "100000000",
|
||||
"max_contract_msg_size": "1024"
|
||||
"max_contract_msg_size": "4096"
|
||||
},
|
||||
"last_code_id": "0",
|
||||
"last_instance_id": "0",
|
||||
|
|
|
@ -168,7 +168,7 @@ mod tests {
|
|||
fn do_init<S: Storage, A: Api, Q: Querier>(deps: &mut Extern<S, A, Q>, creator: &HumanAddr) {
|
||||
let init_msg = InitMsg {
|
||||
asset_chain: 1,
|
||||
asset_address: vec![1; 32],
|
||||
asset_address: vec![1; 32].into(),
|
||||
decimals: 10,
|
||||
mint: None,
|
||||
init_hook: None,
|
||||
|
@ -191,7 +191,7 @@ mod tests {
|
|||
query_wrapped_asset_info(&deps).unwrap(),
|
||||
WrappedAssetInfoResponse {
|
||||
asset_chain: 1,
|
||||
asset_address: vec![1; 32],
|
||||
asset_address: vec![1; 32].into(),
|
||||
bridge: creator.clone(),
|
||||
}
|
||||
);
|
||||
|
|
|
@ -7,7 +7,7 @@ use cw20::Expiration;
|
|||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct InitMsg {
|
||||
pub asset_chain: u8,
|
||||
pub asset_address: Vec<u8>,
|
||||
pub asset_address: Binary,
|
||||
pub decimals: u8,
|
||||
pub mint: Option<InitMint>,
|
||||
pub init_hook: Option<InitHook>,
|
||||
|
@ -105,6 +105,6 @@ pub enum QueryMsg {
|
|||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct WrappedAssetInfoResponse {
|
||||
pub asset_chain: u8, // Asset chain id
|
||||
pub asset_address: Vec<u8>, // Asset smart contract address in the original chain
|
||||
pub asset_address: Binary, // Asset smart contract address in the original chain
|
||||
pub bridge: HumanAddr, // Bridge address, authorized to mint and burn wrapped tokens
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cosmwasm_std::{CanonicalAddr, ReadonlyStorage, Storage};
|
||||
use cosmwasm_std::{CanonicalAddr, ReadonlyStorage, Storage, Binary};
|
||||
use cosmwasm_storage::{singleton, singleton_read, ReadonlySingleton, Singleton};
|
||||
|
||||
pub const KEY_WRAPPED_ASSET: &[u8] = b"wrappedAsset";
|
||||
|
@ -10,7 +10,7 @@ pub const KEY_WRAPPED_ASSET: &[u8] = b"wrappedAsset";
|
|||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct WrappedAssetInfo {
|
||||
pub asset_chain: u8, // Asset chain id
|
||||
pub asset_address: Vec<u8>, // Asset smart contract address on the original chain
|
||||
pub asset_address: Binary, // Asset smart contract address on the original chain
|
||||
pub bridge: CanonicalAddr, // Bridge address, authorized to mint and burn wrapped tokens
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ static WASM: &[u8] =
|
|||
include_bytes!("../../../target/wasm32-unknown-unknown/release/cw20_wrapped.wasm");
|
||||
|
||||
use cosmwasm_std::{
|
||||
from_slice, Env, HandleResponse, HandleResult, HumanAddr, InitResponse, Uint128,
|
||||
from_slice, Env, HandleResponse, HandleResult, HumanAddr, InitResponse, Uint128, Binary,
|
||||
};
|
||||
use cosmwasm_storage::to_length_prefixed;
|
||||
use cosmwasm_vm::testing::{
|
||||
|
@ -51,7 +51,7 @@ fn do_init(height: u64) -> Instance<MockStorage, MockApi, MockQuerier> {
|
|||
let mut deps = mock_instance(WASM, &[]);
|
||||
let init_msg = InitMsg {
|
||||
asset_chain: 1,
|
||||
asset_address: vec![1; 32],
|
||||
asset_address: vec![1; 32].into(),
|
||||
decimals: 10,
|
||||
mint: None,
|
||||
init_hook: None,
|
||||
|
@ -67,7 +67,7 @@ fn do_init(height: u64) -> Instance<MockStorage, MockApi, MockQuerier> {
|
|||
get_wrapped_asset_info(storage),
|
||||
WrappedAssetInfo {
|
||||
asset_chain: 1,
|
||||
asset_address: vec![1; 32],
|
||||
asset_address: vec![1; 32].into(),
|
||||
bridge: api.canonical_address(&TestAddress::INITIALIZER.value()).0?,
|
||||
}
|
||||
);
|
||||
|
@ -141,18 +141,6 @@ fn check_token_details(deps: &mut Instance<MockStorage, MockApi, MockQuerier>, s
|
|||
);
|
||||
}
|
||||
|
||||
fn format_array(data: &Vec<u8>) -> String {
|
||||
let mut result = String::new();
|
||||
|
||||
for num in &data[0..data.len() - 1] {
|
||||
result.push_str(&num.to_string());
|
||||
result.push_str(",");
|
||||
}
|
||||
result.push_str(&data[data.len() - 1].to_string());
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn init_works() {
|
||||
let mut deps = do_init(111);
|
||||
|
@ -168,9 +156,9 @@ fn query_works() {
|
|||
query_response.as_slice(),
|
||||
format!(
|
||||
"{{\"asset_chain\":1,\
|
||||
\"asset_address\":[{}],\
|
||||
\"asset_address\":\"{}\",\
|
||||
\"bridge\":\"{}\"}}",
|
||||
format_array(&vec![1; 32]),
|
||||
Binary::from(vec![1; 32]).to_base64(),
|
||||
TestAddress::INITIALIZER.value().as_str()
|
||||
)
|
||||
.as_bytes()
|
||||
|
|
|
@ -68,15 +68,15 @@ pub fn handle<S: Storage, A: Api, Q: Querier>(
|
|||
msg: HandleMsg,
|
||||
) -> StdResult<HandleResponse> {
|
||||
match msg {
|
||||
HandleMsg::SubmitVAA { vaa } => handle_submit_vaa(deps, env, &vaa),
|
||||
HandleMsg::RegisterAssetHook { asset_id } => handle_register_asset(deps, env, &asset_id),
|
||||
HandleMsg::SubmitVAA { vaa } => handle_submit_vaa(deps, env, &vaa.as_slice()),
|
||||
HandleMsg::RegisterAssetHook { asset_id } => handle_register_asset(deps, env, &asset_id.as_slice()),
|
||||
HandleMsg::LockAssets {
|
||||
asset,
|
||||
recipient,
|
||||
amount,
|
||||
target_chain,
|
||||
nonce,
|
||||
} => handle_lock_assets(deps, env, asset, amount, recipient, target_chain, nonce),
|
||||
} => handle_lock_assets(deps, env, asset, amount, recipient.as_slice(), target_chain, nonce),
|
||||
HandleMsg::SetActive { is_active } => handle_set_active(deps, env, is_active),
|
||||
}
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ fn vaa_update_guardian_set<S: Storage, A: Api, Q: Querier>(
|
|||
let mut pos = 5;
|
||||
for _ in 0..len {
|
||||
new_guardian_set.addresses.push(GuardianAddress {
|
||||
bytes: data[pos..pos + 20].to_vec(),
|
||||
bytes: data[pos..pos + 20].to_vec().into(),
|
||||
});
|
||||
pos += 20;
|
||||
}
|
||||
|
@ -351,7 +351,7 @@ fn vaa_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
code_id: state.wrapped_asset_code_id,
|
||||
msg: to_binary(&WrappedInit {
|
||||
asset_chain: token_chain,
|
||||
asset_address: asset_address.to_vec(),
|
||||
asset_address: asset_address.to_vec().into(),
|
||||
decimals: data.get_u8(103),
|
||||
mint: Some(InitMint {
|
||||
recipient: deps.api.human_address(&target_address)?,
|
||||
|
@ -360,7 +360,7 @@ fn vaa_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
init_hook: Some(InitHook {
|
||||
contract_addr: env.contract.address,
|
||||
msg: to_binary(&HandleMsg::RegisterAssetHook {
|
||||
asset_id: asset_id.to_vec(),
|
||||
asset_id: asset_id.to_vec().into(),
|
||||
})?,
|
||||
}),
|
||||
})?,
|
||||
|
@ -398,7 +398,7 @@ fn handle_lock_assets<S: Storage, A: Api, Q: Querier>(
|
|||
env: Env,
|
||||
asset: HumanAddr,
|
||||
amount: Uint128,
|
||||
recipient: Vec<u8>,
|
||||
recipient: &[u8],
|
||||
target_chain: u8,
|
||||
nonce: u32,
|
||||
) -> StdResult<HandleResponse> {
|
||||
|
@ -449,7 +449,7 @@ fn handle_lock_assets<S: Storage, A: Api, Q: Querier>(
|
|||
let wrapped_token_info: WrappedAssetInfoResponse =
|
||||
deps.querier.custom_query(&request)?;
|
||||
asset_chain = wrapped_token_info.asset_chain;
|
||||
asset_address = wrapped_token_info.asset_address;
|
||||
asset_address = wrapped_token_info.asset_address.as_slice().to_vec();
|
||||
}
|
||||
Err(_) => {
|
||||
// This is a regular asset, transfer its balance
|
||||
|
@ -544,7 +544,7 @@ fn keys_equal(a: &VerifyKey, b: &GuardianAddress) -> bool {
|
|||
if a.len() != b.len() {
|
||||
return false;
|
||||
}
|
||||
for (ai, bi) in a.iter().zip(b.iter()) {
|
||||
for (ai, bi) in a.iter().zip(b.as_slice().iter()) {
|
||||
if ai != bi {
|
||||
return false;
|
||||
}
|
||||
|
@ -594,7 +594,7 @@ mod tests {
|
|||
vaa: &str,
|
||||
) -> StdResult<HandleResponse> {
|
||||
let msg = HandleMsg::SubmitVAA {
|
||||
vaa: hex::decode(vaa).expect("Decoding failed"),
|
||||
vaa: hex::decode(vaa).expect("Decoding failed").into(),
|
||||
};
|
||||
let env = mock_env(&HumanAddr::from("creator"), &[]);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use cosmwasm_std::{HumanAddr, Uint128};
|
||||
use cosmwasm_std::{HumanAddr, Uint128, Binary};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -15,15 +15,15 @@ pub struct InitMsg {
|
|||
#[serde(rename_all = "snake_case")]
|
||||
pub enum HandleMsg {
|
||||
SubmitVAA {
|
||||
vaa: Vec<u8>,
|
||||
vaa: Binary,
|
||||
},
|
||||
RegisterAssetHook {
|
||||
asset_id: Vec<u8>,
|
||||
asset_id: Binary,
|
||||
},
|
||||
LockAssets {
|
||||
asset: HumanAddr,
|
||||
amount: Uint128,
|
||||
recipient: Vec<u8>,
|
||||
recipient: Binary,
|
||||
target_chain: u8,
|
||||
nonce: u32,
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cosmwasm_std::{CanonicalAddr, HumanAddr, StdResult, Storage};
|
||||
use cosmwasm_std::{CanonicalAddr, HumanAddr, StdResult, Storage, Binary};
|
||||
use cosmwasm_storage::{
|
||||
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
|
||||
Singleton,
|
||||
|
@ -34,7 +34,7 @@ pub struct ConfigInfo {
|
|||
// Guardian address
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct GuardianAddress {
|
||||
pub bytes: Vec<u8>, // 20-byte addresses
|
||||
pub bytes: Binary, // 20-byte addresses
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -43,7 +43,7 @@ use hex;
|
|||
impl GuardianAddress {
|
||||
pub fn from(string: &str) -> GuardianAddress {
|
||||
GuardianAddress {
|
||||
bytes: hex::decode(string).expect("Decoding failed"),
|
||||
bytes: hex::decode(string).expect("Decoding failed").into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ fn do_init(
|
|||
#[test]
|
||||
fn init_works() {
|
||||
let guardians = vec![GuardianAddress::from(GuardianAddress {
|
||||
bytes: hex::decode("beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe").expect("Decoding failed"),
|
||||
bytes: hex::decode("beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe").expect("Decoding failed").into(),
|
||||
})];
|
||||
let _deps = do_init(111, &guardians);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ async function script() {
|
|||
let lockResult = await execute_contract(wormhole_contract, {lock_assets: {
|
||||
asset: token_contract,
|
||||
amount,
|
||||
recipient: [...Buffer.from('00000000000000000000000019a4437E2BA06bF1FA42C56Fb269Ca0d30f60716', 'hex')],
|
||||
recipient: Buffer.from('00000000000000000000000019a4437E2BA06bF1FA42C56Fb269Ca0d30f60716', 'hex').toString('base64'),
|
||||
target_chain: 2, // Ethereum
|
||||
nonce: Date.now() % 1000000
|
||||
}});
|
||||
|
|
|
@ -13,7 +13,7 @@ async function script() {
|
|||
let contract_address = await instantiate_contract(wormhole_code_id, {
|
||||
initial_guardian_set: {
|
||||
addresses: [
|
||||
{ bytes: [0xbe, 0xfa, 0x42, 0x9d, 0x57, 0xcd, 0x18, 0xb7, 0xf8, 0xa4, 0xd9, 0x1a, 0x2d, 0xa9, 0xab, 0x4a, 0xf0, 0x5d, 0x0f, 0xbe] }
|
||||
{ bytes: Buffer.from('beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe', 'hex').toString('base64') }
|
||||
],
|
||||
expiration_time: 1000 * 60 * 60
|
||||
},
|
||||
|
|
|
@ -8,7 +8,7 @@ async function script() {
|
|||
|
||||
// Test VAA built using bridge/cmd/vaa-test
|
||||
let vaaResult = await execute_contract(wormhole_contract, {submit_v_a_a: {
|
||||
vaa: [...Buffer.from('010000000001005468beb21caff68710b2af2d60a986245bf85099509b6babe990a6c32456b44b3e2e9493e3056b7d5892957e14beab24be02dab77ed6c8915000e4a1267f78f400000007d01000000038018002010400000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101000000000000000000000000010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e9988080000000000000000000000000000000000000000000000000de0b6b3a7640000', 'hex')]
|
||||
vaa: Buffer.from('010000000001001063f503dd308134e0f158537f54c5799719f4fa2687dd276c72ef60ae0c82c47d4fb560545afaabdf60c15918e221763fd1892c75f2098c0ffd5db4af254a4501000007d01000000038010302010400000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101000000000000000000000000010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e9988080000000000000000000000000000000000000000000000000de0b6b3a7640000', 'hex').toString('base64')
|
||||
}});
|
||||
if (vaaResult == null) return;
|
||||
console.log('Vaa submitted');
|
||||
|
|
Loading…
Reference in New Issue