blockchain-utils-service 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "blockchain-utils-service",
3
+ "version": "1.0.0",
4
+ "description": "A lightweight service for deploying contracts, writing transactions, reading events, and checking block numbers.",
5
+ "main": "src/index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "build": "echo 'No build needed'",
9
+ "test": "echo 'No test yet'"
10
+ },
11
+ "keywords": [
12
+ "thirdweb",
13
+ "blockchain",
14
+ "smart-contracts",
15
+ "events",
16
+ "deploy",
17
+ "transactions"
18
+ ],
19
+ "author": "Mai Labs",
20
+ "license": "MIT",
21
+ "dependencies": {
22
+ "@thirdweb-dev/sdk": "^4.0.99",
23
+ "axios": "^1.6.7",
24
+ "dotenv": "^16.3.0",
25
+ "ethers": "^5.8.0",
26
+ "thirdweb": "^5.104.1",
27
+ "undici": "^7.8.0"
28
+ }
29
+ }
@@ -0,0 +1,88 @@
1
+ // src/contractSubscribeWebhook.js
2
+
3
+ // #pending
4
+ // Add check webhook URL function!
5
+ /**
6
+ * Subscribes to smart contract events and sets up a webhook for notifications.
7
+ *
8
+ * @param {Object} config - Subscription configuration.
9
+ * @param {string} config.name - A name for the webhook subscription.
10
+ * @param {number|string} config.chainId - The chain ID of the blockchain network (e.g., 137 for Polygon).
11
+ * @param {string} config.contractAddress - The address of the deployed smart contract.
12
+ * @param {string} config.thirdwebInsightUrl - The base URL for the Thirdweb Insight API.
13
+ * @param {string[]} config.eventsSignature - An array of event signatures to listen for (e.g., ["Transfer(address,address,uint256)"]).
14
+ * @param {string} config.secretKey - Secret key for authenticating with the Thirdweb Insight.
15
+ * @param {string} config.abi - The contract's ABI (Application Binary Interface), required to decode events.
16
+ * @param {string} config.webhookUrl - The URL where event notifications will be sent.
17
+ * @param {string} config.environment - The Development Environment.
18
+ * @param {string} config.subscriptionType - The type of webhook e.g. "activityType" or "eventType"
19
+ * @returns {Promise<Object>} - Result of the webhook subscription, typically includes subscription ID or status.
20
+ */
21
+ export async function contractSubscribeWebhook({
22
+ chainId,
23
+ contractAddress,
24
+ inhouseStreamUrl,
25
+ eventsSignature,
26
+ webhookUrl,
27
+ environment,
28
+ subscriptionType
29
+ }) {
30
+ try {
31
+ const uri = `${inhouseStreamUrl}/streams/evm`;
32
+ const body = {
33
+ chainId,
34
+ contractAddress,
35
+ eventsSignature,
36
+ webhookUrl,
37
+ environment,
38
+ subscriptionType
39
+ };
40
+ const headers = {
41
+ "Content-Type": "application/json",
42
+ };
43
+ const response = await fetch(uri, {
44
+ method: "POST",
45
+ headers: headers,
46
+ body: JSON.stringify(body),
47
+ });
48
+ const result = await response.json();
49
+ if (!response.ok) {
50
+ throw new Error(`Failed - Webhook Creation for contract: ${JSON.stringify(result)}`);
51
+ }
52
+ return { isSuccess: true, data: { webhookResponse: result } };
53
+ } catch (error) {
54
+ console.log(error)
55
+ return { isSuccess: false, data: `Webhook creation failed: ${JSON.stringify(error.message)}` };
56
+ }
57
+ }
58
+
59
+ // #pending
60
+ /**
61
+ * Updates a Thirdweb Insight Webhook status.
62
+ *
63
+ * @param {string} webhookId – The ID of the webhook to be updated.
64
+ * @param {boolean} disabledFlag – The new status for the webhook, either "true" (to disable) or "false" (to enable).
65
+ * @param {string} inhouseStreamUrl - The base URL for the Thirdweb Insight API.
66
+ * @returns {Promise<{isSuccess: boolean, data: any}>}
67
+ */
68
+ export async function updateWebhookStatus({ streamId, status, inhouseStreamUrl }) {
69
+ if (!streamId || !inhouseStreamUrl || !status) {
70
+ return { isSuccess: false, data: "Missing required parameters" };
71
+ }
72
+ try {
73
+ const uri = `${inhouseStreamUrl}/streams/evm/${streamId}/status`;
74
+ const body = { status };
75
+ const headers = {
76
+ "Content-Type": "application/json"
77
+ };
78
+ const response = await fetch(uri, { method: "POST", headers, body: JSON.stringify(body) });
79
+ if (!response.ok) {
80
+ const errorData = await response.json();
81
+ throw new Error(`UpdateWebhookStatus Failed: ${errorData}`);
82
+ }
83
+ const result = await response.json();
84
+ return { isSuccess: true, data: result };
85
+ } catch (error) {
86
+ return { isSuccess: false, data: JSON.stringify(error) };
87
+ }
88
+ }
package/src/deploy.js ADDED
@@ -0,0 +1,73 @@
1
+ // src/deployNew.js
2
+
3
+ import { createThirdwebClient } from "thirdweb";
4
+ import { deployContract } from "thirdweb/deploys";
5
+ import { engineAccount } from "thirdweb/wallets/engine";
6
+
7
+ /**
8
+ * Deploys a new smart contract using the provided configuration.
9
+ *
10
+ * @param {Object} config - Deployment configuration.
11
+ * @param {string} config.secretKey - The Thirdweb Engine API secret key.
12
+ * @param {string} config.abi - The ABI (Application Binary Interface) of the contract.
13
+ * @param {string} config.bytecode - The compiled bytecode of the contract.
14
+ * @param {object} config.constructorArgs - Constructor arguments required by the contract (e.g., name, symbol, owner).
15
+ * @param {object} config.chain - The Thirdweb chain configuration object (e.g., `80002`).
16
+ * @param {string} config.engineUrl - The thirdweb engine url
17
+ * @param {string} config.backendWalletAddress - The deployer address
18
+ * @param {string} config.authorizationToken - The thirdweb auth key
19
+ * @returns {Promise<string>} - The address of the deployed contract.
20
+ */
21
+ export async function deployNewContract({
22
+ secretKey,
23
+ abi,
24
+ bytecode,
25
+ constructorArgs,
26
+ chain,
27
+ engineUrl,
28
+ backendWalletAddress,
29
+ authorizationToken,
30
+ }) {
31
+ try {
32
+ if (!secretKey || !abi || !bytecode || !chain || !engineUrl || !backendWalletAddress || !authorizationToken) {
33
+ throw new Error("Missing required parameters for deployNewContract");
34
+ }
35
+ const client = createThirdwebClient({ secretKey });
36
+
37
+ const engineAcc = engineAccount({
38
+ engineUrl: engineUrl,
39
+ authToken: authorizationToken,
40
+ walletAddress: backendWalletAddress,
41
+ });
42
+
43
+ const constructorAbi = abi.find(item => item.type === "constructor");
44
+ if (!constructorAbi) {
45
+ const deployedAddress = await deployContract({
46
+ client,
47
+ account: engineAcc,
48
+ chain,
49
+ abi,
50
+ bytecode,
51
+ constructorParams: {}, // Empty if no constructor
52
+ });
53
+ return { deployedAddress };
54
+ }
55
+
56
+ const constructorParams = {};
57
+ constructorAbi.inputs.forEach((input, index) => {
58
+ constructorParams[input.name] = constructorArgs[index];
59
+ });
60
+
61
+ const deployedAddress = await deployContract({
62
+ client,
63
+ account: engineAcc,
64
+ chain,
65
+ abi,
66
+ bytecode,
67
+ constructorParams,
68
+ });
69
+ return { deployedAddress };
70
+ } catch (err) {
71
+ throw new Error(`Failed to deploy contract: ${err.message}`);
72
+ }
73
+ }
@@ -0,0 +1,34 @@
1
+ // Function to check the balance of a blockchain address
2
+ /**
3
+ * Check the balance of a blockchain address through a Thirdweb Engine backend.
4
+ *
5
+ * @param {Object} config
6
+ * @param {string} config.address - Address to check balance for
7
+ * @param {number|string} config.chainId - Chain ID (eg. 80002 for Amoy)
8
+ * @param {string} config.engineUrl - Base URL of your Engine backend (eg. 'https://your-engine.com')
9
+ * @param {string} config.authorizationToken - Bearer token for Engine access
10
+ * @returns {Promise<object>} - Result containing balance in Wei and Eth
11
+ */
12
+
13
+ // #Review Pending
14
+ export const checkBalance = async ({ address, chainId, engineUrl, authorizationToken }) => {
15
+ try {
16
+ const url = `${engineUrl}/backend-wallet/${chainId}/${address}/get-balance`
17
+ const headers = {
18
+ "Content-Type": "application/json",
19
+ Authorization: `Bearer ${authorizationToken}`,
20
+ };
21
+ const response = await fetch(url, { method: "GET", headers });
22
+ if (!response.ok) {
23
+ const errorData = await response.json();
24
+ throw new Error(`${JSON.stringify(errorData)}`);
25
+ }
26
+ const { result } = await response.json();
27
+ const balanceInWei = result.value.toString();
28
+ const balanceInEth = result.displayValue;
29
+
30
+ return { balanceInWei, balanceInEth }
31
+ } catch (error) {
32
+ throw new Error(`failed in checkBalance : ${error}`);
33
+ }
34
+ }
@@ -0,0 +1,34 @@
1
+ // src/getBlockNumberReached.js
2
+
3
+ import { getRpcClient, eth_blockNumber } from 'thirdweb/rpc';
4
+ import { createThirdwebClient } from 'thirdweb';
5
+ import { defineChain } from 'thirdweb/chains';
6
+ /**
7
+ * Checks whether the current block number on the blockchain has reached or surpassed a specified target block number.
8
+ *
9
+ * @param {Object} config - Configuration for the block check.
10
+ * @param {string} config.chainId - The ChainId
11
+ * @param {string} config.clientId - The Thirdweb API clientId used for authentication (if required).
12
+ * @param {number} config.targetBlockNumber - The target block number to compare against.
13
+ * @returns {Promise<boolean>} - Returns `true` if the current block number is greater than or equal to the target, otherwise `false`.
14
+ */
15
+ export async function hasBlockNumberReached({
16
+ chainId,
17
+ clientId,
18
+ targetBlockNumber,
19
+ }) {
20
+ try {
21
+ if (!chainId || !clientId || targetBlockNumber === undefined) {
22
+ throw new Error("Missing required parameters for hasBlockNumberReached");
23
+ }
24
+ const chain = defineChain(Number(chainId));
25
+ const client = createThirdwebClient({
26
+ clientId: clientId,
27
+ });
28
+ const rpcRequest = getRpcClient({ client, chain });
29
+ const currentBlock = await eth_blockNumber(rpcRequest);
30
+ return currentBlock >= targetBlockNumber;
31
+ } catch (err) {
32
+ throw new Error(`Failed to check block number reached: ${err.message}`);
33
+ }
34
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Finds the deployment transaction hash for a given smart contract address on a specific blockchain.
3
+ *
4
+ * @param {string} contractAddress - The address of the deployed smart contract.
5
+ * @param {number|string} chainId - The chain ID of the blockchain network (e.g., 1 for Ethereum Mainnet, 137 for Polygon).
6
+ * @param {string} etherscanAPI - The API key for Etherscan or an Etherscan-compatible explorer used to query transactions.
7
+ * @returns {Promise<string|null>} - The transaction hash of the contract deployment, or `null` if not found.
8
+ */
9
+ export async function findDeploymentTxHash(contractAddress, chainId, etherscanAPI) {
10
+ try {
11
+ const apiUrl = `https://api.etherscan.io/v2/api?chainid=${chainId}&module=contract&action=getcontractcreation&contractaddresses=${contractAddress}&apikey=${etherscanAPI}`;
12
+ const response = await fetch(apiUrl);
13
+ if (!response.ok) {
14
+ const errorData = await response.json();
15
+ throw new Error(`Failed to fetch contract creation info: ${JSON.stringify(errorData)}`);
16
+ }
17
+ const { result, status } = await response.json();
18
+ if (status != '1' || result.length === 0) {
19
+ throw new Error("Failed to retrieve hash!");
20
+ }
21
+ return { isSuccess: true, data: { txHash: result[0].txHash, blockNumber: result[0].blockNumber } };
22
+ } catch (err) {
23
+ return { isSuccess: false, data: err.message }
24
+ }
25
+ }
@@ -0,0 +1,67 @@
1
+ // src/getEvents.js
2
+ import axios from "axios";
3
+ import https from "https";
4
+
5
+ /**
6
+ * Fetch events from a Thirdweb Engine backend between specific blocks.
7
+ *
8
+ * @param {Object} config
9
+ * @param {string} config.thirdwebInsightUrl - Thirdweb Insight base URL (eg. https://insight.thirdweb.com/v1)
10
+ * @param {number|string} config.chainId - Chain ID (eg. 80002 for Amoy)
11
+ * @param {string} config.contractAddress - Smart contract address
12
+ * @param {string} config.eventName - Name of the event to fetch
13
+ * @param {number|string} config.fromBlock - Starting block number
14
+ * @param {number|string} [config.toBlock] - Ending block number (default: 'latest')
15
+ * @param {object} [config.filters] - Optional filters object
16
+ * @param {string} config.clientId - Thirdweb Insight Client Id
17
+ * @param {number} config.limit - Number of events to fetch per page
18
+ * @param {number} config.page - Page number for pagination
19
+ * @returns {Promise<object>} - Events response
20
+ */
21
+ export async function fetchContractEvents({
22
+ thirdwebInsightUrl,
23
+ chainId,
24
+ contractAddress,
25
+ eventSignature,
26
+ fromBlock,
27
+ toBlock = "latest",
28
+ filters = {},
29
+ clientId,
30
+ limit,
31
+ page,
32
+ }) {
33
+ if (
34
+ thirdwebInsightUrl == null ||
35
+ chainId == null ||
36
+ contractAddress == null ||
37
+ eventSignature == null ||
38
+ fromBlock == null ||
39
+ toBlock == null ||
40
+ clientId == null ||
41
+ limit == null ||
42
+ page == null
43
+ ) {
44
+ throw new Error("Missing required parameters for fetchContractEvents");
45
+ }
46
+ const agent = new https.Agent({
47
+ rejectUnauthorized: false,
48
+ });
49
+ const url = `${thirdwebInsightUrl}/events/${contractAddress}/${eventSignature}`;
50
+ const params = {
51
+ chain_id: chainId,
52
+ filter_block_number_gte: fromBlock,
53
+ filter_block_number_lte: toBlock,
54
+ sort_order: "asc",
55
+ limit: limit,
56
+ page: page,
57
+ };
58
+ const headers = {
59
+ "x-client-id": clientId,
60
+ };
61
+ try {
62
+ const response = await axios.get(url, { params, headers });
63
+ return response.data;
64
+ } catch (error) {
65
+ throw new Error(`Failed to fetch events: ${error.response?.data?.error || error.message}`);
66
+ }
67
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Finds the deployment transaction hash for a given smart contract address on a specific blockchain.
3
+ *
4
+ * @param {string} contractAddress - The address of the deployed smart contract.
5
+ * @param {number|string} chainId - The chain ID of the blockchain network (e.g., 1 for Ethereum Mainnet, 137 for Polygon).
6
+ * @param {string} apiKey - The API key Moralis
7
+ * @returns {Promise<object|null>} - Returns { tokenName, tokenSymbol, usdPrice }.
8
+ */
9
+ export async function fetchTokenLatestPrice({ contractAddress, chainId, apiKey }) {
10
+ try {
11
+ if (!contractAddress || !chainId || !apiKey) {
12
+ throw new Error("Missing required parameters for fetchTokenLatestPrice");
13
+ }
14
+ const hexChainId = '0x' + chainId.toString(16);
15
+ const headers = {
16
+ "Content-Type": "application/json",
17
+ "x-api-key": apiKey,
18
+ };
19
+ const apiUrl = `https://deep-index.moralis.io/api/v2.2/erc20/${contractAddress}/price?chain=${hexChainId}&include=percent_change`;
20
+ const response = await fetch(apiUrl, {
21
+ method: 'GET',
22
+ headers: headers
23
+ });
24
+ if (!response.ok) {
25
+ const errorData = await response.json();
26
+ throw new Error(`Fetching price failed: ${JSON.stringify(errorData)}`);
27
+ }
28
+ const { usdPrice, tokenName, tokenSymbol } = await response.json();
29
+ return { tokenName, tokenSymbol, usdPrice };
30
+ } catch (err) {
31
+ throw new Error(`Failed to fetch latest price for ${contractAddress} at ${chainId} : ${err.message}`);
32
+ }
33
+ }
@@ -0,0 +1,46 @@
1
+ // src/getTokenPrice.js
2
+
3
+ import { createThirdwebClient, getContract, readContract } from 'thirdweb';
4
+ import { defineChain } from 'thirdweb/chains';
5
+
6
+ /**
7
+ * Fetches the latest token price from a Chainlink oracle on the specified blockchain.
8
+ *
9
+ * @param {Object} params - Parameters for retrieving the token price.
10
+ * @param {string} params.chainlinkOracleAddress - The address of the Chainlink price feed oracle contract.
11
+ * @param {number} params.chainlinkOracleChainId - The chain ID of the blockchain where the oracle contract is deployed.
12
+ * @param {string} params.clientId - The Thirdweb client ID used for authenticated RPC requests.
13
+ * @returns {Promise<string>} - Returns the latest token price as a string.
14
+ */
15
+ export async function getTokenPrice({
16
+ chainlinkOracleAddress,
17
+ chainlinkOracleChainId,
18
+ clientId
19
+ }) {
20
+ try {
21
+ if (!(chainlinkOracleAddress && chainlinkOracleChainId)) {
22
+ throw new Error("Missing required parameters for getTokenPrice");
23
+ }
24
+ const client = createThirdwebClient({ clientId: clientId });
25
+ const chain = defineChain(Number(chainlinkOracleChainId));
26
+ const contract = getContract({
27
+ client,
28
+ chain: chain,
29
+ address: chainlinkOracleAddress,
30
+ });
31
+ const decimals = Number(await readContract({
32
+ contract,
33
+ method: "function decimals() view returns (uint8)",
34
+ params: [],
35
+ }));
36
+ const latestPrice = Number(await readContract({
37
+ contract,
38
+ method: "function latestAnswer() view returns (int256)",
39
+ params: [],
40
+ }));
41
+ const priceInUsd = latestPrice / Math.pow(10, decimals);
42
+ return priceInUsd;
43
+ } catch (err) {
44
+ throw new Error(`Failed getting token price ${err.message}`);
45
+ }
46
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Retrieve the transaction hash from Thirdweb Engine using the queueId.
3
+ * Retries until the transactionHash is available or max attempts are reached.
4
+ *
5
+ * @param {string} queueId - The queue ID returned after submitting the transaction
6
+ * @param {string} authorizationToken - Bearer token to authorize the request
7
+ * @param {string} engineUrl - Base URL of the Thirdweb Engine
8
+ * @param {number} [maxAttempts=10] - Maximum number of retry attempts
9
+ * @param {number} [delayMs=3000] - Delay in milliseconds between attempts
10
+ * @returns {Promise<Object>} - TransactionHash if available
11
+ */
12
+ export async function getTransactionHash({ queueId, engineUrl, authorizationToken, maxAttempts = 10, delayMs = 3000 }) {
13
+ if (!queueId || !authorizationToken || !engineUrl) {
14
+ throw new Error("Missing required parameters for getTransactionHash");
15
+ }
16
+ const writeUrl = `${engineUrl}/transaction/status/${queueId}`;
17
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
18
+ try {
19
+ const response = await fetch(writeUrl, {
20
+ method: "GET",
21
+ headers: {
22
+ accept: "application/json",
23
+ Authorization: `Bearer ${authorizationToken}`,
24
+ },
25
+ });
26
+ if (!response.ok) {
27
+ throw new Error(`HTTP error! status: ${response.status}`);
28
+ }
29
+ const result = await response.json();
30
+ if (result.result?.transactionHash) {
31
+ return result.result.transactionHash;
32
+ }
33
+ if (attempt < maxAttempts) {
34
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
35
+ } else {
36
+ throw new Error("Transaction hash not available after maximum retries.");
37
+ }
38
+ } catch (error) {
39
+ if (attempt === maxAttempts) {
40
+ throw new Error("Failed to fetch transaction hash after multiple attempts.");
41
+ }
42
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
43
+ }
44
+ }
45
+ }
package/src/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export { deployNewContract } from "./deploy.js";
2
+ export { writeTransaction } from "./writeTransaction.js";
3
+ export { fetchContractEvents } from "./getEvents.js";
4
+ export { hasBlockNumberReached } from "./getBlockNumberReached.js";
5
+ export { contractSubscribeWebhook, updateWebhookStatus } from "./contractSubscribeWebhook.js";
6
+ export { getTransactionHash } from "./getTransactionHash.js";
7
+ export { fetchTokenLatestPrice } from "./getTokenLatestPrice.js";
8
+ export { getTokenPrice } from "./getTokenPrice.js";
9
+ export { findDeploymentTxHash } from "./getCreatorTxHash.js";
10
+ export { readTransaction } from "./readTransaction.js";
11
+ export { checkBalance } from "./getBalance.js";
12
+ export { transferFunds } from "./transfer.js";
@@ -0,0 +1,36 @@
1
+ // src/readTransaction.js
2
+
3
+ /**
4
+ * Reads data from a smart contract using Thirdweb SDK.
5
+ *
6
+ * @param {Object} config
7
+ * @param {string} config.engineUrl - Base URL of your Engine backend (eg. 'https://your-engine.com')
8
+ * @param {number|string} config.chainId - Chain ID (eg. 80002 for Amoy)
9
+ * @param {string} config.contractAddress - Smart contract address
10
+ * @param {string} config.functionName - Full function signature (eg. 'function mint(address,uint256)')
11
+ * @param {string} config.args - Function arguments
12
+ * @param {string} config.authorizationToken - Bearer token for Engine access
13
+ * @returns {Promise<object>} - Result of the read transaction
14
+ */
15
+ export async function readTransaction({ engineUrl, chainId, contractAddress, functionName, args, authorizationToken }) {
16
+ try {
17
+ if (!engineUrl || !chainId || !contractAddress || !functionName || !authorizationToken) {
18
+ throw new Error("Missing required parameters for readTransaction");
19
+ }
20
+ const readUrl = `${engineUrl}/contract/${chainId}/${contractAddress}/read`;
21
+ const headers = {
22
+ "Content-Type": "application/json",
23
+ Authorization: `Bearer ${authorizationToken}`,
24
+ };
25
+ const url = `${readUrl}?functionName=${encodeURIComponent(functionName)}&args=${encodeURIComponent(args)}`;
26
+ const response = await fetch(url, { method: "GET", headers });
27
+ if (!response.ok) {
28
+ const errorData = await response.json();
29
+ throw new Error(`Transaction read failed: ${JSON.stringify(errorData)}`);
30
+ }
31
+ const { result } = await response.json();
32
+ return result;
33
+ } catch (err) {
34
+ throw new Error(`Failed to read transaction: ${err.message}`);
35
+ }
36
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Transfer funds through a Thirdweb Engine backend.
3
+ *
4
+ * @param {Object} config
5
+ * @param {string} config.recipient - Recipient address
6
+ * @param {number|string} config.chainId - Chain ID (eg. 80002 for Amoy)
7
+ * @param {number|string} config.amount - Amount to transfer
8
+ * @param {string} config.engineUrl - Base URL of your Engine backend (eg. 'https://your-engine.com')
9
+ * @param {string} config.authorizationToken - Bearer token for Engine access
10
+ * @param {string} config.backendWalletAddress - Address of backend signer wallet
11
+ * @returns {Promise<object>} - Result of the transfer transaction
12
+ */
13
+
14
+ // #Review Pending
15
+ export const transferFunds = async ({ recipient, chainId, amount, engineUrl, authorizationToken, backendWalletAddress }) => {
16
+ try {
17
+ if ((amount) > 1) {
18
+ throw new Error(`More than 1 Eth not supported!`);
19
+ }
20
+
21
+ const url = `${engineUrl}/backend-wallet/${chainId}/transfer`
22
+ const headers = {
23
+ "Content-Type": "application/json",
24
+ Authorization: `Bearer ${authorizationToken}`,
25
+ "x-backend-wallet-address": backendWalletAddress,
26
+ "x-idempotency-key": `idemp-${Date.now()}`,
27
+ };
28
+ const body = JSON.stringify({
29
+ to: recipient,
30
+ currencyAddress: "0x0000000000000000000000000000000000000000",
31
+ amount: amount
32
+ });
33
+
34
+ const response = await fetch(url, { method: "POST", headers, body });
35
+ if (!response.ok) {
36
+ const errorData = await response.json();
37
+ throw new Error(`${JSON.stringify(errorData)}`);
38
+ }
39
+ const { result } = await response.json();
40
+ return result
41
+ } catch (error) {
42
+ throw new Error(`Failed to transfer: ${error}`);
43
+
44
+ }
45
+
46
+ }
@@ -0,0 +1,55 @@
1
+ // src/writeTransaction.js
2
+ import { Agent, setGlobalDispatcher } from "undici";
3
+
4
+ const agent = new Agent({
5
+ connect: {
6
+ rejectUnauthorized: false,
7
+ },
8
+ });
9
+ setGlobalDispatcher(agent);
10
+
11
+ /**
12
+ * Write a transaction through a Thirdweb Engine backend.
13
+ *
14
+ * @param {Object} config
15
+ * @param {string} config.engineUrl - Base URL of your Engine backend (eg. 'https://your-engine.com')
16
+ * @param {number|string} config.chainId - Chain ID (eg. 80002 for Amoy)
17
+ * @param {string} config.contractAddress - Smart contract address
18
+ * @param {string} config.functionName - Full function signature (eg. 'function mint(address,uint256)')
19
+ * @param {Array} config.args - Function arguments
20
+ * @param {string} config.backendWalletAddress - Address of backend signer wallet
21
+ * @param {string} config.authorizationToken - Bearer token for Engine access
22
+ * @returns {Promise<object>} - Result of the write transaction
23
+ */
24
+ export async function writeTransaction({
25
+ engineUrl,
26
+ chainId,
27
+ contractAddress,
28
+ functionName,
29
+ args,
30
+ backendWalletAddress,
31
+ authorizationToken,
32
+ }) {
33
+ try {
34
+ if (!engineUrl || !chainId || !contractAddress || !functionName || !args || !backendWalletAddress || !authorizationToken) {
35
+ throw new Error("Missing required parameters for writeTransaction");
36
+ }
37
+ const writeUrl = `${engineUrl}/contract/${chainId}/${contractAddress}/write`;
38
+ const headers = {
39
+ "Content-Type": "application/json",
40
+ Authorization: `Bearer ${authorizationToken}`,
41
+ "x-backend-wallet-address": backendWalletAddress,
42
+ "x-idempotency-key": `idemp-${Date.now()}`,
43
+ };
44
+ const body = JSON.stringify({ functionName, args });
45
+ const response = await fetch(writeUrl, { method: "POST", headers, body });
46
+ if (!response.ok) {
47
+ const errorData = await response.json();
48
+ throw new Error(`Transaction write failed: ${JSON.stringify(errorData)}`);
49
+ }
50
+ const { result } = await response.json();
51
+ return result;
52
+ } catch (err) {
53
+ throw new Error(`Failed to write transaction: ${err.message}`);
54
+ }
55
+ }