@ar.io/sdk 4.0.0-solana.9 → 4.0.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/README.md +721 -673
- package/lib/esm/cli/cli.js +28 -152
- package/lib/esm/cli/commands/antCommands.js +5 -66
- package/lib/esm/cli/commands/arnsPurchaseCommands.js +7 -28
- package/lib/esm/cli/commands/escrowCommands.js +23 -4
- package/lib/esm/cli/commands/gatewayWriteCommands.js +15 -8
- package/lib/esm/cli/commands/pruneCommands.js +14 -26
- package/lib/esm/cli/commands/readCommands.js +12 -1
- package/lib/esm/cli/options.js +2 -75
- package/lib/esm/cli/utils.js +96 -209
- package/lib/esm/common/ant-registry.js +12 -160
- package/lib/esm/common/ant.js +40 -1208
- package/lib/esm/common/faucet.js +17 -6
- package/lib/esm/common/index.js +0 -4
- package/lib/esm/common/io.js +13 -1441
- package/lib/esm/constants.js +0 -18
- package/lib/esm/solana/ant-readable.js +391 -54
- package/lib/esm/solana/ant-registry-readable.js +15 -0
- package/lib/esm/solana/ant-registry-writeable.js +19 -4
- package/lib/esm/solana/ant-writeable.js +43 -11
- package/lib/esm/solana/ata.js +15 -0
- package/lib/esm/solana/canonical-message.js +45 -9
- package/lib/esm/solana/clusters.js +71 -22
- package/lib/esm/solana/constants.js +21 -5
- package/lib/esm/solana/delegation-math.js +49 -0
- package/lib/esm/solana/deserialize.js +263 -727
- package/lib/esm/solana/escrow.js +145 -103
- package/lib/esm/solana/events.js +20 -199
- package/lib/esm/solana/funding-plan.js +19 -2
- package/lib/esm/solana/index.js +53 -12
- package/lib/esm/solana/instruction.js +15 -0
- package/lib/esm/solana/io-readable.js +510 -58
- package/lib/esm/solana/io-writeable.js +1179 -183
- package/lib/esm/solana/json-rpc.js +20 -4
- package/lib/esm/solana/metadata.js +15 -0
- package/lib/esm/solana/mpl-core.js +55 -5
- package/lib/esm/solana/pda.js +15 -0
- package/lib/esm/solana/predict-prescribed-observers.js +110 -0
- package/lib/esm/solana/retry.js +117 -0
- package/lib/esm/solana/rpc-circuit-breaker.js +258 -0
- package/lib/esm/solana/send.js +258 -3
- package/lib/esm/solana/spawn-ant.js +16 -2
- package/lib/esm/types/ant.js +8 -8
- package/lib/esm/types/io.js +0 -10
- package/lib/esm/utils/ant.js +0 -64
- package/lib/esm/utils/index.js +0 -3
- package/lib/esm/version.js +1 -1
- package/lib/types/cli/commands/antCommands.d.ts +6 -9
- package/lib/types/cli/commands/arnsPurchaseCommands.d.ts +27 -13
- package/lib/types/cli/commands/escrowCommands.d.ts +6 -0
- package/lib/types/cli/commands/gatewayWriteCommands.d.ts +12 -11
- package/lib/types/cli/commands/pruneCommands.d.ts +11 -11
- package/lib/types/cli/commands/readCommands.d.ts +25 -22
- package/lib/types/cli/commands/transfer.d.ts +9 -9
- package/lib/types/cli/options.d.ts +0 -57
- package/lib/types/cli/types.d.ts +6 -14
- package/lib/types/cli/utils.d.ts +34 -32
- package/lib/types/common/ant-registry.d.ts +35 -74
- package/lib/types/common/ant.d.ts +52 -570
- package/lib/types/common/faucet.d.ts +20 -8
- package/lib/types/common/index.d.ts +0 -3
- package/lib/types/common/io.d.ts +56 -288
- package/lib/types/constants.d.ts +0 -17
- package/lib/types/solana/ant-readable.d.ts +65 -6
- package/lib/types/solana/ant-registry-readable.d.ts +17 -2
- package/lib/types/solana/ant-registry-writeable.d.ts +20 -5
- package/lib/types/solana/ant-writeable.d.ts +39 -24
- package/lib/types/solana/ata.d.ts +15 -0
- package/lib/types/solana/canonical-message.d.ts +44 -5
- package/lib/types/solana/clusters.d.ts +68 -21
- package/lib/types/solana/constants.d.ts +16 -0
- package/lib/types/solana/delegation-math.d.ts +25 -0
- package/lib/types/solana/deserialize.d.ts +28 -198
- package/lib/types/solana/escrow.d.ts +128 -51
- package/lib/types/solana/events.d.ts +26 -144
- package/lib/types/solana/funding-plan.d.ts +15 -0
- package/lib/types/solana/index.d.ts +27 -3
- package/lib/types/solana/instruction.d.ts +15 -0
- package/lib/types/solana/io-readable.d.ts +185 -46
- package/lib/types/solana/io-writeable.d.ts +450 -77
- package/lib/types/solana/json-rpc.d.ts +15 -0
- package/lib/types/solana/metadata.d.ts +15 -0
- package/lib/types/solana/mpl-core.d.ts +44 -0
- package/lib/types/solana/predict-prescribed-observers.d.ts +28 -0
- package/lib/types/solana/retry.d.ts +62 -0
- package/lib/types/solana/rpc-circuit-breaker.d.ts +78 -0
- package/lib/types/solana/send.d.ts +80 -2
- package/lib/types/solana/spawn-ant.d.ts +15 -0
- package/lib/types/solana/types.d.ts +15 -0
- package/lib/types/types/ant-registry.d.ts +4 -4
- package/lib/types/types/ant.d.ts +92 -92
- package/lib/types/types/common.d.ts +18 -74
- package/lib/types/types/faucet.d.ts +2 -2
- package/lib/types/types/io.d.ts +189 -158
- package/lib/types/types/token.d.ts +0 -12
- package/lib/types/utils/ant.d.ts +1 -12
- package/lib/types/utils/index.d.ts +0 -3
- package/lib/types/version.d.ts +1 -1
- package/package.json +23 -37
- package/lib/esm/common/ant-versions.js +0 -87
- package/lib/esm/common/arweave.js +0 -21
- package/lib/esm/common/contracts/ao-process.js +0 -218
- package/lib/esm/common/hyperbeam/hb.js +0 -169
- package/lib/esm/common/marketplace.js +0 -669
- package/lib/esm/common/turbo.js +0 -215
- package/lib/esm/node/index.js +0 -20
- package/lib/esm/solana/generated/ant/events/aclEntryAddedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/aclEntryRemovedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/antMetadataUpdatedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/antReconciledEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/antTransferredEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/attributesClearedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/attributesSyncedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/controllerAddedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/controllerRemovedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/index.js +0 -16
- package/lib/esm/solana/generated/ant/events/recordMetadataPrunedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/recordMetadataRemovedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/recordMetadataUpdatedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/recordRemovedEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/recordSetEvent.js +0 -21
- package/lib/esm/solana/generated/ant/events/recordTransferredEvent.js +0 -21
- package/lib/esm/solana/generated/ant-escrow/events/escrowCancelledEvent.js +0 -21
- package/lib/esm/solana/generated/ant-escrow/events/escrowClaimedEvent.js +0 -21
- package/lib/esm/solana/generated/ant-escrow/events/escrowDepositedEvent.js +0 -21
- package/lib/esm/solana/generated/ant-escrow/events/escrowRecipientUpdatedEvent.js +0 -21
- package/lib/esm/solana/generated/ant-escrow/events/index.js +0 -5
- package/lib/esm/solana/generated/arns/events/demandFactorUpdatedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/index.js +0 -13
- package/lib/esm/solana/generated/arns/events/leaseExtendedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/namePurchasedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/nameReassignedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/nameReleasedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/nameReservedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/nameUnreservedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/nameUpgradedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/namesPrunedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/reservedNameClaimedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/returnedNamePurchasedEvent.js +0 -21
- package/lib/esm/solana/generated/arns/events/undernameIncreasedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/configUpdatedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/coreMigrationFinalizedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/index.js +0 -14
- package/lib/esm/solana/generated/core/events/primaryNameRemovedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/primaryNameRequestExpiredEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/primaryNameRequestedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/primaryNameSetEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/supplyFinalizedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/transferEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/vaultCreatedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/vaultExtendedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/vaultIncreasedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/vaultReleasedEvent.js +0 -21
- package/lib/esm/solana/generated/core/events/vaultRevokedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/allowlistToggledEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/delegateAllowlistedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/delegationClosedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/delegationDecreasedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/delegationEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/epochClosedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/epochCreatedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/epochDistributedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/epochPrescribedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/epochWeightsTalliedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/epochsToggledEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/fundingPlanAppliedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/garMigrationFinalizedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/gatewayFinalizedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/gatewayJoinedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/gatewayLeavingEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/gatewayPrunedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/gatewaySettingsUpdatedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/index.js +0 -31
- package/lib/esm/solana/generated/gar/events/instantWithdrawalEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/observationSubmittedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/observerAddressUpdatedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/operatorStakeIncreasedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/redelegationEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/residueVaultCreatedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/rewardsCompoundedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/stakePaymentEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/withdrawalCancelledEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/withdrawalClaimedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/withdrawalCreatedEvent.js +0 -21
- package/lib/esm/solana/generated/gar/events/withdrawalPaymentEvent.js +0 -21
- package/lib/esm/solana/generated/mpl-core/accounts/assetV1.js +0 -42
- package/lib/esm/solana/generated/mpl-core/accounts/collectionV1.js +0 -42
- package/lib/esm/solana/generated/mpl-core/accounts/hashedAssetV1.js +0 -45
- package/lib/esm/solana/generated/mpl-core/accounts/index.js +0 -12
- package/lib/esm/solana/generated/mpl-core/accounts/pluginHeaderV1.js +0 -45
- package/lib/esm/solana/generated/mpl-core/accounts/pluginRegistryV1.js +0 -42
- package/lib/esm/solana/generated/mpl-core/errors/index.js +0 -8
- package/lib/esm/solana/generated/mpl-core/errors/mplCore.js +0 -136
- package/lib/esm/solana/generated/mpl-core/index.js +0 -8
- package/lib/esm/solana/generated/mpl-core/instructions/addCollectionExternalPluginAdapterV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/addCollectionPluginV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/addExternalPluginAdapterV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/addPluginV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/approveCollectionPluginAuthorityV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/approvePluginAuthorityV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/burnCollectionV1.js +0 -49
- package/lib/esm/solana/generated/mpl-core/instructions/burnV1.js +0 -49
- package/lib/esm/solana/generated/mpl-core/instructions/collect.js +0 -42
- package/lib/esm/solana/generated/mpl-core/instructions/compressV1.js +0 -50
- package/lib/esm/solana/generated/mpl-core/instructions/createCollectionV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/createCollectionV2.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/createV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/createV2.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/decompressV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/executeV1.js +0 -56
- package/lib/esm/solana/generated/mpl-core/instructions/index.js +0 -40
- package/lib/esm/solana/generated/mpl-core/instructions/removeCollectionExternalPluginAdapterV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/removeCollectionPluginV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/removeExternalPluginAdapterV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/removePluginV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/revokeCollectionPluginAuthorityV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/revokePluginAuthorityV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/transferV1.js +0 -49
- package/lib/esm/solana/generated/mpl-core/instructions/updateCollectionExternalPluginAdapterV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/updateCollectionInfoV1.js +0 -45
- package/lib/esm/solana/generated/mpl-core/instructions/updateCollectionPluginV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/updateCollectionV1.js +0 -52
- package/lib/esm/solana/generated/mpl-core/instructions/updateExternalPluginAdapterV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/updatePluginV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/updateV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/updateV2.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/writeCollectionExternalPluginAdapterDataV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/instructions/writeExternalPluginAdapterDataV1.js +0 -53
- package/lib/esm/solana/generated/mpl-core/program-address.js +0 -1
- package/lib/esm/solana/generated/mpl-core/types/addAssetsToGroupV1Args.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/addBlocker.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/addCollectionsToGroupV1Args.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/addGroupsToGroupV1Args.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/agentIdentity.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/agentIdentityInitInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/agentIdentityUpdateInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/appData.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/appDataInitInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/appDataUpdateInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/attribute.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/attributes.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/authority.js +0 -24
- package/lib/esm/solana/generated/mpl-core/types/autograph.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/autographSignature.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/bubblegumV2.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/burnDelegate.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/closeGroupV1Args.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/compressionProof.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/creator.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/dataSection.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/dataSectionInitInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/dataSectionUpdateInfo.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/dataState.js +0 -23
- package/lib/esm/solana/generated/mpl-core/types/edition.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/externalCheckResult.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/externalPluginAdapter.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/externalPluginAdapterInitInfo.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/externalPluginAdapterKey.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/externalPluginAdapterSchema.js +0 -24
- package/lib/esm/solana/generated/mpl-core/types/externalPluginAdapterType.js +0 -28
- package/lib/esm/solana/generated/mpl-core/types/externalPluginAdapterUpdateInfo.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/externalRegistryRecord.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/externalValidationResult.js +0 -24
- package/lib/esm/solana/generated/mpl-core/types/extraAccount.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/freezeDelegate.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/freezeExecute.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/groups.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/hashablePluginSchema.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/hashedAssetSchema.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/hookableLifecycleEvent.js +0 -26
- package/lib/esm/solana/generated/mpl-core/types/immutableMetadata.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/index.js +0 -89
- package/lib/esm/solana/generated/mpl-core/types/key.js +0 -28
- package/lib/esm/solana/generated/mpl-core/types/lifecycleHook.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/lifecycleHookInitInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/lifecycleHookUpdateInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/linkedAppData.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/linkedAppDataInitInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/linkedAppDataUpdateInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/linkedDataKey.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/linkedLifecycleHook.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/linkedLifecycleHookInitInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/linkedLifecycleHookUpdateInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/masterEdition.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/oracle.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/oracleInitInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/oracleUpdateInfo.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/oracleValidation.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/permanentBurnDelegate.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/permanentFreezeDelegate.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/permanentFreezeExecute.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/permanentTransferDelegate.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/plugin.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/pluginAuthorityPair.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/pluginType.js +0 -40
- package/lib/esm/solana/generated/mpl-core/types/registryRecord.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/relationshipKind.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/removeAssetsFromGroupV1Args.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/removeCollectionsFromGroupV1Args.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/removeGroupsFromGroupV1Args.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/royalties.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/ruleSet.js +0 -24
- package/lib/esm/solana/generated/mpl-core/types/seed.js +0 -24
- package/lib/esm/solana/generated/mpl-core/types/transferDelegate.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/updateAuthority.js +0 -24
- package/lib/esm/solana/generated/mpl-core/types/updateDelegate.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/updateGroupV1Args.js +0 -17
- package/lib/esm/solana/generated/mpl-core/types/updateType.js +0 -24
- package/lib/esm/solana/generated/mpl-core/types/validationResult.js +0 -25
- package/lib/esm/solana/generated/mpl-core/types/validationResultsOffset.js +0 -24
- package/lib/esm/solana/generated/mpl-core/types/verifiedCreators.js +0 -18
- package/lib/esm/solana/generated/mpl-core/types/verifiedCreatorsSignature.js +0 -17
- package/lib/esm/utils/ao.js +0 -421
- package/lib/esm/utils/arweave.js +0 -271
- package/lib/esm/utils/processes.js +0 -167
- package/lib/esm/web/index.js +0 -20
- package/lib/types/common/ant-versions.d.ts +0 -39
- package/lib/types/common/arweave.d.ts +0 -17
- package/lib/types/common/contracts/ao-process.d.ts +0 -33
- package/lib/types/common/hyperbeam/hb.d.ts +0 -88
- package/lib/types/common/marketplace.d.ts +0 -556
- package/lib/types/common/turbo.d.ts +0 -61
- package/lib/types/node/index.d.ts +0 -20
- package/lib/types/solana/generated/ant/events/aclEntryAddedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/aclEntryRemovedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/antMetadataUpdatedEvent.d.ts +0 -28
- package/lib/types/solana/generated/ant/events/antReconciledEvent.d.ts +0 -28
- package/lib/types/solana/generated/ant/events/antTransferredEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/attributesClearedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/attributesSyncedEvent.d.ts +0 -24
- package/lib/types/solana/generated/ant/events/controllerAddedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/controllerRemovedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/index.d.ts +0 -15
- package/lib/types/solana/generated/ant/events/recordMetadataPrunedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/recordMetadataRemovedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/recordMetadataUpdatedEvent.d.ts +0 -28
- package/lib/types/solana/generated/ant/events/recordRemovedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant/events/recordSetEvent.d.ts +0 -34
- package/lib/types/solana/generated/ant/events/recordTransferredEvent.d.ts +0 -30
- package/lib/types/solana/generated/ant-escrow/events/escrowCancelledEvent.d.ts +0 -28
- package/lib/types/solana/generated/ant-escrow/events/escrowClaimedEvent.d.ts +0 -32
- package/lib/types/solana/generated/ant-escrow/events/escrowDepositedEvent.d.ts +0 -36
- package/lib/types/solana/generated/ant-escrow/events/escrowRecipientUpdatedEvent.d.ts +0 -26
- package/lib/types/solana/generated/ant-escrow/events/index.d.ts +0 -4
- package/lib/types/solana/generated/arns/events/demandFactorUpdatedEvent.d.ts +0 -28
- package/lib/types/solana/generated/arns/events/index.d.ts +0 -12
- package/lib/types/solana/generated/arns/events/leaseExtendedEvent.d.ts +0 -32
- package/lib/types/solana/generated/arns/events/namePurchasedEvent.d.ts +0 -34
- package/lib/types/solana/generated/arns/events/nameReassignedEvent.d.ts +0 -28
- package/lib/types/solana/generated/arns/events/nameReleasedEvent.d.ts +0 -24
- package/lib/types/solana/generated/arns/events/nameReservedEvent.d.ts +0 -28
- package/lib/types/solana/generated/arns/events/nameUnreservedEvent.d.ts +0 -24
- package/lib/types/solana/generated/arns/events/nameUpgradedEvent.d.ts +0 -28
- package/lib/types/solana/generated/arns/events/namesPrunedEvent.d.ts +0 -26
- package/lib/types/solana/generated/arns/events/reservedNameClaimedEvent.d.ts +0 -24
- package/lib/types/solana/generated/arns/events/returnedNamePurchasedEvent.d.ts +0 -32
- package/lib/types/solana/generated/arns/events/undernameIncreasedEvent.d.ts +0 -32
- package/lib/types/solana/generated/core/events/configUpdatedEvent.d.ts +0 -26
- package/lib/types/solana/generated/core/events/coreMigrationFinalizedEvent.d.ts +0 -26
- package/lib/types/solana/generated/core/events/index.d.ts +0 -13
- package/lib/types/solana/generated/core/events/primaryNameRemovedEvent.d.ts +0 -26
- package/lib/types/solana/generated/core/events/primaryNameRequestExpiredEvent.d.ts +0 -26
- package/lib/types/solana/generated/core/events/primaryNameRequestedEvent.d.ts +0 -30
- package/lib/types/solana/generated/core/events/primaryNameSetEvent.d.ts +0 -24
- package/lib/types/solana/generated/core/events/supplyFinalizedEvent.d.ts +0 -26
- package/lib/types/solana/generated/core/events/transferEvent.d.ts +0 -26
- package/lib/types/solana/generated/core/events/vaultCreatedEvent.d.ts +0 -28
- package/lib/types/solana/generated/core/events/vaultExtendedEvent.d.ts +0 -26
- package/lib/types/solana/generated/core/events/vaultIncreasedEvent.d.ts +0 -28
- package/lib/types/solana/generated/core/events/vaultReleasedEvent.d.ts +0 -26
- package/lib/types/solana/generated/core/events/vaultRevokedEvent.d.ts +0 -28
- package/lib/types/solana/generated/gar/events/allowlistToggledEvent.d.ts +0 -24
- package/lib/types/solana/generated/gar/events/delegateAllowlistedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/delegationClosedEvent.d.ts +0 -24
- package/lib/types/solana/generated/gar/events/delegationDecreasedEvent.d.ts +0 -28
- package/lib/types/solana/generated/gar/events/delegationEvent.d.ts +0 -28
- package/lib/types/solana/generated/gar/events/epochClosedEvent.d.ts +0 -24
- package/lib/types/solana/generated/gar/events/epochCreatedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/epochDistributedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/epochPrescribedEvent.d.ts +0 -28
- package/lib/types/solana/generated/gar/events/epochWeightsTalliedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/epochsToggledEvent.d.ts +0 -24
- package/lib/types/solana/generated/gar/events/fundingPlanAppliedEvent.d.ts +0 -28
- package/lib/types/solana/generated/gar/events/garMigrationFinalizedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/gatewayFinalizedEvent.d.ts +0 -24
- package/lib/types/solana/generated/gar/events/gatewayJoinedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/gatewayLeavingEvent.d.ts +0 -22
- package/lib/types/solana/generated/gar/events/gatewayPrunedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/gatewaySettingsUpdatedEvent.d.ts +0 -24
- package/lib/types/solana/generated/gar/events/index.d.ts +0 -30
- package/lib/types/solana/generated/gar/events/instantWithdrawalEvent.d.ts +0 -30
- package/lib/types/solana/generated/gar/events/observationSubmittedEvent.d.ts +0 -28
- package/lib/types/solana/generated/gar/events/observerAddressUpdatedEvent.d.ts +0 -24
- package/lib/types/solana/generated/gar/events/operatorStakeIncreasedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/redelegationEvent.d.ts +0 -30
- package/lib/types/solana/generated/gar/events/residueVaultCreatedEvent.d.ts +0 -30
- package/lib/types/solana/generated/gar/events/rewardsCompoundedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/stakePaymentEvent.d.ts +0 -28
- package/lib/types/solana/generated/gar/events/withdrawalCancelledEvent.d.ts +0 -30
- package/lib/types/solana/generated/gar/events/withdrawalClaimedEvent.d.ts +0 -26
- package/lib/types/solana/generated/gar/events/withdrawalCreatedEvent.d.ts +0 -28
- package/lib/types/solana/generated/gar/events/withdrawalPaymentEvent.d.ts +0 -28
- package/lib/types/solana/generated/mpl-core/accounts/assetV1.d.ts +0 -37
- package/lib/types/solana/generated/mpl-core/accounts/collectionV1.d.ts +0 -37
- package/lib/types/solana/generated/mpl-core/accounts/hashedAssetV1.d.ts +0 -30
- package/lib/types/solana/generated/mpl-core/accounts/index.d.ts +0 -12
- package/lib/types/solana/generated/mpl-core/accounts/pluginHeaderV1.d.ts +0 -30
- package/lib/types/solana/generated/mpl-core/accounts/pluginRegistryV1.d.ts +0 -31
- package/lib/types/solana/generated/mpl-core/errors/index.d.ts +0 -8
- package/lib/types/solana/generated/mpl-core/errors/mplCore.d.ts +0 -133
- package/lib/types/solana/generated/mpl-core/index.d.ts +0 -8
- package/lib/types/solana/generated/mpl-core/instructions/addCollectionExternalPluginAdapterV1.d.ts +0 -56
- package/lib/types/solana/generated/mpl-core/instructions/addCollectionPluginV1.d.ts +0 -59
- package/lib/types/solana/generated/mpl-core/instructions/addExternalPluginAdapterV1.d.ts +0 -60
- package/lib/types/solana/generated/mpl-core/instructions/addPluginV1.d.ts +0 -63
- package/lib/types/solana/generated/mpl-core/instructions/approveCollectionPluginAuthorityV1.d.ts +0 -59
- package/lib/types/solana/generated/mpl-core/instructions/approvePluginAuthorityV1.d.ts +0 -63
- package/lib/types/solana/generated/mpl-core/instructions/burnCollectionV1.d.ts +0 -52
- package/lib/types/solana/generated/mpl-core/instructions/burnV1.d.ts +0 -60
- package/lib/types/solana/generated/mpl-core/instructions/collect.d.ts +0 -39
- package/lib/types/solana/generated/mpl-core/instructions/compressV1.d.ts +0 -55
- package/lib/types/solana/generated/mpl-core/instructions/createCollectionV1.d.ts +0 -58
- package/lib/types/solana/generated/mpl-core/instructions/createCollectionV2.d.ts +0 -61
- package/lib/types/solana/generated/mpl-core/instructions/createV1.d.ts +0 -77
- package/lib/types/solana/generated/mpl-core/instructions/createV2.d.ts +0 -80
- package/lib/types/solana/generated/mpl-core/instructions/decompressV1.d.ts +0 -60
- package/lib/types/solana/generated/mpl-core/instructions/executeV1.d.ts +0 -63
- package/lib/types/solana/generated/mpl-core/instructions/index.d.ts +0 -40
- package/lib/types/solana/generated/mpl-core/instructions/removeCollectionExternalPluginAdapterV1.d.ts +0 -56
- package/lib/types/solana/generated/mpl-core/instructions/removeCollectionPluginV1.d.ts +0 -56
- package/lib/types/solana/generated/mpl-core/instructions/removeExternalPluginAdapterV1.d.ts +0 -60
- package/lib/types/solana/generated/mpl-core/instructions/removePluginV1.d.ts +0 -60
- package/lib/types/solana/generated/mpl-core/instructions/revokeCollectionPluginAuthorityV1.d.ts +0 -56
- package/lib/types/solana/generated/mpl-core/instructions/revokePluginAuthorityV1.d.ts +0 -60
- package/lib/types/solana/generated/mpl-core/instructions/transferV1.d.ts +0 -64
- package/lib/types/solana/generated/mpl-core/instructions/updateCollectionExternalPluginAdapterV1.d.ts +0 -59
- package/lib/types/solana/generated/mpl-core/instructions/updateCollectionInfoV1.d.ts +0 -47
- package/lib/types/solana/generated/mpl-core/instructions/updateCollectionPluginV1.d.ts +0 -56
- package/lib/types/solana/generated/mpl-core/instructions/updateCollectionV1.d.ts +0 -62
- package/lib/types/solana/generated/mpl-core/instructions/updateExternalPluginAdapterV1.d.ts +0 -63
- package/lib/types/solana/generated/mpl-core/instructions/updatePluginV1.d.ts +0 -60
- package/lib/types/solana/generated/mpl-core/instructions/updateV1.d.ts +0 -66
- package/lib/types/solana/generated/mpl-core/instructions/updateV2.d.ts +0 -70
- package/lib/types/solana/generated/mpl-core/instructions/writeCollectionExternalPluginAdapterDataV1.d.ts +0 -63
- package/lib/types/solana/generated/mpl-core/instructions/writeExternalPluginAdapterDataV1.d.ts +0 -67
- package/lib/types/solana/generated/mpl-core/program-address.d.ts +0 -7
- package/lib/types/solana/generated/mpl-core/types/addAssetsToGroupV1Args.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/addBlocker.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/addCollectionsToGroupV1Args.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/addGroupsToGroupV1Args.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/agentIdentity.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/agentIdentityInitInfo.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/agentIdentityUpdateInfo.d.ts +0 -20
- package/lib/types/solana/generated/mpl-core/types/appData.d.ts +0 -20
- package/lib/types/solana/generated/mpl-core/types/appDataInitInfo.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/appDataUpdateInfo.d.ts +0 -18
- package/lib/types/solana/generated/mpl-core/types/attribute.d.ts +0 -16
- package/lib/types/solana/generated/mpl-core/types/attributes.d.ts +0 -18
- package/lib/types/solana/generated/mpl-core/types/authority.d.ts +0 -29
- package/lib/types/solana/generated/mpl-core/types/autograph.d.ts +0 -18
- package/lib/types/solana/generated/mpl-core/types/autographSignature.d.ts +0 -16
- package/lib/types/solana/generated/mpl-core/types/bubblegumV2.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/burnDelegate.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/closeGroupV1Args.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/compressionProof.d.ts +0 -28
- package/lib/types/solana/generated/mpl-core/types/creator.d.ts +0 -16
- package/lib/types/solana/generated/mpl-core/types/dataSection.d.ts +0 -20
- package/lib/types/solana/generated/mpl-core/types/dataSectionInitInfo.d.ts +0 -20
- package/lib/types/solana/generated/mpl-core/types/dataSectionUpdateInfo.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/dataState.d.ts +0 -16
- package/lib/types/solana/generated/mpl-core/types/edition.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/externalCheckResult.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/externalPluginAdapter.d.ts +0 -66
- package/lib/types/solana/generated/mpl-core/types/externalPluginAdapterInitInfo.d.ts +0 -66
- package/lib/types/solana/generated/mpl-core/types/externalPluginAdapterKey.d.ts +0 -64
- package/lib/types/solana/generated/mpl-core/types/externalPluginAdapterSchema.d.ts +0 -17
- package/lib/types/solana/generated/mpl-core/types/externalPluginAdapterType.d.ts +0 -21
- package/lib/types/solana/generated/mpl-core/types/externalPluginAdapterUpdateInfo.d.ts +0 -59
- package/lib/types/solana/generated/mpl-core/types/externalRegistryRecord.d.ts +0 -28
- package/lib/types/solana/generated/mpl-core/types/externalValidationResult.d.ts +0 -17
- package/lib/types/solana/generated/mpl-core/types/extraAccount.d.ts +0 -86
- package/lib/types/solana/generated/mpl-core/types/freezeDelegate.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/freezeExecute.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/groups.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/hashablePluginSchema.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/hashedAssetSchema.d.ts +0 -16
- package/lib/types/solana/generated/mpl-core/types/hookableLifecycleEvent.d.ts +0 -19
- package/lib/types/solana/generated/mpl-core/types/immutableMetadata.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/index.d.ts +0 -89
- package/lib/types/solana/generated/mpl-core/types/key.d.ts +0 -21
- package/lib/types/solana/generated/mpl-core/types/lifecycleHook.d.ts +0 -24
- package/lib/types/solana/generated/mpl-core/types/lifecycleHookInitInfo.d.ts +0 -28
- package/lib/types/solana/generated/mpl-core/types/lifecycleHookUpdateInfo.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/linkedAppData.d.ts +0 -20
- package/lib/types/solana/generated/mpl-core/types/linkedAppDataInitInfo.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/linkedAppDataUpdateInfo.d.ts +0 -18
- package/lib/types/solana/generated/mpl-core/types/linkedDataKey.d.ts +0 -31
- package/lib/types/solana/generated/mpl-core/types/linkedLifecycleHook.d.ts +0 -24
- package/lib/types/solana/generated/mpl-core/types/linkedLifecycleHookInitInfo.d.ts +0 -28
- package/lib/types/solana/generated/mpl-core/types/linkedLifecycleHookUpdateInfo.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/masterEdition.d.ts +0 -21
- package/lib/types/solana/generated/mpl-core/types/oracle.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/oracleInitInfo.d.ts +0 -26
- package/lib/types/solana/generated/mpl-core/types/oracleUpdateInfo.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/oracleValidation.d.ts +0 -35
- package/lib/types/solana/generated/mpl-core/types/permanentBurnDelegate.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/permanentFreezeDelegate.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/permanentFreezeExecute.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/permanentTransferDelegate.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/plugin.d.ts +0 -150
- package/lib/types/solana/generated/mpl-core/types/pluginAuthorityPair.d.ts +0 -20
- package/lib/types/solana/generated/mpl-core/types/pluginType.d.ts +0 -33
- package/lib/types/solana/generated/mpl-core/types/registryRecord.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/relationshipKind.d.ts +0 -18
- package/lib/types/solana/generated/mpl-core/types/removeAssetsFromGroupV1Args.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/removeCollectionsFromGroupV1Args.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/removeGroupsFromGroupV1Args.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/royalties.d.ts +0 -22
- package/lib/types/solana/generated/mpl-core/types/ruleSet.d.ts +0 -27
- package/lib/types/solana/generated/mpl-core/types/seed.d.ts +0 -36
- package/lib/types/solana/generated/mpl-core/types/transferDelegate.d.ts +0 -13
- package/lib/types/solana/generated/mpl-core/types/updateAuthority.d.ts +0 -27
- package/lib/types/solana/generated/mpl-core/types/updateDelegate.d.ts +0 -15
- package/lib/types/solana/generated/mpl-core/types/updateGroupV1Args.d.ts +0 -19
- package/lib/types/solana/generated/mpl-core/types/updateType.d.ts +0 -17
- package/lib/types/solana/generated/mpl-core/types/validationResult.d.ts +0 -18
- package/lib/types/solana/generated/mpl-core/types/validationResultsOffset.d.ts +0 -33
- package/lib/types/solana/generated/mpl-core/types/verifiedCreators.d.ts +0 -18
- package/lib/types/solana/generated/mpl-core/types/verifiedCreatorsSignature.d.ts +0 -16
- package/lib/types/utils/ao.d.ts +0 -80
- package/lib/types/utils/arweave.d.ts +0 -79
- package/lib/types/utils/processes.d.ts +0 -39
- package/lib/types/web/index.d.ts +0 -20
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Solana implementation of ARIOWrite interface.
|
|
3
18
|
*
|
|
4
19
|
* Extends SolanaARIOReadable with write operations that build and send
|
|
5
20
|
* Solana transactions via Codama-generated instruction builders.
|
|
@@ -18,11 +33,11 @@
|
|
|
18
33
|
* epoch crank instructions, since Codama doesn't generate a typed
|
|
19
34
|
* surface for them.
|
|
20
35
|
*/
|
|
21
|
-
import { AccountRole, address, fetchEncodedAccount, getAddressDecoder, } from '@solana/kit';
|
|
22
|
-
import { PurchaseType, getBuyNameFromDelegationInstructionAsync, getBuyNameFromFundingPlanInstructionAsync, getBuyNameFromOperatorStakeInstructionAsync, getBuyNameFromWithdrawalInstructionAsync, getBuyNameInstructionAsync, getBuyReturnedNameFromDelegationInstructionAsync, getBuyReturnedNameFromFundingPlanInstructionAsync, getBuyReturnedNameFromOperatorStakeInstructionAsync, getBuyReturnedNameFromWithdrawalInstructionAsync, getBuyReturnedNameInstructionAsync, getExtendLeaseFromDelegationInstructionAsync, getExtendLeaseFromFundingPlanInstructionAsync, getExtendLeaseFromOperatorStakeInstructionAsync, getExtendLeaseFromWithdrawalInstructionAsync, getExtendLeaseInstructionAsync, getIncreaseUndernameLimitFromDelegationInstructionAsync, getIncreaseUndernameLimitFromFundingPlanInstructionAsync, getIncreaseUndernameLimitFromOperatorStakeInstructionAsync, getIncreaseUndernameLimitFromWithdrawalInstructionAsync, getIncreaseUndernameLimitInstructionAsync, getPruneExpiredNamesInstructionAsync, getPruneExpiredReservationInstruction, getPruneNameToReturnedInstructionAsync, getPruneReturnedNamesInstructionAsync, getReassignNameInstructionAsync, getReleaseNameInstructionAsync, getUpgradeNameFromDelegationInstructionAsync, getUpgradeNameFromFundingPlanInstructionAsync, getUpgradeNameFromOperatorStakeInstructionAsync, getUpgradeNameFromWithdrawalInstructionAsync, getUpgradeNameInstructionAsync, } from '@ar.io/solana-contracts/arns';
|
|
36
|
+
import { AccountRole, address, appendTransactionMessageInstructions, compileTransaction, createTransactionMessage, fetchEncodedAccount, getAddressDecoder, getBase64EncodedWireTransaction, pipe, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, } from '@solana/kit';
|
|
37
|
+
import { CostIntent, PurchaseType, getBuyNameFromDelegationInstructionAsync, getBuyNameFromFundingPlanInstructionAsync, getBuyNameFromOperatorStakeInstructionAsync, getBuyNameFromWithdrawalInstructionAsync, getBuyNameInstructionAsync, getBuyReturnedNameFromDelegationInstructionAsync, getBuyReturnedNameFromFundingPlanInstructionAsync, getBuyReturnedNameFromOperatorStakeInstructionAsync, getBuyReturnedNameFromWithdrawalInstructionAsync, getBuyReturnedNameInstructionAsync, getExtendLeaseFromDelegationInstructionAsync, getExtendLeaseFromFundingPlanInstructionAsync, getExtendLeaseFromOperatorStakeInstructionAsync, getExtendLeaseFromWithdrawalInstructionAsync, getExtendLeaseInstructionAsync, getGetTokenCostInstructionAsync, getIncreaseUndernameLimitFromDelegationInstructionAsync, getIncreaseUndernameLimitFromFundingPlanInstructionAsync, getIncreaseUndernameLimitFromOperatorStakeInstructionAsync, getIncreaseUndernameLimitFromWithdrawalInstructionAsync, getIncreaseUndernameLimitInstructionAsync, getMigrateArnsRecordInstruction, getPruneExpiredNamesInstructionAsync, getPruneExpiredReservationInstruction, getPruneNameToReturnedInstructionAsync, getPruneReturnedNamesInstructionAsync, getReassignNameInstructionAsync, getReleaseNameInstructionAsync, getUpdateDemandFactorInstruction, getUpgradeNameFromDelegationInstructionAsync, getUpgradeNameFromFundingPlanInstructionAsync, getUpgradeNameFromOperatorStakeInstructionAsync, getUpgradeNameFromWithdrawalInstructionAsync, getUpgradeNameInstructionAsync, } from '@ar.io/solana-contracts/arns';
|
|
23
38
|
import { FundingSourceKind as GeneratedFundingSourceKindEnum } from '@ar.io/solana-contracts/gar';
|
|
24
39
|
import { buildCreateAtaIdempotentIx, getAssociatedTokenAddressKit, } from './ata.js';
|
|
25
|
-
import { deserializeArnsRecord, deserializeEpochSettingsFull, } from './deserialize.js';
|
|
40
|
+
import { deserializeArnsRecord, deserializeDemandFactor, deserializeEpochSettingsFull, deserializePrimaryName, } from './deserialize.js';
|
|
26
41
|
import { buildFundingPlan as buildFundingPlanCore, buildFundingPlanRemainingAccounts, computeResidueIndexes, predictResidueVaults, } from './funding-plan.js';
|
|
27
42
|
/** Maps the SDK's user-facing FundingSourceKind string union to the
|
|
28
43
|
* Codama-generated enum used by the on-chain ix payload. */
|
|
@@ -36,14 +51,15 @@ function toGeneratedFundingSourceSpec(s) {
|
|
|
36
51
|
return { kind: kindMap[s.kind], amount: s.amount };
|
|
37
52
|
}
|
|
38
53
|
import { getSyncAttributesInstruction } from '@ar.io/solana-contracts/ant';
|
|
39
|
-
import { getApprovePrimaryNameInstructionAsync, getCloseExpiredRequestInstruction, getCreateVaultInstructionAsync, getExtendVaultInstructionAsync, getIncreaseVaultInstructionAsync, getReleaseVaultInstructionAsync, getRequestAndSetPrimaryNameFromFundingPlanInstructionAsync, getRequestAndSetPrimaryNameInstructionAsync, getRequestPrimaryNameFromFundingPlanInstructionAsync, getRequestPrimaryNameInstructionAsync, getRevokeVaultInstructionAsync, getVaultedTransferInstructionAsync, } from '@ar.io/solana-contracts/core';
|
|
54
|
+
import { getApprovePrimaryNameInstructionAsync, getCloseExpiredRequestInstruction, getCreateVaultInstructionAsync, getExtendVaultInstructionAsync, getIncreaseVaultInstructionAsync, getReleaseVaultInstructionAsync, getRemovePrimaryNameInstructionAsync, getRequestAndSetPrimaryNameFromFundingPlanInstructionAsync, getRequestAndSetPrimaryNameInstructionAsync, getRequestPrimaryNameFromFundingPlanInstructionAsync, getRequestPrimaryNameInstructionAsync, getRevokeVaultInstructionAsync, getVaultedTransferInstructionAsync, } from '@ar.io/solana-contracts/core';
|
|
40
55
|
import { getDelegationDecoder, getGatewayDecoder, } from '@ar.io/solana-contracts/gar';
|
|
41
|
-
import { Protocol, getAllowDelegateInstructionAsync, getCancelWithdrawalInstruction, getClaimDelegateFromLeavingGatewayInstructionAsync, getClaimWithdrawalInstructionAsync, getCloseDrainedWithdrawalInstruction, getCloseEmptyDelegationInstruction, getCloseEpochInstructionAsync, getCloseObservationInstructionAsync, getCreateEpochInstructionAsync, getDecreaseDelegateStakeInstructionAsync, getDecreaseOperatorStakeInstructionAsync, getDelegateStakeInstructionAsync, getDisallowDelegateInstructionAsync, getDistributeEpochInstructionAsync, getFinalizeGoneInstructionAsync, getIncreaseOperatorStakeInstructionAsync, getInstantWithdrawalInstructionAsync, getJoinNetworkInstructionAsync, getLeaveNetworkInstructionAsync, getPrescribeEpochInstructionAsync, getPruneGatewayInstructionAsync, getRedelegateStakeInstructionAsync, getSaveObservationsInstructionAsync, getSetAllowlistEnabledInstructionAsync, getTallyWeightsInstructionAsync, getUpdateGatewaySettingsInstructionAsync, } from '@ar.io/solana-contracts/gar';
|
|
56
|
+
import { Protocol, getAllowDelegateInstructionAsync, getCancelWithdrawalInstruction, getClaimDelegateFromDisabledGatewayInstructionAsync, getClaimDelegateFromLeavingGatewayInstructionAsync, getClaimWithdrawalInstructionAsync, getCloseDrainedWithdrawalInstruction, getCloseEmptyDelegationInstruction, getCloseEpochInstructionAsync, getCloseObservationInstructionAsync, getCompoundDelegationRewardsInstruction, getCreateEpochInstructionAsync, getDecreaseDelegateStakeInstructionAsync, getDecreaseOperatorStakeInstructionAsync, getDelegateStakeInstructionAsync, getDisallowDelegateInstructionAsync, getDistributeEpochInstructionAsync, getFinalizeGoneInstructionAsync, getIncreaseOperatorStakeInstructionAsync, getInstantWithdrawalInstructionAsync, getJoinNetworkInstructionAsync, getLeaveNetworkInstructionAsync, getPrescribeEpochInstructionAsync, getPruneGatewayInstructionAsync, getRedelegateStakeInstructionAsync, getSaveObservationsInstructionAsync, getSetAllowlistEnabledInstructionAsync, getTallyWeightsInstructionAsync, getUpdateGatewaySettingsInstructionAsync, getUpdateObserverAddressInstructionAsync, } from '@ar.io/solana-contracts/gar';
|
|
42
57
|
import { getTransferCheckedInstruction } from '@solana-program/token';
|
|
43
|
-
import { TOKEN_DECIMALS } from './constants.js';
|
|
58
|
+
import { ARIO_ANT_PROGRAM_ID, TOKEN_DECIMALS } from './constants.js';
|
|
44
59
|
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';
|
|
46
|
-
import {
|
|
60
|
+
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';
|
|
61
|
+
import { predictPrescribedObservers, } from './predict-prescribed-observers.js';
|
|
62
|
+
import { reclaimLookupTablesForSigner, sendAndConfirm, sendWithEphemeralLookupTable, } from './send.js';
|
|
47
63
|
const addressDecoder = getAddressDecoder();
|
|
48
64
|
/** Resolve mARIOToken | number to a plain number */
|
|
49
65
|
function toAmount(qty) {
|
|
@@ -68,6 +84,36 @@ function withRemainingAccounts(ix, remaining) {
|
|
|
68
84
|
];
|
|
69
85
|
return { ...ix, accounts };
|
|
70
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Pick the swapped-gateway operator that `finalize_gone` needs as a writable
|
|
89
|
+
* `remaining_accounts[0]`.
|
|
90
|
+
*
|
|
91
|
+
* `finalize_gone` reclaims a gateway's slot from the compact GatewayRegistry by
|
|
92
|
+
* moving the LAST active slot into it and rewriting that swapped gateway's
|
|
93
|
+
* stored `registry_index`. When the finalized gateway is NOT already the last
|
|
94
|
+
* slot, the on-chain handler requires the swapped Gateway PDA (writable) at
|
|
95
|
+
* `remaining_accounts[0]`; when it IS the last slot, no swap occurs and no
|
|
96
|
+
* extra account is needed. See
|
|
97
|
+
* `programs/ario-gar/src/instructions/gateway.rs::finalize_gone`.
|
|
98
|
+
*
|
|
99
|
+
* `registryAddresses` MUST be the active registry operator addresses in slot
|
|
100
|
+
* order (`getRegistryGatewayAddresses()` — length === on-chain
|
|
101
|
+
* `registry.count`), so `registryAddresses[length - 1]` is exactly the
|
|
102
|
+
* `registry.gateways[count - 1].address` the on-chain swap reads.
|
|
103
|
+
*
|
|
104
|
+
* @returns the swapped gateway's operator address, or `null` when the finalized
|
|
105
|
+
* gateway already occupies the last slot.
|
|
106
|
+
* @throws if `registryIndex` is outside the active registry count (mirrors the
|
|
107
|
+
* on-chain `index < registry.count` guard, surfacing a stale index early).
|
|
108
|
+
*/
|
|
109
|
+
export function selectFinalizeGoneSwapOperator(registryIndex, registryAddresses) {
|
|
110
|
+
if (registryIndex < 0 || registryIndex >= registryAddresses.length) {
|
|
111
|
+
throw new Error(`finalizeGone: registry index ${registryIndex} is outside the active ` +
|
|
112
|
+
`registry count ${registryAddresses.length}`);
|
|
113
|
+
}
|
|
114
|
+
const lastIndex = registryAddresses.length - 1;
|
|
115
|
+
return registryIndex === lastIndex ? null : registryAddresses[lastIndex];
|
|
116
|
+
}
|
|
71
117
|
/**
|
|
72
118
|
* Split a primary name into its undername + base parts using the same rule
|
|
73
119
|
* as the on-chain `splitn(2, '_')` in `programs/ario-core/src/instructions/primary_name.rs`:
|
|
@@ -181,6 +227,47 @@ export function encodeReportTxId(reportTxId) {
|
|
|
181
227
|
decoded.copy(out);
|
|
182
228
|
return out;
|
|
183
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Max `compound_delegation_rewards` instructions packed into one batched tx.
|
|
232
|
+
* Each is a SEPARATE instruction carrying a gateway + delegation + delegator
|
|
233
|
+
* account, so — unlike the single-ix `remaining_accounts` lifecycle batch (see
|
|
234
|
+
* `MAX_LIFECYCLE_BATCH`) and unlike prescribe (which uses an ALT) — the per-item
|
|
235
|
+
* tx cost is high and there is nothing to compress. Cap low enough that a full
|
|
236
|
+
* worst-case batch (all-distinct gateways → no account dedup) stays under
|
|
237
|
+
* Solana's 1232-byte transaction limit. A full batch of 12 overflows it and
|
|
238
|
+
* wedged epoch progression on staging-V2 (the RPC rejected the tx — observed at
|
|
239
|
+
* 1928B base64, well over the 1232B raw cap). Exported so the regression test in
|
|
240
|
+
* `compound-crank.test.ts` asserts this invariant against the live constant.
|
|
241
|
+
*/
|
|
242
|
+
export const MAX_COMPOUND_BATCH = 6;
|
|
243
|
+
/** Observation PDAs closed per tx before close_epoch (each ix carries Epoch +
|
|
244
|
+
* Observation + payer + system accounts — keep well under the tx account cap). */
|
|
245
|
+
const MAX_CLOSE_OBSERVATION_BATCH = 8;
|
|
246
|
+
/** Demand-factor period length (seconds) — mirrors `PERIOD_LENGTH_SECONDS` in ario-arns. */
|
|
247
|
+
const DEMAND_FACTOR_PERIOD_SECONDS = 86_400;
|
|
248
|
+
/**
|
|
249
|
+
* Detect the GAR `InvalidGatewayAccount` error by Anchor error name/message
|
|
250
|
+
* (walking the cause chain + `context.logs`), NOT by numeric code — codes are
|
|
251
|
+
* `6000 + enum-index` and shift across program versions, but the name and
|
|
252
|
+
* message are stable. `prescribe_epoch` raises this when a supplied observer
|
|
253
|
+
* Gateway PDA is missing/spoofed (e.g. a predicted observer left the registry
|
|
254
|
+
* between prediction and tx landing).
|
|
255
|
+
*/
|
|
256
|
+
export function isInvalidGatewayAccountError(error) {
|
|
257
|
+
const parts = [];
|
|
258
|
+
let cur = error;
|
|
259
|
+
for (let i = 0; cur != null && i < 8; i++) {
|
|
260
|
+
const e = cur;
|
|
261
|
+
if (e.message)
|
|
262
|
+
parts.push(e.message);
|
|
263
|
+
if (Array.isArray(e.context?.logs))
|
|
264
|
+
parts.push(e.context.logs.join('\n'));
|
|
265
|
+
cur = e.cause;
|
|
266
|
+
}
|
|
267
|
+
const text = parts.join('\n');
|
|
268
|
+
return (text.includes('InvalidGatewayAccount') ||
|
|
269
|
+
text.includes('Invalid gateway account'));
|
|
270
|
+
}
|
|
184
271
|
export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
185
272
|
signer;
|
|
186
273
|
rpcSubscriptions;
|
|
@@ -280,6 +367,35 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
280
367
|
const [nameRegistry] = await getArnsRegistryPDA(this.arnsProgram);
|
|
281
368
|
return { config, demandFactor, nameRegistry, ...input };
|
|
282
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* If the on-chain ArnsRecord for `name` hasn't been migrated to the
|
|
372
|
+
* current schema (name_hash at offset 8 doesn't match the expected
|
|
373
|
+
* hash), return a `migrate_arns_record` instruction that must be
|
|
374
|
+
* prepended to any operation referencing the record with PDA seed
|
|
375
|
+
* verification.
|
|
376
|
+
*
|
|
377
|
+
* Returns an empty array when the record is already up-to-date or
|
|
378
|
+
* doesn't exist.
|
|
379
|
+
*/
|
|
380
|
+
async _buildMigrateArnsRecordIxIfNeeded(name) {
|
|
381
|
+
const [arnsRecordPda] = await getArnsRecordPDA(name, this.arnsProgram);
|
|
382
|
+
const account = await fetchEncodedAccount(this.rpc, arnsRecordPda, {
|
|
383
|
+
commitment: this.commitment,
|
|
384
|
+
});
|
|
385
|
+
if (!account.exists)
|
|
386
|
+
return [];
|
|
387
|
+
const data = Buffer.from(account.data);
|
|
388
|
+
const expectedHash = hashName(name);
|
|
389
|
+
const storedHash = data.subarray(8, 40);
|
|
390
|
+
if (storedHash.equals(expectedHash))
|
|
391
|
+
return [];
|
|
392
|
+
return [
|
|
393
|
+
getMigrateArnsRecordInstruction({
|
|
394
|
+
record: arnsRecordPda,
|
|
395
|
+
payer: this.signer,
|
|
396
|
+
}, { programAddress: this.arnsProgram }),
|
|
397
|
+
];
|
|
398
|
+
}
|
|
283
399
|
/** Inject ARIO core default PDAs (config). */
|
|
284
400
|
async withCoreDefaults(input) {
|
|
285
401
|
const [config] = await getArioConfigPDA(this.coreProgram);
|
|
@@ -493,25 +609,50 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
493
609
|
return { id: sig };
|
|
494
610
|
}
|
|
495
611
|
async updateGatewaySettings(params, _options) {
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
: null,
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
612
|
+
const ixs = [];
|
|
613
|
+
// Settings fields (label, fqdn, port, etc.) — only emit when at least one
|
|
614
|
+
// non-observer field is provided so we don't send a no-op instruction.
|
|
615
|
+
const { observerAddress: _observer, ...settingsFields } = params;
|
|
616
|
+
if (Object.keys(settingsFields).length > 0) {
|
|
617
|
+
const settingsIx = await getUpdateGatewaySettingsInstructionAsync(await this.withGarDefaults({
|
|
618
|
+
operator: this.signer,
|
|
619
|
+
label: params.label ?? null,
|
|
620
|
+
fqdn: params.fqdn ?? null,
|
|
621
|
+
port: params.port ?? null,
|
|
622
|
+
// Codama exposes `protocol` as Option<Protocol>. We only ever updated
|
|
623
|
+
// the URL parts above, so leave protocol untouched (None).
|
|
624
|
+
protocol: null,
|
|
625
|
+
properties: params.properties ?? null,
|
|
626
|
+
note: params.note ?? null,
|
|
627
|
+
allowDelegatedStaking: typeof params.allowDelegatedStaking === 'boolean'
|
|
628
|
+
? params.allowDelegatedStaking
|
|
629
|
+
: null,
|
|
630
|
+
delegateRewardShareRatio: params.delegateRewardShareRatio ?? null,
|
|
631
|
+
minDelegateStake: params.minDelegatedStake !== undefined
|
|
632
|
+
? BigInt(params.minDelegatedStake)
|
|
633
|
+
: null,
|
|
634
|
+
}), { programAddress: this.garProgram });
|
|
635
|
+
ixs.push(settingsIx);
|
|
636
|
+
}
|
|
637
|
+
// Observer address update — uses a separate on-chain instruction that
|
|
638
|
+
// swaps the observer lookup PDA from old → new.
|
|
639
|
+
if (params.observerAddress !== undefined) {
|
|
640
|
+
const newObserver = address(params.observerAddress);
|
|
641
|
+
const gateway = await this.getGateway({
|
|
642
|
+
address: this.signer.address,
|
|
643
|
+
});
|
|
644
|
+
const oldObserver = address(gateway.observerAddress);
|
|
645
|
+
const [oldObserverLookupPda] = await getObserverLookupPDA(oldObserver, this.garProgram);
|
|
646
|
+
const [newObserverLookupPda] = await getObserverLookupPDA(newObserver, this.garProgram);
|
|
647
|
+
const observerIx = await getUpdateObserverAddressInstructionAsync(await this.withGarDefaults({
|
|
648
|
+
operator: this.signer,
|
|
649
|
+
oldObserverLookup: oldObserverLookupPda,
|
|
650
|
+
newObserverLookup: newObserverLookupPda,
|
|
651
|
+
newObserver,
|
|
652
|
+
}), { programAddress: this.garProgram });
|
|
653
|
+
ixs.push(observerIx);
|
|
654
|
+
}
|
|
655
|
+
const sig = await this.sendTransaction(ixs, 1_000_000);
|
|
515
656
|
return { id: sig };
|
|
516
657
|
}
|
|
517
658
|
async increaseOperatorStake(params, _options) {
|
|
@@ -572,6 +713,11 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
572
713
|
amount,
|
|
573
714
|
}), { programAddress: this.garProgram });
|
|
574
715
|
const sig = await this.sendTransaction([ix], 1_000_000);
|
|
716
|
+
if (!params.instant) {
|
|
717
|
+
return { id: sig };
|
|
718
|
+
}
|
|
719
|
+
// Instant boolean on decrease delegated stake (vs protected exit vault) is not currently supported by the contract — Instead we call InstantWithdrawal after creating the withdrawal, which achieves the same effect but requires two transactions. The protected exit vault is still created in the first transaction, but will be empty and can be ignored when instant = true.
|
|
720
|
+
await this.instantWithdrawal({ vaultId: nextId.toString() }, _options);
|
|
575
721
|
return { id: sig };
|
|
576
722
|
}
|
|
577
723
|
async instantWithdrawal(params, _options) {
|
|
@@ -745,7 +891,16 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
745
891
|
params: buyNameParams,
|
|
746
892
|
}, { programAddress: this.arnsProgram });
|
|
747
893
|
}
|
|
748
|
-
else if (params.fundFrom === 'plan' ||
|
|
894
|
+
else if (params.fundFrom === 'plan' ||
|
|
895
|
+
params.fundFrom === 'any' ||
|
|
896
|
+
params.fundFrom === 'stakes' ||
|
|
897
|
+
params.fundFrom === 'withdrawal') {
|
|
898
|
+
// 'stakes'/'withdrawal' WITHOUT an explicit gatewayAddress/withdrawalId
|
|
899
|
+
// land here (the single-source branches above handle the explicit case).
|
|
900
|
+
// Route through the funding planner, which constrains sources to the
|
|
901
|
+
// chosen mode — it never silently spends liquid balance and auto-splits
|
|
902
|
+
// across the caller's delegations/vaults. (Previously these fell through
|
|
903
|
+
// to the balance path below, silently draining liquid ARIO.)
|
|
749
904
|
ix = await this._buildBuyNameFromFundingPlanIx({
|
|
750
905
|
params,
|
|
751
906
|
antPubkey,
|
|
@@ -756,8 +911,10 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
756
911
|
arnsConfig,
|
|
757
912
|
});
|
|
758
913
|
}
|
|
759
|
-
else
|
|
760
|
-
|
|
914
|
+
else if (!params.fundFrom ||
|
|
915
|
+
params.fundFrom === 'balance' ||
|
|
916
|
+
params.fundFrom === 'turbo') {
|
|
917
|
+
// Direct balance-funded buy.
|
|
761
918
|
ix = await getBuyNameInstructionAsync(await this.withArnsDefaults({
|
|
762
919
|
arnsRecord,
|
|
763
920
|
buyerTokenAccount: buyerATA,
|
|
@@ -768,6 +925,9 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
768
925
|
params: buyNameParams,
|
|
769
926
|
}), { programAddress: this.arnsProgram });
|
|
770
927
|
}
|
|
928
|
+
else {
|
|
929
|
+
throw new Error(`unsupported fundFrom mode '${params.fundFrom}' for buyRecord`);
|
|
930
|
+
}
|
|
771
931
|
// Sprint 4 / ADR-016: bundle `ant.sync_attributes` IFF the buyer
|
|
772
932
|
// owns the ANT (preserves BD-096 — non-holder buys defer the trait
|
|
773
933
|
// sync to a later `syncAttributes()` call by the actual owner).
|
|
@@ -837,12 +997,42 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
837
997
|
};
|
|
838
998
|
}
|
|
839
999
|
// No explicit sources: discover + plan.
|
|
1000
|
+
this.logger.debug(`[funding] discovering sources for ${this.signer.address}`, {
|
|
1001
|
+
fundFrom: params.fundFrom,
|
|
1002
|
+
amountNeeded: amountNeeded.toString(),
|
|
1003
|
+
});
|
|
840
1004
|
const arnsConfig = await this.getArnsConfig();
|
|
841
1005
|
const { discoverFundingSources } = await import('./funding-plan.js');
|
|
842
1006
|
const sources = await discoverFundingSources(this.rpc, this.signer.address, {
|
|
843
1007
|
arioMint: arnsConfig.mint,
|
|
844
1008
|
garProgram: this.garProgram,
|
|
845
1009
|
});
|
|
1010
|
+
this.logger.debug(`[funding] discovered ${sources.length} source(s)`, {
|
|
1011
|
+
sources: sources.map((s) => {
|
|
1012
|
+
if (s.kind === 'balance')
|
|
1013
|
+
return { kind: s.kind, available: s.available.toString() };
|
|
1014
|
+
if (s.kind === 'delegation')
|
|
1015
|
+
return {
|
|
1016
|
+
kind: s.kind,
|
|
1017
|
+
gateway: s.gateway,
|
|
1018
|
+
available: s.available.toString(),
|
|
1019
|
+
minDelegationAmount: s.minDelegationAmount.toString(),
|
|
1020
|
+
};
|
|
1021
|
+
if (s.kind === 'operatorStake')
|
|
1022
|
+
return {
|
|
1023
|
+
kind: s.kind,
|
|
1024
|
+
gateway: s.gateway,
|
|
1025
|
+
available: s.available.toString(),
|
|
1026
|
+
};
|
|
1027
|
+
return {
|
|
1028
|
+
kind: s.kind,
|
|
1029
|
+
withdrawalId: s.withdrawalId.toString(),
|
|
1030
|
+
gateway: s.gateway,
|
|
1031
|
+
available: s.available.toString(),
|
|
1032
|
+
availableAt: s.availableAt.toString(),
|
|
1033
|
+
};
|
|
1034
|
+
}),
|
|
1035
|
+
});
|
|
846
1036
|
const plan = buildFundingPlanCore(sources, amountNeeded, {
|
|
847
1037
|
fundFrom: params.fundFrom,
|
|
848
1038
|
preferGateway: params.gatewayAddress
|
|
@@ -851,10 +1041,20 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
851
1041
|
fundAsOperator: params.fundAsOperator,
|
|
852
1042
|
});
|
|
853
1043
|
if ('kind' in plan) {
|
|
1044
|
+
this.logger.debug(`[funding] plan failed: ${plan.message}`);
|
|
854
1045
|
const err = new Error(plan.message);
|
|
855
1046
|
err.cause = plan;
|
|
856
1047
|
throw err;
|
|
857
1048
|
}
|
|
1049
|
+
this.logger.debug(`[funding] built plan with ${plan.sources.length} source(s)`, {
|
|
1050
|
+
sources: plan.sources.map((s, i) => ({
|
|
1051
|
+
kind: s.kind,
|
|
1052
|
+
amount: s.amount.toString(),
|
|
1053
|
+
gateway: plan.gatewayPerSource[i] ?? null,
|
|
1054
|
+
})),
|
|
1055
|
+
residueDelegationIndexes: plan.residueDelegationIndexes,
|
|
1056
|
+
hasBalanceSource: plan.hasBalanceSource,
|
|
1057
|
+
});
|
|
858
1058
|
return plan;
|
|
859
1059
|
}
|
|
860
1060
|
/**
|
|
@@ -866,7 +1066,12 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
866
1066
|
const garConfig = await this.getGarConfig();
|
|
867
1067
|
const [garSettings] = await getGarSettingsPDA(this.garProgram);
|
|
868
1068
|
const buyerATA = await getAssociatedTokenAddressKit(args.arnsConfig.mint, this.signer.address);
|
|
869
|
-
const cost = await this.
|
|
1069
|
+
const cost = await this._simulateTokenCost({
|
|
1070
|
+
intent: CostIntent.BuyName,
|
|
1071
|
+
name: args.buyNameParams.name,
|
|
1072
|
+
years: args.buyNameParams.years,
|
|
1073
|
+
purchaseType: args.buyNameParams.purchaseType,
|
|
1074
|
+
});
|
|
870
1075
|
const plan = await this._resolveFundingPlan(args.params, cost);
|
|
871
1076
|
const { remainingAccounts, withdrawalCounter, residueVaultCount } = await this._materializeFundingPlan(args.params, plan);
|
|
872
1077
|
return await getBuyNameFromFundingPlanInstructionAsync({
|
|
@@ -979,52 +1184,75 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
979
1184
|
};
|
|
980
1185
|
}
|
|
981
1186
|
/**
|
|
982
|
-
*
|
|
983
|
-
*
|
|
984
|
-
*
|
|
1187
|
+
* Simulate the on-chain `get_token_cost` instruction and return the exact
|
|
1188
|
+
* cost as a `bigint` (mARIO). This guarantees byte-exact agreement with the
|
|
1189
|
+
* on-chain pricing math, avoiding integer-division rounding divergences
|
|
1190
|
+
* that plagued the previous client-side reimplementation.
|
|
985
1191
|
*
|
|
986
|
-
* The
|
|
987
|
-
*
|
|
988
|
-
* live demand-factor and verifies sum(sources) == cost, so an overestimate
|
|
989
|
-
* fails fast with `FundingPlanAmountMismatch`. Callers should retry with a
|
|
990
|
-
* fresh estimate on that error.
|
|
1192
|
+
* The program writes a LE-u64 cost into the transaction's return data;
|
|
1193
|
+
* we parse it from the simulation result.
|
|
991
1194
|
*/
|
|
992
|
-
async
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1195
|
+
async _simulateTokenCost(params) {
|
|
1196
|
+
const demandFactorAddr = await this.demandFactorPda();
|
|
1197
|
+
this.logger.debug(`[funding] simulating token cost`, {
|
|
1198
|
+
intent: params.intent,
|
|
1199
|
+
name: params.name,
|
|
1200
|
+
years: params.years,
|
|
1201
|
+
quantity: params.quantity,
|
|
1202
|
+
purchaseType: params.purchaseType,
|
|
1203
|
+
arnsProgram: this.arnsProgram,
|
|
1204
|
+
demandFactor: demandFactorAddr,
|
|
999
1205
|
});
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
//
|
|
1006
|
-
//
|
|
1007
|
-
//
|
|
1008
|
-
//
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1206
|
+
// Roll the demand factor to the current period BEFORE pricing. The
|
|
1207
|
+
// `GetTokenCost` view reads the STORED demand factor, which is stale until a
|
|
1208
|
+
// crank (or a buy/extend) rolls it — but the `*FromFundingPlan` handlers
|
|
1209
|
+
// roll it inline before computing the cost. Without this, at a period
|
|
1210
|
+
// rollover the plan is sized to the old factor while the program charges
|
|
1211
|
+
// the new one → FundingPlanAmountMismatch (#6066). `update_demand_factor`
|
|
1212
|
+
// is permissionless + idempotent (no-op within the same period), and the
|
|
1213
|
+
// write is local to this simulation; the subsequent `GetTokenCost` in the
|
|
1214
|
+
// same tx sees the rolled value.
|
|
1215
|
+
const updateDfIx = getUpdateDemandFactorInstruction({ demandFactor: demandFactorAddr, payer: this.signer }, { programAddress: this.arnsProgram });
|
|
1216
|
+
const ix = await getGetTokenCostInstructionAsync({
|
|
1217
|
+
demandFactor: demandFactorAddr,
|
|
1218
|
+
payer: this.signer,
|
|
1219
|
+
intent: params.intent,
|
|
1220
|
+
name: params.name,
|
|
1221
|
+
years: params.years ?? null,
|
|
1222
|
+
quantity: params.quantity ?? null,
|
|
1223
|
+
purchaseType: params.purchaseType ?? null,
|
|
1224
|
+
}, { programAddress: this.arnsProgram });
|
|
1225
|
+
const { value: latestBlockhash } = await this.rpc
|
|
1226
|
+
.getLatestBlockhash()
|
|
1227
|
+
.send();
|
|
1228
|
+
const message = pipe(createTransactionMessage({ version: 0 }), (m) => setTransactionMessageFeePayerSigner(this.signer, m), (m) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m), (m) => appendTransactionMessageInstructions([updateDfIx, ix], m));
|
|
1229
|
+
const compiled = compileTransaction(message);
|
|
1230
|
+
const wire = getBase64EncodedWireTransaction(compiled);
|
|
1231
|
+
const sim = await this.rpc
|
|
1232
|
+
.simulateTransaction(wire, {
|
|
1233
|
+
sigVerify: false,
|
|
1234
|
+
replaceRecentBlockhash: true,
|
|
1235
|
+
encoding: 'base64',
|
|
1236
|
+
})
|
|
1237
|
+
.send();
|
|
1238
|
+
if (sim.value.err) {
|
|
1239
|
+
throw new Error(`get_token_cost simulation failed (arnsProgram=${this.arnsProgram}, demandFactor=${demandFactorAddr}): ${JSON.stringify(sim.value.err)}` +
|
|
1240
|
+
(sim.value.logs ? '\n' + sim.value.logs.join('\n') : ''));
|
|
1241
|
+
}
|
|
1242
|
+
const returnData = sim.value.returnData;
|
|
1243
|
+
if (!returnData?.data?.[0]) {
|
|
1244
|
+
throw new Error('get_token_cost simulation returned no data; expected a u64 cost');
|
|
1245
|
+
}
|
|
1246
|
+
const buf = Buffer.from(returnData.data[0], 'base64');
|
|
1247
|
+
if (buf.length < 8) {
|
|
1248
|
+
throw new Error(`get_token_cost return data too short: ${buf.length} bytes (expected 8)`);
|
|
1249
|
+
}
|
|
1250
|
+
const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
1251
|
+
const cost = dv.getBigUint64(0, true);
|
|
1252
|
+
this.logger.debug(`[funding] simulated token cost: ${cost} mARIO`, {
|
|
1253
|
+
name: params.name,
|
|
1254
|
+
});
|
|
1255
|
+
return cost;
|
|
1028
1256
|
}
|
|
1029
1257
|
async arnsConfigPda() {
|
|
1030
1258
|
// The ArNS config (`Settings`) PDA is seeded with `arns_config` — NOT
|
|
@@ -1046,12 +1274,13 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1046
1274
|
return pda;
|
|
1047
1275
|
}
|
|
1048
1276
|
async upgradeRecord(params, _options) {
|
|
1277
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(params.name);
|
|
1049
1278
|
const ix = await this._buildManageStakeIx({
|
|
1050
1279
|
params,
|
|
1051
1280
|
operation: 'upgrade',
|
|
1052
1281
|
});
|
|
1053
1282
|
const syncIx = await this._buildSyncAttributesIxIfOwner(params.name);
|
|
1054
|
-
const sig = await this.sendTransaction(syncIx ? [ix, syncIx] : [ix]);
|
|
1283
|
+
const sig = await this.sendTransaction(syncIx ? [...migrateIxs, ix, syncIx] : [...migrateIxs, ix]);
|
|
1055
1284
|
return { id: sig };
|
|
1056
1285
|
}
|
|
1057
1286
|
async syncAttributes(params, _options) {
|
|
@@ -1061,8 +1290,9 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1061
1290
|
// `_buildSyncAttributesIxIfOwner`, which skips when not the owner so
|
|
1062
1291
|
// the wrapping arns ix can still succeed for non-holder management
|
|
1063
1292
|
// — see BD-095.)
|
|
1293
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(params.name);
|
|
1064
1294
|
const ix = await this._buildSyncAttributesIxUnconditional(params.name);
|
|
1065
|
-
const sig = await this.sendTransaction([ix]);
|
|
1295
|
+
const sig = await this.sendTransaction([...migrateIxs, ix]);
|
|
1066
1296
|
return { id: sig };
|
|
1067
1297
|
}
|
|
1068
1298
|
/**
|
|
@@ -1130,6 +1360,7 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1130
1360
|
}, { programAddress: this.antProgram });
|
|
1131
1361
|
}
|
|
1132
1362
|
async extendLease(params, _options) {
|
|
1363
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(params.name);
|
|
1133
1364
|
const ix = await this._buildManageStakeIx({
|
|
1134
1365
|
params,
|
|
1135
1366
|
operation: 'extend',
|
|
@@ -1137,17 +1368,18 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1137
1368
|
});
|
|
1138
1369
|
// BD-095: extend_lease changes only `end_timestamp`, which isn't
|
|
1139
1370
|
// mirrored in any Metaplex Attributes plugin trait. No bundle.
|
|
1140
|
-
const sig = await this.sendTransaction([ix]);
|
|
1371
|
+
const sig = await this.sendTransaction([...migrateIxs, ix]);
|
|
1141
1372
|
return { id: sig };
|
|
1142
1373
|
}
|
|
1143
1374
|
async increaseUndernameLimit(params, _options) {
|
|
1375
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(params.name);
|
|
1144
1376
|
const ix = await this._buildManageStakeIx({
|
|
1145
1377
|
params,
|
|
1146
1378
|
operation: 'increaseUndername',
|
|
1147
1379
|
quantity: params.increaseCount,
|
|
1148
1380
|
});
|
|
1149
1381
|
const syncIx = await this._buildSyncAttributesIxIfOwner(params.name);
|
|
1150
|
-
const sig = await this.sendTransaction(syncIx ? [ix, syncIx] : [ix]);
|
|
1382
|
+
const sig = await this.sendTransaction(syncIx ? [...migrateIxs, ix, syncIx] : [...migrateIxs, ix]);
|
|
1151
1383
|
return { id: sig };
|
|
1152
1384
|
}
|
|
1153
1385
|
/**
|
|
@@ -1230,13 +1462,25 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1230
1462
|
return getExtendLeaseFromWithdrawalInstructionAsync({ ...wBase, years: args.years }, { programAddress: this.arnsProgram });
|
|
1231
1463
|
return getIncreaseUndernameLimitFromWithdrawalInstructionAsync({ ...wBase, quantity: args.quantity }, { programAddress: this.arnsProgram });
|
|
1232
1464
|
}
|
|
1233
|
-
if (args.params.fundFrom === 'plan' ||
|
|
1465
|
+
if (args.params.fundFrom === 'plan' ||
|
|
1466
|
+
args.params.fundFrom === 'any' ||
|
|
1467
|
+
args.params.fundFrom === 'stakes' ||
|
|
1468
|
+
args.params.fundFrom === 'withdrawal') {
|
|
1469
|
+
// 'stakes'/'withdrawal' without an explicit gatewayAddress/withdrawalId
|
|
1470
|
+
// route here (the single-source branches above handle the explicit
|
|
1471
|
+
// case). The planner constrains sources to the chosen mode and never
|
|
1472
|
+
// spends liquid balance.
|
|
1234
1473
|
// Cost estimation for manage variants: each operation has its own
|
|
1235
1474
|
// pricing path. Keep it pragmatic — let the planner build the plan
|
|
1236
1475
|
// around the user's desired total (caller can pass explicit sources
|
|
1237
1476
|
// to bypass cost estimation entirely).
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1477
|
+
const intentMap = {
|
|
1478
|
+
upgrade: CostIntent.UpgradeName,
|
|
1479
|
+
extend: CostIntent.ExtendLease,
|
|
1480
|
+
increaseUndername: CostIntent.IncreaseUndernameLimit,
|
|
1481
|
+
};
|
|
1482
|
+
const cost = await this._simulateTokenCost({
|
|
1483
|
+
intent: intentMap[args.operation],
|
|
1240
1484
|
name: args.params.name,
|
|
1241
1485
|
years: args.years,
|
|
1242
1486
|
quantity: args.quantity,
|
|
@@ -1274,56 +1518,77 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1274
1518
|
}
|
|
1275
1519
|
throw new Error(`unsupported fundFrom mode '${args.params.fundFrom}' for ${args.operation}`);
|
|
1276
1520
|
}
|
|
1521
|
+
// =========================================
|
|
1522
|
+
// Primary name operations (ario-core)
|
|
1523
|
+
// =========================================
|
|
1277
1524
|
/**
|
|
1278
|
-
*
|
|
1279
|
-
*
|
|
1525
|
+
* If the signer already has a primary name set, build the instruction(s)
|
|
1526
|
+
* needed to remove it so they can be prepended to a request/set tx —
|
|
1527
|
+
* enabling single-tx "change primary name" flows.
|
|
1528
|
+
*
|
|
1529
|
+
* Returns an empty array when the signer has no existing primary name.
|
|
1530
|
+
*
|
|
1531
|
+
* Throws when the signer has a legacy primary-name state (forward
|
|
1532
|
+
* `PrimaryName` PDA exists but its paired `PrimaryNameReverse` PDA does
|
|
1533
|
+
* NOT). Both `remove_primary_name` AND `request_and_set_primary_name`
|
|
1534
|
+
* require the reverse PDA on-chain — the latter rejects with
|
|
1535
|
+
* `MustRemoveExistingPrimaryName` (0x1786, code 6022) any time a
|
|
1536
|
+
* forward record already exists for the signer, regardless of reverse
|
|
1537
|
+
* state. Silently skipping the remove would queue a tx guaranteed to
|
|
1538
|
+
* fail with that opaque error. Surfacing it at the client with a clear
|
|
1539
|
+
* remediation pointer is the only safe behavior.
|
|
1540
|
+
*
|
|
1541
|
+
* The legacy state should not exist on any cluster post-snapshot/import
|
|
1542
|
+
* PR #159 (which emits PrimaryNameReverse in lockstep with PrimaryName)
|
|
1543
|
+
* — it's a relic of pre-#159 imports. Operators on affected clusters
|
|
1544
|
+
* must run `yarn workspace @ar-io/migration-import backfill:primary-name-reverse`
|
|
1545
|
+
* (in the solana-ar-io repo) before this method can succeed.
|
|
1280
1546
|
*/
|
|
1281
|
-
async
|
|
1282
|
-
const [
|
|
1283
|
-
const
|
|
1547
|
+
async _buildRemoveExistingPrimaryNameIxs() {
|
|
1548
|
+
const [primaryNamePda] = await getPrimaryNamePDA(this.signer.address, this.coreProgram);
|
|
1549
|
+
const account = await fetchEncodedAccount(this.rpc, primaryNamePda, {
|
|
1284
1550
|
commitment: this.commitment,
|
|
1285
1551
|
});
|
|
1286
|
-
if (!
|
|
1287
|
-
|
|
1288
|
-
const
|
|
1289
|
-
const
|
|
1290
|
-
const
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1552
|
+
if (!account.exists)
|
|
1553
|
+
return [];
|
|
1554
|
+
const { name: oldName } = deserializePrimaryName(Buffer.from(account.data));
|
|
1555
|
+
const [primaryNameReversePda] = await getPrimaryNameReversePDA(oldName, this.coreProgram);
|
|
1556
|
+
const reverseAccount = await fetchEncodedAccount(this.rpc, primaryNameReversePda, { commitment: this.commitment });
|
|
1557
|
+
if (!reverseAccount.exists) {
|
|
1558
|
+
// Fail fast with an actionable message. See method docstring for
|
|
1559
|
+
// why request_and_set would reject this regardless.
|
|
1560
|
+
throw new Error(`Cannot change primary name: signer "${this.signer.address}" has a ` +
|
|
1561
|
+
`legacy PrimaryName ("${oldName}") with no paired PrimaryNameReverse PDA ` +
|
|
1562
|
+
`(${primaryNameReversePda}). The on-chain remove_primary_name and ` +
|
|
1563
|
+
`request_and_set_primary_name ixs both require the reverse PDA — ` +
|
|
1564
|
+
`request_and_set will reject with MustRemoveExistingPrimaryName (code 6022). ` +
|
|
1565
|
+
`Run \`yarn workspace @ar-io/migration-import backfill:primary-name-reverse\` ` +
|
|
1566
|
+
`against this cluster's ario-core program to materialize the missing reverse ` +
|
|
1567
|
+
`PDA, then retry.`);
|
|
1568
|
+
}
|
|
1569
|
+
return [
|
|
1570
|
+
await getRemovePrimaryNameInstructionAsync({
|
|
1571
|
+
primaryName: primaryNamePda,
|
|
1572
|
+
primaryNameReverse: primaryNameReversePda,
|
|
1573
|
+
owner: this.signer,
|
|
1574
|
+
reverseLookupHash: hashName(oldName),
|
|
1575
|
+
}, { programAddress: this.coreProgram }),
|
|
1576
|
+
];
|
|
1311
1577
|
}
|
|
1312
|
-
// =========================================
|
|
1313
|
-
// Primary name operations (ario-core)
|
|
1314
|
-
// =========================================
|
|
1315
1578
|
/**
|
|
1316
1579
|
* Build the `remaining_accounts` slice + the `antProgramId` arg the
|
|
1317
1580
|
* four ario-core primary-name instructions consume. Sprint 2/5
|
|
1318
1581
|
* reshape (ADR-016): ario-core no longer reads MPL Core asset bytes.
|
|
1319
|
-
* Authorization is "caller is the AntRecord
|
|
1320
|
-
*
|
|
1582
|
+
* Authorization is "caller is the effective AntRecord owner for this
|
|
1583
|
+
* name", resolved from the `AntRecord` + `AntConfig` PDAs (freshness-
|
|
1584
|
+
* gated against `AntConfig.last_known_owner` — see ario-core BD-097 /
|
|
1585
|
+
* BD-109). Both are program-PDA-pinned lookups.
|
|
1321
1586
|
*
|
|
1322
1587
|
* Layouts the on-chain handlers expect:
|
|
1323
1588
|
* request_primary_name: [arnsRecord, demandFactor]
|
|
1324
|
-
* request_and_set_primary_name: [arnsRecord, demandFactor, antRecord]
|
|
1325
|
-
* approve_primary_name: [arnsRecord, antRecord]
|
|
1326
|
-
* remove_primary_name_for_base_name: [arnsRecord, antRecord(@)]
|
|
1589
|
+
* request_and_set_primary_name: [arnsRecord, demandFactor, antRecord, antConfig]
|
|
1590
|
+
* approve_primary_name: [arnsRecord, antRecord, antConfig]
|
|
1591
|
+
* remove_primary_name_for_base_name: [arnsRecord, antRecord(@), antConfig]
|
|
1327
1592
|
*
|
|
1328
1593
|
* `antRecord` keys off the undername part for undernames (e.g.
|
|
1329
1594
|
* "blog_arweave" → AntRecord at "blog") or the canonical "@" sentinel
|
|
@@ -1333,10 +1598,13 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1333
1598
|
*
|
|
1334
1599
|
* `antProgram` honors ADR-016 / BD-100 pluggability: the asset's
|
|
1335
1600
|
* `ANT Program` Attributes-plugin trait selects which program owns the
|
|
1336
|
-
* AntRecord PDA. Absent / unparseable → canonical fallback.
|
|
1337
|
-
*
|
|
1338
|
-
*
|
|
1339
|
-
*
|
|
1601
|
+
* AntRecord PDA. Absent / unparseable → canonical fallback. The detected
|
|
1602
|
+
* trait is untrusted asset/RPC data, so it is honored only when it matches
|
|
1603
|
+
* the canonical program or this client's explicitly-configured
|
|
1604
|
+
* `this.antProgram`; any other value falls back to the configured program
|
|
1605
|
+
* (see the SECURITY note in the body). Both the PDA derivation here and the
|
|
1606
|
+
* `ant_program_id` arg the caller passes to the on-chain ix MUST agree (the
|
|
1607
|
+
* handler re-derives and rejects mismatches).
|
|
1340
1608
|
*/
|
|
1341
1609
|
async _buildPrimaryNameValidationAccounts(name, variant) {
|
|
1342
1610
|
const { isUndername, baseName, undername } = splitPrimaryName(name);
|
|
@@ -1364,10 +1632,26 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1364
1632
|
const arnsRecord = deserializeArnsRecord(Buffer.from(arnsAccount.data));
|
|
1365
1633
|
const antMint = address(arnsRecord.processId);
|
|
1366
1634
|
const { fetchAntProgramFromAsset } = await import('./mpl-core.js');
|
|
1635
|
+
const detected = await fetchAntProgramFromAsset(this.rpc, antMint, {
|
|
1636
|
+
commitment: this.commitment,
|
|
1637
|
+
});
|
|
1638
|
+
// SECURITY (BD-100 / SDK ANT-program auth finding): the asset's
|
|
1639
|
+
// `ANT Program` trait is untrusted asset/RPC data. Only honor a detected
|
|
1640
|
+
// value when it matches the canonical program or the program this client
|
|
1641
|
+
// was explicitly configured with (`this.antProgram`); otherwise fall back
|
|
1642
|
+
// to the configured program so a spoofed trait can't redirect the
|
|
1643
|
+
// AntRecord PDA derivation. This path only derives a READONLY validation
|
|
1644
|
+
// account (the instruction itself targets the canonical core program), so
|
|
1645
|
+
// the fallback is silent rather than a throw — but the gate keeps an
|
|
1646
|
+
// attacker from steering PDA derivation. Heterogeneous BYO-ANT primary
|
|
1647
|
+
// names (an asset on a non-configured program) await the contract-side
|
|
1648
|
+
// resolution of the `ant_program == ario_ant::ID` pin; see the
|
|
1649
|
+
// accompanying security note.
|
|
1367
1650
|
antProgram =
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1651
|
+
detected !== null &&
|
|
1652
|
+
(detected === ARIO_ANT_PROGRAM_ID || detected === this.antProgram)
|
|
1653
|
+
? detected
|
|
1654
|
+
: this.antProgram;
|
|
1371
1655
|
// removeForBaseName always uses the "@" undername (the base-name
|
|
1372
1656
|
// owner's record). The other ANT-auth variants use the undername
|
|
1373
1657
|
// part if the primary name is an undername.
|
|
@@ -1376,10 +1660,24 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1376
1660
|
: undername;
|
|
1377
1661
|
const [antRecordPda] = await getAntRecordPDA(antMint, antUndername, antProgram);
|
|
1378
1662
|
remaining.push({ address: antRecordPda, role: AccountRole.READONLY });
|
|
1663
|
+
// AntConfig PDA (ANT-level owner snapshot). ario-core reads
|
|
1664
|
+
// `AntConfig.last_known_owner` as the implicit-owner source and to
|
|
1665
|
+
// freshness-gate the per-record `AntRecord.owner` delegate (BD-097 /
|
|
1666
|
+
// BD-109). Derived under the SAME resolved `antProgram` as the
|
|
1667
|
+
// AntRecord above. Required trailing account for all three ANT-auth
|
|
1668
|
+
// variants (and the funding-plan variant, whose validation_account_count
|
|
1669
|
+
// is derived from this array's length downstream).
|
|
1670
|
+
const [antConfigPda] = await getAntConfigPDA(antMint, antProgram);
|
|
1671
|
+
remaining.push({ address: antConfigPda, role: AccountRole.READONLY });
|
|
1379
1672
|
}
|
|
1380
1673
|
return { remaining, antProgram };
|
|
1381
1674
|
}
|
|
1382
1675
|
async requestPrimaryName(params, _options) {
|
|
1676
|
+
// If the caller already has a primary name, prepend remove ixs so
|
|
1677
|
+
// the on-chain handler doesn't reject with MustRemoveExistingPrimaryName.
|
|
1678
|
+
const removeIxs = await this._buildRemoveExistingPrimaryNameIxs();
|
|
1679
|
+
const { baseName } = splitPrimaryName(params.name);
|
|
1680
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(baseName);
|
|
1383
1681
|
const coreConfig = await this.getCoreConfig();
|
|
1384
1682
|
const signerATA = await getAssociatedTokenAddressKit(coreConfig.mint, this.signer.address);
|
|
1385
1683
|
const { remaining } = await this._buildPrimaryNameValidationAccounts(params.name, 'request');
|
|
@@ -1405,13 +1703,18 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1405
1703
|
operation: 'request',
|
|
1406
1704
|
});
|
|
1407
1705
|
}
|
|
1408
|
-
const sig = await this.sendTransaction([ix]);
|
|
1706
|
+
const sig = await this.sendTransaction([...removeIxs, ...migrateIxs, ix]);
|
|
1409
1707
|
return { id: sig };
|
|
1410
1708
|
}
|
|
1411
1709
|
async setPrimaryName(params, _options) {
|
|
1412
1710
|
// setPrimaryName routes to the on-chain `request_and_set_primary_name`
|
|
1413
1711
|
// path — the auto-approve flow when the caller owns the AntRecord
|
|
1414
1712
|
// for the matching name (undername part, or "@" for base names).
|
|
1713
|
+
// If the caller already has a primary name, prepend remove ixs so
|
|
1714
|
+
// the "change" is atomic in a single transaction.
|
|
1715
|
+
const removeIxs = await this._buildRemoveExistingPrimaryNameIxs();
|
|
1716
|
+
const { baseName } = splitPrimaryName(params.name);
|
|
1717
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(baseName);
|
|
1415
1718
|
const coreConfig = await this.getCoreConfig();
|
|
1416
1719
|
const signerATA = await getAssociatedTokenAddressKit(coreConfig.mint, this.signer.address);
|
|
1417
1720
|
const { remaining, antProgram } = await this._buildPrimaryNameValidationAccounts(params.name, 'requestAndSet');
|
|
@@ -1437,7 +1740,7 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1437
1740
|
antProgramId: antProgram,
|
|
1438
1741
|
});
|
|
1439
1742
|
}
|
|
1440
|
-
const sig = await this.sendTransaction([ix]);
|
|
1743
|
+
const sig = await this.sendTransaction([...removeIxs, ...migrateIxs, ix]);
|
|
1441
1744
|
return { id: sig };
|
|
1442
1745
|
}
|
|
1443
1746
|
/**
|
|
@@ -1454,19 +1757,10 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1454
1757
|
* funding-source slice to ario-gar's pay_from_funding_plan via CPI.
|
|
1455
1758
|
*/
|
|
1456
1759
|
async _buildPrimaryNameFromFundingPlanIx(args) {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
const dfAccount = await fetchEncodedAccount(this.rpc, demandFactorPda, {
|
|
1461
|
-
commitment: this.commitment,
|
|
1760
|
+
const fee = await this._simulateTokenCost({
|
|
1761
|
+
intent: CostIntent.PrimaryNameRequest,
|
|
1762
|
+
name: args.params.name,
|
|
1462
1763
|
});
|
|
1463
|
-
if (!dfAccount.exists)
|
|
1464
|
-
throw new Error('DemandFactor not found');
|
|
1465
|
-
const dv = new DataView(dfAccount.data.buffer, dfAccount.data.byteOffset, dfAccount.data.byteLength);
|
|
1466
|
-
const demandFactor = dv.getBigUint64(8, true);
|
|
1467
|
-
const PRIMARY_NAME_REQUEST_BASE_FEE = 200000n; // 0.2 ARIO in mARIO
|
|
1468
|
-
const SCALE = 1000000n;
|
|
1469
|
-
const fee = (PRIMARY_NAME_REQUEST_BASE_FEE * demandFactor) / SCALE;
|
|
1470
1764
|
const plan = await this._resolveFundingPlan(args.params, fee);
|
|
1471
1765
|
const garConfig = await this.getGarConfig();
|
|
1472
1766
|
const [garSettings] = await getGarSettingsPDA(this.garProgram);
|
|
@@ -1522,14 +1816,24 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1522
1816
|
*
|
|
1523
1817
|
* Mirrors the on-chain `approve_primary_name` instruction
|
|
1524
1818
|
* (`programs/ario-core/src/instructions/primary_name.rs`).
|
|
1525
|
-
* remaining_accounts: [arns_record(base), ant_record(undername | @)].
|
|
1819
|
+
* remaining_accounts: [arns_record(base), ant_record(undername | @), ant_config].
|
|
1526
1820
|
*/
|
|
1527
1821
|
async approvePrimaryName(params, _options) {
|
|
1822
|
+
const { baseName } = splitPrimaryName(params.name);
|
|
1823
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(baseName);
|
|
1528
1824
|
const [requestPda] = await getPrimaryNameRequestPDA(params.initiator, this.coreProgram);
|
|
1529
1825
|
const [primaryNamePda] = await getPrimaryNamePDA(params.initiator, this.coreProgram);
|
|
1530
1826
|
const [primaryNameReversePda] = await getPrimaryNameReversePDA(params.name, this.coreProgram);
|
|
1531
1827
|
const { remaining, antProgram } = await this._buildPrimaryNameValidationAccounts(params.name, 'approve');
|
|
1532
|
-
|
|
1828
|
+
// withCoreDefaults injects `config` as the ArioConfig PDA derived against
|
|
1829
|
+
// *this.coreProgram*. Without it, Codama's `findConfigPda()` fallback
|
|
1830
|
+
// resolves to the source-pinned `ARioCoreProgramXXXX...` placeholder
|
|
1831
|
+
// program id (declare_id! literal pre-anchor-keys-sync), which on any
|
|
1832
|
+
// non-mainnet deployment produces an unallocated PDA → Anchor #3012
|
|
1833
|
+
// AccountNotInitialized on `config`. requestPrimaryName /
|
|
1834
|
+
// requestAndSetPrimaryName already use withCoreDefaults; this was the
|
|
1835
|
+
// last setPrimaryName-family entrypoint missing it.
|
|
1836
|
+
const ix = withRemainingAccounts(await getApprovePrimaryNameInstructionAsync(await this.withCoreDefaults({
|
|
1533
1837
|
request: requestPda,
|
|
1534
1838
|
initiator: params.initiator,
|
|
1535
1839
|
primaryName: primaryNamePda,
|
|
@@ -1537,8 +1841,8 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1537
1841
|
nameOwner: this.signer,
|
|
1538
1842
|
reverseLookupHash: hashName(params.name),
|
|
1539
1843
|
antProgramId: antProgram,
|
|
1540
|
-
}, { programAddress: this.coreProgram }), remaining);
|
|
1541
|
-
const sig = await this.sendTransaction([ix]);
|
|
1844
|
+
}), { programAddress: this.coreProgram }), remaining);
|
|
1845
|
+
const sig = await this.sendTransaction([...migrateIxs, ix]);
|
|
1542
1846
|
return { id: sig };
|
|
1543
1847
|
}
|
|
1544
1848
|
// =========================================
|
|
@@ -1621,6 +1925,47 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1621
1925
|
return { id: sig };
|
|
1622
1926
|
}
|
|
1623
1927
|
// =========================================
|
|
1928
|
+
// Claim delegation from gateway with delegation DISABLED (ario-gar, Fix #6)
|
|
1929
|
+
// =========================================
|
|
1930
|
+
/**
|
|
1931
|
+
* Claim a delegate's stake out of a gateway that has DISABLED delegation
|
|
1932
|
+
* (`allow_delegated_staking == false`), moving it into the delegate's own
|
|
1933
|
+
* withdrawal vault (WP §6.3 / Fix #6). This is the disabled-gateway analog of
|
|
1934
|
+
* {@link claimDelegateFromLeavingGateway}: the on-chain instruction is
|
|
1935
|
+
* permissionless, so a cranker can sweep delegates out (the operator cannot
|
|
1936
|
+
* re-enable delegation until `total_delegated_stake == 0` and the cooldown
|
|
1937
|
+
* elapses). The withdrawal-counter and withdrawal PDAs are seeded by the
|
|
1938
|
+
* DELEGATOR, so a cranker must pass that delegate's `delegatorAddress`.
|
|
1939
|
+
*
|
|
1940
|
+
* @param params.gatewayAddress The gateway whose delegation was disabled.
|
|
1941
|
+
* @param params.delegatorAddress The delegate to claim for. Defaults to the
|
|
1942
|
+
* signer (self-claim). Pass another address to crank on a delegate's behalf;
|
|
1943
|
+
* the signer covers rent (`payer`) but stake still routes to the delegate's
|
|
1944
|
+
* own vault (the delegator key is bound by the delegation PDA seeds).
|
|
1945
|
+
*/
|
|
1946
|
+
async claimDelegateFromDisabledGateway(params, _options) {
|
|
1947
|
+
const gateway = address(params.gatewayAddress);
|
|
1948
|
+
const delegator = params.delegatorAddress
|
|
1949
|
+
? address(params.delegatorAddress)
|
|
1950
|
+
: this.signer.address;
|
|
1951
|
+
const [gatewayPda] = await getGatewayPDA(gateway, this.garProgram);
|
|
1952
|
+
const [delegationPda] = await getDelegationPDA(gateway, delegator, this.garProgram);
|
|
1953
|
+
// Withdrawal counter + vault are PDA-seeded by the delegator, not the payer.
|
|
1954
|
+
const nextId = await this.getNextWithdrawalId(delegator);
|
|
1955
|
+
const [withdrawalPda] = await getWithdrawalPDA(delegator, nextId, this.garProgram);
|
|
1956
|
+
const ix = await getClaimDelegateFromDisabledGatewayInstructionAsync({
|
|
1957
|
+
gateway: gatewayPda,
|
|
1958
|
+
delegation: delegationPda,
|
|
1959
|
+
withdrawal: withdrawalPda,
|
|
1960
|
+
// `delegator` is an unsigned seeds-derivation key; `payer` (the signer)
|
|
1961
|
+
// covers rent on the init_if_needed counter + the new withdrawal.
|
|
1962
|
+
delegator,
|
|
1963
|
+
payer: this.signer,
|
|
1964
|
+
}, { programAddress: this.garProgram });
|
|
1965
|
+
const sig = await this.sendTransaction([ix], 1_000_000);
|
|
1966
|
+
return { id: sig };
|
|
1967
|
+
}
|
|
1968
|
+
// =========================================
|
|
1624
1969
|
// Delegation allowlist (ario-gar)
|
|
1625
1970
|
// =========================================
|
|
1626
1971
|
/** Add an address to the gateway's delegation allowlist. */
|
|
@@ -1683,10 +2028,54 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1683
2028
|
years: params.years ?? 1,
|
|
1684
2029
|
ant: antPubkey,
|
|
1685
2030
|
};
|
|
2031
|
+
// Returned-name price is a per-slot-decaying Dutch auction, so the
|
|
2032
|
+
// multi-source funding plan (which pre-commits exact source amounts) can't
|
|
2033
|
+
// match the execution-time cost → FundingPlanAmountMismatch (#6066). Prefer
|
|
2034
|
+
// a single-source stake path: it carries no amount, so the program computes
|
|
2035
|
+
// and draws the live cost itself. When the caller asked to fund from
|
|
2036
|
+
// stakes/withdrawal/any without naming a specific gateway/vault,
|
|
2037
|
+
// auto-resolve a single source with enough stake to cover the
|
|
2038
|
+
// (premium-inclusive) cost.
|
|
2039
|
+
let resolvedGateway = params.gatewayAddress;
|
|
2040
|
+
let resolvedFundAsOperator = params.fundAsOperator ?? false;
|
|
2041
|
+
let resolvedWithdrawalId = params.withdrawalId;
|
|
2042
|
+
const wantsStake = params.fundFrom === 'stakes' ||
|
|
2043
|
+
params.fundFrom === 'withdrawal' ||
|
|
2044
|
+
params.fundFrom === 'any';
|
|
2045
|
+
if (wantsStake &&
|
|
2046
|
+
resolvedGateway === undefined &&
|
|
2047
|
+
resolvedWithdrawalId === undefined &&
|
|
2048
|
+
!params.sources?.length) {
|
|
2049
|
+
const picked = await this._autoPickReturnedNameStakeSource(params);
|
|
2050
|
+
if (picked?.kind === 'delegation') {
|
|
2051
|
+
resolvedGateway = picked.gateway;
|
|
2052
|
+
resolvedFundAsOperator = false;
|
|
2053
|
+
}
|
|
2054
|
+
else if (picked?.kind === 'operatorStake') {
|
|
2055
|
+
resolvedGateway = picked.gateway;
|
|
2056
|
+
resolvedFundAsOperator = true;
|
|
2057
|
+
}
|
|
2058
|
+
else if (picked?.kind === 'withdrawal') {
|
|
2059
|
+
resolvedWithdrawalId = picked.withdrawalId;
|
|
2060
|
+
}
|
|
2061
|
+
else if (params.fundFrom !== 'any') {
|
|
2062
|
+
// 'stakes'/'withdrawal' explicitly requested but nothing covers it.
|
|
2063
|
+
throw new Error(`buyReturnedName: no ${params.fundFrom === 'withdrawal'
|
|
2064
|
+
? 'matured withdrawal vault'
|
|
2065
|
+
: 'delegation/operator stake'} large enough to fund '${params.name}' was found for ` +
|
|
2066
|
+
`${this.signer.address}. Fund from balance, or add stake first.`);
|
|
2067
|
+
}
|
|
2068
|
+
// 'any' with nothing found → falls through to the balance path.
|
|
2069
|
+
}
|
|
1686
2070
|
let ix;
|
|
1687
|
-
|
|
2071
|
+
const useBalance = !params.fundFrom ||
|
|
1688
2072
|
params.fundFrom === 'balance' ||
|
|
1689
|
-
params.fundFrom === 'turbo'
|
|
2073
|
+
params.fundFrom === 'turbo' ||
|
|
2074
|
+
(params.fundFrom === 'any' &&
|
|
2075
|
+
resolvedGateway === undefined &&
|
|
2076
|
+
resolvedWithdrawalId === undefined &&
|
|
2077
|
+
!params.sources?.length);
|
|
2078
|
+
if (useBalance) {
|
|
1690
2079
|
ix = await getBuyReturnedNameInstructionAsync(await this.withArnsDefaults({
|
|
1691
2080
|
arnsRecord,
|
|
1692
2081
|
returnedName: returnedNamePda,
|
|
@@ -1715,10 +2104,10 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1715
2104
|
garProgram: this.garProgram,
|
|
1716
2105
|
params: buyParams,
|
|
1717
2106
|
};
|
|
1718
|
-
if (
|
|
1719
|
-
const gatewayAddr = address(
|
|
2107
|
+
if (resolvedGateway !== undefined) {
|
|
2108
|
+
const gatewayAddr = address(resolvedGateway);
|
|
1720
2109
|
const [gatewayPda] = await getGatewayPDA(gatewayAddr, this.garProgram);
|
|
1721
|
-
if (
|
|
2110
|
+
if (resolvedFundAsOperator) {
|
|
1722
2111
|
ix = await getBuyReturnedNameFromOperatorStakeInstructionAsync({ ...sharedReturnedBase, gateway: gatewayPda }, { programAddress: this.arnsProgram });
|
|
1723
2112
|
}
|
|
1724
2113
|
else {
|
|
@@ -1730,21 +2119,21 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1730
2119
|
}, { programAddress: this.arnsProgram });
|
|
1731
2120
|
}
|
|
1732
2121
|
}
|
|
1733
|
-
else if (
|
|
1734
|
-
|
|
1735
|
-
const [withdrawalPda] = await getWithdrawalPDA(this.signer.address, params.withdrawalId, this.garProgram);
|
|
2122
|
+
else if (resolvedWithdrawalId !== undefined) {
|
|
2123
|
+
const [withdrawalPda] = await getWithdrawalPDA(this.signer.address, resolvedWithdrawalId, this.garProgram);
|
|
1736
2124
|
ix = await getBuyReturnedNameFromWithdrawalInstructionAsync({ ...sharedReturnedBase, withdrawal: withdrawalPda }, { programAddress: this.arnsProgram });
|
|
1737
2125
|
}
|
|
1738
|
-
else if (params.fundFrom === 'plan'
|
|
1739
|
-
//
|
|
1740
|
-
//
|
|
1741
|
-
//
|
|
1742
|
-
//
|
|
1743
|
-
//
|
|
1744
|
-
const cost = await this.
|
|
2126
|
+
else if (params.fundFrom === 'plan' && params.sources?.length) {
|
|
2127
|
+
// Explicit caller-supplied plan only: the caller owns the source
|
|
2128
|
+
// amounts and accepts the decay risk (the price moves per slot, so a
|
|
2129
|
+
// stale plan trips FundingPlanAmountMismatch). We do NOT auto-discover
|
|
2130
|
+
// a multi-source plan for returned names — see the single-source note
|
|
2131
|
+
// above.
|
|
2132
|
+
const cost = await this._simulateTokenCost({
|
|
2133
|
+
intent: CostIntent.BuyName,
|
|
1745
2134
|
name: params.name,
|
|
1746
|
-
purchaseType: buyParams.purchaseType,
|
|
1747
2135
|
years: buyParams.years,
|
|
2136
|
+
purchaseType: buyParams.purchaseType,
|
|
1748
2137
|
});
|
|
1749
2138
|
const plan = await this._resolveFundingPlan(params, cost);
|
|
1750
2139
|
const { remainingAccounts, withdrawalCounter, residueVaultCount } = await this._materializeFundingPlan(params, plan);
|
|
@@ -1763,54 +2152,108 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1763
2152
|
throw new Error(`unsupported fundFrom mode '${params.fundFrom}' for buyReturnedName`);
|
|
1764
2153
|
}
|
|
1765
2154
|
}
|
|
2155
|
+
// The on-chain `buy_returned_name*` handlers take `initiator_token_account`
|
|
2156
|
+
// and `buyer_token_account` as `Account<TokenAccount>` (NOT `init`), so
|
|
2157
|
+
// Anchor requires both ATAs to already exist or fails with
|
|
2158
|
+
// AccountNotInitialized (#3012). The original initiator may never have held
|
|
2159
|
+
// ARIO, and the premium always settles from the buyer's liquid ATA — bundle
|
|
2160
|
+
// idempotent ATA creates so the buy succeeds without a separate setup step
|
|
2161
|
+
// (mirrors the vault-ATA handling above). Idempotent: ~1500 CU each, no-op
|
|
2162
|
+
// when the account already exists.
|
|
2163
|
+
const createInitiatorAtaIx = buildCreateAtaIdempotentIx(this.signer.address, initiatorATA, initiator, arnsConfig.mint);
|
|
2164
|
+
const createBuyerAtaIx = buildCreateAtaIdempotentIx(this.signer.address, buyerATA, this.signer.address, arnsConfig.mint);
|
|
1766
2165
|
// Sprint 4 / ADR-016: bundle ant.sync_attributes after the buy so the
|
|
1767
2166
|
// Attributes plugin reflects the new record holder. assetOverride =
|
|
1768
2167
|
// antPubkey because the ArnsRecord PDA is created by buy_returned_name
|
|
1769
2168
|
// and doesn't exist on-chain at SDK build time.
|
|
1770
2169
|
const syncIx = await this._buildSyncAttributesIxIfOwner(params.name, antPubkey);
|
|
1771
|
-
const sig = await this.sendTransaction(
|
|
2170
|
+
const sig = await this.sendTransaction([
|
|
2171
|
+
createBuyerAtaIx,
|
|
2172
|
+
createInitiatorAtaIx,
|
|
2173
|
+
ix,
|
|
2174
|
+
...(syncIx ? [syncIx] : []),
|
|
2175
|
+
]);
|
|
1772
2176
|
return { id: sig };
|
|
1773
2177
|
}
|
|
2178
|
+
/**
|
|
2179
|
+
* Pick a single stake-derived funding source that can cover a returned-name
|
|
2180
|
+
* purchase, for the single-source `buy_returned_name_from_*` paths.
|
|
2181
|
+
*
|
|
2182
|
+
* Returned-name prices decay per slot, so the multi-source funding plan
|
|
2183
|
+
* (which pre-commits exact amounts) can't match the execution-time cost. The
|
|
2184
|
+
* single-source paths carry no amount — the program draws the live cost — so
|
|
2185
|
+
* we only need to pick ONE source with enough stake. We size the pick against
|
|
2186
|
+
* the premium-inclusive estimate (an upper bound, since the price only falls
|
|
2187
|
+
* from now) and choose the largest matching source. Returns `null` when no
|
|
2188
|
+
* single source covers the estimate.
|
|
2189
|
+
*/
|
|
2190
|
+
async _autoPickReturnedNameStakeSource(params) {
|
|
2191
|
+
const estimate = BigInt(Math.ceil(await this.getTokenCost({
|
|
2192
|
+
intent: 'Buy-Name',
|
|
2193
|
+
name: params.name,
|
|
2194
|
+
type: params.type,
|
|
2195
|
+
years: params.years ?? 1,
|
|
2196
|
+
})));
|
|
2197
|
+
const arnsConfig = await this.getArnsConfig();
|
|
2198
|
+
const { discoverFundingSources } = await import('./funding-plan.js');
|
|
2199
|
+
const sources = await discoverFundingSources(this.rpc, this.signer.address, { arioMint: arnsConfig.mint, garProgram: this.garProgram });
|
|
2200
|
+
// 'withdrawal' mode → matured withdrawal vaults only; otherwise prefer
|
|
2201
|
+
// operator stake when the caller asked, else a delegation.
|
|
2202
|
+
const wantKind = params.fundFrom === 'withdrawal'
|
|
2203
|
+
? 'withdrawal'
|
|
2204
|
+
: params.fundAsOperator === true
|
|
2205
|
+
? 'operatorStake'
|
|
2206
|
+
: 'delegation';
|
|
2207
|
+
const candidates = sources
|
|
2208
|
+
.filter((s) => s.kind === wantKind && s.available >= estimate)
|
|
2209
|
+
.sort((a, b) => b.available > a.available ? 1 : b.available < a.available ? -1 : 0);
|
|
2210
|
+
return candidates[0] ?? null;
|
|
2211
|
+
}
|
|
1774
2212
|
// =========================================
|
|
1775
2213
|
// Name management (ario-arns)
|
|
1776
2214
|
// =========================================
|
|
1777
2215
|
/** Reassign an ArNS name to a different ANT. */
|
|
1778
2216
|
async reassignName(params, _options) {
|
|
2217
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(params.name);
|
|
1779
2218
|
const newAnt = address(params.processId);
|
|
1780
2219
|
const [arnsRecord] = await getArnsRecordPDA(params.name, this.arnsProgram);
|
|
2220
|
+
const record = await this.getArNSRecord({ name: params.name });
|
|
2221
|
+
const antAsset = address(record.processId);
|
|
1781
2222
|
const ix = await getReassignNameInstructionAsync(await this.withArnsDefaults({
|
|
1782
2223
|
arnsRecord,
|
|
2224
|
+
antAsset,
|
|
1783
2225
|
caller: this.signer,
|
|
1784
2226
|
newAnt,
|
|
1785
2227
|
}), { programAddress: this.arnsProgram });
|
|
1786
|
-
//
|
|
1787
|
-
//
|
|
1788
|
-
//
|
|
1789
|
-
// the
|
|
1790
|
-
//
|
|
1791
|
-
//
|
|
1792
|
-
//
|
|
1793
|
-
//
|
|
1794
|
-
//
|
|
1795
|
-
// OLD asset, and fail the post-reassign `record.ant == asset.key()`
|
|
1796
|
-
// check. The owner-check inside _buildSyncAttributesIxIfOwner runs
|
|
1797
|
-
// against `newAnt`, so the bundle fires only when the reassign
|
|
1798
|
-
// caller is also the new ANT's holder; otherwise the ix is sent
|
|
1799
|
-
// alone and the new owner runs `syncAttributes()` later (BD-095/096).
|
|
2228
|
+
// Post-reassign the record points at `newAnt`. The bundled
|
|
2229
|
+
// `sync_attributes` MUST target `newAnt` — without the override, the
|
|
2230
|
+
// helper would read the on-chain record at SDK build time (still
|
|
2231
|
+
// pointing at the OLD asset), build a sync ix for the OLD asset, and
|
|
2232
|
+
// fail the post-reassign `record.ant == asset.key()` check. The
|
|
2233
|
+
// owner-check inside _buildSyncAttributesIxIfOwner runs against
|
|
2234
|
+
// `newAnt`, so the bundle fires only when the reassign caller is also
|
|
2235
|
+
// the new ANT's holder; otherwise the ix is sent alone and the new
|
|
2236
|
+
// owner runs `syncAttributes()` later (BD-095/096).
|
|
1800
2237
|
const syncIx = await this._buildSyncAttributesIxIfOwner(params.name, newAnt);
|
|
1801
2238
|
const reassignWithMetas = withRemainingAccounts(ix, [
|
|
1802
2239
|
{ address: newAnt, role: AccountRole.READONLY },
|
|
1803
2240
|
]);
|
|
1804
|
-
const sig = await this.sendTransaction(syncIx
|
|
2241
|
+
const sig = await this.sendTransaction(syncIx
|
|
2242
|
+
? [...migrateIxs, reassignWithMetas, syncIx]
|
|
2243
|
+
: [...migrateIxs, reassignWithMetas]);
|
|
1805
2244
|
return { id: sig };
|
|
1806
2245
|
}
|
|
1807
2246
|
/** Release a permabuy name back to the registry (creates a returned name auction). */
|
|
1808
2247
|
async releaseName(params, _options) {
|
|
2248
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(params.name);
|
|
1809
2249
|
const [returnedNamePda] = await getReturnedNamePDA(params.name, this.arnsProgram);
|
|
1810
2250
|
const [arnsRecord] = await getArnsRecordPDA(params.name, this.arnsProgram);
|
|
2251
|
+
const record = await this.getArNSRecord({ name: params.name });
|
|
2252
|
+
const antAsset = address(record.processId);
|
|
1811
2253
|
const ix = await getReleaseNameInstructionAsync(await this.withArnsDefaults({
|
|
1812
2254
|
arnsRecord,
|
|
1813
2255
|
returnedName: returnedNamePda,
|
|
2256
|
+
antAsset,
|
|
1814
2257
|
caller: this.signer,
|
|
1815
2258
|
}), { programAddress: this.arnsProgram });
|
|
1816
2259
|
// Note: no sync_attributes bundle here — release_name closes the
|
|
@@ -1818,9 +2261,69 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1818
2261
|
// asset's stale traits remain pointing at the released name; off-chain
|
|
1819
2262
|
// resolvers should treat ArnsRecord as the source of truth and ignore
|
|
1820
2263
|
// a "ArNS Name" trait that no longer resolves.
|
|
2264
|
+
const sig = await this.sendTransaction([...migrateIxs, ix]);
|
|
2265
|
+
return { id: sig };
|
|
2266
|
+
}
|
|
2267
|
+
// =========================================
|
|
2268
|
+
// Lazy-state crank steps — materialize accumulator/period state.
|
|
2269
|
+
// Both are permissionless + idempotent (safe to crank on a schedule).
|
|
2270
|
+
// =========================================
|
|
2271
|
+
/**
|
|
2272
|
+
* Roll the demand factor forward to the current period. Permissionless and
|
|
2273
|
+
* idempotent — a no-op within the same period. Pricing already rolls the
|
|
2274
|
+
* factor inline on every buy/extend, so this only refreshes the STORED
|
|
2275
|
+
* factor that `getDemandFactor` and between-buy price previews read; a
|
|
2276
|
+
* periodic crank (~once per 24h `PERIOD_LENGTH_SECONDS`) keeps it current.
|
|
2277
|
+
*/
|
|
2278
|
+
async updateDemandFactor(_options) {
|
|
2279
|
+
const [demandFactorPda] = await getDemandFactorPDA(this.arnsProgram);
|
|
2280
|
+
const ix = getUpdateDemandFactorInstruction({ demandFactor: demandFactorPda, payer: this.signer }, { programAddress: this.arnsProgram });
|
|
1821
2281
|
const sig = await this.sendTransaction([ix]);
|
|
1822
2282
|
return { id: sig };
|
|
1823
2283
|
}
|
|
2284
|
+
/**
|
|
2285
|
+
* Materialize a single delegate's pending rewards into their delegated
|
|
2286
|
+
* stake by settling the gateway's reward-per-share accumulator.
|
|
2287
|
+
* Permissionless — there is no signer beyond the fee payer; `delegator` is
|
|
2288
|
+
* only a PDA-derivation seed. Rewards always accrue correctly in the
|
|
2289
|
+
* accumulator regardless of this call; compounding makes the on-chain
|
|
2290
|
+
* `delegatedStake` reflect them (and earn compound interest in the next
|
|
2291
|
+
* epoch's weighting). Idempotent — a no-op once already settled.
|
|
2292
|
+
*/
|
|
2293
|
+
async compoundDelegationRewards(params, _options) {
|
|
2294
|
+
const ix = await this.buildCompoundDelegationRewardsInstruction(params);
|
|
2295
|
+
const sig = await this.sendTransaction([ix]);
|
|
2296
|
+
return { id: sig };
|
|
2297
|
+
}
|
|
2298
|
+
/**
|
|
2299
|
+
* Compound many delegates' rewards in a SINGLE transaction — one
|
|
2300
|
+
* `compound_delegation_rewards` instruction per entry. Idempotent and
|
|
2301
|
+
* permissionless, so partial batches are safe to retry. Keep each batch
|
|
2302
|
+
* within the per-tx account/CU budget; grouping entries that share a gateway
|
|
2303
|
+
* lowers the unique-account count (the gateway account is reused across
|
|
2304
|
+
* instructions). Typical cranker usage: enumerate with
|
|
2305
|
+
* `SolanaARIOReadable.getDelegationsToCompound`, chunk, then call this.
|
|
2306
|
+
*/
|
|
2307
|
+
async compoundDelegationRewardsBatch(delegations, _options) {
|
|
2308
|
+
if (delegations.length === 0) {
|
|
2309
|
+
throw new Error('compoundDelegationRewardsBatch: delegations list is empty');
|
|
2310
|
+
}
|
|
2311
|
+
const ixs = await Promise.all(delegations.map((d) => this.buildCompoundDelegationRewardsInstruction(d)));
|
|
2312
|
+
const sig = await this.sendTransaction(ixs, 1_400_000);
|
|
2313
|
+
return { id: sig };
|
|
2314
|
+
}
|
|
2315
|
+
/**
|
|
2316
|
+
* Build a single `compound_delegation_rewards` instruction (shared by the
|
|
2317
|
+
* single + batch methods). PDAs are derived under the configured gar program
|
|
2318
|
+
* so the program-id override always targets the right cluster.
|
|
2319
|
+
*/
|
|
2320
|
+
async buildCompoundDelegationRewardsInstruction(params) {
|
|
2321
|
+
const gateway = address(params.gateway);
|
|
2322
|
+
const delegator = address(params.delegator);
|
|
2323
|
+
const [gatewayPda] = await getGatewayPDA(gateway, this.garProgram);
|
|
2324
|
+
const [delegationPda] = await getDelegationPDA(gateway, delegator, this.garProgram);
|
|
2325
|
+
return getCompoundDelegationRewardsInstruction({ gateway: gatewayPda, delegation: delegationPda, delegator }, { programAddress: this.garProgram });
|
|
2326
|
+
}
|
|
1824
2327
|
// =========================================
|
|
1825
2328
|
// Epoch cranking (ario-gar) — permissionless
|
|
1826
2329
|
// =========================================
|
|
@@ -1864,9 +2367,22 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1864
2367
|
}
|
|
1865
2368
|
/**
|
|
1866
2369
|
* Prescribe observers and names for an epoch. Permissionless — call after
|
|
1867
|
-
* weights are tallied.
|
|
1868
|
-
*
|
|
2370
|
+
* weights are tallied.
|
|
2371
|
+
*
|
|
2372
|
+
* `gatewayAccounts` MUST be the Gateway PDAs of the SELECTED observers only
|
|
2373
|
+
* — at most `epoch_settings.prescribed_observer_count` (≤50), NOT the whole
|
|
2374
|
+
* registry. The selection is computed on-chain; mirror it off-chain with
|
|
2375
|
+
* {@link predictPrescribedObservers} / {@link getPredictedObserverPDAs} to
|
|
2376
|
+
* learn the set. Passing every registry gateway (e.g. via
|
|
2377
|
+
* {@link getAllRegistryGatewayPDAs}) hits Solana's `MAX_TX_ACCOUNT_LOCKS = 64`
|
|
2378
|
+
* on large registries and the tx fails at pre-flight.
|
|
2379
|
+
*
|
|
2380
|
+
* The selected PDAs are appended as `remaining_accounts`, followed by the
|
|
2381
|
+
* optional `nameRegistryAccount` (must be LAST) which enables the name
|
|
1869
2382
|
* prescription leg.
|
|
2383
|
+
*
|
|
2384
|
+
* If a selected gateway leaves between prediction and tx landing, the tx
|
|
2385
|
+
* fails with `InvalidGatewayAccount` — retry once with a fresh prediction.
|
|
1870
2386
|
*/
|
|
1871
2387
|
async prescribeEpoch(params, _options) {
|
|
1872
2388
|
const ix = await getPrescribeEpochInstructionAsync(await this.withGarDefaults({
|
|
@@ -1883,7 +2399,28 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1883
2399
|
role: AccountRole.READONLY,
|
|
1884
2400
|
});
|
|
1885
2401
|
}
|
|
1886
|
-
const
|
|
2402
|
+
const fullIx = withRemainingAccounts(ix, remaining);
|
|
2403
|
+
// A prescribe tx with the selected observer set (~50 PDAs) exceeds Solana's
|
|
2404
|
+
// 1232-byte limit once there are more than ~24 remaining accounts, so route
|
|
2405
|
+
// those through an ephemeral Address Lookup Table (create → extend →
|
|
2406
|
+
// compressed v0 tx). Small sets (sparse testnets) take the cheaper inline
|
|
2407
|
+
// path. `prescribe_epoch` searches `remaining_accounts` by PDA, so serving
|
|
2408
|
+
// them via the ALT (which preserves instruction account order) is
|
|
2409
|
+
// transparent — incl. NameRegistry staying last. Validated on staging
|
|
2410
|
+
// (667 gateways, 50 observers): 428k CU, name prescription intact.
|
|
2411
|
+
if (remaining.length > 24) {
|
|
2412
|
+
const id = await sendWithEphemeralLookupTable({
|
|
2413
|
+
rpc: this.rpc,
|
|
2414
|
+
rpcSubscriptions: this.rpcSubscriptions,
|
|
2415
|
+
signer: this.signer,
|
|
2416
|
+
instruction: fullIx,
|
|
2417
|
+
lookupAddresses: remaining.map((a) => a.address),
|
|
2418
|
+
commitment: this.commitment,
|
|
2419
|
+
computeUnitLimit: 1_000_000,
|
|
2420
|
+
});
|
|
2421
|
+
return { id };
|
|
2422
|
+
}
|
|
2423
|
+
const sig = await this.sendTransaction([fullIx], 1_000_000);
|
|
1887
2424
|
return { id: sig };
|
|
1888
2425
|
}
|
|
1889
2426
|
/**
|
|
@@ -1984,6 +2521,411 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
1984
2521
|
}
|
|
1985
2522
|
return pdas;
|
|
1986
2523
|
}
|
|
2524
|
+
/**
|
|
2525
|
+
* Predict the Gateway PDAs that `prescribe_epoch` will select as observers
|
|
2526
|
+
* for `epochIndex`, mirroring the on-chain weighted-roulette selection.
|
|
2527
|
+
*
|
|
2528
|
+
* Returns at most `epoch_settings.prescribed_observer_count` (≤50) PDAs
|
|
2529
|
+
* regardless of registry size — the set to pass as `gatewayAccounts` to
|
|
2530
|
+
* {@link prescribeEpoch}. This is the size-safe replacement for
|
|
2531
|
+
* {@link getAllRegistryGatewayPDAs} on the prescribe path (which oversupplies
|
|
2532
|
+
* and trips `MAX_TX_ACCOUNT_LOCKS = 64` on large registries).
|
|
2533
|
+
*
|
|
2534
|
+
* Reads three accounts (epoch, registry, epoch settings) at the configured
|
|
2535
|
+
* commitment so the prediction reflects live registry weights. If a selected
|
|
2536
|
+
* gateway races out before the tx lands, `prescribeEpoch` throws
|
|
2537
|
+
* `InvalidGatewayAccount` — re-call this and retry once.
|
|
2538
|
+
*/
|
|
2539
|
+
async getPredictedObserverPDAs(epochIndex) {
|
|
2540
|
+
// --- Epoch: hashchain (frozen entropy) + active_gateway_count (walk bound) ---
|
|
2541
|
+
const [epochPda] = await getEpochPDA(epochIndex, this.garProgram);
|
|
2542
|
+
const epochAccount = await fetchEncodedAccount(this.rpc, epochPda, {
|
|
2543
|
+
commitment: this.commitment,
|
|
2544
|
+
});
|
|
2545
|
+
if (!epochAccount.exists)
|
|
2546
|
+
throw new Error(`Epoch ${epochIndex} not found`);
|
|
2547
|
+
const epochData = Buffer.from(epochAccount.data);
|
|
2548
|
+
// After the 8-byte discriminator (see fetchEpochRawFields): 9×u64 = 72
|
|
2549
|
+
// bytes, then hashchain[32], then active_gateway_count(u32).
|
|
2550
|
+
const EPOCH_BASE = 8;
|
|
2551
|
+
const hashchain = epochData.subarray(EPOCH_BASE + 72, EPOCH_BASE + 72 + 32);
|
|
2552
|
+
const activeGatewayCount = epochData.readUInt32LE(EPOCH_BASE + 104);
|
|
2553
|
+
// --- Registry: slots[0..activeGatewayCount] (address + composite_weight) ---
|
|
2554
|
+
const [registryPda] = await getGatewayRegistryPDA(this.garProgram);
|
|
2555
|
+
const registryAccount = await fetchEncodedAccount(this.rpc, registryPda, {
|
|
2556
|
+
commitment: this.commitment,
|
|
2557
|
+
});
|
|
2558
|
+
if (!registryAccount.exists)
|
|
2559
|
+
throw new Error('GatewayRegistry not found');
|
|
2560
|
+
const registryData = Buffer.from(registryAccount.data);
|
|
2561
|
+
const registryCount = registryData.readUInt32LE(40); // 8 disc + 32 authority
|
|
2562
|
+
const SLOTS_OFFSET = 48; // 8 + 32 + 4 count + 4 pad
|
|
2563
|
+
const SLOT_STRIDE = 56; // address(32)+weight(8)+start_ts(8)+status(1)+pad(7)
|
|
2564
|
+
// Walk exactly the on-chain prefix. The roulette uses
|
|
2565
|
+
// registry.gateways[0..epoch.active_gateway_count]; include zero-weight
|
|
2566
|
+
// slots so the cumulative walk and weight sum match byte-for-byte.
|
|
2567
|
+
const walkCount = Math.min(activeGatewayCount, registryCount, 3000);
|
|
2568
|
+
const slots = [];
|
|
2569
|
+
for (let i = 0; i < walkCount; i++) {
|
|
2570
|
+
const slotOffset = SLOTS_OFFSET + i * SLOT_STRIDE;
|
|
2571
|
+
slots.push({
|
|
2572
|
+
address: addressDecoder.decode(registryData.subarray(slotOffset, slotOffset + 32)),
|
|
2573
|
+
compositeWeight: registryData.readBigUInt64LE(slotOffset + 32),
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
// --- Epoch settings: prescribed_observer_count ---
|
|
2577
|
+
const [epochSettingsPda] = await getEpochSettingsPDA(this.garProgram);
|
|
2578
|
+
const settingsAccount = await fetchEncodedAccount(this.rpc, epochSettingsPda, {
|
|
2579
|
+
commitment: this.commitment,
|
|
2580
|
+
});
|
|
2581
|
+
if (!settingsAccount.exists)
|
|
2582
|
+
throw new Error('EpochSettings not found');
|
|
2583
|
+
const settings = deserializeEpochSettingsFull(Buffer.from(settingsAccount.data));
|
|
2584
|
+
// --- Predict selected operators, then derive their Gateway PDAs ---
|
|
2585
|
+
const operators = predictPrescribedObservers(hashchain, slots, settings.prescribedObserverCount);
|
|
2586
|
+
const pdas = [];
|
|
2587
|
+
for (const operator of operators) {
|
|
2588
|
+
const [gatewayPda] = await getGatewayPDA(operator, this.garProgram);
|
|
2589
|
+
pdas.push(gatewayPda);
|
|
2590
|
+
}
|
|
2591
|
+
return pdas;
|
|
2592
|
+
}
|
|
2593
|
+
/**
|
|
2594
|
+
* Reclaim rent from the ephemeral Address Lookup Tables this signer created
|
|
2595
|
+
* for `prescribe_epoch` (see {@link sendWithEphemeralLookupTable}). Each
|
|
2596
|
+
* prescribe leaves a single-use table allocated (~0.0126 SOL); reclaiming
|
|
2597
|
+
* needs a deactivate → ~513-slot cooldown → close sequence, so it can't run
|
|
2598
|
+
* inline. Call this from a throttled/permissionless cleanup pass (cranker /
|
|
2599
|
+
* observer) to deactivate active tables and close cooled-down ones, refunding
|
|
2600
|
+
* the rent to the signer.
|
|
2601
|
+
*
|
|
2602
|
+
* Discovery reads the signer's transaction history (RPC-portable; the ALT
|
|
2603
|
+
* program can't be enumerated via `getProgramAccounts`). The GAR + ArNS
|
|
2604
|
+
* program IDs are passed as the entry-ownership fingerprint so only genuine
|
|
2605
|
+
* prescribe tables are touched. Best-effort: at most `maxTables` submissions
|
|
2606
|
+
* per call, scanning at most `scanLimit` recent signatures.
|
|
2607
|
+
*/
|
|
2608
|
+
async reclaimLookupTableRent(opts) {
|
|
2609
|
+
return reclaimLookupTablesForSigner({
|
|
2610
|
+
rpc: this.rpc,
|
|
2611
|
+
rpcSubscriptions: this.rpcSubscriptions,
|
|
2612
|
+
signer: this.signer,
|
|
2613
|
+
allowedEntryOwners: [this.garProgram, this.arnsProgram],
|
|
2614
|
+
commitment: this.commitment,
|
|
2615
|
+
maxTables: opts?.maxTables,
|
|
2616
|
+
scanLimit: opts?.scanLimit,
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
/** Read and deserialize the full EpochSettings account. */
|
|
2620
|
+
async getEpochSettingsFull() {
|
|
2621
|
+
const [esPda] = await getEpochSettingsPDA(this.garProgram);
|
|
2622
|
+
const account = await fetchEncodedAccount(this.rpc, esPda, {
|
|
2623
|
+
commitment: this.commitment,
|
|
2624
|
+
});
|
|
2625
|
+
if (!account.exists)
|
|
2626
|
+
throw new Error('EpochSettings not found');
|
|
2627
|
+
return deserializeEpochSettingsFull(Buffer.from(account.data));
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Submit `prescribe_epoch` using the off-chain-predicted observer set, with a
|
|
2631
|
+
* single re-predict-and-retry on `InvalidGatewayAccount` (covers a gateway
|
|
2632
|
+
* leaving the registry between the prediction read and the tx landing).
|
|
2633
|
+
*/
|
|
2634
|
+
async prescribeWithPrediction(epochIndex, nameRegistryAccount) {
|
|
2635
|
+
const submit = async () => this.prescribeEpoch({
|
|
2636
|
+
epochIndex,
|
|
2637
|
+
gatewayAccounts: await this.getPredictedObserverPDAs(epochIndex),
|
|
2638
|
+
nameRegistryAccount,
|
|
2639
|
+
});
|
|
2640
|
+
try {
|
|
2641
|
+
return await submit();
|
|
2642
|
+
}
|
|
2643
|
+
catch (err) {
|
|
2644
|
+
if (!isInvalidGatewayAccountError(err))
|
|
2645
|
+
throw err;
|
|
2646
|
+
return submit();
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Advance the epoch lifecycle by ONE on-chain action and return what it did.
|
|
2651
|
+
*
|
|
2652
|
+
* Stateless and idempotent: it reads `EpochSettings` + the current `Epoch`,
|
|
2653
|
+
* determines the single next required step
|
|
2654
|
+
* (`create` → `tally` → `prescribe` → `distribute` → `close`), submits it,
|
|
2655
|
+
* and returns a {@link CrankEpochStepResult}. Call it repeatedly on your own
|
|
2656
|
+
* schedule — it owns *which* on-chain action is correct and *which accounts*
|
|
2657
|
+
* it needs; you own scheduling, logging, error classification, and any
|
|
2658
|
+
* permissionless cleanup.
|
|
2659
|
+
*
|
|
2660
|
+
* Crucially, the `prescribe` leg uses {@link getPredictedObserverPDAs} (only
|
|
2661
|
+
* the ~`prescribed_observer_count` selected Gateway PDAs), so it never trips
|
|
2662
|
+
* `MAX_TX_ACCOUNT_LOCKS = 64` on large registries — and it re-predicts and
|
|
2663
|
+
* retries once on `InvalidGatewayAccount`.
|
|
2664
|
+
*
|
|
2665
|
+
* Errors propagate to the caller (classify/retry as you see fit); the only
|
|
2666
|
+
* internally-handled error is the prescribe `InvalidGatewayAccount` retry.
|
|
2667
|
+
*/
|
|
2668
|
+
async crankEpochStep(opts = {}) {
|
|
2669
|
+
// tally_weights / distribute_epoch append the batch's Gateway PDAs as
|
|
2670
|
+
// remaining_accounts. distribute also CPIs into ario-core (treasury
|
|
2671
|
+
// release) so it carries 10 named accounts; with ~18+ gateway PDAs on top
|
|
2672
|
+
// the tx exceeds Solana's 1232-byte limit. Cap the lifecycle batch at 18 so
|
|
2673
|
+
// an oversized caller `batchSize` can't produce an unsendable tx (verified:
|
|
2674
|
+
// 30 gateways → 1527B; 18 → ~1050B). prescribe is the exception — it needs
|
|
2675
|
+
// ALL selected observers in one tx, so it uses an ALT instead (see
|
|
2676
|
+
// prescribeEpoch).
|
|
2677
|
+
const MAX_LIFECYCLE_BATCH = 18;
|
|
2678
|
+
const batchSize = Math.min(opts.batchSize ?? MAX_LIFECYCLE_BATCH, MAX_LIFECYCLE_BATCH);
|
|
2679
|
+
const enableClose = opts.enableClose ?? true;
|
|
2680
|
+
const retention = opts.epochRetention ?? 7;
|
|
2681
|
+
const enableCompound = opts.enableCompound ?? true;
|
|
2682
|
+
const compoundMinPending = opts.compoundMinPendingRewards ?? 0;
|
|
2683
|
+
const enableDemandFactorRoll = opts.enableDemandFactorRoll ?? true;
|
|
2684
|
+
const enablePrune = opts.enablePrune ?? true;
|
|
2685
|
+
const now = opts.now ?? Math.floor(Date.now() / 1000);
|
|
2686
|
+
const settings = await this.getEpochSettingsFull();
|
|
2687
|
+
if (!settings.enabled)
|
|
2688
|
+
return { action: 'idle', reason: 'epochs_disabled' };
|
|
2689
|
+
const currentIndex = settings.currentEpochIndex;
|
|
2690
|
+
// currentIndex is the NEXT epoch to create; the live one is currentIndex-1.
|
|
2691
|
+
const targetEpochIndex = currentIndex > 0 ? currentIndex - 1 : 0;
|
|
2692
|
+
const nextEpochStart = settings.genesisTimestamp + currentIndex * settings.epochDuration;
|
|
2693
|
+
const epoch = await this.getEpochRaw(targetEpochIndex);
|
|
2694
|
+
// Cold start: the live epoch (targetEpochIndex) doesn't exist yet. Two cases,
|
|
2695
|
+
// handled identically — `create_epoch` always creates epoch[currentIndex] and
|
|
2696
|
+
// then increments the counter, so the NEXT crank finds it live at currentIndex-1:
|
|
2697
|
+
// 1. Genesis: currentIndex === 0 → create epoch 0.
|
|
2698
|
+
// 2. AO→Solana continuity cold start: `admin_set_current_epoch_index` jumped
|
|
2699
|
+
// currentIndex to e.g. 454 with NO prior epochs on-chain (the AO-side
|
|
2700
|
+
// epochs were never created on Solana). targetEpochIndex (453) points at
|
|
2701
|
+
// an epoch that will never exist, so the old `currentIndex === 0`-only
|
|
2702
|
+
// bootstrap deadlocked here ('waiting_for_epoch' forever). Create
|
|
2703
|
+
// epoch[currentIndex] (454) directly — its start was re-anchored to ≈now.
|
|
2704
|
+
if (!epoch) {
|
|
2705
|
+
if (now < nextEpochStart)
|
|
2706
|
+
return {
|
|
2707
|
+
action: 'idle',
|
|
2708
|
+
reason: currentIndex === 0 ? 'waiting_for_genesis' : 'waiting_for_epoch',
|
|
2709
|
+
};
|
|
2710
|
+
const { id } = await this.createEpoch();
|
|
2711
|
+
return { action: 'create', epochIndex: currentIndex, txId: id };
|
|
2712
|
+
}
|
|
2713
|
+
// Tally (batched). activeGatewayCount===0 still needs one tx to flip the flag.
|
|
2714
|
+
if (epoch.weightsTallied === 0) {
|
|
2715
|
+
const gatewayAccounts = epoch.activeGatewayCount > 0
|
|
2716
|
+
? await this.getRegistryGatewayPDAs(epoch.tallyIndex, batchSize)
|
|
2717
|
+
: [];
|
|
2718
|
+
const { id } = await this.tallyWeights({
|
|
2719
|
+
epochIndex: targetEpochIndex,
|
|
2720
|
+
gatewayAccounts,
|
|
2721
|
+
});
|
|
2722
|
+
return {
|
|
2723
|
+
action: 'tally',
|
|
2724
|
+
epochIndex: targetEpochIndex,
|
|
2725
|
+
txId: id,
|
|
2726
|
+
progress: { index: epoch.tallyIndex, total: epoch.activeGatewayCount },
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
// Prescribe (predicted observers only — the size-safe path).
|
|
2730
|
+
if (epoch.prescriptionsDone === 0) {
|
|
2731
|
+
const nameRegistryAccount = opts.nameRegistryAccount === null
|
|
2732
|
+
? undefined
|
|
2733
|
+
: (opts.nameRegistryAccount ??
|
|
2734
|
+
(await getArnsRegistryPDA(this.arnsProgram))[0]);
|
|
2735
|
+
const { id } = await this.prescribeWithPrediction(targetEpochIndex, nameRegistryAccount);
|
|
2736
|
+
return { action: 'prescribe', epochIndex: targetEpochIndex, txId: id };
|
|
2737
|
+
}
|
|
2738
|
+
// Observations happen while the epoch is live. This is the dominant idle
|
|
2739
|
+
// window — fold returned-name pruning in here so it isn't starved on
|
|
2740
|
+
// clusters whose epochs park here (e.g. imported gateways that can't
|
|
2741
|
+
// observe → distribution never advances → the post-distribution tail below
|
|
2742
|
+
// is never reached).
|
|
2743
|
+
if (now < epoch.endTimestamp) {
|
|
2744
|
+
if (enablePrune) {
|
|
2745
|
+
const pruned = await this.maybePruneReturnedNamesStep(opts, now);
|
|
2746
|
+
if (pruned)
|
|
2747
|
+
return pruned;
|
|
2748
|
+
}
|
|
2749
|
+
return { action: 'idle', reason: 'waiting_for_observations' };
|
|
2750
|
+
}
|
|
2751
|
+
// Distribute (batched).
|
|
2752
|
+
if (epoch.rewardsDistributed === 0) {
|
|
2753
|
+
const gatewayAccounts = epoch.activeGatewayCount > 0
|
|
2754
|
+
? await this.getRegistryGatewayPDAs(epoch.distributionIndex, batchSize)
|
|
2755
|
+
: [];
|
|
2756
|
+
const { id } = await this.distributeEpoch({
|
|
2757
|
+
epochIndex: targetEpochIndex,
|
|
2758
|
+
gatewayAccounts,
|
|
2759
|
+
});
|
|
2760
|
+
return {
|
|
2761
|
+
action: 'distribute',
|
|
2762
|
+
epochIndex: targetEpochIndex,
|
|
2763
|
+
txId: id,
|
|
2764
|
+
progress: {
|
|
2765
|
+
index: epoch.distributionIndex,
|
|
2766
|
+
total: epoch.activeGatewayCount,
|
|
2767
|
+
},
|
|
2768
|
+
};
|
|
2769
|
+
}
|
|
2770
|
+
// Close a fully-distributed epoch past retention (GAR-006).
|
|
2771
|
+
//
|
|
2772
|
+
// CRITICAL: this is cleanup of OLD epochs and must NEVER block creation of
|
|
2773
|
+
// NEW ones. `close_epoch` reverts with EpochObservationsNotClosed until the
|
|
2774
|
+
// epoch's Observation PDAs are closed (observations_closed ==
|
|
2775
|
+
// observations_submitted), so we close those FIRST. The whole branch is
|
|
2776
|
+
// wrapped so any failure falls through to create-next instead of throwing
|
|
2777
|
+
// out of crankEpochStep — otherwise a single un-closeable epoch wedges epoch
|
|
2778
|
+
// progression network-wide (every operator's crank hits the same wall).
|
|
2779
|
+
if (enableClose && targetEpochIndex >= retention) {
|
|
2780
|
+
const closeTarget = targetEpochIndex - retention;
|
|
2781
|
+
try {
|
|
2782
|
+
const old = await this.getEpochRaw(closeTarget);
|
|
2783
|
+
if (old && old.rewardsDistributed === 1) {
|
|
2784
|
+
if (old.observationsSubmitted > old.observationsClosed) {
|
|
2785
|
+
// Open observations remain — close a batch before close_epoch.
|
|
2786
|
+
const observers = await this.getEpochObservers(closeTarget);
|
|
2787
|
+
if (observers.length > 0) {
|
|
2788
|
+
const batch = observers.slice(0, MAX_CLOSE_OBSERVATION_BATCH);
|
|
2789
|
+
const { id } = await this.closeObservations({
|
|
2790
|
+
epochIndex: closeTarget,
|
|
2791
|
+
observers: batch,
|
|
2792
|
+
});
|
|
2793
|
+
return {
|
|
2794
|
+
action: 'close_observation',
|
|
2795
|
+
epochIndex: closeTarget,
|
|
2796
|
+
txId: id,
|
|
2797
|
+
progress: { index: batch.length, total: observers.length },
|
|
2798
|
+
};
|
|
2799
|
+
}
|
|
2800
|
+
// Counter says open but no Observation PDA exists (orphaned counter):
|
|
2801
|
+
// can't close it, so don't attempt close_epoch (it would revert) and
|
|
2802
|
+
// don't wedge — fall through to create-next.
|
|
2803
|
+
}
|
|
2804
|
+
else {
|
|
2805
|
+
const { id } = await this.closeEpoch({ epochIndex: closeTarget });
|
|
2806
|
+
return { action: 'close', epochIndex: closeTarget, txId: id };
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
catch {
|
|
2811
|
+
// Best-effort cleanup — never block epoch creation. Retried next tick.
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
// Lazy-state maintenance — lower urgency than the lifecycle, reached only
|
|
2815
|
+
// once the live epoch is fully distributed (rewardsDistributed === 1 here).
|
|
2816
|
+
// Compound FIRST so delegated stake reflects the just-distributed rewards
|
|
2817
|
+
// before the next epoch's tally weights it; then roll the demand factor if
|
|
2818
|
+
// its period elapsed. Both are permissionless + idempotent, and run BEFORE
|
|
2819
|
+
// creating the next epoch so the compounded stake is in place for its tally.
|
|
2820
|
+
if (enableCompound) {
|
|
2821
|
+
const compounded = await this.maybeCompoundStep(compoundMinPending);
|
|
2822
|
+
if (compounded)
|
|
2823
|
+
return compounded;
|
|
2824
|
+
}
|
|
2825
|
+
if (enableDemandFactorRoll) {
|
|
2826
|
+
const rolled = await this.maybeRollDemandFactorStep(now);
|
|
2827
|
+
if (rolled)
|
|
2828
|
+
return rolled;
|
|
2829
|
+
}
|
|
2830
|
+
if (enablePrune) {
|
|
2831
|
+
const pruned = await this.maybePruneReturnedNamesStep(opts, now);
|
|
2832
|
+
if (pruned)
|
|
2833
|
+
return pruned;
|
|
2834
|
+
}
|
|
2835
|
+
// Current epoch fully processed — create the next once its start arrives.
|
|
2836
|
+
if (now >= nextEpochStart) {
|
|
2837
|
+
const { id } = await this.createEpoch();
|
|
2838
|
+
return { action: 'create', epochIndex: currentIndex, txId: id };
|
|
2839
|
+
}
|
|
2840
|
+
return { action: 'idle', reason: 'epoch_complete' };
|
|
2841
|
+
}
|
|
2842
|
+
/**
|
|
2843
|
+
* One compound batch over delegations with pending rewards (≤
|
|
2844
|
+
* {@link MAX_COMPOUND_BATCH} per tx), or `null` when none are due. Settling
|
|
2845
|
+
* is idempotent, so this converges over a few crank steps then no-ops until
|
|
2846
|
+
* the next epoch's distribution advances the accumulator again.
|
|
2847
|
+
*/
|
|
2848
|
+
async maybeCompoundStep(minPendingRewards) {
|
|
2849
|
+
const pending = await this.getDelegationsToCompound({ minPendingRewards });
|
|
2850
|
+
if (pending.length === 0)
|
|
2851
|
+
return null;
|
|
2852
|
+
const batch = pending.slice(0, MAX_COMPOUND_BATCH).map((p) => ({
|
|
2853
|
+
gateway: p.gatewayAddress,
|
|
2854
|
+
delegator: p.delegatorAddress,
|
|
2855
|
+
}));
|
|
2856
|
+
const { id } = await this.compoundDelegationRewardsBatch(batch);
|
|
2857
|
+
return {
|
|
2858
|
+
action: 'compound',
|
|
2859
|
+
txId: id,
|
|
2860
|
+
progress: { index: batch.length, total: pending.length },
|
|
2861
|
+
};
|
|
2862
|
+
}
|
|
2863
|
+
/**
|
|
2864
|
+
* Roll the demand factor forward if its (wall-clock) period elapsed since the
|
|
2865
|
+
* last stored roll, else `null`. Mirrors the on-chain period math; the roll
|
|
2866
|
+
* itself is idempotent.
|
|
2867
|
+
*/
|
|
2868
|
+
async maybeRollDemandFactorStep(now) {
|
|
2869
|
+
const state = await this.getDemandFactorPeriodState();
|
|
2870
|
+
if (!state)
|
|
2871
|
+
return null;
|
|
2872
|
+
const elapsed = now - state.periodZeroStartTimestamp;
|
|
2873
|
+
const periodForNow = elapsed < 0 ? 1 : Math.floor(elapsed / DEMAND_FACTOR_PERIOD_SECONDS) + 1;
|
|
2874
|
+
if (periodForNow <= state.currentPeriod)
|
|
2875
|
+
return null; // same period — no-op
|
|
2876
|
+
const { id } = await this.updateDemandFactor();
|
|
2877
|
+
return { action: 'update_demand_factor', txId: id };
|
|
2878
|
+
}
|
|
2879
|
+
/** Wall-clock (ms) of the last returned-name prune scan; throttles the
|
|
2880
|
+
* getProgramAccounts scan below the crank poll rate. */
|
|
2881
|
+
lastReturnedNamePruneScanMs = 0;
|
|
2882
|
+
/**
|
|
2883
|
+
* One prune batch over ReturnedName PDAs whose 14-day auction window has
|
|
2884
|
+
* elapsed (≤ {@link CrankEpochStepOptions.pruneBatchSize} per tx), or `null`
|
|
2885
|
+
* when none are due / the scan is throttled. Scans the PDAs directly — it does
|
|
2886
|
+
* NOT gate on `config.next_returned_names_prune_timestamp`, which is never set
|
|
2887
|
+
* for imported returned names and would strand them. The contract re-checks
|
|
2888
|
+
* each account's window, so a slightly-skewed client clock is safe.
|
|
2889
|
+
*/
|
|
2890
|
+
async maybePruneReturnedNamesStep(opts, now) {
|
|
2891
|
+
const scanInterval = opts.pruneScanIntervalMs ?? 60_000;
|
|
2892
|
+
const wallNow = Date.now();
|
|
2893
|
+
if (wallNow - this.lastReturnedNamePruneScanMs < scanInterval)
|
|
2894
|
+
return null;
|
|
2895
|
+
this.lastReturnedNamePruneScanMs = wallNow;
|
|
2896
|
+
const expired = await this.getExpiredReturnedNames(now);
|
|
2897
|
+
if (expired.length === 0)
|
|
2898
|
+
return null;
|
|
2899
|
+
const batchSize = opts.pruneBatchSize ?? 15;
|
|
2900
|
+
const batch = expired.slice(0, batchSize).map((r) => r.pubkey);
|
|
2901
|
+
const { id } = await this.pruneReturnedNames({
|
|
2902
|
+
maxNames: batch.length,
|
|
2903
|
+
returnedNames: batch,
|
|
2904
|
+
});
|
|
2905
|
+
return {
|
|
2906
|
+
action: 'prune_returned_names',
|
|
2907
|
+
txId: id,
|
|
2908
|
+
progress: { index: batch.length, total: expired.length },
|
|
2909
|
+
};
|
|
2910
|
+
}
|
|
2911
|
+
/**
|
|
2912
|
+
* The DemandFactor account's stored period + period-zero start (seconds) —
|
|
2913
|
+
* the gate for {@link maybeRollDemandFactorStep}. `null` if the account
|
|
2914
|
+
* doesn't exist (pre-genesis).
|
|
2915
|
+
*/
|
|
2916
|
+
async getDemandFactorPeriodState() {
|
|
2917
|
+
const [pda] = await getDemandFactorPDA(this.arnsProgram);
|
|
2918
|
+
const account = await fetchEncodedAccount(this.rpc, pda, {
|
|
2919
|
+
commitment: this.commitment,
|
|
2920
|
+
});
|
|
2921
|
+
if (!account.exists)
|
|
2922
|
+
return null;
|
|
2923
|
+
const df = deserializeDemandFactor(Buffer.from(account.data));
|
|
2924
|
+
return {
|
|
2925
|
+
currentPeriod: df.currentPeriod,
|
|
2926
|
+
periodZeroStartTimestamp: df.periodZeroStartTimestamp,
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
1987
2929
|
/**
|
|
1988
2930
|
* Read the raw epoch account data for cranker state inspection.
|
|
1989
2931
|
* Returns null if the epoch account doesn't exist yet.
|
|
@@ -2011,10 +2953,13 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
2011
2953
|
* [8 per_obs][8 reward_rate][8 weight_lo][8 weight_hi][32 hashchain]
|
|
2012
2954
|
* [4 active_gw_count][4 dist_idx][4 tally_idx]
|
|
2013
2955
|
* [1 observer_count][1 name_count][1 obs_submitted][1 rewards_dist]
|
|
2014
|
-
* [1 weights_tallied][1 prescriptions_done][1 bump][1
|
|
2956
|
+
* [1 weights_tallied][1 prescriptions_done][1 bump][1 obs_closed]
|
|
2015
2957
|
* [6000 failure_counts][1600 prescribed_observers]
|
|
2016
2958
|
* [1600 prescribed_observer_gateways][64 prescribed_names]
|
|
2017
2959
|
* [7 has_observed][5 _pad2]
|
|
2960
|
+
*
|
|
2961
|
+
* NOTE: byte +123 is `observations_closed` (NOT padding) — `close_epoch`
|
|
2962
|
+
* reverts with EpochObservationsNotClosed until it equals obs_submitted.
|
|
2018
2963
|
*/
|
|
2019
2964
|
fetchEpochRawFields(data) {
|
|
2020
2965
|
const base = 8;
|
|
@@ -2022,15 +2967,19 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
2022
2967
|
const activeGatewayCount = data.readUInt32LE(base + 104);
|
|
2023
2968
|
const distributionIndex = data.readUInt32LE(base + 108);
|
|
2024
2969
|
const tallyIndex = data.readUInt32LE(base + 112);
|
|
2970
|
+
const observationsSubmitted = data.readUInt8(base + 118);
|
|
2025
2971
|
const rewardsDistributed = data.readUInt8(base + 119);
|
|
2026
2972
|
const weightsTallied = data.readUInt8(base + 120);
|
|
2027
2973
|
const prescriptionsDone = data.readUInt8(base + 121);
|
|
2974
|
+
const observationsClosed = data.readUInt8(base + 123);
|
|
2028
2975
|
return {
|
|
2029
2976
|
tallyIndex,
|
|
2030
2977
|
distributionIndex,
|
|
2031
2978
|
weightsTallied,
|
|
2032
2979
|
prescriptionsDone,
|
|
2033
2980
|
rewardsDistributed,
|
|
2981
|
+
observationsSubmitted,
|
|
2982
|
+
observationsClosed,
|
|
2034
2983
|
activeGatewayCount,
|
|
2035
2984
|
endTimestamp,
|
|
2036
2985
|
};
|
|
@@ -2068,6 +3017,7 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
2068
3017
|
* (kicks off the Dutch auction). Permissionless.
|
|
2069
3018
|
*/
|
|
2070
3019
|
async pruneNameToReturned(params, _options) {
|
|
3020
|
+
const migrateIxs = await this._buildMigrateArnsRecordIxIfNeeded(params.name);
|
|
2071
3021
|
const [arnsRecord] = await getArnsRecordPDA(params.name, this.arnsProgram);
|
|
2072
3022
|
const [returnedName] = await getReturnedNamePDA(params.name, this.arnsProgram);
|
|
2073
3023
|
const ix = await getPruneNameToReturnedInstructionAsync(await this.withArnsDefaults({
|
|
@@ -2075,7 +3025,7 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
2075
3025
|
returnedName,
|
|
2076
3026
|
payer: this.signer,
|
|
2077
3027
|
}), { programAddress: this.arnsProgram });
|
|
2078
|
-
const sig = await this.sendTransaction([ix]);
|
|
3028
|
+
const sig = await this.sendTransaction([...migrateIxs, ix]);
|
|
2079
3029
|
return { id: sig };
|
|
2080
3030
|
}
|
|
2081
3031
|
/**
|
|
@@ -2147,11 +3097,34 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
2147
3097
|
async finalizeGone(params, _options) {
|
|
2148
3098
|
const gatewayAddr = address(params.gateway);
|
|
2149
3099
|
const [gatewayPda] = await getGatewayPDA(gatewayAddr, this.garProgram);
|
|
3100
|
+
// `finalize_gone` reclaims this gateway's compact-registry slot by
|
|
3101
|
+
// swap-removing the LAST active slot into it. When this gateway is not the
|
|
3102
|
+
// last slot, the on-chain handler rewrites the swapped gateway's stored
|
|
3103
|
+
// registry_index and therefore requires that swapped Gateway PDA as
|
|
3104
|
+
// writable remaining_accounts[0]
|
|
3105
|
+
// (programs/ario-gar/src/instructions/gateway.rs::finalize_gone). Read the
|
|
3106
|
+
// gateway's slot index + the active registry to decide.
|
|
3107
|
+
const gatewayAccount = await fetchEncodedAccount(this.rpc, gatewayPda, {
|
|
3108
|
+
commitment: this.commitment,
|
|
3109
|
+
});
|
|
3110
|
+
if (!gatewayAccount.exists) {
|
|
3111
|
+
throw new Error(`Gateway not found for operator ${params.gateway}`);
|
|
3112
|
+
}
|
|
3113
|
+
const gateway = getGatewayDecoder().decode(gatewayAccount.data);
|
|
3114
|
+
const registryAddresses = await this.getRegistryGatewayAddresses();
|
|
3115
|
+
const swappedOperator = selectFinalizeGoneSwapOperator(gateway.registryIndex.index, registryAddresses);
|
|
2150
3116
|
const ix = await getFinalizeGoneInstructionAsync(await this.withGarDefaults({
|
|
2151
3117
|
gateway: gatewayPda,
|
|
2152
3118
|
caller: this.signer,
|
|
2153
3119
|
}), { programAddress: this.garProgram });
|
|
2154
|
-
|
|
3120
|
+
let finalIx = ix;
|
|
3121
|
+
if (swappedOperator !== null) {
|
|
3122
|
+
const [swappedGatewayPda] = await getGatewayPDA(address(swappedOperator), this.garProgram);
|
|
3123
|
+
finalIx = withRemainingAccounts(ix, [
|
|
3124
|
+
{ address: swappedGatewayPda, role: AccountRole.WRITABLE },
|
|
3125
|
+
]);
|
|
3126
|
+
}
|
|
3127
|
+
const sig = await this.sendTransaction([finalIx]);
|
|
2155
3128
|
return { id: sig };
|
|
2156
3129
|
}
|
|
2157
3130
|
/**
|
|
@@ -2170,6 +3143,29 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
|
|
|
2170
3143
|
const sig = await this.sendTransaction([ix]);
|
|
2171
3144
|
return { id: sig };
|
|
2172
3145
|
}
|
|
3146
|
+
/**
|
|
3147
|
+
* Close multiple Observation PDAs for one epoch in a single tx (each
|
|
3148
|
+
* `close_observation` increments the parent Epoch's `observations_closed`).
|
|
3149
|
+
* Permissionless; rent is refunded to the payer. Used by the crank to satisfy
|
|
3150
|
+
* `close_epoch`'s `observations_closed == observations_submitted` precondition
|
|
3151
|
+
* before closing a retention-aged epoch. Keep the batch small — each ix carries
|
|
3152
|
+
* the Epoch + Observation + payer + system accounts.
|
|
3153
|
+
*/
|
|
3154
|
+
async closeObservations(params, _options) {
|
|
3155
|
+
if (params.observers.length === 0) {
|
|
3156
|
+
throw new Error('closeObservations: observers must be non-empty');
|
|
3157
|
+
}
|
|
3158
|
+
const ixs = await Promise.all(params.observers.map(async (obs) => {
|
|
3159
|
+
const [observationPda] = await getObservationPDA(params.epochIndex, address(obs), this.garProgram);
|
|
3160
|
+
return getCloseObservationInstructionAsync({
|
|
3161
|
+
observation: observationPda,
|
|
3162
|
+
payer: this.signer,
|
|
3163
|
+
epochIndex: BigInt(params.epochIndex),
|
|
3164
|
+
}, { programAddress: this.garProgram });
|
|
3165
|
+
}));
|
|
3166
|
+
const sig = await this.sendTransaction(ixs);
|
|
3167
|
+
return { id: sig };
|
|
3168
|
+
}
|
|
2173
3169
|
/**
|
|
2174
3170
|
* Close an empty Delegation PDA (`amount == 0`) and refund rent to the
|
|
2175
3171
|
* original delegator (NOT the caller — see GAR-016, prevents griefing).
|