Add Cosmos support to Utils and SDK (#2859)

Co-authored-by: J M Rossy <jm.rossy@gmail.com>
Co-authored-by: Nam Chu Hoai <nambrot@googlemail.com>
Co-authored-by: Kunal Arora <55632507+aroralanuk@users.noreply.github.com>
pull/2896/head
Yorke Rhodes 1 year ago committed by GitHub
parent 34afc967e8
commit 4c49f6179a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .gitattributes
  2. 4
      solidity/package.json
  3. 6
      typescript/helloworld/package.json
  4. 11
      typescript/infra/config/environments/mainnet3/liquidityLayer.ts
  5. 8
      typescript/infra/config/environments/mainnet3/token-bridge.ts
  6. 27
      typescript/infra/config/environments/testnet4/liquidityLayer.ts
  7. 27
      typescript/infra/config/environments/testnet4/token-bridge.ts
  8. 4
      typescript/infra/helm/warp-routes/templates/_helpers.tpl
  9. 6
      typescript/infra/package.json
  10. 6
      typescript/infra/scripts/warp-routes/deploy-warp-monitor.ts
  11. 12
      typescript/infra/scripts/warp-routes/helm.ts
  12. 108
      typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts
  13. 9
      typescript/infra/src/config/agent/relayer.ts
  14. 55
      typescript/infra/src/config/grafana_token_config.ts
  15. 9
      typescript/sdk/package.json
  16. 2
      typescript/sdk/src/app/MultiProtocolApp.test.ts
  17. 18
      typescript/sdk/src/app/MultiProtocolApp.ts
  18. 64
      typescript/sdk/src/consts/chainMetadata.ts
  19. 4
      typescript/sdk/src/consts/chains.ts
  20. 2
      typescript/sdk/src/core/MultiProtocolCore.ts
  21. 184
      typescript/sdk/src/core/adapters/CosmWasmCoreAdapter.ts
  22. 142
      typescript/sdk/src/core/adapters/CosmWasmIgpAdapter.ts
  23. 228
      typescript/sdk/src/cw-types/Cw20Base.types.ts
  24. 92
      typescript/sdk/src/cw-types/HookAggregate.types.ts
  25. 180
      typescript/sdk/src/cw-types/HookMerkle.types.ts
  26. 97
      typescript/sdk/src/cw-types/HookPausable.types.ts
  27. 127
      typescript/sdk/src/cw-types/HookRouting.types.ts
  28. 174
      typescript/sdk/src/cw-types/HookRoutingCustom.types.ts
  29. 132
      typescript/sdk/src/cw-types/HookRoutingFallback.types.ts
  30. 215
      typescript/sdk/src/cw-types/Igp.types.ts
  31. 71
      typescript/sdk/src/cw-types/IgpOracle.types.ts
  32. 97
      typescript/sdk/src/cw-types/IsmAggregate.types.ts
  33. 127
      typescript/sdk/src/cw-types/IsmMultisig.types.ts
  34. 102
      typescript/sdk/src/cw-types/IsmRouting.types.ts
  35. 154
      typescript/sdk/src/cw-types/Mailbox.types.ts
  36. 33
      typescript/sdk/src/cw-types/ValidatorAnnounce.types.ts
  37. 256
      typescript/sdk/src/cw-types/WarpCw20.types.ts
  38. 232
      typescript/sdk/src/cw-types/WarpNative.types.ts
  39. 19
      typescript/sdk/src/index.ts
  40. 122
      typescript/sdk/src/ism/adapters/CosmWasmMultisigAdapter.ts
  41. 31
      typescript/sdk/src/metadata/ChainMetadataManager.ts
  42. 4
      typescript/sdk/src/metadata/agentConfig.ts
  43. 25
      typescript/sdk/src/metadata/chainMetadata.test.ts
  44. 65
      typescript/sdk/src/metadata/chainMetadataTypes.ts
  45. 66
      typescript/sdk/src/providers/MultiProtocolProvider.ts
  46. 78
      typescript/sdk/src/providers/ProviderType.ts
  47. 29
      typescript/sdk/src/providers/providerBuilders.ts
  48. 1
      typescript/sdk/src/router/MultiProtocolRouterApps.ts
  49. 398
      typescript/sdk/src/token/adapters/CosmWasmTokenAdapter.test.ts
  50. 409
      typescript/sdk/src/token/adapters/CosmWasmTokenAdapter.ts
  51. 65
      typescript/sdk/src/token/adapters/CosmosTokenAdapter.ts
  52. 2
      typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts
  53. 13
      typescript/sdk/src/utils/wagmi.ts
  54. 9
      typescript/utils/index.ts
  55. 3
      typescript/utils/package.json
  56. 165
      typescript/utils/src/addresses.ts
  57. 2
      typescript/utils/src/types.ts
  58. 422
      yarn.lock

2
.gitattributes vendored

@ -0,0 +1,2 @@
typescript/sdk/src/cw-types/*.types.ts linguist-generated=true
rust/chains/hyperlane-ethereum/abis/*.abi.json linguist-generated=true

@ -1,10 +1,10 @@
{ {
"name": "@hyperlane-xyz/core", "name": "@hyperlane-xyz/core",
"description": "Core solidity contracts for Hyperlane", "description": "Core solidity contracts for Hyperlane",
"version": "1.5.4-beta0", "version": "3.1.0-beta0",
"dependencies": { "dependencies": {
"@eth-optimism/contracts": "^0.6.0", "@eth-optimism/contracts": "^0.6.0",
"@hyperlane-xyz/utils": "1.5.4-beta0", "@hyperlane-xyz/utils": "3.1.0-beta0",
"@openzeppelin/contracts": "^4.8.0", "@openzeppelin/contracts": "^4.8.0",
"@openzeppelin/contracts-upgradeable": "^4.8.0" "@openzeppelin/contracts-upgradeable": "^4.8.0"
}, },

@ -1,10 +1,10 @@
{ {
"name": "@hyperlane-xyz/helloworld", "name": "@hyperlane-xyz/helloworld",
"description": "A basic skeleton of an Hyperlane app", "description": "A basic skeleton of an Hyperlane app",
"version": "1.5.4-beta0", "version": "3.1.0-beta0",
"dependencies": { "dependencies": {
"@hyperlane-xyz/core": "1.5.4-beta0", "@hyperlane-xyz/core": "3.1.0-beta0",
"@hyperlane-xyz/sdk": "1.5.4-beta0", "@hyperlane-xyz/sdk": "3.1.0-beta0",
"@openzeppelin/contracts-upgradeable": "^4.8.0", "@openzeppelin/contracts-upgradeable": "^4.8.0",
"ethers": "^5.7.2" "ethers": "^5.7.2"
}, },

@ -5,6 +5,7 @@ import {
Chains, Chains,
RpcConsensusType, RpcConsensusType,
chainMetadata, chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
import { LiquidityLayerRelayerConfig } from '../../../src/config/middleware'; import { LiquidityLayerRelayerConfig } from '../../../src/config/middleware';
@ -12,8 +13,14 @@ import { LiquidityLayerRelayerConfig } from '../../../src/config/middleware';
import { environment } from './chains'; import { environment } from './chains';
const circleDomainMapping = [ const circleDomainMapping = [
{ hyperlaneDomain: chainMetadata[Chains.ethereum].chainId, circleDomain: 0 }, {
{ hyperlaneDomain: chainMetadata[Chains.avalanche].chainId, circleDomain: 1 }, hyperlaneDomain: getDomainId(chainMetadata[Chains.ethereum]),
circleDomain: 0,
},
{
hyperlaneDomain: getDomainId(chainMetadata[Chains.avalanche]),
circleDomain: 1,
},
]; ];
export const bridgeAdapterConfigs: ChainMap<BridgeAdapterConfig> = { export const bridgeAdapterConfigs: ChainMap<BridgeAdapterConfig> = {

@ -4,11 +4,15 @@ import {
Chains, Chains,
CircleBridgeAdapterConfig, CircleBridgeAdapterConfig,
chainMetadata, chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
const circleDomainMapping = [ const circleDomainMapping = [
{ hyperlaneDomain: chainMetadata[Chains.goerli].chainId, circleDomain: 0 }, {
{ hyperlaneDomain: chainMetadata[Chains.fuji].chainId, circleDomain: 1 }, hyperlaneDomain: getDomainId(chainMetadata[Chains.goerli]),
circleDomain: 0,
},
{ hyperlaneDomain: getDomainId(chainMetadata[Chains.fuji]), circleDomain: 1 },
]; ];
// Circle deployed contracts // Circle deployed contracts

@ -4,23 +4,36 @@ import {
ChainMap, ChainMap,
Chains, Chains,
chainMetadata, chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
const circleDomainMapping = [ const circleDomainMapping = [
{ hyperlaneDomain: chainMetadata[Chains.goerli].chainId, circleDomain: 0 }, {
{ hyperlaneDomain: chainMetadata[Chains.fuji].chainId, circleDomain: 1 }, hyperlaneDomain: getDomainId(chainMetadata[Chains.goerli]),
circleDomain: 0,
},
{ hyperlaneDomain: getDomainId(chainMetadata[Chains.fuji]), circleDomain: 1 },
]; ];
const wormholeDomainMapping = [ const wormholeDomainMapping = [
{ hyperlaneDomain: chainMetadata[Chains.goerli].chainId, wormholeDomain: 2 },
{ hyperlaneDomain: chainMetadata[Chains.fuji].chainId, wormholeDomain: 6 },
{ hyperlaneDomain: chainMetadata[Chains.mumbai].chainId, wormholeDomain: 5 },
{ {
hyperlaneDomain: chainMetadata[Chains.bsctestnet].chainId, hyperlaneDomain: getDomainId(chainMetadata[Chains.goerli]),
wormholeDomain: 2,
},
{
hyperlaneDomain: getDomainId(chainMetadata[Chains.fuji]),
wormholeDomain: 6,
},
{
hyperlaneDomain: getDomainId(chainMetadata[Chains.mumbai]),
wormholeDomain: 5,
},
{
hyperlaneDomain: getDomainId(chainMetadata[Chains.bsctestnet]),
wormholeDomain: 4, wormholeDomain: 4,
}, },
{ {
hyperlaneDomain: chainMetadata[Chains.alfajores].chainId, hyperlaneDomain: getDomainId(chainMetadata[Chains.alfajores]),
wormholeDomain: 14, wormholeDomain: 14,
}, },
]; ];

@ -4,23 +4,36 @@ import {
ChainMap, ChainMap,
Chains, Chains,
chainMetadata, chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
const circleDomainMapping = [ const circleDomainMapping = [
{ hyperlaneDomain: chainMetadata[Chains.goerli].chainId, circleDomain: 0 }, {
{ hyperlaneDomain: chainMetadata[Chains.fuji].chainId, circleDomain: 1 }, hyperlaneDomain: getDomainId(chainMetadata[Chains.goerli]),
circleDomain: 0,
},
{ hyperlaneDomain: getDomainId(chainMetadata[Chains.fuji]), circleDomain: 1 },
]; ];
const wormholeDomainMapping = [ const wormholeDomainMapping = [
{ hyperlaneDomain: chainMetadata[Chains.goerli].chainId, wormholeDomain: 2 },
{ hyperlaneDomain: chainMetadata[Chains.fuji].chainId, wormholeDomain: 6 },
{ hyperlaneDomain: chainMetadata[Chains.mumbai].chainId, wormholeDomain: 5 },
{ {
hyperlaneDomain: chainMetadata[Chains.bsctestnet].chainId, hyperlaneDomain: getDomainId(chainMetadata[Chains.goerli]),
wormholeDomain: 2,
},
{
hyperlaneDomain: getDomainId(chainMetadata[Chains.fuji]),
wormholeDomain: 6,
},
{
hyperlaneDomain: getDomainId(chainMetadata[Chains.mumbai]),
wormholeDomain: 5,
},
{
hyperlaneDomain: getDomainId(chainMetadata[Chains.bsctestnet]),
wormholeDomain: 4, wormholeDomain: 4,
}, },
{ {
hyperlaneDomain: chainMetadata[Chains.alfajores].chainId, hyperlaneDomain: getDomainId(chainMetadata[Chains.alfajores]),
wormholeDomain: 14, wormholeDomain: 14,
}, },
]; ];

@ -61,6 +61,8 @@ The warp-routes container
command: command:
- ./node_modules/.bin/ts-node - ./node_modules/.bin/ts-node
- ./typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts - ./typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts
- -c - -l
- "10000" - "10000"
- -c
- {{ .Values.config }}
{{- end }} {{- end }}

@ -11,9 +11,9 @@
"@ethersproject/experimental": "^5.7.0", "@ethersproject/experimental": "^5.7.0",
"@ethersproject/hardware-wallets": "^5.7.0", "@ethersproject/hardware-wallets": "^5.7.0",
"@ethersproject/providers": "^5.7.2", "@ethersproject/providers": "^5.7.2",
"@hyperlane-xyz/helloworld": "1.5.4-beta0", "@hyperlane-xyz/helloworld": "3.1.0-beta0",
"@hyperlane-xyz/sdk": "1.5.4-beta0", "@hyperlane-xyz/sdk": "3.1.0-beta0",
"@hyperlane-xyz/utils": "1.5.4-beta0", "@hyperlane-xyz/utils": "3.1.0-beta0",
"@nomiclabs/hardhat-etherscan": "^3.0.3", "@nomiclabs/hardhat-etherscan": "^3.0.3",
"@safe-global/api-kit": "^1.3.0", "@safe-global/api-kit": "^1.3.0",
"@safe-global/protocol-kit": "^1.2.0", "@safe-global/protocol-kit": "^1.2.0",

@ -3,7 +3,11 @@ import { HelmCommand } from '../../src/utils/helm';
import { runWarpRouteHelmCommand } from './helm'; import { runWarpRouteHelmCommand } from './helm';
async function main() { async function main() {
await runWarpRouteHelmCommand(HelmCommand.InstallOrUpgrade, 'mainnet3'); await runWarpRouteHelmCommand(
HelmCommand.InstallOrUpgrade,
'mainnet3',
'neutron',
);
} }
main() main()

@ -6,17 +6,18 @@ import { assertCorrectKubeContext, getEnvironmentConfig } from '../utils';
export async function runWarpRouteHelmCommand( export async function runWarpRouteHelmCommand(
helmCommand: HelmCommand, helmCommand: HelmCommand,
runEnv: DeployEnvironment, runEnv: DeployEnvironment,
config: string,
) { ) {
const envConfig = getEnvironmentConfig(runEnv); const envConfig = getEnvironmentConfig(runEnv);
await assertCorrectKubeContext(envConfig); await assertCorrectKubeContext(envConfig);
const values = getWarpRoutesHelmValues(); const values = getWarpRoutesHelmValues(config);
return execCmd( return execCmd(
`helm ${helmCommand} ${getHelmReleaseName( `helm ${helmCommand} ${getHelmReleaseName(
'zebec', config,
)} ./helm/warp-routes --namespace ${runEnv} ${values.join( )} ./helm/warp-routes --namespace ${runEnv} ${values.join(
' ', ' ',
)} --set fullnameOverride="${getHelmReleaseName('zebec')}"`, )} --set fullnameOverride="${getHelmReleaseName(config)}"`,
); );
} }
@ -24,12 +25,13 @@ function getHelmReleaseName(route: string): string {
return `hyperlane-warp-route-${route}`; return `hyperlane-warp-route-${route}`;
} }
function getWarpRoutesHelmValues() { function getWarpRoutesHelmValues(config: string) {
const values = { const values = {
image: { image: {
repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo', repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: '962d34b-20230905-194531', tag: 'ae8ce44-20231101-012032',
}, },
config: config, // nautilus or neutron
}; };
return helmifyValues(values); return helmifyValues(values);
} }

@ -7,8 +7,8 @@ import { ERC20__factory } from '@hyperlane-xyz/core';
import { import {
ChainMap, ChainMap,
ChainName, ChainName,
CwNativeTokenAdapter,
MultiProtocolProvider, MultiProtocolProvider,
MultiProvider,
SealevelHypCollateralAdapter, SealevelHypCollateralAdapter,
TokenType, TokenType,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
@ -21,8 +21,9 @@ import {
import { import {
WarpTokenConfig, WarpTokenConfig,
tokenList, nautilusList,
} from '../../src/config/nautilus_token_config'; neutronList,
} from '../../src/config/grafana_token_config';
import { startMetricsServer } from '../../src/utils/metrics'; import { startMetricsServer } from '../../src/utils/metrics';
const metricsRegister = new Registry(); const metricsRegister = new Registry();
@ -40,21 +41,29 @@ const warpRouteTokenBalance = new Gauge({
}); });
async function main(): Promise<boolean> { async function main(): Promise<boolean> {
const { checkFrequency } = await yargs(process.argv.slice(2)) const { checkFrequency, config } = await yargs(process.argv.slice(2))
.describe('checkFrequency', 'frequency to check balances in ms') .describe('checkFrequency', 'frequency to check balances in ms')
.demandOption('checkFrequency') .demandOption('checkFrequency')
.alias('c', 'checkFrequency') .alias('l', 'checkFrequency')
.number('checkFrequency') .number('checkFrequency')
.alias('c', 'config')
.describe('config', 'choose warp token config')
.demandOption('config')
.choices('config', ['neutron', 'nautilus'])
.parse(); .parse();
const tokenList: WarpTokenConfig =
config === 'neutron' ? neutronList : nautilusList;
startMetricsServer(metricsRegister); startMetricsServer(metricsRegister);
const multiProvider = new MultiProvider(); console.log('Starting Warp Route balance monitor');
const multiProtocolProvider = new MultiProtocolProvider();
setInterval(async () => { setInterval(async () => {
try { try {
console.log('Checking balances'); debug('Checking balances');
const balances = await checkBalance(tokenList, multiProvider); const balances = await checkBalance(tokenList, multiProtocolProvider);
updateTokenBalanceMetrics(tokenList, balances); updateTokenBalanceMetrics(tokenList, balances);
} catch (e) { } catch (e) {
console.error('Error checking balances', e); console.error('Error checking balances', e);
@ -66,27 +75,40 @@ async function main(): Promise<boolean> {
// TODO: see issue https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/2708 // TODO: see issue https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/2708
async function checkBalance( async function checkBalance(
tokenConfig: WarpTokenConfig, tokenConfig: WarpTokenConfig,
multiprovider: MultiProvider, multiProtocolProvider: MultiProtocolProvider,
): Promise<ChainMap<number>> { ): Promise<ChainMap<number>> {
const output: ChainMap<Promise<number>> = objMap( const output: ChainMap<Promise<number>> = objMap(
tokenConfig, tokenConfig,
async (chain: ChainName, token: WarpTokenConfig[ChainName]) => { async (chain: ChainName, token: WarpTokenConfig[ChainName]) => {
const provider = multiprovider.getProvider(chain); switch (token.type) {
if (token.type === TokenType.native) { case TokenType.native: {
if (token.protocolType === ProtocolType.Ethereum) { switch (token.protocolType) {
case ProtocolType.Ethereum: {
const provider = multiProtocolProvider.getEthersV5Provider(chain);
const nativeBalance = await provider.getBalance( const nativeBalance = await provider.getBalance(
token.hypNativeAddress, token.hypNativeAddress,
); );
return parseFloat( return parseFloat(
ethers.utils.formatUnits(nativeBalance, token.decimals), ethers.utils.formatUnits(nativeBalance, token.decimals),
); );
} else { }
case ProtocolType.Sealevel:
// TODO - solana native // TODO - solana native
return 0; return 0;
case ProtocolType.Cosmos:
// TODO - cosmos native
return 0;
}
break;
} }
} else { case TokenType.collateral: {
if (token.protocolType === ProtocolType.Ethereum) { switch (token.protocolType) {
const tokenContract = ERC20__factory.connect(token.address, provider); case ProtocolType.Ethereum: {
const provider = multiProtocolProvider.getEthersV5Provider(chain);
const tokenContract = ERC20__factory.connect(
token.address,
provider,
);
const collateralBalance = await tokenContract.balanceOf( const collateralBalance = await tokenContract.balanceOf(
token.hypCollateralAddress, token.hypCollateralAddress,
); );
@ -94,10 +116,11 @@ async function checkBalance(
return parseFloat( return parseFloat(
ethers.utils.formatUnits(collateralBalance, token.decimals), ethers.utils.formatUnits(collateralBalance, token.decimals),
); );
} else { }
case ProtocolType.Sealevel: {
const adapter = new SealevelHypCollateralAdapter( const adapter = new SealevelHypCollateralAdapter(
chain, chain,
MultiProtocolProvider.fromMultiProvider(multiprovider), multiProtocolProvider,
{ {
token: token.address, token: token.address,
warpRouter: token.hypCollateralAddress, warpRouter: token.hypCollateralAddress,
@ -113,6 +136,47 @@ async function checkBalance(
ethers.utils.formatUnits(collateralBalance, token.decimals), ethers.utils.formatUnits(collateralBalance, token.decimals),
); );
} }
case ProtocolType.Cosmos: {
const adapter = new CwNativeTokenAdapter(
chain,
multiProtocolProvider,
{
token: token.address,
},
token.address,
);
const collateralBalance = ethers.BigNumber.from(
await adapter.getBalance(token.hypCollateralAddress),
);
return parseFloat(
ethers.utils.formatUnits(collateralBalance, token.decimals),
);
}
}
break;
}
case TokenType.synthetic: {
switch (token.protocolType) {
case ProtocolType.Ethereum: {
const provider = multiProtocolProvider.getEthersV5Provider(chain);
const tokenContract = ERC20__factory.connect(
token.hypSyntheticAddress,
provider,
);
const syntheticBalance = await tokenContract.totalSupply();
return parseFloat(
ethers.utils.formatUnits(syntheticBalance, token.decimals),
);
}
case ProtocolType.Sealevel:
// TODO - solana native
return 0;
case ProtocolType.Cosmos:
// TODO - cosmos native
return 0;
}
break;
}
} }
}, },
); );
@ -128,11 +192,15 @@ function updateTokenBalanceMetrics(
const tokenAddress = const tokenAddress =
token.type === TokenType.native token.type === TokenType.native
? ethers.constants.AddressZero ? ethers.constants.AddressZero
: token.address; : token.type === TokenType.collateral
? token.address
: token.hypSyntheticAddress;
const walletAddress = const walletAddress =
token.type === TokenType.native token.type === TokenType.native
? token.hypNativeAddress ? token.hypNativeAddress
: token.hypCollateralAddress; : token.type === TokenType.collateral
? token.hypCollateralAddress
: token.hypSyntheticAddress;
warpRouteTokenBalance warpRouteTokenBalance
.labels({ .labels({

@ -4,11 +4,12 @@ import {
AgentConfig, AgentConfig,
AgentSignerKeyType, AgentSignerKeyType,
ChainMap, ChainMap,
GasPaymentEnforcement,
MatchingList, MatchingList,
RelayerConfig as RelayerAgentConfig,
chainMetadata, chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
import { GasPaymentEnforcement } from '@hyperlane-xyz/sdk';
import { RelayerConfig as RelayerAgentConfig } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils'; import { ProtocolType } from '@hyperlane-xyz/utils';
import { AgentAwsUser } from '../../agents/aws'; import { AgentAwsUser } from '../../agents/aws';
@ -147,9 +148,9 @@ export function routerMatchingList(
} }
matchingList.push({ matchingList.push({
originDomain: chainMetadata[source].chainId, originDomain: getDomainId(chainMetadata[source]),
senderAddress: routers[source].router, senderAddress: routers[source].router,
destinationDomain: chainMetadata[destination].chainId, destinationDomain: getDomainId(chainMetadata[destination]),
recipientAddress: routers[destination].router, recipientAddress: routers[destination].router,
}); });
} }

@ -2,37 +2,53 @@ import { ChainMap, TokenType } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils'; import { ProtocolType } from '@hyperlane-xyz/utils';
interface NativeTokenConfig { interface NativeTokenConfig {
chainId: number;
symbol: string; symbol: string;
name: string; name: string;
type: TokenType.native; type: TokenType.native;
decimals: number; decimals: number;
hypNativeAddress: string; hypNativeAddress: string;
protocolType: ProtocolType.Ethereum | ProtocolType.Sealevel; protocolType:
| ProtocolType.Ethereum
| ProtocolType.Sealevel
| ProtocolType.Cosmos;
} }
interface CollateralTokenConfig { interface CollateralTokenConfig {
type: TokenType.collateral; type: TokenType.collateral;
address: string; address: string;
chainId: number;
decimals: number; decimals: number;
symbol: string; symbol: string;
name: string; name: string;
hypCollateralAddress: string; hypCollateralAddress: string;
isSpl2022?: boolean; isSpl2022?: boolean;
protocolType: ProtocolType.Ethereum | ProtocolType.Sealevel; protocolType:
| ProtocolType.Ethereum
| ProtocolType.Sealevel
| ProtocolType.Cosmos;
}
interface SyntheticTokenConfig {
type: TokenType.synthetic;
hypSyntheticAddress: string;
decimals: number;
symbol: string;
name: string;
protocolType:
| ProtocolType.Ethereum
| ProtocolType.Sealevel
| ProtocolType.Cosmos;
} }
// TODO: migrate and dedupe to SDK from infra and Warp UI // TODO: migrate and dedupe to SDK from infra and Warp UI
export type WarpTokenConfig = ChainMap< export type WarpTokenConfig = ChainMap<
CollateralTokenConfig | NativeTokenConfig CollateralTokenConfig | NativeTokenConfig | SyntheticTokenConfig
>; >;
export const tokenList: WarpTokenConfig = { /// nautilus configs
export const nautilusList: WarpTokenConfig = {
// bsc // bsc
bsc: { bsc: {
type: TokenType.collateral, type: TokenType.collateral,
chainId: 56,
address: '0x37a56cdcD83Dce2868f721De58cB3830C44C6303', address: '0x37a56cdcD83Dce2868f721De58cB3830C44C6303',
hypCollateralAddress: '0xC27980812E2E66491FD457D488509b7E04144b98', hypCollateralAddress: '0xC27980812E2E66491FD457D488509b7E04144b98',
symbol: 'ZBC', symbol: 'ZBC',
@ -44,7 +60,6 @@ export const tokenList: WarpTokenConfig = {
// nautilus // nautilus
nautilus: { nautilus: {
type: TokenType.native, type: TokenType.native,
chainId: 22222,
hypNativeAddress: '0x4501bBE6e731A4bC5c60C03A77435b2f6d5e9Fe7', hypNativeAddress: '0x4501bBE6e731A4bC5c60C03A77435b2f6d5e9Fe7',
symbol: 'ZBC', symbol: 'ZBC',
name: 'Zebec', name: 'Zebec',
@ -55,7 +70,6 @@ export const tokenList: WarpTokenConfig = {
// solana // solana
solana: { solana: {
type: TokenType.collateral, type: TokenType.collateral,
chainId: 1399811149,
address: 'wzbcJyhGhQDLTV1S99apZiiBdE4jmYfbw99saMMdP59', address: 'wzbcJyhGhQDLTV1S99apZiiBdE4jmYfbw99saMMdP59',
hypCollateralAddress: 'EJqwFjvVJSAxH8Ur2PYuMfdvoJeutjmH6GkoEFQ4MdSa', hypCollateralAddress: 'EJqwFjvVJSAxH8Ur2PYuMfdvoJeutjmH6GkoEFQ4MdSa',
name: 'Zebec', name: 'Zebec',
@ -65,3 +79,26 @@ export const tokenList: WarpTokenConfig = {
protocolType: ProtocolType.Sealevel, protocolType: ProtocolType.Sealevel,
}, },
}; };
/// neutron configs
export const neutronList: WarpTokenConfig = {
neutron: {
type: TokenType.collateral,
address:
'ibc/773B4D0A3CD667B2275D5A4A7A2F0909C0BA0F4059C0B9181E680DDF4965DCC7',
hypCollateralAddress:
'neutron1ch7x3xgpnj62weyes8vfada35zff6z59kt2psqhnx9gjnt2ttqdqtva3pa',
name: 'Celestia',
symbol: 'TIA',
decimals: 6,
protocolType: ProtocolType.Cosmos,
},
mantapacific: {
type: TokenType.synthetic,
hypSyntheticAddress: '0x6Fae4D9935E2fcb11fC79a64e917fb2BF14DaFaa',
name: 'Celestia',
symbol: 'TIA',
decimals: 6,
protocolType: ProtocolType.Ethereum,
},
};

@ -1,16 +1,19 @@
{ {
"name": "@hyperlane-xyz/sdk", "name": "@hyperlane-xyz/sdk",
"description": "The official SDK for the Hyperlane Network", "description": "The official SDK for the Hyperlane Network",
"version": "1.5.4-beta0", "version": "3.1.0-beta0",
"dependencies": { "dependencies": {
"@hyperlane-xyz/core": "1.5.4-beta0", "@cosmjs/cosmwasm-stargate": "^0.31.3",
"@hyperlane-xyz/utils": "1.5.4-beta0", "@cosmjs/stargate": "^0.31.3",
"@hyperlane-xyz/core": "3.1.0-beta0",
"@hyperlane-xyz/utils": "3.1.0-beta0",
"@solana/spl-token": "^0.3.8", "@solana/spl-token": "^0.3.8",
"@solana/web3.js": "^1.78.0", "@solana/web3.js": "^1.78.0",
"@types/coingecko-api": "^1.0.10", "@types/coingecko-api": "^1.0.10",
"@types/debug": "^4.1.7", "@types/debug": "^4.1.7",
"@wagmi/chains": "^0.2.6", "@wagmi/chains": "^0.2.6",
"coingecko-api": "^1.0.10", "coingecko-api": "^1.0.10",
"cosmjs-types": "^0.9.0",
"cross-fetch": "^3.1.5", "cross-fetch": "^3.1.5",
"debug": "^4.3.4", "debug": "^4.3.4",
"ethers": "^5.7.2", "ethers": "^5.7.2",

@ -7,6 +7,7 @@ import { MultiProtocolProvider } from '../providers/MultiProtocolProvider';
import { import {
BaseAppAdapter, BaseAppAdapter,
BaseCosmWasmAdapter,
BaseEvmAdapter, BaseEvmAdapter,
BaseSealevelAdapter, BaseSealevelAdapter,
MultiProtocolApp, MultiProtocolApp,
@ -16,6 +17,7 @@ class TestMultiProtocolApp extends MultiProtocolApp<BaseAppAdapter> {
override protocolToAdapter(protocol: ProtocolType) { override protocolToAdapter(protocol: ProtocolType) {
if (protocol === ProtocolType.Ethereum) return BaseEvmAdapter; if (protocol === ProtocolType.Ethereum) return BaseEvmAdapter;
if (protocol === ProtocolType.Sealevel) return BaseSealevelAdapter; if (protocol === ProtocolType.Sealevel) return BaseSealevelAdapter;
if (protocol === ProtocolType.Cosmos) return BaseCosmWasmAdapter;
throw new Error(`No adapter for protocol ${protocol}`); throw new Error(`No adapter for protocol ${protocol}`);
} }
} }

@ -11,6 +11,8 @@ import {
import { ChainMetadata } from '../metadata/chainMetadataTypes'; import { ChainMetadata } from '../metadata/chainMetadataTypes';
import { MultiProtocolProvider } from '../providers/MultiProtocolProvider'; import { MultiProtocolProvider } from '../providers/MultiProtocolProvider';
import { import {
CosmJsProvider,
CosmJsWasmProvider,
EthersV5Provider, EthersV5Provider,
SolanaWeb3Provider, SolanaWeb3Provider,
TypedProvider, TypedProvider,
@ -49,6 +51,22 @@ export class BaseEvmAdapter extends BaseAppAdapter {
} }
} }
export class BaseCosmWasmAdapter extends BaseAppAdapter {
public readonly protocol: ProtocolType = ProtocolType.Cosmos;
public getProvider(): CosmJsWasmProvider['provider'] {
return this.multiProvider.getCosmJsWasmProvider(this.chainName);
}
}
export class BaseCosmosAdapter extends BaseAppAdapter {
public readonly protocol: ProtocolType = ProtocolType.Cosmos;
public getProvider(): CosmJsProvider['provider'] {
return this.multiProvider.getCosmJsProvider(this.chainName);
}
}
export class BaseSealevelAdapter extends BaseAppAdapter { export class BaseSealevelAdapter extends BaseAppAdapter {
public readonly protocol: ProtocolType = ProtocolType.Sealevel; public readonly protocol: ProtocolType = ProtocolType.Sealevel;

@ -736,6 +736,35 @@ export const proteustestnet: ChainMetadata = {
}, },
}; };
export const mantapacific: ChainMetadata = {
chainId: 169,
domainId: 169,
name: Chains.mantapacific,
protocol: ProtocolType.Ethereum,
displayName: 'Manta Pacific',
displayNameShort: 'Manta',
nativeToken: {
name: 'Ether',
symbol: 'ETH',
decimals: 18,
},
blocks: {
confirmations: 1,
reorgPeriod: 0,
estimateBlockTime: 3,
},
blockExplorers: [
{
name: 'Manta Pacific Explorer',
url: 'https://pacific-explorer.manta.network/',
apiUrl: 'https://pacific-explorer.manta.network/api',
family: ExplorerFamily.Blockscout,
},
],
rpcUrls: [{ http: 'https://pacific-rpc.manta.network/http' }],
isTestnet: false,
};
export const nautilus: ChainMetadata = { export const nautilus: ChainMetadata = {
chainId: 22222, chainId: 22222,
domainId: 22222, domainId: 22222,
@ -759,6 +788,39 @@ export const nautilus: ChainMetadata = {
}, },
}; };
export const neutron: ChainMetadata = {
chainId: 'neutron-1',
domainId: 1853125230,
name: Chains.neutron,
protocol: ProtocolType.Cosmos,
displayName: 'Neutron',
bech32Prefix: 'neutron',
slip44: 118,
nativeToken: {
name: 'Neutron',
symbol: 'NTRN',
decimals: 6,
},
rpcUrls: [
{ http: 'https://rpc-kralum.neutron-1.neutron.org' },
{ http: 'grpc-kralum.neutron-1.neutron.org:80' },
],
blocks: {
confirmations: 1,
reorgPeriod: 0,
estimateBlockTime: 3,
},
blockExplorers: [
{
name: 'Mintscan',
url: 'https://www.mintscan.io/neutron',
apiUrl: 'https://www.mintscan.io/neutron',
family: ExplorerFamily.Other,
},
],
isTestnet: false,
};
/** /**
* Metadata for local test chains * Metadata for local test chains
*/ */
@ -967,9 +1029,11 @@ export const chainMetadata: ChainMap<ChainMetadata> = {
scroll, scroll,
scrollsepolia, scrollsepolia,
sepolia, sepolia,
mantapacific,
moonbasealpha, moonbasealpha,
moonbeam, moonbeam,
mumbai, mumbai,
neutron,
optimism, optimism,
optimismgoerli, optimismgoerli,
polygon, polygon,

@ -21,10 +21,12 @@ export enum Chains {
scroll = 'scroll', scroll = 'scroll',
scrollsepolia = 'scrollsepolia', scrollsepolia = 'scrollsepolia',
sepolia = 'sepolia', sepolia = 'sepolia',
mantapacific = 'mantapacific',
moonbasealpha = 'moonbasealpha', moonbasealpha = 'moonbasealpha',
moonbeam = 'moonbeam', moonbeam = 'moonbeam',
mumbai = 'mumbai', mumbai = 'mumbai',
nautilus = 'nautilus', nautilus = 'nautilus',
neutron = 'neutron',
optimism = 'optimism', optimism = 'optimism',
optimismgoerli = 'optimismgoerli', optimismgoerli = 'optimismgoerli',
polygon = 'polygon', polygon = 'polygon',
@ -57,6 +59,8 @@ export const Mainnets: Array<CoreChainName> = [
Chains.bsc, Chains.bsc,
Chains.celo, Chains.celo,
Chains.ethereum, Chains.ethereum,
Chains.neutron,
Chains.mantapacific,
Chains.moonbeam, Chains.moonbeam,
Chains.optimism, Chains.optimism,
Chains.polygon, Chains.polygon,

@ -11,6 +11,7 @@ import { MultiProtocolProvider } from '../providers/MultiProtocolProvider';
import { TypedTransactionReceipt } from '../providers/ProviderType'; import { TypedTransactionReceipt } from '../providers/ProviderType';
import { ChainMap, ChainName } from '../types'; import { ChainMap, ChainName } from '../types';
import { CosmWasmCoreAdapter } from './adapters/CosmWasmCoreAdapter';
import { EvmCoreAdapter } from './adapters/EvmCoreAdapter'; import { EvmCoreAdapter } from './adapters/EvmCoreAdapter';
import { SealevelCoreAdapter } from './adapters/SealevelCoreAdapter'; import { SealevelCoreAdapter } from './adapters/SealevelCoreAdapter';
import { ICoreAdapter } from './adapters/types'; import { ICoreAdapter } from './adapters/types';
@ -54,6 +55,7 @@ export class MultiProtocolCore extends MultiProtocolApp<
): AdapterClassType<ICoreAdapter> { ): AdapterClassType<ICoreAdapter> {
if (protocol === ProtocolType.Ethereum) return EvmCoreAdapter; if (protocol === ProtocolType.Ethereum) return EvmCoreAdapter;
if (protocol === ProtocolType.Sealevel) return SealevelCoreAdapter; if (protocol === ProtocolType.Sealevel) return SealevelCoreAdapter;
if (protocol === ProtocolType.Cosmos) return CosmWasmCoreAdapter;
throw new Error(`No adapter for protocol ${protocol}`); throw new Error(`No adapter for protocol ${protocol}`);
} }

@ -0,0 +1,184 @@
import { ExecuteInstruction } from '@cosmjs/cosmwasm-stargate';
import { Address, HexString } from '@hyperlane-xyz/utils';
import { BaseCosmWasmAdapter } from '../../app/MultiProtocolApp';
import {
Coin,
DefaultHookResponse,
DefaultIsmResponse,
ExecuteMsg,
LatestDispatchedIdResponse,
MessageDeliveredResponse,
NonceResponse,
OwnerResponse,
QueryMsg,
RequiredHookResponse,
} from '../../cw-types/Mailbox.types';
import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider';
import {
ProviderType,
TypedTransactionReceipt,
} from '../../providers/ProviderType';
import { ChainName } from '../../types';
import { ICoreAdapter } from './types';
type MailboxResponse =
| DefaultHookResponse
| RequiredHookResponse
| DefaultIsmResponse
| NonceResponse
| LatestDispatchedIdResponse
| OwnerResponse
| MessageDeliveredResponse;
export class CosmWasmCoreAdapter
extends BaseCosmWasmAdapter
implements ICoreAdapter
{
constructor(
public readonly chainName: ChainName,
public readonly multiProvider: MultiProtocolProvider<any>,
public readonly addresses: { mailbox: Address },
) {
super(chainName, multiProvider, addresses);
}
prepareMailbox(msg: ExecuteMsg, funds?: Coin[]): ExecuteInstruction {
return {
contractAddress: this.addresses.mailbox,
msg,
funds,
};
}
initTransferOwner(newOwner: Address): ExecuteInstruction {
return this.prepareMailbox({
ownable: {
init_ownership_transfer: {
next_owner: newOwner,
},
},
});
}
claimTransferOwner(): ExecuteInstruction {
return this.prepareMailbox({
ownable: {
claim_ownership: {},
},
});
}
setDefaultHook(address: Address): ExecuteInstruction {
return this.prepareMailbox({
set_default_hook: {
hook: address,
},
});
}
setRequiredHook(address: Address): ExecuteInstruction {
return this.prepareMailbox({
set_required_hook: {
hook: address,
},
});
}
async queryMailbox<R extends MailboxResponse>(msg: QueryMsg): Promise<R> {
const provider = await this.getProvider();
const response: R = await provider.queryContractSmart(
this.addresses.mailbox,
msg,
);
return response;
}
async defaultHook(): Promise<string> {
const response = await this.queryMailbox<DefaultHookResponse>({
mailbox: {
default_hook: {},
},
});
return response.default_hook;
}
async defaultIsm(): Promise<string> {
const response = await this.queryMailbox<DefaultIsmResponse>({
mailbox: {
default_ism: {},
},
});
return response.default_ism;
}
async requiredHook(): Promise<string> {
const response = await this.queryMailbox<RequiredHookResponse>({
mailbox: {
required_hook: {},
},
});
return response.required_hook;
}
async nonce(): Promise<number> {
const response = await this.queryMailbox<NonceResponse>({
mailbox: {
nonce: {},
},
});
return response.nonce;
}
async latestDispatchedId(): Promise<string> {
const response = await this.queryMailbox<LatestDispatchedIdResponse>({
mailbox: {
latest_dispatch_id: {},
},
});
return response.message_id;
}
async owner(): Promise<string> {
const response = await this.queryMailbox<OwnerResponse>({
ownable: {
get_owner: {},
},
});
return response.owner;
}
async delivered(id: string): Promise<boolean> {
const response = await this.queryMailbox<MessageDeliveredResponse>({
mailbox: {
message_delivered: {
id,
},
},
});
return response.delivered;
}
extractMessageIds(
sourceTx: TypedTransactionReceipt,
): Array<{ messageId: string; destination: ChainName }> {
if (sourceTx.type !== ProviderType.CosmJsWasm) {
throw new Error(
`Unsupported provider type for CosmosCoreAdapter ${sourceTx.type}`,
);
}
// TODO: parse mailbox logs and extract message ids
throw new Error('Method not implemented.');
}
async waitForMessageProcessed(
_messageId: HexString,
_destination: ChainName,
_delayMs?: number,
_maxAttempts?: number,
): Promise<void> {
throw new Error('Method not implemented.');
}
}

@ -0,0 +1,142 @@
import { ExecuteInstruction } from '@cosmjs/cosmwasm-stargate';
import { Address } from '@hyperlane-xyz/utils';
import { BaseCosmWasmAdapter } from '../../app/MultiProtocolApp';
import {
BeneficiaryResponse,
DefaultGasResponse,
DomainsResponse,
GetExchangeRateAndGasPriceResponse,
OwnerResponse,
QueryMsg,
QuoteGasPaymentResponse,
RouteResponseForAddr,
RoutesResponseForAddr,
} from '../../cw-types/Igp.types';
import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider';
import { ChainMap, ChainName } from '../../types';
// TODO: import more
type IgpResponse =
| OwnerResponse
| BeneficiaryResponse
| DomainsResponse
| GetExchangeRateAndGasPriceResponse
| RoutesResponseForAddr
| RouteResponseForAddr
| DefaultGasResponse
| QuoteGasPaymentResponse;
export class CosmWasmIgpAdapter extends BaseCosmWasmAdapter {
constructor(
public readonly chainName: ChainName,
public readonly multiProvider: MultiProtocolProvider<any>,
public readonly addresses: { igp: Address },
) {
super(chainName, multiProvider, addresses);
}
async queryIgp<R extends IgpResponse>(msg: QueryMsg): Promise<R> {
const provider = await this.getProvider();
const response: R = await provider.queryContractSmart(
this.addresses.igp,
msg,
);
return response;
}
async owner(): Promise<string> {
const response = await this.queryIgp<OwnerResponse>({
ownable: {
get_owner: {},
},
});
return response.owner;
}
async beneficiary(): Promise<string> {
const beneficiaryResponse: BeneficiaryResponse = await this.queryIgp({
igp: {
beneficiary: {},
},
});
return beneficiaryResponse.beneficiary;
}
async getOracles(): Promise<ChainMap<Address>> {
const domainResponse: RoutesResponseForAddr = await this.queryIgp({
router: {
list_routes: {},
},
});
return Object.fromEntries(
domainResponse.routes.map((_) => [
this.multiProvider.getChainName(_.domain),
_.route ?? '',
]),
);
}
async defaultGas(): Promise<number> {
const defaultGas = await this.queryIgp<DefaultGasResponse>({
igp: {
default_gas: {},
},
});
return defaultGas.gas;
}
async getOracleData(
chain: ChainName,
): Promise<GetExchangeRateAndGasPriceResponse> {
const provider = await this.getProvider();
const domain = this.multiProvider.getDomainId(chain);
const oracles = await this.getOracles();
const oracle = oracles[chain];
const oracleResponse: GetExchangeRateAndGasPriceResponse =
await provider.queryContractSmart(oracle, {
oracle: {
get_exchange_rate_and_gas_price: {
dest_domain: domain,
},
},
});
return oracleResponse;
}
async quoteGasPayment(
domain: number,
destinationGasAmount: number,
): Promise<number> {
const quote: QuoteGasPaymentResponse = await this.queryIgp({
igp: {
quote_gas_payment: {
dest_domain: domain,
gas_amount: destinationGasAmount.toString(),
},
},
});
return Number(quote.gas_needed);
}
setOracleForDomain(
domain: number,
oracle: string,
oracleData: GetExchangeRateAndGasPriceResponse,
): ExecuteInstruction {
return {
contractAddress: oracle,
msg: {
set_remote_gas_data: {
config: {
gas_price: oracleData.gas_price,
token_exchange_rate: oracleData.exchange_rate,
remote_domain: domain,
},
},
},
};
}
}

@ -0,0 +1,228 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export type Uint128 = string;
export type Logo =
| {
url: string;
}
| {
embedded: EmbeddedLogo;
};
export type EmbeddedLogo =
| {
svg: Binary;
}
| {
png: Binary;
};
export type Binary = string;
export interface InstantiateMsg {
decimals: number;
initial_balances: Cw20Coin[];
marketing?: InstantiateMarketingInfo | null;
mint?: MinterResponse | null;
name: string;
symbol: string;
}
export interface Cw20Coin {
address: string;
amount: Uint128;
}
export interface InstantiateMarketingInfo {
description?: string | null;
logo?: Logo | null;
marketing?: string | null;
project?: string | null;
}
export interface MinterResponse {
cap?: Uint128 | null;
minter: string;
}
export type ExecuteMsg =
| {
transfer: {
amount: Uint128;
recipient: string;
};
}
| {
burn: {
amount: Uint128;
};
}
| {
send: {
amount: Uint128;
contract: string;
msg: Binary;
};
}
| {
increase_allowance: {
amount: Uint128;
expires?: Expiration | null;
spender: string;
};
}
| {
decrease_allowance: {
amount: Uint128;
expires?: Expiration | null;
spender: string;
};
}
| {
transfer_from: {
amount: Uint128;
owner: string;
recipient: string;
};
}
| {
send_from: {
amount: Uint128;
contract: string;
msg: Binary;
owner: string;
};
}
| {
burn_from: {
amount: Uint128;
owner: string;
};
}
| {
mint: {
amount: Uint128;
recipient: string;
};
}
| {
update_minter: {
new_minter?: string | null;
};
}
| {
update_marketing: {
description?: string | null;
marketing?: string | null;
project?: string | null;
};
}
| {
upload_logo: Logo;
};
export type Expiration =
| {
at_height: number;
}
| {
at_time: Timestamp;
}
| {
never: {};
};
export type Timestamp = Uint64;
export type Uint64 = string;
export type QueryMsg =
| {
balance: {
address: string;
};
}
| {
token_info: {};
}
| {
minter: {};
}
| {
allowance: {
owner: string;
spender: string;
};
}
| {
all_allowances: {
limit?: number | null;
owner: string;
start_after?: string | null;
};
}
| {
all_spender_allowances: {
limit?: number | null;
spender: string;
start_after?: string | null;
};
}
| {
all_accounts: {
limit?: number | null;
start_after?: string | null;
};
}
| {
marketing_info: {};
}
| {
download_logo: {};
};
export interface AllAccountsResponse {
accounts: string[];
[k: string]: unknown;
}
export interface AllAllowancesResponse {
allowances: AllowanceInfo[];
[k: string]: unknown;
}
export interface AllowanceInfo {
allowance: Uint128;
expires: Expiration;
spender: string;
}
export interface AllSpenderAllowancesResponse {
allowances: SpenderAllowanceInfo[];
[k: string]: unknown;
}
export interface SpenderAllowanceInfo {
allowance: Uint128;
expires: Expiration;
owner: string;
}
export interface AllowanceResponse {
allowance: Uint128;
expires: Expiration;
[k: string]: unknown;
}
export interface BalanceResponse {
balance: Uint128;
}
export interface DownloadLogoResponse {
data: Binary;
mime_type: string;
}
export type LogoInfo =
| {
url: string;
}
| 'embedded';
export type Addr = string;
export interface MarketingInfoResponse {
description?: string | null;
logo?: LogoInfo | null;
marketing?: Addr | null;
project?: string | null;
[k: string]: unknown;
}
export interface TokenInfoResponse {
decimals: number;
name: string;
symbol: string;
total_supply: Uint128;
}

@ -0,0 +1,92 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
hooks: string[];
owner: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
post_dispatch: PostDispatchMsg;
}
| {
set_hooks: {
hooks: string[];
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type HexBinary = string;
export interface PostDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
hook: HookQueryMsg;
}
| {
aggregate_hook: AggregateHookQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type HookQueryMsg =
| {
quote_dispatch: QuoteDispatchMsg;
}
| {
mailbox: {};
};
export type AggregateHookQueryMsg = {
hooks: {};
};
export interface QuoteDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface HooksResponse {
hooks: string[];
}
export interface MailboxResponse {
mailbox: string;
}
export type Uint128 = string;
export interface QuoteDispatchResponse {
gas_amount?: Coin | null;
}
export interface Coin {
amount: Uint128;
denom: string;
[k: string]: unknown;
}

@ -0,0 +1,180 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
mailbox: string;
owner: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
post_dispatch: PostDispatchMsg;
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type HexBinary = string;
export interface PostDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
hook: HookQueryMsg;
}
| {
merkle_hook: MerkleHookQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type HookQueryMsg =
| {
quote_dispatch: QuoteDispatchMsg;
}
| {
mailbox: {};
};
export type MerkleHookQueryMsg =
| {
count: {};
}
| {
root: {};
}
| {
branch: {};
}
| {
tree: {};
}
| {
check_point: {};
};
export interface QuoteDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export interface BranchResponse {
branch: [
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
];
}
export interface CheckPointResponse {
count: number;
root: HexBinary;
}
export interface CountResponse {
count: number;
}
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface MailboxResponse {
mailbox: string;
}
export type Uint128 = string;
export interface QuoteDispatchResponse {
gas_amount?: Coin | null;
}
export interface Coin {
amount: Uint128;
denom: string;
[k: string]: unknown;
}
export interface RootResponse {
root: HexBinary;
}
export interface TreeResponse {
branch: [
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
HexBinary,
];
count: number;
}

@ -0,0 +1,97 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
owner: string;
paused: boolean;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
pausable: PausableMsg;
}
| {
post_dispatch: PostDispatchMsg;
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type PausableMsg =
| {
pause: {};
}
| {
release: {};
};
export type HexBinary = string;
export interface PostDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export type QueryMsg =
| {
pausable: PausableQueryMsg;
}
| {
ownable: OwnableQueryMsg;
}
| {
hook: HookQueryMsg;
};
export type PausableQueryMsg = {
pause_info: {};
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type HookQueryMsg =
| {
quote_dispatch: QuoteDispatchMsg;
}
| {
mailbox: {};
};
export interface QuoteDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface MailboxResponse {
mailbox: string;
}
export interface PauseInfoResponse {
paused: boolean;
}
export type Uint128 = string;
export interface QuoteDispatchResponse {
gas_amount?: Coin | null;
}
export interface Coin {
amount: Uint128;
denom: string;
[k: string]: unknown;
}

@ -0,0 +1,127 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
owner: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
post_dispatch: PostDispatchMsg;
}
| {
router: RouterMsgForAddr;
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type HexBinary = string;
export type RouterMsgForAddr =
| {
set_route: {
set: DomainRouteSetForAddr;
};
}
| {
set_routes: {
set: DomainRouteSetForAddr[];
};
};
export type Addr = string;
export interface PostDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export interface DomainRouteSetForAddr {
domain: number;
route?: Addr | null;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
router: RouterQueryForAddr;
}
| {
hook: HookQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type RouterQueryForAddr =
| {
domains: {};
}
| {
get_route: {
domain: number;
};
}
| {
list_routes: {
limit?: number | null;
offset?: number | null;
order?: Order | null;
};
};
export type Order = 'asc' | 'desc';
export type HookQueryMsg =
| {
quote_dispatch: QuoteDispatchMsg;
}
| {
mailbox: {};
};
export interface QuoteDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export interface DomainsResponse {
domains: number[];
}
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface RouteResponseForAddr {
route: DomainRouteSetForAddr;
}
export interface RoutesResponseForAddr {
routes: DomainRouteSetForAddr[];
}
export interface MailboxResponse {
mailbox: string;
}
export interface Empty {
[k: string]: unknown;
}
export type Uint128 = string;
export interface QuoteDispatchResponse {
gas_amount?: Coin | null;
}
export interface Coin {
amount: Uint128;
denom: string;
[k: string]: unknown;
}

@ -0,0 +1,174 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
owner: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
post_dispatch: PostDispatchMsg;
}
| {
router: RouterMsgForAddr;
}
| {
register_custom_hook: RegisterCustomHookMsg;
}
| {
register_custom_hooks: RegisterCustomHookMsg[];
}
| {
clear_custom_hook: ClearCustomHookMsg;
}
| {
clear_custom_hooks: ClearCustomHookMsg[];
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type HexBinary = string;
export type RouterMsgForAddr =
| {
set_route: {
set: DomainRouteSetForAddr;
};
}
| {
set_routes: {
set: DomainRouteSetForAddr[];
};
};
export type Addr = string;
export interface PostDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export interface DomainRouteSetForAddr {
domain: number;
route?: Addr | null;
}
export interface RegisterCustomHookMsg {
dest_domain: number;
hook: string;
recipient: string;
}
export interface ClearCustomHookMsg {
dest_domain: number;
recipient: string;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
router: RouterQueryForAddr;
}
| {
hook: HookQueryMsg;
}
| {
custom_routing_hook: CustomRoutingHookQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type RouterQueryForAddr =
| {
domains: {};
}
| {
get_route: {
domain: number;
};
}
| {
list_routes: {
limit?: number | null;
offset?: number | null;
order?: Order | null;
};
};
export type Order = 'asc' | 'desc';
export type HookQueryMsg =
| {
quote_dispatch: QuoteDispatchMsg;
}
| {
mailbox: {};
};
export type CustomRoutingHookQueryMsg =
| {
custom_hook: {
dest_domain: number;
recipient: string;
};
}
| {
custom_hooks: {
dest_domain: number;
limit?: number | null;
offset?: string | null;
order?: Order | null;
};
};
export interface QuoteDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export interface CustomHookResponse {
dest_domain: number;
hook: string;
recipient: string;
}
export interface CustomHooksResponse {
custom_hooks: CustomHookResponse[];
}
export interface DomainsResponse {
domains: number[];
}
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface RouteResponseForAddr {
route: DomainRouteSetForAddr;
}
export interface RoutesResponseForAddr {
routes: DomainRouteSetForAddr[];
}
export interface MailboxResponse {
mailbox: string;
}
export interface Empty {
[k: string]: unknown;
}
export type Uint128 = string;
export interface QuoteDispatchResponse {
gas_amount?: Coin | null;
}
export interface Coin {
amount: Uint128;
denom: string;
[k: string]: unknown;
}

@ -0,0 +1,132 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
owner: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
post_dispatch: PostDispatchMsg;
}
| {
router: RouterMsgForAddr;
}
| {
set_fallback_hook: {
hook: string;
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type HexBinary = string;
export type RouterMsgForAddr =
| {
set_route: {
set: DomainRouteSetForAddr;
};
}
| {
set_routes: {
set: DomainRouteSetForAddr[];
};
};
export type Addr = string;
export interface PostDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export interface DomainRouteSetForAddr {
domain: number;
route?: Addr | null;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
router: RouterQueryForAddr;
}
| {
hook: HookQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type RouterQueryForAddr =
| {
domains: {};
}
| {
get_route: {
domain: number;
};
}
| {
list_routes: {
limit?: number | null;
offset?: number | null;
order?: Order | null;
};
};
export type Order = 'asc' | 'desc';
export type HookQueryMsg =
| {
quote_dispatch: QuoteDispatchMsg;
}
| {
mailbox: {};
};
export interface QuoteDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export interface DomainsResponse {
domains: number[];
}
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface RouteResponseForAddr {
route: DomainRouteSetForAddr;
}
export interface RoutesResponseForAddr {
routes: DomainRouteSetForAddr[];
}
export interface MailboxResponse {
mailbox: string;
}
export interface Empty {
[k: string]: unknown;
}
export type Uint128 = string;
export interface QuoteDispatchResponse {
gas_amount?: Coin | null;
}
export interface Coin {
amount: Uint128;
denom: string;
[k: string]: unknown;
}

@ -0,0 +1,215 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
beneficiary: string;
default_gas_usage: number;
gas_token: string;
hrp: string;
owner: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
router: RouterMsgForAddr;
}
| {
post_dispatch: PostDispatchMsg;
}
| {
set_default_gas: {
gas: number;
};
}
| {
set_gas_for_domain: {
config: [number, number][];
};
}
| {
unset_gas_for_domain: {
domains: number[];
};
}
| {
set_beneficiary: {
beneficiary: string;
};
}
| {
pay_for_gas: {
dest_domain: number;
gas_amount: Uint256;
message_id: HexBinary;
refund_address: string;
};
}
| {
claim: {};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type RouterMsgForAddr =
| {
set_route: {
set: DomainRouteSetForAddr;
};
}
| {
set_routes: {
set: DomainRouteSetForAddr[];
};
};
export type Addr = string;
export type HexBinary = string;
export type Uint256 = string;
export interface DomainRouteSetForAddr {
domain: number;
route?: Addr | null;
}
export interface PostDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
hook: HookQueryMsg;
}
| {
router: RouterQueryForAddr;
}
| {
oracle: IgpGasOracleQueryMsg;
}
| {
igp: IgpQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type HookQueryMsg =
| {
quote_dispatch: QuoteDispatchMsg;
}
| {
mailbox: {};
};
export type RouterQueryForAddr =
| {
domains: {};
}
| {
get_route: {
domain: number;
};
}
| {
list_routes: {
limit?: number | null;
offset?: number | null;
order?: Order | null;
};
};
export type Order = 'asc' | 'desc';
export type IgpGasOracleQueryMsg = {
get_exchange_rate_and_gas_price: {
dest_domain: number;
};
};
export type IgpQueryMsg =
| {
default_gas: {};
}
| {
gas_for_domain: {
domains: number[];
};
}
| {
list_gas_for_domains: {
limit?: number | null;
offset?: number | null;
order?: Order | null;
};
}
| {
beneficiary: {};
}
| {
quote_gas_payment: {
dest_domain: number;
gas_amount: Uint256;
};
};
export interface QuoteDispatchMsg {
message: HexBinary;
metadata: HexBinary;
}
export interface BeneficiaryResponse {
beneficiary: string;
}
export interface DefaultGasResponse {
gas: number;
}
export interface DomainsResponse {
domains: number[];
}
export interface GasForDomainResponse {
gas: [number, number][];
}
export type Uint128 = string;
export interface GetExchangeRateAndGasPriceResponse {
exchange_rate: Uint128;
gas_price: Uint128;
}
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface RouteResponseForAddr {
route: DomainRouteSetForAddr;
}
export interface RoutesResponseForAddr {
routes: DomainRouteSetForAddr[];
}
export interface MailboxResponse {
mailbox: string;
}
export interface Empty {
[k: string]: unknown;
}
export interface QuoteDispatchResponse {
gas_amount?: Coin | null;
}
export interface Coin {
amount: Uint128;
denom: string;
[k: string]: unknown;
}
export interface QuoteGasPaymentResponse {
gas_needed: Uint256;
}

@ -0,0 +1,71 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
owner: string;
}
export type ExecuteMsg =
| {
ownership: OwnableMsg;
}
| {
set_remote_gas_data_configs: {
configs: RemoteGasDataConfig[];
};
}
| {
set_remote_gas_data: {
config: RemoteGasDataConfig;
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type Uint128 = string;
export interface RemoteGasDataConfig {
gas_price: Uint128;
remote_domain: number;
token_exchange_rate: Uint128;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
oracle: IgpGasOracleQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type IgpGasOracleQueryMsg = {
get_exchange_rate_and_gas_price: {
dest_domain: number;
};
};
export interface GetExchangeRateAndGasPriceResponse {
exchange_rate: Uint128;
gas_price: Uint128;
}
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}

@ -0,0 +1,97 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
isms: string[];
owner: string;
threshold: number;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
set_isms: {
isms: string[];
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
ism: IsmQueryMsg;
}
| {
aggregate_ism: AggregateIsmQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type IsmQueryMsg =
| {
module_type: {};
}
| {
verify: {
message: HexBinary;
metadata: HexBinary;
};
}
| {
verify_info: {
message: HexBinary;
};
};
export type HexBinary = string;
export type AggregateIsmQueryMsg = {
isms: {};
};
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface IsmsResponse {
isms: string[];
}
export type IsmType =
| 'unused'
| 'routing'
| 'aggregation'
| 'legacy_multisig'
| 'merkle_root_multisig'
| 'message_id_multisig'
| 'null'
| 'ccip_read';
export interface ModuleTypeResponse {
type: IsmType;
}
export interface VerifyResponse {
verified: boolean;
}
export interface VerifyInfoResponse {
threshold: number;
validators: HexBinary[];
}

@ -0,0 +1,127 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
owner: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
enroll_validator: {
set: ValidatorSet;
};
}
| {
enroll_validators: {
set: ValidatorSet[];
};
}
| {
unenroll_validator: {
domain: number;
validator: HexBinary;
};
}
| {
set_threshold: {
set: ThresholdSet;
};
}
| {
set_thresholds: {
set: ThresholdSet[];
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type HexBinary = string;
export interface ValidatorSet {
domain: number;
validator: HexBinary;
}
export interface ThresholdSet {
domain: number;
threshold: number;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
ism: IsmQueryMsg;
}
| {
multisig_ism: MultisigIsmQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type IsmQueryMsg =
| {
module_type: {};
}
| {
verify: {
message: HexBinary;
metadata: HexBinary;
};
}
| {
verify_info: {
message: HexBinary;
};
};
export type MultisigIsmQueryMsg = {
enrolled_validators: {
domain: number;
};
};
export interface EnrolledValidatorsResponse {
threshold: number;
validators: HexBinary[];
}
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export type IsmType =
| 'unused'
| 'routing'
| 'aggregation'
| 'legacy_multisig'
| 'merkle_root_multisig'
| 'message_id_multisig'
| 'null'
| 'ccip_read';
export interface ModuleTypeResponse {
type: IsmType;
}
export interface VerifyResponse {
verified: boolean;
}
export interface VerifyInfoResponse {
threshold: number;
validators: HexBinary[];
}

@ -0,0 +1,102 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
isms: IsmSet[];
owner: string;
}
export interface IsmSet {
address: string;
domain: number;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
set: {
ism: IsmSet;
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
ism: IsmQueryMsg;
}
| {
routing_ism: RoutingIsmQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type IsmQueryMsg =
| {
module_type: {};
}
| {
verify: {
message: HexBinary;
metadata: HexBinary;
};
}
| {
verify_info: {
message: HexBinary;
};
};
export type HexBinary = string;
export type RoutingIsmQueryMsg = {
route: {
message: HexBinary;
};
};
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export type IsmType =
| 'unused'
| 'routing'
| 'aggregation'
| 'legacy_multisig'
| 'merkle_root_multisig'
| 'message_id_multisig'
| 'null'
| 'ccip_read';
export interface ModuleTypeResponse {
type: IsmType;
}
export interface RouteResponse {
ism: string;
}
export interface VerifyResponse {
verified: boolean;
}
export interface VerifyInfoResponse {
threshold: number;
validators: HexBinary[];
}

@ -0,0 +1,154 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
domain: number;
hrp: string;
owner: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
set_default_ism: {
ism: string;
};
}
| {
set_default_hook: {
hook: string;
};
}
| {
set_required_hook: {
hook: string;
};
}
| {
dispatch: DispatchMsg;
}
| {
process: {
message: HexBinary;
metadata: HexBinary;
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type HexBinary = string;
export interface DispatchMsg {
dest_domain: number;
hook?: string | null;
metadata?: HexBinary | null;
msg_body: HexBinary;
recipient_addr: HexBinary;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
hook: MailboxHookQueryMsg;
}
| {
mailbox: MailboxQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type MailboxHookQueryMsg = {
quote_dispatch: DispatchMsg;
};
export type MailboxQueryMsg =
| {
hrp: {};
}
| {
local_domain: {};
}
| {
message_delivered: {
id: HexBinary;
};
}
| {
default_ism: {};
}
| {
default_hook: {};
}
| {
required_hook: {};
}
| {
nonce: {};
}
| {
recipient_ism: {
recipient_addr: string;
};
}
| {
latest_dispatch_id: {};
};
export interface DefaultHookResponse {
default_hook: string;
}
export interface DefaultIsmResponse {
default_ism: string;
}
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface HrpResponse {
hrp: string;
}
export interface LatestDispatchedIdResponse {
message_id: HexBinary;
}
export interface LocalDomainResponse {
local_domain: number;
}
export interface MessageDeliveredResponse {
delivered: boolean;
}
export interface NonceResponse {
nonce: number;
}
export type Uint128 = string;
export interface QuoteDispatchResponse {
gas_amount?: Coin | null;
}
export interface Coin {
amount: Uint128;
denom: string;
[k: string]: unknown;
}
export interface RecipientIsmResponse {
ism: string;
}
export interface RequiredHookResponse {
required_hook: string;
}

@ -0,0 +1,33 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export interface InstantiateMsg {
hrp: string;
mailbox: string;
}
export type ExecuteMsg = {
announce: {
signature: HexBinary;
storage_location: string;
validator: HexBinary;
};
};
export type HexBinary = string;
export type QueryMsg =
| {
get_announce_storage_locations: {
validators: HexBinary[];
};
}
| {
get_announced_validators: {};
};
export interface GetAnnounceStorageLocationsResponse {
storage_locations: [string, string[]][];
}
export interface GetAnnouncedValidatorsResponse {
validators: string[];
}

@ -0,0 +1,256 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export type TokenModeMsgForCw20ModeBridgedAndCw20ModeCollateral =
| {
bridged: Cw20ModeBridged;
}
| {
collateral: Cw20ModeCollateral;
};
export type Uint128 = string;
export type Logo =
| {
url: string;
}
| {
embedded: EmbeddedLogo;
};
export type EmbeddedLogo =
| {
svg: Binary;
}
| {
png: Binary;
};
export type Binary = string;
export interface InstantiateMsg {
hrp: string;
mailbox: string;
owner: string;
token: TokenModeMsgForCw20ModeBridgedAndCw20ModeCollateral;
}
export interface Cw20ModeBridged {
code_id: number;
init_msg: InstantiateMsg1;
}
export interface InstantiateMsg1 {
decimals: number;
initial_balances: Cw20Coin[];
marketing?: InstantiateMarketingInfo | null;
mint?: MinterResponse | null;
name: string;
symbol: string;
}
export interface Cw20Coin {
address: string;
amount: Uint128;
}
export interface InstantiateMarketingInfo {
description?: string | null;
logo?: Logo | null;
marketing?: string | null;
project?: string | null;
}
export interface MinterResponse {
cap?: Uint128 | null;
minter: string;
}
export interface Cw20ModeCollateral {
address: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
router: RouterMsgForHexBinary;
}
| {
connection: ConnectionMsg;
}
| {
handle: HandleMsg;
}
| {
transfer_remote: {
amount: Uint128;
dest_domain: number;
recipient: HexBinary;
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type RouterMsgForHexBinary =
| {
set_route: {
set: DomainRouteSetForHexBinary;
};
}
| {
set_routes: {
set: DomainRouteSetForHexBinary[];
};
};
export type HexBinary = string;
export type ConnectionMsg =
| {
set_mailbox: {
mailbox: string;
};
}
| {
set_hook: {
hook: string;
};
}
| {
set_ism: {
ism: string;
};
};
export interface DomainRouteSetForHexBinary {
domain: number;
route?: HexBinary | null;
}
export interface HandleMsg {
body: HexBinary;
origin: number;
sender: HexBinary;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
router: RouterQueryForHexBinary;
}
| {
connection: ConnectionQueryMsg;
}
| {
token_default: TokenWarpDefaultQueryMsg;
}
| {
ism_specifier: IsmSpecifierQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type RouterQueryForHexBinary =
| {
domains: {};
}
| {
get_route: {
domain: number;
};
}
| {
list_routes: {
limit?: number | null;
offset?: number | null;
order?: Order | null;
};
};
export type Order = 'asc' | 'desc';
export type ConnectionQueryMsg =
| {
get_mailbox: {};
}
| {
get_hook: {};
}
| {
get_ism: {};
};
export type TokenWarpDefaultQueryMsg =
| {
token_type: {};
}
| {
token_mode: {};
};
export type IsmSpecifierQueryMsg = {
interchain_security_module: [];
};
export interface DomainsResponse {
domains: number[];
}
export interface HookResponse {
hook?: string | null;
}
export interface IsmResponse {
ism?: string | null;
}
export interface MailboxResponse {
mailbox?: string | null;
}
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface RouteResponseForHexBinary {
route: DomainRouteSetForHexBinary;
}
export interface InterchainSecurityModuleResponse {
ism?: Addr | null;
}
export interface RoutesResponseForHexBinary {
routes: DomainRouteSetForHexBinary[];
}
export interface Empty {
[k: string]: unknown;
}
export type TokenMode = 'bridged' | 'collateral';
export interface TokenModeResponse {
mode: TokenMode;
}
export type TokenType =
| {
native: TokenTypeNative;
}
| {
c_w20: {
contract: string;
};
}
| {
c_w721: {
contract: string;
};
};
export type TokenTypeNative =
| {
fungible: {
denom: string;
};
}
| {
non_fungible: {
class: string;
};
};
export interface TokenTypeResponse {
type: TokenType;
}

@ -0,0 +1,232 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@0.35.3.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/
export type TokenModeMsgForNativeModeBrigedAndNativeModeCollateral =
| {
bridged: NativeModeBriged;
}
| {
collateral: NativeModeCollateral;
};
export interface InstantiateMsg {
hrp: string;
mailbox: string;
owner: string;
token: TokenModeMsgForNativeModeBrigedAndNativeModeCollateral;
}
export interface NativeModeBriged {
denom: string;
metadata?: Metadata | null;
}
export interface Metadata {
base: string;
denom_units: DenomUnit[];
description: string;
display: string;
name: string;
symbol: string;
}
export interface DenomUnit {
aliases: string[];
denom: string;
exponent: number;
}
export interface NativeModeCollateral {
denom: string;
}
export type ExecuteMsg =
| {
ownable: OwnableMsg;
}
| {
router: RouterMsgForHexBinary;
}
| {
connection: ConnectionMsg;
}
| {
handle: HandleMsg;
}
| {
transfer_remote: {
amount: Uint128;
dest_domain: number;
recipient: HexBinary;
};
};
export type OwnableMsg =
| {
init_ownership_transfer: {
next_owner: string;
};
}
| {
revoke_ownership_transfer: {};
}
| {
claim_ownership: {};
};
export type RouterMsgForHexBinary =
| {
set_route: {
set: DomainRouteSetForHexBinary;
};
}
| {
set_routes: {
set: DomainRouteSetForHexBinary[];
};
};
export type HexBinary = string;
export type ConnectionMsg =
| {
set_mailbox: {
mailbox: string;
};
}
| {
set_hook: {
hook: string;
};
}
| {
set_ism: {
ism: string;
};
};
export type Uint128 = string;
export interface DomainRouteSetForHexBinary {
domain: number;
route?: HexBinary | null;
}
export interface HandleMsg {
body: HexBinary;
origin: number;
sender: HexBinary;
}
export type QueryMsg =
| {
ownable: OwnableQueryMsg;
}
| {
router: RouterQueryForHexBinary;
}
| {
connection: ConnectionQueryMsg;
}
| {
token_default: TokenWarpDefaultQueryMsg;
}
| {
ism_specifier: IsmSpecifierQueryMsg;
};
export type OwnableQueryMsg =
| {
get_owner: {};
}
| {
get_pending_owner: {};
};
export type RouterQueryForHexBinary =
| {
domains: {};
}
| {
get_route: {
domain: number;
};
}
| {
list_routes: {
limit?: number | null;
offset?: number | null;
order?: Order | null;
};
};
export type Order = 'asc' | 'desc';
export type ConnectionQueryMsg =
| {
get_mailbox: {};
}
| {
get_hook: {};
}
| {
get_ism: {};
};
export type TokenWarpDefaultQueryMsg =
| {
token_type: {};
}
| {
token_mode: {};
};
export type IsmSpecifierQueryMsg = {
interchain_security_module: [];
};
export interface DomainsResponse {
domains: number[];
}
export interface HookResponse {
hook?: string | null;
}
export interface IsmResponse {
ism?: string | null;
}
export interface MailboxResponse {
mailbox?: string | null;
}
export type Addr = string;
export interface OwnerResponse {
owner: Addr;
}
export interface PendingOwnerResponse {
pending_owner?: Addr | null;
}
export interface RouteResponseForHexBinary {
route: DomainRouteSetForHexBinary;
}
export interface InterchainSecurityModuleResponse {
ism?: Addr | null;
}
export interface RoutesResponseForHexBinary {
routes: DomainRouteSetForHexBinary[];
}
export interface Empty {
[k: string]: unknown;
}
export type TokenMode = 'bridged' | 'collateral';
export interface TokenModeResponse {
mode: TokenMode;
}
export type TokenType =
| {
native: TokenTypeNative;
}
| {
c_w20: {
contract: string;
};
}
| {
c_w721: {
contract: string;
};
};
export type TokenTypeNative =
| {
fungible: {
denom: string;
};
}
| {
non_fungible: {
class: string;
};
};
export interface TokenTypeResponse {
type: TokenType;
}

@ -164,10 +164,12 @@ export {
export { export {
ChainMetadata, ChainMetadata,
ChainMetadataSchema, ChainMetadataSchema,
ChainMetadataSchemaObject,
ExplorerFamily, ExplorerFamily,
ExplorerFamilyValue, ExplorerFamilyValue,
RpcUrl, RpcUrl,
RpcUrlSchema, RpcUrlSchema,
getChainIdNumber,
getDomainId, getDomainId,
isValidChainMetadata, isValidChainMetadata,
} from './metadata/chainMetadataTypes'; } from './metadata/chainMetadataTypes';
@ -206,6 +208,14 @@ export {
} from './providers/MultiProtocolProvider'; } from './providers/MultiProtocolProvider';
export { MultiProvider, MultiProviderOptions } from './providers/MultiProvider'; export { MultiProvider, MultiProviderOptions } from './providers/MultiProvider';
export { export {
CosmJsContract,
CosmJsProvider,
CosmJsTransaction,
CosmJsTransactionReceipt,
CosmJsWasmContract,
CosmJsWasmProvider,
CosmJsWasmTransaction,
CosmJsWasmTransactionReceipt,
EthersV5Contract, EthersV5Contract,
EthersV5Provider, EthersV5Provider,
EthersV5Transaction, EthersV5Transaction,
@ -276,6 +286,14 @@ export {
RouterViolationType, RouterViolationType,
proxiedFactories, proxiedFactories,
} from './router/types'; } from './router/types';
export {
CW20Metadata,
CwHypCollateralAdapter,
CwHypNativeAdapter,
CwHypSyntheticAdapter,
CwNativeTokenAdapter,
CwTokenAdapter,
} from './token/adapters/CosmWasmTokenAdapter';
export { export {
EvmHypCollateralAdapter, EvmHypCollateralAdapter,
EvmHypSyntheticAdapter, EvmHypSyntheticAdapter,
@ -292,7 +310,6 @@ export {
SealevelHypCollateralAdapter, SealevelHypCollateralAdapter,
SealevelHypNativeAdapter, SealevelHypNativeAdapter,
SealevelHypSyntheticAdapter, SealevelHypSyntheticAdapter,
SealevelHypTokenAdapter,
SealevelNativeTokenAdapter, SealevelNativeTokenAdapter,
SealevelTokenAdapter, SealevelTokenAdapter,
} from './token/adapters/SealevelTokenAdapter'; } from './token/adapters/SealevelTokenAdapter';

@ -0,0 +1,122 @@
import { ExecuteInstruction } from '@cosmjs/cosmwasm-stargate';
import {
Address,
difference,
objMap,
promiseObjAll,
} from '@hyperlane-xyz/utils';
import { BaseCosmWasmAdapter } from '../../app/MultiProtocolApp';
import {
EnrolledValidatorsResponse,
ExecuteMsg as MultisigExecute,
QueryMsg as MultisigQuery,
} from '../../cw-types/IsmMultisig.types';
import { MultisigConfig } from '../../ism/types';
import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider';
import { ChainMap, ChainName } from '../../types';
type MultisigResponse = EnrolledValidatorsResponse;
export class CosmWasmMultisigAdapter extends BaseCosmWasmAdapter {
constructor(
public readonly chainName: ChainName,
public readonly multiProvider: MultiProtocolProvider<any>,
public readonly addresses: { multisig: Address },
) {
super(chainName, multiProvider, addresses);
}
async queryMultisig<R extends MultisigResponse>(
msg: MultisigQuery,
): Promise<R> {
const provider = await this.getProvider();
const response: R = await provider.queryContractSmart(
this.addresses.multisig,
msg,
);
return response;
}
async getConfig(chain: ChainName): Promise<MultisigConfig> {
return this.queryMultisig<EnrolledValidatorsResponse>({
multisig_ism: {
enrolled_validators: {
domain: this.multiProvider.getDomainId(chain),
},
},
});
}
prepareMultisig(msg: MultisigExecute): ExecuteInstruction {
return {
contractAddress: this.addresses.multisig,
msg,
};
}
async configureMultisig(
configMap: ChainMap<MultisigConfig>,
): Promise<ExecuteInstruction[]> {
const configuredMap = await promiseObjAll(
objMap(configMap, (origin, _) => this.getConfig(origin)),
);
const validatorInstructions = Object.entries(configMap).flatMap(
([origin, config]) => {
const domain = this.multiProvider.getDomainId(origin);
const configuredSet = new Set(configuredMap[origin].validators);
const configSet = new Set(config.validators);
const unenrollList = Array.from(
difference(configuredSet, configSet).values(),
);
const enrollList = Array.from(
difference(configSet, configuredSet).values(),
);
return unenrollList
.map((validator) =>
this.prepareMultisig({
unenroll_validator: {
domain,
validator,
},
}),
)
.concat(
enrollList.map((validator) =>
this.prepareMultisig({
enroll_validator: {
set: {
domain,
validator,
},
},
}),
),
);
},
);
const setThresholds = Object.entries(configMap)
.filter(
([origin, { threshold }]) =>
threshold !== configuredMap[origin].threshold,
)
.map(([origin, config]) => ({
domain: this.multiProvider.getDomainId(origin),
threshold: config.threshold,
}));
if (setThresholds.length > 0) {
const thresholdInstruction = this.prepareMultisig({
set_thresholds: {
set: setThresholds,
},
});
return [...validatorInstructions, thresholdInstruction];
}
return validatorInstructions;
}
}

@ -1,6 +1,6 @@
import { Debugger, debug } from 'debug'; import { Debugger, debug } from 'debug';
import { ProtocolType, exclude, isNumeric, pick } from '@hyperlane-xyz/utils'; import { ProtocolType, exclude, pick } from '@hyperlane-xyz/utils';
import { import {
chainMetadata as defaultChainMetadata, chainMetadata as defaultChainMetadata,
@ -64,7 +64,7 @@ export class ChainMetadataManager<MetaExt = {}> {
chainId == metadata.chainId || chainId == metadata.chainId ||
domainId == metadata.chainId || domainId == metadata.chainId ||
(metadata.domainId && (metadata.domainId &&
(chainId == metadata.domainId || domainId === metadata.domainId)); (chainId == metadata.domainId || domainId == metadata.domainId));
if (idCollision) if (idCollision)
throw new Error( throw new Error(
`Chain/Domain id collision: ${name} and ${metadata.name}`, `Chain/Domain id collision: ${name} and ${metadata.name}`,
@ -80,16 +80,12 @@ export class ChainMetadataManager<MetaExt = {}> {
tryGetChainMetadata( tryGetChainMetadata(
chainNameOrId: ChainName | number, chainNameOrId: ChainName | number,
): ChainMetadata<MetaExt> | null { ): ChainMetadata<MetaExt> | null {
let chainMetadata: ChainMetadata<MetaExt> | undefined; // First check if it's a chain name
if (isNumeric(chainNameOrId)) { if (this.metadata[chainNameOrId]) return this.metadata[chainNameOrId];
// Should be chain id or domain id // Otherwise search by chain id and domain id
chainMetadata = Object.values(this.metadata).find( const chainMetadata = Object.values(this.metadata).find(
(m) => m.chainId == chainNameOrId || m.domainId == chainNameOrId, (m) => m.chainId == chainNameOrId || m.domainId == chainNameOrId,
); );
} else if (typeof chainNameOrId === 'string') {
// Should be chain name
chainMetadata = this.metadata[chainNameOrId];
}
return chainMetadata || null; return chainMetadata || null;
} }
@ -130,7 +126,7 @@ export class ChainMetadataManager<MetaExt = {}> {
/** /**
* Get the id for a given chain name, chain id, or domain id * Get the id for a given chain name, chain id, or domain id
*/ */
tryGetChainId(chainNameOrId: ChainName | number): number | null { tryGetChainId(chainNameOrId: ChainName | number): number | string | null {
return this.tryGetChainMetadata(chainNameOrId)?.chainId ?? null; return this.tryGetChainMetadata(chainNameOrId)?.chainId ?? null;
} }
@ -138,14 +134,14 @@ export class ChainMetadataManager<MetaExt = {}> {
* Get the id for a given chain name, chain id, or domain id * Get the id for a given chain name, chain id, or domain id
* @throws if chain's metadata has not been set * @throws if chain's metadata has not been set
*/ */
getChainId(chainNameOrId: ChainName | number): number { getChainId(chainNameOrId: ChainName | number): number | string {
return this.getChainMetadata(chainNameOrId).chainId; return this.getChainMetadata(chainNameOrId).chainId;
} }
/** /**
* Get the ids for all chains known to this MultiProvider * Get the ids for all chains known to this MultiProvider
*/ */
getKnownChainIds(): number[] { getKnownChainIds(): Array<number | string> {
return Object.values(this.metadata).map((c) => c.chainId); return Object.values(this.metadata).map((c) => c.chainId);
} }
@ -154,7 +150,8 @@ export class ChainMetadataManager<MetaExt = {}> {
*/ */
tryGetDomainId(chainNameOrId: ChainName | number): number | null { tryGetDomainId(chainNameOrId: ChainName | number): number | null {
const metadata = this.tryGetChainMetadata(chainNameOrId); const metadata = this.tryGetChainMetadata(chainNameOrId);
return metadata?.domainId ?? metadata?.chainId ?? null; if (!metadata) return null;
return getDomainId(metadata) ?? null;
} }
/** /**
@ -162,8 +159,9 @@ export class ChainMetadataManager<MetaExt = {}> {
* @throws if chain's metadata has not been set * @throws if chain's metadata has not been set
*/ */
getDomainId(chainNameOrId: ChainName | number): number { getDomainId(chainNameOrId: ChainName | number): number {
const metadata = this.getChainMetadata(chainNameOrId); const domainId = this.tryGetDomainId(chainNameOrId);
return getDomainId(metadata); if (!domainId) throw new Error(`No domain id set for ${chainNameOrId}`);
return domainId;
} }
/** /**
@ -224,6 +222,7 @@ export class ChainMetadataManager<MetaExt = {}> {
) { ) {
url.searchParams.set('cluster', solanaChainToClusterName[metadata.name]); url.searchParams.set('cluster', solanaChainToClusterName[metadata.name]);
} }
// TODO cosmos support here
return url.toString(); return url.toString();
} }

@ -7,7 +7,7 @@ import { z } from 'zod';
import { MultiProvider } from '../providers/MultiProvider'; import { MultiProvider } from '../providers/MultiProvider';
import { ChainMap, ChainName } from '../types'; import { ChainMap, ChainName } from '../types';
import { ChainMetadata, ChainMetadataSchema } from './chainMetadataTypes'; import { ChainMetadata, ChainMetadataSchemaObject } from './chainMetadataTypes';
import { ZHash, ZNzUint, ZUWei, ZUint } from './customZodTypes'; import { ZHash, ZNzUint, ZUWei, ZUint } from './customZodTypes';
import { import {
HyperlaneDeploymentArtifacts, HyperlaneDeploymentArtifacts,
@ -80,7 +80,7 @@ export type AgentSignerAwsKey = z.infer<typeof AgentSignerAwsKeySchema>;
export type AgentSignerNode = z.infer<typeof AgentSignerNodeSchema>; export type AgentSignerNode = z.infer<typeof AgentSignerNodeSchema>;
export type AgentSigner = z.infer<typeof AgentSignerSchema>; export type AgentSigner = z.infer<typeof AgentSignerSchema>;
export const AgentChainMetadataSchema = ChainMetadataSchema.merge( export const AgentChainMetadataSchema = ChainMetadataSchemaObject.merge(
HyperlaneDeploymentArtifactsSchema, HyperlaneDeploymentArtifactsSchema,
).extend({ ).extend({
customRpcUrls: z customRpcUrls: z

@ -50,6 +50,16 @@ describe('ChainMetadataSchema', () => {
blocks, blocks,
}), }),
).to.eq(true); ).to.eq(true);
expect(
isValidChainMetadata({
...minimalSchema,
protocol: ProtocolType.Cosmos,
chainId: 'cosmos',
bech32Prefix: 'cosmos',
slip44: 118,
}),
).to.eq(true);
}); });
it('Rejects invalid schemas', () => { it('Rejects invalid schemas', () => {
expect( expect(
@ -80,5 +90,20 @@ describe('ChainMetadataSchema', () => {
name: 'Invalid name', name: 'Invalid name',
}), }),
).to.eq(false); ).to.eq(false);
expect(
isValidChainMetadata({
...minimalSchema,
chainId: 'string-id',
}),
).to.eq(false);
expect(
isValidChainMetadata({
...minimalSchema,
protocol: ProtocolType.Cosmos,
chainId: 'string-id',
}),
).to.eq(false);
}); });
}); });

@ -59,7 +59,7 @@ export type RpcUrl = z.infer<typeof RpcUrlSchema>;
* A collection of useful properties and settings for chains using Hyperlane * A collection of useful properties and settings for chains using Hyperlane
* Specified as a Zod schema * Specified as a Zod schema
*/ */
export const ChainMetadataSchema = z.object({ export const ChainMetadataSchemaObject = z.object({
name: z name: z
.string() .string()
.regex(/^[a-z][a-z0-9]*$/) .regex(/^[a-z][a-z0-9]*$/)
@ -71,9 +71,9 @@ export const ChainMetadataSchema = z.object({
.describe( .describe(
'The type of protocol used by this chain. See ProtocolType for valid values.', 'The type of protocol used by this chain. See ProtocolType for valid values.',
), ),
chainId: ZNzUint.describe( chainId: z
`The chainId of the chain. Uses EIP-155 for EVM chains`, .union([ZNzUint, z.string()])
), .describe(`The chainId of the chain. Uses EIP-155 for EVM chains`),
domainId: ZNzUint.optional().describe( domainId: ZNzUint.optional().describe(
'The domainId of the chain, should generally default to `chainId`. Consumer of `ChainMetadata` should use this value if present, but otherwise fallback to `chainId`.', 'The domainId of the chain, should generally default to `chainId`. Consumer of `ChainMetadata` should use this value if present, but otherwise fallback to `chainId`.',
), ),
@ -161,12 +161,59 @@ export const ChainMetadataSchema = z.object({
.string() .string()
.optional() .optional()
.describe('The URL of the gnosis safe transaction service.'), .describe('The URL of the gnosis safe transaction service.'),
bech32Prefix: z
.string()
.optional()
.describe('The human readable address prefix for the chains using bech32.'),
slip44: z.number().optional().describe('The SLIP-0044 coin type.'),
isTestnet: z isTestnet: z
.boolean() .boolean()
.optional() .optional()
.describe('Whether the chain is considered a testnet or a mainnet.'), .describe('Whether the chain is considered a testnet or a mainnet.'),
}); });
// Add refinements to the object schema to conditionally validate certain fields
export const ChainMetadataSchema = ChainMetadataSchemaObject.refine(
(metadata) => {
if (
[ProtocolType.Ethereum, ProtocolType.Sealevel].includes(
metadata.protocol,
) &&
typeof metadata.chainId !== 'number'
)
return false;
else if (
metadata.protocol === ProtocolType.Cosmos &&
typeof metadata.chainId !== 'string'
)
return false;
else return true;
},
{ message: 'Invalid Chain Id', path: ['chainId'] },
)
.refine(
(metadata) => {
if (typeof metadata.chainId === 'string' && !metadata.domainId)
return false;
else return true;
},
{ message: 'Domain Id required', path: ['domainId'] },
)
.refine(
(metadata) => {
if (
metadata.protocol === ProtocolType.Cosmos &&
(!metadata.bech32Prefix || !metadata.slip44)
)
return false;
else return true;
},
{
message: 'Bech32Prefix and Slip44 required for Cosmos chains',
path: ['bech32Prefix', 'slip44'],
},
);
export type ChainMetadata<Ext = object> = z.infer<typeof ChainMetadataSchema> & export type ChainMetadata<Ext = object> = z.infer<typeof ChainMetadataSchema> &
Ext; Ext;
@ -175,5 +222,13 @@ export function isValidChainMetadata(c: ChainMetadata): boolean {
} }
export function getDomainId(chainMetadata: ChainMetadata): number { export function getDomainId(chainMetadata: ChainMetadata): number {
return chainMetadata.domainId ?? chainMetadata.chainId; if (chainMetadata.domainId) return chainMetadata.domainId;
else if (typeof chainMetadata.chainId === 'number')
return chainMetadata.chainId;
else throw new Error('Invalid chain metadata, no valid domainId');
}
export function getChainIdNumber(chainMetadata: ChainMetadata): number {
if (typeof chainMetadata.chainId === 'number') return chainMetadata.chainId;
else throw new Error('ChainId is not a number, chain may be of Cosmos type');
} }

@ -9,6 +9,8 @@ import type { ChainMap, ChainName } from '../types';
import { MultiProvider, MultiProviderOptions } from './MultiProvider'; import { MultiProvider, MultiProviderOptions } from './MultiProvider';
import { import {
CosmJsProvider,
CosmJsWasmProvider,
EthersV5Provider, EthersV5Provider,
ProviderMap, ProviderMap,
ProviderType, ProviderType,
@ -26,6 +28,7 @@ export const PROTOCOL_DEFAULT_PROVIDER_TYPE: Partial<
> = { > = {
[ProtocolType.Ethereum]: ProviderType.EthersV5, [ProtocolType.Ethereum]: ProviderType.EthersV5,
[ProtocolType.Sealevel]: ProviderType.SolanaWeb3, [ProtocolType.Sealevel]: ProviderType.SolanaWeb3,
[ProtocolType.Cosmos]: ProviderType.CosmJsWasm,
}; };
export interface MultiProtocolProviderOptions { export interface MultiProtocolProviderOptions {
@ -143,38 +146,59 @@ export class MultiProtocolProvider<
return provider; return provider;
} }
protected getSpecificProvider<T>(
chainNameOrId: ChainName | number,
type: ProviderType,
): T {
const provider = this.getProvider(chainNameOrId, type);
if (provider.type !== type)
throw new Error(
`Invalid provider type, expected ${type} but found ${provider.type}`,
);
return provider.provider as T;
}
getEthersV5Provider( getEthersV5Provider(
chainNameOrId: ChainName | number, chainNameOrId: ChainName | number,
): EthersV5Provider['provider'] { ): EthersV5Provider['provider'] {
const provider = this.getProvider(chainNameOrId, ProviderType.EthersV5); return this.getSpecificProvider<EthersV5Provider['provider']>(
if (provider.type !== ProviderType.EthersV5) chainNameOrId,
throw new Error('Invalid provider type'); ProviderType.EthersV5,
return provider.provider; );
} }
// getEthersV6Provider(
// chainNameOrId: ChainName | number,
// ): EthersV6Provider['provider'] {
// const provider = this.getProvider(chainNameOrId, ProviderType.EthersV6);
// if (provider.type !== ProviderType.EthersV6)
// throw new Error('Invalid provider type');
// return provider.provider;
// }
getViemProvider(chainNameOrId: ChainName | number): ViemProvider['provider'] { getViemProvider(chainNameOrId: ChainName | number): ViemProvider['provider'] {
const provider = this.getProvider(chainNameOrId, ProviderType.Viem); return this.getSpecificProvider<ViemProvider['provider']>(
if (provider.type !== ProviderType.Viem) chainNameOrId,
throw new Error('Invalid provider type'); ProviderType.Viem,
return provider.provider; );
} }
getSolanaWeb3Provider( getSolanaWeb3Provider(
chainNameOrId: ChainName | number, chainNameOrId: ChainName | number,
): SolanaWeb3Provider['provider'] { ): SolanaWeb3Provider['provider'] {
const provider = this.getProvider(chainNameOrId, ProviderType.SolanaWeb3); return this.getSpecificProvider<SolanaWeb3Provider['provider']>(
if (provider.type !== ProviderType.SolanaWeb3) chainNameOrId,
throw new Error('Invalid provider type'); ProviderType.SolanaWeb3,
return provider.provider; );
}
getCosmJsProvider(
chainNameOrId: ChainName | number,
): CosmJsProvider['provider'] {
return this.getSpecificProvider<CosmJsProvider['provider']>(
chainNameOrId,
ProviderType.CosmJs,
);
}
getCosmJsWasmProvider(
chainNameOrId: ChainName | number,
): CosmJsWasmProvider['provider'] {
return this.getSpecificProvider<CosmJsWasmProvider['provider']>(
chainNameOrId,
ProviderType.CosmJsWasm,
);
} }
setProvider( setProvider(

@ -1,3 +1,10 @@
import type {
CosmWasmClient,
Contract as CosmWasmContract,
ExecuteInstruction,
} from '@cosmjs/cosmwasm-stargate';
import type { EncodeObject as CmTransaction } from '@cosmjs/proto-signing';
import type { DeliverTxResponse, StargateClient } from '@cosmjs/stargate';
import type { import type {
Connection, Connection,
Transaction as SolTransaction, Transaction as SolTransaction,
@ -21,6 +28,8 @@ export enum ProviderType {
// EthersV6 = 'ethers-v6', Disabled for now to simplify build tooling // EthersV6 = 'ethers-v6', Disabled for now to simplify build tooling
Viem = 'viem', Viem = 'viem',
SolanaWeb3 = 'solana-web3', SolanaWeb3 = 'solana-web3',
CosmJs = 'cosmjs',
CosmJsWasm = 'cosmjs-wasm',
} }
export type ProviderMap<Value> = Partial<Record<ProviderType, Value>>; export type ProviderMap<Value> = Partial<Record<ProviderType, Value>>;
@ -55,11 +64,25 @@ export interface SolanaWeb3Provider extends TypedProviderBase<Connection> {
provider: Connection; provider: Connection;
} }
export interface CosmJsProvider
extends TypedProviderBase<Promise<StargateClient>> {
type: ProviderType.CosmJs;
provider: Promise<StargateClient>;
}
export interface CosmJsWasmProvider
extends TypedProviderBase<Promise<CosmWasmClient>> {
type: ProviderType.CosmJsWasm;
provider: Promise<CosmWasmClient>;
}
export type TypedProvider = export type TypedProvider =
| EthersV5Provider | EthersV5Provider
// | EthersV6Provider // | EthersV6Provider
| ViemProvider | ViemProvider
| SolanaWeb3Provider; | SolanaWeb3Provider
| CosmJsProvider
| CosmJsWasmProvider;
/** /**
* Contracts with discriminated union of provider type * Contracts with discriminated union of provider type
@ -72,7 +95,7 @@ interface TypedContractBase<T> {
export interface EthersV5Contract extends TypedContractBase<EV5Contract> { export interface EthersV5Contract extends TypedContractBase<EV5Contract> {
type: ProviderType.EthersV5; type: ProviderType.EthersV5;
transaction: EV5Contract; contract: EV5Contract;
} }
// export interface EthersV6Contract extends TypedContractBase<Ev6Contract> { // export interface EthersV6Contract extends TypedContractBase<Ev6Contract> {
@ -82,20 +105,34 @@ export interface EthersV5Contract extends TypedContractBase<EV5Contract> {
export interface ViemContract extends TypedContractBase<GetContractReturnType> { export interface ViemContract extends TypedContractBase<GetContractReturnType> {
type: ProviderType.Viem; type: ProviderType.Viem;
transaction: GetContractReturnType; contract: GetContractReturnType;
} }
export interface SolanaWeb3Contract extends TypedContractBase<never> { export interface SolanaWeb3Contract extends TypedContractBase<never> {
type: ProviderType.SolanaWeb3; type: ProviderType.SolanaWeb3;
// Contract concept doesn't exist in @solana/web3.js // Contract concept doesn't exist in @solana/web3.js
transaction: never; contract: never;
}
export interface CosmJsContract extends TypedContractBase<never> {
type: ProviderType.CosmJs;
// TODO, research if cosmos sdk modules have an equivalent for here
contract: never;
}
export interface CosmJsWasmContract
extends TypedContractBase<CosmWasmContract> {
type: ProviderType.CosmJsWasm;
contract: CosmWasmContract;
} }
export type TypedContract = export type TypedContract =
| EthersV5Contract | EthersV5Contract
// | EthersV6Contract // | EthersV6Contract
| ViemContract | ViemContract
| SolanaWeb3Contract; | SolanaWeb3Contract
| CosmJsContract
| CosmJsWasmContract;
/** /**
* Transactions with discriminated union of provider type * Transactions with discriminated union of provider type
@ -128,11 +165,24 @@ export interface SolanaWeb3Transaction
transaction: SolTransaction; transaction: SolTransaction;
} }
export interface CosmJsTransaction extends TypedTransactionBase<CmTransaction> {
type: ProviderType.CosmJs;
transaction: CmTransaction;
}
export interface CosmJsWasmTransaction
extends TypedTransactionBase<ExecuteInstruction> {
type: ProviderType.CosmJs;
transaction: ExecuteInstruction;
}
export type TypedTransaction = export type TypedTransaction =
| EthersV5Transaction | EthersV5Transaction
// | EthersV6Transaction // | EthersV6Transaction
| ViemTransaction | ViemTransaction
| SolanaWeb3Transaction; | SolanaWeb3Transaction
| CosmJsTransaction
| CosmJsWasmTransaction;
/** /**
* Transaction receipt/response with discriminated union of provider type * Transaction receipt/response with discriminated union of provider type
@ -161,7 +211,21 @@ export interface SolanaWeb3TransactionReceipt
receipt: SolTransactionReceipt; receipt: SolTransactionReceipt;
} }
export interface CosmJsTransactionReceipt
extends TypedTransactionReceiptBase<DeliverTxResponse> {
type: ProviderType.CosmJs;
receipt: DeliverTxResponse;
}
export interface CosmJsWasmTransactionReceipt
extends TypedTransactionReceiptBase<DeliverTxResponse> {
type: ProviderType.CosmJsWasm;
receipt: DeliverTxResponse;
}
export type TypedTransactionReceipt = export type TypedTransactionReceipt =
| EthersV5TransactionReceipt | EthersV5TransactionReceipt
| ViemTransactionReceipt | ViemTransactionReceipt
| SolanaWeb3TransactionReceipt; | SolanaWeb3TransactionReceipt
| CosmJsTransactionReceipt
| CosmJsWasmTransactionReceipt;

@ -1,3 +1,5 @@
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate';
import { StargateClient } from '@cosmjs/stargate';
import { Connection } from '@solana/web3.js'; import { Connection } from '@solana/web3.js';
import { providers } from 'ethers'; import { providers } from 'ethers';
import { createPublicClient, http } from 'viem'; import { createPublicClient, http } from 'viem';
@ -7,6 +9,8 @@ import { ProtocolType, isNumeric } from '@hyperlane-xyz/utils';
import { ChainMetadata } from '../metadata/chainMetadataTypes'; import { ChainMetadata } from '../metadata/chainMetadataTypes';
import { import {
CosmJsProvider,
CosmJsWasmProvider,
EthersV5Provider, EthersV5Provider,
ProviderType, ProviderType,
SolanaWeb3Provider, SolanaWeb3Provider,
@ -102,6 +106,28 @@ export function defaultFuelProviderBuilder(
throw new Error('TODO fuel support'); throw new Error('TODO fuel support');
} }
export function defaultCosmJsProviderBuilder(
rpcUrls: ChainMetadata['rpcUrls'],
_network: number | string,
): CosmJsProvider {
if (!rpcUrls.length) throw new Error('No RPC URLs provided');
return {
type: ProviderType.CosmJs,
provider: StargateClient.connect(rpcUrls[0].http),
};
}
export function defaultCosmJsWasmProviderBuilder(
rpcUrls: ChainMetadata['rpcUrls'],
_network: number | string,
): CosmJsWasmProvider {
if (!rpcUrls.length) throw new Error('No RPC URLs provided');
return {
type: ProviderType.CosmJsWasm,
provider: CosmWasmClient.connect(rpcUrls[0].http),
};
}
// Kept for backwards compatibility // Kept for backwards compatibility
export function defaultProviderBuilder( export function defaultProviderBuilder(
rpcUrls: ChainMetadata['rpcUrls'], rpcUrls: ChainMetadata['rpcUrls'],
@ -119,6 +145,8 @@ export const defaultProviderBuilderMap: ProviderBuilderMap = {
// [ProviderType.EthersV6]: defaultEthersV6ProviderBuilder, // [ProviderType.EthersV6]: defaultEthersV6ProviderBuilder,
[ProviderType.Viem]: defaultViemProviderBuilder, [ProviderType.Viem]: defaultViemProviderBuilder,
[ProviderType.SolanaWeb3]: defaultSolProviderBuilder, [ProviderType.SolanaWeb3]: defaultSolProviderBuilder,
[ProviderType.CosmJs]: defaultCosmJsProviderBuilder,
[ProviderType.CosmJsWasm]: defaultCosmJsWasmProviderBuilder,
}; };
export const protocolToDefaultProviderBuilder: Record< export const protocolToDefaultProviderBuilder: Record<
@ -128,4 +156,5 @@ export const protocolToDefaultProviderBuilder: Record<
[ProtocolType.Ethereum]: defaultEthersV5ProviderBuilder, [ProtocolType.Ethereum]: defaultEthersV5ProviderBuilder,
[ProtocolType.Sealevel]: defaultSolProviderBuilder, [ProtocolType.Sealevel]: defaultSolProviderBuilder,
[ProtocolType.Fuel]: defaultFuelProviderBuilder, [ProtocolType.Fuel]: defaultFuelProviderBuilder,
[ProtocolType.Cosmos]: defaultCosmJsWasmProviderBuilder,
}; };

@ -27,6 +27,7 @@ export class MultiProtocolRouterApp<
// enabling extensible generic types // enabling extensible generic types
if (protocol === ProtocolType.Ethereum) return EvmRouterAdapter as any; if (protocol === ProtocolType.Ethereum) return EvmRouterAdapter as any;
if (protocol === ProtocolType.Sealevel) return SealevelRouterAdapter as any; if (protocol === ProtocolType.Sealevel) return SealevelRouterAdapter as any;
// TODO cosmos support here
throw new Error(`No adapter for protocol ${protocol}`); throw new Error(`No adapter for protocol ${protocol}`);
} }

@ -0,0 +1,398 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable no-console */
import {
CosmWasmClient,
ExecuteInstruction,
SigningCosmWasmClient,
} from '@cosmjs/cosmwasm-stargate';
import { Secp256k1, keccak256 } from '@cosmjs/crypto';
import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing';
import { GasPrice, SigningStargateClient } from '@cosmjs/stargate';
import { Tendermint37Client } from '@cosmjs/tendermint-rpc';
import { Address } from '@hyperlane-xyz/utils';
import { chainMetadata } from '../../consts/chainMetadata';
import { Chains } from '../../consts/chains';
import { CosmWasmCoreAdapter } from '../../core/adapters/CosmWasmCoreAdapter';
import {
MailboxResponse,
QueryMsg as MerkleQuery,
OwnerResponse,
} from '../../cw-types/HookMerkle.types';
import { CosmWasmMultisigAdapter } from '../../ism/adapters/CosmWasmMultisigAdapter';
import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider';
const neutronAddresses = {
mailbox: 'neutron1sjzzd4gwkggy6hrrs8kxxatexzcuz3jecsxm3wqgregkulzj8r7qlnuef4',
validatorAnnounce:
'neutron17w4q6efzym3p4c6umyp4cjf2ustjtmwfqdhd7rt2fpcpk9fmjzsq0kj0f8',
};
const neutron = chainMetadata.neutron;
const mantapacific = chainMetadata.mantapacific;
const multiProtocolProvider = new MultiProtocolProvider();
const adapter = new CosmWasmCoreAdapter(
Chains.neutron,
multiProtocolProvider,
neutronAddresses,
);
export async function getSigningClient(pkey: string) {
const wallet = await DirectSecp256k1Wallet.fromKey(
Buffer.from(pkey, 'hex'),
neutron.bech32Prefix!,
);
const [account] = await wallet.getAccounts();
const clientBase = await Tendermint37Client.connect(neutron.rpcUrls[0].http);
const gasPrice = GasPrice.fromString('0.1untrn');
const wasm = await SigningCosmWasmClient.createWithSigner(
clientBase,
wallet,
{
gasPrice,
},
);
const stargate = await SigningStargateClient.createWithSigner(
clientBase,
wallet,
{
gasPrice,
},
);
const pubkey = Secp256k1.uncompressPubkey(account.pubkey);
const ethaddr = keccak256(pubkey.slice(1)).slice(-20);
return {
wasm,
stargate,
signer: account.address,
signer_addr: Buffer.from(ethaddr).toString('hex'),
signer_pubkey: Buffer.from(account.pubkey).toString('hex'),
};
}
const initTransferOwner = (
address: Address,
newOwner: Address,
key = 'ownable',
): ExecuteInstruction => {
return {
contractAddress: address,
msg: {
[key]: {
init_ownership_transfer: {
next_owner: newOwner,
},
},
},
};
};
const claimTransferOwner = (
address: Address,
key = 'ownable',
): ExecuteInstruction => {
return {
contractAddress: address,
msg: {
[key]: {
claim_ownership: {},
},
},
};
};
const getOwner = async (
provider: CosmWasmClient,
address: Address,
): Promise<Address> => {
const ownableQuery = {
ownable: { get_owner: {} },
};
const ownerResponse: OwnerResponse = await provider.queryContractSmart(
address,
ownableQuery,
);
return ownerResponse.owner;
};
export async function rotateHooks() {
const desiredDefault =
'neutron1e5c2qqquc86rd3q77aj2wyht40z6z3q5pclaq040ue9f5f8yuf7qnpvkzk';
const desiredRequired =
'neutron19qjplhq7jsmk7haneafqxyyhltgllvvag8c4g7jkmxw6mvd4h8sq7rqh02';
const safe = await getSigningClient(
'2ac7230628b8b4a587c4005798184735471b9240fc57fc75d97824e1fb6b5409',
);
const tx = await safe.wasm.executeMultiple(
safe.signer,
[
adapter.setDefaultHook(desiredDefault),
adapter.setRequiredHook(desiredRequired),
],
'auto',
);
console.log(tx);
}
export async function rotateAuth() {
const safe = await getSigningClient(
'2ac7230628b8b4a587c4005798184735471b9240fc57fc75d97824e1fb6b5409',
);
const desiredOwner =
'neutron1fqf5mprg3f5hytvzp3t7spmsum6rjrw80mq8zgkc0h6rxga0dtzqws3uu7';
const addresses: string[] = [
'neutron1sjzzd4gwkggy6hrrs8kxxatexzcuz3jecsxm3wqgregkulzj8r7qlnuef4', // mailbox
'neutron17w4q6efzym3p4c6umyp4cjf2ustjtmwfqdhd7rt2fpcpk9fmjzsq0kj0f8', // validator announce
'neutron1q75ky8reksqzh0lkhk9k3csvjwv74jjquahrj233xc7dvzz5fv4qtvw0qg', // multisig ISM
'neutron1e5c2qqquc86rd3q77aj2wyht40z6z3q5pclaq040ue9f5f8yuf7qnpvkzk', // merkle
'neutron19qjplhq7jsmk7haneafqxyyhltgllvvag8c4g7jkmxw6mvd4h8sq7rqh02', // pausable
'neutron1ch7x3xgpnj62weyes8vfada35zff6z59kt2psqhnx9gjnt2ttqdqtva3pa', // warp route
];
const transferInstructions: ExecuteInstruction[] = [];
const claimInstructions: ExecuteInstruction[] = [];
for (const address of addresses) {
const info = await safe.wasm.getContract(address);
console.log({ address, info });
try {
await getOwner(safe.wasm, address);
const transferInstruction = initTransferOwner(address, desiredOwner);
transferInstructions.push(transferInstruction);
const claimInstruction = claimTransferOwner(address);
claimInstructions.push(claimInstruction);
} catch (e: any) {
if (e.message.includes('unknown variant `ownable`')) {
console.log(
`Skipping ${info.label} (${address}) because it is not ownable`,
);
} else {
throw e;
}
}
// }
console.log(JSON.stringify({ transferInstructions, claimInstructions }));
// const tx = await safe.wasm.executeMultiple(
// safe.signer,
// transferInstructions,
// 'auto',
// );
// console.log(tx);
// const claimTx = await safe.wasm.execute(
// safe.signer,
// address,
// claimInstruction.msg,
// 'auto',
// );
// console.log(claimTx);
const res = await safe.wasm.updateAdmin(
safe.signer,
address,
desiredOwner,
'auto',
);
console.log(res);
}
}
export async function summary() {
const summary: any = {};
const provider = await adapter.getProvider();
const getOwner = async (address: Address): Promise<Address> => {
const ownableQuery = {
ownable: { get_owner: {} },
};
const ownerResponse: OwnerResponse = await provider.queryContractSmart(
address,
ownableQuery,
);
return ownerResponse.owner;
};
const owner = await getOwner(neutronAddresses.mailbox);
const info = await provider.getContract(neutronAddresses.mailbox);
const defaultHook = await adapter.defaultHook();
const requiredHook = await adapter.requiredHook();
const defaultIsm = await adapter.defaultIsm();
summary.mailbox = {
owner,
...info,
defaultHook,
requiredHook,
defaultIsm,
};
const router =
'neutron1ch7x3xgpnj62weyes8vfada35zff6z59kt2psqhnx9gjnt2ttqdqtva3pa';
summary.warproute = {
owner: await getOwner(router),
...(await provider.getContract(router)),
};
summary.validatorAnnounce = {
// owner: await getOwner(neutronAddresses.validatorAnnounce),
...(await provider.getContract(neutronAddresses.validatorAnnounce)),
};
const defaultIsmContract = await provider.getContract(defaultIsm);
if (defaultIsmContract.label === 'hpl_ism_multisig') {
const multisigAdapter = new CosmWasmMultisigAdapter(
neutron.name,
multiProtocolProvider,
{ multisig: defaultIsm },
);
const multisigConfig = await multisigAdapter.getConfig(mantapacific.name);
const owner = await getOwner(defaultIsm);
summary.defaultIsm = {
...multisigConfig,
...defaultIsmContract,
owner,
};
}
const getMailbox = async (hook: Address): Promise<Address> => {
const merkleMailboxQuery: MerkleQuery = {
hook: {
mailbox: {},
},
};
const merkleMailboxResponse: MailboxResponse =
await provider.queryContractSmart(hook, merkleMailboxQuery);
return merkleMailboxResponse.mailbox;
};
const requiredHookContract = await provider.getContract(requiredHook);
if (requiredHookContract.label === 'hpl_hook_pausable') {
summary.requiredHook = {
...requiredHookContract,
owner: await getOwner(requiredHook),
mailbox: await getMailbox(requiredHook),
};
}
// else if (requiredHookContract.label === 'hpl_hook_aggregate') {
// const aggregateHookQuery: AggregateQuery = {
// aggregate_hook: {
// hooks: {},
// },
// };
// const hooksResponse: HooksResponse = await provider.queryContractSmart(
// requiredHook,
// aggregateHookQuery,
// );
// summary.requiredHook = {
// ...requiredHookContract,
// hooks: hooksResponse.hooks,
// owner: await getOwner(requiredHook),
// mailbox: await getMailbox(requiredHook),
// };
const defaultHookContract = await provider.getContract(defaultHook);
if (defaultHookContract.label === 'hpl_hook_merkle') {
summary.defaultHook = defaultHookContract;
}
// for (const hook of hooksResponse.hooks) {
// const hook = defaultHook;
// const hookContract = await provider.getContract(hook);
// if (hookContract.label === 'hpl_hook_merkle') {
// // summary.requiredHook.merkleHook = {
// summary.merkleHook = {
// ...hookContract,
// mailbox: await getMailbox(hook),
// owner: await getOwner(hook),
// };
// }
// } else if (hookContract.label === 'hpl_igp') {
// const igpAdapter = new CosmWasmIgpAdapter(
// neutron.name,
// multiProtocolProvider,
// { igp: hook },
// );
// const oracles = await igpAdapter.getOracles();
// const defaultGas = await igpAdapter.defaultGas();
// const beneficiary = await igpAdapter.beneficiary();
// const mantaData = await igpAdapter.getOracleData(mantapacific.name);
// const igpOracle = oracles[mantapacific.name];
// summary.requiredHook.igpHook = {
// oracles,
// mantaOracle: {
// ...mantaData,
// owner: await getOwner(igpOracle),
// ...(await provider.getContract(igpOracle)),
// },
// defaultGas,
// beneficiary,
// mailbox: await getMailbox(hook),
// owner: await getOwner(hook),
// ...hookContract,
// };
// }
// }
console.log(JSON.stringify(summary));
}
export async function rotateValidators() {
const multisigAdapter = new CosmWasmMultisigAdapter(
neutron.name,
multiProtocolProvider,
{
multisig:
'neutron1q75ky8reksqzh0lkhk9k3csvjwv74jjquahrj233xc7dvzz5fv4qtvw0qg',
},
);
const instructions = await multisigAdapter.configureMultisig({
[mantapacific.name]: {
threshold: 5,
validators: [
'8e668c97ad76d0e28375275c41ece4972ab8a5bc', // hyperlane
'521a3e6bf8d24809fde1c1fd3494a859a16f132c', // cosmosstation
'25b9a0961c51e74fd83295293bc029131bf1e05a', // neutron (pablo)
'14025fe092f5f8a401dd9819704d9072196d2125', // p2p
'a0ee95e280d46c14921e524b075d0c341e7ad1c8', // cosmos spaces
'cc9a0b6de7fe314bd99223687d784730a75bb957', // dsrv
'42b6de2edbaa62c2ea2309ad85d20b3e37d38acf', // sg-1
],
},
});
console.log(JSON.stringify(instructions));
// const safe = await getSigningClient(
// '2ac7230628b8b4a587c4005798184735471b9240fc57fc75d97824e1fb6b5409',
// );
// const tx = await safe.wasm.executeMultiple(safe.signer, instructions, 'auto');
// console.log(tx);
}
summary().catch(console.error);

@ -0,0 +1,409 @@
import { ExecuteInstruction } from '@cosmjs/cosmwasm-stargate';
import { Coin } from '@cosmjs/stargate';
import {
Address,
Domain,
addressToBytes32,
strip0x,
} from '@hyperlane-xyz/utils';
import { BaseCosmWasmAdapter } from '../../app/MultiProtocolApp';
import {
BalanceResponse,
ExecuteMsg as Cw20Execute,
QueryMsg as Cw20Query,
TokenInfoResponse,
} from '../../cw-types/Cw20Base.types';
import {
DomainsResponse,
InterchainSecurityModuleResponse,
OwnerResponse,
RouteResponseForHexBinary,
RoutesResponseForHexBinary,
TokenType,
TokenTypeResponse,
ExecuteMsg as WarpCw20Execute,
QueryMsg as WarpCw20Query,
} from '../../cw-types/WarpCw20.types';
import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider';
import { ChainName } from '../../types';
import { ERC20Metadata } from '../config';
import {
IHypTokenAdapter,
ITokenAdapter,
TransferParams,
TransferRemoteParams,
} from './ITokenAdapter';
// Interacts with IBC denom tokens in CosmWasm
export class CwNativeTokenAdapter
extends BaseCosmWasmAdapter
implements ITokenAdapter
{
constructor(
public readonly chainName: string,
public readonly multiProvider: MultiProtocolProvider,
public readonly addresses: Record<string, Address>,
public readonly ibcDenom: string = 'untrn',
) {
super(chainName, multiProvider, addresses);
}
async getBalance(address: Address): Promise<string> {
const provider = await this.getProvider();
const balance = await provider.getBalance(address, this.ibcDenom);
return balance.amount;
}
async getMetadata(): Promise<CW20Metadata> {
throw new Error('Metadata not available to native tokens');
}
async populateApproveTx(
_params: TransferParams,
): Promise<ExecuteInstruction> {
throw new Error('Approve not required for native tokens');
}
async populateTransferTx({
recipient,
weiAmountOrId,
}: TransferParams): Promise<ExecuteInstruction> {
// TODO: check if this works with execute instruction? (contract type, empty message)
return {
contractAddress: recipient,
msg: {},
funds: [
{
amount: weiAmountOrId.toString(),
denom: this.ibcDenom,
},
],
};
}
}
export type CW20Metadata = ERC20Metadata;
type CW20Response = TokenInfoResponse | BalanceResponse;
// Interacts with CW20/721 contracts
export class CwTokenAdapter
extends BaseCosmWasmAdapter
implements ITokenAdapter
{
constructor(
public readonly chainName: string,
public readonly multiProvider: MultiProtocolProvider,
public readonly addresses: { token: Address },
public readonly denom = 'untrn',
) {
super(chainName, multiProvider, addresses);
}
async queryToken<R extends CW20Response>(msg: Cw20Query): Promise<R> {
const provider = await this.getProvider();
const response: R = await provider.queryContractSmart(
this.addresses.token,
msg,
);
return response;
}
prepareToken(msg: Cw20Execute, funds?: Coin[]): ExecuteInstruction {
return {
contractAddress: this.addresses.token,
msg,
funds,
};
}
async getBalance(address: Address): Promise<string> {
const resp = await this.queryToken<BalanceResponse>({
balance: {
address,
},
});
return resp.balance;
}
async getMetadata(): Promise<CW20Metadata> {
const resp = await this.queryToken<TokenInfoResponse>({
token_info: {},
});
return {
...resp,
totalSupply: resp.total_supply,
};
}
async populateApproveTx({
weiAmountOrId,
recipient,
}: TransferParams): Promise<ExecuteInstruction> {
// TODO: check existing allowance
return this.prepareToken({
increase_allowance: {
spender: recipient,
amount: weiAmountOrId.toString(),
expires: {
never: {},
},
},
});
}
async populateTransferTx({
weiAmountOrId,
recipient,
}: TransferParams): Promise<ExecuteInstruction> {
return this.prepareToken({
transfer: {
recipient,
amount: weiAmountOrId.toString(),
},
});
}
}
type TokenRouterResponse =
| TokenTypeResponse
| InterchainSecurityModuleResponse
| DomainsResponse
| OwnerResponse
| RouteResponseForHexBinary
| RoutesResponseForHexBinary;
export class CwHypSyntheticAdapter
extends CwTokenAdapter
implements IHypTokenAdapter
{
constructor(
public readonly chainName: ChainName,
public readonly multiProvider: MultiProtocolProvider<any>,
public readonly addresses: { token: Address; warpRouter: Address },
public readonly gasDenom = 'untrn',
) {
super(chainName, multiProvider, addresses);
}
async queryRouter<R extends TokenRouterResponse>(
msg: WarpCw20Query,
): Promise<R> {
const provider = await this.getProvider();
const response: R = await provider.queryContractSmart(
this.addresses.warpRouter,
msg,
);
return response;
}
prepareRouter(msg: WarpCw20Execute, funds?: Coin[]): ExecuteInstruction {
return {
contractAddress: this.addresses.warpRouter,
msg,
funds,
};
}
async tokenType(): Promise<TokenType> {
const resp = await this.queryRouter<TokenTypeResponse>({
token_default: {
token_type: {},
},
});
return resp.type;
}
async interchainSecurityModule(): Promise<Address> {
throw new Error('Router does not support ISM config yet.');
}
async owner(): Promise<Address> {
const resp = await this.queryRouter<OwnerResponse>({
ownable: {
get_owner: {},
},
});
return resp.owner;
}
async getDomains(): Promise<Domain[]> {
const resp = await this.queryRouter<DomainsResponse>({
router: {
domains: {},
},
});
return resp.domains;
}
async getRouterAddress(domain: Domain): Promise<Buffer> {
const resp = await this.queryRouter<RouteResponseForHexBinary>({
router: {
get_route: {
domain,
},
},
});
const route = resp.route.route;
if (!route) {
throw new Error(`No route found for domain ${domain}`);
}
return Buffer.from(route, 'hex');
}
async getAllRouters(): Promise<Array<{ domain: Domain; address: Buffer }>> {
const resp = await this.queryRouter<RoutesResponseForHexBinary>({
router: {
list_routes: {},
},
});
return resp.routes
.filter((r) => r.route != null)
.map((r) => ({
domain: r.domain,
address: Buffer.from(r.route!, 'hex'),
}));
}
quoteGasPayment(_destination: number): Promise<string> {
throw new Error('Method not implemented.');
}
populateTransferRemoteTx({
destination,
recipient,
weiAmountOrId,
txValue,
}: TransferRemoteParams): ExecuteInstruction {
if (!txValue) {
throw new Error('txValue is required for native tokens');
}
return this.prepareRouter(
{
transfer_remote: {
dest_domain: destination,
recipient: strip0x(addressToBytes32(recipient)),
amount: weiAmountOrId.toString(),
},
},
[
{
amount: txValue.toString(),
denom: this.gasDenom,
},
],
);
}
}
export class CwHypNativeAdapter
extends CwNativeTokenAdapter
implements IHypTokenAdapter
{
private readonly cw20adapter: CwHypSyntheticAdapter;
constructor(
public readonly chainName: ChainName,
public readonly multiProvider: MultiProtocolProvider<any>,
public readonly addresses: { warpRouter: Address },
public readonly gasDenom = 'untrn',
) {
super(chainName, multiProvider, addresses, gasDenom);
this.cw20adapter = new CwHypSyntheticAdapter(
chainName,
multiProvider,
{ token: '', warpRouter: addresses.warpRouter },
gasDenom,
);
}
async getBalance(address: string): Promise<string> {
const provider = await this.getProvider();
const denom = await this.denom();
const balance = await provider.getBalance(address, denom);
return balance.amount;
}
async interchainSecurityModule(): Promise<Address> {
return this.cw20adapter.interchainSecurityModule();
}
async owner(): Promise<Address> {
return this.cw20adapter.owner();
}
async getDomains(): Promise<Domain[]> {
return this.cw20adapter.getDomains();
}
async getRouterAddress(domain: Domain): Promise<Buffer> {
return this.cw20adapter.getRouterAddress(domain);
}
async getAllRouters(): Promise<Array<{ domain: Domain; address: Buffer }>> {
return this.cw20adapter.getAllRouters();
}
quoteGasPayment(destination: number): Promise<string> {
return this.cw20adapter.quoteGasPayment(destination);
}
async denom(): Promise<string> {
const tokenType = await this.cw20adapter.tokenType();
if ('native' in tokenType) {
if ('fungible' in tokenType.native) {
return tokenType.native.fungible.denom;
}
}
throw new Error(`Token type not supported: ${tokenType}`);
}
async populateTransferRemoteTx({
destination,
recipient,
weiAmountOrId,
txValue,
}: TransferRemoteParams): Promise<ExecuteInstruction> {
if (!txValue) {
throw new Error('txValue is required for native tokens');
}
const collateralDenom = await this.denom();
return this.cw20adapter.prepareRouter(
{
transfer_remote: {
dest_domain: destination,
recipient: strip0x(addressToBytes32(recipient)),
amount: weiAmountOrId.toString(),
},
},
[
{
amount: weiAmountOrId.toString(),
denom: collateralDenom,
},
{
amount: txValue.toString(),
denom: this.gasDenom,
},
],
);
}
}
export class CwHypCollateralAdapter
extends CwHypNativeAdapter
implements IHypTokenAdapter
{
constructor(
public readonly chainName: ChainName,
public readonly multiProvider: MultiProtocolProvider<any>,
public readonly addresses: { warpRouter: Address; token: Address },
public readonly gasDenom = 'untrn',
) {
super(chainName, multiProvider, addresses, gasDenom);
}
}

@ -0,0 +1,65 @@
import { MsgTransferEncodeObject } from '@cosmjs/stargate';
import { MsgTransfer } from 'cosmjs-types/ibc/applications/transfer/v1/tx';
import { Address } from '@hyperlane-xyz/utils';
import { BaseCosmosAdapter } from '../../app/MultiProtocolApp';
import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider';
import { MinimalTokenMetadata } from '../config';
import { ITokenAdapter, TransferParams } from './ITokenAdapter';
// Interacts with IBC denom tokens
export class NativeTokenAdapter
extends BaseCosmosAdapter
implements ITokenAdapter
{
constructor(
public readonly chainName: string,
public readonly multiProvider: MultiProtocolProvider,
public readonly addresses: Record<string, Address>,
public readonly ibcDenom: string = 'untrn',
) {
super(chainName, multiProvider, addresses);
}
async getBalance(address: string): Promise<string> {
const provider = await this.getProvider();
const coin = await provider.getBalance(address, this.ibcDenom);
return coin.amount;
}
getMetadata(): Promise<MinimalTokenMetadata> {
throw new Error('Metadata not available to native tokens');
}
populateApproveTx(_transferParams: TransferParams): unknown {
throw new Error('Approve not required for native tokens');
}
async populateTransferTx(
transferParams: TransferParams,
): Promise<MsgTransferEncodeObject> {
const transfer: MsgTransfer = {
sourcePort: '',
sourceChannel: '',
token: {
denom: this.ibcDenom,
amount: transferParams.weiAmountOrId.toString(),
},
sender: '',
receiver: '',
timeoutHeight: {
revisionNumber: 0n,
revisionHeight: 0n,
},
timeoutTimestamp: 0n,
memo: '', // how to encode this?
};
return {
typeUrl: '/ibc.applications.transfer.v1.MsgTransfer',
// @ts-ignore
value: transfer,
};
}
}

@ -162,7 +162,7 @@ export class SealevelTokenAdapter
// we generously request 1M units. // we generously request 1M units.
const TRANSFER_REMOTE_COMPUTE_LIMIT = 1_000_000; const TRANSFER_REMOTE_COMPUTE_LIMIT = 1_000_000;
export abstract class SealevelHypTokenAdapter abstract class SealevelHypTokenAdapter
extends SealevelTokenAdapter extends SealevelTokenAdapter
implements IHypTokenAdapter implements IHypTokenAdapter
{ {

@ -1,20 +1,27 @@
import type { Chain as WagmiChain } from '@wagmi/chains'; import type { Chain as WagmiChain } from '@wagmi/chains';
import { objMap } from '@hyperlane-xyz/utils'; import { ProtocolType, objFilter, objMap } from '@hyperlane-xyz/utils';
import { chainMetadata, etherToken } from '../consts/chainMetadata'; import { chainMetadata, etherToken } from '../consts/chainMetadata';
import type { ChainMetadata } from '../metadata/chainMetadataTypes'; import {
ChainMetadata,
getChainIdNumber,
} from '../metadata/chainMetadataTypes';
import type { ChainMap } from '../types'; import type { ChainMap } from '../types';
// For convenient use in wagmi-based apps // For convenient use in wagmi-based apps
export const wagmiChainMetadata: ChainMap<WagmiChain> = objMap( export const wagmiChainMetadata: ChainMap<WagmiChain> = objMap(
objFilter(
chainMetadata, chainMetadata,
(_, metadata): metadata is ChainMetadata =>
metadata.protocol === ProtocolType.Ethereum,
),
(_, metadata) => chainMetadataToWagmiChain(metadata), (_, metadata) => chainMetadataToWagmiChain(metadata),
); );
export function chainMetadataToWagmiChain(metadata: ChainMetadata): WagmiChain { export function chainMetadataToWagmiChain(metadata: ChainMetadata): WagmiChain {
return { return {
id: metadata.chainId, id: getChainIdNumber(metadata),
name: metadata.displayName || metadata.name, name: metadata.displayName || metadata.name,
network: metadata.name as string, network: metadata.name as string,
nativeCurrency: metadata.nativeToken || etherToken, nativeCurrency: metadata.nativeToken || etherToken,

@ -2,27 +2,36 @@ export {
addressToByteHexString, addressToByteHexString,
addressToBytes, addressToBytes,
addressToBytes32, addressToBytes32,
addressToBytesCosmos,
addressToBytesEvm, addressToBytesEvm,
addressToBytesSol, addressToBytesSol,
bytes32ToAddress, bytes32ToAddress,
bytesToAddressCosmos,
bytesToAddressEvm,
bytesToAddressSol,
bytesToProtocolAddress, bytesToProtocolAddress,
capitalizeAddress, capitalizeAddress,
convertToProtocolAddress, convertToProtocolAddress,
ensure0x, ensure0x,
eqAddress, eqAddress,
eqAddressCosmos,
eqAddressEvm, eqAddressEvm,
eqAddressSol, eqAddressSol,
getAddressProtocolType, getAddressProtocolType,
isAddressCosmos,
isAddressEvm, isAddressEvm,
isAddressSealevel, isAddressSealevel,
isValidAddress, isValidAddress,
isValidAddressCosmos,
isValidAddressEvm, isValidAddressEvm,
isValidAddressSealevel, isValidAddressSealevel,
isValidTransactionHash, isValidTransactionHash,
isValidTransactionHashCosmos,
isValidTransactionHashEvm, isValidTransactionHashEvm,
isValidTransactionHashSealevel, isValidTransactionHashSealevel,
isZeroishAddress, isZeroishAddress,
normalizeAddress, normalizeAddress,
normalizeAddressCosmos,
normalizeAddressEvm, normalizeAddressEvm,
normalizeAddressSealevel, normalizeAddressSealevel,
shortenAddress, shortenAddress,

@ -1,8 +1,9 @@
{ {
"name": "@hyperlane-xyz/utils", "name": "@hyperlane-xyz/utils",
"description": "General utilities and types for the Hyperlane network", "description": "General utilities and types for the Hyperlane network",
"version": "1.5.4-beta0", "version": "3.1.0-beta0",
"dependencies": { "dependencies": {
"@cosmjs/encoding": "^0.31.3",
"@solana/web3.js": "^1.78.0", "@solana/web3.js": "^1.78.0",
"bignumber.js": "^9.1.1", "bignumber.js": "^9.1.1",
"ethers": "^5.7.2" "ethers": "^5.7.2"

@ -1,3 +1,4 @@
import { fromBech32, normalizeBech32, toBech32 } from '@cosmjs/encoding';
import { PublicKey } from '@solana/web3.js'; import { PublicKey } from '@solana/web3.js';
import { utils as ethersUtils } from 'ethers'; import { utils as ethersUtils } from 'ethers';
@ -5,11 +6,16 @@ import { Address, HexString, ProtocolType } from './types';
const EVM_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/; const EVM_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
const SEALEVEL_ADDRESS_REGEX = /^[a-zA-Z0-9]{36,44}$/; const SEALEVEL_ADDRESS_REGEX = /^[a-zA-Z0-9]{36,44}$/;
const COSMOS_ADDRESS_REGEX =
/^[a-z]{1,10}1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38,58}$/; // Bech32
export const IBC_DENOM_REGEX = /^ibc\/([A-Fa-f0-9]{64})$/;
const EVM_TX_HASH_REGEX = /^0x([A-Fa-f0-9]{64})$/; const EVM_TX_HASH_REGEX = /^0x([A-Fa-f0-9]{64})$/;
const SEALEVEL_TX_HASH_REGEX = /^[a-zA-Z1-9]{88}$/; const SEALEVEL_TX_HASH_REGEX = /^[a-zA-Z1-9]{88}$/;
const COSMOS_TX_HASH_REGEX = /^(0x)?[A-Fa-f0-9]{64}$/;
const ZEROISH_ADDRESS_REGEX = /^(0x)?0*$/; const ZEROISH_ADDRESS_REGEX = /^(0x)?0*$/;
const COSMOS_ZEROISH_ADDRESS_REGEX = /^[a-z]{1,10}?1[0]{38}$/;
export function isAddressEvm(address: Address) { export function isAddressEvm(address: Address) {
return EVM_ADDRESS_REGEX.test(address); return EVM_ADDRESS_REGEX.test(address);
@ -19,10 +25,16 @@ export function isAddressSealevel(address: Address) {
return SEALEVEL_ADDRESS_REGEX.test(address); return SEALEVEL_ADDRESS_REGEX.test(address);
} }
export function isAddressCosmos(address: Address) {
return COSMOS_ADDRESS_REGEX.test(address) || IBC_DENOM_REGEX.test(address);
}
export function getAddressProtocolType(address: Address) { export function getAddressProtocolType(address: Address) {
if (!address) return undefined; if (!address) return undefined;
if (isAddressEvm(address)) { if (isAddressEvm(address)) {
return ProtocolType.Ethereum; return ProtocolType.Ethereum;
} else if (isAddressCosmos(address)) {
return ProtocolType.Cosmos;
} else if (isAddressSealevel(address)) { } else if (isAddressSealevel(address)) {
return ProtocolType.Sealevel; return ProtocolType.Sealevel;
} else { } else {
@ -31,20 +43,15 @@ export function getAddressProtocolType(address: Address) {
} }
function routeAddressUtil<T>( function routeAddressUtil<T>(
evmFn: (param: string) => T, fns: Partial<Record<ProtocolType, (param: string) => T>>,
sealevelFn: (param: string) => T,
fallback: T,
param: string, param: string,
fallback?: T,
protocol?: ProtocolType, protocol?: ProtocolType,
) { ) {
protocol = protocol || getAddressProtocolType(param); protocol ||= getAddressProtocolType(param);
if (protocol === ProtocolType.Ethereum) { if (protocol && fns[protocol]) return fns[protocol]!(param);
return evmFn(param); else if (fallback) return fallback;
} else if (protocol === ProtocolType.Sealevel) { else throw new Error(`Unsupported protocol ${protocol}`);
return sealevelFn(param);
} else {
return fallback;
}
} }
// Slower than isAddressEvm above but actually validates content and checksum // Slower than isAddressEvm above but actually validates content and checksum
@ -68,12 +75,26 @@ export function isValidAddressSealevel(address: Address) {
} }
} }
// Slower than isAddressCosmos above but actually validates content and checksum
export function isValidAddressCosmos(address: Address) {
try {
const isValid =
address && (IBC_DENOM_REGEX.test(address) || fromBech32(address));
return !!isValid;
} catch (error) {
return false;
}
}
export function isValidAddress(address: Address, protocol?: ProtocolType) { export function isValidAddress(address: Address, protocol?: ProtocolType) {
return routeAddressUtil( return routeAddressUtil(
isValidAddressEvm, {
isValidAddressSealevel, [ProtocolType.Ethereum]: isValidAddressEvm,
false, [ProtocolType.Sealevel]: isValidAddressSealevel,
[ProtocolType.Cosmos]: isValidAddressCosmos,
},
address, address,
false,
protocol, protocol,
); );
} }
@ -96,10 +117,22 @@ export function normalizeAddressSealevel(address: Address) {
} }
} }
export function normalizeAddressCosmos(address: Address) {
if (isZeroishAddress(address)) return address;
try {
return normalizeBech32(address);
} catch (error) {
return address;
}
}
export function normalizeAddress(address: Address, protocol?: ProtocolType) { export function normalizeAddress(address: Address, protocol?: ProtocolType) {
return routeAddressUtil( return routeAddressUtil(
normalizeAddressEvm, {
normalizeAddressSealevel, [ProtocolType.Ethereum]: normalizeAddressEvm,
[ProtocolType.Sealevel]: normalizeAddressSealevel,
[ProtocolType.Cosmos]: normalizeAddressCosmos,
},
address, address,
address, address,
protocol, protocol,
@ -114,15 +147,22 @@ export function eqAddressSol(a1: Address, a2: Address) {
return normalizeAddressSealevel(a1) === normalizeAddressSealevel(a2); return normalizeAddressSealevel(a1) === normalizeAddressSealevel(a2);
} }
export function eqAddressCosmos(a1: Address, a2: Address) {
return normalizeAddressCosmos(a1) === normalizeAddressCosmos(a2);
}
export function eqAddress(a1: Address, a2: Address) { export function eqAddress(a1: Address, a2: Address) {
const p1 = getAddressProtocolType(a1); const p1 = getAddressProtocolType(a1);
const p2 = getAddressProtocolType(a2); const p2 = getAddressProtocolType(a2);
if (p1 !== p2) return false; if (p1 !== p2) return false;
return routeAddressUtil( return routeAddressUtil(
(_a1) => eqAddressEvm(_a1, a2), {
(_a1) => eqAddressSol(_a1, a2), [ProtocolType.Ethereum]: (_a1) => eqAddressEvm(_a1, a2),
false, [ProtocolType.Sealevel]: (_a1) => eqAddressSol(_a1, a2),
[ProtocolType.Cosmos]: (_a1) => eqAddressCosmos(_a1, a2),
},
a1, a1,
false,
p1, p1,
); );
} }
@ -135,18 +175,27 @@ export function isValidTransactionHashSealevel(input: string) {
return SEALEVEL_TX_HASH_REGEX.test(input); return SEALEVEL_TX_HASH_REGEX.test(input);
} }
export function isValidTransactionHashCosmos(input: string) {
return COSMOS_TX_HASH_REGEX.test(input);
}
export function isValidTransactionHash(input: string, protocol: ProtocolType) { export function isValidTransactionHash(input: string, protocol: ProtocolType) {
if (protocol === ProtocolType.Ethereum) { if (protocol === ProtocolType.Ethereum) {
return isValidTransactionHashEvm(input); return isValidTransactionHashEvm(input);
} else if (protocol === ProtocolType.Sealevel) { } else if (protocol === ProtocolType.Sealevel) {
return isValidTransactionHashSealevel(input); return isValidTransactionHashSealevel(input);
} else if (protocol === ProtocolType.Cosmos) {
return isValidTransactionHashCosmos(input);
} else { } else {
return false; return false;
} }
} }
export function isZeroishAddress(address: Address) { export function isZeroishAddress(address: Address) {
return ZEROISH_ADDRESS_REGEX.test(address); return (
ZEROISH_ADDRESS_REGEX.test(address) ||
COSMOS_ZEROISH_ADDRESS_REGEX.test(address)
);
} }
export function shortenAddress(address: Address, capitalize?: boolean) { export function shortenAddress(address: Address, capitalize?: boolean) {
@ -166,31 +215,40 @@ export function capitalizeAddress(address: Address) {
else return address.toUpperCase(); else return address.toUpperCase();
} }
// For EVM addresses only, kept for backwards compatibility and convenience
export function addressToBytes32(address: Address): string { export function addressToBytes32(address: Address): string {
return ethersUtils return ethersUtils
.hexZeroPad(ethersUtils.hexStripZeros(address), 32) .hexZeroPad(ethersUtils.hexStripZeros(address), 32)
.toLowerCase(); .toLowerCase();
} }
// For EVM addresses only, kept for backwards compatibility and convenience
export function bytes32ToAddress(bytes32: HexString): Address { export function bytes32ToAddress(bytes32: HexString): Address {
return ethersUtils.getAddress(bytes32.slice(-40)); return ethersUtils.getAddress(bytes32.slice(-40));
} }
export function addressToBytesEvm(address: Address): Uint8Array { export function addressToBytesEvm(address: Address): Uint8Array {
const addrBytes32 = addressToBytes32(address); const addrBytes32 = addressToBytes32(address);
return Buffer.from(addrBytes32.substring(2), 'hex'); return Buffer.from(strip0x(addrBytes32), 'hex');
} }
export function addressToBytesSol(address: Address): Uint8Array { export function addressToBytesSol(address: Address): Uint8Array {
return new PublicKey(address).toBytes(); return new PublicKey(address).toBytes();
} }
export function addressToBytesCosmos(address: Address): Uint8Array {
return fromBech32(address).data;
}
export function addressToBytes(address: Address, protocol?: ProtocolType) { export function addressToBytes(address: Address, protocol?: ProtocolType) {
return routeAddressUtil( return routeAddressUtil(
addressToBytesEvm, {
addressToBytesSol, [ProtocolType.Ethereum]: addressToBytesEvm,
new Uint8Array(), [ProtocolType.Sealevel]: addressToBytesSol,
[ProtocolType.Cosmos]: addressToBytesCosmos,
},
address, address,
new Uint8Array(),
protocol, protocol,
); );
} }
@ -199,17 +257,38 @@ export function addressToByteHexString(
address: string, address: string,
protocol?: ProtocolType, protocol?: ProtocolType,
) { ) {
return '0x' + Buffer.from(addressToBytes(address, protocol)).toString('hex'); return ensure0x(
Buffer.from(addressToBytes(address, protocol)).toString('hex'),
);
}
export function bytesToAddressEvm(bytes: Uint8Array): Address {
return bytes32ToAddress(Buffer.from(bytes).toString('hex'));
}
export function bytesToAddressSol(bytes: Uint8Array): Address {
return new PublicKey(bytes).toBase58();
}
export function bytesToAddressCosmos(
bytes: Uint8Array,
prefix: string,
): Address {
if (!prefix) throw new Error('Prefix required for Cosmos address');
return toBech32(prefix, bytes);
} }
export function bytesToProtocolAddress( export function bytesToProtocolAddress(
bytes: Buffer, bytes: Uint8Array,
toProtocol: ProtocolType, toProtocol: ProtocolType,
prefix?: string,
) { ) {
if (toProtocol === ProtocolType.Sealevel) { if (toProtocol === ProtocolType.Ethereum) {
return new PublicKey(bytes).toBase58(); return bytesToAddressEvm(bytes);
} else if (toProtocol === ProtocolType.Ethereum) { } else if (toProtocol === ProtocolType.Sealevel) {
return bytes32ToAddress(bytes.toString('hex')); return bytesToAddressSol(bytes);
} else if (toProtocol === ProtocolType.Cosmos) {
return bytesToAddressCosmos(bytes, prefix!);
} else { } else {
throw new Error(`Unsupported protocol for address ${toProtocol}`); throw new Error(`Unsupported protocol for address ${toProtocol}`);
} }
@ -218,30 +297,14 @@ export function bytesToProtocolAddress(
export function convertToProtocolAddress( export function convertToProtocolAddress(
address: string, address: string,
protocol: ProtocolType, protocol: ProtocolType,
prefix?: string,
) { ) {
const currentProtocol = getAddressProtocolType(address); const currentProtocol = getAddressProtocolType(address);
if (!currentProtocol)
throw new Error(`Unknown address protocol for ${address}`);
if (currentProtocol === protocol) return address; if (currentProtocol === protocol) return address;
if ( const addressBytes = addressToBytes(address, currentProtocol);
currentProtocol === ProtocolType.Ethereum && return bytesToProtocolAddress(addressBytes, protocol, prefix);
protocol === ProtocolType.Sealevel
) {
return new PublicKey(
addressToBytes(address, ProtocolType.Ethereum),
).toBase58();
} else if (
currentProtocol === ProtocolType.Sealevel &&
protocol === ProtocolType.Ethereum
) {
return bytes32ToAddress(
Buffer.from(addressToBytes(address, ProtocolType.Sealevel)).toString(
'hex',
),
);
} else {
throw new Error(
`Unsupported protocol combination ${currentProtocol} -> ${protocol}`,
);
}
} }
export function ensure0x(hexstr: string) { export function ensure0x(hexstr: string) {

@ -4,6 +4,7 @@ export enum ProtocolType {
Ethereum = 'ethereum', Ethereum = 'ethereum',
Sealevel = 'sealevel', Sealevel = 'sealevel',
Fuel = 'fuel', Fuel = 'fuel',
Cosmos = 'cosmos',
} }
// A type that also allows for literal values of the enum // A type that also allows for literal values of the enum
export type ProtocolTypeValue = `${ProtocolType}`; export type ProtocolTypeValue = `${ProtocolType}`;
@ -11,6 +12,7 @@ export type ProtocolTypeValue = `${ProtocolType}`;
export const ProtocolSmallestUnit = { export const ProtocolSmallestUnit = {
[ProtocolType.Ethereum]: 'wei', [ProtocolType.Ethereum]: 'wei',
[ProtocolType.Sealevel]: 'lamports', [ProtocolType.Sealevel]: 'lamports',
[ProtocolType.Cosmos]: 'uATOM',
}; };
/********* BASIC TYPES *********/ /********* BASIC TYPES *********/

@ -2758,6 +2758,173 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@confio/ics23@npm:^0.6.8":
version: 0.6.8
resolution: "@confio/ics23@npm:0.6.8"
dependencies:
"@noble/hashes": ^1.0.0
protobufjs: ^6.8.8
checksum: 376d72f6440db60611b002b00a13e3a5bfd0d3503e7682358dbcf79641e74d8c26c234c321452fb4a758baf66eecef25d950e08bdea270486d9d03ee489e2960
languageName: node
linkType: hard
"@cosmjs/amino@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/amino@npm:0.31.3"
dependencies:
"@cosmjs/crypto": ^0.31.3
"@cosmjs/encoding": ^0.31.3
"@cosmjs/math": ^0.31.3
"@cosmjs/utils": ^0.31.3
checksum: 30e55ed256e1ba8a84b8a92062fd48aed43b1d638b8917af8b28ae007a1eff3ffc9ffb743400db23c583dc2fefae12c3dd8b315451a09f6da9c10a07ce714dfa
languageName: node
linkType: hard
"@cosmjs/cosmwasm-stargate@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/cosmwasm-stargate@npm:0.31.3"
dependencies:
"@cosmjs/amino": ^0.31.3
"@cosmjs/crypto": ^0.31.3
"@cosmjs/encoding": ^0.31.3
"@cosmjs/math": ^0.31.3
"@cosmjs/proto-signing": ^0.31.3
"@cosmjs/stargate": ^0.31.3
"@cosmjs/tendermint-rpc": ^0.31.3
"@cosmjs/utils": ^0.31.3
cosmjs-types: ^0.8.0
long: ^4.0.0
pako: ^2.0.2
checksum: 7f5a4c809fb3b54fa70887a2e7cf2bc9c2a460891a1cd01f6721f8dbe43efa0d6611b642c2e3601c779295008dbe922e8a9985ffecc3bca55533fb43d83d000d
languageName: node
linkType: hard
"@cosmjs/crypto@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/crypto@npm:0.31.3"
dependencies:
"@cosmjs/encoding": ^0.31.3
"@cosmjs/math": ^0.31.3
"@cosmjs/utils": ^0.31.3
"@noble/hashes": ^1
bn.js: ^5.2.0
elliptic: ^6.5.4
libsodium-wrappers-sumo: ^0.7.11
checksum: e562bbcb7cce2c2992aa7fc808fb2b9bcc6d6a27b2567323f41349e7e1aca1b8a4e5b6e0442512cdd7e2bbe54f4b6a0b7ccf71eb574522d0bc405e609dcece8c
languageName: node
linkType: hard
"@cosmjs/encoding@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/encoding@npm:0.31.3"
dependencies:
base64-js: ^1.3.0
bech32: ^1.1.4
readonly-date: ^1.0.0
checksum: dadef0579828299be20a64edf820ac8770c0cc47a842594bc9b494f160a347b745941d795360755ccbe385b9d0912aa54753479d1a70ff762d2d334693952ff9
languageName: node
linkType: hard
"@cosmjs/json-rpc@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/json-rpc@npm:0.31.3"
dependencies:
"@cosmjs/stream": ^0.31.3
xstream: ^11.14.0
checksum: 6f050cf0d02f2a4f9df5391cc77e661684e5c7cc1df0fb71ae903984cb4f10cc765c08e866e417323910cbc63b91e30c38b7f2585ef5e473a8b086cddacc882a
languageName: node
linkType: hard
"@cosmjs/math@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/math@npm:0.31.3"
dependencies:
bn.js: ^5.2.0
checksum: 1685ad41ed78e78854649ca933817c56d39f4b36bba59b5dbdb1728048f431da5531265f4d77bfc9280cdea6c368817109b9f4540d5cfc2093f6ea6ff9e9a8d2
languageName: node
linkType: hard
"@cosmjs/proto-signing@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/proto-signing@npm:0.31.3"
dependencies:
"@cosmjs/amino": ^0.31.3
"@cosmjs/crypto": ^0.31.3
"@cosmjs/encoding": ^0.31.3
"@cosmjs/math": ^0.31.3
"@cosmjs/utils": ^0.31.3
cosmjs-types: ^0.8.0
long: ^4.0.0
checksum: c27c4d921c99f5c06ac92ebba59e78c53b7c115334932dd1365263b98c1a67c7323e3a69ae933babf5a36682c019bbc7da3c9597ca1bf1a4858546bdd681453a
languageName: node
linkType: hard
"@cosmjs/socket@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/socket@npm:0.31.3"
dependencies:
"@cosmjs/stream": ^0.31.3
isomorphic-ws: ^4.0.1
ws: ^7
xstream: ^11.14.0
checksum: 29cc5120732a3badd0d3e4358aa645aa6ad50fedf4a619e2a99a2ec85274bc6df9791f0fb9674417b6eca72762916e8f25277fafb318f3e0a77effa2c52da16b
languageName: node
linkType: hard
"@cosmjs/stargate@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/stargate@npm:0.31.3"
dependencies:
"@confio/ics23": ^0.6.8
"@cosmjs/amino": ^0.31.3
"@cosmjs/encoding": ^0.31.3
"@cosmjs/math": ^0.31.3
"@cosmjs/proto-signing": ^0.31.3
"@cosmjs/stream": ^0.31.3
"@cosmjs/tendermint-rpc": ^0.31.3
"@cosmjs/utils": ^0.31.3
cosmjs-types: ^0.8.0
long: ^4.0.0
protobufjs: ~6.11.3
xstream: ^11.14.0
checksum: 9b680d50f0818e3cfaffccd022d6034c283c1e350a1b8d8f74ffa22352e342ce1cb00533007ba7b5a6a1c1bc30fe327bd09c23ac8b7486691ad127a34c47690c
languageName: node
linkType: hard
"@cosmjs/stream@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/stream@npm:0.31.3"
dependencies:
xstream: ^11.14.0
checksum: 0d273604af4d7093b877582e223eedbcce4a1a4d7d9f80a4f5e215fd8be42ea6546f3778cc918cb0cdb144de52e7d8d4c476b9b4c6f678cebe914224f54d19ad
languageName: node
linkType: hard
"@cosmjs/tendermint-rpc@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/tendermint-rpc@npm:0.31.3"
dependencies:
"@cosmjs/crypto": ^0.31.3
"@cosmjs/encoding": ^0.31.3
"@cosmjs/json-rpc": ^0.31.3
"@cosmjs/math": ^0.31.3
"@cosmjs/socket": ^0.31.3
"@cosmjs/stream": ^0.31.3
"@cosmjs/utils": ^0.31.3
axios: ^0.21.2
readonly-date: ^1.0.0
xstream: ^11.14.0
checksum: 403e220ee4aeb65977a4416d48930d7381e3d4c10bf300fa6f07698c72b85a55f2314ba1a3d45849ce8549de2ff2005988188fc5fe60ac09188edbb89692115d
languageName: node
linkType: hard
"@cosmjs/utils@npm:^0.31.3":
version: 0.31.3
resolution: "@cosmjs/utils@npm:0.31.3"
checksum: 2ff2b270954ab00cc5ae8f23625b562676d0a061c8076905509a5f0701e302e46d24a51a0c3283072e0ce01fbd860baceb25e62303ff17826672fe5f8674b00d
languageName: node
linkType: hard
"@cspotcode/source-map-support@npm:^0.8.0": "@cspotcode/source-map-support@npm:^0.8.0":
version: 0.8.1 version: 0.8.1
resolution: "@cspotcode/source-map-support@npm:0.8.1" resolution: "@cspotcode/source-map-support@npm:0.8.1"
@ -3930,12 +4097,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@hyperlane-xyz/core@1.5.4-beta0, @hyperlane-xyz/core@workspace:solidity": "@hyperlane-xyz/core@3.1.0-beta0, @hyperlane-xyz/core@workspace:solidity":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@hyperlane-xyz/core@workspace:solidity" resolution: "@hyperlane-xyz/core@workspace:solidity"
dependencies: dependencies:
"@eth-optimism/contracts": ^0.6.0 "@eth-optimism/contracts": ^0.6.0
"@hyperlane-xyz/utils": 1.5.4-beta0 "@hyperlane-xyz/utils": 3.1.0-beta0
"@nomiclabs/hardhat-ethers": ^2.2.1 "@nomiclabs/hardhat-ethers": ^2.2.1
"@nomiclabs/hardhat-waffle": ^2.0.3 "@nomiclabs/hardhat-waffle": ^2.0.3
"@openzeppelin/contracts": ^4.8.0 "@openzeppelin/contracts": ^4.8.0
@ -3958,12 +4125,12 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@hyperlane-xyz/helloworld@1.5.4-beta0, @hyperlane-xyz/helloworld@workspace:typescript/helloworld": "@hyperlane-xyz/helloworld@3.1.0-beta0, @hyperlane-xyz/helloworld@workspace:typescript/helloworld":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@hyperlane-xyz/helloworld@workspace:typescript/helloworld" resolution: "@hyperlane-xyz/helloworld@workspace:typescript/helloworld"
dependencies: dependencies:
"@hyperlane-xyz/core": 1.5.4-beta0 "@hyperlane-xyz/core": 3.1.0-beta0
"@hyperlane-xyz/sdk": 1.5.4-beta0 "@hyperlane-xyz/sdk": 3.1.0-beta0
"@nomiclabs/hardhat-ethers": ^2.2.1 "@nomiclabs/hardhat-ethers": ^2.2.1
"@nomiclabs/hardhat-waffle": ^2.0.3 "@nomiclabs/hardhat-waffle": ^2.0.3
"@openzeppelin/contracts-upgradeable": ^4.8.0 "@openzeppelin/contracts-upgradeable": ^4.8.0
@ -4003,9 +4170,9 @@ __metadata:
"@ethersproject/experimental": ^5.7.0 "@ethersproject/experimental": ^5.7.0
"@ethersproject/hardware-wallets": ^5.7.0 "@ethersproject/hardware-wallets": ^5.7.0
"@ethersproject/providers": ^5.7.2 "@ethersproject/providers": ^5.7.2
"@hyperlane-xyz/helloworld": 1.5.4-beta0 "@hyperlane-xyz/helloworld": 3.1.0-beta0
"@hyperlane-xyz/sdk": 1.5.4-beta0 "@hyperlane-xyz/sdk": 3.1.0-beta0
"@hyperlane-xyz/utils": 1.5.4-beta0 "@hyperlane-xyz/utils": 3.1.0-beta0
"@nomiclabs/hardhat-ethers": ^2.2.1 "@nomiclabs/hardhat-ethers": ^2.2.1
"@nomiclabs/hardhat-etherscan": ^3.0.3 "@nomiclabs/hardhat-etherscan": ^3.0.3
"@nomiclabs/hardhat-waffle": ^2.0.3 "@nomiclabs/hardhat-waffle": ^2.0.3
@ -4049,12 +4216,14 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@hyperlane-xyz/sdk@1.5.4-beta0, @hyperlane-xyz/sdk@workspace:typescript/sdk": "@hyperlane-xyz/sdk@3.1.0-beta0, @hyperlane-xyz/sdk@workspace:typescript/sdk":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@hyperlane-xyz/sdk@workspace:typescript/sdk" resolution: "@hyperlane-xyz/sdk@workspace:typescript/sdk"
dependencies: dependencies:
"@hyperlane-xyz/core": 1.5.4-beta0 "@cosmjs/cosmwasm-stargate": ^0.31.3
"@hyperlane-xyz/utils": 1.5.4-beta0 "@cosmjs/stargate": ^0.31.3
"@hyperlane-xyz/core": 3.1.0-beta0
"@hyperlane-xyz/utils": 3.1.0-beta0
"@nomiclabs/hardhat-ethers": ^2.2.1 "@nomiclabs/hardhat-ethers": ^2.2.1
"@nomiclabs/hardhat-waffle": ^2.0.3 "@nomiclabs/hardhat-waffle": ^2.0.3
"@solana/spl-token": ^0.3.8 "@solana/spl-token": ^0.3.8
@ -4066,6 +4235,7 @@ __metadata:
"@wagmi/chains": ^0.2.6 "@wagmi/chains": ^0.2.6
chai: ^4.3.6 chai: ^4.3.6
coingecko-api: ^1.0.10 coingecko-api: ^1.0.10
cosmjs-types: ^0.9.0
cross-fetch: ^3.1.5 cross-fetch: ^3.1.5
debug: ^4.3.4 debug: ^4.3.4
dotenv: ^10.0.0 dotenv: ^10.0.0
@ -4084,10 +4254,11 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@hyperlane-xyz/utils@1.5.4-beta0, @hyperlane-xyz/utils@workspace:typescript/utils": "@hyperlane-xyz/utils@3.1.0-beta0, @hyperlane-xyz/utils@workspace:typescript/utils":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@hyperlane-xyz/utils@workspace:typescript/utils" resolution: "@hyperlane-xyz/utils@workspace:typescript/utils"
dependencies: dependencies:
"@cosmjs/encoding": ^0.31.3
"@solana/web3.js": ^1.78.0 "@solana/web3.js": ^1.78.0
bignumber.js: ^9.1.1 bignumber.js: ^9.1.1
chai: ^4.3.0 chai: ^4.3.0
@ -4312,7 +4483,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@noble/hashes@npm:^1.3.1": "@noble/hashes@npm:^1, @noble/hashes@npm:^1.0.0, @noble/hashes@npm:^1.3.1":
version: 1.3.2 version: 1.3.2
resolution: "@noble/hashes@npm:1.3.2" resolution: "@noble/hashes@npm:1.3.2"
checksum: fe23536b436539d13f90e4b9be843cc63b1b17666a07634a2b1259dded6f490be3d050249e6af98076ea8f2ea0d56f578773c2197f2aa0eeaa5fba5bc18ba474 checksum: fe23536b436539d13f90e4b9be843cc63b1b17666a07634a2b1259dded6f490be3d050249e6af98076ea8f2ea0d56f578773c2197f2aa0eeaa5fba5bc18ba474
@ -4869,6 +5040,79 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2":
version: 1.1.2
resolution: "@protobufjs/aspromise@npm:1.1.2"
checksum: 011fe7ef0826b0fd1a95935a033a3c0fd08483903e1aa8f8b4e0704e3233406abb9ee25350ec0c20bbecb2aad8da0dcea58b392bbd77d6690736f02c143865d2
languageName: node
linkType: hard
"@protobufjs/base64@npm:^1.1.2":
version: 1.1.2
resolution: "@protobufjs/base64@npm:1.1.2"
checksum: 67173ac34de1e242c55da52c2f5bdc65505d82453893f9b51dc74af9fe4c065cf4a657a4538e91b0d4a1a1e0a0642215e31894c31650ff6e3831471061e1ee9e
languageName: node
linkType: hard
"@protobufjs/codegen@npm:^2.0.4":
version: 2.0.4
resolution: "@protobufjs/codegen@npm:2.0.4"
checksum: 59240c850b1d3d0b56d8f8098dd04787dcaec5c5bd8de186fa548de86b86076e1c50e80144b90335e705a044edf5bc8b0998548474c2a10a98c7e004a1547e4b
languageName: node
linkType: hard
"@protobufjs/eventemitter@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/eventemitter@npm:1.1.0"
checksum: 0369163a3d226851682f855f81413cbf166cd98f131edb94a0f67f79e75342d86e89df9d7a1df08ac28be2bc77e0a7f0200526bb6c2a407abbfee1f0262d5fd7
languageName: node
linkType: hard
"@protobufjs/fetch@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/fetch@npm:1.1.0"
dependencies:
"@protobufjs/aspromise": ^1.1.1
"@protobufjs/inquire": ^1.1.0
checksum: 3fce7e09eb3f1171dd55a192066450f65324fd5f7cc01a431df01bb00d0a895e6bfb5b0c5561ce157ee1d886349c90703d10a4e11a1a256418ff591b969b3477
languageName: node
linkType: hard
"@protobufjs/float@npm:^1.0.2":
version: 1.0.2
resolution: "@protobufjs/float@npm:1.0.2"
checksum: 5781e1241270b8bd1591d324ca9e3a3128d2f768077a446187a049e36505e91bc4156ed5ac3159c3ce3d2ba3743dbc757b051b2d723eea9cd367bfd54ab29b2f
languageName: node
linkType: hard
"@protobufjs/inquire@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/inquire@npm:1.1.0"
checksum: ca06f02eaf65ca36fb7498fc3492b7fc087bfcc85c702bac5b86fad34b692bdce4990e0ef444c1e2aea8c034227bd1f0484be02810d5d7e931c55445555646f4
languageName: node
linkType: hard
"@protobufjs/path@npm:^1.1.2":
version: 1.1.2
resolution: "@protobufjs/path@npm:1.1.2"
checksum: 856eeb532b16a7aac071cacde5c5620df800db4c80cee6dbc56380524736205aae21e5ae47739114bf669ab5e8ba0e767a282ad894f3b5e124197cb9224445ee
languageName: node
linkType: hard
"@protobufjs/pool@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/pool@npm:1.1.0"
checksum: d6a34fbbd24f729e2a10ee915b74e1d77d52214de626b921b2d77288bd8f2386808da2315080f2905761527cceffe7ec34c7647bd21a5ae41a25e8212ff79451
languageName: node
linkType: hard
"@protobufjs/utf8@npm:^1.1.0":
version: 1.1.0
resolution: "@protobufjs/utf8@npm:1.1.0"
checksum: f9bf3163d13aaa3b6f5e6fbf37a116e094ea021c0e1f2a7ccd0e12a29e2ce08dafba4e8b36e13f8ed7397e1591610ce880ed1289af4d66cf4ace8a36a9557278
languageName: node
linkType: hard
"@resolver-engine/core@npm:^0.3.3": "@resolver-engine/core@npm:^0.3.3":
version: 0.3.3 version: 0.3.3
resolution: "@resolver-engine/core@npm:0.3.3" resolution: "@resolver-engine/core@npm:0.3.3"
@ -5486,6 +5730,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/long@npm:^4.0.1":
version: 4.0.2
resolution: "@types/long@npm:4.0.2"
checksum: d16cde7240d834cf44ba1eaec49e78ae3180e724cd667052b194a372f350d024cba8dd3f37b0864931683dab09ca935d52f0c4c1687178af5ada9fc85b0635f4
languageName: node
linkType: hard
"@types/lru-cache@npm:^5.1.0": "@types/lru-cache@npm:^5.1.0":
version: 5.1.1 version: 5.1.1
resolution: "@types/lru-cache@npm:5.1.1" resolution: "@types/lru-cache@npm:5.1.1"
@ -5540,6 +5791,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:>=13.7.0":
version: 20.8.9
resolution: "@types/node@npm:20.8.9"
dependencies:
undici-types: ~5.26.4
checksum: 0c05f3502a9507ff27e91dd6fd574fa6f391b3fafedcfe8e0c8d33351fb22d02c0121f854e5b6b3ecb9a8a468407ddf6e7ac0029fb236d4c7e1361ffc758a01f
languageName: node
linkType: hard
"@types/node@npm:^10.0.3": "@types/node@npm:^10.0.3":
version: 10.17.60 version: 10.17.60
resolution: "@types/node@npm:10.17.60" resolution: "@types/node@npm:10.17.60"
@ -6601,6 +6861,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"axios@npm:^0.21.2":
version: 0.21.4
resolution: "axios@npm:0.21.4"
dependencies:
follow-redirects: ^1.14.0
checksum: 44245f24ac971e7458f3120c92f9d66d1fc695e8b97019139de5b0cc65d9b8104647db01e5f46917728edfc0cfd88eb30fc4c55e6053eef4ace76768ce95ff3c
languageName: node
linkType: hard
"babel-code-frame@npm:^6.26.0": "babel-code-frame@npm:^6.26.0":
version: 6.26.0 version: 6.26.0
resolution: "babel-code-frame@npm:6.26.0" resolution: "babel-code-frame@npm:6.26.0"
@ -7255,7 +7524,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"base64-js@npm:^1.3.1": "base64-js@npm:^1.3.0, base64-js@npm:^1.3.1":
version: 1.5.1 version: 1.5.1
resolution: "base64-js@npm:1.5.1" resolution: "base64-js@npm:1.5.1"
checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005
@ -7286,7 +7555,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"bech32@npm:1.1.4": "bech32@npm:1.1.4, bech32@npm:^1.1.4":
version: 1.1.4 version: 1.1.4
resolution: "bech32@npm:1.1.4" resolution: "bech32@npm:1.1.4"
checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b
@ -8559,6 +8828,23 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"cosmjs-types@npm:^0.8.0":
version: 0.8.0
resolution: "cosmjs-types@npm:0.8.0"
dependencies:
long: ^4.0.0
protobufjs: ~6.11.2
checksum: 99714ec956d2cb2e521d39896c9c9a24cf9df0d370265c203646ea015b51e86472efc0cb11f67a80f0649d178b0bcff77ac659e67fdfc8b2437cd7a42018577f
languageName: node
linkType: hard
"cosmjs-types@npm:^0.9.0":
version: 0.9.0
resolution: "cosmjs-types@npm:0.9.0"
checksum: 9b00d169eca334f27418bb80b39e0cff0196af40b0079e1f85536246059279207b853bdb6ec224ead0a02d15d4b7f6bf16bc096d41c436426aa5f8976ed2b430
languageName: node
linkType: hard
"crc-32@npm:^1.2.0": "crc-32@npm:^1.2.0":
version: 1.2.2 version: 1.2.2
resolution: "crc-32@npm:1.2.2" resolution: "crc-32@npm:1.2.2"
@ -10866,6 +11152,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"follow-redirects@npm:^1.14.0":
version: 1.15.3
resolution: "follow-redirects@npm:1.15.3"
peerDependenciesMeta:
debug:
optional: true
checksum: 584da22ec5420c837bd096559ebfb8fe69d82512d5585004e36a3b4a6ef6d5905780e0c74508c7b72f907d1fa2b7bd339e613859e9c304d0dc96af2027fd0231
languageName: node
linkType: hard
"for-each@npm:^0.3.3, for-each@npm:~0.3.3": "for-each@npm:^0.3.3, for-each@npm:~0.3.3":
version: 0.3.3 version: 0.3.3
resolution: "for-each@npm:0.3.3" resolution: "for-each@npm:0.3.3"
@ -11501,6 +11797,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"globalthis@npm:^1.0.1":
version: 1.0.3
resolution: "globalthis@npm:1.0.3"
dependencies:
define-properties: ^1.1.3
checksum: fbd7d760dc464c886d0196166d92e5ffb4c84d0730846d6621a39fbbc068aeeb9c8d1421ad330e94b7bca4bb4ea092f5f21f3d36077812af5d098b4dc006c998
languageName: node
linkType: hard
"globby@npm:^10.0.1": "globby@npm:^10.0.1":
version: 10.0.2 version: 10.0.2
resolution: "globby@npm:10.0.2" resolution: "globby@npm:10.0.2"
@ -13531,6 +13836,22 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"libsodium-sumo@npm:^0.7.13":
version: 0.7.13
resolution: "libsodium-sumo@npm:0.7.13"
checksum: d0905530c53c27a0c01348eed8abc2ecf3725c0647545cc528ea4bbd0ee63b7a471b56abefec5b293086ee64b5ba7cf911a655cd2c36f400a4bfec6e2d152ebd
languageName: node
linkType: hard
"libsodium-wrappers-sumo@npm:^0.7.11":
version: 0.7.13
resolution: "libsodium-wrappers-sumo@npm:0.7.13"
dependencies:
libsodium-sumo: ^0.7.13
checksum: cdaa7ae5d64e71e860b40b5f2fbaec156adc7bc5606f7d32655b6ab84c9878fd90b3a41e99cb96380f0b5727d1ee1c6ad5b440bff35ce8289832e5c8cac99973
languageName: node
linkType: hard
"lilconfig@npm:2.0.5": "lilconfig@npm:2.0.5":
version: 2.0.5 version: 2.0.5
resolution: "lilconfig@npm:2.0.5" resolution: "lilconfig@npm:2.0.5"
@ -13698,6 +14019,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"long@npm:^4.0.0":
version: 4.0.0
resolution: "long@npm:4.0.0"
checksum: 16afbe8f749c7c849db1f4de4e2e6a31ac6e617cead3bdc4f9605cb703cd20e1e9fc1a7baba674ffcca57d660a6e5b53a9e236d7b25a295d3855cca79cc06744
languageName: node
linkType: hard
"looper@npm:^2.0.0": "looper@npm:^2.0.0":
version: 2.0.0 version: 2.0.0
resolution: "looper@npm:2.0.0" resolution: "looper@npm:2.0.0"
@ -15325,6 +15653,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"pako@npm:^2.0.2":
version: 2.1.0
resolution: "pako@npm:2.1.0"
checksum: 71666548644c9a4d056bcaba849ca6fd7242c6cf1af0646d3346f3079a1c7f4a66ffec6f7369ee0dc88f61926c10d6ab05da3e1fca44b83551839e89edd75a3e
languageName: node
linkType: hard
"parent-module@npm:^1.0.0": "parent-module@npm:^1.0.0":
version: 1.0.1 version: 1.0.1
resolution: "parent-module@npm:1.0.1" resolution: "parent-module@npm:1.0.1"
@ -15841,6 +16176,30 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"protobufjs@npm:^6.8.8, protobufjs@npm:~6.11.2, protobufjs@npm:~6.11.3":
version: 6.11.4
resolution: "protobufjs@npm:6.11.4"
dependencies:
"@protobufjs/aspromise": ^1.1.2
"@protobufjs/base64": ^1.1.2
"@protobufjs/codegen": ^2.0.4
"@protobufjs/eventemitter": ^1.1.0
"@protobufjs/fetch": ^1.1.0
"@protobufjs/float": ^1.0.2
"@protobufjs/inquire": ^1.1.0
"@protobufjs/path": ^1.1.2
"@protobufjs/pool": ^1.1.0
"@protobufjs/utf8": ^1.1.0
"@types/long": ^4.0.1
"@types/node": ">=13.7.0"
long: ^4.0.0
bin:
pbjs: bin/pbjs
pbts: bin/pbts
checksum: b2fc6a01897b016c2a7e43a854ab4a3c57080f61be41e552235436e7a730711b8e89e47cb4ae52f0f065b5ab5d5989fc932f390337ce3a8ccf07203415700850
languageName: node
linkType: hard
"proxy-addr@npm:~2.0.7": "proxy-addr@npm:~2.0.7":
version: 2.0.7 version: 2.0.7
resolution: "proxy-addr@npm:2.0.7" resolution: "proxy-addr@npm:2.0.7"
@ -16193,6 +16552,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"readonly-date@npm:^1.0.0":
version: 1.0.0
resolution: "readonly-date@npm:1.0.0"
checksum: 78481e2abf3c2f9bc526029458aee3e2b1c476ca1434c4cc9db5c9aba51bf8f1323c1995d764ff01f2055b01f13e05416b2e14b387f644b0a5a56554c3ee9d0a
languageName: node
linkType: hard
"rechoir@npm:^0.6.2": "rechoir@npm:^0.6.2":
version: 0.6.2 version: 0.6.2
resolution: "rechoir@npm:0.6.2" resolution: "rechoir@npm:0.6.2"
@ -17901,6 +18267,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"symbol-observable@npm:^2.0.3":
version: 2.0.3
resolution: "symbol-observable@npm:2.0.3"
checksum: 533dcf7a7925bada60dbaa06d678e7c4966dbf0959ccba7f60c22b0494ba5d9160d6a66f2951d45a80bf20e655a89f8b91c5f0458dd12faef28716b54f91f49c
languageName: node
linkType: hard
"sync-request@npm:^6.0.0": "sync-request@npm:^6.0.0":
version: 6.1.0 version: 6.1.0
resolution: "sync-request@npm:6.1.0" resolution: "sync-request@npm:6.1.0"
@ -18648,6 +19021,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"undici-types@npm:~5.26.4":
version: 5.26.5
resolution: "undici-types@npm:5.26.5"
checksum: 3192ef6f3fd5df652f2dc1cd782b49d6ff14dc98e5dced492aa8a8c65425227da5da6aafe22523c67f035a272c599bb89cfe803c1db6311e44bed3042fc25487
languageName: node
linkType: hard
"undici@npm:^5.11": "undici@npm:^5.11":
version: 5.11.0 version: 5.11.0
resolution: "undici@npm:5.11.0" resolution: "undici@npm:5.11.0"
@ -20005,7 +20385,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"ws@npm:^7.4.5": "ws@npm:^7, ws@npm:^7.4.5":
version: 7.5.9 version: 7.5.9
resolution: "ws@npm:7.5.9" resolution: "ws@npm:7.5.9"
peerDependencies: peerDependencies:
@ -20102,6 +20482,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"xstream@npm:^11.14.0":
version: 11.14.0
resolution: "xstream@npm:11.14.0"
dependencies:
globalthis: ^1.0.1
symbol-observable: ^2.0.3
checksum: eb96b5f9cd7e6a30d18688f337b8d1c658c85bb08754f2af4247275e25c0605c8435ad8125e04ad7d606c1b760fab4679841906f92718f35f8ce327074e1375a
languageName: node
linkType: hard
"xtend@npm:^4.0.0, xtend@npm:^4.0.1, xtend@npm:~4.0.0, xtend@npm:~4.0.1": "xtend@npm:^4.0.0, xtend@npm:^4.0.1, xtend@npm:~4.0.0, xtend@npm:~4.0.1":
version: 4.0.2 version: 4.0.2
resolution: "xtend@npm:4.0.2" resolution: "xtend@npm:4.0.2"

Loading…
Cancel
Save