UNPKG

@abstraxn/relayer

Version:

Abstraxn Relayer package for handling gas-less transactions, facilitating smart contract interactions, and relaying user transactions efficiently.

222 lines 9.01 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Relayer = void 0; const ethers_1 = require("ethers"); const httpRequests_1 = require("./lib/httpRequests"); const HelperFunction_1 = require("./utils/HelperFunction"); const WebSocketManager_1 = require("./lib/WebSocketManager"); class Relayer { constructor(relayerConfig) { var _a; this.relayerConfig = relayerConfig; if (!relayerConfig.provider || !relayerConfig.signer) { throw new Error("RelayerConfig must include a valid provider and signer."); } this.relayerUrl = relayerConfig.relayerUrl; this.chainId = relayerConfig.chainId; this.signer = relayerConfig.signer; this.provider = relayerConfig.provider; // Initialize WebSocket manager this.webSocketManager = new WebSocketManager_1.WebSocketManager(this.relayerUrl, relayerConfig.webSocket); // Auto-connect if enabled if (((_a = relayerConfig.webSocket) === null || _a === void 0 ? void 0 : _a.autoConnect) !== false) { this.webSocketManager.connect(); } } getRelayerUrl() { return `${this.relayerUrl}`; } async buildRelayerTx(params) { try { const { abi, contractAddress, method, args } = params; if (!abi || !contractAddress || !method) { throw new Error("Invalid parameters: 'abi', 'contractAddress', and 'method' are required."); } // Create contract instance const contract = new ethers_1.Contract(contractAddress, abi, this.provider); // Encode function signature const functionSignature = contract.interface.encodeFunctionData(method, args); // Get user address const userAddress = await this.signer.getAddress(); // Fetch nonce from contract const nonce = await contract.getNonce(userAddress); // Generate meta-transaction hash const metaTxHash = ethers_1.ethers.solidityPackedKeccak256(["uint256", "address", "uint256", "bytes"], [nonce, contractAddress, this.chainId, functionSignature]); // Sign the transaction hash const signature = await this.signer.signMessage(ethers_1.ethers.getBytes(metaTxHash)); const sig = ethers_1.ethers.Signature.from(signature); const { r, s, v } = sig; const executeMetaData = contract.interface.encodeFunctionData("executeMetaTransaction", [userAddress, functionSignature, r, s, v]); return { userAddress, functionSignature, signature, data: executeMetaData, chainId: this.chainId, contractAddress, }; } catch (error) { console.error("Error in buildRelayerTx:", error); throw new Error(`Failed to build relayer transaction: ${error instanceof Error ? error.message : error}`); } } async buildRelayerTxEIP712(params) { try { const { abi, contractAddress, method, args } = params; if (!abi || !contractAddress || !method) { throw new Error("Invalid parameters: 'abi', 'contractAddress', and 'method' are required."); } const contract = new ethers_1.Contract(contractAddress, abi, this.provider); const userAddress = await this.signer.getAddress(); const functionSignature = contract.interface.encodeFunctionData(method, args); const nonce = await contract.getNonce(userAddress); const domain = { name: typeof contract.name === "function" ? await contract.name() : "MetaTx", version: "1", verifyingContract: contractAddress, salt: ethers_1.ethers.zeroPadValue(ethers_1.ethers.toBeHex(this.chainId), 32), }; const types = { MetaTransaction: [ { name: "nonce", type: "uint256" }, { name: "from", type: "address" }, { name: "functionSignature", type: "bytes" }, ], }; const message = { nonce: nonce.toString(), from: userAddress, functionSignature, }; let signature; let r, s; let v; if (typeof this.signer.signTypedData === "function") { signature = await this.signer.signTypedData(domain, types, message); const sig = ethers_1.ethers.Signature.from(signature); ({ r, s, v } = sig); } else if (typeof this.signer._signTypedData === "function") { signature = await this.signer._signTypedData(domain, types, message); const sig = ethers_1.ethers.Signature.from(signature); ({ r, s, v } = sig); } else { throw new Error("Signer does not support EIP-712 signing."); } const executeMetaData = contract.interface.encodeFunctionData("executeMetaTransaction", [ userAddress, functionSignature, r, s, v, ]); return { userAddress, functionSignature, signature, data: executeMetaData, chainId: this.chainId, contractAddress, }; } catch (error) { console.error("Error in buildRelayerTxEIP712:", error); throw new Error(`Failed to build EIP-712 relayer transaction: ${error instanceof Error ? error.message : error}`); } } async sendRelayerTx(txParams) { const relayerUrl = this.getRelayerUrl(); const sendRelayerResponse = await (0, httpRequests_1.sendRequest)({ url: relayerUrl, method: httpRequests_1.HttpMethod.Post, body: { method: "eth_sendTransactionToRelayer", params: txParams, id: (0, HelperFunction_1.getTimestampInSeconds)(), jsonrpc: "2.0", }, }); const response = { message: sendRelayerResponse.message, transactionId: sendRelayerResponse.result, }; return response; } async getRelayerTxStatus(transactionId) { const relayerUrl = this.getRelayerUrl(); const response = await (0, httpRequests_1.sendRequest)({ url: relayerUrl, method: httpRequests_1.HttpMethod.Post, body: { method: "abstraxn_getRelayerTxStatus", params: [transactionId], id: (0, HelperFunction_1.getTimestampInSeconds)(), jsonrpc: "2.0", }, }); const txStatus = response.result; return txStatus; } // WebSocket Methods /** * Send relayer transaction with real-time updates via WebSocket */ async sendRelayerTxWithRealTimeUpdates(params) { // Send the transaction first const response = await this.sendRelayerTx(params); // If real-time updates are enabled, subscribe to transaction updates if (params.enableRealTimeUpdates && response.transactionId) { try { await this.subscribeToTransaction(response.transactionId, params.webSocketEvents); } catch (error) { console.warn('Failed to subscribe to transaction updates:', error); // Don't throw error here as the transaction was still sent successfully } } return response; } /** * Subscribe to real-time transaction updates */ async subscribeToTransaction(transactionId, events) { if (!this.webSocketManager.connected()) { throw new Error('WebSocket not connected. Call connectWebSocket() first.'); } return this.webSocketManager.subscribeToTransaction(transactionId, events || {}); } /** * Unsubscribe from transaction updates */ unsubscribeFromTransaction(transactionId) { this.webSocketManager.unsubscribeFromTransaction(transactionId); } /** * Connect to WebSocket server */ connectWebSocket() { this.webSocketManager.connect(); } /** * Disconnect from WebSocket server */ disconnectWebSocket() { this.webSocketManager.disconnect(); } /** * Check if WebSocket is connected */ isWebSocketConnected() { return this.webSocketManager.connected(); } /** * Get WebSocket connection information */ getWebSocketInfo() { return this.webSocketManager.getConnectionInfo(); } } exports.Relayer = Relayer; //# sourceMappingURL=Relayer.js.map