From 318e05908a996ae86dc5b41fdd97fd9f7036ac1a Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Sat, 8 Feb 2025 22:39:32 -0800 Subject: [PATCH 01/12] added e2e test for transaction receipt & new schemas from cdp-service --- src/client/api.ts | 912 ++++++++++++++++++++++++++++++++++++ src/client/configuration.ts | 8 +- src/tests/e2e.ts | 468 ++++++++++-------- 3 files changed, 1180 insertions(+), 208 deletions(-) diff --git a/src/client/api.ts b/src/client/api.ts index da0e706f..a5efab5b 100644 --- a/src/client/api.ts +++ b/src/client/api.ts @@ -417,6 +417,19 @@ export interface BroadcastTransferRequest { */ 'signed_payload': string; } +/** + * + * @export + * @interface BroadcastUserOperationRequest + */ +export interface BroadcastUserOperationRequest { + /** + * The hex-encoded signature of the user operation. + * @type {string} + * @memberof BroadcastUserOperationRequest + */ + 'signature': string; +} /** * * @export @@ -454,6 +467,31 @@ export interface BuildStakingOperationRequest { */ 'options': { [key: string]: string; }; } +/** + * An action that will be bundled into a user operation. + * @export + * @interface Call + */ +export interface Call { + /** + * The address the call is interacting with. + * @type {string} + * @memberof Call + */ + 'to': string; + /** + * The hex-encoded data to send with the call. + * @type {string} + * @memberof Call + */ + 'data': string; + /** + * The string-encoded integer value to send with the call. + * @type {string} + * @memberof Call + */ + 'value': string; +} /** * * @export @@ -938,6 +976,19 @@ export interface CreateSmartContractRequest { } +/** + * + * @export + * @interface CreateSmartWalletRequest + */ +export interface CreateSmartWalletRequest { + /** + * The address of the owner of the smart wallet. + * @type {string} + * @memberof CreateSmartWalletRequest + */ + 'owner': string; +} /** * * @export @@ -1037,6 +1088,19 @@ export interface CreateTransferRequest { */ 'skip_batching'?: boolean; } +/** + * + * @export + * @interface CreateUserOperationRequest + */ +export interface CreateUserOperationRequest { + /** + * The list of calls to make from the smart wallet. + * @type {Array} + * @memberof CreateUserOperationRequest + */ + 'calls': Array; +} /** * * @export @@ -1506,6 +1570,12 @@ export interface EthereumTransaction { * @memberof EthereumTransaction */ 'rlp_encoded_tx'?: string; + /** + * + * @type {TransactionReceipt} + * @memberof EthereumTransaction + */ + 'receipt'?: TransactionReceipt; } /** * @@ -3043,6 +3113,56 @@ export const SmartContractType = { export type SmartContractType = typeof SmartContractType[keyof typeof SmartContractType]; +/** + * + * @export + * @interface SmartWallet + */ +export interface SmartWallet { + /** + * The onchain address of the smart wallet. + * @type {string} + * @memberof SmartWallet + */ + 'address': string; + /** + * The list of owner addresses for the smart wallet. + * @type {Array} + * @memberof SmartWallet + */ + 'owners': Array; +} +/** + * Paginated list of smart wallets + * @export + * @interface SmartWalletList + */ +export interface SmartWalletList { + /** + * + * @type {Array} + * @memberof SmartWalletList + */ + 'data': Array; + /** + * True if this list has another page of items after this one that can be fetched. + * @type {boolean} + * @memberof SmartWalletList + */ + 'has_more': boolean; + /** + * The page token to be used to fetch the next page. + * @type {string} + * @memberof SmartWalletList + */ + 'next_page': string; + /** + * The total number of wallets + * @type {number} + * @memberof SmartWalletList + */ + 'total_count': number; +} /** * * @export @@ -3261,6 +3381,12 @@ export interface StakingContextContext { * @memberof StakingContextContext */ 'unstakeable_balance': Balance; + /** + * + * @type {Balance} + * @memberof StakingContextContext + */ + 'pending_claimable_balance': Balance; /** * * @type {Balance} @@ -3653,6 +3779,140 @@ export type TransactionStatusEnum = typeof TransactionStatusEnum[keyof typeof Tr */ export type TransactionContent = EthereumTransaction; +/** + * A log emitted from an onchain transaction. + * @export + * @interface TransactionLog + */ +export interface TransactionLog { + /** + * An onchain address of a contract. + * @type {string} + * @memberof TransactionLog + */ + 'address': string; + /** + * + * @type {Array} + * @memberof TransactionLog + */ + 'topics': Array; + /** + * The data included in this log. + * @type {string} + * @memberof TransactionLog + */ + 'data': string; +} +/** + * The receipt of an onchain transaction\'s execution. + * @export + * @interface TransactionReceipt + */ +export interface TransactionReceipt { + /** + * The address this transaction is to. This is null if the transaction was an init transaction, used to deploy a contract. + * @type {string} + * @memberof TransactionReceipt + */ + 'to'?: string; + /** + * The address this transaction is from. + * @type {string} + * @memberof TransactionReceipt + */ + 'from'?: string; + /** + * The EVM address of the smart contract. If this transaction has a null to address, it is an init transaction used to deploy a contract, in which case this is the address created by that contract. + * @type {string} + * @memberof TransactionReceipt + */ + 'contract_address'?: string; + /** + * The index of this transaction in the list of transactions included in the block this transaction was mined in. + * @type {number} + * @memberof TransactionReceipt + */ + 'transaction_index'?: number; + /** + * The EIP-2718 transaction type. See https://eips.ethereum.org/EIPS/eip-2718 for more details. + * @type {number} + * @memberof TransactionReceipt + */ + 'type'?: number; + /** + * A bloom-filter, which includes all the addresses and topics included in any log in this transaction. + * @type {string} + * @memberof TransactionReceipt + */ + 'logs_bloom'?: string; + /** + * The hash of the block at which the transaction was recorded. + * @type {string} + * @memberof TransactionReceipt + */ + 'block_hash'?: string; + /** + * The hash of the onchain sponsored send transaction. + * @type {string} + * @memberof TransactionReceipt + */ + 'transaction_hash'?: string; + /** + * The block height (number) of the block that this transaction was included in. + * @type {number} + * @memberof TransactionReceipt + */ + 'block_number'?: number; + /** + * The number of blocks that have been mined since this transaction, including the actual block it was mined in. + * @type {number} + * @memberof TransactionReceipt + */ + 'confirmations'?: number; + /** + * The intermediate state root of a receipt. + * @type {string} + * @memberof TransactionReceipt + */ + 'root'?: string; + /** + * For the block this transaction was included in, this is the sum of the gas used by each transaction in the ordered list of transactions up to (and including) this transaction. + * @type {number} + * @memberof TransactionReceipt + */ + 'cumulative_gas_used'?: number; + /** + * This is true if the block is in a post-Byzantium Hard Fork block. + * @type {boolean} + * @memberof TransactionReceipt + */ + 'byzantium'?: boolean; + /** + * The status of a transaction is 1 if successful or 0 if it was reverted. + * @type {number} + * @memberof TransactionReceipt + */ + 'status': number; + /** + * + * @type {Array} + * @memberof TransactionReceipt + */ + 'logs': Array; + /** + * The amount of gas actually used by this transaction. + * @type {string} + * @memberof TransactionReceipt + */ + 'gas_used'?: string; + /** + * The effective gas price the transaction was charged at. + * @type {string} + * @memberof TransactionReceipt + */ + 'effective_gas_price'?: string; +} /** * * @export @@ -3870,6 +4130,60 @@ export interface User { */ 'display_name'?: string; } +/** + * + * @export + * @interface UserOperation + */ +export interface UserOperation { + /** + * The ID of the user operation. + * @type {string} + * @memberof UserOperation + */ + 'id': string; + /** + * The ID of the network the user operation is being created on. + * @type {string} + * @memberof UserOperation + */ + 'network_id': string; + /** + * The list of calls to make from the smart wallet. + * @type {Array} + * @memberof UserOperation + */ + 'calls': Array; + /** + * The hex-encoded hash that must be signed by the user. + * @type {string} + * @memberof UserOperation + */ + 'unsigned_payload': string; + /** + * The hex-encoded signature of the user operation. + * @type {string} + * @memberof UserOperation + */ + 'signature'?: string; + /** + * The status of the user operation. + * @type {string} + * @memberof UserOperation + */ + 'status'?: UserOperationStatusEnum; +} + +export const UserOperationStatusEnum = { + Pending: 'pending', + Signed: 'signed', + Broadcast: 'broadcast', + Complete: 'complete', + Failed: 'failed' +} as const; + +export type UserOperationStatusEnum = typeof UserOperationStatusEnum[keyof typeof UserOperationStatusEnum]; + /** * A validator onchain. * @export @@ -9716,6 +10030,604 @@ export class SmartContractsApi extends BaseAPI implements SmartContractsApiInter +/** + * SmartWalletsApi - axios parameter creator + * @export + */ +export const SmartWalletsApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * Broadcast a user operation + * @summary Broadcast a user operation + * @param {string} smartWalletAddress The address of the smart wallet to broadcast the user operation from. + * @param {string} userOperationId The ID of the user operation to broadcast. + * @param {BroadcastUserOperationRequest} [broadcastUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + broadcastUserOperation: async (smartWalletAddress: string, userOperationId: string, broadcastUserOperationRequest?: BroadcastUserOperationRequest, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'smartWalletAddress' is not null or undefined + assertParamExists('broadcastUserOperation', 'smartWalletAddress', smartWalletAddress) + // verify required parameter 'userOperationId' is not null or undefined + assertParamExists('broadcastUserOperation', 'userOperationId', userOperationId) + const localVarPath = `/v1/smart_wallets/{smart_wallet_address}/user_operations/{user_operation_id}/broadcast` + .replace(`{${"smart_wallet_address"}}`, encodeURIComponent(String(smartWalletAddress))) + .replace(`{${"user_operation_id"}}`, encodeURIComponent(String(userOperationId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication apiKey required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(broadcastUserOperationRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Create a new smart wallet, not scoped to a given network. + * @summary Create a new smart wallet + * @param {CreateSmartWalletRequest} [createSmartWalletRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createSmartWallet: async (createSmartWalletRequest?: CreateSmartWalletRequest, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/v1/smart_wallets`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication apiKey required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(createSmartWalletRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Create a new user operation on a smart wallet. + * @summary Create a new user operation + * @param {string} smartWalletAddress The address of the smart wallet to create the user operation on. + * @param {string} networkId The ID of the network to create the user operation on. + * @param {CreateUserOperationRequest} [createUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createUserOperation: async (smartWalletAddress: string, networkId: string, createUserOperationRequest?: CreateUserOperationRequest, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'smartWalletAddress' is not null or undefined + assertParamExists('createUserOperation', 'smartWalletAddress', smartWalletAddress) + // verify required parameter 'networkId' is not null or undefined + assertParamExists('createUserOperation', 'networkId', networkId) + const localVarPath = `/v1/smart_wallets/{smart_wallet_address}/networks/{network_id}/user_operations` + .replace(`{${"smart_wallet_address"}}`, encodeURIComponent(String(smartWalletAddress))) + .replace(`{${"network_id"}}`, encodeURIComponent(String(networkId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication apiKey required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(createUserOperationRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Get smart wallet + * @summary Get smart wallet by address + * @param {string} smartWalletAddress The address of that smart wallet to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getSmartWallet: async (smartWalletAddress: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'smartWalletAddress' is not null or undefined + assertParamExists('getSmartWallet', 'smartWalletAddress', smartWalletAddress) + const localVarPath = `/v1/smart_wallets/{smart_wallet_address}` + .replace(`{${"smart_wallet_address"}}`, encodeURIComponent(String(smartWalletAddress))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication apiKey required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + // authentication session required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Get user operation + * @summary Get user operation + * @param {string} smartWalletAddress The address of the smart wallet the user operation belongs to. + * @param {string} userOperationId The ID of the user operation to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getUserOperation: async (smartWalletAddress: string, userOperationId: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'smartWalletAddress' is not null or undefined + assertParamExists('getUserOperation', 'smartWalletAddress', smartWalletAddress) + // verify required parameter 'userOperationId' is not null or undefined + assertParamExists('getUserOperation', 'userOperationId', userOperationId) + const localVarPath = `/v1/smart_wallets/{smart_wallet_address}/user_operations/{user_operation_id}` + .replace(`{${"smart_wallet_address"}}`, encodeURIComponent(String(smartWalletAddress))) + .replace(`{${"user_operation_id"}}`, encodeURIComponent(String(userOperationId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication apiKey required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + // authentication session required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * List smart wallets + * @summary List smart wallets + * @param {number} [limit] A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + * @param {string} [page] A cursor for pagination across multiple pages of results. Don\'t include this parameter on the first call. Use the next_page value returned in a previous response to request subsequent results. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listSmartWallets: async (limit?: number, page?: string, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/v1/smart_wallets`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication apiKey required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + // authentication session required + await setApiKeyToObject(localVarHeaderParameter, "Jwt", configuration) + + if (limit !== undefined) { + localVarQueryParameter['limit'] = limit; + } + + if (page !== undefined) { + localVarQueryParameter['page'] = page; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * SmartWalletsApi - functional programming interface + * @export + */ +export const SmartWalletsApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = SmartWalletsApiAxiosParamCreator(configuration) + return { + /** + * Broadcast a user operation + * @summary Broadcast a user operation + * @param {string} smartWalletAddress The address of the smart wallet to broadcast the user operation from. + * @param {string} userOperationId The ID of the user operation to broadcast. + * @param {BroadcastUserOperationRequest} [broadcastUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async broadcastUserOperation(smartWalletAddress: string, userOperationId: string, broadcastUserOperationRequest?: BroadcastUserOperationRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.broadcastUserOperation(smartWalletAddress, userOperationId, broadcastUserOperationRequest, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['SmartWalletsApi.broadcastUserOperation']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Create a new smart wallet, not scoped to a given network. + * @summary Create a new smart wallet + * @param {CreateSmartWalletRequest} [createSmartWalletRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createSmartWallet(createSmartWalletRequest?: CreateSmartWalletRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createSmartWallet(createSmartWalletRequest, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['SmartWalletsApi.createSmartWallet']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Create a new user operation on a smart wallet. + * @summary Create a new user operation + * @param {string} smartWalletAddress The address of the smart wallet to create the user operation on. + * @param {string} networkId The ID of the network to create the user operation on. + * @param {CreateUserOperationRequest} [createUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createUserOperation(smartWalletAddress: string, networkId: string, createUserOperationRequest?: CreateUserOperationRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createUserOperation(smartWalletAddress, networkId, createUserOperationRequest, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['SmartWalletsApi.createUserOperation']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Get smart wallet + * @summary Get smart wallet by address + * @param {string} smartWalletAddress The address of that smart wallet to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getSmartWallet(smartWalletAddress: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getSmartWallet(smartWalletAddress, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['SmartWalletsApi.getSmartWallet']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Get user operation + * @summary Get user operation + * @param {string} smartWalletAddress The address of the smart wallet the user operation belongs to. + * @param {string} userOperationId The ID of the user operation to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getUserOperation(smartWalletAddress: string, userOperationId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getUserOperation(smartWalletAddress, userOperationId, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['SmartWalletsApi.getUserOperation']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * List smart wallets + * @summary List smart wallets + * @param {number} [limit] A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + * @param {string} [page] A cursor for pagination across multiple pages of results. Don\'t include this parameter on the first call. Use the next_page value returned in a previous response to request subsequent results. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listSmartWallets(limit?: number, page?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listSmartWallets(limit, page, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['SmartWalletsApi.listSmartWallets']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + } +}; + +/** + * SmartWalletsApi - factory interface + * @export + */ +export const SmartWalletsApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = SmartWalletsApiFp(configuration) + return { + /** + * Broadcast a user operation + * @summary Broadcast a user operation + * @param {string} smartWalletAddress The address of the smart wallet to broadcast the user operation from. + * @param {string} userOperationId The ID of the user operation to broadcast. + * @param {BroadcastUserOperationRequest} [broadcastUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + broadcastUserOperation(smartWalletAddress: string, userOperationId: string, broadcastUserOperationRequest?: BroadcastUserOperationRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.broadcastUserOperation(smartWalletAddress, userOperationId, broadcastUserOperationRequest, options).then((request) => request(axios, basePath)); + }, + /** + * Create a new smart wallet, not scoped to a given network. + * @summary Create a new smart wallet + * @param {CreateSmartWalletRequest} [createSmartWalletRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createSmartWallet(createSmartWalletRequest?: CreateSmartWalletRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.createSmartWallet(createSmartWalletRequest, options).then((request) => request(axios, basePath)); + }, + /** + * Create a new user operation on a smart wallet. + * @summary Create a new user operation + * @param {string} smartWalletAddress The address of the smart wallet to create the user operation on. + * @param {string} networkId The ID of the network to create the user operation on. + * @param {CreateUserOperationRequest} [createUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createUserOperation(smartWalletAddress: string, networkId: string, createUserOperationRequest?: CreateUserOperationRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.createUserOperation(smartWalletAddress, networkId, createUserOperationRequest, options).then((request) => request(axios, basePath)); + }, + /** + * Get smart wallet + * @summary Get smart wallet by address + * @param {string} smartWalletAddress The address of that smart wallet to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getSmartWallet(smartWalletAddress: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getSmartWallet(smartWalletAddress, options).then((request) => request(axios, basePath)); + }, + /** + * Get user operation + * @summary Get user operation + * @param {string} smartWalletAddress The address of the smart wallet the user operation belongs to. + * @param {string} userOperationId The ID of the user operation to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getUserOperation(smartWalletAddress: string, userOperationId: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getUserOperation(smartWalletAddress, userOperationId, options).then((request) => request(axios, basePath)); + }, + /** + * List smart wallets + * @summary List smart wallets + * @param {number} [limit] A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + * @param {string} [page] A cursor for pagination across multiple pages of results. Don\'t include this parameter on the first call. Use the next_page value returned in a previous response to request subsequent results. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listSmartWallets(limit?: number, page?: string, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.listSmartWallets(limit, page, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * SmartWalletsApi - interface + * @export + * @interface SmartWalletsApi + */ +export interface SmartWalletsApiInterface { + /** + * Broadcast a user operation + * @summary Broadcast a user operation + * @param {string} smartWalletAddress The address of the smart wallet to broadcast the user operation from. + * @param {string} userOperationId The ID of the user operation to broadcast. + * @param {BroadcastUserOperationRequest} [broadcastUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApiInterface + */ + broadcastUserOperation(smartWalletAddress: string, userOperationId: string, broadcastUserOperationRequest?: BroadcastUserOperationRequest, options?: RawAxiosRequestConfig): AxiosPromise; + + /** + * Create a new smart wallet, not scoped to a given network. + * @summary Create a new smart wallet + * @param {CreateSmartWalletRequest} [createSmartWalletRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApiInterface + */ + createSmartWallet(createSmartWalletRequest?: CreateSmartWalletRequest, options?: RawAxiosRequestConfig): AxiosPromise; + + /** + * Create a new user operation on a smart wallet. + * @summary Create a new user operation + * @param {string} smartWalletAddress The address of the smart wallet to create the user operation on. + * @param {string} networkId The ID of the network to create the user operation on. + * @param {CreateUserOperationRequest} [createUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApiInterface + */ + createUserOperation(smartWalletAddress: string, networkId: string, createUserOperationRequest?: CreateUserOperationRequest, options?: RawAxiosRequestConfig): AxiosPromise; + + /** + * Get smart wallet + * @summary Get smart wallet by address + * @param {string} smartWalletAddress The address of that smart wallet to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApiInterface + */ + getSmartWallet(smartWalletAddress: string, options?: RawAxiosRequestConfig): AxiosPromise; + + /** + * Get user operation + * @summary Get user operation + * @param {string} smartWalletAddress The address of the smart wallet the user operation belongs to. + * @param {string} userOperationId The ID of the user operation to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApiInterface + */ + getUserOperation(smartWalletAddress: string, userOperationId: string, options?: RawAxiosRequestConfig): AxiosPromise; + + /** + * List smart wallets + * @summary List smart wallets + * @param {number} [limit] A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + * @param {string} [page] A cursor for pagination across multiple pages of results. Don\'t include this parameter on the first call. Use the next_page value returned in a previous response to request subsequent results. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApiInterface + */ + listSmartWallets(limit?: number, page?: string, options?: RawAxiosRequestConfig): AxiosPromise; + +} + +/** + * SmartWalletsApi - object-oriented interface + * @export + * @class SmartWalletsApi + * @extends {BaseAPI} + */ +export class SmartWalletsApi extends BaseAPI implements SmartWalletsApiInterface { + /** + * Broadcast a user operation + * @summary Broadcast a user operation + * @param {string} smartWalletAddress The address of the smart wallet to broadcast the user operation from. + * @param {string} userOperationId The ID of the user operation to broadcast. + * @param {BroadcastUserOperationRequest} [broadcastUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApi + */ + public broadcastUserOperation(smartWalletAddress: string, userOperationId: string, broadcastUserOperationRequest?: BroadcastUserOperationRequest, options?: RawAxiosRequestConfig) { + return SmartWalletsApiFp(this.configuration).broadcastUserOperation(smartWalletAddress, userOperationId, broadcastUserOperationRequest, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Create a new smart wallet, not scoped to a given network. + * @summary Create a new smart wallet + * @param {CreateSmartWalletRequest} [createSmartWalletRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApi + */ + public createSmartWallet(createSmartWalletRequest?: CreateSmartWalletRequest, options?: RawAxiosRequestConfig) { + return SmartWalletsApiFp(this.configuration).createSmartWallet(createSmartWalletRequest, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Create a new user operation on a smart wallet. + * @summary Create a new user operation + * @param {string} smartWalletAddress The address of the smart wallet to create the user operation on. + * @param {string} networkId The ID of the network to create the user operation on. + * @param {CreateUserOperationRequest} [createUserOperationRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApi + */ + public createUserOperation(smartWalletAddress: string, networkId: string, createUserOperationRequest?: CreateUserOperationRequest, options?: RawAxiosRequestConfig) { + return SmartWalletsApiFp(this.configuration).createUserOperation(smartWalletAddress, networkId, createUserOperationRequest, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Get smart wallet + * @summary Get smart wallet by address + * @param {string} smartWalletAddress The address of that smart wallet to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApi + */ + public getSmartWallet(smartWalletAddress: string, options?: RawAxiosRequestConfig) { + return SmartWalletsApiFp(this.configuration).getSmartWallet(smartWalletAddress, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Get user operation + * @summary Get user operation + * @param {string} smartWalletAddress The address of the smart wallet the user operation belongs to. + * @param {string} userOperationId The ID of the user operation to fetch. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApi + */ + public getUserOperation(smartWalletAddress: string, userOperationId: string, options?: RawAxiosRequestConfig) { + return SmartWalletsApiFp(this.configuration).getUserOperation(smartWalletAddress, userOperationId, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * List smart wallets + * @summary List smart wallets + * @param {number} [limit] A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + * @param {string} [page] A cursor for pagination across multiple pages of results. Don\'t include this parameter on the first call. Use the next_page value returned in a previous response to request subsequent results. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof SmartWalletsApi + */ + public listSmartWallets(limit?: number, page?: string, options?: RawAxiosRequestConfig) { + return SmartWalletsApiFp(this.configuration).listSmartWallets(limit, page, options).then((request) => request(this.axios, this.basePath)); + } +} + + + /** * StakeApi - axios parameter creator * @export diff --git a/src/client/configuration.ts b/src/client/configuration.ts index 1fc8a134..a1a0c93e 100644 --- a/src/client/configuration.ts +++ b/src/client/configuration.ts @@ -89,7 +89,13 @@ export class Configuration { this.accessToken = param.accessToken; this.basePath = param.basePath; this.serverIndex = param.serverIndex; - this.baseOptions = param.baseOptions; + this.baseOptions = { + headers: { + ...param.baseOptions?.headers, + 'User-Agent': "OpenAPI-Generator/typescript-axios" + }, + ...param.baseOptions + }; this.formDataCtor = param.formDataCtor; } diff --git a/src/tests/e2e.ts b/src/tests/e2e.ts index 18f32647..fd5eaea2 100644 --- a/src/tests/e2e.ts +++ b/src/tests/e2e.ts @@ -151,6 +151,60 @@ describe("Coinbase SDK E2E Test", () => { }); }, 60000); + it.only("Should be able to invoke a contract and retrieve the transaction receipt", async() => { + const seedFile = JSON.parse(process.env.WALLET_DATA || ""); + const walletId = Object.keys(seedFile)[0]; + const seed = seedFile[walletId].seed; + + const importedWallet = await Wallet.import({ + seed, + walletId, + networkId: Coinbase.networks.BaseSepolia, + }); + + const faucetTransaction = await importedWallet.faucet(Coinbase.assets.Usdc); + await faucetTransaction.wait(); + + const secondWallet = await Wallet.create(); + const secondWalletAddress = (await secondWallet.getDefaultAddress()).getId(); + + const transferArgs = { + to: secondWalletAddress, + value: "1" + } + + const contractInvocation = await importedWallet.invokeContract({ + contractAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + method: "transfer", + args: transferArgs, + }); + + await contractInvocation.wait(); + + const transactionContent = contractInvocation.getTransaction().content(); + console.log(transactionContent) + console.log(transactionContent!.receipt); + + const receipt = transactionContent!.receipt; + + expect(receipt).toBeDefined(); + expect(receipt!.logs).toBeDefined(); + + const logs = receipt!.logs; + + expect(logs).toBeDefined(); + expect(logs.length).toEqual(1); + + const log = logs[0]; + expect(log.address).toEqual("0x036CbD53842c5426634e7929541eC2318f3dCF7e"); + expect(log.topics[0]).toEqual("Transfer"); + expect(log.topics[1]).toEqual(`from: ${(await importedWallet.getDefaultAddress()).getId()}`); + expect(log.topics[2]).toEqual(`to: ${(await secondWallet.getDefaultAddress()).getId()}`); + expect(log.data).toEqual("0x0000000000000000000000000000000000000000000000000000000000000001"); + }, 60000); + + + it.skip("should be able to make gasless transfers", async () => { // Import wallet with balance const seedFile = JSON.parse(process.env.WALLET_DATA || ""); @@ -178,7 +232,7 @@ describe("Coinbase SDK E2E Test", () => { }); await transfer.wait(); - await new Promise(resolve => setTimeout(resolve, 60000)); + await new Promise(resolve => setTimeout(resolve, 100000)); expect(transfer.toString()).toBeDefined(); expect(await transfer.getStatus()).toBe(TransferStatus.COMPLETE); @@ -194,209 +248,209 @@ describe("Coinbase SDK E2E Test", () => { }, 200000); }); -describe("Coinbase SDK Stake E2E Test", () => { - const requiredEnvVars = [ - "STAKE_API_KEY_NAME", - "STAKE_API_PRIVATE_KEY", - "STAKE_ADDRESS_ID_1", - "STAKE_ADDRESS_ID_2", - "STAKE_VALIDATOR_ADDRESS_1", - ]; - - beforeAll(() => { - dotenv.config(); - - requiredEnvVars.forEach(envVar => { - if (!process.env[envVar]) { - throw new Error(`Required environment variable ${envVar} is not set`); - } - }); - - Coinbase.configure({ - apiKeyName: process.env.STAKE_API_KEY_NAME as string, - privateKey: process.env.STAKE_API_PRIVATE_KEY as string, - }); - }); - - it("should be able to access environment variables", () => { - requiredEnvVars.forEach(envVar => { - expect(process.env[envVar]).toBeDefined(); - }); - }); - - describe("Stake: Reward Tests", () => { - it("should list shared eth staking rewards via StakingReward.list", async () => { - const networkId = Coinbase.networks.EthereumMainnet; - const assetId = Coinbase.assets.Eth; - const addressIds = [process.env.STAKE_ADDRESS_ID_1 as string]; - // May 1, 2024 - May 20, 2024 - const startTime = new Date(2024, 4, 1, 0, 0, 0).toISOString(); - const endTime = new Date(2024, 4, 20, 23, 59, 59).toISOString(); - const rewards = await StakingReward.list(networkId, assetId, addressIds, startTime, endTime); - - expect(rewards).toBeDefined(); - expect(rewards.length).toEqual(20); - }); - - it("should list shared eth staking rewards via ExternalAddress", async () => { - // May 1, 2024 - May 20, 2024 - const startTime = new Date(2024, 4, 1, 0, 0, 0).toISOString(); - const endTime = new Date(2024, 4, 20, 23, 59, 59).toISOString(); - - const address = new ExternalAddress( - Coinbase.networks.EthereumMainnet, - process.env.STAKE_ADDRESS_ID_1 as string, - ); - - const rewards = await address.stakingRewards(Coinbase.assets.Eth, startTime, endTime); - - expect(rewards).toBeDefined(); - expect(rewards.length).toEqual(20); - }); - }); - - describe("Stake: Balance Tests", () => { - it("should list shared eth staking balances via StakingBalance.list", async () => { - const networkId = Coinbase.networks.EthereumMainnet; - const assetId = Coinbase.assets.Eth; - const addressId = process.env.STAKE_VALIDATOR_ADDRESS_1 as string; - // Nov 1, 2024 - Nov 20, 2024 - const startTime = new Date(2024, 10, 1, 0, 0, 0).toISOString(); - const endTime = new Date(2024, 10, 20, 23, 59, 59).toISOString(); - const stakingBalances = await StakingBalance.list( - networkId, - assetId, - addressId, - startTime, - endTime, - ); - - expect(stakingBalances).toBeDefined(); - expect(stakingBalances.length).toEqual(20); - }); - }); - - describe("Stake: Validator Tests", () => { - it("should list validators", async () => { - const networkId = Coinbase.networks.EthereumMainnet; - const assetId = Coinbase.assets.Eth; - const status = ValidatorStatus.ACTIVE; - - const validators = await Validator.list(networkId, assetId, status); - - expect(validators).toBeDefined(); - expect(validators.length).toEqual(1); - const validator = validators[0]; - expect(validator.getStatus()).toEqual(ValidatorStatus.ACTIVE); - expect(validator.getValidatorId()).toEqual(process.env.STAKE_VALIDATOR_ADDRESS_1 as string); - }); - - it("should fetch a validator", async () => { - const networkId = Coinbase.networks.EthereumMainnet; - const assetId = Coinbase.assets.Eth; - const validatorId = process.env.STAKE_VALIDATOR_ADDRESS_1 as string; - - const validator = await Validator.fetch(networkId, assetId, validatorId); - - expect(validator).toBeDefined(); - expect(validator.getStatus()).toEqual(ValidatorStatus.ACTIVE); - expect(validator.getValidatorId()).toEqual(validatorId); - }); - }); - - describe("Stake: Context Tests", () => { - it("should return stakeable balances for shared ETH staking", async () => { - const address = new ExternalAddress( - Coinbase.networks.EthereumMainnet, - process.env.STAKE_ADDRESS_ID_2 as string, - ); - - const stakeableBalance = await address.stakeableBalance( - Coinbase.assets.Eth, - StakeOptionsMode.PARTIAL, - ); - - expect(stakeableBalance).toBeDefined(); - expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); - }); - - it("should return unstakeable balances for shared ETH staking", async () => { - const address = new ExternalAddress( - Coinbase.networks.EthereumMainnet, - process.env.STAKE_ADDRESS_ID_1 as string, - ); - - const stakeableBalance = await address.unstakeableBalance( - Coinbase.assets.Eth, - StakeOptionsMode.PARTIAL, - ); - - expect(stakeableBalance).toBeDefined(); - expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); - }); - - it("should return claimable balances for shared ETH staking", async () => { - const address = new ExternalAddress( - Coinbase.networks.EthereumMainnet, - process.env.STAKE_ADDRESS_ID_1 as string, - ); - - const stakeableBalance = await address.claimableBalance( - Coinbase.assets.Eth, - StakeOptionsMode.PARTIAL, - ); - - expect(stakeableBalance).toBeDefined(); - expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); - }); - - it("should return unstakeable balances for Dedicated ETH staking", async () => { - // This address is expected to have 1 validator associated with it, thus returning a 32 unstake balance. - - const address = new ExternalAddress( - Coinbase.networks.EthereumMainnet, - process.env.STAKE_ADDRESS_ID_2 as string, - ); - - const stakeableBalance = await address.unstakeableBalance( - Coinbase.assets.Eth, - StakeOptionsMode.NATIVE, - ); - - expect(stakeableBalance).toBeDefined(); - expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(32); - }); - }); - - describe("Stake: Build Tests", () => { - it("should return an unsigned tx for shared ETH staking", async () => { - const address = new ExternalAddress( - Coinbase.networks.EthereumMainnet, - process.env.STAKE_ADDRESS_ID_2 as string, - ); - - const stakingOperation = await address.buildStakeOperation( - 0.0001, - Coinbase.assets.Eth, - StakeOptionsMode.PARTIAL, - ); - - await stakingOperation.wait({ timeoutSeconds: 5, intervalSeconds: 1 }); - - expect(stakingOperation).toBeDefined(); - expect(stakingOperation.getID()).toBeDefined(); - expect(stakingOperation.getStatus()).toEqual(StakingOperationStatusEnum.Complete); - expect(stakingOperation.getAddressID()).toEqual(process.env.STAKE_ADDRESS_ID_2 as string); - expect(stakingOperation.getNetworkID()).toEqual(Coinbase.networks.EthereumMainnet); - expect(stakingOperation.isCompleteState()).toBe(true); - expect(stakingOperation.getSignedVoluntaryExitMessages()).toEqual([]); - expect(stakingOperation.getTransactions().length).toEqual(1); - expect(stakingOperation.getTransactions()[0].isSigned()).toBe(false); - expect(stakingOperation.getTransactions()[0].getNetworkId()).toEqual( - Coinbase.networks.EthereumMainnet, - ); - expect(stakingOperation.getTransactions()[0].getUnsignedPayload()).toBeDefined(); - expect(stakingOperation.getTransactions()[0].getStatus()).toEqual(TransactionStatus.PENDING); - }); - }); -}); +// describe("Coinbase SDK Stake E2E Test", () => { +// const requiredEnvVars = [ +// "STAKE_API_KEY_NAME", +// "STAKE_API_PRIVATE_KEY", +// "STAKE_ADDRESS_ID_1", +// "STAKE_ADDRESS_ID_2", +// "STAKE_VALIDATOR_ADDRESS_1", +// ]; + +// beforeAll(() => { +// dotenv.config(); + +// requiredEnvVars.forEach(envVar => { +// if (!process.env[envVar]) { +// throw new Error(`Required environment variable ${envVar} is not set`); +// } +// }); + +// Coinbase.configure({ +// apiKeyName: process.env.STAKE_API_KEY_NAME as string, +// privateKey: process.env.STAKE_API_PRIVATE_KEY as string, +// }); +// }); + +// it("should be able to access environment variables", () => { +// requiredEnvVars.forEach(envVar => { +// expect(process.env[envVar]).toBeDefined(); +// }); +// }); + +// describe("Stake: Reward Tests", () => { +// it("should list shared eth staking rewards via StakingReward.list", async () => { +// const networkId = Coinbase.networks.EthereumMainnet; +// const assetId = Coinbase.assets.Eth; +// const addressIds = [process.env.STAKE_ADDRESS_ID_1 as string]; +// // May 1, 2024 - May 20, 2024 +// const startTime = new Date(2024, 4, 1, 0, 0, 0).toISOString(); +// const endTime = new Date(2024, 4, 20, 23, 59, 59).toISOString(); +// const rewards = await StakingReward.list(networkId, assetId, addressIds, startTime, endTime); + +// expect(rewards).toBeDefined(); +// expect(rewards.length).toEqual(20); +// }); + +// it("should list shared eth staking rewards via ExternalAddress", async () => { +// // May 1, 2024 - May 20, 2024 +// const startTime = new Date(2024, 4, 1, 0, 0, 0).toISOString(); +// const endTime = new Date(2024, 4, 20, 23, 59, 59).toISOString(); + +// const address = new ExternalAddress( +// Coinbase.networks.EthereumMainnet, +// process.env.STAKE_ADDRESS_ID_1 as string, +// ); + +// const rewards = await address.stakingRewards(Coinbase.assets.Eth, startTime, endTime); + +// expect(rewards).toBeDefined(); +// expect(rewards.length).toEqual(20); +// }); +// }); + +// describe("Stake: Balance Tests", () => { +// it("should list shared eth staking balances via StakingBalance.list", async () => { +// const networkId = Coinbase.networks.EthereumMainnet; +// const assetId = Coinbase.assets.Eth; +// const addressId = process.env.STAKE_VALIDATOR_ADDRESS_1 as string; +// // Nov 1, 2024 - Nov 20, 2024 +// const startTime = new Date(2024, 10, 1, 0, 0, 0).toISOString(); +// const endTime = new Date(2024, 10, 20, 23, 59, 59).toISOString(); +// const stakingBalances = await StakingBalance.list( +// networkId, +// assetId, +// addressId, +// startTime, +// endTime, +// ); + +// expect(stakingBalances).toBeDefined(); +// expect(stakingBalances.length).toEqual(20); +// }); +// }); + +// describe("Stake: Validator Tests", () => { +// it("should list validators", async () => { +// const networkId = Coinbase.networks.EthereumMainnet; +// const assetId = Coinbase.assets.Eth; +// const status = ValidatorStatus.ACTIVE; + +// const validators = await Validator.list(networkId, assetId, status); + +// expect(validators).toBeDefined(); +// expect(validators.length).toEqual(1); +// const validator = validators[0]; +// expect(validator.getStatus()).toEqual(ValidatorStatus.ACTIVE); +// expect(validator.getValidatorId()).toEqual(process.env.STAKE_VALIDATOR_ADDRESS_1 as string); +// }); + +// it("should fetch a validator", async () => { +// const networkId = Coinbase.networks.EthereumMainnet; +// const assetId = Coinbase.assets.Eth; +// const validatorId = process.env.STAKE_VALIDATOR_ADDRESS_1 as string; + +// const validator = await Validator.fetch(networkId, assetId, validatorId); + +// expect(validator).toBeDefined(); +// expect(validator.getStatus()).toEqual(ValidatorStatus.ACTIVE); +// expect(validator.getValidatorId()).toEqual(validatorId); +// }); +// }); + +// describe("Stake: Context Tests", () => { +// it("should return stakeable balances for shared ETH staking", async () => { +// const address = new ExternalAddress( +// Coinbase.networks.EthereumMainnet, +// process.env.STAKE_ADDRESS_ID_2 as string, +// ); + +// const stakeableBalance = await address.stakeableBalance( +// Coinbase.assets.Eth, +// StakeOptionsMode.PARTIAL, +// ); + +// expect(stakeableBalance).toBeDefined(); +// expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); +// }); + +// it("should return unstakeable balances for shared ETH staking", async () => { +// const address = new ExternalAddress( +// Coinbase.networks.EthereumMainnet, +// process.env.STAKE_ADDRESS_ID_1 as string, +// ); + +// const stakeableBalance = await address.unstakeableBalance( +// Coinbase.assets.Eth, +// StakeOptionsMode.PARTIAL, +// ); + +// expect(stakeableBalance).toBeDefined(); +// expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); +// }); + +// it("should return claimable balances for shared ETH staking", async () => { +// const address = new ExternalAddress( +// Coinbase.networks.EthereumMainnet, +// process.env.STAKE_ADDRESS_ID_1 as string, +// ); + +// const stakeableBalance = await address.claimableBalance( +// Coinbase.assets.Eth, +// StakeOptionsMode.PARTIAL, +// ); + +// expect(stakeableBalance).toBeDefined(); +// expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); +// }); + +// it("should return unstakeable balances for Dedicated ETH staking", async () => { +// // This address is expected to have 1 validator associated with it, thus returning a 32 unstake balance. + +// const address = new ExternalAddress( +// Coinbase.networks.EthereumMainnet, +// process.env.STAKE_ADDRESS_ID_2 as string, +// ); + +// const stakeableBalance = await address.unstakeableBalance( +// Coinbase.assets.Eth, +// StakeOptionsMode.NATIVE, +// ); + +// expect(stakeableBalance).toBeDefined(); +// expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(32); +// }); +// }); + +// describe("Stake: Build Tests", () => { +// it("should return an unsigned tx for shared ETH staking", async () => { +// const address = new ExternalAddress( +// Coinbase.networks.EthereumMainnet, +// process.env.STAKE_ADDRESS_ID_2 as string, +// ); + +// const stakingOperation = await address.buildStakeOperation( +// 0.0001, +// Coinbase.assets.Eth, +// StakeOptionsMode.PARTIAL, +// ); + +// await stakingOperation.wait({ timeoutSeconds: 5, intervalSeconds: 1 }); + +// expect(stakingOperation).toBeDefined(); +// expect(stakingOperation.getID()).toBeDefined(); +// expect(stakingOperation.getStatus()).toEqual(StakingOperationStatusEnum.Complete); +// expect(stakingOperation.getAddressID()).toEqual(process.env.STAKE_ADDRESS_ID_2 as string); +// expect(stakingOperation.getNetworkID()).toEqual(Coinbase.networks.EthereumMainnet); +// expect(stakingOperation.isCompleteState()).toBe(true); +// expect(stakingOperation.getSignedVoluntaryExitMessages()).toEqual([]); +// expect(stakingOperation.getTransactions().length).toEqual(1); +// expect(stakingOperation.getTransactions()[0].isSigned()).toBe(false); +// expect(stakingOperation.getTransactions()[0].getNetworkId()).toEqual( +// Coinbase.networks.EthereumMainnet, +// ); +// expect(stakingOperation.getTransactions()[0].getUnsignedPayload()).toBeDefined(); +// expect(stakingOperation.getTransactions()[0].getStatus()).toEqual(TransactionStatus.PENDING); +// }); +// }); +// }); From 4289cb9a3398e8cc4ca40f03c7a989b26cf5cae5 Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Sat, 8 Feb 2025 22:41:51 -0800 Subject: [PATCH 02/12] uncommented staking tests --- src/tests/e2e.ts | 412 +++++++++++++++++++++++------------------------ 1 file changed, 206 insertions(+), 206 deletions(-) diff --git a/src/tests/e2e.ts b/src/tests/e2e.ts index fd5eaea2..29497752 100644 --- a/src/tests/e2e.ts +++ b/src/tests/e2e.ts @@ -248,209 +248,209 @@ describe("Coinbase SDK E2E Test", () => { }, 200000); }); -// describe("Coinbase SDK Stake E2E Test", () => { -// const requiredEnvVars = [ -// "STAKE_API_KEY_NAME", -// "STAKE_API_PRIVATE_KEY", -// "STAKE_ADDRESS_ID_1", -// "STAKE_ADDRESS_ID_2", -// "STAKE_VALIDATOR_ADDRESS_1", -// ]; - -// beforeAll(() => { -// dotenv.config(); - -// requiredEnvVars.forEach(envVar => { -// if (!process.env[envVar]) { -// throw new Error(`Required environment variable ${envVar} is not set`); -// } -// }); - -// Coinbase.configure({ -// apiKeyName: process.env.STAKE_API_KEY_NAME as string, -// privateKey: process.env.STAKE_API_PRIVATE_KEY as string, -// }); -// }); - -// it("should be able to access environment variables", () => { -// requiredEnvVars.forEach(envVar => { -// expect(process.env[envVar]).toBeDefined(); -// }); -// }); - -// describe("Stake: Reward Tests", () => { -// it("should list shared eth staking rewards via StakingReward.list", async () => { -// const networkId = Coinbase.networks.EthereumMainnet; -// const assetId = Coinbase.assets.Eth; -// const addressIds = [process.env.STAKE_ADDRESS_ID_1 as string]; -// // May 1, 2024 - May 20, 2024 -// const startTime = new Date(2024, 4, 1, 0, 0, 0).toISOString(); -// const endTime = new Date(2024, 4, 20, 23, 59, 59).toISOString(); -// const rewards = await StakingReward.list(networkId, assetId, addressIds, startTime, endTime); - -// expect(rewards).toBeDefined(); -// expect(rewards.length).toEqual(20); -// }); - -// it("should list shared eth staking rewards via ExternalAddress", async () => { -// // May 1, 2024 - May 20, 2024 -// const startTime = new Date(2024, 4, 1, 0, 0, 0).toISOString(); -// const endTime = new Date(2024, 4, 20, 23, 59, 59).toISOString(); - -// const address = new ExternalAddress( -// Coinbase.networks.EthereumMainnet, -// process.env.STAKE_ADDRESS_ID_1 as string, -// ); - -// const rewards = await address.stakingRewards(Coinbase.assets.Eth, startTime, endTime); - -// expect(rewards).toBeDefined(); -// expect(rewards.length).toEqual(20); -// }); -// }); - -// describe("Stake: Balance Tests", () => { -// it("should list shared eth staking balances via StakingBalance.list", async () => { -// const networkId = Coinbase.networks.EthereumMainnet; -// const assetId = Coinbase.assets.Eth; -// const addressId = process.env.STAKE_VALIDATOR_ADDRESS_1 as string; -// // Nov 1, 2024 - Nov 20, 2024 -// const startTime = new Date(2024, 10, 1, 0, 0, 0).toISOString(); -// const endTime = new Date(2024, 10, 20, 23, 59, 59).toISOString(); -// const stakingBalances = await StakingBalance.list( -// networkId, -// assetId, -// addressId, -// startTime, -// endTime, -// ); - -// expect(stakingBalances).toBeDefined(); -// expect(stakingBalances.length).toEqual(20); -// }); -// }); - -// describe("Stake: Validator Tests", () => { -// it("should list validators", async () => { -// const networkId = Coinbase.networks.EthereumMainnet; -// const assetId = Coinbase.assets.Eth; -// const status = ValidatorStatus.ACTIVE; - -// const validators = await Validator.list(networkId, assetId, status); - -// expect(validators).toBeDefined(); -// expect(validators.length).toEqual(1); -// const validator = validators[0]; -// expect(validator.getStatus()).toEqual(ValidatorStatus.ACTIVE); -// expect(validator.getValidatorId()).toEqual(process.env.STAKE_VALIDATOR_ADDRESS_1 as string); -// }); - -// it("should fetch a validator", async () => { -// const networkId = Coinbase.networks.EthereumMainnet; -// const assetId = Coinbase.assets.Eth; -// const validatorId = process.env.STAKE_VALIDATOR_ADDRESS_1 as string; - -// const validator = await Validator.fetch(networkId, assetId, validatorId); - -// expect(validator).toBeDefined(); -// expect(validator.getStatus()).toEqual(ValidatorStatus.ACTIVE); -// expect(validator.getValidatorId()).toEqual(validatorId); -// }); -// }); - -// describe("Stake: Context Tests", () => { -// it("should return stakeable balances for shared ETH staking", async () => { -// const address = new ExternalAddress( -// Coinbase.networks.EthereumMainnet, -// process.env.STAKE_ADDRESS_ID_2 as string, -// ); - -// const stakeableBalance = await address.stakeableBalance( -// Coinbase.assets.Eth, -// StakeOptionsMode.PARTIAL, -// ); - -// expect(stakeableBalance).toBeDefined(); -// expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); -// }); - -// it("should return unstakeable balances for shared ETH staking", async () => { -// const address = new ExternalAddress( -// Coinbase.networks.EthereumMainnet, -// process.env.STAKE_ADDRESS_ID_1 as string, -// ); - -// const stakeableBalance = await address.unstakeableBalance( -// Coinbase.assets.Eth, -// StakeOptionsMode.PARTIAL, -// ); - -// expect(stakeableBalance).toBeDefined(); -// expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); -// }); - -// it("should return claimable balances for shared ETH staking", async () => { -// const address = new ExternalAddress( -// Coinbase.networks.EthereumMainnet, -// process.env.STAKE_ADDRESS_ID_1 as string, -// ); - -// const stakeableBalance = await address.claimableBalance( -// Coinbase.assets.Eth, -// StakeOptionsMode.PARTIAL, -// ); - -// expect(stakeableBalance).toBeDefined(); -// expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); -// }); - -// it("should return unstakeable balances for Dedicated ETH staking", async () => { -// // This address is expected to have 1 validator associated with it, thus returning a 32 unstake balance. - -// const address = new ExternalAddress( -// Coinbase.networks.EthereumMainnet, -// process.env.STAKE_ADDRESS_ID_2 as string, -// ); - -// const stakeableBalance = await address.unstakeableBalance( -// Coinbase.assets.Eth, -// StakeOptionsMode.NATIVE, -// ); - -// expect(stakeableBalance).toBeDefined(); -// expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(32); -// }); -// }); - -// describe("Stake: Build Tests", () => { -// it("should return an unsigned tx for shared ETH staking", async () => { -// const address = new ExternalAddress( -// Coinbase.networks.EthereumMainnet, -// process.env.STAKE_ADDRESS_ID_2 as string, -// ); - -// const stakingOperation = await address.buildStakeOperation( -// 0.0001, -// Coinbase.assets.Eth, -// StakeOptionsMode.PARTIAL, -// ); - -// await stakingOperation.wait({ timeoutSeconds: 5, intervalSeconds: 1 }); - -// expect(stakingOperation).toBeDefined(); -// expect(stakingOperation.getID()).toBeDefined(); -// expect(stakingOperation.getStatus()).toEqual(StakingOperationStatusEnum.Complete); -// expect(stakingOperation.getAddressID()).toEqual(process.env.STAKE_ADDRESS_ID_2 as string); -// expect(stakingOperation.getNetworkID()).toEqual(Coinbase.networks.EthereumMainnet); -// expect(stakingOperation.isCompleteState()).toBe(true); -// expect(stakingOperation.getSignedVoluntaryExitMessages()).toEqual([]); -// expect(stakingOperation.getTransactions().length).toEqual(1); -// expect(stakingOperation.getTransactions()[0].isSigned()).toBe(false); -// expect(stakingOperation.getTransactions()[0].getNetworkId()).toEqual( -// Coinbase.networks.EthereumMainnet, -// ); -// expect(stakingOperation.getTransactions()[0].getUnsignedPayload()).toBeDefined(); -// expect(stakingOperation.getTransactions()[0].getStatus()).toEqual(TransactionStatus.PENDING); -// }); -// }); -// }); +describe("Coinbase SDK Stake E2E Test", () => { + const requiredEnvVars = [ + "STAKE_API_KEY_NAME", + "STAKE_API_PRIVATE_KEY", + "STAKE_ADDRESS_ID_1", + "STAKE_ADDRESS_ID_2", + "STAKE_VALIDATOR_ADDRESS_1", + ]; + + beforeAll(() => { + dotenv.config(); + + requiredEnvVars.forEach(envVar => { + if (!process.env[envVar]) { + throw new Error(`Required environment variable ${envVar} is not set`); + } + }); + + Coinbase.configure({ + apiKeyName: process.env.STAKE_API_KEY_NAME as string, + privateKey: process.env.STAKE_API_PRIVATE_KEY as string, + }); + }); + + it("should be able to access environment variables", () => { + requiredEnvVars.forEach(envVar => { + expect(process.env[envVar]).toBeDefined(); + }); + }); + + describe("Stake: Reward Tests", () => { + it("should list shared eth staking rewards via StakingReward.list", async () => { + const networkId = Coinbase.networks.EthereumMainnet; + const assetId = Coinbase.assets.Eth; + const addressIds = [process.env.STAKE_ADDRESS_ID_1 as string]; + // May 1, 2024 - May 20, 2024 + const startTime = new Date(2024, 4, 1, 0, 0, 0).toISOString(); + const endTime = new Date(2024, 4, 20, 23, 59, 59).toISOString(); + const rewards = await StakingReward.list(networkId, assetId, addressIds, startTime, endTime); + + expect(rewards).toBeDefined(); + expect(rewards.length).toEqual(20); + }); + + it("should list shared eth staking rewards via ExternalAddress", async () => { + // May 1, 2024 - May 20, 2024 + const startTime = new Date(2024, 4, 1, 0, 0, 0).toISOString(); + const endTime = new Date(2024, 4, 20, 23, 59, 59).toISOString(); + + const address = new ExternalAddress( + Coinbase.networks.EthereumMainnet, + process.env.STAKE_ADDRESS_ID_1 as string, + ); + + const rewards = await address.stakingRewards(Coinbase.assets.Eth, startTime, endTime); + + expect(rewards).toBeDefined(); + expect(rewards.length).toEqual(20); + }); + }); + + describe("Stake: Balance Tests", () => { + it("should list shared eth staking balances via StakingBalance.list", async () => { + const networkId = Coinbase.networks.EthereumMainnet; + const assetId = Coinbase.assets.Eth; + const addressId = process.env.STAKE_VALIDATOR_ADDRESS_1 as string; + // Nov 1, 2024 - Nov 20, 2024 + const startTime = new Date(2024, 10, 1, 0, 0, 0).toISOString(); + const endTime = new Date(2024, 10, 20, 23, 59, 59).toISOString(); + const stakingBalances = await StakingBalance.list( + networkId, + assetId, + addressId, + startTime, + endTime, + ); + + expect(stakingBalances).toBeDefined(); + expect(stakingBalances.length).toEqual(20); + }); + }); + + describe("Stake: Validator Tests", () => { + it("should list validators", async () => { + const networkId = Coinbase.networks.EthereumMainnet; + const assetId = Coinbase.assets.Eth; + const status = ValidatorStatus.ACTIVE; + + const validators = await Validator.list(networkId, assetId, status); + + expect(validators).toBeDefined(); + expect(validators.length).toEqual(1); + const validator = validators[0]; + expect(validator.getStatus()).toEqual(ValidatorStatus.ACTIVE); + expect(validator.getValidatorId()).toEqual(process.env.STAKE_VALIDATOR_ADDRESS_1 as string); + }); + + it("should fetch a validator", async () => { + const networkId = Coinbase.networks.EthereumMainnet; + const assetId = Coinbase.assets.Eth; + const validatorId = process.env.STAKE_VALIDATOR_ADDRESS_1 as string; + + const validator = await Validator.fetch(networkId, assetId, validatorId); + + expect(validator).toBeDefined(); + expect(validator.getStatus()).toEqual(ValidatorStatus.ACTIVE); + expect(validator.getValidatorId()).toEqual(validatorId); + }); + }); + + describe("Stake: Context Tests", () => { + it("should return stakeable balances for shared ETH staking", async () => { + const address = new ExternalAddress( + Coinbase.networks.EthereumMainnet, + process.env.STAKE_ADDRESS_ID_2 as string, + ); + + const stakeableBalance = await address.stakeableBalance( + Coinbase.assets.Eth, + StakeOptionsMode.PARTIAL, + ); + + expect(stakeableBalance).toBeDefined(); + expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); + }); + + it("should return unstakeable balances for shared ETH staking", async () => { + const address = new ExternalAddress( + Coinbase.networks.EthereumMainnet, + process.env.STAKE_ADDRESS_ID_1 as string, + ); + + const stakeableBalance = await address.unstakeableBalance( + Coinbase.assets.Eth, + StakeOptionsMode.PARTIAL, + ); + + expect(stakeableBalance).toBeDefined(); + expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); + }); + + it("should return claimable balances for shared ETH staking", async () => { + const address = new ExternalAddress( + Coinbase.networks.EthereumMainnet, + process.env.STAKE_ADDRESS_ID_1 as string, + ); + + const stakeableBalance = await address.claimableBalance( + Coinbase.assets.Eth, + StakeOptionsMode.PARTIAL, + ); + + expect(stakeableBalance).toBeDefined(); + expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(0); + }); + + it("should return unstakeable balances for Dedicated ETH staking", async () => { + // This address is expected to have 1 validator associated with it, thus returning a 32 unstake balance. + + const address = new ExternalAddress( + Coinbase.networks.EthereumMainnet, + process.env.STAKE_ADDRESS_ID_2 as string, + ); + + const stakeableBalance = await address.unstakeableBalance( + Coinbase.assets.Eth, + StakeOptionsMode.NATIVE, + ); + + expect(stakeableBalance).toBeDefined(); + expect(stakeableBalance.toNumber()).toBeGreaterThanOrEqual(32); + }); + }); + + describe("Stake: Build Tests", () => { + it("should return an unsigned tx for shared ETH staking", async () => { + const address = new ExternalAddress( + Coinbase.networks.EthereumMainnet, + process.env.STAKE_ADDRESS_ID_2 as string, + ); + + const stakingOperation = await address.buildStakeOperation( + 0.0001, + Coinbase.assets.Eth, + StakeOptionsMode.PARTIAL, + ); + + await stakingOperation.wait({ timeoutSeconds: 5, intervalSeconds: 1 }); + + expect(stakingOperation).toBeDefined(); + expect(stakingOperation.getID()).toBeDefined(); + expect(stakingOperation.getStatus()).toEqual(StakingOperationStatusEnum.Complete); + expect(stakingOperation.getAddressID()).toEqual(process.env.STAKE_ADDRESS_ID_2 as string); + expect(stakingOperation.getNetworkID()).toEqual(Coinbase.networks.EthereumMainnet); + expect(stakingOperation.isCompleteState()).toBe(true); + expect(stakingOperation.getSignedVoluntaryExitMessages()).toEqual([]); + expect(stakingOperation.getTransactions().length).toEqual(1); + expect(stakingOperation.getTransactions()[0].isSigned()).toBe(false); + expect(stakingOperation.getTransactions()[0].getNetworkId()).toEqual( + Coinbase.networks.EthereumMainnet, + ); + expect(stakingOperation.getTransactions()[0].getUnsignedPayload()).toBeDefined(); + expect(stakingOperation.getTransactions()[0].getStatus()).toEqual(TransactionStatus.PENDING); + }); + }); +}); From 5a0ad438cef44fa5e61eb424f9582c97fd4cea2d Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Sat, 8 Feb 2025 22:44:55 -0800 Subject: [PATCH 03/12] revert timeout for transfer --- src/tests/e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/e2e.ts b/src/tests/e2e.ts index 29497752..5e6a29f6 100644 --- a/src/tests/e2e.ts +++ b/src/tests/e2e.ts @@ -232,7 +232,7 @@ describe("Coinbase SDK E2E Test", () => { }); await transfer.wait(); - await new Promise(resolve => setTimeout(resolve, 100000)); + await new Promise(resolve => setTimeout(resolve, 60000)); expect(transfer.toString()).toBeDefined(); expect(await transfer.getStatus()).toBe(TransferStatus.COMPLETE); From c5fa097b4431e1d07e0e4823141063bd3b0bf897 Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Sat, 8 Feb 2025 22:45:50 -0800 Subject: [PATCH 04/12] removed only tag from e2e test --- src/tests/e2e.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tests/e2e.ts b/src/tests/e2e.ts index 5e6a29f6..893105d2 100644 --- a/src/tests/e2e.ts +++ b/src/tests/e2e.ts @@ -151,7 +151,7 @@ describe("Coinbase SDK E2E Test", () => { }); }, 60000); - it.only("Should be able to invoke a contract and retrieve the transaction receipt", async() => { + it("Should be able to invoke a contract and retrieve the transaction receipt", async() => { const seedFile = JSON.parse(process.env.WALLET_DATA || ""); const walletId = Object.keys(seedFile)[0]; const seed = seedFile[walletId].seed; @@ -203,8 +203,6 @@ describe("Coinbase SDK E2E Test", () => { expect(log.data).toEqual("0x0000000000000000000000000000000000000000000000000000000000000001"); }, 60000); - - it.skip("should be able to make gasless transfers", async () => { // Import wallet with balance const seedFile = JSON.parse(process.env.WALLET_DATA || ""); From d9e13575c049edac9c00a4284f3262563b74767d Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Sat, 8 Feb 2025 23:43:12 -0800 Subject: [PATCH 05/12] fixing staking tests --- src/tests/external_address_test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tests/external_address_test.ts b/src/tests/external_address_test.ts index a9175244..a2bf9a30 100644 --- a/src/tests/external_address_test.ts +++ b/src/tests/external_address_test.ts @@ -63,6 +63,15 @@ describe("ExternalAddress", () => { contract_address: "0x", }, }, + pending_claimable_balance: { + amount: "1000000000000000000", + asset: { + asset_id: Coinbase.assets.Eth, + network_id: Coinbase.networks.EthereumHolesky, + decimals: 18, + contract_address: "0x", + } + } }, }; const STAKING_OPERATION_MODEL: StakingOperationModel = { From b1ca947f38589860a8b1b036cc199d831b222273 Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Sat, 8 Feb 2025 23:48:46 -0800 Subject: [PATCH 06/12] fixed staking tests --- src/tests/wallet_address_test.ts | 9 +++++++++ src/tests/wallet_test.ts | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/tests/wallet_address_test.ts b/src/tests/wallet_address_test.ts index 474ad525..22b99195 100644 --- a/src/tests/wallet_address_test.ts +++ b/src/tests/wallet_address_test.ts @@ -397,6 +397,15 @@ describe("WalletAddress", () => { contract_address: "0x", }, }, + pending_claimable_balance: { + amount: "1000000000000000000", + asset: { + asset_id: Coinbase.assets.Eth, + network_id: Coinbase.networks.EthereumHolesky, + decimals: 18, + contract_address: "0x", + } + } }, }; diff --git a/src/tests/wallet_test.ts b/src/tests/wallet_test.ts index 1036b897..0cfa6385 100644 --- a/src/tests/wallet_test.ts +++ b/src/tests/wallet_test.ts @@ -174,6 +174,15 @@ describe("Wallet Class", () => { contract_address: "0x", }, }, + pending_claimable_balance: { + amount: "1000000000000000000", + asset: { + asset_id: Coinbase.assets.Eth, + network_id: Coinbase.networks.EthereumHolesky, + decimals: 18, + contract_address: "0x", + } + } }, }; From 21894665acaf6a471bc176905d591ee2ba8356c9 Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Sat, 8 Feb 2025 23:52:25 -0800 Subject: [PATCH 07/12] removed unneded console logs --- src/tests/e2e.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tests/e2e.ts b/src/tests/e2e.ts index 893105d2..1aefd4a9 100644 --- a/src/tests/e2e.ts +++ b/src/tests/e2e.ts @@ -182,9 +182,6 @@ describe("Coinbase SDK E2E Test", () => { await contractInvocation.wait(); const transactionContent = contractInvocation.getTransaction().content(); - console.log(transactionContent) - console.log(transactionContent!.receipt); - const receipt = transactionContent!.receipt; expect(receipt).toBeDefined(); From 22c1798750e3770244152fdce280c72014300e6d Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Tue, 11 Feb 2025 13:08:01 -0800 Subject: [PATCH 08/12] updated SDK with backend --- src/client/api.ts | 18 +++++++++++++++--- src/tests/e2e.ts | 8 ++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/client/api.ts b/src/client/api.ts index a5efab5b..9a88220b 100644 --- a/src/client/api.ts +++ b/src/client/api.ts @@ -1790,6 +1790,18 @@ export interface EthereumValidatorMetadata { * @memberof EthereumValidatorMetadata */ 'effective_balance': Balance; + /** + * The address for execution layer rewards (MEV & tx fees). If using a reward splitter plan, this is a smart contract address that splits rewards based on defined commissions and send a portion to the forwarded_fee_recipient_address. + * @type {string} + * @memberof EthereumValidatorMetadata + */ + 'fee_recipient_address': string; + /** + * If using a reward splitter plan, this address receives a defined percentage of the total execution layer rewards. + * @type {string} + * @memberof EthereumValidatorMetadata + */ + 'forwarded_fee_recipient_address'?: string; } /** * The faucet transaction @@ -3790,19 +3802,19 @@ export interface TransactionLog { * @type {string} * @memberof TransactionLog */ - 'address': string; + 'address'?: string; /** * * @type {Array} * @memberof TransactionLog */ - 'topics': Array; + 'topics'?: Array; /** * The data included in this log. * @type {string} * @memberof TransactionLog */ - 'data': string; + 'data'?: string; } /** * The receipt of an onchain transaction\'s execution. diff --git a/src/tests/e2e.ts b/src/tests/e2e.ts index 1aefd4a9..c86cc60b 100644 --- a/src/tests/e2e.ts +++ b/src/tests/e2e.ts @@ -185,7 +185,7 @@ describe("Coinbase SDK E2E Test", () => { const receipt = transactionContent!.receipt; expect(receipt).toBeDefined(); - expect(receipt!.logs).toBeDefined(); + expect(receipt?.logs).toBeDefined(); const logs = receipt!.logs; @@ -194,9 +194,9 @@ describe("Coinbase SDK E2E Test", () => { const log = logs[0]; expect(log.address).toEqual("0x036CbD53842c5426634e7929541eC2318f3dCF7e"); - expect(log.topics[0]).toEqual("Transfer"); - expect(log.topics[1]).toEqual(`from: ${(await importedWallet.getDefaultAddress()).getId()}`); - expect(log.topics[2]).toEqual(`to: ${(await secondWallet.getDefaultAddress()).getId()}`); + expect(log.topics?.[0]).toEqual("Transfer"); + expect(log.topics?.[1]).toEqual(`from: ${(await importedWallet.getDefaultAddress()).getId()}`); + expect(log.topics?.[2]).toEqual(`to: ${(await secondWallet.getDefaultAddress()).getId()}`); expect(log.data).toEqual("0x0000000000000000000000000000000000000000000000000000000000000001"); }, 60000); From 3873f110bb52998c206c9e3dd03b449a56ddf2ef Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Tue, 11 Feb 2025 13:41:07 -0800 Subject: [PATCH 09/12] updated contract invocation e2e test --- src/tests/e2e.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tests/e2e.ts b/src/tests/e2e.ts index c86cc60b..d258ceaa 100644 --- a/src/tests/e2e.ts +++ b/src/tests/e2e.ts @@ -185,9 +185,12 @@ describe("Coinbase SDK E2E Test", () => { const receipt = transactionContent!.receipt; expect(receipt).toBeDefined(); - expect(receipt?.logs).toBeDefined(); - - const logs = receipt!.logs; + + if (!receipt?.logs) { + fail("No logs found in receipt"); + } + + const logs = receipt.logs; expect(logs).toBeDefined(); expect(logs.length).toEqual(1); From 3a61e6947e8fd7d7259e6923fcd1e1066c9d381e Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Tue, 11 Feb 2025 14:03:54 -0800 Subject: [PATCH 10/12] fixing unit tests --- src/tests/utils.ts | 1 + src/tests/validator_test.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tests/utils.ts b/src/tests/utils.ts index c924383c..f76c5118 100644 --- a/src/tests/utils.ts +++ b/src/tests/utils.ts @@ -627,6 +627,7 @@ export function mockEthereumValidator( index: index, public_key: public_key, withdrawal_address: "0xwithdrawal_address_1", + fee_recipient_address: "0xfee_recipient_address_1", slashed: false, activationEpoch: "10", exitEpoch: "10", diff --git a/src/tests/validator_test.ts b/src/tests/validator_test.ts index fcb3c3d6..614f4897 100644 --- a/src/tests/validator_test.ts +++ b/src/tests/validator_test.ts @@ -18,6 +18,7 @@ describe("Validator", () => { amount: "100", asset: { network_id: Coinbase.networks.EthereumHolesky, asset_id: Coinbase.assets.Eth }, }, + fee_recipient_address: "fee-recipient-address-123", balance: { amount: "200", asset: { network_id: Coinbase.networks.EthereumHolesky, asset_id: Coinbase.assets.Eth }, From 6f3312fb8f6d96de632d738fecd3d10bbac9325a Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Wed, 12 Feb 2025 13:04:40 -0800 Subject: [PATCH 11/12] add updated openapi spec --- src/client/api.ts | 98 +++++++---------------------------------------- 1 file changed, 13 insertions(+), 85 deletions(-) diff --git a/src/client/api.ts b/src/client/api.ts index 9a88220b..64d79f8d 100644 --- a/src/client/api.ts +++ b/src/client/api.ts @@ -1791,7 +1791,7 @@ export interface EthereumValidatorMetadata { */ 'effective_balance': Balance; /** - * The address for execution layer rewards (MEV & tx fees). If using a reward splitter plan, this is a smart contract address that splits rewards based on defined commissions and send a portion to the forwarded_fee_recipient_address. + * The address for execution layer rewards (MEV & tx fees). If using a reward splitter plan, this is a smart contract address that splits rewards based on defined commissions and send a portion to the forwarded_fee_recipient_address. * @type {string} * @memberof EthereumValidatorMetadata */ @@ -3802,19 +3802,19 @@ export interface TransactionLog { * @type {string} * @memberof TransactionLog */ - 'address'?: string; + 'address': string; /** * * @type {Array} * @memberof TransactionLog */ - 'topics'?: Array; + 'topics': Array; /** * The data included in this log. * @type {string} * @memberof TransactionLog */ - 'data'?: string; + 'data': string; } /** * The receipt of an onchain transaction\'s execution. @@ -3822,84 +3822,6 @@ export interface TransactionLog { * @interface TransactionReceipt */ export interface TransactionReceipt { - /** - * The address this transaction is to. This is null if the transaction was an init transaction, used to deploy a contract. - * @type {string} - * @memberof TransactionReceipt - */ - 'to'?: string; - /** - * The address this transaction is from. - * @type {string} - * @memberof TransactionReceipt - */ - 'from'?: string; - /** - * The EVM address of the smart contract. If this transaction has a null to address, it is an init transaction used to deploy a contract, in which case this is the address created by that contract. - * @type {string} - * @memberof TransactionReceipt - */ - 'contract_address'?: string; - /** - * The index of this transaction in the list of transactions included in the block this transaction was mined in. - * @type {number} - * @memberof TransactionReceipt - */ - 'transaction_index'?: number; - /** - * The EIP-2718 transaction type. See https://eips.ethereum.org/EIPS/eip-2718 for more details. - * @type {number} - * @memberof TransactionReceipt - */ - 'type'?: number; - /** - * A bloom-filter, which includes all the addresses and topics included in any log in this transaction. - * @type {string} - * @memberof TransactionReceipt - */ - 'logs_bloom'?: string; - /** - * The hash of the block at which the transaction was recorded. - * @type {string} - * @memberof TransactionReceipt - */ - 'block_hash'?: string; - /** - * The hash of the onchain sponsored send transaction. - * @type {string} - * @memberof TransactionReceipt - */ - 'transaction_hash'?: string; - /** - * The block height (number) of the block that this transaction was included in. - * @type {number} - * @memberof TransactionReceipt - */ - 'block_number'?: number; - /** - * The number of blocks that have been mined since this transaction, including the actual block it was mined in. - * @type {number} - * @memberof TransactionReceipt - */ - 'confirmations'?: number; - /** - * The intermediate state root of a receipt. - * @type {string} - * @memberof TransactionReceipt - */ - 'root'?: string; - /** - * For the block this transaction was included in, this is the sum of the gas used by each transaction in the ordered list of transactions up to (and including) this transaction. - * @type {number} - * @memberof TransactionReceipt - */ - 'cumulative_gas_used'?: number; - /** - * This is true if the block is in a post-Byzantium Hard Fork block. - * @type {boolean} - * @memberof TransactionReceipt - */ - 'byzantium'?: boolean; /** * The status of a transaction is 1 if successful or 0 if it was reverted. * @type {number} @@ -3917,13 +3839,13 @@ export interface TransactionReceipt { * @type {string} * @memberof TransactionReceipt */ - 'gas_used'?: string; + 'gas_used': string; /** * The effective gas price the transaction was charged at. * @type {string} * @memberof TransactionReceipt */ - 'effective_gas_price'?: string; + 'effective_gas_price': string; } /** * @@ -4178,12 +4100,18 @@ export interface UserOperation { * @memberof UserOperation */ 'signature'?: string; + /** + * The hash of the transaction that was broadcast. + * @type {string} + * @memberof UserOperation + */ + 'transaction_hash'?: string; /** * The status of the user operation. * @type {string} * @memberof UserOperation */ - 'status'?: UserOperationStatusEnum; + 'status': UserOperationStatusEnum; } export const UserOperationStatusEnum = { From 9a79b706fce5575c0d75642cacf64d79341ef230 Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Wed, 12 Feb 2025 18:25:08 -0800 Subject: [PATCH 12/12] update changelog and version --- CHANGELOG.md | 5 +++++ package-lock.json | 4 ++-- package.json | 2 +- quickstart-template/package.json | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fd93212..97ead9c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Coinbase Node.js SDK Changelog +## [0.18.0] - 2025-02-13 + +### Added +- Add `TransactionReceipt` and `TransactionLog` to contract invocation response. + ## [0.17.0] - 2025-02-01 ### Added diff --git a/package-lock.json b/package-lock.json index 0399d8ce..82464954 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@coinbase/coinbase-sdk", - "version": "0.16.0", + "version": "0.18.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@coinbase/coinbase-sdk", - "version": "0.16.0", + "version": "0.18.0", "license": "ISC", "dependencies": { "@scure/bip32": "^1.4.0", diff --git a/package.json b/package.json index 222d7b75..ab76959c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "license": "ISC", "description": "Coinbase Platform SDK", "repository": "https://github.com/coinbase/coinbase-sdk-nodejs", - "version": "0.17.0", + "version": "0.18.0", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { diff --git a/quickstart-template/package.json b/quickstart-template/package.json index 11b8bc42..404f2166 100644 --- a/quickstart-template/package.json +++ b/quickstart-template/package.json @@ -22,7 +22,7 @@ "dependencies": { "@solana/web3.js": "^2.0.0-rc.1", "bs58": "^6.0.0", - "@coinbase/coinbase-sdk": "^0.16.0", + "@coinbase/coinbase-sdk": "^0.18.0", "csv-parse": "^5.5.6", "csv-writer": "^1.6.0", "viem": "^2.21.6"