|
| 1 | +# Migrating from Engine v2 to v3 |
| 2 | + |
| 3 | +This guide outlines the key changes required to migrate your applications from Engine v2 to Engine v3. We'll cover common operations and highlight the differences in API requests and authentication. |
| 4 | + |
| 5 | +## Writing to a contract |
| 6 | + |
| 7 | +Migrating your contract write operations from v2 to v3 involves changes to the endpoint, authentication mechanism, and request payload structure. |
| 8 | + |
| 9 | +#### OLD (v2) |
| 10 | + |
| 11 | +The v2 approach used your dedicated engine url, with a specific endpoint for each chain and contract and backend wallet address in the header. |
| 12 | + |
| 13 | +```bash |
| 14 | +curl -X POST "<engine_url>/contract/<chain>/<contract_address>/write" \ |
| 15 | + -H "Content-Type: application/json" \ |
| 16 | + -H "Authorization: Bearer <access_token>" \ |
| 17 | + -H "x-backend-wallet-address: <backend_wallet_address>" \ |
| 18 | + -d '{ |
| 19 | + "functionName": "function transferFrom(address from, address to, uint256 amount)", |
| 20 | + "args": [ |
| 21 | + "0x1946267d81Fb8aDeeEa28e6B98bcD446c8248473", |
| 22 | + "0x3EcDBF3B911d0e9052b64850693888b008e18373", |
| 23 | + "0" |
| 24 | + ] |
| 25 | + }' |
| 26 | +``` |
| 27 | + |
| 28 | +#### NEW (v3) |
| 29 | + |
| 30 | +The v3 approach uses a generic POST endpoint, with authentication via secret key and vault access token. Contract, chain, and execution details are now part of a structured JSON payload. |
| 31 | + |
| 32 | +```bash |
| 33 | +curl -X POST "https://engine.thirdweb.com/v1/write/contract" \ |
| 34 | + -H "Content-Type: application/json" \ |
| 35 | + -H "x-secret-key: <your-project-secret-key>" \ |
| 36 | + -H "x-vault-access-token: <your-vault-access-token>" \ |
| 37 | + -d '{ |
| 38 | + "executionOptions": { |
| 39 | + "from": "<your-server-wallet-address>", |
| 40 | + "chainId": "84532" |
| 41 | + }, |
| 42 | + "params": [ |
| 43 | + { |
| 44 | + "contractAddress": "0x...", |
| 45 | + "method": "function transferFrom(address from, address to, uint256 amount)", |
| 46 | + "params": [ |
| 47 | + "0x1946267d81Fb8aDeeEa28e6B98bcD446c8248473", |
| 48 | + "0x3EcDBF3B911d0e9052b64850693888b008e18373", |
| 49 | + "0" |
| 50 | + ] |
| 51 | + } |
| 52 | + ] |
| 53 | + }' |
| 54 | +``` |
| 55 | + |
| 56 | +#### Key Differences: |
| 57 | + |
| 58 | +* **API Endpoint:** The endpoint has changed from a specific path per chain and contract (`<engine_url>/contract/<chain>/<contract_address>/write`) to a general endpoint (`https://engine.thirdweb.com/v1/write/contract`). |
| 59 | +* **Authentication:** |
| 60 | + * V2 used an `Authorization: Bearer <access_token>` header for general API access and an `x-backend-wallet-address` header to specify the sender. |
| 61 | + * V3 uses an `x-secret-key` header (your project's secret key, found in your thirdweb dashboard) for authentication. Your backend wallet is managed by thirdweb Vault, an `x-vault-access-token` header is required for all write operations. |
| 62 | +* **Request Structure:** |
| 63 | + * **Sender & Chain:** In V2, the sender wallet was a header, and the chain was part of the URL. In V3, these are specified in the request body within an `executionOptions` object: `from` for the sender wallet address and `chainId` for the target chain. |
| 64 | + * **Contract Call:** V2 took `functionName` and `args` directly in the body. V3 uses a `params` array in the request body. Each element in this array is an object defining the target `contractAddress`, the partial or full `method` signature (e.g., `"function mintTo(address to, uint256 amount)"`), and the `params` (arguments) for that method. |
| 65 | +* **Function Specification:** While V3 supports using just the method name (e.g., "transferFrom") in the `method` field, providing the full function signature (e.g., "function transferFrom(address from, address to, uint256 amount)") is highly recommended for optimal performance as it avoids an ABI lookup. V2 only required the `functionName`. |
| 66 | + |
| 67 | +--- |
| 68 | + |
| 69 | +## Check the status of a transaction |
| 70 | + |
| 71 | +Querying transaction status has also been updated, moving from a direct ID lookup via GET to a POST request with a filter-based search. |
| 72 | + |
| 73 | +#### OLD (v2) |
| 74 | + |
| 75 | +In v2, transaction status was fetched using a GET request with the `queue_id` in the URL. |
| 76 | + |
| 77 | +```bash |
| 78 | +curl -X GET "<engine_url>/transaction/status/<queue_id>" \ |
| 79 | + -H "Authorization: Bearer <access_token>" |
| 80 | +``` |
| 81 | + |
| 82 | +#### NEW (v3) |
| 83 | + |
| 84 | +V3 uses a search endpoint with a POST request, where transaction identifiers are passed in the request body using filters. |
| 85 | + |
| 86 | +```bash |
| 87 | +curl --location 'https://engine.thirdweb.com/v1/transactions/search' \ |
| 88 | +--header 'x-secret-key: <your-project-secret-key>' \ |
| 89 | +--header 'Content-Type: application/json' \ |
| 90 | +--data '{ |
| 91 | + "filters": [ |
| 92 | + { |
| 93 | + "field": "id", |
| 94 | + "values": [ |
| 95 | + "750cb3eb-d297-4d8e-8d29-76dea99ba294" // transaction id |
| 96 | + ], |
| 97 | + "operation": "OR" |
| 98 | + } |
| 99 | + ] |
| 100 | +}' |
| 101 | +``` |
| 102 | + |
| 103 | +#### Key Differences: |
| 104 | + |
| 105 | +* **API Endpoint & Method:** The V2 `GET` endpoint (`<engine_url>/transaction/status/<queue_id>`) is replaced by a V3 `POST` endpoint (`https://engine.thirdweb.com/v1/transactions/search`). |
| 106 | +* **Authentication:** |
| 107 | + * V2 used an `Authorization: Bearer <access_token>` header. |
| 108 | + * V3 uses an `x-secret-key` header (your project's secret key). |
| 109 | +* **Querying Transaction Status:** |
| 110 | + * In V2, the `queue_id` was passed directly in the URL path. |
| 111 | + * In V3, you send a `POST` request with a JSON body containing a `filters` array. To find a specific transaction, you filter by its `id` (the equivalent of V2's `queue_id`). This filter-based approach is more flexible for querying transactions based on various criteria. |
| 112 | + |
| 113 | +--- |
| 114 | + |
| 115 | +## Reading from a contract |
| 116 | + |
| 117 | +Reading data from a smart contract has also been updated in v3, shifting from URL-based parameters to a structured JSON payload over POST. |
| 118 | + |
| 119 | +#### OLD (v2) |
| 120 | + |
| 121 | +In v2, contract reads were GET requests. The chain, contract address, function name, and arguments were specified in the URL path and query parameters. |
| 122 | + |
| 123 | +```bash |
| 124 | +curl -X GET "<engine_url>/contract/<chain>/<contract_address>/read?functionName=balanceOf&args=0x3EcDBF3B911d0e9052b64850693888b008e18373" \ |
| 125 | + -H "Authorization: Bearer <access_token>" |
| 126 | +``` |
| 127 | + |
| 128 | +#### NEW (v3) |
| 129 | + |
| 130 | +V3 uses a POST request to a dedicated read endpoint. All parameters, including chain, contract details, method signature, and arguments, are provided in the JSON body. |
| 131 | + |
| 132 | +```bash |
| 133 | +curl https://engine.thirdweb.com/v1/read/contract \ |
| 134 | + --request POST \ |
| 135 | + --header 'Content-Type: application/json' \ |
| 136 | + --header 'x-secret-key: <your-project-secret-key>' \ |
| 137 | + --data '{ |
| 138 | + "params": [ |
| 139 | + { |
| 140 | + "contractAddress": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", |
| 141 | + "method": "function balanceOf(address account) returns (uint256)", |
| 142 | + "params": [ |
| 143 | + "0xeb0effdfb4dc5b3d5d3ac6ce29f3ed213e95d675" |
| 144 | + ] |
| 145 | + } |
| 146 | + ], |
| 147 | + "readOptions": { |
| 148 | + "chainId": "84532" |
| 149 | + } |
| 150 | +}' |
| 151 | +``` |
| 152 | + |
| 153 | +#### Key Differences: |
| 154 | + |
| 155 | +* **API Endpoint & Method:** |
| 156 | + * V2 used a `GET` request to `<engine_url>/contract/<chain>/<contract_address>/read` with function details as query parameters. |
| 157 | + * V3 uses a `POST` request to the generic endpoint `https://engine.thirdweb.com/v1/read/contract`. |
| 158 | +* **Authentication:** |
| 159 | + * V2 used an `Authorization: Bearer <access_token>` header. |
| 160 | + * V3 uses an `x-secret-key: <your-project-secret-key>` header. |
| 161 | +* **Request Structure:** |
| 162 | + * In V2, the chain and contract address were part of the URL path, and the function name (`functionName`) and its arguments (`args`) were URL query parameters. |
| 163 | + * In V3, the request body is a JSON object. It includes a `params` array (where each object specifies `contractAddress`, the partial or full `method` signature, and its `params`) and a `readOptions` object to specify the `chainId`. |
| 164 | +* **Function Specification:** Similar to contract writes, while V3 supports using just the method name (e.g., "balanceOf") in the `method` field, providing the full function signature (e.g., "function balanceOf(address account) returns (uint256)") is highly recommended for optimal performance as it avoids an ABI lookup. V2 primarily used just the function name in the `functionName` query parameter. |
| 165 | + |
| 166 | +--- |
| 167 | + |
| 168 | +## Extension functions |
| 169 | + |
| 170 | +Engine v2 has a large number of endpoints to do specific contract calls, like mintTo, claimTo, etc. |
| 171 | + |
| 172 | +Engine v3 does not have these endpoints yet, but they are coming soon. In the meantime, if your backend is written in typescript, we recommend using the [thirdweb SDK](/references/typescript/v5/functions#extensions) to do these operations: |
| 173 | + |
| 174 | +##### OLD (v2) |
| 175 | + |
| 176 | +```ts |
| 177 | +const response = await fetch( |
| 178 | +"<engine_url>/contract/<chain_id>/<nft_contract_address>/erc1155/mint-to", |
| 179 | +{ |
| 180 | + method: "POST", |
| 181 | + headers: { |
| 182 | + "Content-Type": "application/json", |
| 183 | + Authorization: "Bearer <thirdweb_secret_key>", |
| 184 | + "x-backend-wallet-address": "<backend_wallet_address>", |
| 185 | + }, |
| 186 | + body: JSON.stringify({ |
| 187 | + receiver: "0x...", |
| 188 | + metadataWithSupply: { |
| 189 | + metadata: { |
| 190 | + name: "Acme Inc. Superfan", |
| 191 | + description: "Created with thirdweb Engine", |
| 192 | + image: |
| 193 | + "ipfs://QmciR3WLJsf2BgzTSjbG5zCxsrEQ8PqsHK7JWGWsDSNo46/nft.png", |
| 194 | + }, |
| 195 | + supply: "1", |
| 196 | + }, |
| 197 | + }), |
| 198 | +}, |
| 199 | +); |
| 200 | +const data = await response.json(); |
| 201 | +const queueId = data.queueId; |
| 202 | +``` |
| 203 | + |
| 204 | +#### NEW (v3) - using the thirdweb SDK |
| 205 | + |
| 206 | +```ts |
| 207 | +// Create a thirdweb client |
| 208 | +const client = createThirdwebClient({ |
| 209 | + secretKey: "<your-project-secret-key>", |
| 210 | +}); |
| 211 | + |
| 212 | +// Create a server wallet |
| 213 | +const serverWallet = Engine.serverWallet({ |
| 214 | + client, |
| 215 | + address: "<your-server-wallet-address>", |
| 216 | + vaultAccessToken: "<your-vault-access-token>", |
| 217 | +}); |
| 218 | + |
| 219 | +// instead of a dedicated endpoint, you can use the thirdweb SDK to do the operation |
| 220 | +const transaction = mintTo({ |
| 221 | + contract: getContract({ |
| 222 | + client, |
| 223 | + address: "<nft_contract_address>", // Address of the ERC1155 token contract |
| 224 | + chain: baseSepolia, // Chain of the ERC1155 token contract |
| 225 | + }), |
| 226 | + to: "0x...", // The address of the user to mint to |
| 227 | + supply: 1n, // The quantity of NFTs to mint |
| 228 | + nft: { |
| 229 | + name: "Acme Inc. Superfan", |
| 230 | + description: "Created with thirdweb Engine", |
| 231 | + image: |
| 232 | + "ipfs://QmciR3WLJsf2BgzTSjbG5zCxsrEQ8PqsHK7JWGWsDSNo46/nft.png", |
| 233 | + }, |
| 234 | +}); |
| 235 | + |
| 236 | +// Enqueue the transaction via Engine |
| 237 | +const { transactionId } = |
| 238 | + await serverWallet.enqueueTransaction({ |
| 239 | + transaction, |
| 240 | + }); |
| 241 | +``` |
| 242 | + |
| 243 | +The entire thirdweb SDK is available to use with engine v3 in this manner using the [`Engine` namespace](/references/typescript/v5/functions#engine). Check the [thirdweb SDK docs](/references/typescript/v5/functions#extensions) for all available functions. |
0 commit comments