From a9e8cb5eaa5e7b6aef68a2c5e5a5ae2ed3bb7994 Mon Sep 17 00:00:00 2001 From: Derek Croote Date: Tue, 9 Jan 2024 21:35:56 -0800 Subject: [PATCH] refactor!: update OEV gateway interface (#1931) * refactor!: change OEV gateway interface 1. `api3ServerV1` has replaced `dapiServerAddress` 2. `templateId` has replaced `endpointId` and `encodedParameters`. --- .changeset/soft-sloths-brake.md | 6 ++++ .../terraform/aws/templates/oevGw.yaml.tpl | 19 +++++------- .../src/handlers/sign-oev-data.test.ts | 9 ------ .../workers/local-gateways/validation.test.ts | 25 +++++----------- .../src/workers/local-gateways/validation.ts | 29 ++++++------------- 5 files changed, 29 insertions(+), 59 deletions(-) create mode 100644 .changeset/soft-sloths-brake.md diff --git a/.changeset/soft-sloths-brake.md b/.changeset/soft-sloths-brake.md new file mode 100644 index 0000000000..fc51695029 --- /dev/null +++ b/.changeset/soft-sloths-brake.md @@ -0,0 +1,6 @@ +--- +'@api3/airnode-deployer': minor +'@api3/airnode-node': minor +--- + +BREAKING CHANGE: the OEV gateway interface has changed in the following ways: `api3ServerV1` has replaced `dapiServerAddress` and `templateId` has replaced `endpointId` and `encodedParameters`. diff --git a/packages/airnode-deployer/terraform/aws/templates/oevGw.yaml.tpl b/packages/airnode-deployer/terraform/aws/templates/oevGw.yaml.tpl index 783205d9fa..a76e6adbb2 100644 --- a/packages/airnode-deployer/terraform/aws/templates/oevGw.yaml.tpl +++ b/packages/airnode-deployer/terraform/aws/templates/oevGw.yaml.tpl @@ -18,7 +18,7 @@ components: type: object required: - chainId - - dapiServerAddress + - api3ServerV1 - oevProxyAddress - updateId - bidderAddress @@ -29,7 +29,7 @@ components: type: integer format: int32 minimum: 1 - dapiServerAddress: + api3ServerV1: type: string oevProxyAddress: type: string @@ -47,14 +47,11 @@ components: type: object required: - airnodeAddress - - endpointId - - encodedParameters + - templateId properties: airnodeAddress: type: string - endpointId: - type: string - encodedParameters: + templateId: type: string signedData: type: object @@ -82,7 +79,7 @@ components: value: | { "chainId": 1, - "dapiServerAddress": "0x...", + "api3ServerV1": "0x...", "oevProxyAddress": "0x...", "updateId": "0x...", "bidderAddress": "0x...", @@ -90,8 +87,7 @@ components: "beacons": [ { "airnodeAddress": "0x...", - "endpointId": "0x...", - "encodedParameters": "0x...", + "templateId": "0x...", "signedData": { "timestamp": "16...", "encodedValue": "0x...", @@ -100,8 +96,7 @@ components: }, { "airnodeAddress": "0x...", - "endpointId": "0x...", - "encodedParameters": "0x..." + "templateId": "0x...", } ] } diff --git a/packages/airnode-node/src/handlers/sign-oev-data.test.ts b/packages/airnode-node/src/handlers/sign-oev-data.test.ts index 858c3aab11..e36828c4ac 100644 --- a/packages/airnode-node/src/handlers/sign-oev-data.test.ts +++ b/packages/airnode-node/src/handlers/sign-oev-data.test.ts @@ -11,9 +11,6 @@ describe('signOevData', () => { beaconId: '0x1032c3cbea7692429f3f1bdb72c47b5c61bdd3ca995a763027f8aa511b42b11b', templateId: '0x64a8f8e70cd1bd4e4621bde25053bf4e22633241effa9f768bf18ff6400dc702', airnodeAddress: '0x9A2Df85E73851e27044504d72563696E5cE86B95', - endpointId: '0xa473a7ca2d5211e6e5766cc6a27c6e90a4f0270f13565e303c56a629815ed60a', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000657468657265756d000000000000000000000000000000000000000000000000', timestamp: '1677747253', encodedValue: '0x0000000000000000000000000000000000000000000000000000000000000064', // 100 signature: @@ -23,9 +20,6 @@ describe('signOevData', () => { beaconId: '0xd6965b1162b263e4dac3084ff0589614a464ac3e4ca012cb90ebb73094f7204e', templateId: '0x306c24b3373f82f267e678464c3bbca29ca5657d0cc6fa4e92981ff91e7c97f3', airnodeAddress: '0x9A2Df85E73851e27044504d72563696E5cE86B95', - endpointId: '0x6c0d51132b51cfca233be8f652189a62d1d9e3d7e0fed3dd2f131ebbf01d31d5', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000626974636f696e00000000000000000000000000000000000000000000000000', timestamp: '1677747310', encodedValue: '0x0000000000000000000000000000000000000000000000000000000000000096', // 150 signature: @@ -35,9 +29,6 @@ describe('signOevData', () => { beaconId: '0xac1054d456689fa9d63e70d6a39b2f3896f494a544865969f1de6d3a61bf10ed', templateId: '0xf13fcbc7e9b814d6f42ca68793c4c5843950d7d77f4c54105669468efc7bb8a0', airnodeAddress: '0xc89216a9adFA290354eB5365C3d5de6B6A24296a', - endpointId: '0x0441ead8bafbca489e41d994bdde04d233b88423d93bd789651f2dd60d11f752', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000646f6765636f696e000000000000000000000000000000000000000000000000', timestamp: '1677747379', encodedValue: '0x00000000000000000000000000000000000000000000000000000000000000c8', // 200 signature: diff --git a/packages/airnode-node/src/workers/local-gateways/validation.test.ts b/packages/airnode-node/src/workers/local-gateways/validation.test.ts index 5513a25443..05e4d3da61 100644 --- a/packages/airnode-node/src/workers/local-gateways/validation.test.ts +++ b/packages/airnode-node/src/workers/local-gateways/validation.test.ts @@ -35,9 +35,6 @@ const validDecodedBeacons = [ beaconId: '0x1032c3cbea7692429f3f1bdb72c47b5c61bdd3ca995a763027f8aa511b42b11b', templateId: '0x64a8f8e70cd1bd4e4621bde25053bf4e22633241effa9f768bf18ff6400dc702', airnodeAddress: '0x9A2Df85E73851e27044504d72563696E5cE86B95', - endpointId: '0xa473a7ca2d5211e6e5766cc6a27c6e90a4f0270f13565e303c56a629815ed60a', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000657468657265756d000000000000000000000000000000000000000000000000', signedData: { timestamp: '1677747253', encodedValue: '0x00000000000000000000000000000000000000000000000000000000000003e8', // 1000 @@ -50,9 +47,6 @@ const validDecodedBeacons = [ beaconId: '0xd6965b1162b263e4dac3084ff0589614a464ac3e4ca012cb90ebb73094f7204e', templateId: '0x306c24b3373f82f267e678464c3bbca29ca5657d0cc6fa4e92981ff91e7c97f3', airnodeAddress: '0x9A2Df85E73851e27044504d72563696E5cE86B95', - endpointId: '0x6c0d51132b51cfca233be8f652189a62d1d9e3d7e0fed3dd2f131ebbf01d31d5', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000626974636f696e00000000000000000000000000000000000000000000000000', signedData: { timestamp: '1677747310', encodedValue: '0x00000000000000000000000000000000000000000000000000000000000003e9', // 1001 @@ -65,9 +59,6 @@ const validDecodedBeacons = [ beaconId: '0xac1054d456689fa9d63e70d6a39b2f3896f494a544865969f1de6d3a61bf10ed', templateId: '0xf13fcbc7e9b814d6f42ca68793c4c5843950d7d77f4c54105669468efc7bb8a0', airnodeAddress: '0xc89216a9adFA290354eB5365C3d5de6B6A24296a', - endpointId: '0x0441ead8bafbca489e41d994bdde04d233b88423d93bd789651f2dd60d11f752', - encodedParameters: - '0x3173000000000000000000000000000000000000000000000000000000000000636f696e49640000000000000000000000000000000000000000000000000000646f6765636f696e000000000000000000000000000000000000000000000000', signedData: { timestamp: '1677747379', encodedValue: '0x00000000000000000000000000000000000000000000000000000000000003ea', // 1002 @@ -82,12 +73,12 @@ const validBeaconsWithIds = validDecodedBeacons.map>((de ); const validRequestBody: ProcessSignOevDataRequestBody = { chainId: 31337, - dapiServerAddress: '0x720D8B97a6B90AB8a53358447Df5cf28A9391Ab4', + api3ServerV1: '0x720D8B97a6B90AB8a53358447Df5cf28A9391Ab4', oevProxyAddress: '0x9AA42184aFD00c9599CE05748E2199F8f083036b', updateId: '0x3039656530346630306130383438646138323665616363636538343664303000', bidderAddress: '0xb5c062D4d799b85B4e29c274F9570Fd8216AED68', bidAmount: '0x0000000000000000000000000000000000000000000000000000000a571a14c0', - beacons: validBeaconsWithIds.map((beacon) => omit(beacon, ['templateId', 'beaconId'])), + beacons: validBeaconsWithIds.map((beacon) => omit(beacon, ['beaconId'])), }; describe('verifyHttpRequest', () => { @@ -252,10 +243,8 @@ describe('validateBeacons', () => { expect(validateBeacons([validRequestBody.beacons[0]])).toEqual([beacon]); }); - it('returns null if some beacons have invalid encoded parameters', () => { - expect( - validateBeacons([{ ...validRequestBody.beacons[0], encodedParameters: 'invalid encoded parameters' }]) - ).toBeNull(); + it('returns null if some beacons have invalid template IDs', () => { + expect(validateBeacons([{ ...validRequestBody.beacons[0], templateId: 'invalidTemplate' }])).toBeNull(); }); }); @@ -310,7 +299,7 @@ describe('verifySignOevDataRequest', () => { ...validBeaconsWithIds[0], signedData: { ...validBeaconsWithIds[0].signedData, timestamp: '1677740000' }, }; - const invalidEncodedParametersBeacon: BeaconWithIds = { ...validBeaconsWithIds[0], encodedParameters: 'invalid' }; + const invalidTemplateIdBeacon: BeaconWithIds = { ...validBeaconsWithIds[0], templateId: 'invalid' }; const invalidEncodedValueBeacon: BeaconWithIds = { ...validBeaconsWithIds[0], signedData: { ...validBeaconsWithIds[0].signedData, encodedValue: 'invalid' }, @@ -395,10 +384,10 @@ describe('verifySignOevDataRequest', () => { }); }); - it('fails if there are beacons with invalid encoded parameters', () => { + it('fails if there are beacons with invalid template ID', () => { expect( verifySignOevDataRequest({ - beacons: [...validRequestBody.beacons, invalidEncodedParametersBeacon], + beacons: [...validRequestBody.beacons, invalidTemplateIdBeacon], } as ProcessSignOevDataRequestBody) ).toEqual({ success: false, diff --git a/packages/airnode-node/src/workers/local-gateways/validation.ts b/packages/airnode-node/src/workers/local-gateways/validation.ts index 8296ed388e..214f1344fe 100644 --- a/packages/airnode-node/src/workers/local-gateways/validation.ts +++ b/packages/airnode-node/src/workers/local-gateways/validation.ts @@ -6,11 +6,10 @@ import { ethers } from 'ethers'; import { decode } from '@api3/airnode-abi'; import { logger } from '@api3/airnode-utilities'; import { goSync } from '@api3/promise-utils'; -import { ApiCallParameters, ApiCallTemplateWithoutId } from '../../types'; +import { ApiCallParameters } from '../../types'; import { Config, endpointIdSchema } from '../../config'; import { apiCallParametersSchema } from '../../validation'; import { getAirnodeWalletFromPrivateKey } from '../../evm'; -import { getExpectedTemplateIdV1 } from '../../evm/templates'; const TIMESTAMP_DEVIATION = 2; // in minutes // Solidity type(int224).min @@ -121,8 +120,7 @@ export function verifyHttpSignedDataRequest( const beaconSchema = z.object({ airnodeAddress: z.string(), - endpointId: z.string(), - encodedParameters: z.string(), + templateId: z.string(), // Signed data might be missing for some of the beacons (as long as the majority has the data). We still need to know // all of the beacons to derive the data feed ID. signedData: z @@ -146,7 +144,7 @@ export interface BeaconDecoded extends Required { export const signOevDataBodySchema = z.object({ chainId: z.number().positive(), - dapiServerAddress: z.string(), + api3ServerV1: z.string(), oevProxyAddress: z.string(), updateId: z.string(), bidderAddress: z.string(), @@ -234,18 +232,9 @@ export const validateBeacons = (beacons: Beacon[]): BeaconWithIds[] | null => { const goValidateBeacons = goSync(() => { const beaconsWithIds: BeaconWithIds[] = []; for (const beacon of beacons) { - const { airnodeAddress, encodedParameters, endpointId } = beacon; - - // To check parameters validity, exception is caught by the goSync - decode(encodedParameters); - - const template: ApiCallTemplateWithoutId = { - airnodeAddress, - endpointId, - encodedParameters, - }; - // Both template ID and beacon ID can fail, but it's OK because we are wrapping the validation in goSync - const templateId = getExpectedTemplateIdV1(template); + const { airnodeAddress, templateId } = beacon; + + // Beacon ID derivation can fail, but it's OK because we are wrapping the validation in goSync const beaconId = deriveBeaconId(airnodeAddress, templateId); beaconsWithIds.push({ ...beacon, templateId, beaconId }); @@ -262,7 +251,7 @@ export function verifySignOevDataRequest(requestBody: ProcessSignOevDataRequestB oevUpdateHash: string; beacons: BeaconDecoded[]; }> { - const { chainId, dapiServerAddress, oevProxyAddress, updateId, bidderAddress, bidAmount, beacons } = requestBody; + const { chainId, api3ServerV1, oevProxyAddress, updateId, bidderAddress, bidAmount, beacons } = requestBody; const beaconsWithIds = validateBeacons(beacons); if (!beaconsWithIds) { @@ -326,7 +315,7 @@ export function verifySignOevDataRequest(requestBody: ProcessSignOevDataRequestB logger.debug( `Deriving update hash. Params: ${JSON.stringify([ chainId, - dapiServerAddress, + api3ServerV1, oevProxyAddress, dataFeedId, updateId, @@ -340,7 +329,7 @@ export function verifySignOevDataRequest(requestBody: ProcessSignOevDataRequestB ['uint256', 'address', 'address', 'bytes32', 'bytes32', 'uint256', 'bytes', 'address', 'uint256'], [ chainId, - dapiServerAddress, + api3ServerV1, oevProxyAddress, dataFeedId, updateId,