@ar.io/sdk 4.0.0-solana.27 → 4.0.0-solana.29
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.
|
@@ -290,9 +290,23 @@ export class SolanaARIOReadable {
|
|
|
290
290
|
let staked = 0;
|
|
291
291
|
let delegated = 0;
|
|
292
292
|
let withdrawn = 0;
|
|
293
|
+
// `protocolBalance` is the REWARD RESERVE: the live balance of the protocol
|
|
294
|
+
// token account the epoch cranker emits from (ario-gar `distribute_epoch`
|
|
295
|
+
// reads `protocol_token_account.amount`). This matches AO's `protocolBalance`
|
|
296
|
+
// semantics (the qNvAoz0 reserve) and makes the six buckets sum to `total`:
|
|
297
|
+
// circulating + locked + staked + delegated + withdrawn + protocolBalance == total
|
|
298
|
+
//
|
|
299
|
+
// It is deliberately NOT `ArioConfig.protocol_balance`, which is a *folded*
|
|
300
|
+
// accounting field (= reserve + staked + delegated + withdrawn) and so
|
|
301
|
+
// double-counts the staking buckets — surfacing it as "protocol balance"
|
|
302
|
+
// over-reports the reward reserve by tens of millions of ARIO. We fall back
|
|
303
|
+
// to the folded value only when GatewaySettings or the token account can't
|
|
304
|
+
// be read (e.g. pre-init).
|
|
305
|
+
let protocolBalance = config.protocolBalance;
|
|
293
306
|
if (garSettingsAccount.exists) {
|
|
307
|
+
const garData = Buffer.from(garSettingsAccount.data);
|
|
294
308
|
try {
|
|
295
|
-
const counters = deserializeGarSupplyCounters(
|
|
309
|
+
const counters = deserializeGarSupplyCounters(garData);
|
|
296
310
|
staked = counters.totalStaked;
|
|
297
311
|
delegated = counters.totalDelegated;
|
|
298
312
|
withdrawn = counters.totalWithdrawn;
|
|
@@ -300,6 +314,22 @@ export class SolanaARIOReadable {
|
|
|
300
314
|
catch {
|
|
301
315
|
// Old-layout account without supply counters — fall back to 0
|
|
302
316
|
}
|
|
317
|
+
// The protocol token account is pinned in GatewaySettings at offset 189
|
|
318
|
+
// (see ario-gar state/mod.rs::GatewaySettings: 8 disc + 32 authority +
|
|
319
|
+
// 32 mint + 6×8 economic params + 4 max_delegates + 1 migration_active +
|
|
320
|
+
// 32 migration_authority + 32 stake_token_account = 189; the pubkey runs
|
|
321
|
+
// [189, 221)). Read its live SPL balance as the reward reserve.
|
|
322
|
+
if (garData.length >= 221) {
|
|
323
|
+
try {
|
|
324
|
+
const protocolTokenAccount = addressDecoder.decode(garData.subarray(189, 221));
|
|
325
|
+
const reserve = await this.getTokenAccountAmount(protocolTokenAccount);
|
|
326
|
+
if (reserve !== null)
|
|
327
|
+
protocolBalance = reserve;
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
// Couldn't read the reserve — keep the folded fallback.
|
|
331
|
+
}
|
|
332
|
+
}
|
|
303
333
|
}
|
|
304
334
|
return {
|
|
305
335
|
total: config.totalSupply,
|
|
@@ -308,9 +338,31 @@ export class SolanaARIOReadable {
|
|
|
308
338
|
staked,
|
|
309
339
|
delegated,
|
|
310
340
|
withdrawn,
|
|
311
|
-
protocolBalance
|
|
341
|
+
protocolBalance,
|
|
312
342
|
};
|
|
313
343
|
}
|
|
344
|
+
/**
|
|
345
|
+
* Read the `amount` (in mARIO) of an SPL token account directly by address.
|
|
346
|
+
* Returns `null` if the account doesn't exist or is too small to be a token
|
|
347
|
+
* account, so callers can distinguish "absent" from a real zero balance.
|
|
348
|
+
*
|
|
349
|
+
* Uses a portable little-endian u64 decode — some browser bundlers strip the
|
|
350
|
+
* BigInt readers from the `buffer` shim's prototype (see `getBalance`).
|
|
351
|
+
*/
|
|
352
|
+
async getTokenAccountAmount(tokenAccount) {
|
|
353
|
+
const account = await this.getAccount(tokenAccount);
|
|
354
|
+
if (!account.exists)
|
|
355
|
+
return null;
|
|
356
|
+
const data = account.data;
|
|
357
|
+
if (data.length < 72)
|
|
358
|
+
return null;
|
|
359
|
+
let amount = 0n;
|
|
360
|
+
for (let i = 7; i >= 0; i--) {
|
|
361
|
+
amount = (amount << 8n) | BigInt(data[64 + i]);
|
|
362
|
+
}
|
|
363
|
+
// ARIO supply caps at 1B * 1e6 mARIO ≈ 2^50, well under MAX_SAFE_INTEGER.
|
|
364
|
+
return Number(amount);
|
|
365
|
+
}
|
|
314
366
|
// =========================================
|
|
315
367
|
// Balance read methods
|
|
316
368
|
// =========================================
|
|
@@ -2420,16 +2420,26 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
2420
2420
|
// currentIndex is the NEXT epoch to create; the live one is currentIndex-1.
|
|
2421
2421
|
const targetEpochIndex = currentIndex > 0 ? currentIndex - 1 : 0;
|
|
2422
2422
|
const nextEpochStart = settings.genesisTimestamp + currentIndex * settings.epochDuration;
|
|
2423
|
-
|
|
2424
|
-
|
|
2423
|
+
const epoch = await this.getEpochRaw(targetEpochIndex);
|
|
2424
|
+
// Cold start: the live epoch (targetEpochIndex) doesn't exist yet. Two cases,
|
|
2425
|
+
// handled identically — `create_epoch` always creates epoch[currentIndex] and
|
|
2426
|
+
// then increments the counter, so the NEXT crank finds it live at currentIndex-1:
|
|
2427
|
+
// 1. Genesis: currentIndex === 0 → create epoch 0.
|
|
2428
|
+
// 2. AO→Solana continuity cold start: `admin_set_current_epoch_index` jumped
|
|
2429
|
+
// currentIndex to e.g. 454 with NO prior epochs on-chain (the AO-side
|
|
2430
|
+
// epochs were never created on Solana). targetEpochIndex (453) points at
|
|
2431
|
+
// an epoch that will never exist, so the old `currentIndex === 0`-only
|
|
2432
|
+
// bootstrap deadlocked here ('waiting_for_epoch' forever). Create
|
|
2433
|
+
// epoch[currentIndex] (454) directly — its start was re-anchored to ≈now.
|
|
2434
|
+
if (!epoch) {
|
|
2425
2435
|
if (now < nextEpochStart)
|
|
2426
|
-
return {
|
|
2436
|
+
return {
|
|
2437
|
+
action: 'idle',
|
|
2438
|
+
reason: currentIndex === 0 ? 'waiting_for_genesis' : 'waiting_for_epoch',
|
|
2439
|
+
};
|
|
2427
2440
|
const { id } = await this.createEpoch();
|
|
2428
|
-
return { action: 'create', epochIndex:
|
|
2441
|
+
return { action: 'create', epochIndex: currentIndex, txId: id };
|
|
2429
2442
|
}
|
|
2430
|
-
const epoch = await this.getEpochRaw(targetEpochIndex);
|
|
2431
|
-
if (!epoch)
|
|
2432
|
-
return { action: 'idle', reason: 'waiting_for_epoch' };
|
|
2433
2443
|
// Tally (batched). activeGatewayCount===0 still needs one tx to flip the flag.
|
|
2434
2444
|
if (epoch.weightsTallied === 0) {
|
|
2435
2445
|
const gatewayAccounts = epoch.activeGatewayCount > 0
|
package/lib/esm/version.js
CHANGED
|
@@ -83,6 +83,15 @@ export declare class SolanaARIOReadable {
|
|
|
83
83
|
LastDistributedEpochIndex: number;
|
|
84
84
|
}>;
|
|
85
85
|
getTokenSupply(): Promise<TokenSupplyData>;
|
|
86
|
+
/**
|
|
87
|
+
* Read the `amount` (in mARIO) of an SPL token account directly by address.
|
|
88
|
+
* Returns `null` if the account doesn't exist or is too small to be a token
|
|
89
|
+
* account, so callers can distinguish "absent" from a real zero balance.
|
|
90
|
+
*
|
|
91
|
+
* Uses a portable little-endian u64 decode — some browser bundlers strip the
|
|
92
|
+
* BigInt readers from the `buffer` shim's prototype (see `getBalance`).
|
|
93
|
+
*/
|
|
94
|
+
private getTokenAccountAmount;
|
|
86
95
|
/**
|
|
87
96
|
* Resolve the ARIO SPL mint address from the on-chain `ArioConfig`.
|
|
88
97
|
*
|
package/lib/types/types/io.d.ts
CHANGED
|
@@ -144,6 +144,16 @@ export type EligibleDistribution = {
|
|
|
144
144
|
gatewayAddress: WalletAddress;
|
|
145
145
|
cursorId: string;
|
|
146
146
|
};
|
|
147
|
+
/**
|
|
148
|
+
* The six ARIO supply buckets. They are mutually exclusive and sum to `total`:
|
|
149
|
+
* circulating + locked + staked + delegated + withdrawn + protocolBalance === total
|
|
150
|
+
*
|
|
151
|
+
* `protocolBalance` is the protocol **reward reserve** (the pool epoch rewards
|
|
152
|
+
* are paid from) — on Solana this is the live balance of the protocol token
|
|
153
|
+
* account, matching AO's `protocolBalance` (the qNvAoz0 reserve). It is NOT the
|
|
154
|
+
* on-chain `ArioConfig.protocol_balance` accounting field, which folds the
|
|
155
|
+
* staking buckets in and would double-count.
|
|
156
|
+
*/
|
|
147
157
|
export type TokenSupplyData = {
|
|
148
158
|
total: number;
|
|
149
159
|
circulating: number;
|
package/lib/types/version.d.ts
CHANGED