@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
116 lines • 4.82 kB
JavaScript
import { constants } from 'ethers';
import { BaseFee__factory, ERC20__factory, LinearFee__factory, RoutingFee__factory, } from '@hyperlane-xyz/core';
import { assert } from '@hyperlane-xyz/utils';
import { HyperlaneReader } from '../utils/HyperlaneReader.js';
import { OnchainTokenFeeType, TokenFeeType, onChainTypeToTokenFeeTypeMap, } from './types.js';
import { MAX_BPS, convertToBps } from './utils.js';
export class EvmTokenFeeReader extends HyperlaneReader {
multiProvider;
chain;
constructor(multiProvider, chain) {
super(multiProvider, chain);
this.multiProvider = multiProvider;
this.chain = chain;
}
async deriveTokenFeeConfig(params) {
const { address, routingDestinations } = params;
const tokenFee = BaseFee__factory.connect(address, this.provider);
let derivedConfig;
const onchainFeeType = await tokenFee.feeType();
switch (onchainFeeType) {
case OnchainTokenFeeType.LinearFee:
derivedConfig = await this.deriveLinearFeeConfig(address);
break;
case OnchainTokenFeeType.ProgressiveFee:
derivedConfig = await this.deriveProgressiveFeeConfig(address);
break;
case OnchainTokenFeeType.RegressiveFee:
derivedConfig = await this.deriveRegressiveFeeConfig(address);
break;
case OnchainTokenFeeType.RoutingFee:
assert(routingDestinations, `routingDestinations required for ${onChainTypeToTokenFeeTypeMap[onchainFeeType]}`);
derivedConfig = await this.deriveRoutingFeeConfig({
address,
routingDestinations,
});
break;
default:
throw new Error(`Unsupported token fee type: ${onchainFeeType}`);
}
return derivedConfig;
}
async deriveLinearFeeConfig(address) {
const tokenFee = LinearFee__factory.connect(address, this.provider);
const [token, owner, maxFee, halfAmount] = await Promise.all([
tokenFee.token(),
tokenFee.owner(),
tokenFee.maxFee(),
tokenFee.halfAmount(),
]);
const maxFeeBn = BigInt(maxFee.toString());
const halfAmountBn = BigInt(halfAmount.toString());
const bps = convertToBps(maxFeeBn, halfAmountBn);
return {
type: TokenFeeType.LinearFee,
maxFee: maxFeeBn,
halfAmount: halfAmountBn,
address,
bps,
token,
owner,
};
}
async deriveProgressiveFeeConfig(_address) {
throw new Error('Not implemented');
}
async deriveRegressiveFeeConfig(_address) {
throw new Error('Not implemented');
}
async deriveRoutingFeeConfig(params) {
const { address, routingDestinations } = params;
const routingFee = RoutingFee__factory.connect(address, this.provider);
const [token, owner, maxFee, halfAmount] = await Promise.all([
routingFee.token(),
routingFee.owner(),
routingFee.maxFee(),
routingFee.halfAmount(),
]);
const maxFeeBn = BigInt(maxFee.toString());
const halfAmountBn = BigInt(halfAmount.toString());
const feeContracts = {};
if (routingDestinations)
await Promise.all(routingDestinations.map(async (destination) => {
const subFeeAddress = await routingFee.feeContracts(destination);
if (subFeeAddress === constants.AddressZero)
return;
const chainName = this.multiProvider.getChainName(destination);
feeContracts[chainName] = await this.deriveTokenFeeConfig({
address: subFeeAddress,
// Currently, it's not possible to configure nested routing fees domains,
// but we should not expect that to exist
routingDestinations,
});
}));
return {
type: TokenFeeType.RoutingFee,
maxFee: maxFeeBn,
halfAmount: halfAmountBn,
address,
token,
owner,
feeContracts,
};
}
async convertFromBps(bps, tokenAddress) {
// Assume maxFee is uint256.max / token.totalSupply
const token = ERC20__factory.connect(tokenAddress, this.provider);
const totalSupplyBn = await token.totalSupply();
const maxFee = BigInt(constants.MaxUint256.div(totalSupplyBn).toString());
const halfAmount = ((maxFee / 2n) * MAX_BPS) / bps;
return {
maxFee,
halfAmount,
};
}
}
//# sourceMappingURL=EvmTokenFeeReader.js.map