From 650c343a329b3b7b9fd4292a4b9d64b27136ca21 Mon Sep 17 00:00:00 2001 From: MantisClone Date: Fri, 11 Apr 2025 17:24:22 -0400 Subject: [PATCH 1/5] feat(ethereum-storage): add ThirdwebTransactionSubmitter --- packages/ethereum-storage/src/index.ts | 1 + .../src/thirdweb/thirdweb-tx-submitter.ts | 151 ++++++++++++++++++ .../ethereum-storage/src/thirdweb/types.ts | 49 ++++++ .../test/thirdweb-tx-submitter.test.ts | 110 +++++++++++++ 4 files changed, 311 insertions(+) create mode 100644 packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts create mode 100644 packages/ethereum-storage/src/thirdweb/types.ts create mode 100644 packages/ethereum-storage/test/thirdweb-tx-submitter.test.ts diff --git a/packages/ethereum-storage/src/index.ts b/packages/ethereum-storage/src/index.ts index 40dbc32440..e223441dd4 100644 --- a/packages/ethereum-storage/src/index.ts +++ b/packages/ethereum-storage/src/index.ts @@ -6,3 +6,4 @@ export { EthereumStorage } from './ethereum-storage'; export { EthereumTransactionSubmitter } from './ethereum-tx-submitter'; export { GasFeeDefiner } from './gas-fee-definer'; export { IpfsStorage } from './ipfs-storage'; +export { ThirdwebTransactionSubmitter } from './thirdweb/thirdweb-tx-submitter'; diff --git a/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts b/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts new file mode 100644 index 0000000000..3ebd41972f --- /dev/null +++ b/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts @@ -0,0 +1,151 @@ +import { BigNumber, utils } from 'ethers'; +import { StorageTypes, LogTypes } from '@requestnetwork/types'; +import { Engine } from '@thirdweb-dev/engine'; +import { SimpleLogger } from '@requestnetwork/utils'; +import { requestHashSubmitterArtifact } from '@requestnetwork/smart-contracts'; +import { networkToChainId } from './types'; + +export interface ThirdwebSubmitterOptions { + /** + * The URL of your Thirdweb Engine instance + */ + engineUrl: string; + + /** + * The access token for Thirdweb Engine + */ + accessToken: string; + + /** + * The address of the wallet configured in Thirdweb Engine + */ + backendWalletAddress: string; + + /** + * Network name (e.g. 'mainnet', 'goerli', etc.) + */ + network: string; + + /** + * Optional logger instance + */ + logger?: LogTypes.ILogger; +} + +/** + * Handles the submission of IPFS hashes through Thirdweb Engine + */ +export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSubmitter { + private readonly logger: LogTypes.ILogger; + private readonly engine: Engine; + private readonly backendWalletAddress: string; + private _network: string; + private _hashSubmitterAddress: string; + + constructor({ + engineUrl, + accessToken, + backendWalletAddress, + network, + logger, + }: ThirdwebSubmitterOptions) { + this.logger = logger || new SimpleLogger(); + this.engine = new Engine({ + url: engineUrl, + accessToken: accessToken, + }); + this.backendWalletAddress = backendWalletAddress; + this._network = network; + // Get the hash submitter address for the specified network + this._hashSubmitterAddress = requestHashSubmitterArtifact.getAddress(network); + } + + get network(): string { + return this._network; + } + + set network(value: string) { + this._network = value; + } + + get hashSubmitterAddress(): string { + return this._hashSubmitterAddress; + } + + set hashSubmitterAddress(value: string) { + this._hashSubmitterAddress = value; + } + + async initialize(): Promise { + const chainId = networkToChainId[this._network] || 1; + this.logger.info( + `Initializing ThirdwebTransactionSubmitter for network ${this._network} (chainId: ${chainId})`, + ); + + // Check Engine connection + try { + await this.engine.getWallets({}); + this.logger.info('Successfully connected to Thirdweb Engine'); + } catch (error) { + this.logger.error('Failed to connect to Thirdweb Engine', error); + throw new Error('Failed to connect to Thirdweb Engine'); + } + } + + /** + * Submits an IPFS hash via Thirdweb Engine + */ + async submit(ipfsHash: string, ipfsSize: number): Promise { + this.logger.info(`Submitting hash ${ipfsHash} with size ${ipfsSize} via Thirdweb Engine`); + const preparedTx = await this.prepareSubmit(ipfsHash, ipfsSize); + const chainId = networkToChainId[this._network] || 1; + + try { + const result = await this.engine.sendTransaction({ + chainId: chainId, + fromAddress: this.backendWalletAddress, + toAddress: preparedTx.to, + data: preparedTx.data as string, + value: preparedTx.value ? preparedTx.value.toString() : '0', + }); + + this.logger.info(`Transaction submitted successfully: ${result.transactionHash}`); + return { + hash: result.transactionHash, + wait: async () => { + // This function returns a promise that resolves when the transaction is mined + // Transaction status can be tracked either by polling the blockchain + // or by using webhook notifications from Thirdweb Engine + return { status: 1 }; + }, + }; + } catch (error) { + this.logger.error('Failed to submit transaction through Thirdweb Engine', error); + throw error; + } + } + + /** + * Prepares the transaction for submitting an IPFS hash + */ + async prepareSubmit(ipfsHash: string, ipfsSize: number): Promise { + // Create contract interface for the hash submitter + const iface = requestHashSubmitterArtifact.getInterface(); + + // Calculate fee - in a real implementation, you might want to fetch this from the contract + // For now, we assume it's 0 for simplicity + const fee = BigNumber.from(0); + + // Encode function data + const data = iface.encodeFunctionData('submitHash', [ + ipfsHash, + utils.hexZeroPad(utils.hexlify(ipfsSize), 32), + ]); + + return { + to: this.hashSubmitterAddress, + data: data, + value: fee, + }; + } +} diff --git a/packages/ethereum-storage/src/thirdweb/types.ts b/packages/ethereum-storage/src/thirdweb/types.ts new file mode 100644 index 0000000000..24022cdf81 --- /dev/null +++ b/packages/ethereum-storage/src/thirdweb/types.ts @@ -0,0 +1,49 @@ +/** + * Configuration for the Thirdweb Engine + */ +export interface ThirdwebEngineConfig { + /** + * The URL of your Thirdweb Engine instance + */ + engineUrl: string; + + /** + * The access token for Thirdweb Engine + */ + accessToken: string; + + /** + * The address of the wallet configured in Thirdweb Engine + */ + backendWalletAddress: string; + + /** + * Secret for verifying webhook signatures + */ + webhookSecret?: string; + + /** + * Whether to use Thirdweb Engine + */ + enabled: boolean; +} + +/** + * Chain ID mapping for common networks + */ +export const networkToChainId: Record = { + mainnet: 1, + goerli: 5, + sepolia: 11155111, + xdai: 100, + private: 1337, +}; + +/** + * Get the chain ID for a given network + * @param network Network name + * @returns Chain ID + */ +export function getChainId(network: string): number { + return networkToChainId[network] || 1; +} diff --git a/packages/ethereum-storage/test/thirdweb-tx-submitter.test.ts b/packages/ethereum-storage/test/thirdweb-tx-submitter.test.ts new file mode 100644 index 0000000000..adfdd643d7 --- /dev/null +++ b/packages/ethereum-storage/test/thirdweb-tx-submitter.test.ts @@ -0,0 +1,110 @@ +import { ThirdwebTransactionSubmitter } from '../src/thirdweb/thirdweb-tx-submitter'; +import { Engine } from '@thirdweb-dev/engine'; +import { LogTypes } from '@requestnetwork/types'; +import { requestHashSubmitterArtifact } from '@requestnetwork/smart-contracts'; +import { networkToChainId } from '../src/thirdweb/types'; + +// Mock the Thirdweb Engine +jest.mock('@thirdweb-dev/engine', () => { + return { + Engine: jest.fn().mockImplementation(() => ({ + getWallets: jest.fn().mockResolvedValue([{ address: '0x123' }]), + sendTransaction: jest.fn().mockResolvedValue({ + transactionHash: '0xabcdef1234567890', + }), + })), + }; +}); + +// Mock the hash submitter artifact +jest.mock('@requestnetwork/smart-contracts', () => { + return { + requestHashSubmitterArtifact: { + getAddress: jest.fn().mockReturnValue('0xf25186b5081ff5ce73482ad761db0eb0d25abfbf'), + getInterface: jest.fn().mockReturnValue({ + encodeFunctionData: jest.fn().mockReturnValue('0x1234abcd'), + }), + }, + }; +}); + +describe('ThirdwebTransactionSubmitter', () => { + const mockLogger: LogTypes.ILogger = { + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + const submitterOptions = { + engineUrl: 'https://engine.thirdweb.com', + accessToken: 'test-token', + backendWalletAddress: '0xbackendWalletAddress', + network: 'mainnet', + logger: mockLogger, + }; + + let txSubmitter: ThirdwebTransactionSubmitter; + + beforeEach(() => { + jest.clearAllMocks(); + txSubmitter = new ThirdwebTransactionSubmitter(submitterOptions); + }); + + it('can initialize', async () => { + await txSubmitter.initialize(); + expect(mockLogger.info).toHaveBeenCalledWith( + 'Initializing ThirdwebTransactionSubmitter for network mainnet (chainId: 1)', + ); + expect(mockLogger.info).toHaveBeenCalledWith('Successfully connected to Thirdweb Engine'); + }); + + it('can prepare submit', async () => { + const result = await txSubmitter.prepareSubmit('ipfshash', 100); + + expect(result).toEqual({ + to: '0xf25186b5081ff5ce73482ad761db0eb0d25abfbf', + data: '0x1234abcd', + value: expect.any(Object), + }); + + expect(requestHashSubmitterArtifact.getInterface).toHaveBeenCalled(); + expect(requestHashSubmitterArtifact.getInterface().encodeFunctionData).toHaveBeenCalledWith( + 'submitHash', + ['ipfshash', expect.any(String)], + ); + }); + + it('can submit', async () => { + const result = await txSubmitter.submit('ipfshash', 100); + + expect(result).toEqual({ + hash: '0xabcdef1234567890', + wait: expect.any(Function), + }); + + expect(mockLogger.info).toHaveBeenCalledWith( + 'Submitting hash ipfshash with size 100 via Thirdweb Engine', + ); + + const engineInstance = (Engine as jest.Mock).mock.results[0].value; + expect(engineInstance.sendTransaction).toHaveBeenCalledWith({ + chainId: 1, + fromAddress: '0xbackendWalletAddress', + toAddress: '0xf25186b5081ff5ce73482ad761db0eb0d25abfbf', + data: '0x1234abcd', + value: '0', + }); + }); + + it('should handle errors during submission', async () => { + const engineInstance = (Engine as jest.Mock).mock.results[0].value; + engineInstance.sendTransaction.mockRejectedValueOnce(new Error('Transaction failed')); + + await expect(txSubmitter.submit('ipfshash', 100)).rejects.toThrow('Transaction failed'); + expect(mockLogger.error).toHaveBeenCalledWith( + 'Failed to submit transaction through Thirdweb Engine', + expect.any(Error), + ); + }); +}); From d2d424366d4cb20c7758414878a18864ffa0a272 Mon Sep 17 00:00:00 2001 From: MantisClone Date: Mon, 14 Apr 2025 12:44:53 -0400 Subject: [PATCH 2/5] feat: integrate Thirdweb Engine into Request Node --- packages/request-node/README.md | 74 +++++++++++---------- packages/request-node/src/config.ts | 88 +++++++++++++++++++++++-- packages/request-node/src/dataAccess.ts | 66 +++++++++++-------- packages/request-node/src/server.ts | 34 ++++++++-- 4 files changed, 185 insertions(+), 77 deletions(-) diff --git a/packages/request-node/README.md b/packages/request-node/README.md index 56361f839a..1bb02d93eb 100644 --- a/packages/request-node/README.md +++ b/packages/request-node/README.md @@ -221,42 +221,25 @@ Default values correspond to the basic configuration used to run a server in a t #### Options: -- `--port` Port for the server to listen for API requests - - Default value: `3000` - - Environment variable name: `$PORT` -- `--networkId` Id of the Ethereum network used - - Default value: `0` - - Environment variable name: `$ETHEREUM_NETWORK_ID` -- `--providerUrl` URL of the web3 provider for Ethereum - - Default value: `http://localhost:8545` - - Environment variable name: `$WEB3_PROVIDER_URL` -- `--ipfsUrl` URL of the IPFS gateway - - Default value: `http://localhost:5001` - - Environment variable name: `$IPFS_URL` -- `--ipfsTimeout` Timeout threshold to connect to the IPFS gateway - - Default value: `10000` - - Environment variable name: `$IPFS_TIMEOUT` -- `--blockConfirmations` The number of block confirmations to consider a transaction successful - - Default value: `2` - - Environment variable name: `$BLOCK_CONFIRMATIONS` -- `--storageConcurrency` Maximum number of concurrent calls to Ethereum or IPFS - - Default value: `'200'` - - Environment variable name: `$STORAGE_MAX_CONCURRENCY` -- `--logLevel` The maximum level of messages we will log - - Environment variable name: `$LOG_LEVEL` - - Available levels: ERROR, WARN, INFO and DEBUG -- `--logMode` Defines the log format to use - - Environment variable name: `$LOG_MODE` - - Available modes: - - `human` is a more human readable log to display during development - - `machine` is better for parsing on CI or deployments -- `--persistTransactionTimeout` Defines the delay in seconds to wait before sending a timeout when creating or updating a request - - Default value: 600 - - Environment variable name: `$PERSIST_TRANSACTION_TIMEOUT` -- `--externalUrl` External url of the node (used to identified where the buffer data are stored before being broadcasted on ethereum) - - Environment variable name: `$EXTERNAL_URL` -- `--graphNodeUrl` External url of the Graph node, if any. If specified, this will replace the traditional data access with the Graph implementation. Default is undefined. See [TheGraph mode](#thegraph-mode). - - Environment variable name: `$GRAPH_NODE_URL` +| Option | Environment Variable | Description | Required | Default Value | +| -------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------ | ----------------------------------- | +| `--port` | `PORT` | Port for the server to listen for API requests | No | `3000` | +| `--networkId` | `ETHEREUM_NETWORK_ID` | Id of the Ethereum network used | No | `0` | +| `--providerUrl` | `WEB3_PROVIDER_URL` | URL of the web3 provider for Ethereum | No | `http://localhost:8545` | +| `--ipfsUrl` | `IPFS_URL` | URL of the IPFS gateway | No | `http://localhost:5001` | +| `--ipfsTimeout` | `IPFS_TIMEOUT` | Timeout threshold to connect to the IPFS gateway | No | `10000` | +| `--blockConfirmations` | `BLOCK_CONFIRMATIONS` | The number of block confirmations to consider a transaction successful | No | `2` | +| `--storageConcurrency` | `STORAGE_MAX_CONCURRENCY` | Maximum number of concurrent calls to Ethereum or IPFS | No | `200` | +| `--logLevel` | `LOG_LEVEL` | The maximum level of messages we will log (ERROR, WARN, INFO or DEBUG) | No | `INFO` | +| `--logMode` | `LOG_MODE` | The log format to use (human or machine) | No | `human` | +| `--persistTransactionTimeout` | `PERSIST_TRANSACTION_TIMEOUT` | Defines the delay in seconds to wait before sending a timeout when creating or updating a request | No | `600` | +| `--externalUrl` | `EXTERNAL_URL` | External url of the node (used to identify where the buffer data are stored) | No | - | +| `--graphNodeUrl` | `GRAPH_NODE_URL` | External url of the Graph node. See [TheGraph mode](#thegraph-mode) | No | - | +| `--thirdwebEngineUrl` | `THIRDWEB_ENGINE_URL` | URL of your Thirdweb Engine instance | **Yes** | - | +| `--thirdwebAccessToken` | `THIRDWEB_ACCESS_TOKEN` | Access token for Thirdweb Engine | **Yes** | - | +| `--thirdwebBackendWalletAddress` | `THIRDWEB_BACKEND_WALLET_ADDRESS` | Address of the wallet configured in Thirdweb Engine | **Yes** | - | +| `--thirdwebWebhookSecret` | `THIRDWEB_WEBHOOK_SECRET` | Secret for verifying webhook signatures | No | - | +| - | `MNEMONIC` | The mnemonic for generating the wallet private key | **Yes** (except on private networks) | `candy maple...` (only for testing) | #### Mnemonic @@ -336,6 +319,25 @@ yarn start Open a browser and navigate towards: http://localhost:3000/status You can see the details of your local Request & IPFS nodes. +## Thirdweb Engine Integration + +The Request Node uses Thirdweb Engine for transaction submission, which offers several advantages: + +- No need to manage private keys in the Request Node +- Better transaction management and monitoring +- Automated gas price optimization and retry mechanisms +- Webhook notifications for transaction status + +### Setting Up Thirdweb Engine + +1. Deploy Thirdweb Engine by following the [official documentation](https://portal.thirdweb.com/engine/getting-started) +2. Create a wallet in Thirdweb Engine for the Request Node +3. Ensure the wallet has sufficient funds for gas costs +4. Generate an access token with appropriate permissions +5. Configure the Request Node with the required environment variables (see Options table above) + +**Note:** The Request Node no longer supports transaction submission through local wallets. All transactions are processed through Thirdweb Engine. + ## Contributing Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. diff --git a/packages/request-node/src/config.ts b/packages/request-node/src/config.ts index 48640e077b..dc872c49eb 100644 --- a/packages/request-node/src/config.ts +++ b/packages/request-node/src/config.ts @@ -41,7 +41,6 @@ const defaultValues = { mode: LogMode.human, }, server: { - headers: '{}', port: 3000, }, wallet: { @@ -51,6 +50,12 @@ const defaultValues = { litProtocolRPC: 'https://yellowstone-rpc.litprotocol.com', litProtocolCapacityCreditsUsage: '1', litProtocolCapacityCreditsExpirationInSeconds: 10 * 60, // 10 minutes + thirdweb: { + engineUrl: '', + accessToken: '', + backendWalletAddress: '', + webhookSecret: '', + }, }; const getOption = ( @@ -83,6 +88,42 @@ export const getLitProtocolNetwork = makeOption( defaultValues.litProtocolNetwork, ); +/** + * Get Thirdweb Engine URL from command line argument, environment variables or default values + */ +export const getThirdwebEngineUrl = makeOption( + 'thirdwebEngineUrl', + 'THIRDWEB_ENGINE_URL', + defaultValues.thirdweb.engineUrl, +); + +/** + * Get Thirdweb Access Token from command line argument, environment variables or default values + */ +export const getThirdwebAccessToken = makeOption( + 'thirdwebAccessToken', + 'THIRDWEB_ACCESS_TOKEN', + defaultValues.thirdweb.accessToken, +); + +/** + * Get Thirdweb Backend Wallet Address from command line argument, environment variables or default values + */ +export const getThirdwebBackendWalletAddress = makeOption( + 'thirdwebBackendWalletAddress', + 'THIRDWEB_BACKEND_WALLET_ADDRESS', + defaultValues.thirdweb.backendWalletAddress, +); + +/** + * Get Thirdweb Webhook Secret from command line argument, environment variables or default values + */ +export const getThirdwebWebhookSecret = makeOption( + 'thirdwebWebhookSecret', + 'THIRDWEB_WEBHOOK_SECRET', + defaultValues.thirdweb.webhookSecret, +); + /** * Get the litProtocolNetwork from command line argument, environment variables or default values to send with the API responses */ @@ -240,9 +281,12 @@ export function getHelpMessage(): string { OPTIONS SERVER OPTIONS port (${defaultValues.server.port})\t\t\t\tPort for the server to listen for API requests - headers (${ - defaultValues.server.headers - })\t\t\t\tCustom headers to send with the API responses + + THIRDWEB ENGINE OPTIONS + thirdwebEngineUrl\t\t\t\tURL of your Thirdweb Engine instance (REQUIRED) + thirdwebAccessToken\t\t\t\tAccess token for Thirdweb Engine (REQUIRED) + thirdwebBackendWalletAddress\t\tAddress of the wallet configured in Thirdweb Engine (REQUIRED) + thirdwebWebhookSecret\t\t\tSecret for verifying webhook signatures (optional) THE GRAPH OPTIONS graphNodeUrl (${defaultValues.storage.thegraph.nodeUrl})\t\t\t\tURL of the Graph node @@ -280,13 +324,13 @@ export function getHelpMessage(): string { logMode (${defaultValues.log.mode})\t\t\tThe node log mode (human or machine) EXAMPLE - yarn start --port 5000 --networkId 1 + yarn start --port 5000 --networkId 1 --thirdwebEngineUrl=https://engine.thirdweb.io --thirdwebAccessToken=your_token --thirdwebBackendWalletAddress=0x123... - All options are optional, not specified options are read from environment variables - If the environment variable is not specified, default value is used + All options except Thirdweb Engine options are optional. Thirdweb Engine options are required and can be set via environment variables if not specified in command line. Default mnemonic is: ${defaultValues.wallet.mnemonic} + NOTE: This mnemonic should ONLY be used for testing on private networks. `; return message; @@ -306,5 +350,35 @@ export const getConfigDisplay = (): string => { Lit Protocol RPC: ${getLitProtocolRPC()} Lit Protocol Capacity Credits Uses: ${getLitProtocolCapacityCreditsUsage()} Lit Protocol Capacity Credits Expiration in seconds: ${getLitProtocolCapacityCreditsExpirationInSeconds()} + Thirdweb Engine URL: ${getThirdwebEngineUrl()} + Thirdweb Backend Wallet: ${getThirdwebBackendWalletAddress()} `; }; + +/** + * Check if all required Thirdweb configuration values are provided + * @throws Error if required configuration is missing + */ +export function validateThirdwebConfig(): void { + const engineUrl = getThirdwebEngineUrl(); + const accessToken = getThirdwebAccessToken(); + const backendWalletAddress = getThirdwebBackendWalletAddress(); + + if (!engineUrl) { + throw new Error( + 'Thirdweb Engine URL is required. Set THIRDWEB_ENGINE_URL environment variable or use --thirdwebEngineUrl option.', + ); + } + + if (!accessToken) { + throw new Error( + 'Thirdweb Access Token is required. Set THIRDWEB_ACCESS_TOKEN environment variable or use --thirdwebAccessToken option.', + ); + } + + if (!backendWalletAddress) { + throw new Error( + 'Thirdweb Backend Wallet Address is required. Set THIRDWEB_BACKEND_WALLET_ADDRESS environment variable or use --thirdwebBackendWalletAddress option.', + ); + } +} diff --git a/packages/request-node/src/dataAccess.ts b/packages/request-node/src/dataAccess.ts index 9f51609b41..ca93803239 100644 --- a/packages/request-node/src/dataAccess.ts +++ b/packages/request-node/src/dataAccess.ts @@ -1,49 +1,57 @@ -import { providers, Wallet } from 'ethers'; -import { NonceManager } from '@ethersproject/experimental'; -import { CurrencyTypes, DataAccessTypes, LogTypes, StorageTypes } from '@requestnetwork/types'; - -import * as config from './config'; import { TheGraphDataAccess } from '@requestnetwork/thegraph-data-access'; +import { EthereumStorage, ThirdwebTransactionSubmitter } from '@requestnetwork/ethereum-storage'; import { PendingStore } from '@requestnetwork/data-access'; -import { EthereumStorage, EthereumTransactionSubmitter } from '@requestnetwork/ethereum-storage'; +import { LogTypes, StorageTypes } from '@requestnetwork/types'; +import * as config from './config'; -export function getDataAccess( - network: CurrencyTypes.EvmChainName, +/** + * Creates and returns a data access instance + * @param network The Ethereum network to use + * @param ipfsStorage The IPFS storage instance + * @param logger Logger instance + * @param graphqlUrl GraphQL endpoint URL + * @param blockConfirmations Number of block confirmations to wait for + * @returns A data access instance + */ +export async function getDataAccess( + network: string, ipfsStorage: StorageTypes.IIpfsStorage, logger: LogTypes.ILogger, -): DataAccessTypes.IDataAccess { - const graphNodeUrl = config.getGraphNodeUrl(); + graphqlUrl: string, + blockConfirmations: number, +): Promise { + // Validate that all required Thirdweb config options are set + config.validateThirdwebConfig(); - const wallet = Wallet.fromMnemonic(config.getMnemonic()).connect( - new providers.StaticJsonRpcProvider(config.getStorageWeb3ProviderUrl()), - ); + logger.info('Using Thirdweb Engine for transaction submission'); - const signer = new NonceManager(wallet); - - const gasPriceMin = config.getGasPriceMin(); - const gasPriceMax = config.getGasPriceMax(); - const gasPriceMultiplier = config.getGasPriceMultiplier(); - const blockConfirmations = config.getBlockConfirmations(); - const txSubmitter = new EthereumTransactionSubmitter({ + // Create ThirdwebTransactionSubmitter + const txSubmitter = new ThirdwebTransactionSubmitter({ + engineUrl: config.getThirdwebEngineUrl(), + accessToken: config.getThirdwebAccessToken(), + backendWalletAddress: config.getThirdwebBackendWalletAddress(), network, logger, - gasPriceMin, - gasPriceMax, - gasPriceMultiplier, - signer, }); - const pendingStore = new PendingStore(); + + // Initialize the transaction submitter + await txSubmitter.initialize(); + + // Create Ethereum Storage with the transaction submitter const storage = new EthereumStorage({ ipfsStorage, txSubmitter, - logger, blockConfirmations, + logger, }); + + // Create and return TheGraphDataAccess return new TheGraphDataAccess({ - graphql: { url: graphNodeUrl }, + graphql: { + url: graphqlUrl, + }, storage, - network, + pendingStore: new PendingStore(), logger, - pendingStore, }); } diff --git a/packages/request-node/src/server.ts b/packages/request-node/src/server.ts index 2422492cfd..eaebecff15 100755 --- a/packages/request-node/src/server.ts +++ b/packages/request-node/src/server.ts @@ -8,6 +8,7 @@ import ConfirmedTransactionStore from './request/confirmedTransactionStore'; import { EvmChains } from '@requestnetwork/currency'; import { getEthereumStorageNetworkNameFromId } from '@requestnetwork/ethereum-storage'; import { SubgraphClient } from '@requestnetwork/thegraph-data-access'; +import { StorageTypes } from '@requestnetwork/types'; // Initialize the node logger const logger = new Logger(config.getLogLevel(), config.getLogMode()); @@ -21,10 +22,32 @@ const getNetwork = () => { return network; }; -export const getRequestNode = (): RequestNode => { +// Initialize the data access layer +async function initializeDataAccess(ipfsStorage: StorageTypes.IIpfsStorage) { + // Get configuration values const network = getNetwork(); - const storage = getDataStorage(logger); - const dataAccess = getDataAccess(network, storage, logger); + const graphqlUrl = config.getGraphNodeUrl(); + const blockConfirmations = config.getBlockConfirmations(); + + // Create data access with Thirdweb transaction submitter + const dataAccess = await getDataAccess( + network, + ipfsStorage, + logger, + graphqlUrl, + blockConfirmations, + ); + + return dataAccess; +} + +export const getRequestNode = async (): Promise => { + const network = getNetwork(); + const ipfsStorage = getDataStorage(logger); + await ipfsStorage.initialize(); + + // Use the initialized data access + const dataAccess = await initializeDataAccess(ipfsStorage); // we access the subgraph client directly, not through the data access, // because this feature is specific to RN use with Request Node. Without a node, @@ -34,12 +57,13 @@ export const getRequestNode = (): RequestNode => { network, ); - return new RequestNode(dataAccess, storage, confirmedTransactionStore, logger); + return new RequestNode(dataAccess, ipfsStorage, confirmedTransactionStore, logger); }; +// Main server setup export const startNode = async (): Promise => { const port = config.getServerPort(); - const requestNode = getRequestNode(); + const requestNode = await getRequestNode(); const server = withShutdown( requestNode.listen(port, () => { logger.info(`Listening on port ${port}`); From fd3bc45a40c8597059849aaeb91854661c0c490f Mon Sep 17 00:00:00 2001 From: MantisClone Date: Mon, 14 Apr 2025 16:29:10 -0400 Subject: [PATCH 3/5] fix: make object returned by submit() adhere to Ethers v5 interfaces * refactor: comments --- .../src/thirdweb/thirdweb-tx-submitter.ts | 121 +++++++++++++----- 1 file changed, 87 insertions(+), 34 deletions(-) diff --git a/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts b/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts index 3ebd41972f..81ba7ff06c 100644 --- a/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts +++ b/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts @@ -18,6 +18,7 @@ export interface ThirdwebSubmitterOptions { /** * The address of the wallet configured in Thirdweb Engine + * This is the wallet that will sign and send transactions */ backendWalletAddress: string; @@ -33,14 +34,18 @@ export interface ThirdwebSubmitterOptions { } /** - * Handles the submission of IPFS hashes through Thirdweb Engine + * Handles the submission of IPFS CID hashes using Thirdweb Engine. + * Thirdweb Engine manages transaction signing, fee estimation, and automatically + * handles retries for failed transactions. */ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSubmitter { private readonly logger: LogTypes.ILogger; private readonly engine: Engine; private readonly backendWalletAddress: string; - private _network: string; - private _hashSubmitterAddress: string; + + // Public variables instead of getters/setters + public network: string; + public hashSubmitterAddress: string; constructor({ engineUrl, @@ -55,31 +60,15 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu accessToken: accessToken, }); this.backendWalletAddress = backendWalletAddress; - this._network = network; + this.network = network; // Get the hash submitter address for the specified network - this._hashSubmitterAddress = requestHashSubmitterArtifact.getAddress(network); - } - - get network(): string { - return this._network; - } - - set network(value: string) { - this._network = value; - } - - get hashSubmitterAddress(): string { - return this._hashSubmitterAddress; - } - - set hashSubmitterAddress(value: string) { - this._hashSubmitterAddress = value; + this.hashSubmitterAddress = requestHashSubmitterArtifact.getAddress(network); } async initialize(): Promise { - const chainId = networkToChainId[this._network] || 1; + const chainId = networkToChainId[this.network] || 1; this.logger.info( - `Initializing ThirdwebTransactionSubmitter for network ${this._network} (chainId: ${chainId})`, + `Initializing ThirdwebTransactionSubmitter for network ${this.network} (chainId: ${chainId})`, ); // Check Engine connection @@ -93,12 +82,15 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu } /** - * Submits an IPFS hash via Thirdweb Engine + * Submits an IPFS CID hash via Thirdweb Engine + * @param ipfsHash - The IPFS CID hash to submit + * @param ipfsSize - The size of the data on IPFS + * @returns A transaction object compatible with ethers.js TransactionResponse interface */ async submit(ipfsHash: string, ipfsSize: number): Promise { - this.logger.info(`Submitting hash ${ipfsHash} with size ${ipfsSize} via Thirdweb Engine`); + this.logger.info(`Submitting IPFS CID ${ipfsHash} with size ${ipfsSize} via Thirdweb Engine`); const preparedTx = await this.prepareSubmit(ipfsHash, ipfsSize); - const chainId = networkToChainId[this._network] || 1; + const chainId = networkToChainId[this.network] || 1; try { const result = await this.engine.sendTransaction({ @@ -110,13 +102,71 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu }); this.logger.info(`Transaction submitted successfully: ${result.transactionHash}`); + + // Return a complete ethers.js TransactionResponse-compatible object for an EIP-1559 transaction return { + // Only available for mined transactions + blockHash: null, + blockNumber: null, + timestamp: Math.floor(Date.now() / 1000), + transactionIndex: null, + + // Transaction details hash: result.transactionHash, + from: this.backendWalletAddress, + chainId, + to: preparedTx.to, + nonce: 0, // Not available from Thirdweb Engine + gasLimit: BigNumber.from(2000000), + gasPrice: null, // Not used in EIP-1559 transactions + data: preparedTx.data, + value: preparedTx.value || BigNumber.from(0), + confirmations: 1, + + // EIP-1559 fields + maxPriorityFeePerGas: BigNumber.from(2000000000), // 2 Gwei tip + maxFeePerGas: BigNumber.from(50000000000), // 50 Gwei max fee + + // Transaction type (2: EIP-1559) + type: 2, + + // Signature components (not available) + r: '0x0000000000000000000000000000000000000000000000000000000000000000', + s: '0x0000000000000000000000000000000000000000000000000000000000000000', + v: 0, + + /** + * Returns a promise that resolves to a transaction receipt. + * + * This implements a "fire and forget" pattern - we submit the transaction + * to Thirdweb Engine and immediately assume success without waiting for + * or confirming that the transaction is actually mined. + * + * We don't use polling or webhook notifications to track transaction status. + * Thirdweb Engine handles retries and gas price adjustments internally. + * + * @returns A simplified TransactionReceipt compatible with ethers.js + */ wait: async () => { - // This function returns a promise that resolves when the transaction is mined - // Transaction status can be tracked either by polling the blockchain - // or by using webhook notifications from Thirdweb Engine - return { status: 1 }; + return { + // TransactionReceipt properties + transactionHash: result.transactionHash, + blockNumber: 0, + blockHash: '0x0000000000000000000000000000000000000000000000000000000000000000', + confirmations: 1, + status: 1, // 1 = success + from: this.backendWalletAddress, + to: preparedTx.to, + contractAddress: null, + transactionIndex: 0, + gasUsed: BigNumber.from(0), + cumulativeGasUsed: BigNumber.from(0), + effectiveGasPrice: BigNumber.from(0), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + type: 2, // EIP-1559 transaction type + }; }, }; } catch (error) { @@ -126,15 +176,18 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu } /** - * Prepares the transaction for submitting an IPFS hash + * Prepares the transaction for submitting an IPFS CID hash + * @param ipfsHash - The IPFS CID hash to submit + * @param ipfsSize - The size of the data on IPFS + * @returns A transaction request object compatible with ethers.js */ async prepareSubmit(ipfsHash: string, ipfsSize: number): Promise { // Create contract interface for the hash submitter const iface = requestHashSubmitterArtifact.getInterface(); - // Calculate fee - in a real implementation, you might want to fetch this from the contract - // For now, we assume it's 0 for simplicity - const fee = BigNumber.from(0); + // Get the fee from the contract + const hashSubmitter = requestHashSubmitterArtifact.connect(this.network); + const fee = await hashSubmitter.getFeesAmount(ipfsSize); // Encode function data const data = iface.encodeFunctionData('submitHash', [ From e759fc41652f66c73c38a2539e901e9be73935ee Mon Sep 17 00:00:00 2001 From: MantisClone Date: Tue, 15 Apr 2025 14:59:47 -0400 Subject: [PATCH 4/5] fix(ethereum-storage): build errors --- packages/ethereum-storage/package.json | 1 + .../src/thirdweb/thirdweb-tx-submitter.ts | 53 ++++++++++++------- .../ethereum-storage/src/thirdweb/types.ts | 16 +++--- .../test/thirdweb-tx-submitter.test.ts | 1 - packages/request-node/src/dataAccess.ts | 15 +++--- yarn.lock | 36 +++---------- 6 files changed, 58 insertions(+), 64 deletions(-) diff --git a/packages/ethereum-storage/package.json b/packages/ethereum-storage/package.json index bea62766f3..4c7566c6bb 100644 --- a/packages/ethereum-storage/package.json +++ b/packages/ethereum-storage/package.json @@ -44,6 +44,7 @@ "@requestnetwork/smart-contracts": "0.48.0", "@requestnetwork/types": "0.54.0", "@requestnetwork/utils": "0.54.0", + "@thirdweb-dev/engine": "0.0.19", "ethers": "5.7.2", "form-data": "3.0.0", "qs": "6.11.2", diff --git a/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts b/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts index 81ba7ff06c..f52dc2c9a5 100644 --- a/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts +++ b/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts @@ -1,9 +1,10 @@ -import { BigNumber, utils } from 'ethers'; +import { BigNumber, utils, providers } from 'ethers'; import { StorageTypes, LogTypes } from '@requestnetwork/types'; import { Engine } from '@thirdweb-dev/engine'; import { SimpleLogger } from '@requestnetwork/utils'; import { requestHashSubmitterArtifact } from '@requestnetwork/smart-contracts'; -import { networkToChainId } from './types'; +import type { CurrencyTypes } from '@requestnetwork/types'; +import { getChainId, networkToChainId } from './types'; export interface ThirdwebSubmitterOptions { /** @@ -23,14 +24,19 @@ export interface ThirdwebSubmitterOptions { backendWalletAddress: string; /** - * Network name (e.g. 'mainnet', 'goerli', etc.) + * Network name (e.g. 'gnosis', 'sepolia', etc.) */ - network: string; + network: CurrencyTypes.EvmChainName; /** * Optional logger instance */ logger?: LogTypes.ILogger; + + /** + * Optional RPC URL for the network. If not provided, will use default public RPC. + */ + rpcUrl?: string; } /** @@ -42,9 +48,10 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu private readonly logger: LogTypes.ILogger; private readonly engine: Engine; private readonly backendWalletAddress: string; + private readonly provider: providers.Provider; // Public variables instead of getters/setters - public network: string; + public network: CurrencyTypes.EvmChainName; public hashSubmitterAddress: string; constructor({ @@ -53,6 +60,7 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu backendWalletAddress, network, logger, + rpcUrl, }: ThirdwebSubmitterOptions) { this.logger = logger || new SimpleLogger(); this.engine = new Engine({ @@ -63,6 +71,11 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu this.network = network; // Get the hash submitter address for the specified network this.hashSubmitterAddress = requestHashSubmitterArtifact.getAddress(network); + + // Initialize provider with RPC URL if provided, otherwise use default network name + this.provider = rpcUrl + ? new providers.JsonRpcProvider(rpcUrl) + : providers.getDefaultProvider(network); } async initialize(): Promise { @@ -73,7 +86,7 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu // Check Engine connection try { - await this.engine.getWallets({}); + await this.engine.default.getOpenapiJson(); this.logger.info('Successfully connected to Thirdweb Engine'); } catch (error) { this.logger.error('Failed to connect to Thirdweb Engine', error); @@ -90,18 +103,20 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu async submit(ipfsHash: string, ipfsSize: number): Promise { this.logger.info(`Submitting IPFS CID ${ipfsHash} with size ${ipfsSize} via Thirdweb Engine`); const preparedTx = await this.prepareSubmit(ipfsHash, ipfsSize); - const chainId = networkToChainId[this.network] || 1; + const chainId = getChainId(this.network); try { - const result = await this.engine.sendTransaction({ - chainId: chainId, - fromAddress: this.backendWalletAddress, - toAddress: preparedTx.to, - data: preparedTx.data as string, - value: preparedTx.value ? preparedTx.value.toString() : '0', - }); + const result = await this.engine.backendWallet.sendTransaction( + chainId, + this.backendWalletAddress, + { + toAddress: preparedTx.to, + data: preparedTx.data, + value: preparedTx.value ? preparedTx.value.toString() : '0', + }, + ); - this.logger.info(`Transaction submitted successfully: ${result.transactionHash}`); + this.logger.info(`Transaction submitted. Queue ID: ${result.result.queueId}`); // Return a complete ethers.js TransactionResponse-compatible object for an EIP-1559 transaction return { @@ -112,7 +127,7 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu transactionIndex: null, // Transaction details - hash: result.transactionHash, + hash: '0x0000000000000000000000000000000000000000000000000000000000000000', from: this.backendWalletAddress, chainId, to: preparedTx.to, @@ -150,7 +165,7 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu wait: async () => { return { // TransactionReceipt properties - transactionHash: result.transactionHash, + transactionHash: '0x0000000000000000000000000000000000000000000000000000000000000000', blockNumber: 0, blockHash: '0x0000000000000000000000000000000000000000000000000000000000000000', confirmations: 1, @@ -185,8 +200,8 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu // Create contract interface for the hash submitter const iface = requestHashSubmitterArtifact.getInterface(); - // Get the fee from the contract - const hashSubmitter = requestHashSubmitterArtifact.connect(this.network); + // Get the fee from the contract - now using provider + const hashSubmitter = requestHashSubmitterArtifact.connect(this.network, this.provider); const fee = await hashSubmitter.getFeesAmount(ipfsSize); // Encode function data diff --git a/packages/ethereum-storage/src/thirdweb/types.ts b/packages/ethereum-storage/src/thirdweb/types.ts index 24022cdf81..3b2a1a1928 100644 --- a/packages/ethereum-storage/src/thirdweb/types.ts +++ b/packages/ethereum-storage/src/thirdweb/types.ts @@ -31,12 +31,12 @@ export interface ThirdwebEngineConfig { /** * Chain ID mapping for common networks */ -export const networkToChainId: Record = { - mainnet: 1, - goerli: 5, - sepolia: 11155111, - xdai: 100, - private: 1337, +export const networkToChainId: Record = { + mainnet: '1', + goerli: '5', + sepolia: '11155111', + xdai: '100', + private: '1337', }; /** @@ -44,6 +44,6 @@ export const networkToChainId: Record = { * @param network Network name * @returns Chain ID */ -export function getChainId(network: string): number { - return networkToChainId[network] || 1; +export function getChainId(network: string): string { + return networkToChainId[network] || '1'; } diff --git a/packages/ethereum-storage/test/thirdweb-tx-submitter.test.ts b/packages/ethereum-storage/test/thirdweb-tx-submitter.test.ts index adfdd643d7..09683648e4 100644 --- a/packages/ethereum-storage/test/thirdweb-tx-submitter.test.ts +++ b/packages/ethereum-storage/test/thirdweb-tx-submitter.test.ts @@ -2,7 +2,6 @@ import { ThirdwebTransactionSubmitter } from '../src/thirdweb/thirdweb-tx-submit import { Engine } from '@thirdweb-dev/engine'; import { LogTypes } from '@requestnetwork/types'; import { requestHashSubmitterArtifact } from '@requestnetwork/smart-contracts'; -import { networkToChainId } from '../src/thirdweb/types'; // Mock the Thirdweb Engine jest.mock('@thirdweb-dev/engine', () => { diff --git a/packages/request-node/src/dataAccess.ts b/packages/request-node/src/dataAccess.ts index ca93803239..c65a0bee9c 100644 --- a/packages/request-node/src/dataAccess.ts +++ b/packages/request-node/src/dataAccess.ts @@ -1,7 +1,7 @@ import { TheGraphDataAccess } from '@requestnetwork/thegraph-data-access'; import { EthereumStorage, ThirdwebTransactionSubmitter } from '@requestnetwork/ethereum-storage'; import { PendingStore } from '@requestnetwork/data-access'; -import { LogTypes, StorageTypes } from '@requestnetwork/types'; +import { CurrencyTypes, LogTypes, StorageTypes } from '@requestnetwork/types'; import * as config from './config'; /** @@ -9,15 +9,15 @@ import * as config from './config'; * @param network The Ethereum network to use * @param ipfsStorage The IPFS storage instance * @param logger Logger instance - * @param graphqlUrl GraphQL endpoint URL + * @param graphNodeUrl Graph Node endpoint URL * @param blockConfirmations Number of block confirmations to wait for * @returns A data access instance */ export async function getDataAccess( - network: string, + network: CurrencyTypes.EvmChainName, ipfsStorage: StorageTypes.IIpfsStorage, logger: LogTypes.ILogger, - graphqlUrl: string, + graphNodeUrl: string, blockConfirmations: number, ): Promise { // Validate that all required Thirdweb config options are set @@ -47,11 +47,10 @@ export async function getDataAccess( // Create and return TheGraphDataAccess return new TheGraphDataAccess({ - graphql: { - url: graphqlUrl, - }, + graphql: { url: graphNodeUrl }, storage, - pendingStore: new PendingStore(), + network, logger, + pendingStore: new PendingStore(), }); } diff --git a/yarn.lock b/yarn.lock index 445b3f98d6..d1f126975d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6345,6 +6345,11 @@ dependencies: defer-to-connect "^2.0.1" +"@thirdweb-dev/engine@0.0.19": + version "0.0.19" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/engine/-/engine-0.0.19.tgz#d875faf82862d30aa9741abb8ac3d6c74354a304" + integrity sha512-Gseb0+enmAWnc6T2zX6TnpAy/HP29J5HHOilpKQJ26DI2O+ivQ/m1YrYrIKoye+MIhSAVB5ItQNKxbvuhizVVQ== + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz" @@ -23650,7 +23655,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -23668,15 +23673,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz" @@ -23811,7 +23807,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -23846,13 +23842,6 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" @@ -27046,7 +27035,7 @@ workerpool@6.2.1: resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -27081,15 +27070,6 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" From 2df637e18abd5f5143d1ca96b120f47d6918c9b4 Mon Sep 17 00:00:00 2001 From: MantisClone Date: Tue, 15 Apr 2025 17:02:17 -0400 Subject: [PATCH 5/5] fix: build errors --- .../src/thirdweb/thirdweb-tx-submitter.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts b/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts index f52dc2c9a5..3989ed1782 100644 --- a/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts +++ b/packages/ethereum-storage/src/thirdweb/thirdweb-tx-submitter.ts @@ -4,7 +4,7 @@ import { Engine } from '@thirdweb-dev/engine'; import { SimpleLogger } from '@requestnetwork/utils'; import { requestHashSubmitterArtifact } from '@requestnetwork/smart-contracts'; import type { CurrencyTypes } from '@requestnetwork/types'; -import { getChainId, networkToChainId } from './types'; +import { getChainId } from './types'; export interface ThirdwebSubmitterOptions { /** @@ -79,18 +79,17 @@ export class ThirdwebTransactionSubmitter implements StorageTypes.ITransactionSu } async initialize(): Promise { - const chainId = networkToChainId[this.network] || 1; + const chainId = getChainId(this.network); this.logger.info( `Initializing ThirdwebTransactionSubmitter for network ${this.network} (chainId: ${chainId})`, ); // Check Engine connection try { - await this.engine.default.getOpenapiJson(); + await this.engine.backendWallet.getBalance(chainId, this.backendWalletAddress); this.logger.info('Successfully connected to Thirdweb Engine'); } catch (error) { - this.logger.error('Failed to connect to Thirdweb Engine', error); - throw new Error('Failed to connect to Thirdweb Engine'); + throw new Error(`Failed to connect to Thirdweb Engine due to error: ${error}`); } }