@stablechain/sdk 1.0.4 → 1.0.5
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.
- package/README.md +757 -0
- package/dist/chunk-QQ26UI3F.cjs +665 -0
- package/dist/chunk-VS6GBRDF.js +665 -0
- package/dist/erc3009.cjs +26 -0
- package/dist/erc3009.d.cts +429 -0
- package/dist/erc3009.d.ts +429 -0
- package/dist/erc3009.js +26 -0
- package/dist/index.cjs +451 -221
- package/dist/index.d.cts +82 -4
- package/dist/index.d.ts +82 -4
- package/dist/index.js +346 -116
- package/package.json +6 -1
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } async function _asyncOptionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = await fn(value); } else if (op === 'call' || op === 'optionalCall') { value = await fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/services/erc3009/abi.ts
|
|
2
|
+
var ERC3009_ABI = [
|
|
3
|
+
{
|
|
4
|
+
type: "function",
|
|
5
|
+
name: "transferWithAuthorization",
|
|
6
|
+
stateMutability: "nonpayable",
|
|
7
|
+
inputs: [
|
|
8
|
+
{ name: "from", type: "address" },
|
|
9
|
+
{ name: "to", type: "address" },
|
|
10
|
+
{ name: "value", type: "uint256" },
|
|
11
|
+
{ name: "validAfter", type: "uint256" },
|
|
12
|
+
{ name: "validBefore", type: "uint256" },
|
|
13
|
+
{ name: "nonce", type: "bytes32" },
|
|
14
|
+
{ name: "v", type: "uint8" },
|
|
15
|
+
{ name: "r", type: "bytes32" },
|
|
16
|
+
{ name: "s", type: "bytes32" }
|
|
17
|
+
],
|
|
18
|
+
outputs: []
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
type: "function",
|
|
22
|
+
name: "receiveWithAuthorization",
|
|
23
|
+
stateMutability: "nonpayable",
|
|
24
|
+
inputs: [
|
|
25
|
+
{ name: "from", type: "address" },
|
|
26
|
+
{ name: "to", type: "address" },
|
|
27
|
+
{ name: "value", type: "uint256" },
|
|
28
|
+
{ name: "validAfter", type: "uint256" },
|
|
29
|
+
{ name: "validBefore", type: "uint256" },
|
|
30
|
+
{ name: "nonce", type: "bytes32" },
|
|
31
|
+
{ name: "v", type: "uint8" },
|
|
32
|
+
{ name: "r", type: "bytes32" },
|
|
33
|
+
{ name: "s", type: "bytes32" }
|
|
34
|
+
],
|
|
35
|
+
outputs: []
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: "function",
|
|
39
|
+
name: "cancelAuthorization",
|
|
40
|
+
stateMutability: "nonpayable",
|
|
41
|
+
inputs: [
|
|
42
|
+
{ name: "authorizer", type: "address" },
|
|
43
|
+
{ name: "nonce", type: "bytes32" },
|
|
44
|
+
{ name: "v", type: "uint8" },
|
|
45
|
+
{ name: "r", type: "bytes32" },
|
|
46
|
+
{ name: "s", type: "bytes32" }
|
|
47
|
+
],
|
|
48
|
+
outputs: []
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: "function",
|
|
52
|
+
name: "authorizationState",
|
|
53
|
+
stateMutability: "view",
|
|
54
|
+
inputs: [
|
|
55
|
+
{ name: "authorizer", type: "address" },
|
|
56
|
+
{ name: "nonce", type: "bytes32" }
|
|
57
|
+
],
|
|
58
|
+
outputs: [{ name: "", type: "bool" }]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: "function",
|
|
62
|
+
name: "balanceOf",
|
|
63
|
+
stateMutability: "view",
|
|
64
|
+
inputs: [{ name: "account", type: "address" }],
|
|
65
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: "event",
|
|
69
|
+
name: "AuthorizationUsed",
|
|
70
|
+
anonymous: false,
|
|
71
|
+
inputs: [
|
|
72
|
+
{ name: "authorizer", type: "address", indexed: true },
|
|
73
|
+
{ name: "nonce", type: "bytes32", indexed: true }
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: "function",
|
|
78
|
+
name: "eip712Domain",
|
|
79
|
+
stateMutability: "view",
|
|
80
|
+
inputs: [],
|
|
81
|
+
outputs: [
|
|
82
|
+
{ name: "fields", type: "bytes1" },
|
|
83
|
+
{ name: "name", type: "string" },
|
|
84
|
+
{ name: "version", type: "string" },
|
|
85
|
+
{ name: "chainId", type: "uint256" },
|
|
86
|
+
{ name: "verifyingContract", type: "address" },
|
|
87
|
+
{ name: "salt", type: "bytes32" },
|
|
88
|
+
{ name: "extensions", type: "uint256[]" }
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: "function",
|
|
93
|
+
name: "name",
|
|
94
|
+
stateMutability: "view",
|
|
95
|
+
inputs: [],
|
|
96
|
+
outputs: [{ name: "", type: "string" }]
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
var AUTHORIZATION_FIELDS = [
|
|
100
|
+
{ name: "from", type: "address" },
|
|
101
|
+
{ name: "to", type: "address" },
|
|
102
|
+
{ name: "value", type: "uint256" },
|
|
103
|
+
{ name: "validAfter", type: "uint256" },
|
|
104
|
+
{ name: "validBefore", type: "uint256" },
|
|
105
|
+
{ name: "nonce", type: "bytes32" }
|
|
106
|
+
];
|
|
107
|
+
var TRANSFER_WITH_AUTHORIZATION_TYPES = {
|
|
108
|
+
TransferWithAuthorization: AUTHORIZATION_FIELDS
|
|
109
|
+
};
|
|
110
|
+
var RECEIVE_WITH_AUTHORIZATION_TYPES = {
|
|
111
|
+
ReceiveWithAuthorization: AUTHORIZATION_FIELDS
|
|
112
|
+
};
|
|
113
|
+
var CANCEL_AUTHORIZATION_TYPES = {
|
|
114
|
+
CancelAuthorization: [
|
|
115
|
+
{ name: "authorizer", type: "address" },
|
|
116
|
+
{ name: "nonce", type: "bytes32" }
|
|
117
|
+
]
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// src/services/erc3009/signAuthorization.ts
|
|
121
|
+
var _actions = require('viem/actions');
|
|
122
|
+
|
|
123
|
+
// src/constants.ts
|
|
124
|
+
var STABLE_USDT_ADDRESS = "0x779ded0c9e1022225f8e0630b35a9b54be713736";
|
|
125
|
+
var STABLE_VAULT_ADDRESS = "0xb7Df8db22A5DBBFA9ebeb94b3910aec6a4f05c08";
|
|
126
|
+
|
|
127
|
+
// src/errors.ts
|
|
128
|
+
var _viem = require('viem');
|
|
129
|
+
var StableError = class extends _viem.BaseError {
|
|
130
|
+
};
|
|
131
|
+
var StableValidationError = class extends StableError {
|
|
132
|
+
constructor(field, value, reason, opts) {
|
|
133
|
+
super(reason, {
|
|
134
|
+
name: "StableValidationError",
|
|
135
|
+
cause: _optionalChain([opts, 'optionalAccess', _ => _.cause]),
|
|
136
|
+
metaMessages: [`Field: ${field}`, `Value: ${formatValue(value)}`]
|
|
137
|
+
});
|
|
138
|
+
this.field = field;
|
|
139
|
+
this.value = value;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
var StableQuoteError = class extends StableError {
|
|
143
|
+
constructor(args) {
|
|
144
|
+
const meta = [`Provider: ${args.provider}`];
|
|
145
|
+
if (args.httpStatus !== void 0)
|
|
146
|
+
meta.push(`HTTP status: ${args.httpStatus}`);
|
|
147
|
+
if (args.providerCode) meta.push(`Provider code: ${args.providerCode}`);
|
|
148
|
+
super(args.shortMessage, {
|
|
149
|
+
name: "StableQuoteError",
|
|
150
|
+
cause: args.cause,
|
|
151
|
+
metaMessages: meta
|
|
152
|
+
});
|
|
153
|
+
this.provider = args.provider;
|
|
154
|
+
this.httpStatus = args.httpStatus;
|
|
155
|
+
this.providerCode = args.providerCode;
|
|
156
|
+
this.body = args.body;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
var StableTransactionError = class extends StableError {
|
|
160
|
+
constructor(args) {
|
|
161
|
+
const meta = [`Phase: ${args.phase}`];
|
|
162
|
+
if (args.chainId !== void 0) meta.push(`Chain ID: ${args.chainId}`);
|
|
163
|
+
if (args.txHash) meta.push(`Tx hash: ${args.txHash}`);
|
|
164
|
+
if (args.revertReason) meta.push(`Revert reason: ${args.revertReason}`);
|
|
165
|
+
super(args.shortMessage, {
|
|
166
|
+
name: "StableTransactionError",
|
|
167
|
+
cause: args.cause,
|
|
168
|
+
metaMessages: meta
|
|
169
|
+
});
|
|
170
|
+
this.phase = args.phase;
|
|
171
|
+
this.txHash = args.txHash;
|
|
172
|
+
this.chainId = args.chainId;
|
|
173
|
+
this.revertReason = args.revertReason;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
var StableNetworkError = class extends StableError {
|
|
177
|
+
constructor(args) {
|
|
178
|
+
super(args.shortMessage, {
|
|
179
|
+
name: "StableNetworkError",
|
|
180
|
+
cause: args.cause,
|
|
181
|
+
metaMessages: args.url ? [`URL: ${args.url}`] : void 0
|
|
182
|
+
});
|
|
183
|
+
this.url = args.url;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
var StableBulkError = class extends StableError {
|
|
187
|
+
constructor(args) {
|
|
188
|
+
super(args.shortMessage, { name: "StableBulkError" });
|
|
189
|
+
this.results = args.results;
|
|
190
|
+
this.succeeded = args.succeeded;
|
|
191
|
+
this.failed = args.failed;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
function formatValue(v) {
|
|
195
|
+
if (typeof v === "bigint") return `${v}n`;
|
|
196
|
+
if (typeof v === "string") return JSON.stringify(v);
|
|
197
|
+
if (v === null) return "null";
|
|
198
|
+
if (v === void 0) return "undefined";
|
|
199
|
+
try {
|
|
200
|
+
return JSON.stringify(v);
|
|
201
|
+
} catch (e) {
|
|
202
|
+
return String(v);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/services/erc3009/shared.ts
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
var _accounts = require('viem/accounts');
|
|
213
|
+
|
|
214
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
215
|
+
function randomNonce() {
|
|
216
|
+
return _accounts.generatePrivateKey.call(void 0, );
|
|
217
|
+
}
|
|
218
|
+
function splitSignature(signature) {
|
|
219
|
+
const { r, s, v, yParity } = _viem.parseSignature.call(void 0, signature);
|
|
220
|
+
return { r, s, v: v !== void 0 ? Number(v) : (_nullishCoalesce(yParity, () => ( 0))) + 27 };
|
|
221
|
+
}
|
|
222
|
+
function resolveSigner(client, account) {
|
|
223
|
+
const signer = _nullishCoalesce(account, () => ( client.account));
|
|
224
|
+
if (!signer) {
|
|
225
|
+
throw new StableValidationError(
|
|
226
|
+
"signer",
|
|
227
|
+
void 0,
|
|
228
|
+
"erc3009: requires a signer \u2014 pass `account` or configure one on the client"
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
return signer;
|
|
232
|
+
}
|
|
233
|
+
function signerAddress(signer) {
|
|
234
|
+
return typeof signer === "string" ? signer : signer.address;
|
|
235
|
+
}
|
|
236
|
+
async function resolveDomain(client, token, overrides) {
|
|
237
|
+
const chainId = await _asyncNullishCoalesce(await _asyncNullishCoalesce(await _asyncOptionalChain([overrides, 'optionalAccess', async _2 => _2.chainId]), async () => ( _optionalChain([client, 'access', _3 => _3.chain, 'optionalAccess', _4 => _4.id]))), async () => ( await _actions.getChainId.call(void 0, client)));
|
|
238
|
+
const verifyingContract = _nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _5 => _5.verifyingContract]), () => ( token));
|
|
239
|
+
if (_optionalChain([overrides, 'optionalAccess', _6 => _6.name]) !== void 0 && _optionalChain([overrides, 'optionalAccess', _7 => _7.version]) !== void 0) {
|
|
240
|
+
return {
|
|
241
|
+
name: overrides.name,
|
|
242
|
+
version: overrides.version,
|
|
243
|
+
chainId,
|
|
244
|
+
verifyingContract
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
const res = await _actions.readContract.call(void 0, client, {
|
|
249
|
+
address: token,
|
|
250
|
+
abi: ERC3009_ABI,
|
|
251
|
+
functionName: "eip712Domain"
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
name: _nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _8 => _8.name]), () => ( res[1])),
|
|
255
|
+
version: _nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _9 => _9.version]), () => ( res[2])),
|
|
256
|
+
chainId,
|
|
257
|
+
verifyingContract
|
|
258
|
+
};
|
|
259
|
+
} catch (e2) {
|
|
260
|
+
const name = await _asyncNullishCoalesce(await _asyncOptionalChain([overrides, 'optionalAccess', async _10 => _10.name]), async () => ( await _actions.readContract.call(void 0, client, {
|
|
261
|
+
address: token,
|
|
262
|
+
abi: ERC3009_ABI,
|
|
263
|
+
functionName: "name"
|
|
264
|
+
})));
|
|
265
|
+
return {
|
|
266
|
+
name,
|
|
267
|
+
version: _nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _11 => _11.version]), () => ( "1")),
|
|
268
|
+
chainId,
|
|
269
|
+
verifyingContract
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function validateAuthorizationParams(params) {
|
|
274
|
+
if (!_viem.isAddress.call(void 0, params.from)) {
|
|
275
|
+
throw new StableValidationError(
|
|
276
|
+
"from",
|
|
277
|
+
params.from,
|
|
278
|
+
`erc3009: invalid sender address "${params.from}"`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
if (!_viem.isAddress.call(void 0, params.to) || params.to === ZERO_ADDRESS) {
|
|
282
|
+
throw new StableValidationError(
|
|
283
|
+
"to",
|
|
284
|
+
params.to,
|
|
285
|
+
`erc3009: invalid recipient address "${params.to}"`
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
if (params.value <= 0n) {
|
|
289
|
+
throw new StableValidationError(
|
|
290
|
+
"value",
|
|
291
|
+
params.value,
|
|
292
|
+
"erc3009: value must be a positive bigint (token smallest unit)"
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
if (params.validBefore <= params.validAfter) {
|
|
296
|
+
throw new StableValidationError(
|
|
297
|
+
"validBefore",
|
|
298
|
+
params.validBefore,
|
|
299
|
+
"erc3009: validBefore must be greater than validAfter"
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
validateNonce(params.nonce);
|
|
303
|
+
}
|
|
304
|
+
function validateNonce(nonce) {
|
|
305
|
+
if (!/^0x[0-9a-fA-F]*$/.test(nonce) || _viem.size.call(void 0, nonce) !== 32) {
|
|
306
|
+
throw new StableValidationError(
|
|
307
|
+
"nonce",
|
|
308
|
+
nonce,
|
|
309
|
+
"erc3009: nonce must be a 32-byte hex value"
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/services/erc3009/signAuthorization.ts
|
|
315
|
+
async function signAuthorization(client, parameters, primaryType, types) {
|
|
316
|
+
const token = _nullishCoalesce(parameters.token, () => ( STABLE_USDT_ADDRESS));
|
|
317
|
+
const signer = resolveSigner(client, parameters.account);
|
|
318
|
+
const authorization = {
|
|
319
|
+
from: _nullishCoalesce(parameters.from, () => ( signerAddress(signer))),
|
|
320
|
+
to: parameters.to,
|
|
321
|
+
value: parameters.value,
|
|
322
|
+
validAfter: _nullishCoalesce(parameters.validAfter, () => ( 0n)),
|
|
323
|
+
validBefore: parameters.validBefore,
|
|
324
|
+
nonce: _nullishCoalesce(parameters.nonce, () => ( randomNonce()))
|
|
325
|
+
};
|
|
326
|
+
validateAuthorizationParams(authorization);
|
|
327
|
+
const domain = await resolveDomain(client, token, parameters.domain);
|
|
328
|
+
let signature;
|
|
329
|
+
try {
|
|
330
|
+
signature = await _actions.signTypedData.call(void 0, client, {
|
|
331
|
+
account: signer,
|
|
332
|
+
domain,
|
|
333
|
+
types,
|
|
334
|
+
primaryType,
|
|
335
|
+
message: authorization
|
|
336
|
+
});
|
|
337
|
+
} catch (err) {
|
|
338
|
+
throw new StableTransactionError({
|
|
339
|
+
phase: "sign",
|
|
340
|
+
shortMessage: "erc3009: wallet rejected or failed to sign the authorization",
|
|
341
|
+
chainId: domain.chainId === void 0 ? void 0 : Number(domain.chainId),
|
|
342
|
+
cause: err
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return { authorization, signature, ...splitSignature(signature) };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// src/services/erc3009/signTransferAuthorization.ts
|
|
349
|
+
function signTransferAuthorization(client, parameters) {
|
|
350
|
+
return signAuthorization(
|
|
351
|
+
client,
|
|
352
|
+
parameters,
|
|
353
|
+
"TransferWithAuthorization",
|
|
354
|
+
TRANSFER_WITH_AUTHORIZATION_TYPES
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/services/erc3009/signReceiveAuthorization.ts
|
|
359
|
+
function signReceiveAuthorization(client, parameters) {
|
|
360
|
+
return signAuthorization(
|
|
361
|
+
client,
|
|
362
|
+
parameters,
|
|
363
|
+
"ReceiveWithAuthorization",
|
|
364
|
+
RECEIVE_WITH_AUTHORIZATION_TYPES
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/services/erc3009/submit.ts
|
|
369
|
+
|
|
370
|
+
async function submitAuthorizationTx(client, token, functionName, signed) {
|
|
371
|
+
const signer = resolveSigner(client, void 0);
|
|
372
|
+
const { authorization: a, v, r, s } = signed;
|
|
373
|
+
try {
|
|
374
|
+
return await _actions.writeContract.call(void 0, client, {
|
|
375
|
+
address: token,
|
|
376
|
+
abi: ERC3009_ABI,
|
|
377
|
+
functionName,
|
|
378
|
+
args: [
|
|
379
|
+
a.from,
|
|
380
|
+
a.to,
|
|
381
|
+
a.value,
|
|
382
|
+
a.validAfter,
|
|
383
|
+
a.validBefore,
|
|
384
|
+
a.nonce,
|
|
385
|
+
v,
|
|
386
|
+
r,
|
|
387
|
+
s
|
|
388
|
+
],
|
|
389
|
+
account: signer,
|
|
390
|
+
chain: client.chain
|
|
391
|
+
});
|
|
392
|
+
} catch (err) {
|
|
393
|
+
throw new StableTransactionError({
|
|
394
|
+
phase: "send",
|
|
395
|
+
shortMessage: `erc3009: ${functionName} transaction failed`,
|
|
396
|
+
chainId: _optionalChain([client, 'access', _12 => _12.chain, 'optionalAccess', _13 => _13.id]),
|
|
397
|
+
cause: err
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/services/erc3009/transferWithAuthorization.ts
|
|
403
|
+
async function transferWithAuthorization(client, parameters) {
|
|
404
|
+
const token = _nullishCoalesce(parameters.token, () => ( STABLE_USDT_ADDRESS));
|
|
405
|
+
const signed = "signed" in parameters ? parameters.signed : await signTransferAuthorization(client, parameters);
|
|
406
|
+
return submitAuthorizationTx(
|
|
407
|
+
client,
|
|
408
|
+
token,
|
|
409
|
+
"transferWithAuthorization",
|
|
410
|
+
signed
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/services/erc3009/receiveWithAuthorization.ts
|
|
415
|
+
async function receiveWithAuthorization(client, parameters) {
|
|
416
|
+
const token = _nullishCoalesce(parameters.token, () => ( STABLE_USDT_ADDRESS));
|
|
417
|
+
const signed = "signed" in parameters ? parameters.signed : await signReceiveAuthorization(client, parameters);
|
|
418
|
+
const caller = signerAddress(resolveSigner(client, void 0));
|
|
419
|
+
if (caller.toLowerCase() !== signed.authorization.to.toLowerCase()) {
|
|
420
|
+
throw new StableValidationError(
|
|
421
|
+
"caller",
|
|
422
|
+
caller,
|
|
423
|
+
`erc3009: receiveWithAuthorization must be submitted by the recipient (to=${signed.authorization.to})`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
return submitAuthorizationTx(
|
|
427
|
+
client,
|
|
428
|
+
token,
|
|
429
|
+
"receiveWithAuthorization",
|
|
430
|
+
signed
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// src/services/erc3009/cancelAuthorization.ts
|
|
435
|
+
|
|
436
|
+
async function cancelAuthorization(client, parameters) {
|
|
437
|
+
const token = _nullishCoalesce(parameters.token, () => ( STABLE_USDT_ADDRESS));
|
|
438
|
+
const signer = resolveSigner(client, parameters.account);
|
|
439
|
+
const authorizer = _nullishCoalesce(parameters.authorizer, () => ( signerAddress(signer)));
|
|
440
|
+
validateNonce(parameters.nonce);
|
|
441
|
+
const domain = await resolveDomain(client, token, parameters.domain);
|
|
442
|
+
const message = { authorizer, nonce: parameters.nonce };
|
|
443
|
+
let signature;
|
|
444
|
+
try {
|
|
445
|
+
signature = await _actions.signTypedData.call(void 0, client, {
|
|
446
|
+
account: signer,
|
|
447
|
+
domain,
|
|
448
|
+
types: CANCEL_AUTHORIZATION_TYPES,
|
|
449
|
+
primaryType: "CancelAuthorization",
|
|
450
|
+
message
|
|
451
|
+
});
|
|
452
|
+
} catch (err) {
|
|
453
|
+
throw new StableTransactionError({
|
|
454
|
+
phase: "sign",
|
|
455
|
+
shortMessage: "erc3009: wallet rejected or failed to sign the cancellation",
|
|
456
|
+
chainId: domain.chainId === void 0 ? void 0 : Number(domain.chainId),
|
|
457
|
+
cause: err
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
const { v, r, s } = splitSignature(signature);
|
|
461
|
+
try {
|
|
462
|
+
return await _actions.writeContract.call(void 0, client, {
|
|
463
|
+
address: token,
|
|
464
|
+
abi: ERC3009_ABI,
|
|
465
|
+
functionName: "cancelAuthorization",
|
|
466
|
+
args: [authorizer, parameters.nonce, v, r, s],
|
|
467
|
+
account: signer,
|
|
468
|
+
chain: client.chain
|
|
469
|
+
});
|
|
470
|
+
} catch (err) {
|
|
471
|
+
throw new StableTransactionError({
|
|
472
|
+
phase: "send",
|
|
473
|
+
shortMessage: "erc3009: cancelAuthorization transaction failed",
|
|
474
|
+
chainId: _optionalChain([client, 'access', _14 => _14.chain, 'optionalAccess', _15 => _15.id]),
|
|
475
|
+
cause: err
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/services/erc3009/prepareTransferWithAuthorization.ts
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
async function prepareTransferWithAuthorization(client, parameters) {
|
|
484
|
+
const token = _nullishCoalesce(parameters.token, () => ( STABLE_USDT_ADDRESS));
|
|
485
|
+
const signed = await signTransferAuthorization(client, parameters);
|
|
486
|
+
const { authorization: a, v, r, s } = signed;
|
|
487
|
+
const data = _viem.encodeFunctionData.call(void 0, {
|
|
488
|
+
abi: ERC3009_ABI,
|
|
489
|
+
functionName: "transferWithAuthorization",
|
|
490
|
+
args: [
|
|
491
|
+
a.from,
|
|
492
|
+
a.to,
|
|
493
|
+
a.value,
|
|
494
|
+
a.validAfter,
|
|
495
|
+
a.validBefore,
|
|
496
|
+
a.nonce,
|
|
497
|
+
v,
|
|
498
|
+
r,
|
|
499
|
+
s
|
|
500
|
+
]
|
|
501
|
+
});
|
|
502
|
+
const chainId = await _asyncNullishCoalesce(await _asyncOptionalChain([client, 'access', async _16 => _16.chain, 'optionalAccess', async _17 => _17.id]), async () => ( await _actions.getChainId.call(void 0, client)));
|
|
503
|
+
return { to: token, data, value: 0n, chainId, signed };
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// src/services/erc3009/verifyAuthorization.ts
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
async function verifyAuthorization(client, parameters) {
|
|
510
|
+
const token = _nullishCoalesce(parameters.token, () => ( STABLE_USDT_ADDRESS));
|
|
511
|
+
const primaryType = _nullishCoalesce(parameters.primaryType, () => ( "TransferWithAuthorization"));
|
|
512
|
+
const isReceive = primaryType === "ReceiveWithAuthorization";
|
|
513
|
+
const types = isReceive ? RECEIVE_WITH_AUTHORIZATION_TYPES : TRANSFER_WITH_AUTHORIZATION_TYPES;
|
|
514
|
+
const { authorization: a, signature, v, r, s } = parameters.signed;
|
|
515
|
+
const reasons = [];
|
|
516
|
+
const domain = await resolveDomain(client, token, parameters.domain);
|
|
517
|
+
let signer;
|
|
518
|
+
try {
|
|
519
|
+
signer = await _viem.recoverTypedDataAddress.call(void 0, {
|
|
520
|
+
domain,
|
|
521
|
+
types,
|
|
522
|
+
primaryType,
|
|
523
|
+
message: a,
|
|
524
|
+
signature
|
|
525
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic primaryType/types
|
|
526
|
+
});
|
|
527
|
+
if (signer.toLowerCase() !== a.from.toLowerCase()) {
|
|
528
|
+
reasons.push("signer_mismatch");
|
|
529
|
+
}
|
|
530
|
+
} catch (e3) {
|
|
531
|
+
reasons.push("invalid_signature");
|
|
532
|
+
}
|
|
533
|
+
const used = await _actions.readContract.call(void 0, client, {
|
|
534
|
+
address: token,
|
|
535
|
+
abi: ERC3009_ABI,
|
|
536
|
+
functionName: "authorizationState",
|
|
537
|
+
args: [a.from, a.nonce]
|
|
538
|
+
});
|
|
539
|
+
if (used) reasons.push("already_used");
|
|
540
|
+
const now = await _asyncNullishCoalesce(parameters.now, async () => ( (await _actions.getBlock.call(void 0, client, { blockTag: "latest" })).timestamp));
|
|
541
|
+
const margin = BigInt(_nullishCoalesce(parameters.expiryMarginSeconds, () => ( 0)));
|
|
542
|
+
if (a.validAfter > now) reasons.push("not_yet_valid");
|
|
543
|
+
if (a.validBefore <= now) reasons.push("expired");
|
|
544
|
+
else if (a.validBefore <= now + margin) reasons.push("expiring_soon");
|
|
545
|
+
const balance = await _actions.readContract.call(void 0, client, {
|
|
546
|
+
address: token,
|
|
547
|
+
abi: ERC3009_ABI,
|
|
548
|
+
functionName: "balanceOf",
|
|
549
|
+
args: [a.from]
|
|
550
|
+
});
|
|
551
|
+
let shortfall;
|
|
552
|
+
if (balance < a.value) {
|
|
553
|
+
reasons.push("insufficient_funds");
|
|
554
|
+
shortfall = a.value - balance;
|
|
555
|
+
}
|
|
556
|
+
let revertReason;
|
|
557
|
+
try {
|
|
558
|
+
await _actions.simulateContract.call(void 0, client, {
|
|
559
|
+
address: token,
|
|
560
|
+
abi: ERC3009_ABI,
|
|
561
|
+
functionName: isReceive ? "receiveWithAuthorization" : "transferWithAuthorization",
|
|
562
|
+
args: [
|
|
563
|
+
a.from,
|
|
564
|
+
a.to,
|
|
565
|
+
a.value,
|
|
566
|
+
a.validAfter,
|
|
567
|
+
a.validBefore,
|
|
568
|
+
a.nonce,
|
|
569
|
+
v,
|
|
570
|
+
r,
|
|
571
|
+
s
|
|
572
|
+
],
|
|
573
|
+
account: a.to
|
|
574
|
+
});
|
|
575
|
+
} catch (err) {
|
|
576
|
+
reasons.push("would_revert");
|
|
577
|
+
revertReason = _nullishCoalesce(err.shortMessage, () => ( err.message));
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
ok: reasons.length === 0,
|
|
581
|
+
reasons,
|
|
582
|
+
signer,
|
|
583
|
+
balance,
|
|
584
|
+
shortfall,
|
|
585
|
+
revertReason
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// src/services/erc3009/getAuthorizationState.ts
|
|
590
|
+
|
|
591
|
+
function getAuthorizationState(client, parameters) {
|
|
592
|
+
validateNonce(parameters.nonce);
|
|
593
|
+
return _actions.readContract.call(void 0, client, {
|
|
594
|
+
address: _nullishCoalesce(parameters.token, () => ( STABLE_USDT_ADDRESS)),
|
|
595
|
+
abi: ERC3009_ABI,
|
|
596
|
+
functionName: "authorizationState",
|
|
597
|
+
args: [parameters.authorizer, parameters.nonce]
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// src/services/erc3009/getAuthorizationUsage.ts
|
|
602
|
+
|
|
603
|
+
var AUTHORIZATION_USED_EVENT = {
|
|
604
|
+
type: "event",
|
|
605
|
+
name: "AuthorizationUsed",
|
|
606
|
+
anonymous: false,
|
|
607
|
+
inputs: [
|
|
608
|
+
{ name: "authorizer", type: "address", indexed: true },
|
|
609
|
+
{ name: "nonce", type: "bytes32", indexed: true }
|
|
610
|
+
]
|
|
611
|
+
};
|
|
612
|
+
async function getAuthorizationUsage(client, parameters) {
|
|
613
|
+
validateNonce(parameters.nonce);
|
|
614
|
+
const logs = await _actions.getLogs.call(void 0, client, {
|
|
615
|
+
address: _nullishCoalesce(parameters.token, () => ( STABLE_USDT_ADDRESS)),
|
|
616
|
+
event: AUTHORIZATION_USED_EVENT,
|
|
617
|
+
args: { authorizer: parameters.authorizer, nonce: parameters.nonce },
|
|
618
|
+
fromBlock: _nullishCoalesce(parameters.fromBlock, () => ( "earliest")),
|
|
619
|
+
toBlock: _nullishCoalesce(parameters.toBlock, () => ( "latest"))
|
|
620
|
+
});
|
|
621
|
+
const hit = logs.at(-1);
|
|
622
|
+
if (!hit) return { used: false };
|
|
623
|
+
return {
|
|
624
|
+
used: true,
|
|
625
|
+
txHash: _nullishCoalesce(hit.transactionHash, () => ( void 0)),
|
|
626
|
+
blockNumber: _nullishCoalesce(hit.blockNumber, () => ( void 0))
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/services/erc3009/decorator.ts
|
|
631
|
+
function erc3009Actions(client) {
|
|
632
|
+
return {
|
|
633
|
+
signTransferAuthorization: (p) => signTransferAuthorization(client, p),
|
|
634
|
+
signReceiveAuthorization: (p) => signReceiveAuthorization(client, p),
|
|
635
|
+
transferWithAuthorization: (p) => transferWithAuthorization(client, p),
|
|
636
|
+
receiveWithAuthorization: (p) => receiveWithAuthorization(client, p),
|
|
637
|
+
cancelAuthorization: (p) => cancelAuthorization(client, p),
|
|
638
|
+
prepareTransferWithAuthorization: (p) => prepareTransferWithAuthorization(client, p),
|
|
639
|
+
verifyAuthorization: (p) => verifyAuthorization(client, p),
|
|
640
|
+
getAuthorizationState: (p) => getAuthorizationState(client, p),
|
|
641
|
+
getAuthorizationUsage: (p) => getAuthorizationUsage(client, p)
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
exports.StableError = StableError; exports.StableValidationError = StableValidationError; exports.StableQuoteError = StableQuoteError; exports.StableTransactionError = StableTransactionError; exports.StableNetworkError = StableNetworkError; exports.StableBulkError = StableBulkError; exports.ERC3009_ABI = ERC3009_ABI; exports.STABLE_USDT_ADDRESS = STABLE_USDT_ADDRESS; exports.STABLE_VAULT_ADDRESS = STABLE_VAULT_ADDRESS; exports.signTransferAuthorization = signTransferAuthorization; exports.signReceiveAuthorization = signReceiveAuthorization; exports.transferWithAuthorization = transferWithAuthorization; exports.receiveWithAuthorization = receiveWithAuthorization; exports.cancelAuthorization = cancelAuthorization; exports.prepareTransferWithAuthorization = prepareTransferWithAuthorization; exports.verifyAuthorization = verifyAuthorization; exports.getAuthorizationState = getAuthorizationState; exports.getAuthorizationUsage = getAuthorizationUsage; exports.erc3009Actions = erc3009Actions;
|