@ar.io/sdk 4.0.0-solana.24 → 4.0.0-solana.25

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.
@@ -108,6 +108,12 @@ class BorshReader {
108
108
  return undefined;
109
109
  return this.readU32();
110
110
  }
111
+ readOptionU16() {
112
+ const tag = this.readU8();
113
+ if (tag === 0)
114
+ return undefined;
115
+ return this.readU16();
116
+ }
111
117
  skip(bytes) {
112
118
  this.offset += bytes;
113
119
  }
@@ -332,6 +338,15 @@ export function deserializeGatewayWithAccumulator(data) {
332
338
  const delegateRewardShareRatio = r.readU16() / 100;
333
339
  const minDelegatedStake = r.readU64AsNumber();
334
340
  const allowlistEnabled = r.readBool();
341
+ // GATEWAY_VERSION 1.1.0 added two fields to GatewaySettings2 — MUST read them
342
+ // here to keep the byte stream aligned for every field after `settings`.
343
+ // - pending_delegate_reward_share_ratio: Option<u16> (Fix #7) — basis points
344
+ // of a deferred reward-share change applied at the next epoch's tally.
345
+ // - delegation_disabled_at: Option<i64> (Fix #6) — unix seconds the operator
346
+ // disabled delegation; starts the re-enable cooldown.
347
+ const pendingRatioRaw = r.readOptionU16();
348
+ const pendingDelegateRewardShareRatio = pendingRatioRaw === undefined ? undefined : pendingRatioRaw / 100;
349
+ const delegationDisabledAt = r.readOptionI64();
335
350
  // RegistryIndex (index: u32, _reserved: u8 — was is_registered:bool)
336
351
  r.readU32(); // registryIndex
337
352
  r.readU8(); // _reserved (layout-preserving placeholder for the legacy is_registered byte)
@@ -378,6 +393,8 @@ export function deserializeGatewayWithAccumulator(data) {
378
393
  fqdn,
379
394
  port,
380
395
  protocol: 'https', // protocolIdx: 0=Http, 1=Https — only HTTPS in practice
396
+ pendingDelegateRewardShareRatio, // Fix #7: undefined when no change is queued
397
+ delegationDisabledAt, // Fix #6: undefined when delegation is enabled
381
398
  };
382
399
  return {
383
400
  operator: operator,
@@ -1743,6 +1743,39 @@ export class SolanaARIOReadable {
1743
1743
  }
1744
1744
  return out;
1745
1745
  }
1746
+ /**
1747
+ * Enumerate Joined Gateway PDAs whose delegation has been DISABLED
1748
+ * (`allow_delegated_staking == false`) yet still hold delegated stake
1749
+ * (`total_delegated_stake > 0`) — i.e. delegates that an operator's disable
1750
+ * left stranded (WP §6.3 / Fix #6). Each such gateway's delegates must be
1751
+ * cranked out via
1752
+ * {@link SolanaARIOWriteable.claimDelegateFromDisabledGateway} (enumerate
1753
+ * them with {@link getGatewayDelegates}) before the operator can re-enable
1754
+ * delegation. This is the discovery primitive a cranker uses to sweep them.
1755
+ */
1756
+ async getDisabledGatewaysWithDelegatedStake() {
1757
+ const accounts = await this.getAccountsByDiscriminator(this.garProgram, GATEWAY_DISCRIMINATOR);
1758
+ const decoder = getGatewayDecoder();
1759
+ const out = [];
1760
+ for (const { pubkey, data } of accounts) {
1761
+ try {
1762
+ const g = decoder.decode(data);
1763
+ if (g.status !== GatewayStatus.Joined)
1764
+ continue;
1765
+ if (!g.settings.allowDelegatedStaking && g.totalDelegatedStake > 0n) {
1766
+ out.push({
1767
+ pubkey,
1768
+ operator: g.operator,
1769
+ totalDelegatedStake: g.totalDelegatedStake,
1770
+ });
1771
+ }
1772
+ }
1773
+ catch {
1774
+ // skip malformed
1775
+ }
1776
+ }
1777
+ return out;
1778
+ }
1746
1779
  /**
1747
1780
  * Enumerate Delegation PDAs with `amount == 0`. Eligible for
1748
1781
  * `closeEmptyDelegation` (rent refund to the original delegator).
@@ -38,7 +38,7 @@ function toGeneratedFundingSourceSpec(s) {
38
38
  import { getSyncAttributesInstruction } from '@ar.io/solana-contracts/ant';
39
39
  import { getApprovePrimaryNameInstructionAsync, getCloseExpiredRequestInstruction, getCreateVaultInstructionAsync, getExtendVaultInstructionAsync, getIncreaseVaultInstructionAsync, getReleaseVaultInstructionAsync, getRemovePrimaryNameInstructionAsync, getRequestAndSetPrimaryNameFromFundingPlanInstructionAsync, getRequestAndSetPrimaryNameInstructionAsync, getRequestPrimaryNameFromFundingPlanInstructionAsync, getRequestPrimaryNameInstructionAsync, getRevokeVaultInstructionAsync, getVaultedTransferInstructionAsync, } from '@ar.io/solana-contracts/core';
40
40
  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';
41
+ import { Protocol, getAllowDelegateInstructionAsync, getCancelWithdrawalInstruction, getClaimDelegateFromDisabledGatewayInstructionAsync, 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';
42
42
  import { getTransferCheckedInstruction } from '@solana-program/token';
43
43
  import { ARIO_ANT_PROGRAM_ID, TOKEN_DECIMALS } from './constants.js';
44
44
  import { SolanaARIOReadable } from './io-readable.js';
@@ -1771,6 +1771,47 @@ export class SolanaARIOWriteable extends SolanaARIOReadable {
1771
1771
  return { id: sig };
1772
1772
  }
1773
1773
  // =========================================
1774
+ // Claim delegation from gateway with delegation DISABLED (ario-gar, Fix #6)
1775
+ // =========================================
1776
+ /**
1777
+ * Claim a delegate's stake out of a gateway that has DISABLED delegation
1778
+ * (`allow_delegated_staking == false`), moving it into the delegate's own
1779
+ * withdrawal vault (WP §6.3 / Fix #6). This is the disabled-gateway analog of
1780
+ * {@link claimDelegateFromLeavingGateway}: the on-chain instruction is
1781
+ * permissionless, so a cranker can sweep delegates out (the operator cannot
1782
+ * re-enable delegation until `total_delegated_stake == 0` and the cooldown
1783
+ * elapses). The withdrawal-counter and withdrawal PDAs are seeded by the
1784
+ * DELEGATOR, so a cranker must pass that delegate's `delegatorAddress`.
1785
+ *
1786
+ * @param params.gatewayAddress The gateway whose delegation was disabled.
1787
+ * @param params.delegatorAddress The delegate to claim for. Defaults to the
1788
+ * signer (self-claim). Pass another address to crank on a delegate's behalf;
1789
+ * the signer covers rent (`payer`) but stake still routes to the delegate's
1790
+ * own vault (the delegator key is bound by the delegation PDA seeds).
1791
+ */
1792
+ async claimDelegateFromDisabledGateway(params, _options) {
1793
+ const gateway = address(params.gatewayAddress);
1794
+ const delegator = params.delegatorAddress
1795
+ ? address(params.delegatorAddress)
1796
+ : this.signer.address;
1797
+ const [gatewayPda] = await getGatewayPDA(gateway, this.garProgram);
1798
+ const [delegationPda] = await getDelegationPDA(gateway, delegator, this.garProgram);
1799
+ // Withdrawal counter + vault are PDA-seeded by the delegator, not the payer.
1800
+ const nextId = await this.getNextWithdrawalId(delegator);
1801
+ const [withdrawalPda] = await getWithdrawalPDA(delegator, nextId, this.garProgram);
1802
+ const ix = await getClaimDelegateFromDisabledGatewayInstructionAsync({
1803
+ gateway: gatewayPda,
1804
+ delegation: delegationPda,
1805
+ withdrawal: withdrawalPda,
1806
+ // `delegator` is an unsigned seeds-derivation key; `payer` (the signer)
1807
+ // covers rent on the init_if_needed counter + the new withdrawal.
1808
+ delegator,
1809
+ payer: this.signer,
1810
+ }, { programAddress: this.garProgram });
1811
+ const sig = await this.sendTransaction([ix], 1_000_000);
1812
+ return { id: sig };
1813
+ }
1814
+ // =========================================
1774
1815
  // Delegation allowlist (ario-gar)
1775
1816
  // =========================================
1776
1817
  /** Add an address to the gateway's delegation allowlist. */
@@ -14,4 +14,4 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  // AUTOMATICALLY GENERATED FILE - DO NOT TOUCH
17
- export const version = '4.0.0-solana.24';
17
+ export const version = '4.0.0-solana.25';
@@ -46,6 +46,7 @@ declare class BorshReader {
46
46
  readString(): string;
47
47
  readOptionI64(): number | undefined;
48
48
  readOptionU32(): number | undefined;
49
+ readOptionU16(): number | undefined;
49
50
  skip(bytes: number): void;
50
51
  getOffset(): number;
51
52
  remaining(): number;
@@ -309,6 +309,21 @@ export declare class SolanaARIOReadable {
309
309
  pubkey: Address;
310
310
  operator: Address;
311
311
  }>>;
312
+ /**
313
+ * Enumerate Joined Gateway PDAs whose delegation has been DISABLED
314
+ * (`allow_delegated_staking == false`) yet still hold delegated stake
315
+ * (`total_delegated_stake > 0`) — i.e. delegates that an operator's disable
316
+ * left stranded (WP §6.3 / Fix #6). Each such gateway's delegates must be
317
+ * cranked out via
318
+ * {@link SolanaARIOWriteable.claimDelegateFromDisabledGateway} (enumerate
319
+ * them with {@link getGatewayDelegates}) before the operator can re-enable
320
+ * delegation. This is the discovery primitive a cranker uses to sweep them.
321
+ */
322
+ getDisabledGatewaysWithDelegatedStake(): Promise<Array<{
323
+ pubkey: Address;
324
+ operator: Address;
325
+ totalDelegatedStake: bigint;
326
+ }>>;
312
327
  /**
313
328
  * Enumerate Delegation PDAs with `amount == 0`. Eligible for
314
329
  * `closeEmptyDelegation` (rent refund to the original delegator).
@@ -422,6 +422,26 @@ export declare class SolanaARIOWriteable extends SolanaARIOReadable {
422
422
  claimDelegateFromLeavingGateway(params: {
423
423
  gatewayAddress: string;
424
424
  }, _options?: WriteOptions): Promise<MessageResult>;
425
+ /**
426
+ * Claim a delegate's stake out of a gateway that has DISABLED delegation
427
+ * (`allow_delegated_staking == false`), moving it into the delegate's own
428
+ * withdrawal vault (WP §6.3 / Fix #6). This is the disabled-gateway analog of
429
+ * {@link claimDelegateFromLeavingGateway}: the on-chain instruction is
430
+ * permissionless, so a cranker can sweep delegates out (the operator cannot
431
+ * re-enable delegation until `total_delegated_stake == 0` and the cooldown
432
+ * elapses). The withdrawal-counter and withdrawal PDAs are seeded by the
433
+ * DELEGATOR, so a cranker must pass that delegate's `delegatorAddress`.
434
+ *
435
+ * @param params.gatewayAddress The gateway whose delegation was disabled.
436
+ * @param params.delegatorAddress The delegate to claim for. Defaults to the
437
+ * signer (self-claim). Pass another address to crank on a delegate's behalf;
438
+ * the signer covers rent (`payer`) but stake still routes to the delegate's
439
+ * own vault (the delegator key is bound by the delegation PDA seeds).
440
+ */
441
+ claimDelegateFromDisabledGateway(params: {
442
+ gatewayAddress: string;
443
+ delegatorAddress?: string;
444
+ }, _options?: WriteOptions): Promise<MessageResult>;
425
445
  /** Add an address to the gateway's delegation allowlist. */
426
446
  allowDelegate(params: {
427
447
  delegate: string;
@@ -232,6 +232,22 @@ export type GatewaySettings = {
232
232
  fqdn: string;
233
233
  port: number;
234
234
  protocol: 'https';
235
+ /**
236
+ * Solana only (GATEWAY_VERSION 1.1.0+). A `delegateRewardShareRatio` change
237
+ * requested mid-epoch is staged here and applied at the next epoch's
238
+ * `tally_weights` (WP §6.3 / Fix #7), so the active value stays epoch-stable.
239
+ * When set, render the active `delegateRewardShareRatio` as the current rate
240
+ * and this as "pending until next epoch". Percent (0-95), same scale as
241
+ * `delegateRewardShareRatio`. Undefined when no change is queued.
242
+ */
243
+ pendingDelegateRewardShareRatio?: number;
244
+ /**
245
+ * Solana only (GATEWAY_VERSION 1.1.0+). Unix seconds when the operator
246
+ * disabled delegation (WP §6.3 / Fix #6). Re-enabling is blocked until every
247
+ * delegate has been withdrawn AND the withdrawal-period cooldown has elapsed
248
+ * since this time. Undefined when delegation is enabled.
249
+ */
250
+ delegationDisabledAt?: number;
235
251
  };
236
252
  export type BalanceWithAddress = {
237
253
  address: WalletAddress;
@@ -13,4 +13,4 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- export declare const version = "4.0.0-solana.23";
16
+ export declare const version = "4.0.0-solana.24";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ar.io/sdk",
3
- "version": "4.0.0-solana.24",
3
+ "version": "4.0.0-solana.25",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ar-io/ar-io-sdk.git"
@@ -123,7 +123,7 @@
123
123
  "typescript": "^5.1.6"
124
124
  },
125
125
  "dependencies": {
126
- "@ar.io/solana-contracts": "0.4.0",
126
+ "@ar.io/solana-contracts": "0.5.0-staging.15",
127
127
  "@solana-program/address-lookup-table": "^0.11.0",
128
128
  "@solana-program/compute-budget": "^0.15.0",
129
129
  "@solana-program/token": "^0.13.0",