@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
192 lines • 7.66 kB
JavaScript
import { assert } from '@hyperlane-xyz/utils';
import { BaseCosmosAdapter } from '../../app/MultiProtocolApp.js';
import { CwHypCollateralAdapter } from './CosmWasmTokenAdapter.js';
const COSMOS_IBC_TRANSFER_TIMEOUT = 600_000; // 10 minutes
// Interacts with native tokens on a Cosmos chain (e.g TIA on Celestia)
export class CosmNativeTokenAdapter extends BaseCosmosAdapter {
chainName;
multiProvider;
addresses;
properties;
constructor(chainName, multiProvider, addresses, properties) {
if (!properties.ibcDenom)
throw new Error('Missing properties for CosmNativeTokenAdapter');
super(chainName, multiProvider, addresses);
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
this.properties = properties;
}
async getBalance(address) {
const provider = await this.getProvider();
const coin = await provider.getBalance(address, this.properties.ibcDenom);
return BigInt(coin.amount);
}
async getMetadata() {
const { nativeToken } = this.multiProvider.getChainMetadata(this.chainName);
assert(nativeToken, `Native token data is required for ${CosmNativeTokenAdapter.name}`);
return {
name: nativeToken.name,
symbol: nativeToken.symbol,
decimals: nativeToken.decimals,
};
}
async getMinimumTransferAmount(_recipient) {
return 0n;
}
async isApproveRequired() {
return false;
}
async isRevokeApprovalRequired(_owner, _spender) {
return false;
}
populateApproveTx(_transferParams) {
throw new Error('Approve not required for native tokens');
}
async populateTransferTx(transferParams) {
return {
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
value: {
fromAddress: transferParams.fromAccountOwner,
toAddress: transferParams.recipient,
amount: [
{
amount: transferParams.weiAmountOrId.toString(),
denom: this.properties.ibcDenom,
},
],
},
};
}
async getTotalSupply() {
// Not implemented.
return undefined;
}
}
// Interacts with native tokens on a Cosmos chain and adds support for IBC transfers
// This implements the IHypTokenAdapter interface but it's an imperfect fit as some
// methods don't apply to IBC transfers the way they do for Warp transfers
export class CosmIbcTokenAdapter extends CosmNativeTokenAdapter {
chainName;
multiProvider;
addresses;
properties;
constructor(chainName, multiProvider, addresses, properties) {
if (!properties.ibcDenom ||
!properties.sourcePort ||
!properties.sourceChannel)
throw new Error('Missing properties for CosmNativeIbcTokenAdapter');
super(chainName, multiProvider, addresses, properties);
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
this.properties = properties;
}
getDomains() {
throw new Error('Method not applicable to IBC adapters');
}
getRouterAddress(_domain) {
throw new Error('Method not applicable to IBC adapters');
}
getAllRouters() {
throw new Error('Method not applicable to IBC adapters');
}
getBridgedSupply() {
throw new Error('Method not applicable to IBC adapters');
}
async quoteTransferRemoteGas({ destination: _destination, }) {
// TODO implement IBC interchain transfer gas estimation here
return {
igpQuote: { amount: 0n, addressOrDenom: this.properties.ibcDenom },
};
}
getMetadata() {
throw new Error('Metadata not available to native tokens');
}
async populateTransferTx(_transferParams) {
throw new Error('TODO not yet implemented');
}
async populateTransferRemoteTx(transferParams, memo = '') {
if (!transferParams.fromAccountOwner)
throw new Error('fromAccountOwner is required for ibc transfers');
const value = {
sourcePort: this.properties.sourcePort,
sourceChannel: this.properties.sourceChannel,
token: {
denom: this.properties.ibcDenom,
amount: transferParams.weiAmountOrId.toString(),
},
sender: transferParams.fromAccountOwner,
receiver: transferParams.recipient,
// Represented as nano-seconds
timeoutTimestamp: BigInt(new Date().getTime() + COSMOS_IBC_TRANSFER_TIMEOUT) * 1000000n,
memo,
};
return {
typeUrl: '/ibc.applications.transfer.v1.MsgTransfer',
value,
};
}
}
// A wrapper for the CosmIbcTokenAdapter that adds support auto-initiated warp transfers
// A.k.a. 'One-Click' cosmos to evm transfers
export class CosmIbcToWarpTokenAdapter extends CosmIbcTokenAdapter {
chainName;
multiProvider;
addresses;
properties;
constructor(chainName, multiProvider, addresses, properties) {
super(chainName, multiProvider, addresses, properties);
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
this.properties = properties;
}
async quoteTransferRemoteGas({ destination: _destination, }) {
// TODO implement IBC interchain transfer gas estimation here
return {
igpQuote: {
amount: 0n,
addressOrDenom: this.properties.intermediateIbcDenom,
},
};
}
async populateTransferRemoteTx(transferParams) {
const cwAdapter = new CwHypCollateralAdapter(this.properties.intermediateChainName, this.multiProvider, {
token: this.properties.intermediateIbcDenom,
warpRouter: this.addresses.intermediateRouterAddress,
});
const { interchainGas } = transferParams;
assert(interchainGas?.igpQuote.addressOrDenom === this.properties.ibcDenom, 'Only same-denom interchain gas is supported for IBC to Warp transfers');
// This transformation is necessary to ensure the CW adapter recognizes the gas
// denom is the same as this adapter's denom (e.g. utia & igp/77...)
const intermediateInterchainGas = {
addressOrDenom: this.properties.intermediateIbcDenom,
amount: interchainGas?.igpQuote.amount || 0n,
};
const transfer = await cwAdapter.populateTransferRemoteTx({
...transferParams,
interchainGas: { igpQuote: intermediateInterchainGas },
});
const cwMemo = {
wasm: {
contract: transfer.contractAddress,
msg: transfer.msg,
funds: transfer.funds,
},
};
const memo = JSON.stringify(cwMemo);
if (transfer.funds?.length !== 1) {
// Only transfers where the interchain gas denom matches the token are currently supported
throw new Error('Expected exactly one denom for IBC to Warp transfer');
}
// Grab amount from the funds details which accounts for interchain gas
const weiAmountOrId = transfer.funds[0].amount;
return super.populateTransferRemoteTx({
...transferParams,
weiAmountOrId,
recipient: this.addresses.intermediateRouterAddress,
}, memo);
}
}
//# sourceMappingURL=CosmosTokenAdapter.js.map