From 0ddd9148fb9e8046a91918fb87bc69fad26a972b Mon Sep 17 00:00:00 2001 From: "James Morris, MS" <96435344+james-a-morris@users.noreply.github.com> Date: Tue, 10 Dec 2024 15:46:50 -0500 Subject: [PATCH 1/6] chore: bump api spec (#1317) Signed-off-by: james-a-morris --- api-docs-openapi.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api-docs-openapi.yaml b/api-docs-openapi.yaml index a22d1992e..ed8fc94d9 100644 --- a/api-docs-openapi.yaml +++ b/api-docs-openapi.yaml @@ -104,8 +104,8 @@ paths: Calldata passed to the `recipient` if `recipient` is a contract address. This calldata is passed to the recipient via the recipient's handleAcrossMessage() public function. The length of - this value is constrained by the API to ~4096 chars minus the length - of the full URL. + this value is constrained by the API to ~12288 chars (12KB) minus + the length of the full URL. _Example:_ 0xABC123 From f790005e8e8f86d8fa5da6aa053f1859d314d826 Mon Sep 17 00:00:00 2001 From: dylanuma Date: Wed, 11 Dec 2024 16:50:05 +0000 Subject: [PATCH 2/6] feat: relayer signature auth --- api/relayer_auth.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 api/relayer_auth.ts diff --git a/api/relayer_auth.ts b/api/relayer_auth.ts new file mode 100644 index 000000000..d6c662855 --- /dev/null +++ b/api/relayer_auth.ts @@ -0,0 +1,31 @@ +import { ethers } from 'ethers'; + +/** + * Get the address that signed a configuration update + * @param configPayload The configuration update payload + * @param signature The signature provided by the relayer + * @returns The Ethereum address that signed the payload + */ +async function getSignerAddress( + configPayload: Record, + signature: string +): Promise { + try { + // Convert payload to string and hash it + const payloadStr = JSON.stringify(configPayload); + const messageHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(payloadStr)); + + // Create signable message + const prefixedMessage = ethers.utils.arrayify(messageHash); + + // Recover the address that signed the message + const recoveredAddress = ethers.utils.verifyMessage(prefixedMessage, signature); + + // Convert to checksum format + return ethers.utils.getAddress(recoveredAddress); + + } catch (error) { + console.error('Error recovering signer address:', error); + throw error; + } +} \ No newline at end of file From 2198f1c63bdb287b11fc128c60c93357655be56e Mon Sep 17 00:00:00 2001 From: dylanuma Date: Wed, 11 Dec 2024 16:55:37 +0000 Subject: [PATCH 3/6] feat: relayer auth verification method --- ...yer_auth.ts => relayer_auth_submission.ts} | 0 api/relayer_auth_verification.ts | 31 +++++++++++++++++++ 2 files changed, 31 insertions(+) rename api/{relayer_auth.ts => relayer_auth_submission.ts} (100%) create mode 100644 api/relayer_auth_verification.ts diff --git a/api/relayer_auth.ts b/api/relayer_auth_submission.ts similarity index 100% rename from api/relayer_auth.ts rename to api/relayer_auth_submission.ts diff --git a/api/relayer_auth_verification.ts b/api/relayer_auth_verification.ts new file mode 100644 index 000000000..d6c662855 --- /dev/null +++ b/api/relayer_auth_verification.ts @@ -0,0 +1,31 @@ +import { ethers } from 'ethers'; + +/** + * Get the address that signed a configuration update + * @param configPayload The configuration update payload + * @param signature The signature provided by the relayer + * @returns The Ethereum address that signed the payload + */ +async function getSignerAddress( + configPayload: Record, + signature: string +): Promise { + try { + // Convert payload to string and hash it + const payloadStr = JSON.stringify(configPayload); + const messageHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(payloadStr)); + + // Create signable message + const prefixedMessage = ethers.utils.arrayify(messageHash); + + // Recover the address that signed the message + const recoveredAddress = ethers.utils.verifyMessage(prefixedMessage, signature); + + // Convert to checksum format + return ethers.utils.getAddress(recoveredAddress); + + } catch (error) { + console.error('Error recovering signer address:', error); + throw error; + } +} \ No newline at end of file From ac81cd0144eaaa8f22a9ac966be98150ec87186c Mon Sep 17 00:00:00 2001 From: dylanuma Date: Wed, 11 Dec 2024 16:56:22 +0000 Subject: [PATCH 4/6] fix: use local packages --- api/relayer_auth_submission.ts | 13 ++++--- api/relayer_auth_verification.ts | 64 +++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/api/relayer_auth_submission.ts b/api/relayer_auth_submission.ts index d6c662855..69989e7c5 100644 --- a/api/relayer_auth_submission.ts +++ b/api/relayer_auth_submission.ts @@ -1,4 +1,5 @@ -import { ethers } from 'ethers'; +import { utils } from 'ethers'; +import { getProvider } from '@/utils/provider'; /** * Get the address that signed a configuration update @@ -6,23 +7,23 @@ import { ethers } from 'ethers'; * @param signature The signature provided by the relayer * @returns The Ethereum address that signed the payload */ -async function getSignerAddress( +export async function getSignerAddress( configPayload: Record, signature: string ): Promise { try { // Convert payload to string and hash it const payloadStr = JSON.stringify(configPayload); - const messageHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(payloadStr)); + const messageHash = utils.keccak256(utils.toUtf8Bytes(payloadStr)); // Create signable message - const prefixedMessage = ethers.utils.arrayify(messageHash); + const prefixedMessage = utils.arrayify(messageHash); // Recover the address that signed the message - const recoveredAddress = ethers.utils.verifyMessage(prefixedMessage, signature); + const recoveredAddress = utils.verifyMessage(prefixedMessage, signature); // Convert to checksum format - return ethers.utils.getAddress(recoveredAddress); + return utils.getAddress(recoveredAddress); } catch (error) { console.error('Error recovering signer address:', error); diff --git a/api/relayer_auth_verification.ts b/api/relayer_auth_verification.ts index d6c662855..30e72b077 100644 --- a/api/relayer_auth_verification.ts +++ b/api/relayer_auth_verification.ts @@ -1,31 +1,67 @@ -import { ethers } from 'ethers'; +import { utils } from 'ethers'; +import { getProvider } from '@/utils/provider'; /** - * Get the address that signed a configuration update + * Verify a relayer's configuration update signature and nonce * @param configPayload The configuration update payload - * @param signature The signature provided by the relayer - * @returns The Ethereum address that signed the payload + * @param signature The signature provided by the relayer + * @param nonce The nonce value to prevent replay attacks + * @throws Error if signature is invalid or nonce has been used */ -async function getSignerAddress( +export async function verifyRelayerSignature( configPayload: Record, - signature: string -): Promise { + signature: string, + nonce: number +): Promise { try { + // Verify nonce hasn't been used before + if (await hasNonceBeenUsed(nonce)) { + throw new Error('Nonce has already been used'); + } + + // Add nonce to payload before verifying + const payloadWithNonce = { + ...configPayload, + nonce + }; + // Convert payload to string and hash it - const payloadStr = JSON.stringify(configPayload); - const messageHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(payloadStr)); + const payloadStr = JSON.stringify(payloadWithNonce); + const messageHash = utils.keccak256(utils.toUtf8Bytes(payloadStr)); // Create signable message - const prefixedMessage = ethers.utils.arrayify(messageHash); + const prefixedMessage = utils.arrayify(messageHash); // Recover the address that signed the message - const recoveredAddress = ethers.utils.verifyMessage(prefixedMessage, signature); + const recoveredAddress = utils.verifyMessage(prefixedMessage, signature); + const checksumAddress = utils.getAddress(recoveredAddress); + + // Verify signer is an authorized relayer + if (!await isAuthorizedRelayer(checksumAddress)) { + throw new Error('Signer is not an authorized relayer'); + } - // Convert to checksum format - return ethers.utils.getAddress(recoveredAddress); + // Store nonce as used + await storeUsedNonce(nonce); } catch (error) { - console.error('Error recovering signer address:', error); + console.error('Error verifying relayer signature:', error); throw error; } +} + +// Helper functions that would need to be implemented: +async function hasNonceBeenUsed(nonce: number): Promise { + // Check if nonce exists in storage + throw new Error('Not implemented'); +} + +async function isAuthorizedRelayer(address: string): Promise { + // Check if address is in authorized relayer list + throw new Error('Not implemented'); +} + +async function storeUsedNonce(nonce: number): Promise { + // Store nonce in persistent storage + throw new Error('Not implemented'); } \ No newline at end of file From f23d7212fd2539789c3484fd55f32ceb48e04d7e Mon Sep 17 00:00:00 2001 From: dylanuma Date: Wed, 11 Dec 2024 16:59:44 +0000 Subject: [PATCH 5/6] fix: remove dylan files :( --- api/relayer_auth_submission.ts | 32 --------------- api/relayer_auth_verification.ts | 67 -------------------------------- 2 files changed, 99 deletions(-) delete mode 100644 api/relayer_auth_submission.ts delete mode 100644 api/relayer_auth_verification.ts diff --git a/api/relayer_auth_submission.ts b/api/relayer_auth_submission.ts deleted file mode 100644 index 69989e7c5..000000000 --- a/api/relayer_auth_submission.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { utils } from 'ethers'; -import { getProvider } from '@/utils/provider'; - -/** - * Get the address that signed a configuration update - * @param configPayload The configuration update payload - * @param signature The signature provided by the relayer - * @returns The Ethereum address that signed the payload - */ -export async function getSignerAddress( - configPayload: Record, - signature: string -): Promise { - try { - // Convert payload to string and hash it - const payloadStr = JSON.stringify(configPayload); - const messageHash = utils.keccak256(utils.toUtf8Bytes(payloadStr)); - - // Create signable message - const prefixedMessage = utils.arrayify(messageHash); - - // Recover the address that signed the message - const recoveredAddress = utils.verifyMessage(prefixedMessage, signature); - - // Convert to checksum format - return utils.getAddress(recoveredAddress); - - } catch (error) { - console.error('Error recovering signer address:', error); - throw error; - } -} \ No newline at end of file diff --git a/api/relayer_auth_verification.ts b/api/relayer_auth_verification.ts deleted file mode 100644 index 30e72b077..000000000 --- a/api/relayer_auth_verification.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { utils } from 'ethers'; -import { getProvider } from '@/utils/provider'; - -/** - * Verify a relayer's configuration update signature and nonce - * @param configPayload The configuration update payload - * @param signature The signature provided by the relayer - * @param nonce The nonce value to prevent replay attacks - * @throws Error if signature is invalid or nonce has been used - */ -export async function verifyRelayerSignature( - configPayload: Record, - signature: string, - nonce: number -): Promise { - try { - // Verify nonce hasn't been used before - if (await hasNonceBeenUsed(nonce)) { - throw new Error('Nonce has already been used'); - } - - // Add nonce to payload before verifying - const payloadWithNonce = { - ...configPayload, - nonce - }; - - // Convert payload to string and hash it - const payloadStr = JSON.stringify(payloadWithNonce); - const messageHash = utils.keccak256(utils.toUtf8Bytes(payloadStr)); - - // Create signable message - const prefixedMessage = utils.arrayify(messageHash); - - // Recover the address that signed the message - const recoveredAddress = utils.verifyMessage(prefixedMessage, signature); - const checksumAddress = utils.getAddress(recoveredAddress); - - // Verify signer is an authorized relayer - if (!await isAuthorizedRelayer(checksumAddress)) { - throw new Error('Signer is not an authorized relayer'); - } - - // Store nonce as used - await storeUsedNonce(nonce); - - } catch (error) { - console.error('Error verifying relayer signature:', error); - throw error; - } -} - -// Helper functions that would need to be implemented: -async function hasNonceBeenUsed(nonce: number): Promise { - // Check if nonce exists in storage - throw new Error('Not implemented'); -} - -async function isAuthorizedRelayer(address: string): Promise { - // Check if address is in authorized relayer list - throw new Error('Not implemented'); -} - -async function storeUsedNonce(nonce: number): Promise { - // Store nonce in persistent storage - throw new Error('Not implemented'); -} \ No newline at end of file From e9d2866134aa92840ef0b932380a2cce659ef0dc Mon Sep 17 00:00:00 2001 From: Paul <108695806+pxrl@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:26:27 +0000 Subject: [PATCH 6/6] Initial relayer limit config type --- api/_types/exclusivity.types.ts | 56 +++++++++++++++++++++++++++++++++ api/_types/index.ts | 1 + 2 files changed, 57 insertions(+) create mode 100644 api/_types/exclusivity.types.ts diff --git a/api/_types/exclusivity.types.ts b/api/_types/exclusivity.types.ts new file mode 100644 index 000000000..435ba59a4 --- /dev/null +++ b/api/_types/exclusivity.types.ts @@ -0,0 +1,56 @@ +export type RelayerFillLimit = { + originChainId: number; + inputToken: string; + destinationChainId: number; + outputToken: string; + minOutputAmount?: number; + maxOutputAmount?: number; + minExclusivityPeriod?: number; + minProfitThreshold?: number; + balanceMultiplier?: number; + msgFill?: boolean; +}; + +// Example config. +export const RelayerConfigUpdate: RelayerFillLimit[] = [ + { + originChainId: 1, + inputToken: "", + destinationChainId: 42161, + outputToken: "", + minExclusivityPeriod: 20, + minProfitThreshold: 0.0003, + balanceMultiplier: 0.6, + maxOutputAmount: 2500, + }, + { + originChainId: 10, + inputToken: "", + destinationChainId: 42161, + outputToken: "", + minExclusivityPeriod: 5, + minProfitThreshold: 0.0003, + balanceMultiplier: 0.6, + maxOutputAmount: 2500, + }, + { + originChainId: 137, + inputToken: "", + destinationChainId: 42161, + outputToken: "", + minExclusivityPeriod: 5, + minProfitThreshold: 0.0003, + balanceMultiplier: 0.6, + maxOutputAmount: 2500, + }, + { + originChainId: 324, + inputToken: "", + destinationChainId: 42161, + outputToken: "", + minExclusivityPeriod: 5, + minProfitThreshold: 0.0003, + balanceMultiplier: 0.6, + maxOutputAmount: 2500, + }, +]; diff --git a/api/_types/index.ts b/api/_types/index.ts index 6723d1603..3e5e03912 100644 --- a/api/_types/index.ts +++ b/api/_types/index.ts @@ -1,2 +1,3 @@ +export * from "./exclusivity.types"; export * from "./generic.types"; export * from "./utility.types";