Skip to content

Commit

Permalink
fix: partially exclude fot from fee (#784)
Browse files Browse the repository at this point in the history
* fix: partially exclude fot from fee

* fix prettier

* Add DFNDR FOT test case for fee exclusion

* fix gql batch token fee query

* add more unit test

* chore: bump sor to 3.37.0 to support some FOT fee

* fix test assertion

* fix test assertion
  • Loading branch information
jsy1218 authored Jul 29, 2024
1 parent 997236d commit 88968a2
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 10 deletions.
6 changes: 6 additions & 0 deletions lib/graphql/graphql-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ query Token($chain: Chain!, $address: String!) {
feeData {
buyFeeBps
sellFeeBps
feeTakenOnTransfer
externalTransferFailed
sellReverted
}
}
}
Expand All @@ -29,6 +32,9 @@ query Tokens($contracts: [ContractInput!]!) {
feeData {
buyFeeBps
sellFeeBps
feeTakenOnTransfer
externalTransferFailed
sellReverted
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/graphql/graphql-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ export interface TokenInfo {
feeData?: {
buyFeeBps?: string
sellFeeBps?: string
feeTakenOnTransfer?: boolean
externalTransferFailed?: boolean
sellReverted?: boolean
}
}
19 changes: 17 additions & 2 deletions lib/graphql/graphql-token-fee-fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,24 @@ export class GraphQLTokenFeeFetcher implements ITokenFeeFetcher {
if (token.feeData?.buyFeeBps || token.feeData?.sellFeeBps) {
const buyFeeBps = token.feeData.buyFeeBps ? BigNumber.from(token.feeData.buyFeeBps) : undefined
const sellFeeBps = token.feeData.sellFeeBps ? BigNumber.from(token.feeData.sellFeeBps) : undefined
tokenFeeMap[token.address] = { buyFeeBps, sellFeeBps }
const feeTakenOnTransfer = token.feeData.feeTakenOnTransfer
const externalTransferFailed = token.feeData.externalTransferFailed
const sellReverted = token.feeData.sellReverted
tokenFeeMap[token.address] = {
buyFeeBps,
sellFeeBps,
feeTakenOnTransfer,
externalTransferFailed,
sellReverted,
}
} else {
tokenFeeMap[token.address] = { buyFeeBps: undefined, sellFeeBps: undefined }
tokenFeeMap[token.address] = {
buyFeeBps: undefined,
sellFeeBps: undefined,
feeTakenOnTransfer: false,
externalTransferFailed: false,
sellReverted: false,
}
}
})
metric.putMetric('GraphQLTokenFeeFetcherFetchFeesSuccess', 1, MetricLoggerUnit.Count)
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"@uniswap/router-sdk": "^1.9.2",
"@uniswap/sdk-core": "^5.3.0",
"@types/semver": "^7.5.8",
"@uniswap/smart-order-router": "3.36.2",
"@uniswap/smart-order-router": "3.37.0",
"@uniswap/token-lists": "^1.0.0-beta.33",
"@uniswap/universal-router-sdk": "^2.2.0",
"@uniswap/v2-sdk": "^4.3.2",
Expand Down
34 changes: 34 additions & 0 deletions test/mocha/e2e/quote.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,24 @@ const BULLET_WHT_TAX = new Token(
BigNumber.from(500),
BigNumber.from(500)
)
export const DFNDR = new Token(
ChainId.MAINNET,
'0x3f57c35633cb29834bb7577ba8052eab90f52a02',
18,
'DFNDR',
'Defender Bot',
false
)
export const DFNDR_WITH_TAX = new Token(
ChainId.MAINNET,
'0x3f57c35633cb29834bb7577ba8052eab90f52a02',
18,
'DFNDR',
'Defender Bot',
false,
BigNumber.from(500),
BigNumber.from(500)
)

const V2_SUPPORTED_PAIRS = [
[WETH9[ChainId.ARBITRUM_ONE], USDC_NATIVE_ARBITRUM],
Expand Down Expand Up @@ -1114,6 +1132,7 @@ describe('quote', function () {
const tokenInAndTokenOut = [
[BULLET, WETH9[ChainId.MAINNET]!],
[WETH9[ChainId.MAINNET]!, BULLET],
[WETH9[ChainId.MAINNET]!, DFNDR],
]

tokenInAndTokenOut.forEach(([tokenIn, tokenOut]) => {
Expand Down Expand Up @@ -1156,9 +1175,12 @@ describe('quote', function () {
enableUniversalRouter: true,
// if fee-on-transfer flag is not enabled, most likely the simulation will fail due to quote not subtracting the tax
simulateFromAddress: enableFeeOnTransferFeeFetching ? simulateFromAddress : undefined,
portionBips: FLAT_PORTION.bips,
portionRecipient: FLAT_PORTION.recipient,
}

const queryParams = qs.stringify(quoteReq)
console.log(`${API}?${queryParams}`)

const response: AxiosResponse<QuoteResponse> = await axios.get<QuoteResponse>(
`${API}?${queryParams}`
Expand All @@ -1170,6 +1192,18 @@ describe('quote', function () {

const quoteWithFlagOn = responses.find((r) => r.enableFeeOnTransferFeeFetching === true)
expect(quoteWithFlagOn).not.to.be.undefined

// in case of FOT token that should not take a portion/fee, we assert that all portion fields are undefined
if (!tokenOut?.equals(WETH9[ChainId.MAINNET])) {
expect(quoteWithFlagOn!.data.portionAmount).to.be.undefined
expect(quoteWithFlagOn!.data.portionBips).to.be.undefined
expect(quoteWithFlagOn!.data.portionRecipient).to.be.undefined
} else {
expect(quoteWithFlagOn!.data.portionAmount).to.be.not.undefined
expect(quoteWithFlagOn!.data.portionBips).to.be.not.undefined
expect(quoteWithFlagOn!.data.portionRecipient).to.be.not.undefined
}

responses
.filter((r) => r.enableFeeOnTransferFeeFetching !== true)
.forEach((r) => {
Expand Down
16 changes: 16 additions & 0 deletions test/mocha/integ/graphql/graphql-token-fee-fetcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,15 @@ describe('integration test for GraphQLTokenFeeFetcher', () => {
expect(tokenFeeMap[WETH9[ChainId.MAINNET]!.address]).to.not.be.undefined
expect(tokenFeeMap[WETH9[ChainId.MAINNET]!.address]?.buyFeeBps).to.be.undefined
expect(tokenFeeMap[WETH9[ChainId.MAINNET]!.address]?.sellFeeBps).to.be.undefined
expect(tokenFeeMap[WETH9[ChainId.MAINNET]!.address]?.feeTakenOnTransfer).to.not.be.undefined
expect(tokenFeeMap[WETH9[ChainId.MAINNET]!.address]?.externalTransferFailed).to.not.be.undefined
expect(tokenFeeMap[WETH9[ChainId.MAINNET]!.address]?.sellReverted).to.not.be.undefined
expect(tokenFeeMap[BITBOY.address]).to.not.be.undefined
expect(tokenFeeMap[BITBOY.address]?.buyFeeBps?._hex).equals(BITBOY.buyFeeBps?._hex)
expect(tokenFeeMap[BITBOY.address]?.sellFeeBps?._hex).equals(BITBOY.sellFeeBps?._hex)
expect(tokenFeeMap[BITBOY.address]?.feeTakenOnTransfer).equals(false)
expect(tokenFeeMap[BITBOY.address]?.externalTransferFailed).equals(true)
expect(tokenFeeMap[BITBOY.address]?.sellReverted).equals(false)
})

it('Fetch BULLET and BITBOY, should return BOTH', async () => {
Expand All @@ -77,9 +83,16 @@ describe('integration test for GraphQLTokenFeeFetcher', () => {
expect(tokenFeeMap[BULLET.address]).to.not.be.undefined
expect(tokenFeeMap[BULLET.address]?.buyFeeBps?._hex).equals(BULLET.buyFeeBps?._hex)
expect(tokenFeeMap[BULLET.address]?.sellFeeBps?._hex).equals(BULLET.sellFeeBps?._hex)
expect(tokenFeeMap[BULLET.address]?.feeTakenOnTransfer).equals(false)
expect(tokenFeeMap[BULLET.address]?.externalTransferFailed).equals(true)
expect(tokenFeeMap[BULLET.address]?.sellReverted).equals(true)

expect(tokenFeeMap[BITBOY.address]).to.not.be.undefined
expect(tokenFeeMap[BITBOY.address]?.buyFeeBps?._hex).equals(BITBOY.buyFeeBps?._hex)
expect(tokenFeeMap[BITBOY.address]?.sellFeeBps?._hex).equals(BITBOY.sellFeeBps?._hex)
expect(tokenFeeMap[BITBOY.address]?.feeTakenOnTransfer).equals(false)
expect(tokenFeeMap[BITBOY.address]?.externalTransferFailed).equals(true)
expect(tokenFeeMap[BITBOY.address]?.sellReverted).equals(false)

expect(spyGraphQLFetcher.calledOnce).to.be.true
expect(spyOnChainFetcher.calledOnce).to.be.false
Expand All @@ -97,6 +110,9 @@ describe('integration test for GraphQLTokenFeeFetcher', () => {
expect(tokenFeeMap[BITBOY.address]).to.not.be.undefined
expect(tokenFeeMap[BITBOY.address]?.buyFeeBps?._hex).equals(BITBOY.buyFeeBps?._hex)
expect(tokenFeeMap[BITBOY.address]?.sellFeeBps?._hex).equals(BITBOY.sellFeeBps?._hex)
expect(tokenFeeMap[BITBOY.address]?.feeTakenOnTransfer).equals(false)
expect(tokenFeeMap[BITBOY.address]?.externalTransferFailed).equals(true)
expect(tokenFeeMap[BITBOY.address]?.sellReverted).equals(false)

expect(spyGraphQLFetcher.calledOnce).to.be.true
expect(spyOnChainFetcher.calledOnce).to.be.true
Expand Down

0 comments on commit 88968a2

Please sign in to comment.