Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support cosmos contract byte lengths other than 32 #3147

Merged
merged 13 commits into from
Jan 23, 2024
Merged
39 changes: 31 additions & 8 deletions rust/chains/hyperlane-cosmos/src/libs/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,21 @@ impl CosmosAddress {
///
/// - digest: H256 digest (hex representation of address)
/// - prefix: Bech32 prefix
pub fn from_h256(digest: H256, prefix: &str) -> ChainResult<Self> {
/// - byte_count: Number of bytes to truncate the digest to. Cosmos addresses can sometimes
/// be less than 32 bytes, so this helps to serialize it in bech32 with the appropriate
/// length.
pub fn from_h256(digest: H256, prefix: &str, byte_count: usize) -> ChainResult<Self> {
// This is the hex-encoded version of the address
let bytes = digest.as_bytes();
let untruncated_bytes = digest.as_bytes();

if byte_count > untruncated_bytes.len() {
return Err(Overflow.into());
}

let remainder_bytes_start = untruncated_bytes.len() - byte_count;
// Left-truncate the digest to the desired length
let bytes = &untruncated_bytes[remainder_bytes_start..];

// Bech32 encode it
let account_id =
AccountId::new(prefix, bytes).map_err(Into::<HyperlaneCosmosError>::into)?;
Expand Down Expand Up @@ -132,22 +144,33 @@ pub mod test {
addr.address(),
"neutron1kknekjxg0ear00dky5ykzs8wwp2gz62z9s6aaj"
);
// TODO: watch out for this edge case. This check will fail unless
// the first 12 bytes are removed from the digest.
// let digest = addr.digest();
// let addr2 = CosmosAddress::from_h256(digest, prefix).expect("Cosmos address creation failed");
// assert_eq!(addr.address(), addr2.address());

// Create an address with the same digest & explicitly set the byte count to 20,
// which should have the same result as the above.
let digest = addr.digest();
let addr2 =
CosmosAddress::from_h256(digest, prefix, 20).expect("Cosmos address creation failed");
assert_eq!(addr.address(), addr2.address());
}

#[test]
fn test_bech32_encode_from_h256() {
let hex_key = "0x1b16866227825a5166eb44031cdcf6568b3e80b52f2806e01b89a34dc90ae616";
let key = hex_or_base58_to_h256(hex_key).unwrap();
let prefix = "dual";
let addr = CosmosAddress::from_h256(key, prefix).expect("Cosmos address creation failed");
let addr =
CosmosAddress::from_h256(key, prefix, 32).expect("Cosmos address creation failed");
assert_eq!(
addr.address(),
"dual1rvtgvc38sfd9zehtgsp3eh8k269naq949u5qdcqm3x35mjg2uctqfdn3yq"
);

// Last 20 bytes only, which is 0x1cdcf6568b3e80b52f2806e01b89a34dc90ae616
let addr =
CosmosAddress::from_h256(key, prefix, 20).expect("Cosmos address creation failed");
assert_eq!(
addr.address(),
"dual1rnw0v45t86qt2tegqmsphzdrfhys4esk9ktul7"
);
}
}
15 changes: 12 additions & 3 deletions rust/chains/hyperlane-cosmos/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ impl CosmosMailbox {
}

/// Prefix used in the bech32 address encoding
pub fn prefix(&self) -> String {
self.config.get_prefix()
pub fn bech32_prefix(&self) -> String {
self.config.get_bech32_prefix()
}

fn contract_address_bytes(&self) -> usize {
self.config.get_contract_address_bytes()
}
}

Expand Down Expand Up @@ -151,7 +155,12 @@ impl Mailbox for CosmosMailbox {

#[instrument(err, ret, skip(self))]
async fn recipient_ism(&self, recipient: H256) -> ChainResult<H256> {
let address = CosmosAddress::from_h256(recipient, &self.prefix())?.address();
let address = CosmosAddress::from_h256(
recipient,
&self.bech32_prefix(),
self.contract_address_bytes(),
)?
.address();

let payload = mailbox::RecipientIsmRequest {
recipient_ism: mailbox::RecipientIsmRequestInner {
Expand Down
8 changes: 7 additions & 1 deletion rust/chains/hyperlane-cosmos/src/providers/grpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,13 @@ impl WasmGrpcProvider {
Endpoint::new(conf.get_grpc_url()).map_err(Into::<HyperlaneCosmosError>::into)?;
let channel = endpoint.connect_lazy();
let contract_address = locator
.map(|l| CosmosAddress::from_h256(l.address, &conf.get_prefix()))
.map(|l| {
CosmosAddress::from_h256(
l.address,
&conf.get_bech32_prefix(),
conf.get_contract_address_bytes(),
)
})
.transpose()?;

Ok(Self {
Expand Down
3 changes: 2 additions & 1 deletion rust/chains/hyperlane-cosmos/src/providers/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ impl CosmosWasmIndexer {
provider,
contract_address: CosmosAddress::from_h256(
locator.address,
conf.get_prefix().as_str(),
conf.get_bech32_prefix().as_str(),
conf.get_contract_address_bytes(),
)?,
target_event_kind: format!("{}-{}", Self::WASM_TYPE, event_type),
reorg_period,
Expand Down
25 changes: 18 additions & 7 deletions rust/chains/hyperlane-cosmos/src/trait_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ pub struct ConnectionConf {
rpc_url: String,
/// The chain ID
chain_id: String,
/// The prefix for the account address
prefix: String,
/// The human readable address prefix for the chains using bech32.
bech32_prefix: String,
/// Canoncial Assets Denom
canonical_asset: String,
/// The gas price set by the cosmos-sdk validator. Note that this represents the
/// minimum price set by the validator.
/// More details here: https://docs.cosmos.network/main/learn/beginner/gas-fees#antehandler
gas_price: RawCosmosAmount,
/// The number of bytes used to represent a contract address.
/// Cosmos address lengths are sometimes less than 32 bytes, so this helps to serialize it in
/// bech32 with the appropriate length.
contract_address_bytes: usize,
}

/// Untyped cosmos amount
Expand Down Expand Up @@ -86,9 +90,9 @@ impl ConnectionConf {
self.chain_id.clone()
}

/// Get the prefix
pub fn get_prefix(&self) -> String {
self.prefix.clone()
/// Get the bech32 prefix
pub fn get_bech32_prefix(&self) -> String {
self.bech32_prefix.clone()
}

/// Get the asset
Expand All @@ -101,22 +105,29 @@ impl ConnectionConf {
self.gas_price.clone()
}

/// Get the number of bytes used to represent a contract address
pub fn get_contract_address_bytes(&self) -> usize {
self.contract_address_bytes
}

/// Create a new connection configuration
pub fn new(
grpc_url: String,
rpc_url: String,
chain_id: String,
prefix: String,
bech32_prefix: String,
canonical_asset: String,
minimum_gas_price: RawCosmosAmount,
contract_address_bytes: usize,
) -> Self {
Self {
grpc_url,
rpc_url,
chain_id,
prefix,
bech32_prefix,
canonical_asset,
gas_price: minimum_gas_price,
contract_address_bytes,
}
}
}
3 changes: 2 additions & 1 deletion rust/config/mainnet3_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -431,11 +431,12 @@
],
"grpcUrl": "https://grpc-kralum.neutron-1.neutron.org:80",
"canonicalAsset": "untrn",
"prefix": "neutron",
"bech32Prefix": "neutron",
"gasPrice": {
"amount": "0.57",
"denom": "untrn"
},
"contractAddressBytes": 32,
"index": {
"from": 4000000,
"chunk": 100000
Expand Down
14 changes: 12 additions & 2 deletions rust/hyperlane-base/src/settings/parser/connection_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,14 @@ pub fn build_cosmos_connection_conf(

let prefix = chain
.chain(err)
.get_key("prefix")
.get_key("bech32Prefix")
.parse_string()
.end()
.or_else(|| {
local_err.push(&chain.cwp + "prefix", eyre!("Missing prefix for chain"));
local_err.push(
&chain.cwp + "bech32Prefix",
eyre!("Missing bech32 prefix for chain"),
);
None
});

Expand All @@ -100,6 +103,12 @@ pub fn build_cosmos_connection_conf(
.and_then(parse_cosmos_gas_price)
.end();

let contract_address_bytes = chain
.chain(err)
.get_opt_key("contractAddressBytes")
.parse_u64()
.end();

if !local_err.is_ok() {
err.merge(local_err);
None
Expand All @@ -111,6 +120,7 @@ pub fn build_cosmos_connection_conf(
prefix.unwrap().to_string(),
canonical_asset.unwrap(),
gas_price.unwrap(),
contract_address_bytes.unwrap().try_into().unwrap(),
)))
}
}
Expand Down
10 changes: 5 additions & 5 deletions rust/utils/run-locally/src/cosmos/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub struct IGPOracleInstantiateMsg {
#[cw_serde]
pub struct EmptyMsg {}

const PREFIX: &str = "osmo";
const BECH32_PREFIX: &str = "osmo";

#[apply(as_task)]
pub fn deploy_cw_hyperlane(
Expand All @@ -46,7 +46,7 @@ pub fn deploy_cw_hyperlane(
codes.hpl_mailbox,
core::mailbox::InstantiateMsg {
owner: deployer_addr.to_string(),
hrp: PREFIX.to_string(),
hrp: BECH32_PREFIX.to_string(),
domain,
},
"hpl_mailbox",
Expand All @@ -68,7 +68,7 @@ pub fn deploy_cw_hyperlane(
Some(deployer_addr),
codes.hpl_igp,
GasOracleInitMsg {
hrp: PREFIX.to_string(),
hrp: BECH32_PREFIX.to_string(),
owner: deployer_addr.clone(),
gas_token: "uosmo".to_string(),
beneficiary: deployer_addr.clone(),
Expand Down Expand Up @@ -159,7 +159,7 @@ pub fn deploy_cw_hyperlane(
Some(deployer_addr),
codes.hpl_validator_announce,
core::va::InstantiateMsg {
hrp: PREFIX.to_string(),
hrp: BECH32_PREFIX.to_string(),
mailbox: mailbox.to_string(),
},
"hpl_validator_announce",
Expand All @@ -173,7 +173,7 @@ pub fn deploy_cw_hyperlane(
Some(deployer_addr),
codes.hpl_test_mock_msg_receiver,
TestMockMsgReceiverInstantiateMsg {
hrp: PREFIX.to_string(),
hrp: BECH32_PREFIX.to_string(),
},
"hpl_test_mock_msg_receiver",
);
Expand Down
6 changes: 4 additions & 2 deletions rust/utils/run-locally/src/cosmos/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,11 @@ pub struct AgentConfig {
pub chain_id: String,
pub rpc_urls: Vec<AgentUrl>,
pub grpc_url: String,
pub prefix: String,
pub bech32_prefix: String,
pub signer: AgentConfigSigner,
pub index: AgentConfigIndex,
pub gas_price: RawCosmosAmount,
pub contract_address_bytes: usize,
}

#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
Expand Down Expand Up @@ -156,7 +157,7 @@ impl AgentConfig {
),
}],
grpc_url: format!("http://{}", network.launch_resp.endpoint.grpc_addr),
prefix: "osmo".to_string(),
bech32_prefix: "osmo".to_string(),
signer: AgentConfigSigner {
typ: "cosmosKey".to_string(),
key: format!("0x{}", hex::encode(validator.priv_key.to_bytes())),
Expand All @@ -166,6 +167,7 @@ impl AgentConfig {
denom: "uosmo".to_string(),
amount: "0.05".to_string(),
},
contract_address_bytes: 20,
index: AgentConfigIndex {
from: 1,
chunk: 100,
Expand Down
2 changes: 1 addition & 1 deletion solidity/test/message.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { TestMessage, TestMessage__factory } from '../types';

const remoteDomain = 1000;
const localDomain = 2000;
const version = 0;
const version = 3;
tkporter marked this conversation as resolved.
Show resolved Hide resolved
const nonce = 11;

describe('Message', async () => {
Expand Down
Loading
Loading