@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
332 lines • 10.8 kB
JavaScript
import { addressToBytes32, assert, strip0x, } from '@hyperlane-xyz/utils';
import { BaseCosmWasmAdapter } from '../../app/MultiProtocolApp.js';
// Interacts with IBC denom tokens in CosmWasm
export class CwNativeTokenAdapter extends BaseCosmWasmAdapter {
chainName;
multiProvider;
addresses;
denom;
constructor(chainName, multiProvider, addresses, denom) {
super(chainName, multiProvider, addresses);
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
this.denom = denom;
}
async getBalance(address) {
const provider = await this.getProvider();
const balance = await provider.getBalance(address, this.denom);
return BigInt(balance.amount);
}
async getMetadata() {
throw new Error('Metadata not available to native tokens');
}
async getMinimumTransferAmount(_recipient) {
return 0n;
}
async isApproveRequired() {
return false;
}
async isRevokeApprovalRequired(_owner, _spender) {
return false;
}
async populateApproveTx(_params) {
throw new Error('Approve not required for native tokens');
}
async populateTransferTx({ recipient, weiAmountOrId, }) {
// TODO: check if this works with execute instruction? (contract type, empty message)
return {
contractAddress: recipient,
msg: {},
funds: [
{
amount: weiAmountOrId.toString(),
denom: this.denom,
},
],
};
}
async getTotalSupply() {
// Not implemented.
return undefined;
}
}
// Interacts with CW20/721 contracts
export class CwTokenAdapter extends BaseCosmWasmAdapter {
chainName;
multiProvider;
addresses;
constructor(chainName, multiProvider, addresses) {
super(chainName, multiProvider, addresses);
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
}
async queryToken(msg) {
const provider = await this.getProvider();
const response = await provider.queryContractSmart(this.addresses.token, msg);
return response;
}
prepareToken(msg, funds) {
return {
contractAddress: this.addresses.token,
msg,
funds,
};
}
async getBalance(address) {
const provider = await this.getProvider();
const balance = await provider.getBalance(address, this.addresses.token);
return BigInt(balance.amount);
}
async getMetadata() {
return this.queryToken({
token_info: {},
});
}
async getMinimumTransferAmount(_recipient) {
return 0n;
}
async isApproveRequired() {
return false;
}
async isRevokeApprovalRequired(_owner, _spender) {
return false;
}
async populateApproveTx({ weiAmountOrId, recipient, }) {
// TODO: check existing allowance
return this.prepareToken({
increase_allowance: {
spender: recipient,
amount: weiAmountOrId.toString(),
expires: {
never: {},
},
},
});
}
async populateTransferTx({ weiAmountOrId, recipient, }) {
return this.prepareToken({
transfer: {
recipient,
amount: weiAmountOrId.toString(),
},
});
}
async getTotalSupply() {
// Not implemented.
return undefined;
}
}
export class CwHypSyntheticAdapter extends CwTokenAdapter {
chainName;
multiProvider;
addresses;
constructor(chainName, multiProvider, addresses) {
super(chainName, multiProvider, addresses);
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
}
async queryRouter(msg) {
const provider = await this.getProvider();
const response = await provider.queryContractSmart(this.addresses.warpRouter, msg);
return response;
}
prepareRouter(msg, funds) {
return {
contractAddress: this.addresses.warpRouter,
msg,
funds,
};
}
async getTokenType() {
const resp = await this.queryRouter({
token_default: {
token_type: {},
},
});
return resp.type;
}
async getInterchainSecurityModule() {
throw new Error('Router does not support ISM config yet.');
}
async getOwner() {
const resp = await this.queryRouter({
ownable: {
get_owner: {},
},
});
return resp.owner;
}
async getDomains() {
const resp = await this.queryRouter({
router: {
domains: {},
},
});
return resp.domains;
}
async getRouterAddress(domain) {
const resp = await this.queryRouter({
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() {
const resp = await this.queryRouter({
router: {
list_routes: {},
},
});
return resp.routes
.filter((r) => r.route != null)
.map((r) => ({
domain: r.domain,
address: Buffer.from(r.route, 'hex'),
}));
}
getBridgedSupply() {
return this.getTotalSupply();
}
async quoteTransferRemoteGas(_destination) {
// TODO this may require separate queries to get the hook and/or mailbox
// before making a query for the QuoteDispatchResponse
// Punting on this given that only static quotes are used for now
// const resp = await this.queryRouter<QuoteDispatchResponse>({
// router: {
// TODO: {},
// },
// });
// return {
// amount: BigInt(resp.gas_amount?.amount || 0),
// addressOrDenom: resp.gas_amount?.denom,
// };
throw new Error('CW adapter quoteTransferRemoteGas method not implemented');
}
async populateTransferRemoteTx({ destination, recipient, weiAmountOrId, interchainGas, }) {
if (!interchainGas)
interchainGas = await this.quoteTransferRemoteGas(destination);
const { addressOrDenom: igpDenom, amount: igpAmount } = interchainGas;
assert(igpDenom, 'Interchain gas denom required for Cosmos');
return this.prepareRouter({
transfer_remote: {
dest_domain: destination,
recipient: strip0x(addressToBytes32(recipient)),
amount: weiAmountOrId.toString(),
},
}, [
{
amount: igpAmount.toString(),
denom: igpDenom,
},
]);
}
}
export class CwHypNativeAdapter extends CwNativeTokenAdapter {
chainName;
multiProvider;
addresses;
cw20adapter;
constructor(chainName, multiProvider, addresses) {
super(chainName, multiProvider, addresses, '');
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
this.cw20adapter = new CwHypSyntheticAdapter(chainName, multiProvider, {
token: '',
warpRouter: addresses.warpRouter,
});
}
async getBalance(address) {
const provider = await this.getProvider();
const denom = await this.getDenom();
const balance = await provider.getBalance(address, denom);
return BigInt(balance.amount);
}
async getInterchainSecurityModule() {
return this.cw20adapter.getInterchainSecurityModule();
}
async getOwner() {
return this.cw20adapter.getOwner();
}
async getDomains() {
return this.cw20adapter.getDomains();
}
async getRouterAddress(domain) {
return this.cw20adapter.getRouterAddress(domain);
}
async getAllRouters() {
return this.cw20adapter.getAllRouters();
}
getBridgedSupply() {
return this.getBalance(this.addresses.warpRouter);
}
quoteTransferRemoteGas(destination) {
return this.cw20adapter.quoteTransferRemoteGas(destination);
}
async getDenom() {
const tokenType = await this.cw20adapter.getTokenType();
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, interchainGas, }) {
const collateralDenom = await this.getDenom();
if (!interchainGas)
interchainGas = await this.quoteTransferRemoteGas(destination);
const { addressOrDenom: igpDenom, amount: igpAmount } = interchainGas;
assert(igpDenom, 'Interchain gas denom required for Cosmos');
// If more than one denom is used as funds, they must be sorted by the denom
const funds = collateralDenom === igpDenom
? [
{
amount: (BigInt(weiAmountOrId) + igpAmount).toString(),
denom: collateralDenom,
},
]
: [
{
amount: weiAmountOrId.toString(),
denom: collateralDenom,
},
{
amount: igpAmount.toString(),
denom: igpDenom,
},
].sort((a, b) => a.denom.localeCompare(b.denom));
return this.cw20adapter.prepareRouter({
transfer_remote: {
dest_domain: destination,
recipient: strip0x(addressToBytes32(recipient)),
amount: weiAmountOrId.toString(),
},
}, funds);
}
}
export class CwHypCollateralAdapter extends CwHypNativeAdapter {
chainName;
multiProvider;
addresses;
constructor(chainName, multiProvider, addresses) {
super(chainName, multiProvider, addresses);
this.chainName = chainName;
this.multiProvider = multiProvider;
this.addresses = addresses;
}
async isRevokeApprovalRequired(_owner, _spender) {
return false;
}
}
//# sourceMappingURL=CosmWasmTokenAdapter.js.map