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",
"description": "Core solidity contracts for Hyperlane",
"version": "1.5.4-beta0",
"version": "3.1.0-beta0",
"dependencies": {
"@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-upgradeable": "^4.8.0"
},

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

@ -5,6 +5,7 @@ import {
Chains,
RpcConsensusType,
chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk';
import { LiquidityLayerRelayerConfig } from '../../../src/config/middleware';
@ -12,8 +13,14 @@ import { LiquidityLayerRelayerConfig } from '../../../src/config/middleware';
import { environment } from './chains';
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> = {

@ -4,11 +4,15 @@ import {
Chains,
CircleBridgeAdapterConfig,
chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk';
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

@ -4,23 +4,36 @@ import {
ChainMap,
Chains,
chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk';
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 = [
{ 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,
},
{
hyperlaneDomain: chainMetadata[Chains.alfajores].chainId,
hyperlaneDomain: getDomainId(chainMetadata[Chains.alfajores]),
wormholeDomain: 14,
},
];

@ -4,23 +4,36 @@ import {
ChainMap,
Chains,
chainMetadata,
getDomainId,
} from '@hyperlane-xyz/sdk';
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 = [
{ 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,
},
{
hyperlaneDomain: chainMetadata[Chains.alfajores].chainId,
hyperlaneDomain: getDomainId(chainMetadata[Chains.alfajores]),
wormholeDomain: 14,
},
];

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

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

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

@ -6,17 +6,18 @@ import { assertCorrectKubeContext, getEnvironmentConfig } from '../utils';
export async function runWarpRouteHelmCommand(
helmCommand: HelmCommand,
runEnv: DeployEnvironment,
config: string,
) {
const envConfig = getEnvironmentConfig(runEnv);
await assertCorrectKubeContext(envConfig);
const values = getWarpRoutesHelmValues();
const values = getWarpRoutesHelmValues(config);
return execCmd(
`helm ${helmCommand} ${getHelmReleaseName(
'zebec',
config,
)} ./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}`;
}
function getWarpRoutesHelmValues() {
function getWarpRoutesHelmValues(config: string) {
const values = {
image: {
repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: '962d34b-20230905-194531',
tag: 'ae8ce44-20231101-012032',
},
config: config, // nautilus or neutron
};
return helmifyValues(values);
}

@ -7,8 +7,8 @@ import { ERC20__factory } from '@hyperlane-xyz/core';
import {
ChainMap,
ChainName,
CwNativeTokenAdapter,
MultiProtocolProvider,
MultiProvider,
SealevelHypCollateralAdapter,
TokenType,
} from '@hyperlane-xyz/sdk';
@ -21,8 +21,9 @@ import {
import {
WarpTokenConfig,
tokenList,
} from '../../src/config/nautilus_token_config';
nautilusList,
neutronList,
} from '../../src/config/grafana_token_config';
import { startMetricsServer } from '../../src/utils/metrics';
const metricsRegister = new Registry();
@ -40,21 +41,29 @@ const warpRouteTokenBalance = new Gauge({
});
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')
.demandOption('checkFrequency')
.alias('c', 'checkFrequency')
.alias('l', 'checkFrequency')
.number('checkFrequency')
.alias('c', 'config')
.describe('config', 'choose warp token config')
.demandOption('config')
.choices('config', ['neutron', 'nautilus'])
.parse();
const tokenList: WarpTokenConfig =
config === 'neutron' ? neutronList : nautilusList;
startMetricsServer(metricsRegister);
const multiProvider = new MultiProvider();
console.log('Starting Warp Route balance monitor');
const multiProtocolProvider = new MultiProtocolProvider();
setInterval(async () => {
try {
console.log('Checking balances');
const balances = await checkBalance(tokenList, multiProvider);
debug('Checking balances');
const balances = await checkBalance(tokenList, multiProtocolProvider);
updateTokenBalanceMetrics(tokenList, balances);
} catch (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
async function checkBalance(
tokenConfig: WarpTokenConfig,
multiprovider: MultiProvider,
multiProtocolProvider: MultiProtocolProvider,
): Promise<ChainMap<number>> {
const output: ChainMap<Promise<number>> = objMap(
tokenConfig,
async (chain: ChainName, token: WarpTokenConfig[ChainName]) => {
const provider = multiprovider.getProvider(chain);
if (token.type === TokenType.native) {
if (token.protocolType === ProtocolType.Ethereum) {
switch (token.type) {
case TokenType.native: {
switch (token.protocolType) {
case ProtocolType.Ethereum: {
const provider = multiProtocolProvider.getEthersV5Provider(chain);
const nativeBalance = await provider.getBalance(
token.hypNativeAddress,
);
return parseFloat(
ethers.utils.formatUnits(nativeBalance, token.decimals),
);
} else {
}
case ProtocolType.Sealevel:
// TODO - solana native
return 0;
case ProtocolType.Cosmos:
// TODO - cosmos native
return 0;
}
break;
}
} else {
if (token.protocolType === ProtocolType.Ethereum) {
const tokenContract = ERC20__factory.connect(token.address, provider);
case TokenType.collateral: {
switch (token.protocolType) {
case ProtocolType.Ethereum: {
const provider = multiProtocolProvider.getEthersV5Provider(chain);
const tokenContract = ERC20__factory.connect(
token.address,
provider,
);
const collateralBalance = await tokenContract.balanceOf(
token.hypCollateralAddress,
);
@ -94,10 +116,11 @@ async function checkBalance(
return parseFloat(
ethers.utils.formatUnits(collateralBalance, token.decimals),
);
} else {
}
case ProtocolType.Sealevel: {
const adapter = new SealevelHypCollateralAdapter(
chain,
MultiProtocolProvider.fromMultiProvider(multiprovider),
multiProtocolProvider,
{
token: token.address,
warpRouter: token.hypCollateralAddress,
@ -113,6 +136,47 @@ async function checkBalance(
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 =
token.type === TokenType.native
? ethers.constants.AddressZero
: token.address;
: token.type === TokenType.collateral
? token.address
: token.hypSyntheticAddress;
const walletAddress =
token.type === TokenType.native
? token.hypNativeAddress
: token.hypCollateralAddress;
: token.type === TokenType.collateral
? token.hypCollateralAddress
: token.hypSyntheticAddress;
warpRouteTokenBalance
.labels({

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

@ -2,37 +2,53 @@ import { ChainMap, TokenType } from '@hyperlane-xyz/sdk';
import { ProtocolType } from '@hyperlane-xyz/utils';
interface NativeTokenConfig {
chainId: number;
symbol: string;
name: string;
type: TokenType.native;
decimals: number;
hypNativeAddress: string;
protocolType: ProtocolType.Ethereum | ProtocolType.Sealevel;
protocolType:
| ProtocolType.Ethereum
| ProtocolType.Sealevel
| ProtocolType.Cosmos;
}
interface CollateralTokenConfig {
type: TokenType.collateral;
address: string;
chainId: number;
decimals: number;
symbol: string;
name: string;
hypCollateralAddress: string;
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
export type WarpTokenConfig = ChainMap<
CollateralTokenConfig | NativeTokenConfig
CollateralTokenConfig | NativeTokenConfig | SyntheticTokenConfig
>;
export const tokenList: WarpTokenConfig = {
/// nautilus configs
export const nautilusList: WarpTokenConfig = {
// bsc
bsc: {
type: TokenType.collateral,
chainId: 56,
address: '0x37a56cdcD83Dce2868f721De58cB3830C44C6303',
hypCollateralAddress: '0xC27980812E2E66491FD457D488509b7E04144b98',
symbol: 'ZBC',
@ -44,7 +60,6 @@ export const tokenList: WarpTokenConfig = {
// nautilus
nautilus: {
type: TokenType.native,
chainId: 22222,
hypNativeAddress: '0x4501bBE6e731A4bC5c60C03A77435b2f6d5e9Fe7',
symbol: 'ZBC',
name: 'Zebec',
@ -55,7 +70,6 @@ export const tokenList: WarpTokenConfig = {
// solana
solana: {
type: TokenType.collateral,
chainId: 1399811149,
address: 'wzbcJyhGhQDLTV1S99apZiiBdE4jmYfbw99saMMdP59',
hypCollateralAddress: 'EJqwFjvVJSAxH8Ur2PYuMfdvoJeutjmH6GkoEFQ4MdSa',
name: 'Zebec',
@ -65,3 +79,26 @@ export const tokenList: WarpTokenConfig = {
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",
"description": "The official SDK for the Hyperlane Network",
"version": "1.5.4-beta0",
"version": "3.1.0-beta0",
"dependencies": {
"@hyperlane-xyz/core": "1.5.4-beta0",
"@hyperlane-xyz/utils": "1.5.4-beta0",
"@cosmjs/cosmwasm-stargate": "^0.31.3",
"@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/web3.js": "^1.78.0",
"@types/coingecko-api": "^1.0.10",
"@types/debug": "^4.1.7",
"@wagmi/chains": "^0.2.6",
"coingecko-api": "^1.0.10",
"cosmjs-types": "^0.9.0",
"cross-fetch": "^3.1.5",
"debug": "^4.3.4",
"ethers": "^5.7.2",

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

@ -11,6 +11,8 @@ import {
import { ChainMetadata } from '../metadata/chainMetadataTypes';
import { MultiProtocolProvider } from '../providers/MultiProtocolProvider';
import {
CosmJsProvider,
CosmJsWasmProvider,
EthersV5Provider,
SolanaWeb3Provider,
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 {
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 = {
chainId: 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
*/
@ -967,9 +1029,11 @@ export const chainMetadata: ChainMap<ChainMetadata> = {
scroll,
scrollsepolia,
sepolia,
mantapacific,
moonbasealpha,
moonbeam,
mumbai,
neutron,
optimism,
optimismgoerli,
polygon,

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

@ -11,6 +11,7 @@ import { MultiProtocolProvider } from '../providers/MultiProtocolProvider';
import { TypedTransactionReceipt } from '../providers/ProviderType';
import { ChainMap, ChainName } from '../types';
import { CosmWasmCoreAdapter } from './adapters/CosmWasmCoreAdapter';
import { EvmCoreAdapter } from './adapters/EvmCoreAdapter';
import { SealevelCoreAdapter } from './adapters/SealevelCoreAdapter';
import { ICoreAdapter } from './adapters/types';
@ -54,6 +55,7 @@ export class MultiProtocolCore extends MultiProtocolApp<
): AdapterClassType<ICoreAdapter> {
if (protocol === ProtocolType.Ethereum) return EvmCoreAdapter;
if (protocol === ProtocolType.Sealevel) return SealevelCoreAdapter;
if (protocol === ProtocolType.Cosmos) return CosmWasmCoreAdapter;
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 {
ChainMetadata,
ChainMetadataSchema,
ChainMetadataSchemaObject,
ExplorerFamily,
ExplorerFamilyValue,
RpcUrl,
RpcUrlSchema,
getChainIdNumber,
getDomainId,
isValidChainMetadata,
} from './metadata/chainMetadataTypes';
@ -206,6 +208,14 @@ export {
} from './providers/MultiProtocolProvider';
export { MultiProvider, MultiProviderOptions } from './providers/MultiProvider';
export {
CosmJsContract,
CosmJsProvider,
CosmJsTransaction,
CosmJsTransactionReceipt,
CosmJsWasmContract,
CosmJsWasmProvider,
CosmJsWasmTransaction,
CosmJsWasmTransactionReceipt,
EthersV5Contract,
EthersV5Provider,
EthersV5Transaction,
@ -276,6 +286,14 @@ export {
RouterViolationType,
proxiedFactories,
} from './router/types';
export {
CW20Metadata,
CwHypCollateralAdapter,
CwHypNativeAdapter,
CwHypSyntheticAdapter,
CwNativeTokenAdapter,
CwTokenAdapter,
} from './token/adapters/CosmWasmTokenAdapter';
export {
EvmHypCollateralAdapter,
EvmHypSyntheticAdapter,
@ -292,7 +310,6 @@ export {
SealevelHypCollateralAdapter,
SealevelHypNativeAdapter,
SealevelHypSyntheticAdapter,
SealevelHypTokenAdapter,
SealevelNativeTokenAdapter,
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 { ProtocolType, exclude, isNumeric, pick } from '@hyperlane-xyz/utils';
import { ProtocolType, exclude, pick } from '@hyperlane-xyz/utils';
import {
chainMetadata as defaultChainMetadata,
@ -64,7 +64,7 @@ export class ChainMetadataManager<MetaExt = {}> {
chainId == metadata.chainId ||
domainId == metadata.chainId ||
(metadata.domainId &&
(chainId == metadata.domainId || domainId === metadata.domainId));
(chainId == metadata.domainId || domainId == metadata.domainId));
if (idCollision)
throw new Error(
`Chain/Domain id collision: ${name} and ${metadata.name}`,
@ -80,16 +80,12 @@ export class ChainMetadataManager<MetaExt = {}> {
tryGetChainMetadata(
chainNameOrId: ChainName | number,
): ChainMetadata<MetaExt> | null {
let chainMetadata: ChainMetadata<MetaExt> | undefined;
if (isNumeric(chainNameOrId)) {
// Should be chain id or domain id
chainMetadata = Object.values(this.metadata).find(
// First check if it's a chain name
if (this.metadata[chainNameOrId]) return this.metadata[chainNameOrId];
// Otherwise search by chain id and domain id
const chainMetadata = Object.values(this.metadata).find(
(m) => m.chainId == chainNameOrId || m.domainId == chainNameOrId,
);
} else if (typeof chainNameOrId === 'string') {
// Should be chain name
chainMetadata = this.metadata[chainNameOrId];
}
return chainMetadata || null;
}
@ -130,7 +126,7 @@ export class ChainMetadataManager<MetaExt = {}> {
/**
* 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;
}
@ -138,14 +134,14 @@ export class ChainMetadataManager<MetaExt = {}> {
* Get the id for a given chain name, chain id, or domain id
* @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;
}
/**
* 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);
}
@ -154,7 +150,8 @@ export class ChainMetadataManager<MetaExt = {}> {
*/
tryGetDomainId(chainNameOrId: ChainName | number): number | null {
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
*/
getDomainId(chainNameOrId: ChainName | number): number {
const metadata = this.getChainMetadata(chainNameOrId);
return getDomainId(metadata);
const domainId = this.tryGetDomainId(chainNameOrId);
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]);
}
// TODO cosmos support here
return url.toString();
}

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

@ -50,6 +50,16 @@ describe('ChainMetadataSchema', () => {
blocks,
}),
).to.eq(true);
expect(
isValidChainMetadata({
...minimalSchema,
protocol: ProtocolType.Cosmos,
chainId: 'cosmos',
bech32Prefix: 'cosmos',
slip44: 118,
}),
).to.eq(true);
});
it('Rejects invalid schemas', () => {
expect(
@ -80,5 +90,20 @@ describe('ChainMetadataSchema', () => {
name: 'Invalid name',
}),
).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
* Specified as a Zod schema
*/
export const ChainMetadataSchema = z.object({
export const ChainMetadataSchemaObject = z.object({
name: z
.string()
.regex(/^[a-z][a-z0-9]*$/)
@ -71,9 +71,9 @@ export const ChainMetadataSchema = z.object({
.describe(
'The type of protocol used by this chain. See ProtocolType for valid values.',
),
chainId: ZNzUint.describe(
`The chainId of the chain. Uses EIP-155 for EVM chains`,
),
chainId: z
.union([ZNzUint, z.string()])
.describe(`The chainId of the chain. Uses EIP-155 for EVM chains`),
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`.',
),
@ -161,12 +161,59 @@ export const ChainMetadataSchema = z.object({
.string()
.optional()
.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
.boolean()
.optional()
.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> &
Ext;
@ -175,5 +222,13 @@ export function isValidChainMetadata(c: ChainMetadata): boolean {
}
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 {
CosmJsProvider,
CosmJsWasmProvider,
EthersV5Provider,
ProviderMap,
ProviderType,
@ -26,6 +28,7 @@ export const PROTOCOL_DEFAULT_PROVIDER_TYPE: Partial<
> = {
[ProtocolType.Ethereum]: ProviderType.EthersV5,
[ProtocolType.Sealevel]: ProviderType.SolanaWeb3,
[ProtocolType.Cosmos]: ProviderType.CosmJsWasm,
};
export interface MultiProtocolProviderOptions {
@ -143,38 +146,59 @@ export class MultiProtocolProvider<
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(
chainNameOrId: ChainName | number,
): EthersV5Provider['provider'] {
const provider = this.getProvider(chainNameOrId, ProviderType.EthersV5);
if (provider.type !== ProviderType.EthersV5)
throw new Error('Invalid provider type');
return provider.provider;
return this.getSpecificProvider<EthersV5Provider['provider']>(
chainNameOrId,
ProviderType.EthersV5,
);
}
// 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'] {
const provider = this.getProvider(chainNameOrId, ProviderType.Viem);
if (provider.type !== ProviderType.Viem)
throw new Error('Invalid provider type');
return provider.provider;
return this.getSpecificProvider<ViemProvider['provider']>(
chainNameOrId,
ProviderType.Viem,
);
}
getSolanaWeb3Provider(
chainNameOrId: ChainName | number,
): SolanaWeb3Provider['provider'] {
const provider = this.getProvider(chainNameOrId, ProviderType.SolanaWeb3);
if (provider.type !== ProviderType.SolanaWeb3)
throw new Error('Invalid provider type');
return provider.provider;
return this.getSpecificProvider<SolanaWeb3Provider['provider']>(
chainNameOrId,
ProviderType.SolanaWeb3,
);
}
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(

@ -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 {
Connection,
Transaction as SolTransaction,
@ -21,6 +28,8 @@ export enum ProviderType {
// EthersV6 = 'ethers-v6', Disabled for now to simplify build tooling
Viem = 'viem',
SolanaWeb3 = 'solana-web3',
CosmJs = 'cosmjs',
CosmJsWasm = 'cosmjs-wasm',
}
export type ProviderMap<Value> = Partial<Record<ProviderType, Value>>;
@ -55,11 +64,25 @@ export interface SolanaWeb3Provider extends TypedProviderBase<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 =
| EthersV5Provider
// | EthersV6Provider
| ViemProvider
| SolanaWeb3Provider;
| SolanaWeb3Provider
| CosmJsProvider
| CosmJsWasmProvider;
/**
* Contracts with discriminated union of provider type
@ -72,7 +95,7 @@ interface TypedContractBase<T> {
export interface EthersV5Contract extends TypedContractBase<EV5Contract> {
type: ProviderType.EthersV5;
transaction: EV5Contract;
contract: EV5Contract;
}
// export interface EthersV6Contract extends TypedContractBase<Ev6Contract> {
@ -82,20 +105,34 @@ export interface EthersV5Contract extends TypedContractBase<EV5Contract> {
export interface ViemContract extends TypedContractBase<GetContractReturnType> {
type: ProviderType.Viem;
transaction: GetContractReturnType;
contract: GetContractReturnType;
}
export interface SolanaWeb3Contract extends TypedContractBase<never> {
type: ProviderType.SolanaWeb3;
// 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 =
| EthersV5Contract
// | EthersV6Contract
| ViemContract
| SolanaWeb3Contract;
| SolanaWeb3Contract
| CosmJsContract
| CosmJsWasmContract;
/**
* Transactions with discriminated union of provider type
@ -128,11 +165,24 @@ export interface SolanaWeb3Transaction
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 =
| EthersV5Transaction
// | EthersV6Transaction
| ViemTransaction
| SolanaWeb3Transaction;
| SolanaWeb3Transaction
| CosmJsTransaction
| CosmJsWasmTransaction;
/**
* Transaction receipt/response with discriminated union of provider type
@ -161,7 +211,21 @@ export interface SolanaWeb3TransactionReceipt
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 =
| EthersV5TransactionReceipt
| 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 { providers } from 'ethers';
import { createPublicClient, http } from 'viem';
@ -7,6 +9,8 @@ import { ProtocolType, isNumeric } from '@hyperlane-xyz/utils';
import { ChainMetadata } from '../metadata/chainMetadataTypes';
import {
CosmJsProvider,
CosmJsWasmProvider,
EthersV5Provider,
ProviderType,
SolanaWeb3Provider,
@ -102,6 +106,28 @@ export function defaultFuelProviderBuilder(
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
export function defaultProviderBuilder(
rpcUrls: ChainMetadata['rpcUrls'],
@ -119,6 +145,8 @@ export const defaultProviderBuilderMap: ProviderBuilderMap = {
// [ProviderType.EthersV6]: defaultEthersV6ProviderBuilder,
[ProviderType.Viem]: defaultViemProviderBuilder,
[ProviderType.SolanaWeb3]: defaultSolProviderBuilder,
[ProviderType.CosmJs]: defaultCosmJsProviderBuilder,
[ProviderType.CosmJsWasm]: defaultCosmJsWasmProviderBuilder,
};
export const protocolToDefaultProviderBuilder: Record<
@ -128,4 +156,5 @@ export const protocolToDefaultProviderBuilder: Record<
[ProtocolType.Ethereum]: defaultEthersV5ProviderBuilder,
[ProtocolType.Sealevel]: defaultSolProviderBuilder,
[ProtocolType.Fuel]: defaultFuelProviderBuilder,
[ProtocolType.Cosmos]: defaultCosmJsWasmProviderBuilder,
};

@ -27,6 +27,7 @@ export class MultiProtocolRouterApp<
// enabling extensible generic types
if (protocol === ProtocolType.Ethereum) return EvmRouterAdapter as any;
if (protocol === ProtocolType.Sealevel) return SealevelRouterAdapter as any;
// TODO cosmos support here
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.
const TRANSFER_REMOTE_COMPUTE_LIMIT = 1_000_000;
export abstract class SealevelHypTokenAdapter
abstract class SealevelHypTokenAdapter
extends SealevelTokenAdapter
implements IHypTokenAdapter
{

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

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

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

@ -1,3 +1,4 @@
import { fromBech32, normalizeBech32, toBech32 } from '@cosmjs/encoding';
import { PublicKey } from '@solana/web3.js';
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 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 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 COSMOS_ZEROISH_ADDRESS_REGEX = /^[a-z]{1,10}?1[0]{38}$/;
export function isAddressEvm(address: Address) {
return EVM_ADDRESS_REGEX.test(address);
@ -19,10 +25,16 @@ export function isAddressSealevel(address: 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) {
if (!address) return undefined;
if (isAddressEvm(address)) {
return ProtocolType.Ethereum;
} else if (isAddressCosmos(address)) {
return ProtocolType.Cosmos;
} else if (isAddressSealevel(address)) {
return ProtocolType.Sealevel;
} else {
@ -31,20 +43,15 @@ export function getAddressProtocolType(address: Address) {
}
function routeAddressUtil<T>(
evmFn: (param: string) => T,
sealevelFn: (param: string) => T,
fallback: T,
fns: Partial<Record<ProtocolType, (param: string) => T>>,
param: string,
fallback?: T,
protocol?: ProtocolType,
) {
protocol = protocol || getAddressProtocolType(param);
if (protocol === ProtocolType.Ethereum) {
return evmFn(param);
} else if (protocol === ProtocolType.Sealevel) {
return sealevelFn(param);
} else {
return fallback;
}
protocol ||= getAddressProtocolType(param);
if (protocol && fns[protocol]) return fns[protocol]!(param);
else if (fallback) return fallback;
else throw new Error(`Unsupported protocol ${protocol}`);
}
// 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) {
return routeAddressUtil(
isValidAddressEvm,
isValidAddressSealevel,
false,
{
[ProtocolType.Ethereum]: isValidAddressEvm,
[ProtocolType.Sealevel]: isValidAddressSealevel,
[ProtocolType.Cosmos]: isValidAddressCosmos,
},
address,
false,
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) {
return routeAddressUtil(
normalizeAddressEvm,
normalizeAddressSealevel,
{
[ProtocolType.Ethereum]: normalizeAddressEvm,
[ProtocolType.Sealevel]: normalizeAddressSealevel,
[ProtocolType.Cosmos]: normalizeAddressCosmos,
},
address,
address,
protocol,
@ -114,15 +147,22 @@ export function eqAddressSol(a1: Address, a2: Address) {
return normalizeAddressSealevel(a1) === normalizeAddressSealevel(a2);
}
export function eqAddressCosmos(a1: Address, a2: Address) {
return normalizeAddressCosmos(a1) === normalizeAddressCosmos(a2);
}
export function eqAddress(a1: Address, a2: Address) {
const p1 = getAddressProtocolType(a1);
const p2 = getAddressProtocolType(a2);
if (p1 !== p2) return false;
return routeAddressUtil(
(_a1) => eqAddressEvm(_a1, a2),
(_a1) => eqAddressSol(_a1, a2),
false,
{
[ProtocolType.Ethereum]: (_a1) => eqAddressEvm(_a1, a2),
[ProtocolType.Sealevel]: (_a1) => eqAddressSol(_a1, a2),
[ProtocolType.Cosmos]: (_a1) => eqAddressCosmos(_a1, a2),
},
a1,
false,
p1,
);
}
@ -135,18 +175,27 @@ export function isValidTransactionHashSealevel(input: string) {
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) {
if (protocol === ProtocolType.Ethereum) {
return isValidTransactionHashEvm(input);
} else if (protocol === ProtocolType.Sealevel) {
return isValidTransactionHashSealevel(input);
} else if (protocol === ProtocolType.Cosmos) {
return isValidTransactionHashCosmos(input);
} else {
return false;
}
}
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) {
@ -166,31 +215,40 @@ export function capitalizeAddress(address: Address) {
else return address.toUpperCase();
}
// For EVM addresses only, kept for backwards compatibility and convenience
export function addressToBytes32(address: Address): string {
return ethersUtils
.hexZeroPad(ethersUtils.hexStripZeros(address), 32)
.toLowerCase();
}
// For EVM addresses only, kept for backwards compatibility and convenience
export function bytes32ToAddress(bytes32: HexString): Address {
return ethersUtils.getAddress(bytes32.slice(-40));
}
export function addressToBytesEvm(address: Address): Uint8Array {
const addrBytes32 = addressToBytes32(address);
return Buffer.from(addrBytes32.substring(2), 'hex');
return Buffer.from(strip0x(addrBytes32), 'hex');
}
export function addressToBytesSol(address: Address): Uint8Array {
return new PublicKey(address).toBytes();
}
export function addressToBytesCosmos(address: Address): Uint8Array {
return fromBech32(address).data;
}
export function addressToBytes(address: Address, protocol?: ProtocolType) {
return routeAddressUtil(
addressToBytesEvm,
addressToBytesSol,
new Uint8Array(),
{
[ProtocolType.Ethereum]: addressToBytesEvm,
[ProtocolType.Sealevel]: addressToBytesSol,
[ProtocolType.Cosmos]: addressToBytesCosmos,
},
address,
new Uint8Array(),
protocol,
);
}
@ -199,17 +257,38 @@ export function addressToByteHexString(
address: string,
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(
bytes: Buffer,
bytes: Uint8Array,
toProtocol: ProtocolType,
prefix?: string,
) {
if (toProtocol === ProtocolType.Sealevel) {
return new PublicKey(bytes).toBase58();
} else if (toProtocol === ProtocolType.Ethereum) {
return bytes32ToAddress(bytes.toString('hex'));
if (toProtocol === ProtocolType.Ethereum) {
return bytesToAddressEvm(bytes);
} else if (toProtocol === ProtocolType.Sealevel) {
return bytesToAddressSol(bytes);
} else if (toProtocol === ProtocolType.Cosmos) {
return bytesToAddressCosmos(bytes, prefix!);
} else {
throw new Error(`Unsupported protocol for address ${toProtocol}`);
}
@ -218,30 +297,14 @@ export function bytesToProtocolAddress(
export function convertToProtocolAddress(
address: string,
protocol: ProtocolType,
prefix?: string,
) {
const currentProtocol = getAddressProtocolType(address);
if (!currentProtocol)
throw new Error(`Unknown address protocol for ${address}`);
if (currentProtocol === protocol) return address;
if (
currentProtocol === ProtocolType.Ethereum &&
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}`,
);
}
const addressBytes = addressToBytes(address, currentProtocol);
return bytesToProtocolAddress(addressBytes, protocol, prefix);
}
export function ensure0x(hexstr: string) {

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

@ -2758,6 +2758,173 @@ __metadata:
languageName: node
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":
version: 0.8.1
resolution: "@cspotcode/source-map-support@npm:0.8.1"
@ -3930,12 +4097,12 @@ __metadata:
languageName: node
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
resolution: "@hyperlane-xyz/core@workspace:solidity"
dependencies:
"@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-waffle": ^2.0.3
"@openzeppelin/contracts": ^4.8.0
@ -3958,12 +4125,12 @@ __metadata:
languageName: unknown
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
resolution: "@hyperlane-xyz/helloworld@workspace:typescript/helloworld"
dependencies:
"@hyperlane-xyz/core": 1.5.4-beta0
"@hyperlane-xyz/sdk": 1.5.4-beta0
"@hyperlane-xyz/core": 3.1.0-beta0
"@hyperlane-xyz/sdk": 3.1.0-beta0
"@nomiclabs/hardhat-ethers": ^2.2.1
"@nomiclabs/hardhat-waffle": ^2.0.3
"@openzeppelin/contracts-upgradeable": ^4.8.0
@ -4003,9 +4170,9 @@ __metadata:
"@ethersproject/experimental": ^5.7.0
"@ethersproject/hardware-wallets": ^5.7.0
"@ethersproject/providers": ^5.7.2
"@hyperlane-xyz/helloworld": 1.5.4-beta0
"@hyperlane-xyz/sdk": 1.5.4-beta0
"@hyperlane-xyz/utils": 1.5.4-beta0
"@hyperlane-xyz/helloworld": 3.1.0-beta0
"@hyperlane-xyz/sdk": 3.1.0-beta0
"@hyperlane-xyz/utils": 3.1.0-beta0
"@nomiclabs/hardhat-ethers": ^2.2.1
"@nomiclabs/hardhat-etherscan": ^3.0.3
"@nomiclabs/hardhat-waffle": ^2.0.3
@ -4049,12 +4216,14 @@ __metadata:
languageName: unknown
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
resolution: "@hyperlane-xyz/sdk@workspace:typescript/sdk"
dependencies:
"@hyperlane-xyz/core": 1.5.4-beta0
"@hyperlane-xyz/utils": 1.5.4-beta0
"@cosmjs/cosmwasm-stargate": ^0.31.3
"@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-waffle": ^2.0.3
"@solana/spl-token": ^0.3.8
@ -4066,6 +4235,7 @@ __metadata:
"@wagmi/chains": ^0.2.6
chai: ^4.3.6
coingecko-api: ^1.0.10
cosmjs-types: ^0.9.0
cross-fetch: ^3.1.5
debug: ^4.3.4
dotenv: ^10.0.0
@ -4084,10 +4254,11 @@ __metadata:
languageName: unknown
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
resolution: "@hyperlane-xyz/utils@workspace:typescript/utils"
dependencies:
"@cosmjs/encoding": ^0.31.3
"@solana/web3.js": ^1.78.0
bignumber.js: ^9.1.1
chai: ^4.3.0
@ -4312,7 +4483,7 @@ __metadata:
languageName: node
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
resolution: "@noble/hashes@npm:1.3.2"
checksum: fe23536b436539d13f90e4b9be843cc63b1b17666a07634a2b1259dded6f490be3d050249e6af98076ea8f2ea0d56f578773c2197f2aa0eeaa5fba5bc18ba474
@ -4869,6 +5040,79 @@ __metadata:
languageName: node
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":
version: 0.3.3
resolution: "@resolver-engine/core@npm:0.3.3"
@ -5486,6 +5730,13 @@ __metadata:
languageName: node
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":
version: 5.1.1
resolution: "@types/lru-cache@npm:5.1.1"
@ -5540,6 +5791,15 @@ __metadata:
languageName: node
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":
version: 10.17.60
resolution: "@types/node@npm:10.17.60"
@ -6601,6 +6861,15 @@ __metadata:
languageName: node
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":
version: 6.26.0
resolution: "babel-code-frame@npm:6.26.0"
@ -7255,7 +7524,7 @@ __metadata:
languageName: node
linkType: hard
"base64-js@npm:^1.3.1":
"base64-js@npm:^1.3.0, base64-js@npm:^1.3.1":
version: 1.5.1
resolution: "base64-js@npm:1.5.1"
checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005
@ -7286,7 +7555,7 @@ __metadata:
languageName: node
linkType: hard
"bech32@npm:1.1.4":
"bech32@npm:1.1.4, bech32@npm:^1.1.4":
version: 1.1.4
resolution: "bech32@npm:1.1.4"
checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b
@ -8559,6 +8828,23 @@ __metadata:
languageName: node
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":
version: 1.2.2
resolution: "crc-32@npm:1.2.2"
@ -10866,6 +11152,16 @@ __metadata:
languageName: node
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":
version: 0.3.3
resolution: "for-each@npm:0.3.3"
@ -11501,6 +11797,15 @@ __metadata:
languageName: node
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":
version: 10.0.2
resolution: "globby@npm:10.0.2"
@ -13531,6 +13836,22 @@ __metadata:
languageName: node
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":
version: 2.0.5
resolution: "lilconfig@npm:2.0.5"
@ -13698,6 +14019,13 @@ __metadata:
languageName: node
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":
version: 2.0.0
resolution: "looper@npm:2.0.0"
@ -15325,6 +15653,13 @@ __metadata:
languageName: node
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":
version: 1.0.1
resolution: "parent-module@npm:1.0.1"
@ -15841,6 +16176,30 @@ __metadata:
languageName: node
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":
version: 2.0.7
resolution: "proxy-addr@npm:2.0.7"
@ -16193,6 +16552,13 @@ __metadata:
languageName: node
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":
version: 0.6.2
resolution: "rechoir@npm:0.6.2"
@ -17901,6 +18267,13 @@ __metadata:
languageName: node
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":
version: 6.1.0
resolution: "sync-request@npm:6.1.0"
@ -18648,6 +19021,13 @@ __metadata:
languageName: node
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":
version: 5.11.0
resolution: "undici@npm:5.11.0"
@ -20005,7 +20385,7 @@ __metadata:
languageName: node
linkType: hard
"ws@npm:^7.4.5":
"ws@npm:^7, ws@npm:^7.4.5":
version: 7.5.9
resolution: "ws@npm:7.5.9"
peerDependencies:
@ -20102,6 +20482,16 @@ __metadata:
languageName: node
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":
version: 4.0.2
resolution: "xtend@npm:4.0.2"

Loading…
Cancel
Save