@vetro-protocol/gateway 1.0.0-beta

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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/_esm/abi/gatewayAbi.js +185 -0
  4. package/_esm/abi/gatewayAbi.js.map +1 -0
  5. package/_esm/actions/index.js +18 -0
  6. package/_esm/actions/index.js.map +1 -0
  7. package/_esm/actions/public/getMaxWithdraw.js +28 -0
  8. package/_esm/actions/public/getMaxWithdraw.js.map +1 -0
  9. package/_esm/actions/public/getMintFee.js +28 -0
  10. package/_esm/actions/public/getMintFee.js.map +1 -0
  11. package/_esm/actions/public/getPeggedToken.js +23 -0
  12. package/_esm/actions/public/getPeggedToken.js.map +1 -0
  13. package/_esm/actions/public/getRedeemFee.js +28 -0
  14. package/_esm/actions/public/getRedeemFee.js.map +1 -0
  15. package/_esm/actions/public/getRedeemRequest.js +28 -0
  16. package/_esm/actions/public/getRedeemRequest.js.map +1 -0
  17. package/_esm/actions/public/getTreasury.js +23 -0
  18. package/_esm/actions/public/getTreasury.js.map +1 -0
  19. package/_esm/actions/public/getWithdrawalDelay.js +23 -0
  20. package/_esm/actions/public/getWithdrawalDelay.js.map +1 -0
  21. package/_esm/actions/public/getWithdrawalDelayEnabled.js +23 -0
  22. package/_esm/actions/public/getWithdrawalDelayEnabled.js.map +1 -0
  23. package/_esm/actions/public/index.js +12 -0
  24. package/_esm/actions/public/index.js.map +1 -0
  25. package/_esm/actions/public/isInstantRedeemWhitelisted.js +28 -0
  26. package/_esm/actions/public/isInstantRedeemWhitelisted.js.map +1 -0
  27. package/_esm/actions/public/previewDeposit.js +35 -0
  28. package/_esm/actions/public/previewDeposit.js.map +1 -0
  29. package/_esm/actions/public/previewRedeem.js +35 -0
  30. package/_esm/actions/public/previewRedeem.js.map +1 -0
  31. package/_esm/actions/wallet/cancelRedeemRequest.js +89 -0
  32. package/_esm/actions/wallet/cancelRedeemRequest.js.map +1 -0
  33. package/_esm/actions/wallet/deposit.js +193 -0
  34. package/_esm/actions/wallet/deposit.js.map +1 -0
  35. package/_esm/actions/wallet/redeem.js +226 -0
  36. package/_esm/actions/wallet/redeem.js.map +1 -0
  37. package/_esm/actions/wallet/requestRedeem.js +153 -0
  38. package/_esm/actions/wallet/requestRedeem.js.map +1 -0
  39. package/_esm/gatewayAddresses.js +18 -0
  40. package/_esm/gatewayAddresses.js.map +1 -0
  41. package/_esm/index.js +30 -0
  42. package/_esm/index.js.map +1 -0
  43. package/_esm/types.js +2 -0
  44. package/_esm/types.js.map +1 -0
  45. package/_esm/utils/isAddressValid.js +3 -0
  46. package/_esm/utils/isAddressValid.js.map +1 -0
  47. package/_types/abi/gatewayAbi.d.ts +252 -0
  48. package/_types/abi/gatewayAbi.d.ts.map +1 -0
  49. package/_types/actions/index.d.ts +16 -0
  50. package/_types/actions/index.d.ts.map +1 -0
  51. package/_types/actions/public/getMaxWithdraw.d.ts +6 -0
  52. package/_types/actions/public/getMaxWithdraw.d.ts.map +1 -0
  53. package/_types/actions/public/getMintFee.d.ts +6 -0
  54. package/_types/actions/public/getMintFee.d.ts.map +1 -0
  55. package/_types/actions/public/getPeggedToken.d.ts +5 -0
  56. package/_types/actions/public/getPeggedToken.d.ts.map +1 -0
  57. package/_types/actions/public/getRedeemFee.d.ts +6 -0
  58. package/_types/actions/public/getRedeemFee.d.ts.map +1 -0
  59. package/_types/actions/public/getRedeemRequest.d.ts +6 -0
  60. package/_types/actions/public/getRedeemRequest.d.ts.map +1 -0
  61. package/_types/actions/public/getTreasury.d.ts +5 -0
  62. package/_types/actions/public/getTreasury.d.ts.map +1 -0
  63. package/_types/actions/public/getWithdrawalDelay.d.ts +5 -0
  64. package/_types/actions/public/getWithdrawalDelay.d.ts.map +1 -0
  65. package/_types/actions/public/getWithdrawalDelayEnabled.d.ts +5 -0
  66. package/_types/actions/public/getWithdrawalDelayEnabled.d.ts.map +1 -0
  67. package/_types/actions/public/index.d.ts +12 -0
  68. package/_types/actions/public/index.d.ts.map +1 -0
  69. package/_types/actions/public/isInstantRedeemWhitelisted.d.ts +6 -0
  70. package/_types/actions/public/isInstantRedeemWhitelisted.d.ts.map +1 -0
  71. package/_types/actions/public/previewDeposit.d.ts +7 -0
  72. package/_types/actions/public/previewDeposit.d.ts.map +1 -0
  73. package/_types/actions/public/previewRedeem.d.ts +7 -0
  74. package/_types/actions/public/previewRedeem.d.ts.map +1 -0
  75. package/_types/actions/wallet/cancelRedeemRequest.d.ts +14 -0
  76. package/_types/actions/wallet/cancelRedeemRequest.d.ts.map +1 -0
  77. package/_types/actions/wallet/deposit.d.ts +19 -0
  78. package/_types/actions/wallet/deposit.d.ts.map +1 -0
  79. package/_types/actions/wallet/redeem.d.ts +24 -0
  80. package/_types/actions/wallet/redeem.d.ts.map +1 -0
  81. package/_types/actions/wallet/requestRedeem.d.ts +18 -0
  82. package/_types/actions/wallet/requestRedeem.d.ts.map +1 -0
  83. package/_types/gatewayAddresses.d.ts +8 -0
  84. package/_types/gatewayAddresses.d.ts.map +1 -0
  85. package/_types/index.d.ts +42 -0
  86. package/_types/index.d.ts.map +1 -0
  87. package/_types/types.d.ts +53 -0
  88. package/_types/types.d.ts.map +1 -0
  89. package/_types/utils/isAddressValid.d.ts +3 -0
  90. package/_types/utils/isAddressValid.d.ts.map +1 -0
  91. package/package.json +59 -0
  92. package/src/abi/gatewayAbi.ts +184 -0
  93. package/src/actions/index.ts +18 -0
  94. package/src/actions/public/getMaxWithdraw.ts +40 -0
  95. package/src/actions/public/getMintFee.ts +40 -0
  96. package/src/actions/public/getPeggedToken.ts +33 -0
  97. package/src/actions/public/getRedeemFee.ts +40 -0
  98. package/src/actions/public/getRedeemRequest.ts +40 -0
  99. package/src/actions/public/getTreasury.ts +33 -0
  100. package/src/actions/public/getWithdrawalDelay.ts +33 -0
  101. package/src/actions/public/getWithdrawalDelayEnabled.ts +33 -0
  102. package/src/actions/public/index.ts +11 -0
  103. package/src/actions/public/isInstantRedeemWhitelisted.ts +40 -0
  104. package/src/actions/public/previewDeposit.ts +49 -0
  105. package/src/actions/public/previewRedeem.ts +49 -0
  106. package/src/actions/wallet/cancelRedeemRequest.ts +135 -0
  107. package/src/actions/wallet/deposit.ts +277 -0
  108. package/src/actions/wallet/redeem.ts +321 -0
  109. package/src/actions/wallet/requestRedeem.ts +226 -0
  110. package/src/gatewayAddresses.ts +27 -0
  111. package/src/index.ts +79 -0
  112. package/src/types.ts +60 -0
  113. package/src/utils/isAddressValid.ts +4 -0
@@ -0,0 +1,321 @@
1
+ import { EventEmitter } from "events";
2
+ import { toPromiseEvent } from "to-promise-event";
3
+ import {
4
+ type Address,
5
+ type TransactionReceipt,
6
+ type WalletClient,
7
+ encodeFunctionData,
8
+ isAddress,
9
+ isAddressEqual,
10
+ zeroAddress,
11
+ } from "viem";
12
+ import { waitForTransactionReceipt, writeContract } from "viem/actions";
13
+ import { allowance, approve } from "viem-erc20/actions";
14
+
15
+ import { gatewayAbi } from "../../abi/gatewayAbi.js";
16
+ import type { RedeemEvents } from "../../types.js";
17
+ import { getMaxWithdraw } from "../public/getMaxWithdraw.js";
18
+ import { getPeggedToken } from "../public/getPeggedToken.js";
19
+ import { getWithdrawalDelayEnabled } from "../public/getWithdrawalDelayEnabled.js";
20
+ import { isInstantRedeemWhitelisted } from "../public/isInstantRedeemWhitelisted.js";
21
+
22
+ export type RedeemParams = {
23
+ approveAmount?: bigint;
24
+ gatewayAddress: Address;
25
+ minAmountOut: bigint;
26
+ peggedTokenIn: bigint;
27
+ receiver: Address;
28
+ tokenOut: Address;
29
+ };
30
+
31
+ const canRedeem = async function ({
32
+ approveAmount,
33
+ client,
34
+ gatewayAddress,
35
+ minAmountOut,
36
+ peggedTokenIn,
37
+ receiver,
38
+ tokenOut,
39
+ }: {
40
+ approveAmount: bigint;
41
+ client: WalletClient;
42
+ gatewayAddress: Address;
43
+ minAmountOut: bigint;
44
+ peggedTokenIn: bigint;
45
+ receiver: Address;
46
+ tokenOut: Address;
47
+ }): Promise<{
48
+ canRedeem: boolean;
49
+ reason?: string;
50
+ }> {
51
+ // Validate client
52
+ if (!client) {
53
+ return {
54
+ canRedeem: false,
55
+ reason: "Client is not defined",
56
+ };
57
+ }
58
+ if (!client.chain) {
59
+ return {
60
+ canRedeem: false,
61
+ reason: "Chain is not defined on wallet client",
62
+ };
63
+ }
64
+ // Validate client has required properties
65
+ if (!client.account) {
66
+ return {
67
+ canRedeem: false,
68
+ reason: "Client must have an account",
69
+ };
70
+ }
71
+ // Validate gateway address
72
+ if (!gatewayAddress || !isAddress(gatewayAddress)) {
73
+ return {
74
+ canRedeem: false,
75
+ reason: "Invalid gateway address",
76
+ };
77
+ }
78
+ if (isAddressEqual(gatewayAddress, zeroAddress)) {
79
+ return {
80
+ canRedeem: false,
81
+ reason: "Gateway address cannot be zero address",
82
+ };
83
+ }
84
+ // Validate tokenOut address
85
+ if (!tokenOut || !isAddress(tokenOut)) {
86
+ return {
87
+ canRedeem: false,
88
+ reason: "Invalid token address",
89
+ };
90
+ }
91
+ if (isAddressEqual(tokenOut, zeroAddress)) {
92
+ return {
93
+ canRedeem: false,
94
+ reason: "Token address cannot be zero address",
95
+ };
96
+ }
97
+
98
+ // Validate receiver address
99
+ if (!receiver || !isAddress(receiver)) {
100
+ return {
101
+ canRedeem: false,
102
+ reason: "Invalid receiver address",
103
+ };
104
+ }
105
+ if (isAddressEqual(receiver, zeroAddress)) {
106
+ return {
107
+ canRedeem: false,
108
+ reason: "Receiver address cannot be zero address",
109
+ };
110
+ }
111
+
112
+ // Validate peggedTokenIn
113
+ if (typeof peggedTokenIn !== "bigint") {
114
+ return {
115
+ canRedeem: false,
116
+ reason: "Amount must be a bigint",
117
+ };
118
+ }
119
+ if (peggedTokenIn <= 0n) {
120
+ return {
121
+ canRedeem: false,
122
+ reason: "Amount must be greater than 0",
123
+ };
124
+ }
125
+
126
+ // Validate minAmountOut
127
+ if (typeof minAmountOut !== "bigint") {
128
+ return {
129
+ canRedeem: false,
130
+ reason: "Minimum output must be a bigint",
131
+ };
132
+ }
133
+ if (minAmountOut < 0n) {
134
+ return {
135
+ canRedeem: false,
136
+ reason: "Minimum output cannot be negative",
137
+ };
138
+ }
139
+ // Validate approveAmount
140
+ if (approveAmount < peggedTokenIn) {
141
+ return {
142
+ canRedeem: false,
143
+ reason: "Approve amount must be greater than or equal to amount",
144
+ };
145
+ }
146
+
147
+ // Check treasury has enough balance for the requested token
148
+ const maxWithdrawable = await getMaxWithdraw(client, {
149
+ address: gatewayAddress,
150
+ tokenOut,
151
+ });
152
+
153
+ if (minAmountOut > maxWithdrawable) {
154
+ return {
155
+ canRedeem: false,
156
+ reason: "Not enough balance in treasury",
157
+ };
158
+ }
159
+
160
+ return { canRedeem: true };
161
+ };
162
+
163
+ const runRedeem = (
164
+ walletClient: WalletClient,
165
+ {
166
+ approveAmount,
167
+ gatewayAddress,
168
+ minAmountOut,
169
+ peggedTokenIn,
170
+ receiver,
171
+ tokenOut,
172
+ }: RedeemParams,
173
+ ) =>
174
+ async function (emitter: EventEmitter<RedeemEvents>) {
175
+ const resolvedApproveAmount = approveAmount ?? peggedTokenIn;
176
+ try {
177
+ const { canRedeem: canRedeemFlag, reason } = await canRedeem({
178
+ approveAmount: resolvedApproveAmount,
179
+ client: walletClient,
180
+ gatewayAddress,
181
+ minAmountOut,
182
+ peggedTokenIn,
183
+ receiver,
184
+ tokenOut,
185
+ });
186
+
187
+ if (!canRedeemFlag) {
188
+ emitter.emit("redeem-failed-validation", reason!);
189
+ return;
190
+ }
191
+
192
+ // Check if user is whitelisted for instant redeem
193
+ const [isWhitelisted, delayEnabled] = await Promise.all([
194
+ isInstantRedeemWhitelisted(walletClient, {
195
+ account: walletClient.account!.address,
196
+ address: gatewayAddress,
197
+ }),
198
+ getWithdrawalDelayEnabled(walletClient, {
199
+ address: gatewayAddress,
200
+ }),
201
+ ]);
202
+
203
+ // Approval is needed when the user is whitelisted (instant redeem burns pegged tokens)
204
+ // or when delay is disabled (redeem completes immediately)
205
+ if (isWhitelisted || !delayEnabled) {
206
+ // Get the pegged token address
207
+ const peggedTokenAddress = await getPeggedToken(walletClient, {
208
+ address: gatewayAddress,
209
+ });
210
+
211
+ // Check current allowance for pegged token
212
+ const currentAllowance = await allowance(walletClient, {
213
+ address: peggedTokenAddress,
214
+ owner: walletClient.account!.address,
215
+ spender: gatewayAddress,
216
+ });
217
+
218
+ // If allowance is insufficient, approve first
219
+ if (currentAllowance < peggedTokenIn) {
220
+ emitter.emit("pre-approve");
221
+
222
+ const approvalHash = await approve(walletClient, {
223
+ address: peggedTokenAddress,
224
+ amount: resolvedApproveAmount,
225
+ spender: gatewayAddress,
226
+ }).catch(function (error: Error) {
227
+ emitter.emit("user-signing-approval-error", error);
228
+ });
229
+
230
+ if (!approvalHash) {
231
+ return;
232
+ }
233
+
234
+ emitter.emit("user-signed-approval", approvalHash);
235
+
236
+ const approvalReceipt = await waitForTransactionReceipt(
237
+ walletClient,
238
+ {
239
+ hash: approvalHash,
240
+ },
241
+ ).catch(function (error: Error) {
242
+ emitter.emit("redeem-failed", error);
243
+ });
244
+
245
+ if (!approvalReceipt) {
246
+ return;
247
+ }
248
+
249
+ if (approvalReceipt.status === "reverted") {
250
+ emitter.emit("approve-transaction-reverted", approvalReceipt);
251
+ return;
252
+ }
253
+
254
+ emitter.emit("approve-transaction-succeeded", approvalReceipt);
255
+ }
256
+ }
257
+
258
+ emitter.emit("pre-redeem");
259
+
260
+ const redeemHash = await writeContract(walletClient, {
261
+ abi: gatewayAbi,
262
+ account: walletClient.account!,
263
+ address: gatewayAddress,
264
+ args: [tokenOut, peggedTokenIn, minAmountOut, receiver],
265
+ chain: walletClient.chain,
266
+ functionName: "redeem",
267
+ }).catch(function (error: Error) {
268
+ emitter.emit("user-signing-redeem-error", error);
269
+ });
270
+
271
+ if (!redeemHash) {
272
+ return;
273
+ }
274
+
275
+ emitter.emit("user-signed-redeem", redeemHash);
276
+
277
+ const redeemReceipt = await waitForTransactionReceipt(walletClient, {
278
+ hash: redeemHash,
279
+ }).catch(function (error: Error) {
280
+ emitter.emit("redeem-failed", error);
281
+ });
282
+
283
+ if (!redeemReceipt) {
284
+ return;
285
+ }
286
+
287
+ const redeemEventMap: Record<
288
+ TransactionReceipt["status"],
289
+ keyof RedeemEvents
290
+ > = {
291
+ reverted: "redeem-transaction-reverted",
292
+ success: "redeem-transaction-succeeded",
293
+ };
294
+
295
+ emitter.emit(redeemEventMap[redeemReceipt.status], redeemReceipt);
296
+ } catch (error) {
297
+ emitter.emit("unexpected-error", error as Error);
298
+ } finally {
299
+ emitter.emit("redeem-settled");
300
+ }
301
+ };
302
+
303
+ export const redeem = (...args: Parameters<typeof runRedeem>) =>
304
+ toPromiseEvent<RedeemEvents>(runRedeem(...args));
305
+
306
+ export const encodeRedeem = ({
307
+ minAmountOut,
308
+ peggedTokenIn,
309
+ receiver,
310
+ tokenOut,
311
+ }: {
312
+ minAmountOut: bigint;
313
+ peggedTokenIn: bigint;
314
+ receiver: Address;
315
+ tokenOut: Address;
316
+ }) =>
317
+ encodeFunctionData({
318
+ abi: gatewayAbi,
319
+ args: [tokenOut, peggedTokenIn, minAmountOut, receiver],
320
+ functionName: "redeem",
321
+ });
@@ -0,0 +1,226 @@
1
+ import { EventEmitter } from "events";
2
+ import { toPromiseEvent } from "to-promise-event";
3
+ import {
4
+ type Address,
5
+ type TransactionReceipt,
6
+ type WalletClient,
7
+ encodeFunctionData,
8
+ isAddress,
9
+ isAddressEqual,
10
+ zeroAddress,
11
+ } from "viem";
12
+ import { waitForTransactionReceipt, writeContract } from "viem/actions";
13
+ import { allowance, approve } from "viem-erc20/actions";
14
+
15
+ import { gatewayAbi } from "../../abi/gatewayAbi.js";
16
+ import type { RequestRedeemEvents } from "../../types.js";
17
+ import { getPeggedToken } from "../public/getPeggedToken.js";
18
+
19
+ export type RequestRedeemParams = {
20
+ approveAmount?: bigint;
21
+ gatewayAddress: Address;
22
+ peggedTokenAmount: bigint;
23
+ };
24
+
25
+ const canRequestRedeem = function ({
26
+ approveAmount,
27
+ client,
28
+ gatewayAddress,
29
+ peggedTokenAmount,
30
+ }: {
31
+ approveAmount: bigint;
32
+ client: WalletClient;
33
+ gatewayAddress: Address;
34
+ peggedTokenAmount: bigint;
35
+ }): {
36
+ canRequestRedeem: boolean;
37
+ reason?: string;
38
+ } {
39
+ if (!client) {
40
+ return {
41
+ canRequestRedeem: false,
42
+ reason: "Client is not defined",
43
+ };
44
+ }
45
+ if (!client.chain) {
46
+ return {
47
+ canRequestRedeem: false,
48
+ reason: "Chain is not defined on wallet client",
49
+ };
50
+ }
51
+ if (!client.account) {
52
+ return {
53
+ canRequestRedeem: false,
54
+ reason: "Client must have an account",
55
+ };
56
+ }
57
+ // Validate gateway address
58
+ if (!gatewayAddress || !isAddress(gatewayAddress)) {
59
+ return {
60
+ canRequestRedeem: false,
61
+ reason: "Invalid gateway address",
62
+ };
63
+ }
64
+ if (isAddressEqual(gatewayAddress, zeroAddress)) {
65
+ return {
66
+ canRequestRedeem: false,
67
+ reason: "Gateway address cannot be zero address",
68
+ };
69
+ }
70
+
71
+ if (typeof peggedTokenAmount !== "bigint") {
72
+ return {
73
+ canRequestRedeem: false,
74
+ reason: "Amount must be a bigint",
75
+ };
76
+ }
77
+ if (peggedTokenAmount <= 0n) {
78
+ return {
79
+ canRequestRedeem: false,
80
+ reason: "Amount must be greater than 0",
81
+ };
82
+ }
83
+
84
+ // Validate approveAmount
85
+ if (approveAmount < peggedTokenAmount) {
86
+ return {
87
+ canRequestRedeem: false,
88
+ reason: "Approve amount must be greater than or equal to amount",
89
+ };
90
+ }
91
+
92
+ return { canRequestRedeem: true };
93
+ };
94
+
95
+ const runRequestRedeem = (
96
+ walletClient: WalletClient,
97
+ { approveAmount, gatewayAddress, peggedTokenAmount }: RequestRedeemParams,
98
+ ) =>
99
+ async function (emitter: EventEmitter<RequestRedeemEvents>) {
100
+ const resolvedApproveAmount = approveAmount ?? peggedTokenAmount;
101
+ try {
102
+ const { canRequestRedeem: canRequestRedeemFlag, reason } =
103
+ canRequestRedeem({
104
+ approveAmount: resolvedApproveAmount,
105
+ client: walletClient,
106
+ gatewayAddress,
107
+ peggedTokenAmount,
108
+ });
109
+
110
+ if (!canRequestRedeemFlag) {
111
+ emitter.emit("request-redeem-failed-validation", reason!);
112
+ return;
113
+ }
114
+
115
+ // Get the pegged token address
116
+ const peggedTokenAddress = await getPeggedToken(walletClient, {
117
+ address: gatewayAddress,
118
+ });
119
+
120
+ // Check current allowance for pegged token
121
+ const currentAllowance = await allowance(walletClient, {
122
+ address: peggedTokenAddress,
123
+ owner: walletClient.account!.address,
124
+ spender: gatewayAddress,
125
+ });
126
+
127
+ // If allowance is insufficient, approve first
128
+ if (currentAllowance < peggedTokenAmount) {
129
+ emitter.emit("pre-approve");
130
+
131
+ const approvalHash = await approve(walletClient, {
132
+ address: peggedTokenAddress,
133
+ amount: resolvedApproveAmount,
134
+ spender: gatewayAddress,
135
+ }).catch(function (error: Error) {
136
+ emitter.emit("user-signing-approval-error", error);
137
+ });
138
+
139
+ if (!approvalHash) {
140
+ return;
141
+ }
142
+
143
+ emitter.emit("user-signed-approval", approvalHash);
144
+
145
+ const approvalReceipt = await waitForTransactionReceipt(walletClient, {
146
+ hash: approvalHash,
147
+ }).catch(function (error: Error) {
148
+ emitter.emit("request-redeem-failed", error);
149
+ });
150
+
151
+ if (!approvalReceipt) {
152
+ return;
153
+ }
154
+
155
+ if (approvalReceipt.status === "reverted") {
156
+ emitter.emit("approve-transaction-reverted", approvalReceipt);
157
+ return;
158
+ }
159
+
160
+ emitter.emit("approve-transaction-succeeded", approvalReceipt);
161
+ }
162
+
163
+ emitter.emit("pre-request-redeem");
164
+
165
+ const requestRedeemHash = await writeContract(walletClient, {
166
+ abi: gatewayAbi,
167
+ account: walletClient.account!,
168
+ address: gatewayAddress,
169
+ args: [peggedTokenAmount],
170
+ chain: walletClient.chain,
171
+ functionName: "requestRedeem",
172
+ }).catch(function (error: Error) {
173
+ emitter.emit("user-signing-request-redeem-error", error);
174
+ });
175
+
176
+ if (!requestRedeemHash) {
177
+ return;
178
+ }
179
+
180
+ emitter.emit("user-signed-request-redeem", requestRedeemHash);
181
+
182
+ const requestRedeemReceipt = await waitForTransactionReceipt(
183
+ walletClient,
184
+ {
185
+ hash: requestRedeemHash,
186
+ },
187
+ ).catch(function (error: Error) {
188
+ emitter.emit("request-redeem-failed", error);
189
+ });
190
+
191
+ if (!requestRedeemReceipt) {
192
+ return;
193
+ }
194
+
195
+ const requestRedeemEventMap: Record<
196
+ TransactionReceipt["status"],
197
+ keyof RequestRedeemEvents
198
+ > = {
199
+ reverted: "request-redeem-transaction-reverted",
200
+ success: "request-redeem-transaction-succeeded",
201
+ };
202
+
203
+ emitter.emit(
204
+ requestRedeemEventMap[requestRedeemReceipt.status],
205
+ requestRedeemReceipt,
206
+ );
207
+ } catch (error) {
208
+ emitter.emit("unexpected-error", error as Error);
209
+ } finally {
210
+ emitter.emit("request-redeem-settled");
211
+ }
212
+ };
213
+
214
+ export const requestRedeem = (...args: Parameters<typeof runRequestRedeem>) =>
215
+ toPromiseEvent<RequestRedeemEvents>(runRequestRedeem(...args));
216
+
217
+ export const encodeRequestRedeem = ({
218
+ peggedTokenAmount,
219
+ }: {
220
+ peggedTokenAmount: bigint;
221
+ }) =>
222
+ encodeFunctionData({
223
+ abi: gatewayAbi,
224
+ args: [peggedTokenAmount],
225
+ functionName: "requestRedeem",
226
+ });
@@ -0,0 +1,27 @@
1
+ import type { Address } from "viem";
2
+
3
+ export type Gateway = {
4
+ address: Address;
5
+ // Portal-API symbol used to convert this gateway's peg unit into USD.
6
+ // "USD" is treated as identity (no conversion needed).
7
+ pegBaseSymbol: string;
8
+ };
9
+
10
+ // Whitelisted-token oracles within a gateway are denominated in the gateway's
11
+ // peg unit (e.g. WBTC/BTC for the vetBTC gateway, USDT/USD for the VUSD gateway),
12
+ // so the USD price for any whitelisted token is `oracle × portal[pegBaseSymbol]`.
13
+ // See `web/src/fetchers/fetchPrices.ts` for the merge.
14
+ export const gateways: Gateway[] = [
15
+ // VUSD
16
+ {
17
+ address: "0xDaD503f8B9d42bb7af3AfC588358D30163e4416F",
18
+ pegBaseSymbol: "USD",
19
+ },
20
+ // vetBTC
21
+ {
22
+ address: "0xCBA2Ffa0AC52d7871a4221a871793Eb788013faB",
23
+ pegBaseSymbol: "BTC",
24
+ },
25
+ ];
26
+
27
+ export const gatewayAddresses: Address[] = gateways.map((g) => g.address);
package/src/index.ts ADDED
@@ -0,0 +1,79 @@
1
+ import type { Client, WalletClient } from "viem";
2
+
3
+ import {
4
+ getMaxWithdraw,
5
+ getMintFee,
6
+ getPeggedToken,
7
+ getRedeemFee,
8
+ getRedeemRequest,
9
+ getTreasury,
10
+ getWithdrawalDelay,
11
+ getWithdrawalDelayEnabled,
12
+ isInstantRedeemWhitelisted,
13
+ previewDeposit,
14
+ previewRedeem,
15
+ } from "./actions/public/index.js";
16
+ import {
17
+ type CancelRedeemRequestParams,
18
+ cancelRedeemRequest,
19
+ } from "./actions/wallet/cancelRedeemRequest.js";
20
+ import { type DepositParams, deposit } from "./actions/wallet/deposit.js";
21
+ import { type RedeemParams, redeem } from "./actions/wallet/redeem.js";
22
+ import {
23
+ type RequestRedeemParams,
24
+ requestRedeem,
25
+ } from "./actions/wallet/requestRedeem.js";
26
+
27
+ // Export ABI
28
+ export { gatewayAbi } from "./abi/gatewayAbi.js";
29
+ // Export gateway addresses and per-gateway peg-base metadata
30
+ export {
31
+ type Gateway,
32
+ gatewayAddresses,
33
+ gateways,
34
+ } from "./gatewayAddresses.js";
35
+
36
+ export type { CancelRedeemRequestParams };
37
+
38
+ export {
39
+ type CancelRedeemRequestEvents,
40
+ type DepositEvents,
41
+ type RedeemEvents,
42
+ type RequestRedeemEvents,
43
+ } from "./types.js";
44
+
45
+ // Export factory functions for .extend() pattern
46
+ export const gatewayPublicActions = () => (client: Client) => ({
47
+ getMaxWithdraw: (params: Parameters<typeof getMaxWithdraw>[1]) =>
48
+ getMaxWithdraw(client, params),
49
+ getMintFee: (params: Parameters<typeof getMintFee>[1]) =>
50
+ getMintFee(client, params),
51
+ getPeggedToken: (params: Parameters<typeof getPeggedToken>[1]) =>
52
+ getPeggedToken(client, params),
53
+ getRedeemFee: (params: Parameters<typeof getRedeemFee>[1]) =>
54
+ getRedeemFee(client, params),
55
+ getRedeemRequest: (params: Parameters<typeof getRedeemRequest>[1]) =>
56
+ getRedeemRequest(client, params),
57
+ getTreasury: (params: Parameters<typeof getTreasury>[1]) =>
58
+ getTreasury(client, params),
59
+ getWithdrawalDelay: (params: Parameters<typeof getWithdrawalDelay>[1]) =>
60
+ getWithdrawalDelay(client, params),
61
+ getWithdrawalDelayEnabled: (
62
+ params: Parameters<typeof getWithdrawalDelayEnabled>[1],
63
+ ) => getWithdrawalDelayEnabled(client, params),
64
+ isInstantRedeemWhitelisted: (
65
+ params: Parameters<typeof isInstantRedeemWhitelisted>[1],
66
+ ) => isInstantRedeemWhitelisted(client, params),
67
+ previewDeposit: (params: Parameters<typeof previewDeposit>[1]) =>
68
+ previewDeposit(client, params),
69
+ previewRedeem: (params: Parameters<typeof previewRedeem>[1]) =>
70
+ previewRedeem(client, params),
71
+ });
72
+
73
+ export const gatewayWalletActions = () => (client: WalletClient) => ({
74
+ cancelRedeemRequest: (params: CancelRedeemRequestParams) =>
75
+ cancelRedeemRequest(client, params),
76
+ deposit: (params: DepositParams) => deposit(client, params),
77
+ redeem: (params: RedeemParams) => redeem(client, params),
78
+ requestRedeem: (params: RequestRedeemParams) => requestRedeem(client, params),
79
+ });
package/src/types.ts ADDED
@@ -0,0 +1,60 @@
1
+ import type { Hash, TransactionReceipt } from "viem";
2
+
3
+ type CommonEvents = {
4
+ "unexpected-error": [Error];
5
+ };
6
+
7
+ type ApprovalEvents = {
8
+ "approve-transaction-reverted": [TransactionReceipt];
9
+ "approve-transaction-succeeded": [TransactionReceipt];
10
+ "pre-approve": [];
11
+ "user-signed-approval": [Hash];
12
+ "user-signing-approval-error": [Error];
13
+ };
14
+
15
+ export type DepositEvents = ApprovalEvents &
16
+ CommonEvents & {
17
+ "deposit-failed": [Error];
18
+ "deposit-failed-validation": [string];
19
+ "deposit-settled": [];
20
+ "deposit-transaction-reverted": [TransactionReceipt];
21
+ "deposit-transaction-succeeded": [TransactionReceipt];
22
+ "pre-deposit": [];
23
+ "user-signed-deposit": [Hash];
24
+ "user-signing-deposit-error": [Error];
25
+ };
26
+
27
+ export type CancelRedeemRequestEvents = CommonEvents & {
28
+ "cancel-redeem-request-failed": [Error];
29
+ "cancel-redeem-request-failed-validation": [string];
30
+ "cancel-redeem-request-settled": [];
31
+ "cancel-redeem-request-transaction-reverted": [TransactionReceipt];
32
+ "cancel-redeem-request-transaction-succeeded": [TransactionReceipt];
33
+ "pre-cancel-redeem-request": [];
34
+ "user-signed-cancel-redeem-request": [Hash];
35
+ "user-signing-cancel-redeem-request-error": [Error];
36
+ };
37
+
38
+ export type RedeemEvents = ApprovalEvents &
39
+ CommonEvents & {
40
+ "pre-redeem": [];
41
+ "redeem-failed": [Error];
42
+ "redeem-failed-validation": [string];
43
+ "redeem-settled": [];
44
+ "redeem-transaction-reverted": [TransactionReceipt];
45
+ "redeem-transaction-succeeded": [TransactionReceipt];
46
+ "user-signed-redeem": [Hash];
47
+ "user-signing-redeem-error": [Error];
48
+ };
49
+
50
+ export type RequestRedeemEvents = ApprovalEvents &
51
+ CommonEvents & {
52
+ "pre-request-redeem": [];
53
+ "request-redeem-failed": [Error];
54
+ "request-redeem-failed-validation": [string];
55
+ "request-redeem-settled": [];
56
+ "request-redeem-transaction-reverted": [TransactionReceipt];
57
+ "request-redeem-transaction-succeeded": [TransactionReceipt];
58
+ "user-signed-request-redeem": [Hash];
59
+ "user-signing-request-redeem-error": [Error];
60
+ };