Skip to content

Commit 64964da

Browse files
gregfromstlclaudejoaquim-vergeskumaryash90d4mr
authored
[SDK] Refactor: Update Pay Functions to use UB (#7064)
Signed-off-by: samina <[email protected]> Signed-off-by: Maximilian Hubert <[email protected]> Co-authored-by: Claude <[email protected]> Co-authored-by: Joaquim Verges <[email protected]> Co-authored-by: kumaryash90 <[email protected]> Co-authored-by: Prithvish Baidya <[email protected]> Co-authored-by: samina <[email protected]> Co-authored-by: Maximilian Hubert <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Jonas Daniels <[email protected]> Co-authored-by: arcoraven <[email protected]>
1 parent 260c2fd commit 64964da

39 files changed

+1348
-886
lines changed

.changeset/open-readers-do.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Faster useSendTransaction execution

.changeset/stale-yaks-bathe.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
---
2+
"thirdweb": minor
3+
---
4+
5+
Adds Bridge.Transfer module for direct token transfers:
6+
7+
```typescript
8+
import { Bridge, NATIVE_TOKEN_ADDRESS } from "thirdweb";
9+
10+
const quote = await Bridge.Transfer.prepare({
11+
chainId: 1,
12+
tokenAddress: NATIVE_TOKEN_ADDRESS,
13+
amount: toWei("0.01"),
14+
sender: "0x...",
15+
receiver: "0x...",
16+
client: thirdwebClient,
17+
});
18+
```
19+
20+
This will return a quote that might look like:
21+
```typescript
22+
{
23+
originAmount: 10000026098875381n,
24+
destinationAmount: 10000000000000000n,
25+
blockNumber: 22026509n,
26+
timestamp: 1741730936680,
27+
estimatedExecutionTimeMs: 1000
28+
steps: [
29+
{
30+
originToken: {
31+
chainId: 1,
32+
address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
33+
symbol: "ETH",
34+
name: "Ethereum",
35+
decimals: 18,
36+
priceUsd: 2000,
37+
iconUri: "https://..."
38+
},
39+
destinationToken: {
40+
chainId: 1,
41+
address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
42+
symbol: "ETH",
43+
name: "Ethereum",
44+
decimals: 18,
45+
priceUsd: 2000,
46+
iconUri: "https://..."
47+
},
48+
originAmount: 10000026098875381n,
49+
destinationAmount: 10000000000000000n,
50+
estimatedExecutionTimeMs: 1000
51+
transactions: [
52+
{
53+
action: "approval",
54+
id: "0x",
55+
to: "0x...",
56+
data: "0x...",
57+
chainId: 1,
58+
type: "eip1559"
59+
},
60+
{
61+
action: "transfer",
62+
to: "0x...",
63+
value: 10000026098875381n,
64+
data: "0x...",
65+
chainId: 1,
66+
type: "eip1559"
67+
}
68+
]
69+
}
70+
],
71+
expiration: 1741730936680,
72+
intent: {
73+
chainId: 1,
74+
tokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
75+
amount: 10000000000000000n,
76+
sender: "0x...",
77+
receiver: "0x..."
78+
}
79+
}
80+
```
81+
82+
## Sending the transactions
83+
The `transactions` array is a series of [ox](https://oxlib.sh) EIP-1559 transactions that must be executed one after the other in order to fulfill the complete route. There are a few things to keep in mind when executing these transactions:
84+
- Approvals will have the `approval` action specified. You can perform approvals with `sendAndConfirmTransaction`, then proceed to the next transaction.
85+
- All transactions are assumed to be executed by the `sender` address, regardless of which chain they are on. The final transaction will use the `receiver` as the recipient address.
86+
- If an `expiration` timestamp is provided, all transactions must be executed before that time to guarantee successful execution at the specified price.
87+
88+
NOTE: To get the status of each non-approval transaction, use `Bridge.status` rather than checking for transaction inclusion. This function will ensure full completion of the transfer.
89+
90+
You can include arbitrary data to be included on any webhooks and status responses with the `purchaseData` option:
91+
92+
```ts
93+
const quote = await Bridge.Transfer.prepare({
94+
chainId: 1,
95+
tokenAddress: NATIVE_TOKEN_ADDRESS,
96+
amount: toWei("0.01"),
97+
sender: "0x...",
98+
receiver: "0x...",
99+
purchaseData: {
100+
reference: "payment-123",
101+
metadata: {
102+
note: "Transfer to Alice"
103+
}
104+
},
105+
client: thirdwebClient,
106+
});
107+
```
108+
109+
## Fees
110+
There may be fees associated with the transfer. These fees are paid by the `feePayer` address, which defaults to the `sender` address. You can specify a different address with the `feePayer` option. If you do not specify an option or explicitly specify `sender`, the fees will be added to the input amount. If you specify the `receiver` as the fee payer the fees will be subtracted from the destination amount.
111+
112+
For example, if you were to request a transfer with `feePayer` set to `receiver`:
113+
```typescript
114+
const quote = await Bridge.Transfer.prepare({
115+
chainId: 1,
116+
tokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
117+
amount: 100_000_000n, // 100 USDC
118+
sender: "0x...",
119+
receiver: "0x...",
120+
feePayer: "receiver",
121+
client: thirdwebClient,
122+
});
123+
```
124+
125+
The returned quote might look like:
126+
```typescript
127+
{
128+
originAmount: 100_000_000n, // 100 USDC
129+
destinationAmount: 99_970_000n, // 99.97 USDC
130+
...
131+
}
132+
```
133+
134+
If you were to request a transfer with `feePayer` set to `sender`:
135+
```typescript
136+
const quote = await Bridge.Transfer.prepare({
137+
chainId: 1,
138+
tokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
139+
amount: 100_000_000n, // 100 USDC
140+
sender: "0x...",
141+
receiver: "0x...",
142+
feePayer: "sender",
143+
client: thirdwebClient,
144+
});
145+
```
146+
147+
The returned quote might look like:
148+
```typescript
149+
{
150+
originAmount: 100_030_000n, // 100.03 USDC
151+
destinationAmount: 100_000_000n, // 100 USDC
152+
...
153+
}
154+
```

apps/dashboard/src/@/constants/thirdweb.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
NEXT_PUBLIC_IPFS_GATEWAY_URL,
44
} from "@/constants/public-envs";
55
import {
6+
THIRDWEB_BRIDGE_URL,
67
THIRDWEB_BUNDLER_DOMAIN,
78
THIRDWEB_INAPP_WALLET_DOMAIN,
89
THIRDWEB_INSIGHT_API_DOMAIN,
@@ -35,6 +36,7 @@ export function getConfiguredThirdwebClient(options: {
3536
social: THIRDWEB_SOCIAL_API_DOMAIN,
3637
bundler: THIRDWEB_BUNDLER_DOMAIN,
3738
insight: THIRDWEB_INSIGHT_API_DOMAIN,
39+
bridge: THIRDWEB_BRIDGE_URL,
3840
});
3941
}
4042

apps/dashboard/src/constants/urls.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ export const THIRDWEB_INSIGHT_API_DOMAIN =
2626

2727
export const THIRDWEB_ANALYTICS_DOMAIN =
2828
process.env.NEXT_PUBLIC_ANALYTICS_URL || "c.thirdweb-dev.com";
29+
30+
export const THIRDWEB_BRIDGE_URL =
31+
process.env.NEXT_PUBLIC_BRIDGE_URL || "bridge.thirdweb-dev.com";

apps/login/src/lib/dev-mode.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { setThirdwebDomains } from "thirdweb/utils";
22
import {
3+
THIRDWEB_BRIDGE_DOMAIN,
34
THIRDWEB_BUNDLER_DOMAIN,
45
THIRDWEB_INAPP_WALLET_DOMAIN,
56
THIRDWEB_PAY_DOMAIN,
@@ -19,6 +20,7 @@ export function initDevMode() {
1920
storage: THIRDWEB_STORAGE_DOMAIN,
2021
social: THIRDWEB_SOCIAL_API_DOMAIN,
2122
bundler: THIRDWEB_BUNDLER_DOMAIN,
23+
bridge: THIRDWEB_BRIDGE_DOMAIN,
2224
});
2325
}
2426
}

apps/login/src/lib/urls.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ export const THIRDWEB_SOCIAL_API_DOMAIN =
1616

1717
export const THIRDWEB_BUNDLER_DOMAIN =
1818
process.env.NEXT_PUBLIC_BUNDLER_URL || "bundler.thirdweb-dev.com";
19+
20+
export const THIRDWEB_BRIDGE_DOMAIN =
21+
process.env.NEXT_PUBLIC_BRIDGE_URL || "bridge.thirdweb-dev.com";

apps/playground-web/src/lib/client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ setThirdwebDomains({
1010
pay: process.env.NEXT_PUBLIC_PAY_URL,
1111
analytics: process.env.NEXT_PUBLIC_ANALYTICS_URL,
1212
insight: process.env.NEXT_PUBLIC_INSIGHT_URL,
13+
bridge: process.env.NEXT_PUBLIC_BRIDGE_URL,
1314
});
1415

1516
const isDev =

packages/thirdweb/.size-limit.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{
99
"name": "thirdweb (cjs)",
1010
"path": "./dist/cjs/exports/thirdweb.js",
11-
"limit": "200 kB"
11+
"limit": "350 kB"
1212
},
1313
{
1414
"name": "thirdweb (minimal + tree-shaking)",

packages/thirdweb/src/bridge/Buy.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { Address as ox__Address } from "ox";
22
import { defineChain } from "../chains/utils.js";
33
import type { ThirdwebClient } from "../client/client.js";
4+
import { getThirdwebBaseUrl } from "../utils/domains.js";
45
import { getClientFetch } from "../utils/fetch.js";
56
import { stringify } from "../utils/json.js";
6-
import { UNIVERSAL_BRIDGE_URL } from "./constants.js";
77
import type { PreparedQuote, Quote } from "./types/Quote.js";
88

99
/**
@@ -113,12 +113,13 @@ export async function quote(options: quote.Options): Promise<quote.Result> {
113113
"buyAmountWei" in options ? options.buyAmountWei : options.amount;
114114

115115
const clientFetch = getClientFetch(client);
116-
const url = new URL(`${UNIVERSAL_BRIDGE_URL}/buy/quote`);
116+
const url = new URL(`${getThirdwebBaseUrl("bridge")}/v1/buy/quote`);
117117
url.searchParams.set("originChainId", originChainId.toString());
118118
url.searchParams.set("originTokenAddress", originTokenAddress);
119119
url.searchParams.set("destinationChainId", destinationChainId.toString());
120120
url.searchParams.set("destinationTokenAddress", destinationTokenAddress);
121121
url.searchParams.set("buyAmountWei", amount.toString());
122+
url.searchParams.set("amount", amount.toString());
122123
if (maxSteps) {
123124
url.searchParams.set("maxSteps", maxSteps.toString());
124125
}
@@ -199,7 +200,7 @@ export declare namespace quote {
199200
* This will return a quote that might look like:
200201
* ```typescript
201202
* {
202-
* originAmount: 10000026098875381n,
203+
* originAmount: 2000030000n,
203204
* destinationAmount: 1000000000000000000n,
204205
* blockNumber: 22026509n,
205206
* timestamp: 1741730936680,
@@ -208,11 +209,11 @@ export declare namespace quote {
208209
* {
209210
* originToken: {
210211
* chainId: 1,
211-
* address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
212-
* symbol: "ETH",
213-
* name: "Ethereum",
214-
* decimals: 18,
215-
* priceUsd: 2000,
212+
* address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
213+
* symbol: "USDC",
214+
* name: "USDC",
215+
* decimals: 6,
216+
* priceUsd: 1,
216217
* iconUri: "https://..."
217218
* },
218219
* destinationToken: {
@@ -224,7 +225,7 @@ export declare namespace quote {
224225
* priceUsd: 2000,
225226
* iconUri: "https://..."
226227
* },
227-
* originAmount: 10000026098875381n,
228+
* originAmount: 2000030000n,
228229
* destinationAmount: 1000000000000000000n,
229230
* estimatedExecutionTimeMs: 1000
230231
* transactions: [
@@ -250,7 +251,7 @@ export declare namespace quote {
250251
* expiration: 1741730936680,
251252
* intent: {
252253
* originChainId: 1,
253-
* originTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
254+
* originTokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
254255
* destinationChainId: 10,
255256
* destinationTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
256257
* amount: 1000000000000000000n
@@ -334,15 +335,16 @@ export async function prepare(
334335
} = options;
335336

336337
const clientFetch = getClientFetch(client);
337-
const url = new URL(`${UNIVERSAL_BRIDGE_URL}/buy/prepare`);
338+
const url = new URL(`${getThirdwebBaseUrl("bridge")}/v1/buy/prepare`);
338339

339340
const response = await clientFetch(url.toString(), {
340341
method: "POST",
341342
headers: {
342343
"Content-Type": "application/json",
343344
},
344345
body: stringify({
345-
buyAmountWei: amount.toString(),
346+
buyAmountWei: amount.toString(), // legacy
347+
amount: amount.toString(),
346348
originChainId: originChainId.toString(),
347349
originTokenAddress,
348350
destinationChainId: destinationChainId.toString(),
@@ -382,6 +384,8 @@ export async function prepare(
382384
destinationChainId,
383385
destinationTokenAddress,
384386
amount,
387+
sender,
388+
receiver,
385389
},
386390
};
387391
}
@@ -407,6 +411,8 @@ export declare namespace prepare {
407411
destinationChainId: number;
408412
destinationTokenAddress: ox__Address.Address;
409413
amount: bigint;
414+
sender: ox__Address.Address;
415+
receiver: ox__Address.Address;
410416
purchaseData?: unknown;
411417
};
412418
};

packages/thirdweb/src/bridge/Chains.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ThirdwebClient } from "../client/client.js";
2+
import { getThirdwebBaseUrl } from "../utils/domains.js";
23
import { getClientFetch } from "../utils/fetch.js";
3-
import { UNIVERSAL_BRIDGE_URL } from "./constants.js";
44
import type { Chain } from "./types/Chain.js";
55

66
/**
@@ -54,7 +54,7 @@ export async function chains(options: chains.Options): Promise<chains.Result> {
5454
const { client } = options;
5555

5656
const clientFetch = getClientFetch(client);
57-
const url = new URL(`${UNIVERSAL_BRIDGE_URL}/chains`);
57+
const url = new URL(`${getThirdwebBaseUrl("bridge")}/v1/chains`);
5858

5959
const response = await clientFetch(url.toString());
6060
if (!response.ok) {

packages/thirdweb/src/bridge/Routes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Address as ox__Address, Hex as ox__Hex } from "ox";
22
import type { ThirdwebClient } from "../client/client.js";
3+
import { getThirdwebBaseUrl } from "../utils/domains.js";
34
import { getClientFetch } from "../utils/fetch.js";
4-
import { UNIVERSAL_BRIDGE_URL } from "./constants.js";
55
import type { Route } from "./types/Route.js";
66

77
/**
@@ -133,7 +133,7 @@ export async function routes(options: routes.Options): Promise<routes.Result> {
133133
} = options;
134134

135135
const clientFetch = getClientFetch(client);
136-
const url = new URL(`${UNIVERSAL_BRIDGE_URL}/routes`);
136+
const url = new URL(`${getThirdwebBaseUrl("bridge")}/v1/routes`);
137137
if (originChainId) {
138138
url.searchParams.set("originChainId", originChainId.toString());
139139
}

0 commit comments

Comments
 (0)