@ar.io/sdk 4.0.0-solana.25 → 4.0.0-solana.27
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.
|
@@ -1723,8 +1723,21 @@ export class SolanaARIOReadable {
|
|
|
1723
1723
|
return out;
|
|
1724
1724
|
}
|
|
1725
1725
|
/**
|
|
1726
|
-
* Enumerate Gateway PDAs
|
|
1727
|
-
*
|
|
1726
|
+
* Enumerate Gateway PDAs that are candidates for `finalizeGone` GC — i.e.
|
|
1727
|
+
* those whose `status == Leaving`.
|
|
1728
|
+
*
|
|
1729
|
+
* NOTE: despite the historical name, this returns `Leaving` (not `Gone`)
|
|
1730
|
+
* gateways. `Gone` is NOT a persistent discovery state: the on-chain
|
|
1731
|
+
* `finalize_gone` instruction accepts a `Leaving` gateway, flips it to
|
|
1732
|
+
* `Gone`, and closes the Gateway PDA in the *same* instruction
|
|
1733
|
+
* (programs/ario-gar/src/instructions/gateway.rs::finalize_gone), so a
|
|
1734
|
+
* gateway is never observably parked at `Gone`. Filtering on `Gone` matched
|
|
1735
|
+
* nothing and left Leaving gateways un-GC'd. Time/delegation eligibility is
|
|
1736
|
+
* still enforced on-chain (`finalize_gone` reverts early if the leave window
|
|
1737
|
+
* hasn't elapsed or delegations remain), so over-returning not-yet-eligible
|
|
1738
|
+
* Leaving gateways is safe — the tx just no-ops/reverts.
|
|
1739
|
+
*
|
|
1740
|
+
* @deprecated Prefer {@link getLeavingGateways} — same result, accurate name.
|
|
1728
1741
|
*/
|
|
1729
1742
|
async getGoneGateways() {
|
|
1730
1743
|
const accounts = await this.getAccountsByDiscriminator(this.garProgram, GATEWAY_DISCRIMINATOR);
|
|
@@ -1733,7 +1746,7 @@ export class SolanaARIOReadable {
|
|
|
1733
1746
|
for (const { pubkey, data } of accounts) {
|
|
1734
1747
|
try {
|
|
1735
1748
|
const g = decoder.decode(data);
|
|
1736
|
-
if (g.status === GatewayStatus.
|
|
1749
|
+
if (g.status === GatewayStatus.Leaving) {
|
|
1737
1750
|
out.push({ pubkey, operator: g.operator });
|
|
1738
1751
|
}
|
|
1739
1752
|
}
|
|
@@ -1743,6 +1756,14 @@ export class SolanaARIOReadable {
|
|
|
1743
1756
|
}
|
|
1744
1757
|
return out;
|
|
1745
1758
|
}
|
|
1759
|
+
/**
|
|
1760
|
+
* Enumerate Gateway PDAs whose `status == Leaving` — the persistent
|
|
1761
|
+
* pre-finalization state that `finalizeGone` GC's. Alias for
|
|
1762
|
+
* {@link getGoneGateways} with a name that matches the on-chain state.
|
|
1763
|
+
*/
|
|
1764
|
+
async getLeavingGateways() {
|
|
1765
|
+
return this.getGoneGateways();
|
|
1766
|
+
}
|
|
1746
1767
|
/**
|
|
1747
1768
|
* Enumerate Joined Gateway PDAs whose delegation has been DISABLED
|
|
1748
1769
|
* (`allow_delegated_staking == false`) yet still hold delegated stake
|
|
@@ -42,7 +42,7 @@ import { Protocol, getAllowDelegateInstructionAsync, getCancelWithdrawalInstruct
|
|
|
42
42
|
import { getTransferCheckedInstruction } from '@solana-program/token';
|
|
43
43
|
import { ARIO_ANT_PROGRAM_ID, TOKEN_DECIMALS } from './constants.js';
|
|
44
44
|
import { SolanaARIOReadable } from './io-readable.js';
|
|
45
|
-
import { getAntRecordPDA, getArioConfigPDA, getArnsRecordPDA, getArnsRegistryPDA, getArnsSettingsPDA, getDelegationPDA, getDemandFactorPDA, getEpochPDA, getEpochSettingsPDA, getGarSettingsPDA, getGatewayPDA, getGatewayRegistryPDA, getObservationPDA, getObserverLookupPDA, getPrimaryNamePDA, getPrimaryNameRequestPDA, getPrimaryNameReversePDA, getReservedNamePDA, getReturnedNamePDA, getVaultPDA, getWithdrawalCounterPDA, getWithdrawalPDA, hashName, } from './pda.js';
|
|
45
|
+
import { getAntConfigPDA, getAntRecordPDA, getArioConfigPDA, getArnsRecordPDA, getArnsRegistryPDA, getArnsSettingsPDA, getDelegationPDA, getDemandFactorPDA, getEpochPDA, getEpochSettingsPDA, getGarSettingsPDA, getGatewayPDA, getGatewayRegistryPDA, getObservationPDA, getObserverLookupPDA, getPrimaryNamePDA, getPrimaryNameRequestPDA, getPrimaryNameReversePDA, getReservedNamePDA, getReturnedNamePDA, getVaultPDA, getWithdrawalCounterPDA, getWithdrawalPDA, hashName, } from './pda.js';
|
|
46
46
|
import { predictPrescribedObservers, } from './predict-prescribed-observers.js';
|
|
47
47
|
import { reclaimLookupTablesForSigner, sendAndConfirm, sendWithEphemeralLookupTable, } from './send.js';
|
|
48
48
|
const addressDecoder = getAddressDecoder();
|
|
@@ -69,6 +69,36 @@ function withRemainingAccounts(ix, remaining) {
|
|
|
69
69
|
];
|
|
70
70
|
return { ...ix, accounts };
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Pick the swapped-gateway operator that `finalize_gone` needs as a writable
|
|
74
|
+
* `remaining_accounts[0]`.
|
|
75
|
+
*
|
|
76
|
+
* `finalize_gone` reclaims a gateway's slot from the compact GatewayRegistry by
|
|
77
|
+
* moving the LAST active slot into it and rewriting that swapped gateway's
|
|
78
|
+
* stored `registry_index`. When the finalized gateway is NOT already the last
|
|
79
|
+
* slot, the on-chain handler requires the swapped Gateway PDA (writable) at
|
|
80
|
+
* `remaining_accounts[0]`; when it IS the last slot, no swap occurs and no
|
|
81
|
+
* extra account is needed. See
|
|
82
|
+
* `programs/ario-gar/src/instructions/gateway.rs::finalize_gone`.
|
|
83
|
+
*
|
|
84
|
+
* `registryAddresses` MUST be the active registry operator addresses in slot
|
|
85
|
+
* order (`getRegistryGatewayAddresses()` — length === on-chain
|
|
86
|
+
* `registry.count`), so `registryAddresses[length - 1]` is exactly the
|
|
87
|
+
* `registry.gateways[count - 1].address` the on-chain swap reads.
|
|
88
|
+
*
|
|
89
|
+
* @returns the swapped gateway's operator address, or `null` when the finalized
|
|
90
|
+
* gateway already occupies the last slot.
|
|
91
|
+
* @throws if `registryIndex` is outside the active registry count (mirrors the
|
|
92
|
+
* on-chain `index < registry.count` guard, surfacing a stale index early).
|
|
93
|
+
*/
|
|
94
|
+
export function selectFinalizeGoneSwapOperator(registryIndex, registryAddresses) {
|
|
95
|
+
if (registryIndex < 0 || registryIndex >= registryAddresses.length) {
|
|
96
|
+
throw new Error(`finalizeGone: registry index ${registryIndex} is outside the active ` +
|
|
97
|
+
`registry count ${registryAddresses.length}`);
|
|
98
|
+
}
|
|
99
|
+
const lastIndex = registryAddresses.length - 1;
|
|
100
|
+
return registryIndex === lastIndex ? null : registryAddresses[lastIndex];
|
|
101
|
+
}
|
|
72
102
|
/**
|
|
73
103
|
* Split a primary name into its undername + base parts using the same rule
|
|
74
104
|
* as the on-chain `splitn(2, '_')` in `programs/ario-core/src/instructions/primary_name.rs`:
|
|
@@ -1427,14 +1457,16 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1427
1457
|
* Build the `remaining_accounts` slice + the `antProgramId` arg the
|
|
1428
1458
|
* four ario-core primary-name instructions consume. Sprint 2/5
|
|
1429
1459
|
* reshape (ADR-016): ario-core no longer reads MPL Core asset bytes.
|
|
1430
|
-
* Authorization is "caller is the AntRecord
|
|
1431
|
-
*
|
|
1460
|
+
* Authorization is "caller is the effective AntRecord owner for this
|
|
1461
|
+
* name", resolved from the `AntRecord` + `AntConfig` PDAs (freshness-
|
|
1462
|
+
* gated against `AntConfig.last_known_owner` — see ario-core BD-097 /
|
|
1463
|
+
* BD-109). Both are program-PDA-pinned lookups.
|
|
1432
1464
|
*
|
|
1433
1465
|
* Layouts the on-chain handlers expect:
|
|
1434
1466
|
* request_primary_name: [arnsRecord, demandFactor]
|
|
1435
|
-
* request_and_set_primary_name: [arnsRecord, demandFactor, antRecord]
|
|
1436
|
-
* approve_primary_name: [arnsRecord, antRecord]
|
|
1437
|
-
* remove_primary_name_for_base_name: [arnsRecord, antRecord(@)]
|
|
1467
|
+
* request_and_set_primary_name: [arnsRecord, demandFactor, antRecord, antConfig]
|
|
1468
|
+
* approve_primary_name: [arnsRecord, antRecord, antConfig]
|
|
1469
|
+
* remove_primary_name_for_base_name: [arnsRecord, antRecord(@), antConfig]
|
|
1438
1470
|
*
|
|
1439
1471
|
* `antRecord` keys off the undername part for undernames (e.g.
|
|
1440
1472
|
* "blog_arweave" → AntRecord at "blog") or the canonical "@" sentinel
|
|
@@ -1506,6 +1538,15 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1506
1538
|
: undername;
|
|
1507
1539
|
const [antRecordPda] = await getAntRecordPDA(antMint, antUndername, antProgram);
|
|
1508
1540
|
remaining.push({ address: antRecordPda, role: AccountRole.READONLY });
|
|
1541
|
+
// AntConfig PDA (ANT-level owner snapshot). ario-core reads
|
|
1542
|
+
// `AntConfig.last_known_owner` as the implicit-owner source and to
|
|
1543
|
+
// freshness-gate the per-record `AntRecord.owner` delegate (BD-097 /
|
|
1544
|
+
// BD-109). Derived under the SAME resolved `antProgram` as the
|
|
1545
|
+
// AntRecord above. Required trailing account for all three ANT-auth
|
|
1546
|
+
// variants (and the funding-plan variant, whose validation_account_count
|
|
1547
|
+
// is derived from this array's length downstream).
|
|
1548
|
+
const [antConfigPda] = await getAntConfigPDA(antMint, antProgram);
|
|
1549
|
+
remaining.push({ address: antConfigPda, role: AccountRole.READONLY });
|
|
1509
1550
|
}
|
|
1510
1551
|
return { remaining, antProgram };
|
|
1511
1552
|
}
|
|
@@ -1662,7 +1703,7 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1662
1703
|
*
|
|
1663
1704
|
* Mirrors the on-chain `approve_primary_name` instruction
|
|
1664
1705
|
* (`programs/ario-core/src/instructions/primary_name.rs`).
|
|
1665
|
-
* remaining_accounts: [arns_record(base), ant_record(undername | @)].
|
|
1706
|
+
* remaining_accounts: [arns_record(base), ant_record(undername | @), ant_config].
|
|
1666
1707
|
*/
|
|
1667
1708
|
async approvePrimaryName(params, _options) {
|
|
1668
1709
|
const { baseName } = splitPrimaryName(params.name);
|
|
@@ -2616,11 +2657,34 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
2616
2657
|
async finalizeGone(params, _options) {
|
|
2617
2658
|
const gatewayAddr = address(params.gateway);
|
|
2618
2659
|
const [gatewayPda] = await getGatewayPDA(gatewayAddr, this.garProgram);
|
|
2660
|
+
// `finalize_gone` reclaims this gateway's compact-registry slot by
|
|
2661
|
+
// swap-removing the LAST active slot into it. When this gateway is not the
|
|
2662
|
+
// last slot, the on-chain handler rewrites the swapped gateway's stored
|
|
2663
|
+
// registry_index and therefore requires that swapped Gateway PDA as
|
|
2664
|
+
// writable remaining_accounts[0]
|
|
2665
|
+
// (programs/ario-gar/src/instructions/gateway.rs::finalize_gone). Read the
|
|
2666
|
+
// gateway's slot index + the active registry to decide.
|
|
2667
|
+
const gatewayAccount = await fetchEncodedAccount(this.rpc, gatewayPda, {
|
|
2668
|
+
commitment: this.commitment,
|
|
2669
|
+
});
|
|
2670
|
+
if (!gatewayAccount.exists) {
|
|
2671
|
+
throw new Error(`Gateway not found for operator ${params.gateway}`);
|
|
2672
|
+
}
|
|
2673
|
+
const gateway = getGatewayDecoder().decode(gatewayAccount.data);
|
|
2674
|
+
const registryAddresses = await this.getRegistryGatewayAddresses();
|
|
2675
|
+
const swappedOperator = selectFinalizeGoneSwapOperator(gateway.registryIndex.index, registryAddresses);
|
|
2619
2676
|
const ix = await getFinalizeGoneInstructionAsync(await this.withGarDefaults({
|
|
2620
2677
|
gateway: gatewayPda,
|
|
2621
2678
|
caller: this.signer,
|
|
2622
2679
|
}), { programAddress: this.garProgram });
|
|
2623
|
-
|
|
2680
|
+
let finalIx = ix;
|
|
2681
|
+
if (swappedOperator !== null) {
|
|
2682
|
+
const [swappedGatewayPda] = await getGatewayPDA(address(swappedOperator), this.garProgram);
|
|
2683
|
+
finalIx = withRemainingAccounts(ix, [
|
|
2684
|
+
{ address: swappedGatewayPda, role: AccountRole.WRITABLE },
|
|
2685
|
+
]);
|
|
2686
|
+
}
|
|
2687
|
+
const sig = await this.sendTransaction([finalIx]);
|
|
2624
2688
|
return { id: sig };
|
|
2625
2689
|
}
|
|
2626
2690
|
/**
|
package/lib/esm/version.js
CHANGED
|
@@ -302,13 +302,35 @@ export declare class SolanaARIOReadable {
|
|
|
302
302
|
failedConsecutive: number;
|
|
303
303
|
}>>;
|
|
304
304
|
/**
|
|
305
|
-
* Enumerate Gateway PDAs
|
|
306
|
-
*
|
|
305
|
+
* Enumerate Gateway PDAs that are candidates for `finalizeGone` GC — i.e.
|
|
306
|
+
* those whose `status == Leaving`.
|
|
307
|
+
*
|
|
308
|
+
* NOTE: despite the historical name, this returns `Leaving` (not `Gone`)
|
|
309
|
+
* gateways. `Gone` is NOT a persistent discovery state: the on-chain
|
|
310
|
+
* `finalize_gone` instruction accepts a `Leaving` gateway, flips it to
|
|
311
|
+
* `Gone`, and closes the Gateway PDA in the *same* instruction
|
|
312
|
+
* (programs/ario-gar/src/instructions/gateway.rs::finalize_gone), so a
|
|
313
|
+
* gateway is never observably parked at `Gone`. Filtering on `Gone` matched
|
|
314
|
+
* nothing and left Leaving gateways un-GC'd. Time/delegation eligibility is
|
|
315
|
+
* still enforced on-chain (`finalize_gone` reverts early if the leave window
|
|
316
|
+
* hasn't elapsed or delegations remain), so over-returning not-yet-eligible
|
|
317
|
+
* Leaving gateways is safe — the tx just no-ops/reverts.
|
|
318
|
+
*
|
|
319
|
+
* @deprecated Prefer {@link getLeavingGateways} — same result, accurate name.
|
|
307
320
|
*/
|
|
308
321
|
getGoneGateways(): Promise<Array<{
|
|
309
322
|
pubkey: Address;
|
|
310
323
|
operator: Address;
|
|
311
324
|
}>>;
|
|
325
|
+
/**
|
|
326
|
+
* Enumerate Gateway PDAs whose `status == Leaving` — the persistent
|
|
327
|
+
* pre-finalization state that `finalizeGone` GC's. Alias for
|
|
328
|
+
* {@link getGoneGateways} with a name that matches the on-chain state.
|
|
329
|
+
*/
|
|
330
|
+
getLeavingGateways(): Promise<Array<{
|
|
331
|
+
pubkey: Address;
|
|
332
|
+
operator: Address;
|
|
333
|
+
}>>;
|
|
312
334
|
/**
|
|
313
335
|
* Enumerate Joined Gateway PDAs whose delegation has been DISABLED
|
|
314
336
|
* (`allow_delegated_staking == false`) yet still hold delegated stake
|
|
@@ -26,6 +26,29 @@ import type { mARIOToken } from '../types/token.js';
|
|
|
26
26
|
import { deserializeEpochSettingsFull } from './deserialize.js';
|
|
27
27
|
import { SolanaARIOReadable } from './io-readable.js';
|
|
28
28
|
import type { SolanaRpcSubscriptions, SolanaSigner, SolanaWriteConfig } from './types.js';
|
|
29
|
+
/**
|
|
30
|
+
* Pick the swapped-gateway operator that `finalize_gone` needs as a writable
|
|
31
|
+
* `remaining_accounts[0]`.
|
|
32
|
+
*
|
|
33
|
+
* `finalize_gone` reclaims a gateway's slot from the compact GatewayRegistry by
|
|
34
|
+
* moving the LAST active slot into it and rewriting that swapped gateway's
|
|
35
|
+
* stored `registry_index`. When the finalized gateway is NOT already the last
|
|
36
|
+
* slot, the on-chain handler requires the swapped Gateway PDA (writable) at
|
|
37
|
+
* `remaining_accounts[0]`; when it IS the last slot, no swap occurs and no
|
|
38
|
+
* extra account is needed. See
|
|
39
|
+
* `programs/ario-gar/src/instructions/gateway.rs::finalize_gone`.
|
|
40
|
+
*
|
|
41
|
+
* `registryAddresses` MUST be the active registry operator addresses in slot
|
|
42
|
+
* order (`getRegistryGatewayAddresses()` — length === on-chain
|
|
43
|
+
* `registry.count`), so `registryAddresses[length - 1]` is exactly the
|
|
44
|
+
* `registry.gateways[count - 1].address` the on-chain swap reads.
|
|
45
|
+
*
|
|
46
|
+
* @returns the swapped gateway's operator address, or `null` when the finalized
|
|
47
|
+
* gateway already occupies the last slot.
|
|
48
|
+
* @throws if `registryIndex` is outside the active registry count (mirrors the
|
|
49
|
+
* on-chain `index < registry.count` guard, surfacing a stale index early).
|
|
50
|
+
*/
|
|
51
|
+
export declare function selectFinalizeGoneSwapOperator(registryIndex: number, registryAddresses: string[]): string | null;
|
|
29
52
|
/**
|
|
30
53
|
* Split a primary name into its undername + base parts using the same rule
|
|
31
54
|
* as the on-chain `splitn(2, '_')` in `programs/ario-core/src/instructions/primary_name.rs`:
|
|
@@ -350,14 +373,16 @@ export declare class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
350
373
|
* Build the `remaining_accounts` slice + the `antProgramId` arg the
|
|
351
374
|
* four ario-core primary-name instructions consume. Sprint 2/5
|
|
352
375
|
* reshape (ADR-016): ario-core no longer reads MPL Core asset bytes.
|
|
353
|
-
* Authorization is "caller is the AntRecord
|
|
354
|
-
*
|
|
376
|
+
* Authorization is "caller is the effective AntRecord owner for this
|
|
377
|
+
* name", resolved from the `AntRecord` + `AntConfig` PDAs (freshness-
|
|
378
|
+
* gated against `AntConfig.last_known_owner` — see ario-core BD-097 /
|
|
379
|
+
* BD-109). Both are program-PDA-pinned lookups.
|
|
355
380
|
*
|
|
356
381
|
* Layouts the on-chain handlers expect:
|
|
357
382
|
* request_primary_name: [arnsRecord, demandFactor]
|
|
358
|
-
* request_and_set_primary_name: [arnsRecord, demandFactor, antRecord]
|
|
359
|
-
* approve_primary_name: [arnsRecord, antRecord]
|
|
360
|
-
* remove_primary_name_for_base_name: [arnsRecord, antRecord(@)]
|
|
383
|
+
* request_and_set_primary_name: [arnsRecord, demandFactor, antRecord, antConfig]
|
|
384
|
+
* approve_primary_name: [arnsRecord, antRecord, antConfig]
|
|
385
|
+
* remove_primary_name_for_base_name: [arnsRecord, antRecord(@), antConfig]
|
|
361
386
|
*
|
|
362
387
|
* `antRecord` keys off the undername part for undernames (e.g.
|
|
363
388
|
* "blog_arweave" → AntRecord at "blog") or the canonical "@" sentinel
|
|
@@ -400,7 +425,7 @@ export declare class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
400
425
|
*
|
|
401
426
|
* Mirrors the on-chain `approve_primary_name` instruction
|
|
402
427
|
* (`programs/ario-core/src/instructions/primary_name.rs`).
|
|
403
|
-
* remaining_accounts: [arns_record(base), ant_record(undername | @)].
|
|
428
|
+
* remaining_accounts: [arns_record(base), ant_record(undername | @), ant_config].
|
|
404
429
|
*/
|
|
405
430
|
approvePrimaryName(params: {
|
|
406
431
|
initiator: Address;
|
package/lib/types/version.d.ts
CHANGED