Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('PeggedSwapArgs', () => {

it('should handle maximum uint256 values for reserves and rates', () => {
const maxUint256 = (1n << 256n) - 1n
const maxLinearWidth = 2n * 10n ** 27n
const maxLinearWidth = 5000n * 10n ** 27n
const args = new PeggedSwapArgs(maxUint256, maxUint256, maxLinearWidth, maxUint256, maxUint256)

const encoded = PeggedSwapArgs.CODER.encode(args)
Expand All @@ -54,8 +54,8 @@ describe('PeggedSwapArgs', () => {
expect(() => new PeggedSwapArgs(1n, 1n, 1n, 1n, 0n)).toThrow(/Invalid rateGt/)
})

it('should throw when linearWidth exceeds 2e27', () => {
const tooLarge = 2n * 10n ** 27n + 1n
it('should throw when linearWidth exceeds 5000e27', () => {
const tooLarge = 5000n * 10n ** 27n + 1n
expect(() => new PeggedSwapArgs(1n, 1n, tooLarge, 1n, 1n)).toThrow(/Invalid linearWidth/)
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { HexString } from '@1inch/sdk-core'
import { UINT_256_MAX } from '@1inch/byte-utils'
import assert from 'assert'
import { PeggedSwapArgsCoder } from './pegged-swap-args-coder'
import { MAX_LINEAR_WIDTH } from './pegged-swap-math/pegged-swap-math'
import type { PeggedTokenInfo } from './types'
import { resolveRate } from './rate-resolver'
import type { IArgsCoder, IArgsData } from '../types'
Expand All @@ -19,7 +20,7 @@ export class PeggedSwapArgs implements IArgsData {
/**
* x0 - Initial X reserve (normalization factor) = initial_balance_X * rateLt (or rateGt)
* y0 - Initial Y reserve (normalization factor) = initial_balance_Y * rateGt (or rateLt)
* linearWidth - Linear component coefficient A scaled by 1e27 (e.g., 0.8e27 for A=0.8)
* linearWidth - Linear component coefficient A scaled by 1e27 (e.g., 0.8e27 for A=0.8); must be ≤ MAX_LINEAR_WIDTH (A ≤ 5000)
* rateLt - Rate multiplier for token with LOWER address
* rateGt - Rate multiplier for token with GREATER address
* > For equal decimals (e.g., both 18): rateLt = rateGt = 1
Expand All @@ -35,7 +36,7 @@ export class PeggedSwapArgs implements IArgsData {
assert(x0 > 0n && y0 > 0n, 'Reserves cannot be zero')
assert(x0 <= UINT_256_MAX, `Invalid x0: ${x0}`)
assert(y0 <= UINT_256_MAX, `Invalid y0: ${y0}`)
assert(linearWidth <= 2n * 10n ** 27n, `Invalid linearWidth: ${linearWidth}`)
assert(linearWidth <= MAX_LINEAR_WIDTH, `Invalid linearWidth: ${linearWidth}`)
assert(
rateLt > 0n && rateLt <= UINT_256_MAX,
`Invalid rateLt: ${rateLt}. Must be positive and <= UINT_256_MAX`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,22 @@ describe('linearWidthFromSymmetricRangePercent', () => {
expect(linearWidth).toBe(1460784313725490196078431372n)
})

it('allows linearWidth at the on-chain maximum (20% symmetric range)', () => {
expect(linearWidthFromSymmetricRangePercent(20)).toBe(MAX_LINEAR_WIDTH)
it('maps a 20% symmetric range to A = 2', () => {
expect(linearWidthFromSymmetricRangePercent(20)).toBe(2n * PEGGED_SWAP_ONE)
})

it('allows narrow peg bands up to the on-chain maximum (A ≈ 5000 at the 0.01% floor)', () => {
// X = 0.0001 → A = (1 - X) / (2X) = 4999.5 → 4999.5e27 ≤ MAX_LINEAR_WIDTH (5000e27).
expect(linearWidthFromSymmetricRangePercent(0.01)).toBe(49995n * 10n ** 26n)
})

it('rejects zero and 100% symmetric range', () => {
expect(() => linearWidthFromSymmetricRangePercent(0)).toThrow(/must be positive/)
expect(() => linearWidthFromSymmetricRangePercent(100)).toThrow(/less than 100%/)
})

it('rejects narrow peg bands whose A exceeds 2', () => {
expect(() => linearWidthFromSymmetricRangePercent(0.2)).toThrow(/exceeds maximum/)
it('rejects peg bands tighter than the A ≤ 5000 floor', () => {
expect(() => linearWidthFromSymmetricRangePercent(0.001)).toThrow(/exceeds maximum/)
})
})

Expand All @@ -44,8 +49,12 @@ describe('symmetricRangePercentFromLinearWidth', () => {
expect(symmetricRangePercentFromLinearWidth(15n * 10n ** 26n)).toBe(25)
})

it('returns 20% at the on-chain maximum linearWidth', () => {
expect(symmetricRangePercentFromLinearWidth(MAX_LINEAR_WIDTH)).toBe(20)
it('returns 20% at A = 2', () => {
expect(symmetricRangePercentFromLinearWidth(2n * PEGGED_SWAP_ONE)).toBe(20)
})

it('returns ≈0.009999% at the on-chain maximum linearWidth (A = 5000)', () => {
expect(symmetricRangePercentFromLinearWidth(MAX_LINEAR_WIDTH)).toBeCloseTo(100 / 10001, 6)
})

it('returns 100% when linearWidth is zero', () => {
Expand All @@ -63,7 +72,7 @@ describe('symmetricRangePercentFromLinearWidth', () => {
})

it('round-trips percent -> linearWidth -> percent', () => {
for (const percent of [20, 25, 25.5, 33.33, 50, 99]) {
for (const percent of [0.01, 0.1, 1, 20, 25, 25.5, 33.33, 50, 99]) {
const linearWidth = linearWidthFromSymmetricRangePercent(percent)
expect(symmetricRangePercentFromLinearWidth(linearWidth)).toBeCloseTo(percent, 10)
}
Expand All @@ -75,7 +84,7 @@ describe('symmetricRangePercentFromLinearWidth', () => {
5n * 10n ** 26n,
10n ** 27n,
15n * 10n ** 26n,
MAX_LINEAR_WIDTH,
2n * PEGGED_SWAP_ONE,
]) {
const percent = symmetricRangePercentFromLinearWidth(linearWidth)
const recovered = linearWidthFromSymmetricRangePercent(percent)
Expand All @@ -86,7 +95,7 @@ describe('symmetricRangePercentFromLinearWidth', () => {
})

it('round-trips exactly for clean percents', () => {
for (const percent of [20, 25, 50]) {
for (const percent of [0.01, 0.1, 20, 25, 50]) {
const linearWidth = linearWidthFromSymmetricRangePercent(percent)
expect(symmetricRangePercentFromLinearWidth(linearWidth)).toBe(percent)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { bigintSqrt } from '../../utils'
/** Matches `PeggedSwapMath.ONE` in swap-vm. */
export const PEGGED_SWAP_ONE: bigint = 10n ** 27n

/** Maximum on-chain `linearWidth` (`A` ≤ 2). */
export const MAX_LINEAR_WIDTH: bigint = 2n * PEGGED_SWAP_ONE
/** Maximum on-chain `linearWidth` (`A` ≤ 5000). */
export const MAX_LINEAR_WIDTH: bigint = 5000n * PEGGED_SWAP_ONE

const MARGINAL_PRICE_ONE = 10n ** 18n

Expand Down
Loading