Skip to content

Commit 736c3f8

Browse files
authored
[SDK] Feature: Add maxSteps to bridge quote functions (#6953)
1 parent 055e451 commit 736c3f8

File tree

5 files changed

+229
-2
lines changed

5 files changed

+229
-2
lines changed

.changeset/forty-states-shake.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Adds the `maxSteps` option to Buy.quote, Buy.prepare, Sell.quote, and Sell.prepare functions. This allows users to limit quotes to routes with a specific number of steps or fewer. For example:
6+
7+
```ts
8+
const quote = await bridge.Buy.quote({
9+
originChainId: 1,
10+
originTokenAddress: "0x...",
11+
destinationChainId: 137,
12+
destinationTokenAddress: "0x...",
13+
amount: 1000000n,
14+
maxSteps: 2
15+
});
16+
17+
const preparedQuote = await bridge.Buy.prepare({
18+
originChainId: 1,
19+
originTokenAddress: "0x...",
20+
destinationChainId: 137,
21+
destinationTokenAddress: "0x...",
22+
amount: 1000000n,
23+
sender: "0x...",
24+
receiver: "0x...",
25+
maxSteps: 2
26+
});
27+
28+
const quote = await bridge.Sell.quote({
29+
originChainId: 1,
30+
originTokenAddress: "0x...",
31+
destinationChainId: 137,
32+
destinationTokenAddress: "0x...",
33+
amount: 1000000n,
34+
maxSteps: 3
35+
});
36+
37+
const preparedQuote = await bridge.Sell.prepare({
38+
originChainId: 1,
39+
originTokenAddress: "0x...",
40+
destinationChainId: 137,
41+
destinationTokenAddress: "0x...",
42+
amount: 1000000n,
43+
sender: "0x...",
44+
receiver: "0x...",
45+
maxSteps: 3
46+
});
47+
```

packages/thirdweb/src/bridge/Buy.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ describe.runIf(process.env.TW_SECRET_KEY)("Bridge.Buy.quote", () => {
3232
}),
3333
).rejects.toThrowError();
3434
});
35+
36+
it("should limit quotes to routes with a certain number of steps", async () => {
37+
const quote = await Buy.quote({
38+
originChainId: 1,
39+
originTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
40+
destinationChainId: 10,
41+
destinationTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
42+
amount: toWei("0.01"),
43+
maxSteps: 2,
44+
client: TEST_CLIENT,
45+
});
46+
47+
expect(quote).toBeDefined();
48+
expect(quote.destinationAmount).toEqual(toWei("0.01"));
49+
expect(quote.intent).toBeDefined();
50+
expect(quote.steps.length).toBeLessThanOrEqual(2);
51+
});
3552
});
3653

3754
describe.runIf(process.env.TW_SECRET_KEY)("Bridge.Buy.prepare", () => {
@@ -72,4 +89,23 @@ describe.runIf(process.env.TW_SECRET_KEY)("Bridge.Buy.prepare", () => {
7289
}),
7390
).rejects.toThrowError();
7491
});
92+
93+
it("should limit quotes to routes with a certain number of steps", async () => {
94+
const quote = await Buy.prepare({
95+
originChainId: 1,
96+
originTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
97+
destinationChainId: 10,
98+
destinationTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
99+
amount: toWei("0.01"),
100+
maxSteps: 2,
101+
sender: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
102+
receiver: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
103+
client: TEST_CLIENT,
104+
});
105+
106+
expect(quote).toBeDefined();
107+
expect(quote.destinationAmount).toEqual(toWei("0.01"));
108+
expect(quote.steps.length).toBeLessThanOrEqual(2);
109+
expect(quote.intent).toBeDefined();
110+
});
75111
});

packages/thirdweb/src/bridge/Buy.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Address as ox__Address } from "ox";
22
import { defineChain } from "../chains/utils.js";
33
import type { ThirdwebClient } from "../client/client.js";
44
import { getClientFetch } from "../utils/fetch.js";
5+
import { stringify } from "../utils/json.js";
56
import { UNIVERSAL_BRIDGE_URL } from "./constants.js";
67
import type { PreparedQuote, Quote } from "./types/Quote.js";
78

@@ -70,6 +71,20 @@ import type { PreparedQuote, Quote } from "./types/Quote.js";
7071
*
7172
* You can access this functions input and output types with `Buy.quote.Options` and `Buy.quote.Result`, respectively.
7273
*
74+
* To limit quotes to routes that have a certain number of steps involved, use the `maxSteps` option.
75+
*
76+
* ```ts
77+
* const quote = await Bridge.Buy.quote({
78+
* originChainId: 1,
79+
* originTokenAddress: NATIVE_TOKEN_ADDRESS,
80+
* destinationChainId: 10,
81+
* destinationTokenAddress: NATIVE_TOKEN_ADDRESS,
82+
* amount: toWei("0.01"),
83+
* maxSteps: 2, // Will only return a quote for routes with 2 or fewer steps
84+
* client: thirdwebClient,
85+
* });
86+
* ```
87+
*
7388
* @param options - The options for the quote.
7489
* @param options.originChainId - The chain ID of the origin token.
7590
* @param options.originTokenAddress - The address of the origin token.
@@ -91,6 +106,7 @@ export async function quote(options: quote.Options): Promise<quote.Result> {
91106
destinationChainId,
92107
destinationTokenAddress,
93108
client,
109+
maxSteps,
94110
} = options;
95111
const amount =
96112
"buyAmountWei" in options ? options.buyAmountWei : options.amount;
@@ -102,6 +118,9 @@ export async function quote(options: quote.Options): Promise<quote.Result> {
102118
url.searchParams.set("destinationChainId", destinationChainId.toString());
103119
url.searchParams.set("destinationTokenAddress", destinationTokenAddress);
104120
url.searchParams.set("buyAmountWei", amount.toString());
121+
if (maxSteps) {
122+
url.searchParams.set("maxSteps", maxSteps.toString());
123+
}
105124

106125
const response = await clientFetch(url.toString());
107126
if (!response.ok) {
@@ -137,6 +156,7 @@ export declare namespace quote {
137156
destinationChainId: number;
138157
destinationTokenAddress: ox__Address.Address;
139158
client: ThirdwebClient;
159+
maxSteps?: number;
140160
} & (
141161
| {
142162
buyAmountWei: bigint;
@@ -247,6 +267,37 @@ export declare namespace quote {
247267
*
248268
* You can access this functions input and output types with `Buy.prepare.Options` and `Buy.prepare.Result`, respectively.
249269
*
270+
* You can include arbitrary data to be included on any webhooks and status responses with the `purchaseData` option.
271+
*
272+
* ```ts
273+
* const quote = await Bridge.Buy.prepare({
274+
* originChainId: 1,
275+
* originTokenAddress: NATIVE_TOKEN_ADDRESS,
276+
* destinationChainId: 10,
277+
* destinationTokenAddress: NATIVE_TOKEN_ADDRESS,
278+
* amount: toWei("0.01"),
279+
* purchaseData: {
280+
* size: "large",
281+
* shippingAddress: "123 Main St, New York, NY 10001",
282+
* },
283+
* client: thirdwebClient,
284+
* });
285+
* ```
286+
*
287+
* To limit quotes to routes that have a certain number of steps involved, use the `maxSteps` option.
288+
*
289+
* ```ts
290+
* const quote = await Bridge.Buy.prepare({
291+
* originChainId: 1,
292+
* originTokenAddress: NATIVE_TOKEN_ADDRESS,
293+
* destinationChainId: 10,
294+
* destinationTokenAddress: NATIVE_TOKEN_ADDRESS,
295+
* amount: toWei("0.01"),
296+
* maxSteps: 2, // Will only return a quote for routes with 2 or fewer steps
297+
* client: thirdwebClient,
298+
* });
299+
* ```
300+
*
250301
* @param options - The options for the quote.
251302
* @param options.originChainId - The chain ID of the origin token.
252303
* @param options.originTokenAddress - The address of the origin token.
@@ -277,6 +328,7 @@ export async function prepare(
277328
client,
278329
amount,
279330
purchaseData,
331+
maxSteps,
280332
} = options;
281333

282334
const clientFetch = getClientFetch(client);
@@ -287,7 +339,7 @@ export async function prepare(
287339
headers: {
288340
"Content-Type": "application/json",
289341
},
290-
body: JSON.stringify({
342+
body: stringify({
291343
buyAmountWei: amount.toString(),
292344
originChainId: originChainId.toString(),
293345
originTokenAddress,
@@ -296,6 +348,7 @@ export async function prepare(
296348
sender,
297349
receiver,
298350
purchaseData,
351+
maxSteps,
299352
}),
300353
});
301354
if (!response.ok) {
@@ -342,6 +395,7 @@ export declare namespace prepare {
342395
amount: bigint;
343396
client: ThirdwebClient;
344397
purchaseData?: unknown;
398+
maxSteps?: number;
345399
};
346400

347401
type Result = PreparedQuote & {

packages/thirdweb/src/bridge/Sell.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ describe.runIf(process.env.TW_SECRET_KEY)("Bridge.Sell.quote", () => {
3232
}),
3333
).rejects.toThrowError();
3434
});
35+
36+
it("should limit quotes to routes with a certain number of steps", async () => {
37+
const quote = await Sell.quote({
38+
originChainId: 1,
39+
originTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
40+
destinationChainId: 10,
41+
destinationTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
42+
amount: toWei("0.01"),
43+
maxSteps: 2,
44+
client: TEST_CLIENT,
45+
});
46+
47+
expect(quote).toBeDefined();
48+
expect(quote.originAmount).toEqual(toWei("0.01"));
49+
expect(quote.intent).toBeDefined();
50+
expect(quote.steps.length).toBeLessThanOrEqual(2);
51+
});
3552
});
3653

3754
describe.runIf(process.env.TW_SECRET_KEY)("Bridge.Sell.prepare", () => {
@@ -69,4 +86,23 @@ describe.runIf(process.env.TW_SECRET_KEY)("Bridge.Sell.prepare", () => {
6986
}),
7087
).rejects.toThrowError();
7188
});
89+
90+
it("should limit quotes to routes with a certain number of steps", async () => {
91+
const quote = await Sell.prepare({
92+
originChainId: 1,
93+
originTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
94+
destinationChainId: 10,
95+
destinationTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
96+
amount: toWei("0.01"),
97+
maxSteps: 2,
98+
sender: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
99+
receiver: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
100+
client: TEST_CLIENT,
101+
});
102+
103+
expect(quote).toBeDefined();
104+
expect(quote.originAmount).toEqual(toWei("0.01"));
105+
expect(quote.steps.length).toBeLessThanOrEqual(2);
106+
expect(quote.intent).toBeDefined();
107+
});
72108
});

packages/thirdweb/src/bridge/Sell.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Address as ox__Address } from "ox";
22
import { defineChain } from "../chains/utils.js";
33
import type { ThirdwebClient } from "../client/client.js";
44
import { getClientFetch } from "../utils/fetch.js";
5+
import { stringify } from "../utils/json.js";
56
import { UNIVERSAL_BRIDGE_URL } from "./constants.js";
67
import type { PreparedQuote, Quote } from "./types/Quote.js";
78

@@ -70,6 +71,20 @@ import type { PreparedQuote, Quote } from "./types/Quote.js";
7071
*
7172
* You can access this functions input and output types with `Sell.quote.Options` and `Sell.quote.Result`, respectively.
7273
*
74+
* To limit quotes to routes that have a certain number of steps involved, use the `maxSteps` option.
75+
*
76+
* ```ts
77+
* const quote = await Bridge.Sell.quote({
78+
* originChainId: 1,
79+
* originTokenAddress: NATIVE_TOKEN_ADDRESS,
80+
* destinationChainId: 10,
81+
* destinationTokenAddress: NATIVE_TOKEN_ADDRESS,
82+
* amount: toWei("0.01"),
83+
* maxSteps: 2, // Will only return a quote for routes with 2 or fewer steps
84+
* client: thirdwebClient,
85+
* });
86+
* ```
87+
*
7388
* @param options - The options for the quote.
7489
* @param options.originChainId - The chain ID of the origin token.
7590
* @param options.originTokenAddress - The address of the origin token.
@@ -92,6 +107,7 @@ export async function quote(options: quote.Options): Promise<quote.Result> {
92107
destinationTokenAddress,
93108
amount,
94109
client,
110+
maxSteps,
95111
} = options;
96112

97113
const clientFetch = getClientFetch(client);
@@ -101,6 +117,9 @@ export async function quote(options: quote.Options): Promise<quote.Result> {
101117
url.searchParams.set("destinationChainId", destinationChainId.toString());
102118
url.searchParams.set("destinationTokenAddress", destinationTokenAddress);
103119
url.searchParams.set("sellAmountWei", amount.toString());
120+
if (typeof maxSteps !== "undefined") {
121+
url.searchParams.set("maxSteps", maxSteps.toString());
122+
}
104123

105124
const response = await clientFetch(url.toString());
106125
if (!response.ok) {
@@ -136,6 +155,7 @@ export declare namespace quote {
136155
destinationTokenAddress: ox__Address.Address;
137156
amount: bigint;
138157
client: ThirdwebClient;
158+
maxSteps?: number;
139159
};
140160

141161
type Result = Quote & {
@@ -238,6 +258,37 @@ export declare namespace quote {
238258
*
239259
* You can access this functions input and output types with `Sell.prepare.Options` and `Sell.prepare.Result`, respectively.
240260
*
261+
* You can include arbitrary data to be included on any webhooks and status responses with the `purchaseData` option.
262+
*
263+
* ```ts
264+
* const quote = await Bridge.Sell.prepare({
265+
* originChainId: 1,
266+
* originTokenAddress: NATIVE_TOKEN_ADDRESS,
267+
* destinationChainId: 10,
268+
* destinationTokenAddress: NATIVE_TOKEN_ADDRESS,
269+
* amount: toWei("0.01"),
270+
* purchaseData: {
271+
* size: "large",
272+
* shippingAddress: "123 Main St, New York, NY 10001",
273+
* },
274+
* client: thirdwebClient,
275+
* });
276+
* ```
277+
*
278+
* To limit quotes to routes that have a certain number of steps involved, use the `maxSteps` option.
279+
*
280+
* ```ts
281+
* const quote = await Bridge.Sell.prepare({
282+
* originChainId: 1,
283+
* originTokenAddress: NATIVE_TOKEN_ADDRESS,
284+
* destinationChainId: 10,
285+
* destinationTokenAddress: NATIVE_TOKEN_ADDRESS,
286+
* amount: toWei("0.01"),
287+
* maxSteps: 2, // Will only return a quote for routes with 2 or fewer steps
288+
* client: thirdwebClient,
289+
* });
290+
* ```
291+
*
241292
* @param options - The options for the quote.
242293
* @param options.originChainId - The chain ID of the origin token.
243294
* @param options.originTokenAddress - The address of the origin token.
@@ -268,6 +319,7 @@ export async function prepare(
268319
receiver,
269320
client,
270321
purchaseData,
322+
maxSteps,
271323
} = options;
272324

273325
const clientFetch = getClientFetch(client);
@@ -278,7 +330,7 @@ export async function prepare(
278330
headers: {
279331
"Content-Type": "application/json",
280332
},
281-
body: JSON.stringify({
333+
body: stringify({
282334
sellAmountWei: amount.toString(),
283335
originChainId: originChainId.toString(),
284336
originTokenAddress,
@@ -287,6 +339,7 @@ export async function prepare(
287339
sender,
288340
receiver,
289341
purchaseData,
342+
maxSteps,
290343
}),
291344
});
292345
if (!response.ok) {
@@ -335,6 +388,7 @@ export declare namespace prepare {
335388
receiver: ox__Address.Address;
336389
client: ThirdwebClient;
337390
purchaseData?: unknown;
391+
maxSteps?: number;
338392
};
339393

340394
type Result = PreparedQuote & {

0 commit comments

Comments
 (0)