@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
196 lines • 7.7 kB
JavaScript
import { ProtocolType, addressToBytes32, convertToProtocolAddress, isAddressCosmos, } from '@hyperlane-xyz/utils';
import { BaseCosmNativeAdapter } from '../../app/MultiProtocolApp.js';
import { PROTOCOL_TO_DEFAULT_NATIVE_TOKEN } from '../nativeTokenMetadata.js';
const COSMOS_TYPE_URL_SEND = '/cosmos.bank.v1beta1.MsgSend';
const COSMOS_EMPTY_VALUE = '';
class CosmosModuleTokenAdapter extends BaseCosmNativeAdapter {
chainName;
multiProvider;
addresses;
properties;
// use getter so Tokens which extend this base class
// can overwrite this denom
async getDenom() {
return this.properties.denom;
}
constructor(chainName, multiProvider, addresses, properties) {
if (!properties.denom) {
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 denom = await this.getDenom();
// if the address is a cosmos address we can simply read the account balance
// of that address. The address can also be an ETH address format indicating
// that the balance of a Hyp Token Contract should be returned. In this case
// we get the token by it's id and return the bridged supply which equals the
// balance the token has.
if (isAddressCosmos(address)) {
const coin = await provider.getBalance(address, denom);
return BigInt(coin.amount);
}
else {
const { bridged_supply } = await provider.query.warp.BridgedSupply({
id: address,
});
return BigInt(bridged_supply?.amount ?? '0');
}
}
async getMetadata() {
const token = await this.multiProvider.getNativeToken(this.chainName);
return {
symbol: token.symbol,
name: token.name,
decimals: token.decimals,
};
}
async getMinimumTransferAmount(_recipient) {
return 0n;
}
async isApproveRequired() {
return false;
}
populateApproveTx(_transferParams) {
throw new Error('Approve not required for native tokens');
}
async isRevokeApprovalRequired(_, __) {
return false;
}
async populateTransferTx(transferParams) {
const denom = await this.getDenom();
return {
typeUrl: COSMOS_TYPE_URL_SEND,
value: {
fromAddress: transferParams.fromAccountOwner,
toAddress: transferParams.recipient,
amount: [
{
denom,
amount: transferParams.weiAmountOrId.toString(),
},
],
},
};
}
async getTotalSupply() {
const provider = await this.getProvider();
const denom = await this.getDenom();
const supply = await provider.query.bank.supplyOf(denom);
return BigInt(supply.amount);
}
}
export class CosmNativeHypCollateralAdapter extends CosmosModuleTokenAdapter {
chainName;
multiProvider;
addresses;
tokenId;
constructor(chainName, multiProvider, addresses) {
super(chainName, multiProvider, addresses, {
denom: PROTOCOL_TO_DEFAULT_NATIVE_TOKEN[ProtocolType.CosmosNative].denom,
});
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
this.tokenId = addresses.token;
}
async getDenom() {
const provider = await this.getProvider();
const { token } = await provider.query.warp.Token({ id: this.tokenId });
return token?.origin_denom ?? '';
}
async getDomains() {
const provider = await this.getProvider();
const remoteRouters = await provider.query.warp.RemoteRouters({
id: this.tokenId,
});
return remoteRouters.remote_routers.map((router) => router.receiver_domain);
}
async getRouterAddress(domain) {
const provider = await this.getProvider();
const remoteRouters = await provider.query.warp.RemoteRouters({
id: this.tokenId,
});
const router = remoteRouters.remote_routers.find((router) => router.receiver_domain === domain);
if (!router) {
throw new Error(`Router with domain "${domain}" not found`);
}
return Buffer.from(router.receiver_contract);
}
async getAllRouters() {
const provider = await this.getProvider();
const remoteRouters = await provider.query.warp.RemoteRouters({
id: this.tokenId,
});
return remoteRouters.remote_routers.map((router) => ({
domain: router.receiver_domain,
address: Buffer.from(router.receiver_contract),
}));
}
async getBridgedSupply() {
const provider = await this.getProvider();
const { bridged_supply } = await provider.query.warp.BridgedSupply({
id: this.tokenId,
});
if (!bridged_supply) {
return undefined;
}
return BigInt(bridged_supply.amount);
}
async quoteTransferRemoteGas(destination, _, customHook) {
const provider = await this.getProvider();
const { gas_payment } = await provider.query.warp.QuoteRemoteTransfer({
id: this.tokenId,
destination_domain: destination.toString(),
custom_hook_id: customHook || COSMOS_EMPTY_VALUE,
custom_hook_metadata: COSMOS_EMPTY_VALUE,
});
return {
addressOrDenom: gas_payment[0]?.denom,
amount: BigInt(gas_payment[0]?.amount ?? '0'),
};
}
async populateTransferRemoteTx(params) {
if (!params.interchainGas) {
params.interchainGas = await this.quoteTransferRemoteGas(params.destination, undefined, params.customHook);
}
const provider = await this.getProvider();
const { remote_routers } = await provider.query.warp.RemoteRouters({
id: this.tokenId,
});
const router = remote_routers.find((router) => router.receiver_domain === params.destination);
if (!router) {
throw new Error(`Failed to find remote router for token id and destination: ${this.tokenId},${params.destination}`);
}
if (!params.interchainGas.addressOrDenom) {
throw new Error(`Require denom for max fee, didn't receive and denom in the interchainGas quote`);
}
const msg = {
typeUrl: '/hyperlane.warp.v1.MsgRemoteTransfer',
value: {
sender: params.fromAccountOwner,
recipient: addressToBytes32(convertToProtocolAddress(params.recipient, ProtocolType.Ethereum), ProtocolType.Ethereum),
amount: params.weiAmountOrId.toString(),
token_id: this.tokenId,
destination_domain: params.destination,
gas_limit: router.gas,
max_fee: {
denom: params.interchainGas.addressOrDenom || '',
amount: params.interchainGas.amount.toString(),
},
},
};
return msg;
}
}
export class CosmNativeHypSyntheticAdapter extends CosmNativeHypCollateralAdapter {
async getTokenDenom() {
return `hyperlane/${this.tokenId}`;
}
}
//# sourceMappingURL=CosmosModuleTokenAdapter.js.map