Skip to content

Commit

Permalink
feat: add world chain forwarder to dsr oracle forwarders (#30)
Browse files Browse the repository at this point in the history
* feat: add world chain forwarder to dsr oracle forwarders

* feat: WIP

* chore: update d3m ticker tests

* fix: fix cap automator tests

* fix: formatting
  • Loading branch information
barrutko authored Aug 29, 2024
1 parent f544da3 commit c7ea31f
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 89 deletions.
45 changes: 45 additions & 0 deletions abis/forwarderUpdated.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[
{
"inputs": [],
"name": "getLastSeenPotData",
"outputs": [
{
"components": [
{
"internalType": "uint96",
"name": "dsr",
"type": "uint96"
},
{
"internalType": "uint120",
"name": "chi",
"type": "uint120"
},
{
"internalType": "uint40",
"name": "rho",
"type": "uint40"
}
],
"internalType": "struct IForwarderBase.PotData",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "gasLimit",
"type": "uint32"
}
],
"name": "refresh",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
1 change: 1 addition & 0 deletions abis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { default as dsNoteAbi } from './dsNote.json'
export { default as erc20Abi } from './erc20.json'
export { default as forwarderAbi } from './forwarder.json'
export { default as forwarderArbitrumAbi } from './forwarderArbitrum.json'
export { default as forwarderUpdatedAbi } from './forwarderUpdated.json'
export { default as gnosisGovernanceExecutorAbi } from './gnosisGovernanceExecutor.json'
export { default as killSwitchOracleAbi } from './killSwitchOracle.json'
export { default as metaMorphoAbi } from './metaMorpho.json'
Expand Down
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const ETHERSCAN_KEY = process.env.ETHERSCAN_KEY

let forking = {
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
blockNumber: 20126359, // 2024-06-19 02:23:47
blockNumber: 20627610, // 2024-08-28 02:13:35
} as HardhatNetworkForkingUserConfig

if (TEST_NETWORK == 'mainnet') {
Expand Down
138 changes: 69 additions & 69 deletions test/web3-functions/mainnet/cap-automator.test.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions test/web3-functions/mainnet/d3m-ticker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Web3FunctionResultCallData } from '@gelatonetwork/web3-functions-sdk/*'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { SnapshotRestorer, takeSnapshot } from '@nomicfoundation/hardhat-network-helpers'

import { d3mHubAbi, multicallAbi, vatAbi } from '../../../abis'
import { d3mHubAbi, vatAbi } from '../../../abis'
import { addresses, ilk } from '../../../utils'

const { w3f, ethers } = hre
Expand All @@ -27,7 +27,7 @@ describe('d3mTicker', function () {
let threshold: string

const userArgs = { threshold: 0, performGasCheck: false, sendSlackMessages: false }
const artDifferenceOnTheFork = BigInt('43108457969557943776482696')
const artDifferenceOnTheFork = BigInt('8446563830271303300236973')

before(async () => {
cleanStateRestorer = await takeSnapshot()
Expand Down
39 changes: 23 additions & 16 deletions test/web3-functions/mainnet/xchain-oracle-ticker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('xchainOracleTicker', function () {
let pot: Contract

let optimismStyleForwarderAddresses: string[]
let updatedOptimismStyleForwarderAddresses: string[]
let arbitrumStyleForwarderAddresses: string[]
let allForwarderAddresses: string[]

Expand All @@ -48,8 +49,13 @@ describe('xchainOracleTicker', function () {
pauseProxy = await ethers.getSigner(addresses.mainnet.pauseProxy)

optimismStyleForwarderAddresses = Object.values(addresses.mainnet.dsrForwarders.optimismStyle)
updatedOptimismStyleForwarderAddresses = Object.values(addresses.mainnet.dsrForwarders.updatedOptimismStyle)
arbitrumStyleForwarderAddresses = Object.values(addresses.mainnet.dsrForwarders.arbitrumStyle)
allForwarderAddresses = [...optimismStyleForwarderAddresses, ...arbitrumStyleForwarderAddresses]
allForwarderAddresses = [
...optimismStyleForwarderAddresses,
...updatedOptimismStyleForwarderAddresses,
...arbitrumStyleForwarderAddresses,
]

pot = new Contract(addresses.mainnet.pot, potAbi, pauseProxy)
forwarderInterface = new utils.Interface(forwarderAbi)
Expand All @@ -76,7 +82,7 @@ describe('xchainOracleTicker', function () {
!result.canExec && expect(result.message).to.equal('Pot data refresh not needed')
})

it('one refresh is needed (stale rho)', async () => {
it('some refreshes are needed (stale rho)', async () => {
const rhoDeltas = await Promise.all(
allForwarderAddresses.map(async (forwarderAddress) => {
const forwarder = new Contract(forwarderAddress, forwarderInterface, reader)
Expand All @@ -101,25 +107,26 @@ describe('xchainOracleTicker', function () {
}
const callData = result.callData as Web3FunctionResultCallData[]

expect(callData).to.have.length(1)
expect(callData).to.have.length(3)

expect(callData[0].to).to.equal(allForwarderAddresses[rhoDeltas.indexOf(largestRhoDelta)])

const forwarder = new Contract(callData[0].to, forwarderInterface, reader)
const potRho = (await pot.rho()).toNumber()
const rhoBefore = (await forwarder.getLastSeenPotData()).rho

await insistOnExecution(() =>
keeper.sendTransaction({
to: callData[0].to,
data: callData[0].data,
}),
)
for (const data of callData) {
const forwarder = new Contract(data.to, forwarderInterface, reader)
const rhoBefore = (await forwarder.getLastSeenPotData()).rho

await insistOnExecution(() =>
keeper.sendTransaction({
to: data.to,
data: data.data,
}),
)

const rhoAfter = (await forwarder.getLastSeenPotData()).rho
const rhoAfter = (await forwarder.getLastSeenPotData()).rho

expect(rhoBefore).to.be.lessThan(potRho)
expect(rhoAfter).to.equal(potRho)
expect(rhoBefore).to.be.lessThan(potRho)
expect(rhoAfter).to.equal(potRho)
}
})

it('all refreshes are needed (stale rho)', async () => {
Expand Down
4 changes: 4 additions & 0 deletions utils/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const addresses = {
pool: '0xC13e21B648A5Ee794902342038FF3aDAB66BE987',
pot: '0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7',
protocolDataProvider: '0xFc21d6d146E6086B8359705C8b28512a983db0cb',
reth: '0xae78736Cd615f374D3085123A210448E74Fc6393',
vat: '0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B',
wbtc: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
Expand All @@ -23,6 +24,9 @@ export const addresses = {
base: '0x8Ed551D485701fe489c215E13E42F6fc59563e0e',
optimism: '0x4042127DecC0cF7cc0966791abebf7F76294DeF3',
},
updatedOptimismStyle: {
worldChain: '0xA34437dAAE56A7CC6DC757048933D7777b3e547B',
},
},
priceSources: {
wbtcBtc: '0xfdFD9C85aD200c506Cf9e21F1FD8dd01932FBB23',
Expand Down
31 changes: 30 additions & 1 deletion web3-functions/xchain-oracle-ticker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Web3Function, Web3FunctionContext } from '@gelatonetwork/web3-functions
import axios from 'axios'
import { providers, utils } from 'ethers'

import { forwarderAbi, forwarderArbitrumAbi, multicallAbi, potAbi } from '../../abis'
import { forwarderAbi, forwarderArbitrumAbi, forwarderUpdatedAbi, multicallAbi, potAbi } from '../../abis'
import { addresses, formatChi, formatDsr, formatTimestamp, sendMessageToSlack } from '../../utils'

const arbitrumDomainUrls: Record<string, string | undefined> = {
Expand Down Expand Up @@ -36,6 +36,7 @@ Feed refresh to be sent to:${messageBits.join('')}\`\`\``

const optimismStyleForwarderAddresses = addresses.mainnet.dsrForwarders.optimismStyle
const arbitrumStyleForwarderAddresses = addresses.mainnet.dsrForwarders.arbitrumStyle
const updatedOptimismStyleForwarderAddresses = addresses.mainnet.dsrForwarders.updatedOptimismStyle

const multicall = new Contract(addresses.mainnet.multicall, multicallAbi, provider)
const pot = new Contract(addresses.mainnet.pot, potAbi, provider)
Expand All @@ -53,6 +54,7 @@ Feed refresh to be sent to:${messageBits.join('')}\`\`\``
for (const forwarderAddress of [
...Object.values(optimismStyleForwarderAddresses),
...Object.values(arbitrumStyleForwarderAddresses),
...Object.values(updatedOptimismStyleForwarderAddresses),
]) {
multicallCalls.push({
target: forwarderAddress,
Expand Down Expand Up @@ -86,6 +88,33 @@ Feed refresh to be sent to:${messageBits.join('')}\`\`\``
}
}

const updatedForwarderInterface = new utils.Interface(forwarderUpdatedAbi)

for (const [domain, forwarderAddress] of Object.entries(updatedOptimismStyleForwarderAddresses)) {
const lastForwardedPotData = updatedForwarderInterface.decodeFunctionResult(
'getLastSeenPotData',
multicallResults[0],
)[0]

multicallResults = multicallResults.slice(1)

const outdatedDsr = BigInt(lastForwardedPotData.dsr) != BigInt(currentDsr)
const staleRho = BigInt(latestTimestamp) > BigInt(lastForwardedPotData.rho) + maxDelta

if (outdatedDsr || staleRho) {
callsToExecute.push({
to: forwarderAddress,
data: updatedForwarderInterface.encodeFunctionData('refresh', [gasLimit]),
})

const refreshReason = outdatedDsr
? `outdated dsr: ${formatDsr(lastForwardedPotData.dsr.toString())}`
: `stale rho: ${formatTimestamp(Number(lastForwardedPotData.rho))}`

slackMessageBits.push(generateSlackMessageBit(domain, refreshReason))
}
}

const arbitrumForwarderInterface = new utils.Interface(forwarderArbitrumAbi)

for (const [domain, forwarderAddress] of Object.entries(arbitrumStyleForwarderAddresses)) {
Expand Down

0 comments on commit c7ea31f

Please sign in to comment.