@dynamic-labs/aleo 4.79.1 → 4.80.0
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/CHANGELOG.md +16 -0
- package/package.cjs +1 -1
- package/package.js +1 -1
- package/package.json +10 -6
- package/src/connectors/DynamicWaasAleoConnector/DynamicWaasAleoConnector.cjs +798 -0
- package/src/connectors/DynamicWaasAleoConnector/DynamicWaasAleoConnector.d.ts +409 -0
- package/src/connectors/DynamicWaasAleoConnector/DynamicWaasAleoConnector.js +794 -0
- package/src/connectors/DynamicWaasAleoConnector/index.cjs +13 -0
- package/src/connectors/DynamicWaasAleoConnector/index.d.ts +3 -0
- package/src/connectors/DynamicWaasAleoConnector/index.js +9 -0
- package/src/connectors/WaasAleoWalletConnector/WaasAleoWalletConnector.cjs +216 -0
- package/src/connectors/WaasAleoWalletConnector/WaasAleoWalletConnector.d.ts +116 -0
- package/src/connectors/WaasAleoWalletConnector/WaasAleoWalletConnector.js +211 -0
- package/src/connectors/WaasAleoWalletConnector/index.d.ts +1 -0
- package/src/index.cjs +15 -0
- package/src/index.d.ts +5 -0
- package/src/index.js +7 -0
- package/src/utils/AleoUiTransaction/AleoUiTransaction.cjs +354 -0
- package/src/utils/AleoUiTransaction/AleoUiTransaction.d.ts +130 -0
- package/src/utils/AleoUiTransaction/AleoUiTransaction.js +350 -0
- package/src/utils/AleoUiTransaction/index.d.ts +2 -0
- package/src/utils/aleoSendableTokens/aleoSendableTokens.cjs +185 -0
- package/src/utils/aleoSendableTokens/aleoSendableTokens.d.ts +78 -0
- package/src/utils/aleoSendableTokens/aleoSendableTokens.js +175 -0
- package/src/utils/aleoSendableTokens/index.d.ts +2 -0
- package/src/utils/aleoShieldableTokens/aleoShieldableTokens.cjs +119 -0
- package/src/utils/aleoShieldableTokens/aleoShieldableTokens.d.ts +45 -0
- package/src/utils/aleoShieldableTokens/aleoShieldableTokens.js +114 -0
- package/src/utils/aleoShieldableTokens/index.d.ts +2 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
var _tslib = require('../../../_virtual/_tslib.cjs');
|
|
7
|
+
var utils = require('@dynamic-labs/utils');
|
|
8
|
+
var aleoSendableTokens = require('../aleoSendableTokens/aleoSendableTokens.cjs');
|
|
9
|
+
|
|
10
|
+
// `10n ** decimals` via string construction. Equivalent to `BigInt(10) **
|
|
11
|
+
// BigInt(decimals)` but avoids the TS2791 error in environments whose
|
|
12
|
+
// `target` predates es2016 (which is where rollup compiles this package).
|
|
13
|
+
const pow10 = (decimals) => BigInt(`1${'0'.repeat(decimals)}`);
|
|
14
|
+
// Aleo addresses are 63-character strings: `aleo1` prefix + 58 lowercase
|
|
15
|
+
// alphanumeric characters. We deliberately don't enforce the bech32m
|
|
16
|
+
// alphabet — Aleo's encoding admits a wider character set than standard
|
|
17
|
+
// bech32m (e.g. `o` appears in real testnet addresses). Format-level
|
|
18
|
+
// validation only — the on-chain transition rejects bad checksums with a
|
|
19
|
+
// clear error, so we don't pull the Provable WASM into the widget bundle
|
|
20
|
+
// for client-side checksum verification.
|
|
21
|
+
const ALEO_ADDRESS_REGEX = /^aleo1[a-z0-9]{58}$/;
|
|
22
|
+
/**
|
|
23
|
+
* Aleo `IUITransaction` for the widget's Send flow.
|
|
24
|
+
*
|
|
25
|
+
* Both supported modes spend FROM a private record (so the wallet's
|
|
26
|
+
* available balance is always the shielded record sum); they differ
|
|
27
|
+
* only in what the recipient receives:
|
|
28
|
+
*
|
|
29
|
+
* - **Individual** = `<program>/transfer_private` — recipient also gets
|
|
30
|
+
* a private record. The most common Aleo flow.
|
|
31
|
+
* - **Exchange** = `<program>/transfer_private_to_public` —
|
|
32
|
+
* recipient's *public* balance is incremented. Useful for off-ramps,
|
|
33
|
+
* exchange deposits, etc.
|
|
34
|
+
*
|
|
35
|
+
* The submit path branches on the **selected token's program kind**:
|
|
36
|
+
*
|
|
37
|
+
* - `credits` → `credits.aleo` transitions, 3 inputs `[record, recipient, amount]`.
|
|
38
|
+
* - `stablecoin` → `<stablecoin>.aleo` transitions, 3 inputs
|
|
39
|
+
* `[recipient, amount, record]`. The iframe appends a
|
|
40
|
+
* Sealance freeze-list exclusion proof (and its type)
|
|
41
|
+
* automatically — see `proveTransaction` in the iframe's
|
|
42
|
+
* Aleo client.
|
|
43
|
+
* - `arc21` → `token_registry.aleo` transitions, 3 inputs
|
|
44
|
+
* `[recipient, amount, record]`. The token_id is
|
|
45
|
+
* encoded inside the record's plaintext, so the
|
|
46
|
+
* transition signature does NOT include it as a
|
|
47
|
+
* separate argument — only the record carries it.
|
|
48
|
+
*
|
|
49
|
+
* In all kinds, the form auto-picks the smallest single record (filtered
|
|
50
|
+
* to the selected token) that covers the amount. If no single record
|
|
51
|
+
* fits, the form surfaces a merge CTA backed by `joinAllRecordsForToken`.
|
|
52
|
+
*/
|
|
53
|
+
class AleoUiTransaction {
|
|
54
|
+
constructor({ from, networkId, listOwnedRecords, joinAllRecordsForToken, onSubmit, }) {
|
|
55
|
+
var _a;
|
|
56
|
+
this.chain = 'ALEO';
|
|
57
|
+
this.data = undefined;
|
|
58
|
+
this.fee = { gas: undefined };
|
|
59
|
+
this.transactionModes = [
|
|
60
|
+
{
|
|
61
|
+
icon: 'individual',
|
|
62
|
+
id: 'individual',
|
|
63
|
+
label: 'Individual',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
icon: 'exchange',
|
|
67
|
+
id: 'exchange',
|
|
68
|
+
label: 'Exchange',
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
// No default — the user must explicitly pick Individual or Exchange
|
|
72
|
+
// before submitting. Both modes spend from the same shielded balance,
|
|
73
|
+
// so the rest of the form stays interactive without a selection; we
|
|
74
|
+
// just gate the Preview/Submit button. Pre-selecting felt
|
|
75
|
+
// presumptuous given Individual vs. Exchange has real semantic
|
|
76
|
+
// differences (recipient gets a private record vs. public balance).
|
|
77
|
+
this.selectedTransactionMode = undefined;
|
|
78
|
+
this.from = from;
|
|
79
|
+
this.networkId = networkId;
|
|
80
|
+
this.listOwnedRecords = listOwnedRecords;
|
|
81
|
+
this.joinAllRecordsForToken = joinAllRecordsForToken;
|
|
82
|
+
this.onSubmitFn = onSubmit;
|
|
83
|
+
this.selectedToken = (_a = this.tokensForNetwork()[0]) !== null && _a !== void 0 ? _a : this.creditsFallback();
|
|
84
|
+
}
|
|
85
|
+
setTransactionMode(modeId) {
|
|
86
|
+
if (modeId !== 'exchange' && modeId !== 'individual')
|
|
87
|
+
return;
|
|
88
|
+
this.selectedTransactionMode = modeId;
|
|
89
|
+
}
|
|
90
|
+
setSelectedToken(contractAddress) {
|
|
91
|
+
const match = this.tokensForNetwork().find((t) => t.contractAddress === contractAddress);
|
|
92
|
+
if (match)
|
|
93
|
+
this.selectedToken = match;
|
|
94
|
+
}
|
|
95
|
+
setPendingAmount(amountInput) {
|
|
96
|
+
try {
|
|
97
|
+
this.pendingValue = this.parse(amountInput);
|
|
98
|
+
}
|
|
99
|
+
catch (_a) {
|
|
100
|
+
this.pendingValue = undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Triggered by the form's "Merge records first" button. After this
|
|
105
|
+
* resolves the form re-evaluates `getRecordMergeAction`, so we drop the
|
|
106
|
+
* cached records first to force a fresh `listOwnedRecords` on the
|
|
107
|
+
* next call (the on-chain merge produced new records).
|
|
108
|
+
*/
|
|
109
|
+
mergeRecordsForSelectedToken() {
|
|
110
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
yield this.joinAllRecordsForToken(this.selectedToken);
|
|
112
|
+
this.cachedRecords = undefined;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
getRecordMergeAction() {
|
|
116
|
+
// Both modes consume one private record, so the CTA fires for either
|
|
117
|
+
// selection when the user's largest single record (of the selected
|
|
118
|
+
// token) can't cover the amount. (Exchange = transfer_private_to_public
|
|
119
|
+
// also burns a record; the only difference is that the recipient gets
|
|
120
|
+
// public balance instead of a private record.)
|
|
121
|
+
if (this.pendingValue === undefined || this.pendingValue <= BigInt(0)) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
// We can only know "fits / doesn't fit" if we've loaded records at
|
|
125
|
+
// least once. The form refreshes the action on amount blur — by then
|
|
126
|
+
// the iframe has typically been pinged at least once (e.g. when
|
|
127
|
+
// `getBalance` ran), but we also have to handle the cold case where
|
|
128
|
+
// records haven't been fetched yet. Returning `undefined` here is
|
|
129
|
+
// safe: the form will re-check on blur after the user types again,
|
|
130
|
+
// and `listOwnedRecords` will be invoked from the submit path
|
|
131
|
+
// anyway. We choose to never block submit on an unknown — the worst
|
|
132
|
+
// case is the user clicks Preview, sees the underlying error, and
|
|
133
|
+
// clicks merge from there.
|
|
134
|
+
if (!this.cachedRecords)
|
|
135
|
+
return undefined;
|
|
136
|
+
const matching = this.cachedRecords.filter((r) => aleoSendableTokens.recordMatchesSendableToken(r, this.selectedToken));
|
|
137
|
+
const largest = matching.reduce((acc, r) => {
|
|
138
|
+
const v = aleoSendableTokens.extractRecordAtomicAmount(r, this.selectedToken);
|
|
139
|
+
return v > acc ? v : acc;
|
|
140
|
+
}, BigInt(0));
|
|
141
|
+
if (largest >= this.pendingValue)
|
|
142
|
+
return undefined;
|
|
143
|
+
// No single record fits. The CTA mirrors the language we use in the
|
|
144
|
+
// demo + the merge button we already shipped. Action delegates back
|
|
145
|
+
// to the connector via the closure injected at construction time.
|
|
146
|
+
const { symbol } = this.selectedToken;
|
|
147
|
+
return {
|
|
148
|
+
actionLabel: 'Merge records first',
|
|
149
|
+
message: `No single private record covers this amount. Largest is ${this.format(largest)} ${symbol}; you're sending ${this.format(this.pendingValue)} ${symbol}.`,
|
|
150
|
+
onAction: () => this.mergeRecordsForSelectedToken(),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Parses a human-readable amount (e.g. `"0.5"`) into atomic units using
|
|
155
|
+
* the *selected token's* decimals (credits = 6, stablecoin = 6, each
|
|
156
|
+
* ARC-21 token has its own — wETH = 18, etc.). BigInt math via integer
|
|
157
|
+
* multiplication keeps precision lossless up to `decimals` places.
|
|
158
|
+
*/
|
|
159
|
+
parse(input) {
|
|
160
|
+
const { decimals } = this.selectedToken;
|
|
161
|
+
const trimmed = input.trim();
|
|
162
|
+
const re = new RegExp(`^(\\d+)(?:\\.(\\d{1,${decimals}}))?$`);
|
|
163
|
+
const match = re.exec(trimmed);
|
|
164
|
+
if (!match) {
|
|
165
|
+
throw new Error(`Invalid amount — expected up to ${decimals} decimal places.`);
|
|
166
|
+
}
|
|
167
|
+
const [, whole, fracRaw] = match;
|
|
168
|
+
const frac = (fracRaw !== null && fracRaw !== void 0 ? fracRaw : '').padEnd(decimals, '0');
|
|
169
|
+
return BigInt(whole) * pow10(decimals) + BigInt(frac);
|
|
170
|
+
}
|
|
171
|
+
// Formats an atomic-units bigint into a display string using the
|
|
172
|
+
// selected token's decimals. BigInt math throughout — Number() coercion
|
|
173
|
+
// on the whole atomic value would lose precision for high-decimal tokens
|
|
174
|
+
// (e.g. wETH at 18 decimals: 9 wETH ≈ 9·10¹⁸ atomic units, well past
|
|
175
|
+
// Number.MAX_SAFE_INTEGER).
|
|
176
|
+
format(value, { precision } = {}) {
|
|
177
|
+
const { decimals } = this.selectedToken;
|
|
178
|
+
if (decimals === 0) {
|
|
179
|
+
return utils.formatNumberText(value.toString(), { precision });
|
|
180
|
+
}
|
|
181
|
+
const negative = value < BigInt(0);
|
|
182
|
+
const abs = negative ? -value : value;
|
|
183
|
+
const divisor = pow10(decimals);
|
|
184
|
+
const wholePart = abs / divisor;
|
|
185
|
+
const fracPart = abs % divisor;
|
|
186
|
+
// Linear-time trailing-zero trim. Avoids `/0+$/` — anchored, bounded
|
|
187
|
+
// input, but the SAST tooling flags any `+`-quantified regex as
|
|
188
|
+
// ReDoS-prone, so we walk back manually.
|
|
189
|
+
const fracPadded = fracPart.toString().padStart(decimals, '0');
|
|
190
|
+
let fracEnd = fracPadded.length;
|
|
191
|
+
while (fracEnd > 0 && fracPadded[fracEnd - 1] === '0')
|
|
192
|
+
fracEnd -= 1;
|
|
193
|
+
const fracString = fracPadded.slice(0, fracEnd);
|
|
194
|
+
const sign = negative ? '-' : '';
|
|
195
|
+
const decimalString = fracString.length > 0
|
|
196
|
+
? `${sign}${wholePart.toString()}.${fracString}`
|
|
197
|
+
: `${sign}${wholePart.toString()}`;
|
|
198
|
+
return utils.formatNumberText(decimalString, { precision });
|
|
199
|
+
}
|
|
200
|
+
validateAddressFormat(address) {
|
|
201
|
+
return ALEO_ADDRESS_REGEX.test(address);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns the user's *available* balance for the selected token in
|
|
205
|
+
* atomic units — the sum of unspent matching records. Both Send modes
|
|
206
|
+
* spend FROM records, so the displayed available balance is the same
|
|
207
|
+
* regardless of the toggle. Caches the record list so the merge CTA
|
|
208
|
+
* (and the auto-pick at submit time) can share it.
|
|
209
|
+
*/
|
|
210
|
+
getBalance() {
|
|
211
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
212
|
+
const records = yield this.refreshRecordsCache();
|
|
213
|
+
return records
|
|
214
|
+
.filter((r) => aleoSendableTokens.recordMatchesSendableToken(r, this.selectedToken))
|
|
215
|
+
.reduce((acc, r) => acc + aleoSendableTokens.extractRecordAtomicAmount(r, this.selectedToken), BigInt(0));
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Feemaster sponsors `credits.aleo/transfer_public` and `transfer_private`
|
|
220
|
+
* per ANF's policy, so the user pays zero on credits sends. Stablecoin
|
|
221
|
+
* + ARC-21 sends today fall through to user-paid (Feemaster policy
|
|
222
|
+
* doesn't yet cover them on testnet); the iframe still completes the
|
|
223
|
+
* transfer, just deducts the credits-fee directly. The optimistic `0n`
|
|
224
|
+
* here matches what we tell the user via `isGasSponsored()` below.
|
|
225
|
+
*/
|
|
226
|
+
fetchFee() {
|
|
227
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
228
|
+
this.fee.gas = BigInt(0);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
isGasSponsored() {
|
|
232
|
+
return this.selectedToken.programKind === 'credits';
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Tells the SendBalanceView to populate the picker / "Available"
|
|
236
|
+
* display from the wallet's *shielded* balance per token — not from
|
|
237
|
+
* the redcoast public-balance fetch the form would otherwise use.
|
|
238
|
+
* Both Send modes (Individual = `transfer_private`, Exchange =
|
|
239
|
+
* `transfer_private_to_public`) consume a private record, so what
|
|
240
|
+
* the user can actually send is the records sum.
|
|
241
|
+
*
|
|
242
|
+
* Returns one entry per token in the network registry (credits +
|
|
243
|
+
* stablecoins always; mainnet additionally exposes the 5 ARC-21
|
|
244
|
+
* hyp_warp tokens). Tokens with zero matching records still appear so
|
|
245
|
+
* the user can see the full menu — picking a zero-balance token
|
|
246
|
+
* surfaces the merge / fund flow, not silently hides the option.
|
|
247
|
+
*/
|
|
248
|
+
getSendableTokenBalances() {
|
|
249
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
250
|
+
const records = yield this.refreshRecordsCache();
|
|
251
|
+
const tokens = this.tokensForNetwork();
|
|
252
|
+
return tokens.map((token) => {
|
|
253
|
+
var _a;
|
|
254
|
+
const sumAtomic = records
|
|
255
|
+
.filter((r) => aleoSendableTokens.recordMatchesSendableToken(r, token))
|
|
256
|
+
.reduce((acc, r) => acc + aleoSendableTokens.extractRecordAtomicAmount(r, token), BigInt(0));
|
|
257
|
+
const divisor = Number(pow10(token.decimals));
|
|
258
|
+
const rawBalance = Number(sumAtomic);
|
|
259
|
+
return {
|
|
260
|
+
address: token.contractAddress,
|
|
261
|
+
balance: rawBalance / divisor,
|
|
262
|
+
decimals: token.decimals,
|
|
263
|
+
// Every Aleo Send token uses the same record-spend mechanics and
|
|
264
|
+
// the same `transaction.parse` / `getBalance` / `submit` pipeline
|
|
265
|
+
// internally (decimals + program both come from `selectedToken`).
|
|
266
|
+
// The form's "non-native" branch was designed for EVM-style ERC-20
|
|
267
|
+
// tokens that need a separate `parseNonNativeToken` + a separate
|
|
268
|
+
// contract balance source — neither of which applies here. Marking
|
|
269
|
+
// every entry as native sends the form through `transaction.parse`
|
|
270
|
+
// + `transaction.getBalance`, which is exactly what we want for
|
|
271
|
+
// credits AND stablecoins AND ARC-21 alike. Not a hack — it's an
|
|
272
|
+
// accurate description of the form's contract for this chain.
|
|
273
|
+
isNative: true,
|
|
274
|
+
logoURI: (_a = token.logoURI) !== null && _a !== void 0 ? _a : '',
|
|
275
|
+
name: token.name,
|
|
276
|
+
rawBalance,
|
|
277
|
+
symbol: token.symbol,
|
|
278
|
+
};
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
submit() {
|
|
283
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
284
|
+
if (!this.selectedTransactionMode) {
|
|
285
|
+
throw new Error('Pick Individual or Exchange before submitting an Aleo transfer.');
|
|
286
|
+
}
|
|
287
|
+
if (!this.to) {
|
|
288
|
+
throw new Error('Recipient address is required');
|
|
289
|
+
}
|
|
290
|
+
if (this.value === undefined) {
|
|
291
|
+
throw new Error('Amount is required');
|
|
292
|
+
}
|
|
293
|
+
// Both modes consume one private record. Pick the smallest record of
|
|
294
|
+
// the SELECTED token that covers `value` for minimal change-record
|
|
295
|
+
// fragmentation. If none fits we throw — the form should have already
|
|
296
|
+
// shown the merge CTA, but we keep the safety net so a stale form
|
|
297
|
+
// state can't slip a doomed transaction past us.
|
|
298
|
+
const targetValue = this.value;
|
|
299
|
+
const records = yield this.refreshRecordsCache();
|
|
300
|
+
const fitting = records
|
|
301
|
+
.filter((r) => aleoSendableTokens.recordMatchesSendableToken(r, this.selectedToken) &&
|
|
302
|
+
typeof r.record_plaintext === 'string')
|
|
303
|
+
.map((r) => ({
|
|
304
|
+
atomic: aleoSendableTokens.extractRecordAtomicAmount(r, this.selectedToken),
|
|
305
|
+
plaintext: r.record_plaintext,
|
|
306
|
+
}))
|
|
307
|
+
.filter((r) => r.atomic >= targetValue)
|
|
308
|
+
.sort((a, b) => {
|
|
309
|
+
if (a.atomic < b.atomic)
|
|
310
|
+
return -1;
|
|
311
|
+
if (a.atomic > b.atomic)
|
|
312
|
+
return 1;
|
|
313
|
+
return 0;
|
|
314
|
+
});
|
|
315
|
+
if (fitting.length === 0) {
|
|
316
|
+
throw new Error('No single private record covers this amount. Merge records first.');
|
|
317
|
+
}
|
|
318
|
+
return this.onSubmitFn({
|
|
319
|
+
mode: this.selectedTransactionMode,
|
|
320
|
+
recordPlaintext: fitting[0].plaintext,
|
|
321
|
+
to: this.to,
|
|
322
|
+
token: this.selectedToken,
|
|
323
|
+
value: this.value,
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
refreshRecordsCache() {
|
|
328
|
+
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
329
|
+
const records = yield this.listOwnedRecords();
|
|
330
|
+
this.cachedRecords = records;
|
|
331
|
+
return records;
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
tokensForNetwork() {
|
|
335
|
+
return aleoSendableTokens.getAleoSendableTokensForNetwork(this.networkId);
|
|
336
|
+
}
|
|
337
|
+
// Last-resort default when the network registry is empty (shouldn't
|
|
338
|
+
// happen in practice — both supported networks include credits).
|
|
339
|
+
creditsFallback() {
|
|
340
|
+
return {
|
|
341
|
+
contractAddress: aleoSendableTokens.ALEO_CREDITS_PROGRAM,
|
|
342
|
+
decimals: aleoSendableTokens.ALEO_CREDITS_DECIMALS,
|
|
343
|
+
logoURI: '',
|
|
344
|
+
name: 'Aleo Credits',
|
|
345
|
+
programId: aleoSendableTokens.ALEO_CREDITS_PROGRAM,
|
|
346
|
+
programKind: 'credits',
|
|
347
|
+
recordName: 'credits',
|
|
348
|
+
recordTypeLiteral: 'credits.record',
|
|
349
|
+
symbol: 'ALEO',
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
exports.AleoUiTransaction = AleoUiTransaction;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { TokenBalance } from '@dynamic-labs/sdk-api-core';
|
|
2
|
+
import { IUITransaction, IUITransactionFormatOptions, RecordMergeAction, TransactionModeOption } from '@dynamic-labs/types';
|
|
3
|
+
import { AleoOwnedRecord, AleoSendableToken } from '../aleoSendableTokens';
|
|
4
|
+
export type AleoTransferMode = 'exchange' | 'individual';
|
|
5
|
+
export type AleoSubmitParams = {
|
|
6
|
+
to: string;
|
|
7
|
+
value: bigint;
|
|
8
|
+
mode: AleoTransferMode;
|
|
9
|
+
recordPlaintext: string;
|
|
10
|
+
token: AleoSendableToken;
|
|
11
|
+
};
|
|
12
|
+
type AleoUiTransactionProps = {
|
|
13
|
+
/** The sender's `aleo1...` address. */
|
|
14
|
+
from: string;
|
|
15
|
+
networkId: number;
|
|
16
|
+
listOwnedRecords: () => Promise<AleoOwnedRecord[]>;
|
|
17
|
+
joinAllRecordsForToken: (token: AleoSendableToken) => Promise<void>;
|
|
18
|
+
onSubmit: (params: AleoSubmitParams) => Promise<string>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Aleo `IUITransaction` for the widget's Send flow.
|
|
22
|
+
*
|
|
23
|
+
* Both supported modes spend FROM a private record (so the wallet's
|
|
24
|
+
* available balance is always the shielded record sum); they differ
|
|
25
|
+
* only in what the recipient receives:
|
|
26
|
+
*
|
|
27
|
+
* - **Individual** = `<program>/transfer_private` — recipient also gets
|
|
28
|
+
* a private record. The most common Aleo flow.
|
|
29
|
+
* - **Exchange** = `<program>/transfer_private_to_public` —
|
|
30
|
+
* recipient's *public* balance is incremented. Useful for off-ramps,
|
|
31
|
+
* exchange deposits, etc.
|
|
32
|
+
*
|
|
33
|
+
* The submit path branches on the **selected token's program kind**:
|
|
34
|
+
*
|
|
35
|
+
* - `credits` → `credits.aleo` transitions, 3 inputs `[record, recipient, amount]`.
|
|
36
|
+
* - `stablecoin` → `<stablecoin>.aleo` transitions, 3 inputs
|
|
37
|
+
* `[recipient, amount, record]`. The iframe appends a
|
|
38
|
+
* Sealance freeze-list exclusion proof (and its type)
|
|
39
|
+
* automatically — see `proveTransaction` in the iframe's
|
|
40
|
+
* Aleo client.
|
|
41
|
+
* - `arc21` → `token_registry.aleo` transitions, 3 inputs
|
|
42
|
+
* `[recipient, amount, record]`. The token_id is
|
|
43
|
+
* encoded inside the record's plaintext, so the
|
|
44
|
+
* transition signature does NOT include it as a
|
|
45
|
+
* separate argument — only the record carries it.
|
|
46
|
+
*
|
|
47
|
+
* In all kinds, the form auto-picks the smallest single record (filtered
|
|
48
|
+
* to the selected token) that covers the amount. If no single record
|
|
49
|
+
* fits, the form surfaces a merge CTA backed by `joinAllRecordsForToken`.
|
|
50
|
+
*/
|
|
51
|
+
export declare class AleoUiTransaction implements IUITransaction {
|
|
52
|
+
chain: string;
|
|
53
|
+
to: string | undefined;
|
|
54
|
+
from: string;
|
|
55
|
+
value: bigint | undefined;
|
|
56
|
+
data: string | undefined;
|
|
57
|
+
receipt: string | undefined;
|
|
58
|
+
fee: {
|
|
59
|
+
gas: bigint | undefined;
|
|
60
|
+
};
|
|
61
|
+
nativePrice?: number;
|
|
62
|
+
readonly transactionModes: TransactionModeOption[];
|
|
63
|
+
selectedTransactionMode: AleoTransferMode | undefined;
|
|
64
|
+
private readonly networkId;
|
|
65
|
+
private readonly listOwnedRecords;
|
|
66
|
+
private readonly joinAllRecordsForToken;
|
|
67
|
+
private readonly onSubmitFn;
|
|
68
|
+
private pendingValue;
|
|
69
|
+
private cachedRecords;
|
|
70
|
+
private selectedToken;
|
|
71
|
+
constructor({ from, networkId, listOwnedRecords, joinAllRecordsForToken, onSubmit, }: AleoUiTransactionProps);
|
|
72
|
+
setTransactionMode(modeId: string): void;
|
|
73
|
+
setSelectedToken(contractAddress: string): void;
|
|
74
|
+
setPendingAmount(amountInput: string): void;
|
|
75
|
+
/**
|
|
76
|
+
* Triggered by the form's "Merge records first" button. After this
|
|
77
|
+
* resolves the form re-evaluates `getRecordMergeAction`, so we drop the
|
|
78
|
+
* cached records first to force a fresh `listOwnedRecords` on the
|
|
79
|
+
* next call (the on-chain merge produced new records).
|
|
80
|
+
*/
|
|
81
|
+
private mergeRecordsForSelectedToken;
|
|
82
|
+
getRecordMergeAction(): RecordMergeAction | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Parses a human-readable amount (e.g. `"0.5"`) into atomic units using
|
|
85
|
+
* the *selected token's* decimals (credits = 6, stablecoin = 6, each
|
|
86
|
+
* ARC-21 token has its own — wETH = 18, etc.). BigInt math via integer
|
|
87
|
+
* multiplication keeps precision lossless up to `decimals` places.
|
|
88
|
+
*/
|
|
89
|
+
parse(input: string): bigint;
|
|
90
|
+
format(value: bigint, { precision }?: IUITransactionFormatOptions): string;
|
|
91
|
+
validateAddressFormat(address: string): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Returns the user's *available* balance for the selected token in
|
|
94
|
+
* atomic units — the sum of unspent matching records. Both Send modes
|
|
95
|
+
* spend FROM records, so the displayed available balance is the same
|
|
96
|
+
* regardless of the toggle. Caches the record list so the merge CTA
|
|
97
|
+
* (and the auto-pick at submit time) can share it.
|
|
98
|
+
*/
|
|
99
|
+
getBalance(): Promise<bigint>;
|
|
100
|
+
/**
|
|
101
|
+
* Feemaster sponsors `credits.aleo/transfer_public` and `transfer_private`
|
|
102
|
+
* per ANF's policy, so the user pays zero on credits sends. Stablecoin
|
|
103
|
+
* + ARC-21 sends today fall through to user-paid (Feemaster policy
|
|
104
|
+
* doesn't yet cover them on testnet); the iframe still completes the
|
|
105
|
+
* transfer, just deducts the credits-fee directly. The optimistic `0n`
|
|
106
|
+
* here matches what we tell the user via `isGasSponsored()` below.
|
|
107
|
+
*/
|
|
108
|
+
fetchFee(): Promise<void>;
|
|
109
|
+
isGasSponsored(): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Tells the SendBalanceView to populate the picker / "Available"
|
|
112
|
+
* display from the wallet's *shielded* balance per token — not from
|
|
113
|
+
* the redcoast public-balance fetch the form would otherwise use.
|
|
114
|
+
* Both Send modes (Individual = `transfer_private`, Exchange =
|
|
115
|
+
* `transfer_private_to_public`) consume a private record, so what
|
|
116
|
+
* the user can actually send is the records sum.
|
|
117
|
+
*
|
|
118
|
+
* Returns one entry per token in the network registry (credits +
|
|
119
|
+
* stablecoins always; mainnet additionally exposes the 5 ARC-21
|
|
120
|
+
* hyp_warp tokens). Tokens with zero matching records still appear so
|
|
121
|
+
* the user can see the full menu — picking a zero-balance token
|
|
122
|
+
* surfaces the merge / fund flow, not silently hides the option.
|
|
123
|
+
*/
|
|
124
|
+
getSendableTokenBalances(): Promise<TokenBalance[]>;
|
|
125
|
+
submit(): Promise<string>;
|
|
126
|
+
private refreshRecordsCache;
|
|
127
|
+
private tokensForNetwork;
|
|
128
|
+
private creditsFallback;
|
|
129
|
+
}
|
|
130
|
+
export {};
|