Skip to content

Commit

Permalink
feat(calculator): allow calculating a taking amount with block fee (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
vbrvk authored Mar 13, 2024
1 parent 702584f commit 44c86c7
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 26 deletions.
6 changes: 3 additions & 3 deletions src/auction-calculator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ const details = new AuctionDetails({
})
const calculator = AuctionCalculator.fromAuctionData(settlementData, details) // #=> AuctionCalculator instance

const rate = calculator.calcRateBump(1673548160)
const rate = calculator.calcRateBump(startTime + 11n)
// #=> 40000

const auctionTakingAmount = calculator.calcAuctionTakingAmount(
'1420000000',
1420000000n,
rate
)
// #=> '1427105680'
// #=> 1427105680
```


52 changes: 49 additions & 3 deletions src/auction-calculator/auction-calculator.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Address} from '@1inch/limit-order-sdk'
import {parseEther, parseUnits} from 'ethers'
import {AuctionCalculator} from './auction-calculator'
import {SettlementPostInteractionData, AuctionDetails} from '../fusion-order'
import {bpsToRatioFormat} from '../sdk'
Expand Down Expand Up @@ -29,13 +30,58 @@ describe('Auction Calculator', () => {
auctionDetails
)

const rate = calculator.calcRateBump(Number(auctionStartTime + 60n))
const rate = calculator.calcRateBump(auctionStartTime + 60n)
const auctionTakingAmount = calculator.calcAuctionTakingAmount(
'1420000000',
1420000000n,
rate
)

expect(rate).toBe(25000)
expect(auctionTakingAmount).toBe('1423692355') // 1423550000 from rate + 142355 (1bps) integrator fee
expect(auctionTakingAmount).toBe(1423692355n) // 1423550000 from rate + 142355 (1bps) integrator fee
})

describe('Gas bump', () => {
const now = BigInt(Math.floor(Date.now() / 1000))
const duration = 1800n // 30m
const takingAmount = parseEther('1')
const calculator = new AuctionCalculator(
now - 60n,
duration,
1000000n,
[{delay: 60, coefficient: 500000}],
0n,
{
gasBumpEstimate: 10000n, // 0.1% of taking amount
gasPriceEstimate: 1000n // 1gwei
}
)

it('0 gwei = no gas fee', () => {
const bump = calculator.calcRateBump(now)
expect(calculator.calcAuctionTakingAmount(takingAmount, bump)).toBe(
parseEther('1.05')
)
})

it('0.1 gwei = 0.01% gas fee', () => {
const bump = calculator.calcRateBump(now, parseUnits('1', 8))
expect(calculator.calcAuctionTakingAmount(takingAmount, bump)).toBe(
parseEther('1.0499')
)
})

it('15 gwei = 1.5% gas fee', () => {
const bump = calculator.calcRateBump(now, parseUnits('15', 9))
expect(calculator.calcAuctionTakingAmount(takingAmount, bump)).toBe(
parseEther('1.035')
)
})

it('100 gwei = 10% gas fee, should be capped with takingAmount', () => {
const bump = calculator.calcRateBump(now, parseUnits('100', 9))
expect(calculator.calcAuctionTakingAmount(takingAmount, bump)).toBe(
parseEther('1')
)
})
})
})
75 changes: 55 additions & 20 deletions src/auction-calculator/auction-calculator.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import {linearInterpolation} from './calc'
import {RATE_BUMP_DENOMINATOR} from './constants'
import {SettlementPostInteractionData} from '../fusion-order/settlement-post-interaction-data'
import {AuctionDetails, AuctionPoint} from '../fusion-order/auction-details'
import {
SettlementPostInteractionData,
AuctionDetails,
AuctionPoint
} from '../fusion-order'
import {addRatioToAmount} from '../sdk'

export class AuctionCalculator {
private static GAS_PRICE_BASE = 1_000_000n // 1000 means 1 Gwei

constructor(
private readonly startTime: bigint,
private readonly duration: bigint,
private readonly initialRateBump: bigint,
private readonly points: AuctionPoint[],
private readonly takerFeeRatio: bigint
private readonly takerFeeRatio: bigint,
private readonly gasCost: {
/**
* Rate bump to cover gas price. 10_000_000 means 100%
*/
gasBumpEstimate: bigint
/**
* Gas price at estimation time. 1000 means 1 Gwei
*/
gasPriceEstimate: bigint
} = {gasBumpEstimate: 0n, gasPriceEstimate: 0n}
) {}

static fromAuctionData(
Expand All @@ -22,43 +37,67 @@ export class AuctionCalculator {
details.duration,
details.initialRateBump,
details.points,
data.integratorFee?.ratio || 0n
data.integratorFee?.ratio || 0n,
details.gasCost
)
}

/**
* @see https://github.com/1inch/limit-order-settlement/blob/1b6757eecb2574953b543821db6f7bbff5afee48/contracts/extensions/BaseExtension.sol#L56
*/
calcAuctionTakingAmount(takingAmount: string, rate: number): string {
calcAuctionTakingAmount(takingAmount: bigint, rate: number): bigint {
const auctionTakingAmount =
(BigInt(takingAmount) * (BigInt(rate) + RATE_BUMP_DENOMINATOR)) /
RATE_BUMP_DENOMINATOR

if (this.takerFeeRatio === 0n) {
return auctionTakingAmount.toString()
return auctionTakingAmount
}

return addRatioToAmount(
auctionTakingAmount,
this.takerFeeRatio
).toString()
return addRatioToAmount(auctionTakingAmount, this.takerFeeRatio)
}

/**
* @see https://github.com/1inch/limit-order-settlement/blob/1b6757eecb2574953b543821db6f7bbff5afee48/contracts/extensions/BaseExtension.sol#L121
* @see https://github.com/1inch/limit-order-settlement/blob/273defdf7b0f1867299dcbc306f32f035579310f/contracts/extensions/BaseExtension.sol#L121
* @param time auction timestamp in seconds
* @param blockBaseFee blockBaseFee in Wei, if passed, then rate will be calculated as if order executed in block with `blockBaseFee`
*/
calcRateBump(time: number): number {
calcRateBump(time: bigint, blockBaseFee = 0n): number {
const gasBump = this.getGasPriceBump(blockBaseFee)
const auctionBump = this.getAuctionBump(time)

const final = auctionBump > gasBump ? auctionBump - gasBump : 0n

return Number(final)
}

private getGasPriceBump(blockBaseFee: bigint): bigint {
if (
this.gasCost.gasBumpEstimate === 0n ||
this.gasCost.gasPriceEstimate === 0n ||
blockBaseFee === 0n
) {
return 0n
}

return (
(this.gasCost.gasBumpEstimate * blockBaseFee) /
this.gasCost.gasPriceEstimate /
AuctionCalculator.GAS_PRICE_BASE
)
}

private getAuctionBump(time: bigint): bigint {
let cumulativeTime = BigInt(this.startTime)
const lastTime = BigInt(this.duration) + cumulativeTime
const startBump = BigInt(this.initialRateBump)

const currentTime = BigInt(time)

if (currentTime <= cumulativeTime) {
return Number(this.initialRateBump)
return this.initialRateBump
} else if (currentTime >= lastTime) {
return 0
return 0n
}

let prevCoefficient = startBump
Expand All @@ -71,29 +110,25 @@ export class AuctionCalculator {
const coefficientBN = BigInt(coefficient)

if (cumulativeTime >= currentTime) {
const rate = linearInterpolation(
return linearInterpolation(
prevCumulativeTime,
cumulativeTime,
prevCoefficient,
coefficientBN,
currentTime
)

return Number(rate)
}

prevCumulativeTime = cumulativeTime
prevCoefficient = coefficientBN
}

const rate = linearInterpolation(
return linearInterpolation(
prevCumulativeTime,
lastTime,
prevCoefficient,
0n,
currentTime
)

return Number(rate)
}
}

0 comments on commit 44c86c7

Please sign in to comment.