diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bbcafeda..0f9a82d5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,8 +11,6 @@ on: jobs: documentation: runs-on: ubuntu-latest - # Don't run twice for a push within an internal PR - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository steps: - name: Clone repo uses: actions/checkout@v4 @@ -22,8 +20,6 @@ jobs: lint-build-test: runs-on: ubuntu-latest name: Build, lint and test - # Don't run twice for a push within an internal PR - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository steps: - name: Clone repo uses: actions/checkout@v4 diff --git a/airseeker_v2_pipeline.drawio b/airseeker_v2_pipeline.drawio index ef71b522..230441c5 100644 --- a/airseeker_v2_pipeline.drawio +++ b/airseeker_v2_pipeline.drawio @@ -1,46 +1,9 @@ - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -50,15 +13,6 @@ - - - - - - - - - @@ -114,7 +68,7 @@ - + @@ -128,14 +82,6 @@ - - - - - - - - @@ -153,13 +99,7 @@ - - - - - - - + @@ -170,37 +110,28 @@ - - - - - + + + + - + - - - - - - - - - + - - + + @@ -208,25 +139,22 @@ - + - + - + - + - - - @@ -258,6 +186,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/airseeker_v2_pipeline.drawio.svg b/airseeker_v2_pipeline.drawio.svg index ecc3e7ac..5e31beb6 100644 --- a/airseeker_v2_pipeline.drawio.svg +++ b/airseeker_v2_pipeline.drawio.svg @@ -1,4 +1,4 @@ -
for each batch
in a single RPC call
in a staggered way
for each batch...
read from 
read from 
Get all active Airnode addresses.
Get all active Airnode addresses.
TODO: maybe not needed
Signed API URL fetching loop

TODO: maybe not needed...
for all
responses
for all...
fetch from
fetch from
Fetch the signed API URLs from each provider across all chains.
Fetch the signed API URLs from each prov...
write to
write to
Persist the URLs per provider.
Persist the URLs per provider.
State
State
Chain
Chain
State
State
Repeat indefinitely, after every
fetchInterval.
Repeat indefinitely, after every...
Signed data fetching loop
Signed data fetching loop
read signedApiUrlFetchInterval
from
read signedApiUrlFetchInterval...
Repeat indefinitely, after every signedApiUrlFetchInterval.
Repeat indefinitely, after every signedA...
for each
in parallel
for each...
Get all active Airnode addresses and their respective signed API URLs.
Get all active Airnode addresses and the...
State
State
for all
responses
for all...
Call signed API URLs in parallel.
Call signed API URLs in parallel.
for all valid
responses
for all valid...
Validate signatures and timestamps.
Validate signatures and timestamps.
Persist the signed data per beacon.
Persist the signed data per beacon.
write to
write to
State
State
independently for
each sub-loop
independently for...
For each provider across all chains run a separate sub-loop.
For each provider across all chains run...
Data feed update loop
Data feed update loop
Repeat indefinitely, after every updateInterval.
Repeat indefinitely, after every updateI...
for each batch
in a single RPC call
in a staggered way
for each batch...
Determine the number of batches of active dAPIs.

TODO: This is not yet finalized
Determine the number of batches of activ...
fetch from
fetch from
Chain
Chain
for all active dAPIs
in the batch
for all active dAPIs...
in a single RPC call
in a single RPC call
Fetch the active dAPIs batch together with Airnode address and template ID(s).

TODO: This is not yet finalized.
Fetch the active dAPIs batch together wi...
fetch from
fetch from
Chain
Chain
Call signed API URLs in parallel.
Call signed API URLs in parallel.
Call signed API URL.
Call signed API URL.
Fetch the signed API URLs from each provider across all chains.
Fetch the signed API URLs from each prov...
Fetch the signed API URLs from each provider using across all chains.
Fetch the signed API URLs from each prov...
Persist the Airnode addresses and template IDs for these dAPIs.

TODO: This is not yet finalized.
Persist the Airnode addresses and templa...
write to
write to
State
State
for all dAPIs
for all dAPIs
Get the on-chain values for dAPIs.
Get the on-chain values for dAPIs.
Fetch the active dAPIs batch together with Airnode address and template ID(s).

TODO: This is not yet finalized.
Fetch the active dAPIs batch together wi...
Fetch the active dAPIs batch together with Airnode address and template ID(s).

TODO: This is not yet finalized.
Fetch the active dAPIs batch together wi...
fetch from
fetch from
Chain
Chain
if there is any dAPI
to be updated
if there is any dAPI...
Determine which dAPIs need to
be updated.
Determine which dAPIs need to...
for each dAPI that needs
to be updated
for each dAPI that needs...
Calculate gas price
(once for all dAPIs).
Calculate gas price...
for each update
transaction
for each update...
Create a multicall update transaction with
respective sponsor wallet.
Create a multicall update transaction wi...
Submit a multicall transaction.
Submit a multicall transaction.
to
to
Chain
Chain
Config
Config
Config
Config
read fetchInterval
from
read fetchInterval...
Config
Config
read from 
read from 
read from
read from
merge
merge
read dataFeedUpdateInterval
from
read dataFeedUpdateInterval...
Config
Config
Repeat indefinitely, after every updateInterval.
Repeat indefinitely, after every updateI...
Repeat indefinitely, after every dataFeedUpdateInterval.
Repeat indefinitely, after every dataFee...
Text is not SVG - cannot display
\ No newline at end of file +
Repeat indefinitely, after every
fetchInterval.
Repeat indefinitely, after every...
Signed data fetching loop
Signed data fetching loop
for each
in parallel
for each...
Get all active Airnode addresses and their respective signed API URLs.
Get all active Airnode addresses and the...
State
State
for all
responses
for all...
Call signed API URLs in parallel.
Call signed API URLs in parallel.
for all valid
responses
for all valid...
Validate signatures and timestamps.
Validate signatures and timestamps.
Persist the signed data per beacon.
Persist the signed data per beacon.
write to
write to
State
State
independently for
each sub-loop
independently for...
For each provider across all chains run a separate sub-loop.
For each provider across all chains run...
Data feed update loop
Data feed update loop
Repeat indefinitely, after every updateInterval.
Repeat indefinitely, after every updateI...
for each batch
in a single RPC call
in a staggered way
for each batch...
Multicall to get the first batch of active dAPIs along with the total count of active dAPIs.
Multicall to get the first batch of acti...
fetch from
fetch from
Chain
Chain
for all active dAPIs
in the batch
for all active dAPIs...
Fetch the active dAPIs batch together with Airnode address and template ID(s).

TODO: This is not yet finalized.
Fetch the active dAPIs batch together wi...
fetch from
fetch from
Chain
Chain
Call signed API URLs in parallel.
Call signed API URLs in parallel.
Call signed API URL.
Call signed API URL.
Persist the Airnode addresses, template IDs, signed API URLs and on-chain values for these dAPIs.
Persist the Airnode addresses, template...
write to
write to
State
State
for all dAPIs
for all dAPIs
Fetch the active dAPIs batch together with Airnode address and template ID(s).

TODO: This is not yet finalized.
Fetch the active dAPIs batch together wi...
Fetch the rest of the active dAPI batches together with Airnode address, template ID(s), signed API URLs and on chain values.
Fetch the rest of the active dAPI batche...
if there is any dAPI
to be updated
if there is any dAPI...
Determine which dAPIs need to
be updated.
Determine which dAPIs need to...
for each dAPI that needs
to be updated
for each dAPI that needs...
Run gas collector and calculate gas price
(once for all dAPIs).
Run gas collector and calculate gas pric...
for each update
transaction
for each update...
Create a multicall update transaction with
respective sponsor wallet.
Create a multicall update transaction wi...
Submit a multicall transaction.
Submit a multicall transaction.
to
to
Chain
Chain
Config
Config
read fetchInterval
from
read fetchInterval...
Config
Config
read from 
read from 
read from
read from
merge
merge
read dataFeedUpdateInterval
from
read dataFeedUpdateInterval...
Config
Config
Repeat indefinitely, after every updateInterval.
Repeat indefinitely, after every updateI...
Repeat indefinitely, after every dataFeedUpdateInterval.
Repeat indefinitely, after every dataFee...
for each dAPI where an update is not needed
for each d...
clear stored on chain datafeed value from gas price store
clear stored on chain datafeed value fro...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/src/condition-check/condition-check.test.ts b/src/condition-check/condition-check.test.ts index 4b30001a..b6ee1b76 100644 --- a/src/condition-check/condition-check.test.ts +++ b/src/condition-check/condition-check.test.ts @@ -1,4 +1,8 @@ import { BigNumber, ethers } from 'ethers'; + +import { getUnixTimestamp } from '../../test/fixtures/utils'; +import { HUNDRED_PERCENT } from '../constants'; + import { calculateMedian, calculateUpdateInPercentage, @@ -7,8 +11,6 @@ import { checkDeviationThresholdExceeded, checkUpdateConditions, } from './condition-check'; -import { getUnixTimestamp } from '../../test/fixtures/utils'; -import { HUNDRED_PERCENT } from '../constants'; describe('checkUpdateCondition', () => { const onChainValue = ethers.BigNumber.from(500); @@ -101,47 +103,47 @@ describe('checkOnchainDataFreshness', () => { describe('calculateUpdateInPercentage', () => { it('calculates zero change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(10), ethers.BigNumber.from(10)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(0 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(0 * HUNDRED_PERCENT)); }); it('calculates 100 percent change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(10), ethers.BigNumber.from(20)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(1 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(1 * HUNDRED_PERCENT)); }); it('calculates positive to negative change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(10), ethers.BigNumber.from(-5)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(1.5 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(1.5 * HUNDRED_PERCENT)); }); it('calculates negative to positive change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(-5), ethers.BigNumber.from(5)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(2 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(2 * HUNDRED_PERCENT)); }); it('calculates initial zero to positive change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(0), ethers.BigNumber.from(5)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(5 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(5 * HUNDRED_PERCENT)); }); it('calculates initial zero to negative change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(0), ethers.BigNumber.from(-5)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(5 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(5 * HUNDRED_PERCENT)); }); it('calculates initial positive to zero change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(5), ethers.BigNumber.from(0)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(1 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(1 * HUNDRED_PERCENT)); }); it('calculates initial negative to zero change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(-5), ethers.BigNumber.from(0)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(1 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(1 * HUNDRED_PERCENT)); }); it('calculates initial negative to negative change', () => { const updateInPercentage = calculateUpdateInPercentage(ethers.BigNumber.from(-5), ethers.BigNumber.from(-1)); - expect(updateInPercentage).toEqual(ethers.BigNumber.from(0.8 * HUNDRED_PERCENT)); + expect(updateInPercentage).toStrictEqual(ethers.BigNumber.from(0.8 * HUNDRED_PERCENT)); }); }); @@ -149,24 +151,24 @@ describe('calculateMedian', () => { describe('for array with odd number of elements', () => { it('calculates median for sorted array', () => { const arr = [BigNumber.from(10), BigNumber.from(11), BigNumber.from(24), BigNumber.from(30), BigNumber.from(47)]; - expect(calculateMedian(arr)).toEqual(BigNumber.from(24)); + expect(calculateMedian(arr)).toStrictEqual(BigNumber.from(24)); }); it('calculates median for unsorted array', () => { const arr = [BigNumber.from(24), BigNumber.from(11), BigNumber.from(10), BigNumber.from(47), BigNumber.from(30)]; - expect(calculateMedian(arr)).toEqual(BigNumber.from(24)); + expect(calculateMedian(arr)).toStrictEqual(BigNumber.from(24)); }); }); describe('for array with even number of elements', () => { it('calculates median for sorted array', () => { const arr = [BigNumber.from(10), BigNumber.from(11), BigNumber.from(24), BigNumber.from(30)]; - expect(calculateMedian(arr)).toEqual(BigNumber.from(17)); + expect(calculateMedian(arr)).toStrictEqual(BigNumber.from(17)); }); it('calculates median for unsorted array', () => { const arr = [BigNumber.from(24), BigNumber.from(11), BigNumber.from(10), BigNumber.from(30)]; - expect(calculateMedian(arr)).toEqual(BigNumber.from(17)); + expect(calculateMedian(arr)).toStrictEqual(BigNumber.from(17)); }); }); }); diff --git a/src/condition-check/condition-check.ts b/src/condition-check/condition-check.ts index 5256f893..b9d19f26 100644 --- a/src/condition-check/condition-check.ts +++ b/src/condition-check/condition-check.ts @@ -1,4 +1,5 @@ import { ethers } from 'ethers'; + import { HUNDRED_PERCENT } from '../constants'; import { logger } from '../logger';