Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

[🧬 🧬 Release] v1.8.0-rc.0 #2001

Merged
merged 16 commits into from
Dec 22, 2021
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
96 changes: 59 additions & 37 deletions cypress-custom/integration/fee.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,51 @@
import { WETH9 as WETH } from '@uniswap/sdk-core'
import { OrderKind } from '@gnosis.pm/gp-v2-contracts'
import { FeeQuoteParams, FeeInformation } from '../../src/custom/utils/price'
import { GetQuoteResponse } from '@gnosis.pm/gp-v2-contracts'
import { parseUnits } from 'ethers/lib/utils'

const DAI = '0xc7AD46e0b8a400Bb3C915120d284AafbA8fc4735'
const FOUR_HOURS = 3600 * 4 * 1000
const DEFAULT_SELL_TOKEN = WETH[4]
const DEFAULT_APP_DATA = '0x0000000000000000000000000000000000000000000000000000000000000000'
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'

const FEE_QUERY = `https://protocol-rinkeby.dev.gnosisdev.com/api/v1/quote`

const baseParams = {
from: ZERO_ADDRESS,
receiver: ZERO_ADDRESS,
validTo: Math.ceil(Date.now() / 1000 + 500),
appData: DEFAULT_APP_DATA,
sellTokenBalance: 'erc20',
buyTokenBalance: 'erc20',
partiallyFillable: false,
}

const getFeeQuery = ({ sellToken, buyToken, amount, kind }: Omit<FeeQuoteParams, 'chainId'>) =>
`https://protocol-rinkeby.dev.gnosisdev.com/api/v1/fee?sellToken=${sellToken}&buyToken=${buyToken}&amount=${amount}&kind=${kind}`
const mockQuoteResponse = {
quote: {
// arb props here..
sellToken: '0x6810e776880c02933d47db1b9fc05908e5386b96',
buyToken: '0x6810e776880c02933d47db1b9fc05908e5386b96',
receiver: '0x6810e776880c02933d47db1b9fc05908e5386b96',
sellAmount: '1234567890',
buyAmount: '1234567890',
validTo: 0,
appData: '0x0000000000000000000000000000000000000000000000000000000000000000',
feeAmount: '1234567890',
kind: 'buy',
partiallyFillable: true,
sellTokenBalance: 'erc20',
buyTokenBalance: 'erc20',
},
from: ZERO_ADDRESS,
}

function _assertFeeData(fee: FeeInformation | string): void {
function _assertFeeData(fee: GetQuoteResponse): void {
if (typeof fee === 'string') {
fee = JSON.parse(fee)
}
expect(fee).to.have.property('amount')
expect(fee).to.have.property('expirationDate')
expect(fee).to.have.property('quote')
expect(fee).to.have.property('expiration')
expect(fee.quote).to.have.property('feeAmount')
}

/* Fee not currently being saved in local so commenting this out
Expand Down Expand Up @@ -54,18 +84,25 @@ function _assertFeeFetched(token: string): Cypress.Chainable {

describe('Fee endpoint', () => {
it('Returns the expected info', () => {
const FEE_QUERY = getFeeQuery({
const params = {
sellToken: DEFAULT_SELL_TOKEN.address,
buyToken: DAI,
amount: parseUnits('0.1', DEFAULT_SELL_TOKEN.decimals).toString(),
kind: OrderKind.SELL,
sellAmountBeforeFee: parseUnits('0.1', DEFAULT_SELL_TOKEN.decimals).toString(),
kind: 'sell',
fromDecimals: DEFAULT_SELL_TOKEN.decimals,
toDecimals: 6,
})
// BASE PARAMS
...baseParams,
}

// GIVEN: -
// WHEN: Call fee API
cy.request(FEE_QUERY)
cy.request({
method: 'POST',
url: FEE_QUERY,
body: params,
log: true,
})
.its('body')
// THEN: The API response has the expected data
.should(_assertFeeData)
Expand All @@ -74,27 +111,19 @@ describe('Fee endpoint', () => {

describe('Fee: Complex fetch and persist fee', () => {
const INPUT_AMOUNT = '0.1'
const FEE_QUERY = getFeeQuery({
sellToken: DEFAULT_SELL_TOKEN.address,
buyToken: DAI,
amount: parseUnits(INPUT_AMOUNT, DEFAULT_SELL_TOKEN.decimals).toString(),
kind: OrderKind.SELL,
fromDecimals: DEFAULT_SELL_TOKEN.decimals,
toDecimals: 6,
})

// Needs to run first to pass because of Cypress async issues between tests
it('Re-fetched when it expires', () => {
// GIVEN: input token Fee expiration is always 6 hours from now
const SIX_HOURS = FOUR_HOURS * 1.5
const LATER_TIME = new Date(Date.now() + SIX_HOURS).toISOString()
const LATER_FEE = {
expirationDate: LATER_TIME,
amount: '0',
...mockQuoteResponse,
expiration: LATER_TIME,
}

// only override Date functions (default is to override all time based functions)
cy.stubResponse({ url: FEE_QUERY, alias: 'feeRequest', body: LATER_FEE })
cy.stubResponse({ method: 'POST', url: FEE_QUERY, alias: 'feeRequest', body: LATER_FEE })

// GIVEN: user visits app, selects 0.1 WETH as sell, DAI as buy
// and goes AFK
Expand All @@ -116,36 +145,29 @@ describe('Fee: Complex fetch and persist fee', () => {
const mockedTime = new Date($clock.details().now)

// THEN: fee time is properly stubbed and
expect(body.expirationDate).to.equal(LATER_TIME)
expect(body.expiration).to.equal(LATER_TIME)
// THEN: the mocked later date is indeed less than the new fee (read: the fee is valid)
expect(new Date(body.expirationDate)).to.be.greaterThan(mockedTime)
expect(new Date(body.expiration)).to.be.greaterThan(mockedTime)
})
})
})
})

describe('Fee: simple checks it exists', () => {
const INPUT_AMOUNT = '0.1'
const FEE_QUERY = getFeeQuery({
sellToken: DEFAULT_SELL_TOKEN.address,
buyToken: DAI,
amount: parseUnits(INPUT_AMOUNT, DEFAULT_SELL_TOKEN.decimals).toString(),
kind: OrderKind.SELL,
fromDecimals: DEFAULT_SELL_TOKEN.decimals,
toDecimals: 6,
})
const FEE_RESP = {
const QUOTE_RESP = {
...mockQuoteResponse,
// 1 min in future
expirationDate: new Date(Date.now() + 60000).toISOString(),
amount: parseUnits('0.05', DEFAULT_SELL_TOKEN.decimals).toString(),
expiration: new Date(Date.now() + 60000).toISOString(),
}

it('Fetch fee when selecting both tokens', () => {
// Stub responses from fee endpoint
cy.stubResponse({
method: 'POST',
url: FEE_QUERY,
alias: 'feeRequest',
body: FEE_RESP,
body: QUOTE_RESP,
})
// GIVEN: A user loads the swap page
// WHEN: Select DAI token as output and sells 0.1 WETH
Expand Down
12 changes: 11 additions & 1 deletion cypress-custom/support/commands.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ declare namespace Cypress {
*
* @example cy.stubResponse({ url: '/api/v1/someEndpoint/', alias: 'endpoint', body: { foo: 'foo' } })
*/
stubResponse({ url, alias, body }: { url: string; alias?: string; body?: any }): Chainable<Subject>
stubResponse({
method,
url,
alias,
body,
}: {
method: 'GET' | 'POST' | 'DELETE'
url: string
alias?: string
body?: any
}): Chainable<Subject>
}
}
4 changes: 2 additions & 2 deletions cypress-custom/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ function enterOutputAmount(tokenAddress, amount, selectToken = false) {
cy.get('#swap-currency-input .token-amount-output').type(amount.toString(), { force: true, delay: 400 })
}

function stubResponse({ url, alias = 'stubbedResponse', body }) {
cy.intercept({ method: 'GET', url }, _responseHandlerFactory(body)).as(alias)
function stubResponse({ method, url, alias = 'stubbedResponse', body }) {
cy.intercept({ method, url }, _responseHandlerFactory(body)).as(alias)
}

Cypress.Commands.add('swapClickInputToken', () => clickInputToken)
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,14 @@
"license": "GPL-3.0-or-later",
"dependencies": {
"@gnosis.pm/cow-runner-game": "^0.2.9",
"@gnosis.pm/dex-js": "^0.12.0",
"@gnosis.pm/gp-v2-contracts": "^1.0.2",
"@gnosis.pm/dex-js": "^0.14.0",
"@gnosis.pm/gp-v2-contracts": "^1.1.2",
"@gnosis.pm/safe-service-client": "^0.1.1",
"@pinata/sdk": "^1.1.23",
"@sentry/react": "^6.11.0",
"@sentry/tracing": "^6.11.0",
"@uniswap/default-token-list": "^2.0.0",
"@walletconnect/web3-provider": "^1.6.6",
"bignumber.js": "9.0.1",
"bnc-sdk": "^3.5.0",
"fast-safe-stringify": "^2.0.8",
"paraswap": "^5.0.1",
Expand Down
Loading