@hot-labs/kit 1.1.0-beta.4 → 1.1.0-beta.7

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.
@@ -7,10 +7,9 @@ import { rpc } from "../near/rpc";
7
7
  import type { Intent, Commitment, TokenDiffIntent, MtWithdrawIntent, FtWithdrawIntent, NftWithdrawIntent, TransferIntent } from "./types";
8
8
  import { OmniToken } from "./chains";
9
9
  import { tokens } from "./tokens";
10
- import { formatter } from "./utils";
11
10
  import { api } from "./api";
12
11
 
13
- import { openPayment } from "../ui/router";
12
+ import { openPayment, openToast } from "../ui/router";
14
13
 
15
14
  export const TGAS = 1000000000000n;
16
15
 
@@ -21,14 +20,22 @@ export class Intents {
21
20
  return new Intents();
22
21
  }
23
22
 
24
- hashes: string[] = [];
25
- intents: Intent[] = [];
26
- signer?: OmniWallet;
27
- nonce?: Uint8Array;
28
- deadline?: Date;
29
-
23
+ signedHashes: string[] = [];
30
24
  commitments: Commitment[] = [];
31
25
  need = new Map<OmniToken, bigint>();
26
+ signer?: OmniWallet;
27
+
28
+ unsignedCommitment?: {
29
+ intents: Intent[];
30
+ nonce?: Uint8Array;
31
+ deadline?: Date;
32
+ };
33
+
34
+ addIntent(intent: Intent) {
35
+ if (!this.unsignedCommitment) this.unsignedCommitment = { intents: [] };
36
+ this.unsignedCommitment.intents.push(intent);
37
+ return this;
38
+ }
32
39
 
33
40
  addNeed(token: OmniToken, amount: bigint) {
34
41
  if (!this.need.has(token)) this.need.set(token, 0n);
@@ -38,7 +45,7 @@ export class Intents {
38
45
 
39
46
  authCall(args: { contractId: string; msg: string; attachNear: bigint; tgas: number }) {
40
47
  this.addNeed(OmniToken.NEAR, args.attachNear);
41
- this.intents.push({
48
+ this.addIntent({
42
49
  min_gas: (BigInt(args.tgas) * TGAS).toString(),
43
50
  attached_deposit: args.attachNear.toString(),
44
51
  contract_id: args.contractId,
@@ -58,7 +65,7 @@ export class Intents {
58
65
  recipient: "pay.fi.tg",
59
66
  amount,
60
67
  token,
61
- }).depositAndExecute({ email });
68
+ }).yieldExecute({ email });
62
69
  }
63
70
 
64
71
  transfer(args: { recipient: string; token: OmniToken; amount: number | bigint; memo?: string; msg?: string; tgas?: number }) {
@@ -74,7 +81,7 @@ export class Intents {
74
81
  };
75
82
 
76
83
  this.addNeed(args.token, BigInt(amount));
77
- this.intents.push(intent);
84
+ this.addIntent(intent);
78
85
  return this;
79
86
  }
80
87
 
@@ -96,7 +103,7 @@ export class Intents {
96
103
  msg: args.msg,
97
104
  };
98
105
 
99
- this.intents.push(intent);
106
+ this.addIntent(intent);
100
107
  return this;
101
108
  }
102
109
 
@@ -119,7 +126,7 @@ export class Intents {
119
126
  }
120
127
  }
121
128
 
122
- this.intents.push(intent);
129
+ this.addIntent(intent);
123
130
  return this;
124
131
  }
125
132
 
@@ -156,7 +163,7 @@ export class Intents {
156
163
  this.addNeed(token, BigInt(rawIntent.amounts[i]));
157
164
  }
158
165
 
159
- this.intents.push({
166
+ this.addIntent({
160
167
  intent: "mt_withdraw",
161
168
  amounts: rawIntent.amounts,
162
169
  receiver_id: rawIntent.receiver_id,
@@ -211,12 +218,12 @@ export class Intents {
211
218
  }
212
219
 
213
220
  addPublicKey(publicKey: string) {
214
- this.intents.push({ intent: "add_public_key", public_key: publicKey });
221
+ this.addIntent({ intent: "add_public_key", public_key: publicKey });
215
222
  return this;
216
223
  }
217
224
 
218
225
  removePublicKey(publicKey: string) {
219
- this.intents.push({ intent: "remove_public_key", public_key: publicKey });
226
+ this.addIntent({ intent: "remove_public_key", public_key: publicKey });
220
227
  return this;
221
228
  }
222
229
 
@@ -229,7 +236,7 @@ export class Intents {
229
236
  if (standart === "nep245") {
230
237
  const mtContract = tokenParts[0];
231
238
  const tokenId = tokenParts.slice(1).join(":");
232
- this.intents.push({
239
+ this.addIntent({
233
240
  intent: "mt_withdraw",
234
241
  amounts: [amount],
235
242
  receiver_id: args.receiver,
@@ -243,7 +250,7 @@ export class Intents {
243
250
  }
244
251
 
245
252
  if (standart === "nep141") {
246
- this.intents.push({
253
+ this.addIntent({
247
254
  intent: "ft_withdraw",
248
255
  receiver_id: args.receiver,
249
256
  token: tokenParts.join(":"),
@@ -255,7 +262,7 @@ export class Intents {
255
262
  }
256
263
 
257
264
  if (standart === "nep171") {
258
- this.intents.push({
265
+ this.addIntent({
259
266
  intent: "nft_withdraw",
260
267
  receiver_id: args.receiver,
261
268
  token_id: tokenParts.join(":"),
@@ -270,7 +277,7 @@ export class Intents {
270
277
  }
271
278
 
272
279
  attachHashes(hashes: string[]) {
273
- this.hashes.push(...hashes);
280
+ this.signedHashes.push(...hashes);
274
281
  return this;
275
282
  }
276
283
 
@@ -280,22 +287,26 @@ export class Intents {
280
287
  }
281
288
 
282
289
  attachDeadline(deadline: Date) {
283
- this.deadline = deadline;
290
+ if (!this.unsignedCommitment) this.unsignedCommitment = { intents: [] };
291
+ this.unsignedCommitment.deadline = deadline;
284
292
  return this;
285
293
  }
286
294
 
287
295
  attachNonce(nonce: Uint8Array) {
288
- this.nonce = nonce;
296
+ if (!this.unsignedCommitment) this.unsignedCommitment = { intents: [] };
297
+ this.unsignedCommitment.nonce = nonce;
289
298
  return this;
290
299
  }
291
300
 
292
301
  attachTimeout(seconds: number) {
293
- this.deadline = new Date(Date.now() + seconds * 1000);
302
+ if (!this.unsignedCommitment) this.unsignedCommitment = { intents: [] };
303
+ this.unsignedCommitment.deadline = new Date(Date.now() + seconds * 1000);
294
304
  return this;
295
305
  }
296
306
 
297
307
  attachSeed(seed: string) {
298
- this.nonce = new Uint8Array(sha256(new TextEncoder().encode(seed))).slice(0, 32);
308
+ if (!this.unsignedCommitment) this.unsignedCommitment = { intents: [] };
309
+ this.unsignedCommitment.nonce = new Uint8Array(sha256(new TextEncoder().encode(seed))).slice(0, 32);
299
310
  return this;
300
311
  }
301
312
 
@@ -308,10 +319,10 @@ export class Intents {
308
319
  const intAmount = typeof amount === "number" ? tokens.get(token).int(amount) : amount;
309
320
 
310
321
  // this.addNeed(token, -intAmount); Do we need to add the need here?
311
- const tokenDiff = this.intents.find((intent) => intent.intent === "token_diff");
322
+ const tokenDiff = this.unsignedCommitment?.intents.find((intent) => intent.intent === "token_diff");
312
323
 
313
324
  if (tokenDiff) tokenDiff.diff[token.toString()] = intAmount.toString();
314
- else this.intents.push({ intent: "token_diff", diff: { [token.toString()]: intAmount.toString() } });
325
+ else this.addIntent({ intent: "token_diff", diff: { [token.toString()]: intAmount.toString() } });
315
326
  return this;
316
327
  }
317
328
 
@@ -319,10 +330,10 @@ export class Intents {
319
330
  const intAmount = typeof amount === "number" ? tokens.get(token).int(amount) : amount;
320
331
 
321
332
  this.addNeed(token as OmniToken, intAmount);
322
- const tokenDiff = this.intents.find((intent) => intent.intent === "token_diff");
333
+ const tokenDiff = this.unsignedCommitment?.intents.find((intent) => intent.intent === "token_diff");
323
334
 
324
335
  if (tokenDiff) tokenDiff.diff[token.toString()] = (-intAmount).toString();
325
- else this.intents.push({ intent: "token_diff", diff: { [token.toString()]: (-intAmount).toString() } });
336
+ else this.addIntent({ intent: "token_diff", diff: { [token.toString()]: (-intAmount).toString() } });
326
337
  return this;
327
338
  }
328
339
 
@@ -332,9 +343,13 @@ export class Intents {
332
343
  if (!signer.omniAddress) throw new Error("No omni address");
333
344
 
334
345
  const commitments: Commitment[] = [];
335
- for (const intent of this.intents) {
336
- const signed = await signer.signIntents([intent], { deadline: this.deadline ? +this.deadline : undefined, nonce: this.nonce });
337
- commitments.push(signed);
346
+ for (const intent of this.unsignedCommitment?.intents || []) {
347
+ commitments.push(
348
+ await signer.signIntents([intent], {
349
+ deadline: this.unsignedCommitment?.deadline ? +this.unsignedCommitment.deadline : undefined,
350
+ nonce: this.unsignedCommitment?.nonce,
351
+ })
352
+ );
338
353
  }
339
354
 
340
355
  return commitments;
@@ -344,48 +359,60 @@ export class Intents {
344
359
  const signer = this.signer;
345
360
  if (!signer) throw new Error("No signer attached");
346
361
  if (!signer.omniAddress) throw new Error("No omni address");
347
- return await signer.signIntents(this.intents, {
348
- deadline: this.deadline ? +this.deadline : undefined,
349
- nonce: this.nonce,
362
+ const commitment = await signer.signIntents(this.unsignedCommitment?.intents || [], {
363
+ deadline: this.unsignedCommitment?.deadline ? +this.unsignedCommitment.deadline : undefined,
364
+ nonce: this.unsignedCommitment?.nonce,
350
365
  });
366
+
367
+ this.unsignedCommitment = undefined;
368
+ this.commitments.push(commitment);
369
+ return this;
351
370
  }
352
371
 
353
372
  async simulate() {
354
- if (!this.signer) throw new Error("No signer attached");
355
- const signed = await this.sign();
356
- return await Intents.simulateIntents([signed]);
373
+ if (this.commitments.length === 0) throw new Error("No commitments attached");
374
+ return await Intents.simulateIntents(this.commitments);
357
375
  }
358
376
 
359
- async depositAndExecute(payload?: Record<string, any>) {
377
+ async yieldExecute(payload?: Record<string, any>) {
360
378
  if (!this.wibe3) throw new Error("No wibe3 attached");
361
- return openPayment(this.wibe3, this, payload);
362
- }
379
+ const { depositQoute, processing } = await openPayment(this.wibe3, this);
380
+ const depositAddress = depositQoute === "direct" ? undefined : typeof depositQoute?.qoute === "object" ? depositQoute?.qoute?.depositAddress : undefined;
363
381
 
364
- async execute() {
365
- if (!this.signer) throw new Error("No signer attached");
366
- const signed = await this.sign();
367
- return await Intents.publish([signed], this.hashes);
368
- }
369
-
370
- async executeBatch(params = { checkTokens: true, chunkSize: this.intents.length, onSuccess: (bucket: number, hash: string) => {} }) {
371
- if (!this.signer) throw new Error("No signer attached");
372
- const batches = formatter.chunk(this.intents, params.chunkSize);
373
- let index = 0;
382
+ if (depositAddress) {
383
+ const { near_trx } = await api.yieldIntentCall({ depositAddress, commitment: this.commitments[0], payload });
384
+ return near_trx;
385
+ }
374
386
 
375
- const hashes: string[] = [];
376
- for (const batch of batches) {
377
- const signed = await this.signer.signIntents(batch, {
378
- deadline: this.deadline ? +this.deadline : undefined,
379
- nonce: this.nonce,
380
- });
387
+ await processing?.();
388
+ return this.execute();
389
+ }
381
390
 
382
- const hash = await Intents.publish([...this.commitments, signed], this.hashes);
383
- await rpc.waitTransactionResult(hash, "intents.near");
384
- params.onSuccess(index++, hash);
385
- hashes.push(hash);
391
+ async depositAndExecute({ actionName = "Payment", message }: { actionName?: string; message?: string } = {}) {
392
+ if (!this.wibe3) throw new Error("No wibe3 attached");
393
+ const { processing } = await openPayment(this.wibe3, this, actionName);
394
+ const close = openToast(message || "Executing payment");
395
+
396
+ try {
397
+ await processing?.();
398
+ const result = await this.execute();
399
+ close();
400
+ return result;
401
+ } catch (e) {
402
+ close();
403
+ throw e;
386
404
  }
405
+ }
387
406
 
388
- return hashes;
407
+ async execute() {
408
+ if (this.unsignedCommitment != null) await this.sign();
409
+ const task = Intents.publish(this.commitments, this.signedHashes);
410
+ this.commitments = [];
411
+ this.signedHashes = [];
412
+
413
+ const hash = await task;
414
+ await rpc.waitTransactionResult(hash, "intents.near");
415
+ return hash;
389
416
  }
390
417
 
391
418
  static async publish(signed: Commitment[], hashes: string[] = []): Promise<string> {
package/src/core/utils.ts CHANGED
@@ -148,7 +148,12 @@ export const formatter = {
148
148
  },
149
149
 
150
150
  amount(value: Value, decimals = 24) {
151
- const num = String(+formatter.num(value).toFixed(decimals));
151
+ if (+formatter.num(value) > 1_000_000_000_000_000_000) return `${formatter.round(+formatter.num(value) / 1_000_000_000_000_000, 2)}Q`;
152
+ if (+formatter.num(value) > 1_000_000_000_000_000) return `${formatter.round(+formatter.num(value) / 1_000_000_000_000, 2)}T`;
153
+ if (+formatter.num(value) > 1_000_000_000_000) return `${formatter.round(+formatter.num(value) / 1_000_000_000, 2)}B`;
154
+ if (+formatter.num(value) > 1_000_000_000) return `${formatter.round(+formatter.num(value) / 1_000_000, 2)}M`;
155
+ const num = formatter.num(value).toFixed(decimals);
156
+ if (+num === 0) return "0";
152
157
  return formatter.formatNumberWithSubscriptZeros(num, 3, 0.0001);
153
158
  },
154
159
 
package/src/exchange.ts CHANGED
@@ -184,7 +184,7 @@ export class Exchange {
184
184
  if (!intentFrom) throw new Error("Unsupported token");
185
185
  if (!intentTo) throw new Error("Unsupported token");
186
186
 
187
- const deadlineTime = 20 * 60 * 1000;
187
+ const deadlineTime = 5 * 60 * 1000;
188
188
  const directChains = [Network.Near, Network.Juno, Network.Gonka, Network.ADI];
189
189
  const deadline = new Date(Date.now() + deadlineTime).toISOString();
190
190
  const noFee = from.symbol === to.symbol || (from.symbol.toLowerCase().includes("usd") && to.symbol.toLowerCase().includes("usd"));
@@ -14,7 +14,6 @@ import {
14
14
  } from "@solana/spl-token";
15
15
 
16
16
  import { Network, WalletType } from "../core/chains";
17
- import { OmniConnector } from "../OmniConnector";
18
17
  import { OmniWallet } from "../OmniWallet";
19
18
 
20
19
  import { Token } from "../core/token";
@@ -148,7 +147,7 @@ class SolanaWallet extends OmniWallet {
148
147
  }
149
148
 
150
149
  async getPriorityFeeEstimate(params: any): Promise<any> {
151
- const response = await fetch(api.baseUrl + "/api/v1/wibe3/helius/staked", {
150
+ const response = await fetch(api.baseUrl + "/api/v1/evm/helius/staked", {
152
151
  body: JSON.stringify({ jsonrpc: "2.0", id: "helius-sdk", method: "getPriorityFeeEstimate", params: [params] }),
153
152
  headers: { "Content-Type": "application/json" },
154
153
  method: "POST",
package/src/ui/Popup.tsx CHANGED
@@ -16,6 +16,11 @@ export const present = (render: (close: () => void) => React.ReactNode) => {
16
16
  div.remove();
17
17
  })
18
18
  );
19
+
20
+ return () => {
21
+ root.unmount();
22
+ div.remove();
23
+ };
19
24
  };
20
25
 
21
26
  interface PopupProps {
@@ -0,0 +1,45 @@
1
+ import styled from "styled-components";
2
+ import { Loader } from "./payment/Profile";
3
+
4
+ const Toast = ({ message }: { message: string }) => {
5
+ return (
6
+ <ToastRoot>
7
+ <div style={{ width: 44, height: 44, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: 12, background: "rgba(255, 255, 255, 0.07)" }}>
8
+ <Loader />
9
+ </div>
10
+
11
+ <div>
12
+ <p style={{ color: "#ADA5A4" }}>Executing transaction</p>
13
+ <p style={{ marginTop: 2 }}>{message}</p>
14
+ </div>
15
+ </ToastRoot>
16
+ );
17
+ };
18
+
19
+ export default Toast;
20
+
21
+ const ToastRoot = styled.div`
22
+ position: fixed;
23
+ bottom: 48px;
24
+ left: 12px;
25
+ right: 12px;
26
+ background: var(--surface-common-container--low, #262729);
27
+ border: 1px solid var(--border-lowest, rgba(255, 255, 255, 0.07));
28
+ border-radius: 8px;
29
+ padding: 12px;
30
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: space-between;
34
+ z-index: 1000000000;
35
+ width: fit-content;
36
+ padding-right: 24px;
37
+ gap: 12px;
38
+
39
+ p {
40
+ color: var(--text-primary, #fff);
41
+ font-size: 16px;
42
+ font-weight: 500;
43
+ margin: 0;
44
+ }
45
+ `;
@@ -7,7 +7,6 @@ import { Commitment, formatter, Intents } from "../../core";
7
7
  import { Recipient } from "../../core/recipient";
8
8
  import { Network } from "../../core/chains";
9
9
  import { Token } from "../../core/token";
10
- import { api } from "../../core/api";
11
10
 
12
11
  import { BridgeReview } from "../../exchange";
13
12
  import { openConnector } from "../router";
@@ -22,10 +21,10 @@ import { Loader } from "./Profile";
22
21
 
23
22
  interface PaymentProps {
24
23
  intents: Intents;
24
+ actionName?: string;
25
25
  connector: HotConnector;
26
- payload?: Record<string, any>;
27
26
  onReject: (message: string) => void;
28
- onSuccess: (task: { paymentId: string; tx: string }) => void;
27
+ onConfirm: (args: { depositQoute: BridgeReview | "direct"; processing?: () => Promise<BridgeReview> }) => void;
29
28
  }
30
29
 
31
30
  const animations = {
@@ -36,7 +35,7 @@ const animations = {
36
35
 
37
36
  const PAY_SLIPPAGE = 0.002;
38
37
 
39
- export const Payment = observer(({ connector, intents, payload, onReject, onSuccess }: PaymentProps) => {
38
+ export const Payment = observer(({ connector, intents, actionName = "Payment", onReject, onConfirm }: PaymentProps) => {
40
39
  useState(() => {
41
40
  fetch(animations.loading);
42
41
  fetch(animations.success);
@@ -53,16 +52,15 @@ export const Payment = observer(({ connector, intents, payload, onReject, onSucc
53
52
  wallet?: OmniWallet;
54
53
  commitment?: Commitment;
55
54
  review?: BridgeReview | "direct";
56
- data?: { paymentId: string; tx: string };
55
+ success?: { depositQoute: BridgeReview | "direct"; processing?: () => Promise<BridgeReview> };
57
56
  step?: "selectToken" | "sign" | "transfer" | "success" | "error" | "loading";
58
- success?: boolean;
59
57
  loading?: boolean;
60
58
  error?: any;
61
59
  } | null>(null);
62
60
 
63
61
  const need = connector.omni(intents.need.keys().next().value!);
64
62
  const needAmount = intents.need.values().next().value || 0n;
65
- const title = `Payment ${need.readable(needAmount)} ${need.symbol}`;
63
+ const title = `${actionName} for ${need.readable(needAmount)} ${need.symbol}`;
66
64
 
67
65
  const selectToken = async (from: Token, wallet?: OmniWallet) => {
68
66
  if (!wallet) return;
@@ -96,8 +94,8 @@ export const Payment = observer(({ connector, intents, payload, onReject, onSucc
96
94
  const signStep = async () => {
97
95
  try {
98
96
  setFlow((t) => (t ? { ...t, step: "sign", loading: true } : null));
99
- const commitment = await intents.sign();
100
- setFlow((t) => (t ? { ...t, step: "transfer", commitment, loading: false } : null));
97
+ await intents.sign();
98
+ setFlow((t) => (t ? { ...t, step: "transfer", loading: false } : null));
101
99
  } catch (error) {
102
100
  console.error(error);
103
101
  setFlow((t) => (t ? { ...t, step: "error", loading: false, error } : null));
@@ -107,20 +105,15 @@ export const Payment = observer(({ connector, intents, payload, onReject, onSucc
107
105
 
108
106
  const confirmPaymentStep = async () => {
109
107
  try {
110
- const commitment = flow?.commitment;
111
- if (!commitment) throw new Error("Commitment not found");
112
108
  if (!flow?.review) throw new Error("Review not found");
113
109
  setFlow((t) => (t ? { ...t, step: "loading" } : null));
114
110
 
115
- // make swap if need
116
- let depositAddress: string | undefined;
117
- if (flow.review != "direct") {
118
- const result = await connector.exchange.makeSwap(flow.review, { log: () => {} });
119
- depositAddress = typeof result.review?.qoute === "object" ? result.review?.qoute?.depositAddress : undefined;
111
+ if (flow.review == "direct") {
112
+ return setFlow({ step: "success", loading: false, success: { depositQoute: "direct" } });
120
113
  }
121
114
 
122
- const data = await api.yieldIntentCall({ depositAddress, commitment, payload });
123
- setFlow((t) => (t ? { ...t, step: "success", loading: false, success: true, data } : null));
115
+ const result = await connector.exchange.makeSwap(flow.review, { log: () => {} });
116
+ setFlow({ loading: false, step: "success", success: { depositQoute: result.review, processing: result.processing } });
124
117
  } catch (error) {
125
118
  console.error(error);
126
119
  setFlow((t) => (t ? { ...t, step: "error", loading: false, error } : null));
@@ -134,9 +127,9 @@ export const Payment = observer(({ connector, intents, payload, onReject, onSucc
134
127
  <div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
135
128
  {/* @ts-expect-error: dotlottie-wc is not typed */}
136
129
  <dotlottie-wc key="success" src={animations.success} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
137
- <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Payment successful</p>
130
+ <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>{actionName} successful</p>
138
131
  </div>
139
- <PopupButton style={{ marginTop: "auto" }} onClick={() => onSuccess(flow.data!)}>
132
+ <PopupButton style={{ marginTop: "auto" }} onClick={() => onConfirm(flow.success!)}>
140
133
  Continue
141
134
  </PopupButton>
142
135
  </Popup>
@@ -149,7 +142,7 @@ export const Payment = observer(({ connector, intents, payload, onReject, onSucc
149
142
  <div style={{ width: "100%", height: 400, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
150
143
  {/* @ts-expect-error: dotlottie-wc is not typed */}
151
144
  <dotlottie-wc key="loading" src={animations.loading} speed="1" style={{ marginTop: -64, width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
152
- <p style={{ fontSize: 24, marginTop: -16, fontWeight: "bold" }}>Processing payment</p>
145
+ <p style={{ fontSize: 24, marginTop: -16, fontWeight: "bold" }}>Processing {actionName.toLowerCase()}</p>
153
146
  </div>
154
147
  </Popup>
155
148
  );
@@ -161,7 +154,7 @@ export const Payment = observer(({ connector, intents, payload, onReject, onSucc
161
154
  <div style={{ width: "100%", height: 400, gap: 8, display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
162
155
  {/* @ts-expect-error: dotlottie-wc is not typed */}
163
156
  <dotlottie-wc key="error" src={animations.failed} speed="1" style={{ width: 300, height: 300 }} mode="forward" loop autoplay></dotlottie-wc>
164
- <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>Payment failed</p>
157
+ <p style={{ fontSize: 24, marginTop: -32, fontWeight: "bold" }}>{actionName} failed</p>
165
158
  <p style={{ fontSize: 14, width: "80%", textAlign: "center", overflowY: "auto", lineBreak: "anywhere" }}>{flow.error?.toString?.() ?? "Unknown error"}</p>
166
159
  </div>
167
160
  <PopupButton onClick={() => onReject(flow.error?.toString?.() ?? "Unknown error")}>Close</PopupButton>
@@ -197,7 +190,7 @@ export const Payment = observer(({ connector, intents, payload, onReject, onSucc
197
190
  </PopupOption>
198
191
 
199
192
  <PopupButton style={{ marginTop: 24 }} disabled={!flow?.review} onClick={confirmPaymentStep}>
200
- {flow?.loading ? "Confirming..." : "Confirm payment"}
193
+ {flow?.loading ? "Confirming..." : `Confirm ${actionName.toLowerCase()}`}
201
194
  </PopupButton>
202
195
  </Popup>
203
196
  );
@@ -273,8 +266,8 @@ export const Payment = observer(({ connector, intents, payload, onReject, onSucc
273
266
  <WalletIcon />
274
267
  </div>
275
268
  <PopupOptionInfo>
276
- <p>Connect wallet</p>
277
- <span className="wallet-address">To more pay options</span>
269
+ <p>Don't find the right token?</p>
270
+ <span className="wallet-address">Connect another wallet</span>
278
271
  </PopupOptionInfo>
279
272
  </PopupOption>
280
273
  </Popup>
package/src/ui/router.tsx CHANGED
@@ -21,16 +21,17 @@ import { LogoutPopup } from "./connect/LogoutPopup";
21
21
  import { WalletPicker } from "./connect/WalletPicker";
22
22
  import { Connector } from "./connect/ConnectWallet";
23
23
  import { WCRequest } from "./connect/WCRequest";
24
+ import Toast from "./Toast";
24
25
 
25
- export const openPayment = (connector: HotConnector, intents: Intents, payload?: Record<string, any>) => {
26
- return new Promise<{ paymentId: string; tx: string }>((resolve, reject) => {
26
+ export const openPayment = (connector: HotConnector, intents: Intents, actionName?: string) => {
27
+ return new Promise<{ depositQoute: BridgeReview | "direct"; processing?: () => Promise<BridgeReview> }>((resolve, reject) => {
27
28
  present((close) => (
28
29
  <Payment //
30
+ actionName={actionName}
29
31
  onReject={() => (close(), reject(new Error("User rejected")))}
30
- onSuccess={(task) => (close(), resolve(task))}
32
+ onConfirm={(args) => (close(), resolve(args))}
31
33
  connector={connector}
32
34
  intents={intents}
33
- payload={payload}
34
35
  />
35
36
  ));
36
37
  });
@@ -92,3 +93,7 @@ export const openWCRequest = <T,>(args: { task: () => Promise<T>; deeplink?: str
92
93
  present((close) => <WCRequest deeplink={args.deeplink} name={args.name} icon={args.icon} onClose={close} task={taskPromise} />);
93
94
  return taskPromise;
94
95
  };
96
+
97
+ export const openToast = (message: string) => {
98
+ return present(() => <Toast message={message} />);
99
+ };