Skip to content

Commit

Permalink
USDe/USD price cap (#3401)
Browse files Browse the repository at this point in the history
  • Loading branch information
mxiao-cll authored Aug 21, 2024
1 parent 26a9a02 commit bbee9bd
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/unlucky-melons-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/synthetix-feeds-adapter': minor
---

USDe/USD $1 price cap
13 changes: 11 additions & 2 deletions packages/sources/synthetix-feeds/src/transport/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { Decimal } from 'decimal.js'
import StakedUSDeV2 from '../abi/StakedUSDeV2.json'
import EACAggregatorProxy from '../abi/EACAggregatorProxy.json'
import WstETH from '../abi/WstETH.json'
import { makeLogger } from '@chainlink/external-adapter-framework/util'

const logger = makeLogger('synthetix-feeds-util')

const TEN = BigNumber.from(10)

Expand Down Expand Up @@ -38,8 +41,14 @@ const getUSDeToUSD = async (

const decimals = BigNumber.from((await contract.decimals()).toString())
const result = BigNumber.from((await contract.latestAnswer()).toString())

return new Decimal(utils.formatUnits(result, decimals).toString())
const resultDecimal = new Decimal(utils.formatUnits(result, decimals).toString())

if (resultDecimal > new Decimal(1)) {
logger.warn(`USDe/USD price ${resultDecimal} is over $1, capping to $1`)
return new Decimal(1)
} else {
return resultDecimal
}
}

export const getwstETHToUSD = async (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`synthetix feeds execute price endpoint sUSDe - USD success - $1 cap 1`] = `
{
"data": {
"result": 1.0969985583503274,
},
"result": 1.0969985583503274,
"statusCode": 200,
"timestamps": {
"providerDataReceivedUnixMs": 978347471111,
"providerDataRequestedUnixMs": 978347471111,
},
}
`;
95 changes: 95 additions & 0 deletions packages/sources/synthetix-feeds/test/integration/pricecap.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
TestAdapter,
setEnvVariables,
} from '@chainlink/external-adapter-framework/util/testing-utils'
import { ethers } from 'ethers'

export const SUSDE_USDE_ADDRESS = '0x0000000000000000000000000000000000000001'
export const USDE_USD_ADDRESS = '0x0000000000000000000000000000000000000002'

jest.mock('ethers', () => {
const actualModule = jest.requireActual('ethers')
return {
...actualModule,
ethers: {
...actualModule.ethers,
providers: {
JsonRpcProvider: function (): ethers.providers.JsonRpcProvider {
return {} as ethers.providers.JsonRpcProvider
},
},
Contract: function (address: string) {
return {
decimals: jest.fn().mockImplementation(() => {
switch (address) {
case SUSDE_USDE_ADDRESS:
return '18'
case USDE_USD_ADDRESS:
return '8'
default:
throw new Error('Method does not exist on this contract')
}
}),
convertToAssets: jest.fn().mockImplementation(() => {
switch (address) {
case SUSDE_USDE_ADDRESS:
return '1096998558350327369'
default:
throw new Error('Method does not exist on this contract')
}
}),
latestAnswer: jest.fn().mockImplementation(() => {
switch (address) {
case USDE_USD_ADDRESS:
return '199904861'
default:
throw new Error('Method does not exist on this contract')
}
}),
}
},
},
}
})

describe('synthetix feeds execute', () => {
let spy: jest.SpyInstance
let testAdapter: TestAdapter
let oldEnv: NodeJS.ProcessEnv

beforeAll(async () => {
oldEnv = JSON.parse(JSON.stringify(process.env))
process.env.RPC_URL = 'http://localhost:8545'
process.env.CHAIN_ID = '1'
process.env.BACKGROUND_EXECUTE_MS = '1000'

const mockDate = new Date('2001-01-01T11:11:11.111Z')
spy = jest.spyOn(Date, 'now').mockReturnValue(mockDate.getTime())

const adapter = (await import('./../../src')).adapter
adapter.rateLimiting = undefined
testAdapter = await TestAdapter.startWithMockedCache(adapter, {
testAdapter: {} as TestAdapter<never>,
})
})

afterAll(async () => {
setEnvVariables(oldEnv)
await testAdapter.api.close()
spy.mockRestore()
})

describe('price endpoint', () => {
it('sUSDe - USD success - $1 cap', async () => {
const data = {
base: 'sUSDe',
quote: 'USD',
base_address: SUSDE_USDE_ADDRESS,
quote_address: USDE_USD_ADDRESS,
}
const response = await testAdapter.request(data)
expect(response.statusCode).toBe(200)
expect(response.json()).toMatchSnapshot()
})
})
})

0 comments on commit bbee9bd

Please sign in to comment.