@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
227 lines • 9.39 kB
JavaScript
import { z } from 'zod';
import { ZBigNumberish, ZBps, ZChainName, ZHash, } from '../metadata/customZodTypes.js';
import { MAX_BPS_DECIMALS, convertToBps, isBpsPrecisionValid, } from './utils.js';
// Matches the enum in BaseFee.sol
export var OnchainTokenFeeType;
(function (OnchainTokenFeeType) {
OnchainTokenFeeType[OnchainTokenFeeType["LinearFee"] = 1] = "LinearFee";
OnchainTokenFeeType[OnchainTokenFeeType["RegressiveFee"] = 2] = "RegressiveFee";
OnchainTokenFeeType[OnchainTokenFeeType["ProgressiveFee"] = 3] = "ProgressiveFee";
OnchainTokenFeeType[OnchainTokenFeeType["RoutingFee"] = 4] = "RoutingFee";
OnchainTokenFeeType[OnchainTokenFeeType["CrossCollateralRoutingFee"] = 5] = "CrossCollateralRoutingFee";
OnchainTokenFeeType[OnchainTokenFeeType["OffchainQuotedLinearFee"] = 6] = "OffchainQuotedLinearFee";
})(OnchainTokenFeeType || (OnchainTokenFeeType = {}));
export var TokenFeeType;
(function (TokenFeeType) {
TokenFeeType["LinearFee"] = "LinearFee";
TokenFeeType["ProgressiveFee"] = "ProgressiveFee";
TokenFeeType["RegressiveFee"] = "RegressiveFee";
TokenFeeType["RoutingFee"] = "RoutingFee";
TokenFeeType["CrossCollateralRoutingFee"] = "CrossCollateralRoutingFee";
TokenFeeType["OffchainQuotedLinearFee"] = "OffchainQuotedLinearFee";
})(TokenFeeType || (TokenFeeType = {}));
export const ImmutableTokenFeeType = [
TokenFeeType.LinearFee,
TokenFeeType.RegressiveFee,
TokenFeeType.ProgressiveFee,
];
// Mapping between the on-chain token fee type (uint) and the token fee type (string)
export const onChainTypeToTokenFeeTypeMap = {
[OnchainTokenFeeType.LinearFee]: TokenFeeType.LinearFee,
[OnchainTokenFeeType.RegressiveFee]: TokenFeeType.RegressiveFee,
[OnchainTokenFeeType.ProgressiveFee]: TokenFeeType.ProgressiveFee,
[OnchainTokenFeeType.RoutingFee]: TokenFeeType.RoutingFee,
[OnchainTokenFeeType.CrossCollateralRoutingFee]: TokenFeeType.CrossCollateralRoutingFee,
[OnchainTokenFeeType.OffchainQuotedLinearFee]: TokenFeeType.OffchainQuotedLinearFee,
};
// keccak256("RoutingFee.DEFAULT_ROUTER")
export const DEFAULT_ROUTER_KEY = '0x6e086cd647d6eb8b516856666e2c1465fb8a6a58d3a75938362acc674eacaf47';
// ====== SHARED SCHEMAS ======
// For deployed/read configs - token is required for BaseFee implementations
export const BaseFeeConfigSchema = z.object({
token: ZHash,
owner: ZHash,
});
// For input configs - token is NOT specified by user, resolved at deploy time based on token type
export const BaseFeeConfigInputSchema = z.object({
owner: ZHash,
});
export const FeeParametersSchema = z.object({
maxFee: ZBigNumberish,
halfAmount: ZBigNumberish,
});
const StandardFeeConfigBaseSchema = BaseFeeConfigSchema.merge(FeeParametersSchema);
const BpsConfigSchema = StandardFeeConfigBaseSchema.extend({
bps: ZBps,
});
// Shared schema for offchain quote signer configuration
export const QuoteSignersSchema = z.object({
quoteSigners: z.array(ZHash).optional(),
});
// ====== INDIVIDUAL FEE SCHEMAS ======
export const LinearFeeConfigSchema = BpsConfigSchema.extend({
type: z.literal(TokenFeeType.LinearFee),
});
// Linear Fee Input - only requires bps & type, token is optional
export const LinearFeeInputConfigSchema = BaseFeeConfigInputSchema.extend({
type: z.literal(TokenFeeType.LinearFee),
bps: ZBps.optional(),
...FeeParametersSchema.partial().shape,
})
.superRefine((v, ctx) => {
const hasBps = v.bps !== undefined;
const hasFeeParams = v.maxFee !== undefined && v.halfAmount !== undefined;
if (!hasBps && !hasFeeParams) {
ctx.addIssue({
code: 'custom',
path: ['bps'],
message: 'Provide bps or both maxFee and halfAmount',
});
}
if (hasBps && v.bps <= 0) {
ctx.addIssue({
code: 'custom',
path: ['bps'],
message: 'bps must be > 0',
});
}
if (hasBps && !isBpsPrecisionValid(v.bps)) {
ctx.addIssue({
code: 'custom',
path: ['bps'],
message: `bps must have at most ${MAX_BPS_DECIMALS} decimal places`,
});
}
if (v.halfAmount === 0n) {
// Prevents divide by 0
ctx.addIssue({
code: 'custom',
path: ['halfAmount'],
message: 'halfAmount must be > 0',
});
}
})
.transform((v) => ({
...v,
bps: v.bps ?? convertToBps(v.maxFee, v.halfAmount),
}));
export const OffchainQuotedLinearFeeConfigSchema = BpsConfigSchema.merge(QuoteSignersSchema).extend({
type: z.literal(TokenFeeType.OffchainQuotedLinearFee),
});
export const OffchainQuotedLinearFeeInputConfigSchema = BaseFeeConfigInputSchema.merge(QuoteSignersSchema)
.extend({
type: z.literal(TokenFeeType.OffchainQuotedLinearFee),
bps: ZBps.optional(),
...FeeParametersSchema.partial().shape,
})
.superRefine((v, ctx) => {
const hasBps = v.bps !== undefined;
const hasFeeParams = v.maxFee !== undefined && v.halfAmount !== undefined;
if (!hasBps && !hasFeeParams) {
ctx.addIssue({
code: 'custom',
path: ['bps'],
message: 'Provide bps or both maxFee and halfAmount',
});
}
if (hasBps && v.bps <= 0) {
ctx.addIssue({
code: 'custom',
path: ['bps'],
message: 'bps must be > 0',
});
}
if (hasBps && !isBpsPrecisionValid(v.bps)) {
ctx.addIssue({
code: 'custom',
path: ['bps'],
message: `bps must have at most ${MAX_BPS_DECIMALS} decimal places`,
});
}
if (v.halfAmount === 0n) {
ctx.addIssue({
code: 'custom',
path: ['halfAmount'],
message: 'halfAmount must be > 0',
});
}
})
.transform((v) => ({
...v,
bps: v.bps ?? convertToBps(v.maxFee, v.halfAmount),
}));
export const ProgressiveFeeConfigSchema = StandardFeeConfigBaseSchema.extend({
type: z.literal(TokenFeeType.ProgressiveFee),
});
export const ProgressiveFeeInputConfigSchema = BaseFeeConfigInputSchema.extend({
type: z.literal(TokenFeeType.ProgressiveFee),
maxFee: ZBigNumberish,
halfAmount: ZBigNumberish,
}).refine((v) => BigInt(v.halfAmount) > 0n, {
path: ['halfAmount'],
message: 'halfAmount must be > 0',
});
export const RegressiveFeeConfigSchema = StandardFeeConfigBaseSchema.extend({
type: z.literal(TokenFeeType.RegressiveFee),
});
export const RegressiveFeeInputConfigSchema = BaseFeeConfigInputSchema.extend({
type: z.literal(TokenFeeType.RegressiveFee),
maxFee: ZBigNumberish,
halfAmount: ZBigNumberish,
}).refine((v) => BigInt(v.halfAmount) > 0n, {
path: ['halfAmount'],
message: 'halfAmount must be > 0',
});
export const RoutingFeeConfigSchema = BaseFeeConfigSchema.extend({
type: z.literal(TokenFeeType.RoutingFee),
feeContracts: z.record(ZChainName, z.lazy(() => TokenFeeConfigSchema)), // Destination -> Fee
});
const CROSS_COLLATERAL_DESTINATION_MESSAGE = 'CrossCollateralRoutingFee destinations must define at least one router fee';
const CrossCollateralRoutingFeeDestinationConfigSchema = z
.record(ZHash, z.lazy(() => TokenFeeConfigSchema))
.refine((value) => Object.keys(value).length > 0, {
message: CROSS_COLLATERAL_DESTINATION_MESSAGE,
});
export const CrossCollateralRoutingFeeConfigSchema = z.object({
type: z.literal(TokenFeeType.CrossCollateralRoutingFee),
owner: ZHash,
feeContracts: z.record(ZChainName, CrossCollateralRoutingFeeDestinationConfigSchema), // Destination -> { routerKey -> Fee }, including DEFAULT_ROUTER_KEY
});
// Routing Fee Input - maxFee/halfAmount NOT configurable (contract hardcodes to max uint256)
export const RoutingFeeInputConfigSchema = BaseFeeConfigInputSchema.extend({
type: z.literal(TokenFeeType.RoutingFee),
feeContracts: z.record(ZChainName, z.lazy(() => TokenFeeConfigInputSchema)),
}).refine((value) => Object.keys(value.feeContracts).length > 0, {
path: ['feeContracts'],
message: 'RoutingFee must define at least one destination fee',
});
const CrossCollateralRoutingFeeDestinationInputConfigSchema = z
.record(ZHash, z.lazy(() => TokenFeeConfigInputSchema))
.refine((value) => Object.keys(value).length > 0, {
message: CROSS_COLLATERAL_DESTINATION_MESSAGE,
});
export const CrossCollateralRoutingFeeInputConfigSchema = BaseFeeConfigInputSchema.extend({
type: z.literal(TokenFeeType.CrossCollateralRoutingFee),
feeContracts: z.record(ZChainName, CrossCollateralRoutingFeeDestinationInputConfigSchema),
}).refine((value) => Object.keys(value.feeContracts).length > 0, {
path: ['feeContracts'],
message: 'CrossCollateralRoutingFee must define at least one destination fee',
});
// ====== UNION SCHEMAS ======
export const TokenFeeConfigSchema = z.discriminatedUnion('type', [
LinearFeeConfigSchema,
OffchainQuotedLinearFeeConfigSchema,
ProgressiveFeeConfigSchema,
RegressiveFeeConfigSchema,
RoutingFeeConfigSchema,
CrossCollateralRoutingFeeConfigSchema,
]);
export const TokenFeeConfigInputSchema = z.union([
LinearFeeInputConfigSchema,
OffchainQuotedLinearFeeInputConfigSchema,
ProgressiveFeeInputConfigSchema,
RegressiveFeeInputConfigSchema,
RoutingFeeInputConfigSchema,
CrossCollateralRoutingFeeInputConfigSchema,
]);
//# sourceMappingURL=types.js.map