@arcium-hq/client 0.10.3 → 0.11.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/build/index.cjs CHANGED
@@ -1883,7 +1883,7 @@ function createPacker(fields, typeName = 'Packer') {
1883
1883
  var address = "Arcj82pX7HxYKLR92qvgZUAd7vGS1k4hQvAFcPATFdEQ";
1884
1884
  var metadata = {
1885
1885
  name: "arcium",
1886
- version: "0.10.3",
1886
+ version: "0.11.0",
1887
1887
  spec: "0.1.0",
1888
1888
  description: "The Arcium program"
1889
1889
  };
@@ -2174,6 +2174,84 @@ var instructions = [
2174
2174
  }
2175
2175
  ]
2176
2176
  },
2177
+ {
2178
+ name: "bind_recovery_peer_migration",
2179
+ discriminator: [
2180
+ 30,
2181
+ 148,
2182
+ 4,
2183
+ 206,
2184
+ 139,
2185
+ 2,
2186
+ 55,
2187
+ 156
2188
+ ],
2189
+ accounts: [
2190
+ {
2191
+ name: "authority",
2192
+ docs: [
2193
+ "The recovery peer's `authority` — same dual role as in `MigrateArxNode`: it authorizes the",
2194
+ "bind and is the owner of `primary_stake_account`."
2195
+ ],
2196
+ signer: true
2197
+ },
2198
+ {
2199
+ name: "recovery_peer_account",
2200
+ docs: [
2201
+ "Must already be layout-migrated (`migrate_recovery_peer`) so the appended",
2202
+ "`primary_stake_account` field exists; otherwise the zero-copy load fails on the short",
2203
+ "account. Bundle `migrate_recovery_peer` ahead of this instruction in the same transaction."
2204
+ ],
2205
+ writable: true,
2206
+ pda: {
2207
+ seeds: [
2208
+ {
2209
+ kind: "const",
2210
+ value: [
2211
+ 82,
2212
+ 101,
2213
+ 99,
2214
+ 111,
2215
+ 118,
2216
+ 101,
2217
+ 114,
2218
+ 121,
2219
+ 80,
2220
+ 101,
2221
+ 101,
2222
+ 114,
2223
+ 65,
2224
+ 99,
2225
+ 99,
2226
+ 111,
2227
+ 117,
2228
+ 110,
2229
+ 116
2230
+ ]
2231
+ },
2232
+ {
2233
+ kind: "arg",
2234
+ path: "peer_offset"
2235
+ }
2236
+ ]
2237
+ }
2238
+ },
2239
+ {
2240
+ name: "primary_stake_account",
2241
+ writable: true
2242
+ },
2243
+ {
2244
+ name: "arcium_staking_program",
2245
+ address: "ArcStnN9zZZVB5WjgPhLHjYpY7Gb29mzb96ySsb1kxgq"
2246
+ }
2247
+ ],
2248
+ args: [
2249
+ {
2250
+ name: "peer_offset",
2251
+ type: "u32"
2252
+ }
2253
+ ]
2254
+ },
2177
2255
  {
2178
2256
  name: "bump_epoch_cluster",
2179
2257
  discriminator: [
@@ -2287,6 +2365,7 @@ var instructions = [
2287
2365
  },
2288
2366
  {
2289
2367
  name: "mxe",
2368
+ writable: true,
2290
2369
  pda: {
2291
2370
  seeds: [
2292
2371
  {
@@ -2824,6 +2903,7 @@ var instructions = [
2824
2903
  },
2825
2904
  {
2826
2905
  name: "mxe",
2906
+ writable: true,
2827
2907
  pda: {
2828
2908
  seeds: [
2829
2909
  {
@@ -3153,13 +3233,88 @@ var instructions = [
3153
3233
  ],
3154
3234
  accounts: [
3155
3235
  {
3156
- name: "node_authority",
3236
+ name: "staking_pool_signer",
3237
+ docs: [
3238
+ "The `arcium_staking::state::StakingPoolAccount` PDA, signing via CPI. Also the destination",
3239
+ "for the settled lamports (so the staking program immediately owns them for later",
3240
+ "proportional distribution). The `seeds`/`bump` constraint verifies it's the canonical pool",
3241
+ "PDA under `ARCIUM_STAKING_ID` (so only the staking program can call this); `Signer`",
3242
+ "enforces it actually signed."
3243
+ ],
3157
3244
  writable: true,
3158
- signer: true
3245
+ signer: true,
3246
+ pda: {
3247
+ seeds: [
3248
+ {
3249
+ kind: "const",
3250
+ value: [
3251
+ 83,
3252
+ 116,
3253
+ 97,
3254
+ 107,
3255
+ 105,
3256
+ 110,
3257
+ 103,
3258
+ 80,
3259
+ 111,
3260
+ 111,
3261
+ 108,
3262
+ 65,
3263
+ 99,
3264
+ 99,
3265
+ 111,
3266
+ 117,
3267
+ 110,
3268
+ 116
3269
+ ]
3270
+ }
3271
+ ],
3272
+ program: {
3273
+ kind: "const",
3274
+ value: [
3275
+ 146,
3276
+ 110,
3277
+ 184,
3278
+ 172,
3279
+ 179,
3280
+ 131,
3281
+ 118,
3282
+ 35,
3283
+ 207,
3284
+ 122,
3285
+ 30,
3286
+ 190,
3287
+ 228,
3288
+ 134,
3289
+ 232,
3290
+ 140,
3291
+ 222,
3292
+ 89,
3293
+ 53,
3294
+ 150,
3295
+ 174,
3296
+ 187,
3297
+ 151,
3298
+ 58,
3299
+ 208,
3300
+ 108,
3301
+ 237,
3302
+ 119,
3303
+ 97,
3304
+ 204,
3305
+ 184,
3306
+ 186
3307
+ ]
3308
+ }
3309
+ }
3159
3310
  },
3160
3311
  {
3161
- name: "recipient",
3162
- writable: true
3312
+ name: "primary_stake_account",
3313
+ docs: [
3314
+ "The `PrimaryStakingAccount` bound to this node. Passed so the handler can verify",
3315
+ "`node.primary_staking_account == primary_stake_account.key()` — i.e. the staking account",
3316
+ "that's about to claim the fees is the one this node was initialized with."
3317
+ ]
3163
3318
  },
3164
3319
  {
3165
3320
  name: "cluster",
@@ -3238,7 +3393,197 @@ var instructions = [
3238
3393
  name: "node_offset",
3239
3394
  type: "u32"
3240
3395
  }
3241
- ]
3396
+ ],
3397
+ returns: "u64"
3398
+ },
3399
+ {
3400
+ name: "claim_recovery_peer_fees",
3401
+ discriminator: [
3402
+ 132,
3403
+ 120,
3404
+ 187,
3405
+ 164,
3406
+ 106,
3407
+ 57,
3408
+ 202,
3409
+ 8
3410
+ ],
3411
+ accounts: [
3412
+ {
3413
+ name: "staking_pool_signer",
3414
+ docs: [
3415
+ "`arcium_staking::StakingPoolAccount` PDA, signing via CPI and receiving the drained",
3416
+ "lamports. The `seeds`/`bump` constraint verifies it's the canonical pool PDA under",
3417
+ "`ARCIUM_STAKING_ID`; `Signer` enforces `is_signer`."
3418
+ ],
3419
+ writable: true,
3420
+ signer: true,
3421
+ pda: {
3422
+ seeds: [
3423
+ {
3424
+ kind: "const",
3425
+ value: [
3426
+ 83,
3427
+ 116,
3428
+ 97,
3429
+ 107,
3430
+ 105,
3431
+ 110,
3432
+ 103,
3433
+ 80,
3434
+ 111,
3435
+ 111,
3436
+ 108,
3437
+ 65,
3438
+ 99,
3439
+ 99,
3440
+ 111,
3441
+ 117,
3442
+ 110,
3443
+ 116
3444
+ ]
3445
+ }
3446
+ ],
3447
+ program: {
3448
+ kind: "const",
3449
+ value: [
3450
+ 146,
3451
+ 110,
3452
+ 184,
3453
+ 172,
3454
+ 179,
3455
+ 131,
3456
+ 118,
3457
+ 35,
3458
+ 207,
3459
+ 122,
3460
+ 30,
3461
+ 190,
3462
+ 228,
3463
+ 134,
3464
+ 232,
3465
+ 140,
3466
+ 222,
3467
+ 89,
3468
+ 53,
3469
+ 150,
3470
+ 174,
3471
+ 187,
3472
+ 151,
3473
+ 58,
3474
+ 208,
3475
+ 108,
3476
+ 237,
3477
+ 119,
3478
+ 97,
3479
+ 204,
3480
+ 184,
3481
+ 186
3482
+ ]
3483
+ }
3484
+ }
3485
+ },
3486
+ {
3487
+ name: "primary_stake_account",
3488
+ docs: [
3489
+ "`PrimaryStakingAccount` the claiming peer is bound to. Only the key is compared",
3490
+ "against `recovery_peer.primary_stake_account`; the staking program owns the struct."
3491
+ ]
3492
+ },
3493
+ {
3494
+ name: "recovery_peer",
3495
+ pda: {
3496
+ seeds: [
3497
+ {
3498
+ kind: "const",
3499
+ value: [
3500
+ 82,
3501
+ 101,
3502
+ 99,
3503
+ 111,
3504
+ 118,
3505
+ 101,
3506
+ 114,
3507
+ 121,
3508
+ 80,
3509
+ 101,
3510
+ 101,
3511
+ 114,
3512
+ 65,
3513
+ 99,
3514
+ 99,
3515
+ 111,
3516
+ 117,
3517
+ 110,
3518
+ 116
3519
+ ]
3520
+ },
3521
+ {
3522
+ kind: "arg",
3523
+ path: "peer_offset"
3524
+ }
3525
+ ]
3526
+ }
3527
+ },
3528
+ {
3529
+ name: "mxe",
3530
+ writable: true,
3531
+ pda: {
3532
+ seeds: [
3533
+ {
3534
+ kind: "const",
3535
+ value: [
3536
+ 77,
3537
+ 88,
3538
+ 69,
3539
+ 65,
3540
+ 99,
3541
+ 99,
3542
+ 111,
3543
+ 117,
3544
+ 110,
3545
+ 116
3546
+ ]
3547
+ },
3548
+ {
3549
+ kind: "arg",
3550
+ path: "mxe_program"
3551
+ }
3552
+ ]
3553
+ }
3554
+ },
3555
+ {
3556
+ name: "pool",
3557
+ writable: true,
3558
+ pda: {
3559
+ seeds: [
3560
+ {
3561
+ kind: "const",
3562
+ value: [
3563
+ 70,
3564
+ 101,
3565
+ 101,
3566
+ 80,
3567
+ 111,
3568
+ 111,
3569
+ 108
3570
+ ]
3571
+ }
3572
+ ]
3573
+ }
3574
+ }
3575
+ ],
3576
+ args: [
3577
+ {
3578
+ name: "mxe_program",
3579
+ type: "pubkey"
3580
+ },
3581
+ {
3582
+ name: "peer_offset",
3583
+ type: "u32"
3584
+ }
3585
+ ],
3586
+ returns: "u64"
3242
3587
  },
3243
3588
  {
3244
3589
  name: "close_computation_definition",
@@ -4543,8 +4888,16 @@ var instructions = [
4543
4888
  {
4544
4889
  name: "large_execpool"
4545
4890
  }
4546
- ],
4547
- args: [
4891
+ ],
4892
+ args: [
4893
+ {
4894
+ name: "_selector",
4895
+ type: {
4896
+ defined: {
4897
+ name: "LeaderSelector"
4898
+ }
4899
+ }
4900
+ }
4548
4901
  ]
4549
4902
  },
4550
4903
  {
@@ -6156,6 +6509,31 @@ var instructions = [
6156
6509
  ]
6157
6510
  }
6158
6511
  },
6512
+ {
6513
+ name: "primary_stake_account",
6514
+ docs: [
6515
+ "The `PrimaryStakingAccount` (owned by the `arcium_staking` program) that this node will be",
6516
+ "bound to for the rest of its life. Reward settlement requires this linkage: fees accrued",
6517
+ "under this node can only be drained via a CPI signed by the staking program's pool PDA",
6518
+ "after matching on this key.",
6519
+ "the staking program's responsibility — if the staker binds garbage they lock themselves",
6520
+ "out of rewards, which is their own problem."
6521
+ ],
6522
+ writable: true
6523
+ },
6524
+ {
6525
+ name: "staker",
6526
+ docs: [
6527
+ "Authority of `primary_stake_account`. Required as a second signer so we can CPI into",
6528
+ "`arcium_staking::bind_primary_stake` and commit the stake to this node. The staking",
6529
+ "program re-derives the stake PDA from this key and rejects the call if it mismatches."
6530
+ ],
6531
+ signer: true
6532
+ },
6533
+ {
6534
+ name: "arcium_staking_program",
6535
+ address: "ArcStnN9zZZVB5WjgPhLHjYpY7Gb29mzb96ySsb1kxgq"
6536
+ },
6159
6537
  {
6160
6538
  name: "system_program",
6161
6539
  address: "11111111111111111111111111111111"
@@ -7023,6 +7401,15 @@ var instructions = [
7023
7401
  }
7024
7402
  ],
7025
7403
  args: [
7404
+ {
7405
+ name: "recovery_peers",
7406
+ type: {
7407
+ array: [
7408
+ "u32",
7409
+ 100
7410
+ ]
7411
+ }
7412
+ }
7026
7413
  ]
7027
7414
  },
7028
7415
  {
@@ -7137,8 +7524,8 @@ var instructions = [
7137
7524
  ]
7138
7525
  },
7139
7526
  {
7140
- kind: "arg",
7141
- path: "_mxe_program"
7527
+ kind: "account",
7528
+ path: "mxe_program"
7142
7529
  }
7143
7530
  ]
7144
7531
  }
@@ -7438,6 +7825,17 @@ var instructions = [
7438
7825
  ]
7439
7826
  }
7440
7827
  },
7828
+ {
7829
+ name: "instructions_sysvar",
7830
+ docs: [
7831
+ "Instructions sysvar — used in the handler to verify the **next** instruction in this",
7832
+ "transaction is `arcium_staking::init_mxe_recovery_stake_state` with the same",
7833
+ "`mxe_program`. This mirrors the reverse check on the staking side and is what",
7834
+ "guarantees that every MXE is created alongside its recovery stake state (replacement",
7835
+ "for the CPI we couldn't do because of the 4KB stack limit on `try_accounts`)."
7836
+ ],
7837
+ address: "Sysvar1nstructions1111111111111111111111111"
7838
+ },
7441
7839
  {
7442
7840
  name: "system_program",
7443
7841
  address: "11111111111111111111111111111111"
@@ -7448,19 +7846,6 @@ var instructions = [
7448
7846
  name: "cluster_offset",
7449
7847
  type: "u32"
7450
7848
  },
7451
- {
7452
- name: "mxe_program",
7453
- type: "pubkey"
7454
- },
7455
- {
7456
- name: "recovery_peers",
7457
- type: {
7458
- array: [
7459
- "u32",
7460
- 100
7461
- ]
7462
- }
7463
- },
7464
7849
  {
7465
7850
  name: "keygen_offset",
7466
7851
  type: "u64"
@@ -7918,6 +8303,31 @@ var instructions = [
7918
8303
  ]
7919
8304
  }
7920
8305
  },
8306
+ {
8307
+ name: "primary_stake_account",
8308
+ docs: [
8309
+ "The `PrimaryStakingAccount` (owned by `arcium_staking`) that the recovery peer is",
8310
+ "binding itself to. Mirrors the stake-first requirement on `InitArxNode`: every",
8311
+ "recovery peer has to point at a real staking account so we have someone to slash",
8312
+ "(or dock rewards from) if the peer misbehaves. Full account-structure validation",
8313
+ "is the staking program's job — here we just make sure the account is owned by it.",
8314
+ "point at any primary stake account they have authority over."
8315
+ ],
8316
+ writable: true
8317
+ },
8318
+ {
8319
+ name: "staker",
8320
+ docs: [
8321
+ "Authority of `primary_stake_account`. Required as a second signer so we can CPI into",
8322
+ "`arcium_staking::bind_primary_stake` and commit the stake to this recovery peer. The",
8323
+ "staking program re-derives the stake PDA from this key and rejects on mismatch."
8324
+ ],
8325
+ signer: true
8326
+ },
8327
+ {
8328
+ name: "arcium_staking_program",
8329
+ address: "ArcStnN9zZZVB5WjgPhLHjYpY7Gb29mzb96ySsb1kxgq"
8330
+ },
7921
8331
  {
7922
8332
  name: "system_program",
7923
8333
  address: "11111111111111111111111111111111"
@@ -8054,6 +8464,171 @@ var instructions = [
8054
8464
  }
8055
8465
  ]
8056
8466
  },
8467
+ {
8468
+ name: "migrate_arx_node",
8469
+ discriminator: [
8470
+ 26,
8471
+ 223,
8472
+ 103,
8473
+ 52,
8474
+ 241,
8475
+ 117,
8476
+ 229,
8477
+ 143
8478
+ ],
8479
+ accounts: [
8480
+ {
8481
+ name: "authority",
8482
+ docs: [
8483
+ "The node's `config.authority`, which both *authorizes* the bind (only the node's own admin",
8484
+ "may link a stake account to it — otherwise anyone could divert a node's rewards to their",
8485
+ "own stake) and doubles as the `staker` (owner of `primary_stake_account`) for the CPI."
8486
+ ],
8487
+ signer: true
8488
+ },
8489
+ {
8490
+ name: "arx_node_acc",
8491
+ writable: true,
8492
+ pda: {
8493
+ seeds: [
8494
+ {
8495
+ kind: "const",
8496
+ value: [
8497
+ 65,
8498
+ 114,
8499
+ 120,
8500
+ 78,
8501
+ 111,
8502
+ 100,
8503
+ 101
8504
+ ]
8505
+ },
8506
+ {
8507
+ kind: "arg",
8508
+ path: "node_offset"
8509
+ }
8510
+ ]
8511
+ }
8512
+ },
8513
+ {
8514
+ name: "primary_stake_account",
8515
+ docs: [
8516
+ "The `PrimaryStakingAccount` (created beforehand via",
8517
+ "`arcium_staking::add_primary_stake_to_legacy_acc`) to bind. Owner-checked here; the staking",
8518
+ "program re-derives `[SEED, authority]` and rejects a mismatch during the bind CPI."
8519
+ ],
8520
+ writable: true
8521
+ },
8522
+ {
8523
+ name: "arcium_staking_program",
8524
+ address: "ArcStnN9zZZVB5WjgPhLHjYpY7Gb29mzb96ySsb1kxgq"
8525
+ }
8526
+ ],
8527
+ args: [
8528
+ {
8529
+ name: "node_offset",
8530
+ type: "u32"
8531
+ }
8532
+ ]
8533
+ },
8534
+ {
8535
+ name: "migrate_cluster",
8536
+ docs: [
8537
+ "One-shot layout migrations for the staking upgrade. Each grows one already-deployed",
8538
+ "account to the current (append-only) layout; idempotent and permissionless. See",
8539
+ "`instructions::migration`."
8540
+ ],
8541
+ discriminator: [
8542
+ 158,
8543
+ 61,
8544
+ 104,
8545
+ 161,
8546
+ 253,
8547
+ 138,
8548
+ 0,
8549
+ 17
8550
+ ],
8551
+ accounts: [
8552
+ {
8553
+ name: "payer",
8554
+ writable: true,
8555
+ signer: true
8556
+ },
8557
+ {
8558
+ name: "cluster",
8559
+ docs: [
8560
+ "because the new program cannot deserialize the old (short) layout via `Account<Cluster>`."
8561
+ ],
8562
+ writable: true
8563
+ },
8564
+ {
8565
+ name: "system_program",
8566
+ address: "11111111111111111111111111111111"
8567
+ }
8568
+ ],
8569
+ args: [
8570
+ ]
8571
+ },
8572
+ {
8573
+ name: "migrate_mxe_account",
8574
+ discriminator: [
8575
+ 96,
8576
+ 162,
8577
+ 117,
8578
+ 100,
8579
+ 242,
8580
+ 143,
8581
+ 16,
8582
+ 80
8583
+ ],
8584
+ accounts: [
8585
+ {
8586
+ name: "payer",
8587
+ writable: true,
8588
+ signer: true
8589
+ },
8590
+ {
8591
+ name: "mxe",
8592
+ writable: true
8593
+ },
8594
+ {
8595
+ name: "system_program",
8596
+ address: "11111111111111111111111111111111"
8597
+ }
8598
+ ],
8599
+ args: [
8600
+ ]
8601
+ },
8602
+ {
8603
+ name: "migrate_recovery_peer",
8604
+ discriminator: [
8605
+ 58,
8606
+ 226,
8607
+ 37,
8608
+ 60,
8609
+ 200,
8610
+ 31,
8611
+ 251,
8612
+ 245
8613
+ ],
8614
+ accounts: [
8615
+ {
8616
+ name: "payer",
8617
+ writable: true,
8618
+ signer: true
8619
+ },
8620
+ {
8621
+ name: "recovery_peer",
8622
+ writable: true
8623
+ },
8624
+ {
8625
+ name: "system_program",
8626
+ address: "11111111111111111111111111111111"
8627
+ }
8628
+ ],
8629
+ args: [
8630
+ ]
8631
+ },
8057
8632
  {
8058
8633
  name: "propose_fee",
8059
8634
  discriminator: [
@@ -8272,7 +8847,12 @@ var instructions = [
8272
8847
  docs: [
8273
8848
  "Queues a computation.",
8274
8849
  "cu_price_micro: The priority price of a CU, in micro-lamports. Used",
8275
- "to calculate the priority fee and rounded down."
8850
+ "to calculate the priority fee and rounded down.",
8851
+ "callback_cu_limit: The compute unit limit to request for the callback transaction(s)",
8852
+ "via set_compute_unit_limit. 0 means unset (the node uses the default compute budget).",
8853
+ "A non-zero value incurs an additional priority fee of callback_cu_limit * cu_price_micro.",
8854
+ "callback_cu_limit + padding together occupy the 8 bytes that previously held the",
8855
+ "(always-zero) output_delivery_fee: u64, so the instruction layout is unchanged."
8276
8856
  ],
8277
8857
  discriminator: [
8278
8858
  1,
@@ -8605,8 +9185,12 @@ var instructions = [
8605
9185
  type: "u8"
8606
9186
  },
8607
9187
  {
8608
- name: "output_delivery_fee",
8609
- type: "u64"
9188
+ name: "callback_cu_limit",
9189
+ type: "u32"
9190
+ },
9191
+ {
9192
+ name: "padding",
9193
+ type: "u32"
8610
9194
  },
8611
9195
  {
8612
9196
  name: "cu_price_micro",
@@ -9883,7 +10467,63 @@ var instructions = [
9883
10467
  ],
9884
10468
  accounts: [
9885
10469
  {
9886
- name: "current_authority",
10470
+ name: "current_authority",
10471
+ writable: true,
10472
+ signer: true
10473
+ },
10474
+ {
10475
+ name: "cluster_acc",
10476
+ writable: true,
10477
+ pda: {
10478
+ seeds: [
10479
+ {
10480
+ kind: "const",
10481
+ value: [
10482
+ 67,
10483
+ 108,
10484
+ 117,
10485
+ 115,
10486
+ 116,
10487
+ 101,
10488
+ 114
10489
+ ]
10490
+ },
10491
+ {
10492
+ kind: "arg",
10493
+ path: "_id"
10494
+ }
10495
+ ]
10496
+ }
10497
+ }
10498
+ ],
10499
+ args: [
10500
+ {
10501
+ name: "cluster_id",
10502
+ type: "u32"
10503
+ },
10504
+ {
10505
+ name: "new_authority",
10506
+ type: {
10507
+ option: "pubkey"
10508
+ }
10509
+ }
10510
+ ]
10511
+ },
10512
+ {
10513
+ name: "set_cluster_td_info",
10514
+ discriminator: [
10515
+ 182,
10516
+ 126,
10517
+ 92,
10518
+ 101,
10519
+ 25,
10520
+ 252,
10521
+ 84,
10522
+ 180
10523
+ ],
10524
+ accounts: [
10525
+ {
10526
+ name: "authority",
9887
10527
  writable: true,
9888
10528
  signer: true
9889
10529
  },
@@ -9918,28 +10558,32 @@ var instructions = [
9918
10558
  type: "u32"
9919
10559
  },
9920
10560
  {
9921
- name: "new_authority",
10561
+ name: "td_info",
9922
10562
  type: {
9923
- option: "pubkey"
10563
+ option: {
10564
+ defined: {
10565
+ name: "NodeMetadata"
10566
+ }
10567
+ }
9924
10568
  }
9925
10569
  }
9926
10570
  ]
9927
10571
  },
9928
10572
  {
9929
- name: "set_cluster_td_info",
10573
+ name: "set_leader_choice",
9930
10574
  discriminator: [
9931
- 182,
9932
- 126,
9933
- 92,
9934
- 101,
9935
- 25,
9936
- 252,
9937
- 84,
9938
- 180
10575
+ 42,
10576
+ 7,
10577
+ 112,
10578
+ 255,
10579
+ 254,
10580
+ 186,
10581
+ 135,
10582
+ 133
9939
10583
  ],
9940
10584
  accounts: [
9941
10585
  {
9942
- name: "authority",
10586
+ name: "node_authority",
9943
10587
  writable: true,
9944
10588
  signer: true
9945
10589
  },
@@ -9962,7 +10606,53 @@ var instructions = [
9962
10606
  },
9963
10607
  {
9964
10608
  kind: "arg",
9965
- path: "_id"
10609
+ path: "cluster_offset"
10610
+ }
10611
+ ]
10612
+ }
10613
+ },
10614
+ {
10615
+ name: "arx_node_acc",
10616
+ pda: {
10617
+ seeds: [
10618
+ {
10619
+ kind: "const",
10620
+ value: [
10621
+ 65,
10622
+ 114,
10623
+ 120,
10624
+ 78,
10625
+ 111,
10626
+ 100,
10627
+ 101
10628
+ ]
10629
+ },
10630
+ {
10631
+ kind: "arg",
10632
+ path: "node_offset"
10633
+ }
10634
+ ]
10635
+ }
10636
+ },
10637
+ {
10638
+ name: "mempool",
10639
+ pda: {
10640
+ seeds: [
10641
+ {
10642
+ kind: "const",
10643
+ value: [
10644
+ 77,
10645
+ 101,
10646
+ 109,
10647
+ 112,
10648
+ 111,
10649
+ 111,
10650
+ 108
10651
+ ]
10652
+ },
10653
+ {
10654
+ kind: "arg",
10655
+ path: "cluster_offset"
9966
10656
  }
9967
10657
  ]
9968
10658
  }
@@ -9970,16 +10660,18 @@ var instructions = [
9970
10660
  ],
9971
10661
  args: [
9972
10662
  {
9973
- name: "cluster_id",
10663
+ name: "cluster_offset",
9974
10664
  type: "u32"
9975
10665
  },
9976
10666
  {
9977
- name: "td_info",
10667
+ name: "node_offset",
10668
+ type: "u32"
10669
+ },
10670
+ {
10671
+ name: "choice",
9978
10672
  type: {
9979
- option: {
9980
- defined: {
9981
- name: "NodeMetadata"
9982
- }
10673
+ defined: {
10674
+ name: "LeaderChoice"
9983
10675
  }
9984
10676
  }
9985
10677
  }
@@ -10311,6 +11003,156 @@ var instructions = [
10311
11003
  }
10312
11004
  ]
10313
11005
  },
11006
+ {
11007
+ name: "set_node_staking",
11008
+ discriminator: [
11009
+ 158,
11010
+ 40,
11011
+ 109,
11012
+ 244,
11013
+ 217,
11014
+ 195,
11015
+ 35,
11016
+ 140
11017
+ ],
11018
+ accounts: [
11019
+ {
11020
+ name: "staking_pool_signer",
11021
+ docs: [
11022
+ "The `arcium_staking::state::StakingPoolAccount` PDA, signing via CPI. The `seeds`/`bump`",
11023
+ "constraint verifies it's the canonical pool PDA under `ARCIUM_STAKING_ID` (so only the",
11024
+ "staking program can call this)"
11025
+ ],
11026
+ signer: true,
11027
+ pda: {
11028
+ seeds: [
11029
+ {
11030
+ kind: "const",
11031
+ value: [
11032
+ 83,
11033
+ 116,
11034
+ 97,
11035
+ 107,
11036
+ 105,
11037
+ 110,
11038
+ 103,
11039
+ 80,
11040
+ 111,
11041
+ 111,
11042
+ 108,
11043
+ 65,
11044
+ 99,
11045
+ 99,
11046
+ 111,
11047
+ 117,
11048
+ 110,
11049
+ 116
11050
+ ]
11051
+ }
11052
+ ],
11053
+ program: {
11054
+ kind: "const",
11055
+ value: [
11056
+ 146,
11057
+ 110,
11058
+ 184,
11059
+ 172,
11060
+ 179,
11061
+ 131,
11062
+ 118,
11063
+ 35,
11064
+ 207,
11065
+ 122,
11066
+ 30,
11067
+ 190,
11068
+ 228,
11069
+ 134,
11070
+ 232,
11071
+ 140,
11072
+ 222,
11073
+ 89,
11074
+ 53,
11075
+ 150,
11076
+ 174,
11077
+ 187,
11078
+ 151,
11079
+ 58,
11080
+ 208,
11081
+ 108,
11082
+ 237,
11083
+ 119,
11084
+ 97,
11085
+ 204,
11086
+ 184,
11087
+ 186
11088
+ ]
11089
+ }
11090
+ }
11091
+ },
11092
+ {
11093
+ name: "cluster",
11094
+ writable: true,
11095
+ pda: {
11096
+ seeds: [
11097
+ {
11098
+ kind: "const",
11099
+ value: [
11100
+ 67,
11101
+ 108,
11102
+ 117,
11103
+ 115,
11104
+ 116,
11105
+ 101,
11106
+ 114
11107
+ ]
11108
+ },
11109
+ {
11110
+ kind: "arg",
11111
+ path: "cluster_offset"
11112
+ }
11113
+ ]
11114
+ }
11115
+ },
11116
+ {
11117
+ name: "clock",
11118
+ pda: {
11119
+ seeds: [
11120
+ {
11121
+ kind: "const",
11122
+ value: [
11123
+ 67,
11124
+ 108,
11125
+ 111,
11126
+ 99,
11127
+ 107,
11128
+ 65,
11129
+ 99,
11130
+ 99,
11131
+ 111,
11132
+ 117,
11133
+ 110,
11134
+ 116
11135
+ ]
11136
+ }
11137
+ ]
11138
+ }
11139
+ }
11140
+ ],
11141
+ args: [
11142
+ {
11143
+ name: "cluster_offset",
11144
+ type: "u32"
11145
+ },
11146
+ {
11147
+ name: "node_offset",
11148
+ type: "u32"
11149
+ },
11150
+ {
11151
+ name: "stake",
11152
+ type: "u64"
11153
+ }
11154
+ ]
11155
+ },
10314
11156
  {
10315
11157
  name: "submit_aggregated_bls_pubkey",
10316
11158
  discriminator: [
@@ -11640,6 +12482,11 @@ var errors = [
11640
12482
  name: "MaxParallelismReached",
11641
12483
  msg: "Max parallelism reached"
11642
12484
  },
12485
+ {
12486
+ code: 6104,
12487
+ name: "MempoolAlreadyFullSize",
12488
+ msg: "Mempool is already at its full allocated size"
12489
+ },
11643
12490
  {
11644
12491
  code: 6200,
11645
12492
  name: "InvalidComputationOffset",
@@ -11815,6 +12662,16 @@ var errors = [
11815
12662
  name: "InvalidNodeOffset",
11816
12663
  msg: "Node offset is invalid"
11817
12664
  },
12665
+ {
12666
+ code: 6411,
12667
+ name: "InvalidStakingPoolSigner",
12668
+ msg: "The provided staking pool signer is not the staking program's StakingPoolAccount PDA"
12669
+ },
12670
+ {
12671
+ code: 6412,
12672
+ name: "InvalidStakingAccount",
12673
+ msg: "The provided primary stake account is not owned by the staking program or does not match the node's bound staking account"
12674
+ },
11818
12675
  {
11819
12676
  code: 6500,
11820
12677
  name: "ClusterFull",
@@ -11873,7 +12730,7 @@ var errors = [
11873
12730
  {
11874
12731
  code: 6602,
11875
12732
  name: "HeapFull",
11876
- msg: "Heap is full"
12733
+ msg: "Mempool capacity for the current slot reached - retry next slot or reduce queue rate"
11877
12734
  },
11878
12735
  {
11879
12736
  code: 6603,
@@ -11990,6 +12847,11 @@ var errors = [
11990
12847
  name: "RecoveryInitAlreadyInitialized",
11991
12848
  msg: "Recovery already initialized"
11992
12849
  },
12850
+ {
12851
+ code: 6626,
12852
+ name: "InvalidSubsequentIx",
12853
+ msg: "Subsequent instruction in this transaction is not the expected one"
12854
+ },
11993
12855
  {
11994
12856
  code: 6700,
11995
12857
  name: "MxeNotInMigrationState",
@@ -12114,6 +12976,11 @@ var errors = [
12114
12976
  code: 6725,
12115
12977
  name: "CannotCloseMxeDuringMigration",
12116
12978
  msg: "MXE is in migration state, cannot close MXE"
12979
+ },
12980
+ {
12981
+ code: 6726,
12982
+ name: "InvalidMigrationAccount",
12983
+ msg: "Account is not a valid target for this migration (wrong owner or discriminator)"
12117
12984
  }
12118
12985
  ];
12119
12986
  var types = [
@@ -12914,30 +13781,71 @@ var types = [
12914
13781
  }
12915
13782
  },
12916
13783
  {
12917
- name: "bls_public_key",
13784
+ name: "bls_public_key",
13785
+ docs: [
13786
+ "BLS public key for the cluster (64 bytes compressed G2 point for alt-bn128)",
13787
+ "Set only when all nodes have submitted and agreed on the aggregated pubkey"
13788
+ ],
13789
+ type: {
13790
+ defined: {
13791
+ name: "SetUnset",
13792
+ generics: [
13793
+ {
13794
+ kind: "type",
13795
+ type: {
13796
+ defined: {
13797
+ name: "BN254G2BLSPublicKey"
13798
+ }
13799
+ }
13800
+ }
13801
+ ]
13802
+ }
13803
+ }
13804
+ },
13805
+ {
13806
+ name: "bump",
13807
+ docs: [
13808
+ "PDA bump. Declared by hand rather than via the `#[bump]` macro (which appends the bump",
13809
+ "as the *final* struct field) so it keeps its original offset right after",
13810
+ "`bls_public_key`. Everything below is appended *after* the bump, which means the byte",
13811
+ "layout of every field up to and including `bump` is identical to the pre-staking",
13812
+ "`Cluster` — old deserializers (including external user programs that read this account)",
13813
+ "decode the original prefix and harmlessly ignore the trailing staking fields."
13814
+ ],
13815
+ type: "u8"
13816
+ },
13817
+ {
13818
+ name: "current_epoch_total_rewards",
13819
+ docs: [
13820
+ "Running total of computation rewards accrued during `rewards_epoch`. Drained to zero",
13821
+ "by `claim_node_fees` when nodes settle via `finalize_epoch_rewards`."
13822
+ ],
13823
+ type: "u64"
13824
+ },
13825
+ {
13826
+ name: "rewards_epoch",
13827
+ docs: [
13828
+ "The epoch that `current_epoch_total_rewards` belongs to. If the clock has advanced",
13829
+ "past this epoch and `current_epoch_total_rewards > 0`, the rewards are stale",
13830
+ "(nodes didn't settle in time) — new accruals are silently skipped until nodes",
13831
+ "finalize, which punishes lazy operators."
13832
+ ],
13833
+ type: {
13834
+ defined: {
13835
+ name: "Epoch"
13836
+ }
13837
+ }
13838
+ },
13839
+ {
13840
+ name: "leader_selector",
12918
13841
  docs: [
12919
- "BLS public key for the cluster (64 bytes compressed G2 point for alt-bn128)",
12920
- "Set only when all nodes have submitted and agreed on the aggregated pubkey"
13842
+ "The selector for leader."
12921
13843
  ],
12922
13844
  type: {
12923
13845
  defined: {
12924
- name: "SetUnset",
12925
- generics: [
12926
- {
12927
- kind: "type",
12928
- type: {
12929
- defined: {
12930
- name: "BN254G2BLSPublicKey"
12931
- }
12932
- }
12933
- }
12934
- ]
13846
+ name: "LeaderSelector"
12935
13847
  }
12936
13848
  }
12937
- },
12938
- {
12939
- name: "bump",
12940
- type: "u8"
12941
13849
  }
12942
13850
  ]
12943
13851
  }
@@ -13471,16 +14379,28 @@ var types = [
13471
14379
  {
13472
14380
  name: "priority_fee",
13473
14381
  docs: [
13474
- "The additional fee to enforce priortized execution in the mempool."
14382
+ "The additional fee to enforce prioritized execution in the mempool."
13475
14383
  ],
13476
14384
  type: "u64"
13477
14385
  },
13478
14386
  {
13479
- name: "output_delivery_fee",
14387
+ name: "callback_cu_limit",
13480
14388
  docs: [
13481
- "A fee for output delivery fees (i.e. tx fees)."
14389
+ "The compute unit limit to request for the callback transaction(s), i.e. how many CUs the",
14390
+ "node should request via set_compute_unit_limit. 0 means unset, in which case the node uses",
14391
+ "the default compute budget.",
14392
+ "",
14393
+ "This reuses the low 4 bytes of what was previously `output_delivery_fee: u64` (which was",
14394
+ "always 0), so the serialized layout of ExecutionFee is unchanged."
13482
14395
  ],
13483
- type: "u64"
14396
+ type: "u32"
14397
+ },
14398
+ {
14399
+ name: "padding",
14400
+ docs: [
14401
+ "Padding preserving the original 8-byte (u64) layout of the former `output_delivery_fee`."
14402
+ ],
14403
+ type: "u32"
13484
14404
  }
13485
14405
  ]
13486
14406
  }
@@ -13846,6 +14766,113 @@ var types = [
13846
14766
  ]
13847
14767
  }
13848
14768
  },
14769
+ {
14770
+ name: "LeaderChoice",
14771
+ docs: [
14772
+ "The computation chosen by a node to be executed when the node is leader."
14773
+ ],
14774
+ type: {
14775
+ kind: "struct",
14776
+ fields: [
14777
+ {
14778
+ name: "offset",
14779
+ docs: [
14780
+ "Computation_offset of the chosen computation."
14781
+ ],
14782
+ type: "u64"
14783
+ },
14784
+ {
14785
+ name: "slot_idx",
14786
+ docs: [
14787
+ "The index of the max_heap the computation is in inside the MemPool's Circular Buffer.",
14788
+ "This is the physical index, not the logical one."
14789
+ ],
14790
+ type: "u16"
14791
+ }
14792
+ ]
14793
+ }
14794
+ },
14795
+ {
14796
+ name: "LeaderInfo",
14797
+ docs: [
14798
+ "The information about a node."
14799
+ ],
14800
+ type: {
14801
+ kind: "struct",
14802
+ fields: [
14803
+ {
14804
+ name: "stake",
14805
+ docs: [
14806
+ "The node's stake."
14807
+ ],
14808
+ type: "u64"
14809
+ },
14810
+ {
14811
+ name: "count",
14812
+ docs: [
14813
+ "The number + 1 of times the node has been chosen as leader in this cycle.",
14814
+ "0 if the stake is unset.",
14815
+ "This way works well for performance."
14816
+ ],
14817
+ type: "u64"
14818
+ },
14819
+ {
14820
+ name: "last_counter_plus_one",
14821
+ docs: [
14822
+ "The last time the node has been chosen as leader."
14823
+ ],
14824
+ type: "u64"
14825
+ },
14826
+ {
14827
+ name: "choice",
14828
+ docs: [
14829
+ "The choice of that node."
14830
+ ],
14831
+ type: {
14832
+ defined: {
14833
+ name: "LeaderChoice"
14834
+ }
14835
+ }
14836
+ }
14837
+ ]
14838
+ }
14839
+ },
14840
+ {
14841
+ name: "LeaderSelector",
14842
+ docs: [
14843
+ "To select a Leader.",
14844
+ "Uses the greatest divisors method: https://en.wikipedia.org/wiki/D%27Hondt_method"
14845
+ ],
14846
+ type: {
14847
+ kind: "struct",
14848
+ fields: [
14849
+ {
14850
+ name: "staking_epoch",
14851
+ docs: [
14852
+ "The last epoch the staking was set."
14853
+ ],
14854
+ type: {
14855
+ defined: {
14856
+ name: "Epoch"
14857
+ }
14858
+ }
14859
+ },
14860
+ {
14861
+ name: "info",
14862
+ docs: [
14863
+ "The information about each node."
14864
+ ],
14865
+ type: {
14866
+ vec: {
14867
+ defined: {
14868
+ name: "LeaderInfo"
14869
+ }
14870
+ }
14871
+ }
14872
+ }
14873
+ ]
14874
+ }
14875
+ },
13849
14876
  {
13850
14877
  name: "LocalCircuitSource",
13851
14878
  type: {
@@ -13970,7 +14997,40 @@ var types = [
13970
14997
  },
13971
14998
  {
13972
14999
  name: "bump",
15000
+ docs: [
15001
+ "PDA bump. Declared by hand rather than via the `#[bump]` macro (which appends the bump",
15002
+ "as the *final* struct field) so it keeps its original offset right after `status`.",
15003
+ "The recovery-reward fields below are appended *after* the bump, leaving the byte layout",
15004
+ "of every field up to and including `bump` identical to the pre-staking `MXEAccount` —",
15005
+ "old deserializers (including external user programs) decode the original prefix and",
15006
+ "harmlessly ignore the trailing fields."
15007
+ ],
13973
15008
  type: "u8"
15009
+ },
15010
+ {
15011
+ name: "current_epoch_recovery_rewards",
15012
+ docs: [
15013
+ "Running total of recovery-peer rewards accrued during `recovery_rewards_epoch`.",
15014
+ "Fed by the 20% slice of every computation/failure fee processed on this MXE;",
15015
+ "drained to zero by `claim_recovery_peer_fees` when recovery peers settle via",
15016
+ "`arcium_staking::finalize_recovery_epoch_rewards`. Same stale-epoch guard as",
15017
+ "`Cluster::current_epoch_total_rewards` — if peers don't settle before the epoch",
15018
+ "rolls over, new accruals are silently skipped until the pot is drained."
15019
+ ],
15020
+ type: "u64"
15021
+ },
15022
+ {
15023
+ name: "recovery_rewards_epoch",
15024
+ docs: [
15025
+ "Epoch that `current_epoch_recovery_rewards` is attributed to. Compared against the",
15026
+ "executing cluster's `last_updated_epoch` (the same proxy used by cluster rewards) to",
15027
+ "decide whether a new accrual is for the current round or a stale one."
15028
+ ],
15029
+ type: {
15030
+ defined: {
15031
+ name: "Epoch"
15032
+ }
15033
+ }
13974
15034
  }
13975
15035
  ]
13976
15036
  }
@@ -14305,9 +15365,7 @@ var types = [
14305
15365
  name: "NodeRef",
14306
15366
  docs: [
14307
15367
  "A reference to a node in the cluster.",
14308
- "The offset is to derive the Node Account.",
14309
- "The current_total_rewards is the total rewards the node has received so far in the current",
14310
- "epoch."
15368
+ "The offset is to derive the Node Account."
14311
15369
  ],
14312
15370
  type: {
14313
15371
  kind: "struct",
@@ -14317,11 +15375,22 @@ var types = [
14317
15375
  type: "u32"
14318
15376
  },
14319
15377
  {
14320
- name: "current_total_rewards",
15378
+ name: "_padding",
14321
15379
  docs: [
14322
- "Current total rewards the node has received in the current epoch in lamports."
15380
+ "Reserved padding occupying the 8 bytes that previously held `current_total_rewards: u64`",
15381
+ "(per-node reward tracking, now superseded by the cluster-level",
15382
+ "`current_epoch_total_rewards`). We keep these bytes rather than shrinking `NodeRef`",
15383
+ "because `nodes: Vec<NodeRef>` sits in the *middle* of the `Cluster` struct: removing the",
15384
+ "field would change the encoded element size and desync the borsh decode of every field",
15385
+ "after `nodes` for already-deployed accounts and external deserializers. Do not repurpose",
15386
+ "without a full account migration."
14323
15387
  ],
14324
- type: "u64"
15388
+ type: {
15389
+ array: [
15390
+ "u8",
15391
+ 8
15392
+ ]
15393
+ }
14325
15394
  },
14326
15395
  {
14327
15396
  name: "vote",
@@ -14759,7 +15828,27 @@ var types = [
14759
15828
  },
14760
15829
  {
14761
15830
  name: "bump",
15831
+ docs: [
15832
+ "PDA bump. Declared by hand rather than via the `#[bump]` macro (which appends the bump",
15833
+ "as the *final* struct field) so it keeps its original offset (76) right after",
15834
+ "`peer_offset`. `primary_stake_account` is appended *after* the bump, leaving the byte",
15835
+ "layout of every field up to and including `bump` identical to the pre-staking",
15836
+ "`RecoveryPeerAccount` — old deserializers decode the original prefix and harmlessly",
15837
+ "ignore the trailing field."
15838
+ ],
14762
15839
  type: "u8"
15840
+ },
15841
+ {
15842
+ name: "primary_stake_account",
15843
+ docs: [
15844
+ "The `PrimaryStakingAccount` (owned by `arcium_staking`) this recovery peer is bound",
15845
+ "to. Enforced at init time via an owner check so every recovery peer has skin in the",
15846
+ "game — the same stake-first model we already apply to `ArxNode`. Stored here so",
15847
+ "downstream instructions (and off-chain consumers) can look up the backing stake",
15848
+ "without re-validating the chain of accounts. Appended after `bump` to preserve the",
15849
+ "legacy on-chain layout (see the `bump` field comment)."
15850
+ ],
15851
+ type: "pubkey"
14763
15852
  }
14764
15853
  ]
14765
15854
  }
@@ -15308,6 +16397,26 @@ const MXE_RECOVERY_ACC_SEED = 'MxeRecoveryAccount';
15308
16397
  * @constant {string}
15309
16398
  */
15310
16399
  const RAW_CIRCUIT_ACC_SEED = 'ComputationDefinitionRaw';
16400
+ /**
16401
+ * Seed for RecoveryPeerAccount PDA.
16402
+ * @constant {string}
16403
+ */
16404
+ const RECOVERY_PEER_ACC_SEED = 'RecoveryPeerAccount';
16405
+ /**
16406
+ * Seed for Operator PDA.
16407
+ * @constant {string}
16408
+ */
16409
+ const OPERATOR_ACC_SEED = 'Operator';
16410
+ /**
16411
+ * Seed for FailureClaimAccountHeader PDA.
16412
+ * @constant {string}
16413
+ */
16414
+ const FAILURE_CLAIM_ACC_SEED = 'FailureClaimAccountHeader';
16415
+ /**
16416
+ * Seed for ArciumSignerAccount PDA.
16417
+ * @constant {string}
16418
+ */
16419
+ const ARCIUM_SIGNER_ACC_SEED = 'ArciumSignerAccount';
15311
16420
  /**
15312
16421
  * Maximum number of bytes that can be reallocated per instruction.
15313
16422
  * @constant {number}
@@ -15328,11 +16437,36 @@ const MAX_ACCOUNT_SIZE = 10485760;
15328
16437
  * @constant {number}
15329
16438
  */
15330
16439
  const MAX_EMBIGGEN_IX_PER_TX = 18;
16440
+ /**
16441
+ * Default number of upload transactions sent in parallel.
16442
+ * @constant {number}
16443
+ */
16444
+ const DEFAULT_UPLOAD_TX_BATCH_SIZE = 500;
15331
16445
  /**
15332
16446
  * Size of account discriminator in bytes.
15333
16447
  * @constant {number}
15334
16448
  */
15335
16449
  const DISCRIMINATOR_SIZE = 8;
16450
+ /**
16451
+ * Size of the bump field in a ComputationDefinitionRaw account.
16452
+ * @constant {number}
16453
+ */
16454
+ const RAW_CIRCUIT_ACCOUNT_BUMP_SIZE = 1;
16455
+ /**
16456
+ * Size of ComputationDefinitionRaw account metadata before circuit bytes.
16457
+ * @constant {number}
16458
+ */
16459
+ const RAW_CIRCUIT_ACCOUNT_HEADER_SIZE = DISCRIMINATOR_SIZE + RAW_CIRCUIT_ACCOUNT_BUMP_SIZE;
16460
+ /**
16461
+ * Maximum circuit bytes that fit in one ComputationDefinitionRaw account.
16462
+ * @constant {number}
16463
+ */
16464
+ const MAX_RAW_CIRCUIT_BYTES_PER_ACC = MAX_ACCOUNT_SIZE - RAW_CIRCUIT_ACCOUNT_HEADER_SIZE;
16465
+ /**
16466
+ * Maximum number of raw circuit accounts addressable by the u8 raw circuit index.
16467
+ * @constant {number}
16468
+ */
16469
+ const MAX_RAW_CIRCUIT_ACCOUNTS = 256;
15336
16470
  /**
15337
16471
  * Size of offset buffer in bytes (u32).
15338
16472
  * @constant {number}
@@ -15343,7 +16477,20 @@ const OFFSET_BUFFER_SIZE = 4;
15343
16477
  * @constant {number}
15344
16478
  */
15345
16479
  const COMP_DEF_OFFSET_SIZE = 4;
16480
+ /**
16481
+ * Maximum recovery peer slots supported by key recovery accounts.
16482
+ * @constant {number}
16483
+ */
16484
+ const MAX_RECOVERY_PEERS = 100;
16485
+ /**
16486
+ * Minimum recovery peers required for key recovery.
16487
+ * @constant {number}
16488
+ */
16489
+ const MIN_RECOVERY_PEERS = 4;
15346
16490
 
16491
+ const U64_SEED_SIZE = 8;
16492
+ const MAX_U8 = 0xff;
16493
+ const MAX_U32$1 = 0xffffffff;
15347
16494
  /**
15348
16495
  * Return the public key of the deployed Arcium program on Solana.
15349
16496
  * @returns Arcium program's public key.
@@ -15358,10 +16505,7 @@ function getArciumProgramId() {
15358
16505
  * @returns Derived computation account public key.
15359
16506
  */
15360
16507
  function getComputationAccAddress(clusterOffset, computationOffset) {
15361
- const clOffsetBuffer = Buffer.alloc(OFFSET_BUFFER_SIZE);
15362
- clOffsetBuffer.writeUInt32LE(clusterOffset, 0);
15363
- const seeds = [Buffer.from(COMPUTATION_ACC_SEED), clOffsetBuffer, computationOffset.toArrayLike(Buffer, 'le', 8)];
15364
- return generateArciumPDAFrom(seeds)[0];
16508
+ return findArciumPda([stringSeed(COMPUTATION_ACC_SEED), u32Seed(clusterOffset), u64Seed(computationOffset)]);
15365
16509
  }
15366
16510
  /**
15367
16511
  * Derive the mempool account address for a given cluster.
@@ -15369,10 +16513,7 @@ function getComputationAccAddress(clusterOffset, computationOffset) {
15369
16513
  * @returns Derived mempool account public key.
15370
16514
  */
15371
16515
  function getMempoolAccAddress(clusterOffset) {
15372
- const clOffsetBuffer = Buffer.alloc(OFFSET_BUFFER_SIZE);
15373
- clOffsetBuffer.writeUInt32LE(clusterOffset, 0);
15374
- const seeds = [Buffer.from(MEMPOOL_ACC_SEED), clOffsetBuffer];
15375
- return generateArciumPDAFrom(seeds)[0];
16516
+ return findArciumPda([stringSeed(MEMPOOL_ACC_SEED), u32Seed(clusterOffset)]);
15376
16517
  }
15377
16518
  /**
15378
16519
  * Derive the executing pool account address for a given cluster.
@@ -15380,26 +16521,21 @@ function getMempoolAccAddress(clusterOffset) {
15380
16521
  * @returns Derived executing pool account public key.
15381
16522
  */
15382
16523
  function getExecutingPoolAccAddress(clusterOffset) {
15383
- const clOffsetBuffer = Buffer.alloc(OFFSET_BUFFER_SIZE);
15384
- clOffsetBuffer.writeUInt32LE(clusterOffset, 0);
15385
- const seeds = [Buffer.from(EXEC_POOL_ACC_SEED), clOffsetBuffer];
15386
- return generateArciumPDAFrom(seeds)[0];
16524
+ return findArciumPda([stringSeed(EXEC_POOL_ACC_SEED), u32Seed(clusterOffset)]);
15387
16525
  }
15388
16526
  /**
15389
16527
  * Derive the fee pool account address.
15390
16528
  * @returns Derived fee pool account public key.
15391
16529
  */
15392
16530
  function getFeePoolAccAddress() {
15393
- const seeds = [Buffer.from(POOL_ACC_SEED)];
15394
- return generateArciumPDAFrom(seeds)[0];
16531
+ return findArciumPda([stringSeed(POOL_ACC_SEED)]);
15395
16532
  }
15396
16533
  /**
15397
16534
  * Derive the clock account address.
15398
16535
  * @returns Derived clock account public key.
15399
16536
  */
15400
16537
  function getClockAccAddress() {
15401
- const seeds = [Buffer.from(CLOCK_ACC_SEED)];
15402
- return generateArciumPDAFrom(seeds)[0];
16538
+ return findArciumPda([stringSeed(CLOCK_ACC_SEED)]);
15403
16539
  }
15404
16540
  /**
15405
16541
  * Derive the cluster account address for a given offset.
@@ -15407,10 +16543,7 @@ function getClockAccAddress() {
15407
16543
  * @returns Derived cluster account public key.
15408
16544
  */
15409
16545
  function getClusterAccAddress(clusterOffset) {
15410
- const offsetBuffer = Buffer.alloc(OFFSET_BUFFER_SIZE);
15411
- offsetBuffer.writeUInt32LE(clusterOffset, 0);
15412
- const seeds = [Buffer.from(CLUSTER_ACC_SEED), offsetBuffer];
15413
- return generateArciumPDAFrom(seeds)[0];
16546
+ return findArciumPda([stringSeed(CLUSTER_ACC_SEED), u32Seed(clusterOffset)]);
15414
16547
  }
15415
16548
  /**
15416
16549
  * Derive the ArxNode account address for a given offset.
@@ -15418,10 +16551,7 @@ function getClusterAccAddress(clusterOffset) {
15418
16551
  * @returns Derived ArxNode account public key.
15419
16552
  */
15420
16553
  function getArxNodeAccAddress(nodeOffset) {
15421
- const offsetBuffer = Buffer.alloc(OFFSET_BUFFER_SIZE);
15422
- offsetBuffer.writeUInt32LE(nodeOffset, 0);
15423
- const seeds = [Buffer.from(ARX_NODE_ACC_SEED), offsetBuffer];
15424
- return generateArciumPDAFrom(seeds)[0];
16554
+ return findArciumPda([stringSeed(ARX_NODE_ACC_SEED), u32Seed(nodeOffset)]);
15425
16555
  }
15426
16556
  /**
15427
16557
  * Derive the MXE account address for a given MXE program ID.
@@ -15429,8 +16559,7 @@ function getArxNodeAccAddress(nodeOffset) {
15429
16559
  * @returns Derived MXE account public key.
15430
16560
  */
15431
16561
  function getMXEAccAddress(mxeProgramId) {
15432
- const seeds = [Buffer.from(MXE_ACCOUNT_SEED), mxeProgramId.toBuffer()];
15433
- return generateArciumPDAFrom(seeds)[0];
16562
+ return findArciumPda([stringSeed(MXE_ACCOUNT_SEED), pubkeySeed(mxeProgramId)]);
15434
16563
  }
15435
16564
  /**
15436
16565
  * Derive the computation definition account address for a given MXE program ID and offset.
@@ -15439,10 +16568,7 @@ function getMXEAccAddress(mxeProgramId) {
15439
16568
  * @returns Derived computation definition account public key.
15440
16569
  */
15441
16570
  function getCompDefAccAddress(mxeProgramId, compDefOffset) {
15442
- const offsetBuffer = Buffer.alloc(OFFSET_BUFFER_SIZE);
15443
- offsetBuffer.writeUInt32LE(compDefOffset, 0);
15444
- const seeds = [Buffer.from(COMP_DEF_ACC_SEED), mxeProgramId.toBuffer(), offsetBuffer];
15445
- return generateArciumPDAFrom(seeds)[0];
16571
+ return findArciumPda([stringSeed(COMP_DEF_ACC_SEED), pubkeySeed(mxeProgramId), u32Seed(compDefOffset)]);
15446
16572
  }
15447
16573
  /**
15448
16574
  * Derive the recovery cluster account address for a given MXE program ID.
@@ -15450,8 +16576,7 @@ function getCompDefAccAddress(mxeProgramId, compDefOffset) {
15450
16576
  * @returns Derived recovery cluster account public key.
15451
16577
  */
15452
16578
  function getRecoveryClusterAccAddress(mxeProgramId) {
15453
- const seeds = [Buffer.from(RECOVERY_CLUSTER_ACC_SEED), mxeProgramId.toBuffer()];
15454
- return generateArciumPDAFrom(seeds)[0];
16579
+ return findArciumPda([stringSeed(RECOVERY_CLUSTER_ACC_SEED), pubkeySeed(mxeProgramId)]);
15455
16580
  }
15456
16581
  /**
15457
16582
  * Derive the MXE recovery account address for a key recovery session.
@@ -15459,22 +16584,52 @@ function getRecoveryClusterAccAddress(mxeProgramId) {
15459
16584
  * @returns Derived MXE recovery account public key.
15460
16585
  */
15461
16586
  function getMxeRecoveryAccAddress(originalMxeProgramId) {
15462
- const seeds = [Buffer.from(MXE_RECOVERY_ACC_SEED), originalMxeProgramId.toBuffer()];
15463
- return generateArciumPDAFrom(seeds)[0];
16587
+ return findArciumPda([stringSeed(MXE_RECOVERY_ACC_SEED), pubkeySeed(originalMxeProgramId)]);
16588
+ }
16589
+ /**
16590
+ * Derive the recovery peer account address for a given recovery peer offset.
16591
+ * @param peerOffset - Recovery peer offset as a u32 in `[0, 2^32 - 1]`.
16592
+ * @returns Derived recovery peer account public key.
16593
+ */
16594
+ function getRecoveryPeerAccAddress(peerOffset) {
16595
+ return findArciumPda([stringSeed(RECOVERY_PEER_ACC_SEED), u32Seed(peerOffset)]);
16596
+ }
16597
+ /**
16598
+ * Derive the operator account address for a given operator signer.
16599
+ * @param operatorSigner - Public key of the operator signer.
16600
+ * @returns Derived operator account public key.
16601
+ */
16602
+ function getOperatorAccAddress(operatorSigner) {
16603
+ return findArciumPda([stringSeed(OPERATOR_ACC_SEED), pubkeySeed(operatorSigner)]);
16604
+ }
16605
+ /**
16606
+ * Derive the failure claim account address for a given MXE program and computation offset.
16607
+ * @param mxeProgramId - Public key of the MXE program.
16608
+ * @param computationOffset - Computation offset as an anchor.BN in `[0, 2^64 - 1]`.
16609
+ * @returns Derived failure claim account public key.
16610
+ */
16611
+ function getFailureClaimAccAddress(mxeProgramId, computationOffset) {
16612
+ return findArciumPda([stringSeed(FAILURE_CLAIM_ACC_SEED), pubkeySeed(mxeProgramId), u64Seed(computationOffset)]);
16613
+ }
16614
+ /**
16615
+ * Derive the Arcium signer account address used by an MXE program when invoking the Arcium
16616
+ * program. Unlike most other helpers in this module, this PDA is derived under the MXE
16617
+ * program ID (the caller), not the Arcium program ID - Arcium verifies the seed via
16618
+ * `seeds::program = _mxe_program`.
16619
+ * @param mxeProgramId - Public key of the MXE program that owns the signer PDA.
16620
+ * @returns Derived Arcium signer account public key.
16621
+ */
16622
+ function getArciumSignerAccAddress(mxeProgramId) {
16623
+ return findPda(mxeProgramId, [stringSeed(ARCIUM_SIGNER_ACC_SEED)]);
15464
16624
  }
15465
16625
  /**
15466
16626
  * Derive the raw circuit account address for a given computation definition and index.
15467
16627
  * @param compDefPubkey - Public key of the computation definition account.
15468
- * @param rawCircuitIndex - Index of the raw circuit account (0-based).
16628
+ * @param rawCircuitIndex - Index of the raw circuit account as a u8 in `[0, 255]`.
15469
16629
  * @returns Derived raw circuit account public key.
15470
16630
  */
15471
16631
  function getRawCircuitAccAddress(compDefPubkey, rawCircuitIndex) {
15472
- const seeds = [
15473
- Buffer.from(RAW_CIRCUIT_ACC_SEED),
15474
- compDefPubkey.toBuffer(),
15475
- Buffer.from([rawCircuitIndex]),
15476
- ];
15477
- return generateArciumPDAFrom(seeds)[0];
16632
+ return findArciumPda([stringSeed(RAW_CIRCUIT_ACC_SEED), pubkeySeed(compDefPubkey), u8Seed(rawCircuitIndex)]);
15478
16633
  }
15479
16634
  /**
15480
16635
  * Derive the address lookup table address for an MXE program.
@@ -15484,120 +16639,149 @@ function getRawCircuitAccAddress(compDefPubkey, rawCircuitIndex) {
15484
16639
  */
15485
16640
  function getLookupTableAddress(mxeProgramId, lutOffset) {
15486
16641
  const mxeAccount = getMXEAccAddress(mxeProgramId);
15487
- const lutIndexBuffer = lutOffset.toArrayLike(Buffer, 'le', 8);
15488
- const seeds = [mxeAccount.toBuffer(), lutIndexBuffer];
15489
- return web3_js.PublicKey.findProgramAddressSync(seeds, web3_js.AddressLookupTableProgram.programId)[0];
16642
+ return findPda(web3_js.AddressLookupTableProgram.programId, [pubkeySeed(mxeAccount), u64Seed(lutOffset)]);
15490
16643
  }
15491
- /**
15492
- * Generate a program-derived address (PDA) from the provided seeds and the Arcium program ID.
15493
- * @param seeds - Array of Buffer seeds used for PDA derivation.
15494
- * @returns Tuple containing the derived public key and the bump seed.
15495
- */
15496
- function generateArciumPDAFrom(seeds) {
15497
- const programId = getArciumProgramId();
15498
- return web3_js.PublicKey.findProgramAddressSync(seeds, programId);
16644
+ function stringSeed(value) {
16645
+ return Buffer.from(value);
16646
+ }
16647
+ function u8Seed(value) {
16648
+ assertIntegerInRange(value, 0, MAX_U8, 'u8 seed');
16649
+ return Buffer.from([value]);
16650
+ }
16651
+ function u32Seed(value) {
16652
+ assertIntegerInRange(value, 0, MAX_U32$1, 'u32 seed');
16653
+ const buffer = Buffer.alloc(OFFSET_BUFFER_SIZE);
16654
+ buffer.writeUInt32LE(value, 0);
16655
+ return buffer;
16656
+ }
16657
+ function u64Seed(value) {
16658
+ if (value.isNeg() || value.byteLength() > U64_SEED_SIZE) {
16659
+ throw new RangeError(`u64 seed must be between 0 and 18446744073709551615 (got ${value.toString()})`);
16660
+ }
16661
+ return value.toArrayLike(Buffer, 'le', U64_SEED_SIZE);
16662
+ }
16663
+ function pubkeySeed(value) {
16664
+ return value.toBuffer();
16665
+ }
16666
+ function findArciumPda(seeds) {
16667
+ return findPda(getArciumProgramId(), seeds);
16668
+ }
16669
+ function findPda(programId, seeds) {
16670
+ return web3_js.PublicKey.findProgramAddressSync(seeds, programId)[0];
16671
+ }
16672
+ function assertIntegerInRange(value, min, max, label) {
16673
+ if (!Number.isInteger(value) || value < min || value > max) {
16674
+ throw new RangeError(`${label} must be an integer between ${min} and ${max} (got ${value})`);
16675
+ }
15499
16676
  }
15500
16677
 
15501
- const TINY_MEMPOOL_ACC_NAME = 'tinyMempool';
15502
- const TINY_MEMPOOL_DISCRIMINATOR = [
15503
- 176,
15504
- 33,
15505
- 67,
15506
- 108,
15507
- 73,
15508
- 135,
15509
- 110,
15510
- 166,
15511
- ];
15512
- const TINY_EXECPOOL_ACC_NAME = 'tinyExecPool';
15513
- const TINY_EXECPOOL_DISCRIMINATOR = [
15514
- 80,
15515
- 245,
15516
- 5,
15517
- 90,
15518
- 154,
15519
- 189,
15520
- 190,
15521
- 172,
15522
- ];
15523
- const SMALL_MEMPOOL_ACC_NAME = 'smallMempool';
15524
- const SMALL_MEMPOOL_DISCRIMINATOR = [
15525
- 123,
15526
- 153,
15527
- 151,
15528
- 118,
15529
- 126,
15530
- 71,
15531
- 73,
15532
- 92,
15533
- ];
15534
- const SMALL_EXECPOOL_ACC_NAME = 'smallExecPool';
15535
- const SMALL_EXECPOOL_DISCRIMINATOR = [
15536
- 37,
15537
- 147,
15538
- 249,
15539
- 253,
15540
- 217,
15541
- 136,
15542
- 3,
15543
- 87,
16678
+ // Names are validated against the IDL account-name union at compile time, so a
16679
+ // typo or stale tier fails `tsc` rather than only throwing at load.
16680
+ const MEMPOOL_DECODER_ACCOUNT_NAMES = [
16681
+ 'tinyMempool',
16682
+ 'smallMempool',
16683
+ 'mediumMempool',
16684
+ 'largeMempool',
15544
16685
  ];
15545
- const MEDIUM_MEMPOOL_ACC_NAME = 'mediumMempool';
15546
- const MEDIUM_MEMPOOL_DISCRIMINATOR = [
15547
- 10,
15548
- 249,
15549
- 58,
15550
- 39,
15551
- 255,
15552
- 231,
15553
- 199,
15554
- 168,
16686
+ const EXECUTING_POOL_DECODER_ACCOUNT_NAMES = [
16687
+ 'tinyExecPool',
16688
+ 'smallExecPool',
16689
+ 'mediumExecPool',
16690
+ 'largeExecPool',
15555
16691
  ];
15556
- const MEDIUM_EXECPOOL_ACC_NAME = 'mediumExecPool';
15557
- const MEDIUM_EXECPOOL_DISCRIMINATOR = [
15558
- 97,
15559
- 117,
15560
- 128,
15561
- 202,
15562
- 213,
15563
- 76,
15564
- 5,
15565
- 163,
15566
- ];
15567
- const LARGE_MEMPOOL_ACC_NAME = 'largeMempool';
15568
- const LARGE_MEMPOOL_DISCRIMINATOR = [
15569
- 16,
15570
- 168,
15571
- 90,
15572
- 235,
15573
- 249,
15574
- 207,
15575
- 73,
15576
- 223,
15577
- ];
15578
- const LARGE_EXECPOOL_ACC_NAME = 'largeExecPool';
15579
- const LARGE_EXECPOOL_DISCRIMINATOR = [
15580
- 147,
15581
- 145,
15582
- 148,
15583
- 170,
15584
- 30,
15585
- 13,
15586
- 43,
15587
- 216,
15588
- ];
15589
- const MEMPOOL_DISCRIMINATOR_MAP = {
15590
- [TINY_MEMPOOL_DISCRIMINATOR.toString()]: TINY_MEMPOOL_ACC_NAME,
15591
- [SMALL_MEMPOOL_DISCRIMINATOR.toString()]: SMALL_MEMPOOL_ACC_NAME,
15592
- [MEDIUM_MEMPOOL_DISCRIMINATOR.toString()]: MEDIUM_MEMPOOL_ACC_NAME,
15593
- [LARGE_MEMPOOL_DISCRIMINATOR.toString()]: LARGE_MEMPOOL_ACC_NAME,
15594
- };
15595
- const EXECPOOL_DISCRIMINATOR_MAP = {
15596
- [TINY_EXECPOOL_DISCRIMINATOR.toString()]: TINY_EXECPOOL_ACC_NAME,
15597
- [SMALL_EXECPOOL_DISCRIMINATOR.toString()]: SMALL_EXECPOOL_ACC_NAME,
15598
- [MEDIUM_EXECPOOL_DISCRIMINATOR.toString()]: MEDIUM_EXECPOOL_ACC_NAME,
15599
- [LARGE_EXECPOOL_DISCRIMINATOR.toString()]: LARGE_EXECPOOL_ACC_NAME,
15600
- };
16692
+ function discriminatorKey(discriminator) {
16693
+ return Buffer.from(discriminator).toString('hex');
16694
+ }
16695
+ // Discriminator bytes are read from the IDL at load time rather than pinned, so the
16696
+ // decoder tracks the program's account layout as the single source of truth; a
16697
+ // missing or renamed tier throws here instead of silently misrouting at runtime.
16698
+ const accountDiscriminatorCoder = new anchor.BorshCoder(anchor.convertIdlToCamelCase(ARCIUM_IDL)).accounts;
16699
+ function buildPoolAccountMap(accountNames) {
16700
+ return new Map(accountNames.map((name) => [
16701
+ discriminatorKey(accountDiscriminatorCoder.accountDiscriminator(name)),
16702
+ name,
16703
+ ]));
16704
+ }
16705
+ const MEMPOOL_ACCOUNT_BY_DISCRIMINATOR = buildPoolAccountMap(MEMPOOL_DECODER_ACCOUNT_NAMES);
16706
+ const EXECUTING_POOL_ACCOUNT_BY_DISCRIMINATOR = buildPoolAccountMap(EXECUTING_POOL_DECODER_ACCOUNT_NAMES);
16707
+ function getPoolAccountNameByDiscriminator(accountData, accountsByDiscriminator, kind) {
16708
+ if (accountData.length < DISCRIMINATOR_SIZE) {
16709
+ throw new Error(`${kind} account data is shorter than discriminator size`);
16710
+ }
16711
+ const key = discriminatorKey(accountData.subarray(0, DISCRIMINATOR_SIZE));
16712
+ const accountName = accountsByDiscriminator.get(key);
16713
+ if (accountName === undefined) {
16714
+ throw new Error(`Unknown ${kind} account discriminator: ${key}`);
16715
+ }
16716
+ return accountName;
16717
+ }
16718
+ /** @internal */
16719
+ function getMempoolAccountNameByDiscriminator(accountData) {
16720
+ return getPoolAccountNameByDiscriminator(accountData, MEMPOOL_ACCOUNT_BY_DISCRIMINATOR, 'mempool');
16721
+ }
16722
+ /** @internal */
16723
+ function getExecutingPoolAccountNameByDiscriminator(accountData) {
16724
+ return getPoolAccountNameByDiscriminator(accountData, EXECUTING_POOL_ACCOUNT_BY_DISCRIMINATOR, 'executing pool');
16725
+ }
16726
+
16727
+ const MAX_U32 = 0xffffffff;
16728
+ /**
16729
+ * Mirrors the on-chain `init_mxe_part2` recovery-peer bounds before building the instruction.
16730
+ * @internal
16731
+ */
16732
+ function assertValidRecoveryPeers(recoveryPeers) {
16733
+ if (recoveryPeers.length > MAX_RECOVERY_PEERS) {
16734
+ throw new Error(`recoveryPeers must have at most ${MAX_RECOVERY_PEERS} elements (got ${recoveryPeers.length})`);
16735
+ }
16736
+ let nonZeroPeers = 0;
16737
+ for (let index = 0; index < recoveryPeers.length; index += 1) {
16738
+ const peer = recoveryPeers[index];
16739
+ if (!Number.isInteger(peer) || peer < 0 || peer > MAX_U32) {
16740
+ throw new RangeError(`recoveryPeers[${index}] must be an integer in [0, ${MAX_U32}] (got ${peer})`);
16741
+ }
16742
+ if (peer !== 0) {
16743
+ nonZeroPeers += 1;
16744
+ }
16745
+ }
16746
+ if (nonZeroPeers > 0 && nonZeroPeers < MIN_RECOVERY_PEERS) {
16747
+ throw new Error(`recoveryPeers must have 0 or at least ${MIN_RECOVERY_PEERS} non-zero offsets (found ${nonZeroPeers})`);
16748
+ }
16749
+ }
16750
+ /** @internal */
16751
+ function normalizeRecoveryPeers(recoveryPeers) {
16752
+ assertValidRecoveryPeers(recoveryPeers);
16753
+ const paddedRecoveryPeers = [...recoveryPeers];
16754
+ while (paddedRecoveryPeers.length < MAX_RECOVERY_PEERS) {
16755
+ paddedRecoveryPeers.push(0);
16756
+ }
16757
+ return paddedRecoveryPeers;
16758
+ }
16759
+
16760
+ /** @internal */
16761
+ function getRawCircuitAccountCount(rawCircuitByteLength) {
16762
+ if (!Number.isInteger(rawCircuitByteLength) || rawCircuitByteLength < 0) {
16763
+ throw new RangeError(`rawCircuit byte length must be a non-negative integer (got ${rawCircuitByteLength})`);
16764
+ }
16765
+ const accountCount = Math.ceil(rawCircuitByteLength / MAX_RAW_CIRCUIT_BYTES_PER_ACC);
16766
+ if (accountCount > MAX_RAW_CIRCUIT_ACCOUNTS) {
16767
+ throw new RangeError(`Raw circuit is too large for on-chain upload: requires ${accountCount} raw circuit accounts, maximum is ${MAX_RAW_CIRCUIT_ACCOUNTS}`);
16768
+ }
16769
+ return accountCount;
16770
+ }
16771
+ /** @internal */
16772
+ function assertRawCircuitUploadLength(rawCircuitByteLength, declaredCircuitByteLength, circuitName) {
16773
+ if (!Number.isInteger(rawCircuitByteLength) || rawCircuitByteLength < 0) {
16774
+ throw new RangeError(`rawCircuit byte length must be a non-negative integer (got ${rawCircuitByteLength})`);
16775
+ }
16776
+ if (!Number.isInteger(declaredCircuitByteLength) || declaredCircuitByteLength <= 0) {
16777
+ throw new RangeError(`Declared circuit byte length for ${circuitName} must be a positive integer (got ${declaredCircuitByteLength})`);
16778
+ }
16779
+ if (rawCircuitByteLength !== declaredCircuitByteLength) {
16780
+ throw new RangeError(`Raw circuit byte length for ${circuitName} must match the computation definition: got ${rawCircuitByteLength}, expected ${declaredCircuitByteLength}`);
16781
+ }
16782
+ }
16783
+
16784
+ const { BN } = anchor;
15601
16785
  /**
15602
16786
  * Fetch and decode the mempool account info for any mempool account size.
15603
16787
  * @param provider - Anchor provider to use for fetching accounts.
@@ -15606,15 +16790,8 @@ const EXECPOOL_DISCRIMINATOR_MAP = {
15606
16790
  * @throws Error if the account cannot be fetched or the discriminator is unknown.
15607
16791
  */
15608
16792
  async function getMempoolAccInfo(provider, mempoolAccPubkey) {
15609
- const accData = await provider.connection.getAccountInfo(mempoolAccPubkey);
15610
- if (accData === null) {
15611
- throw new Error(`Failed to fetch mempool account ${mempoolAccPubkey.toBase58()}`);
15612
- }
15613
- const discriminator = Array.from(accData.data.subarray(0, DISCRIMINATOR_SIZE)).toString();
15614
- const accName = MEMPOOL_DISCRIMINATOR_MAP[discriminator];
15615
- if (accName === undefined) {
15616
- throw new Error(`Unknown mempool account discriminator: ${discriminator}`);
15617
- }
16793
+ const accData = requireAccountInfo(await provider.connection.getAccountInfo(mempoolAccPubkey), mempoolAccPubkey, 'mempool');
16794
+ const accName = getMempoolAccountNameByDiscriminator(accData.data);
15618
16795
  const program = getArciumProgram(provider);
15619
16796
  return program.coder.accounts.decode(accName, accData.data);
15620
16797
  }
@@ -15626,18 +16803,17 @@ async function getMempoolAccInfo(provider, mempoolAccPubkey) {
15626
16803
  * @throws Error if the account cannot be fetched or the discriminator is unknown.
15627
16804
  */
15628
16805
  async function getExecutingPoolAccInfo(provider, executingPoolAccPubkey) {
15629
- const accData = await provider.connection.getAccountInfo(executingPoolAccPubkey);
15630
- if (accData === null) {
15631
- throw new Error(`Failed to fetch executing pool account ${executingPoolAccPubkey.toBase58()}`);
15632
- }
15633
- const discriminator = Array.from(accData.data.subarray(0, DISCRIMINATOR_SIZE)).toString();
15634
- const accName = EXECPOOL_DISCRIMINATOR_MAP[discriminator];
15635
- if (accName === undefined) {
15636
- throw new Error(`Unknown executing pool account discriminator: ${discriminator}`);
15637
- }
16806
+ const accData = requireAccountInfo(await provider.connection.getAccountInfo(executingPoolAccPubkey), executingPoolAccPubkey, 'executing pool');
16807
+ const accName = getExecutingPoolAccountNameByDiscriminator(accData.data);
15638
16808
  const program = getArciumProgram(provider);
15639
16809
  return program.coder.accounts.decode(accName, accData.data);
15640
16810
  }
16811
+ function requireAccountInfo(accountInfo, pubkey, label) {
16812
+ if (accountInfo === null) {
16813
+ throw new Error(`Failed to fetch ${label} account ${pubkey.toBase58()}`);
16814
+ }
16815
+ return accountInfo;
16816
+ }
15641
16817
  /**
15642
16818
  * Return all computation references in the mempool for a given account.
15643
16819
  * Only non-stake computations are included.
@@ -15681,15 +16857,15 @@ async function getComputationsInMempool(arciumProgram, address) {
15681
16857
  async function getMempoolPriorityFeeStats(arciumProgram, mempoolAddress) {
15682
16858
  const refs = await getComputationsInMempool(arciumProgram, mempoolAddress);
15683
16859
  if (refs.length === 0) {
15684
- const zero = new anchor__namespace.BN(0);
16860
+ const zero = new BN(0);
15685
16861
  return { mean: zero, median: zero, min: zero, max: zero, count: 0 };
15686
16862
  }
15687
16863
  const fees = refs.map(ref => ref.priorityFee).sort((a, b) => a.cmp(b));
15688
- const sum = fees.reduce((acc, fee) => acc.add(fee), new anchor__namespace.BN(0));
15689
- const mean = sum.div(new anchor__namespace.BN(fees.length));
16864
+ const sum = fees.reduce((acc, fee) => acc.add(fee), new BN(0));
16865
+ const mean = sum.div(new BN(fees.length));
15690
16866
  const mid = Math.floor(fees.length / 2);
15691
16867
  const median = fees.length % 2 === 0
15692
- ? fees[mid - 1].add(fees[mid]).div(new anchor__namespace.BN(2))
16868
+ ? fees[mid - 1].add(fees[mid]).div(new BN(2))
15693
16869
  : fees[mid];
15694
16870
  return {
15695
16871
  mean,
@@ -15762,11 +16938,12 @@ function getCircuitState(circuitSource) {
15762
16938
  * @param mxeProgramId - Public key of the MXE program.
15763
16939
  * @param rawCircuit - Raw circuit data as a Uint8Array.
15764
16940
  * @param logging - Whether to log progress (default: true).
15765
- * @param chunkSize - Number of upload transactions to send in parallel (default: 500).
16941
+ * @param chunkSize - Number of upload transactions to send in parallel. Defaults to
16942
+ * {@link DEFAULT_UPLOAD_TX_BATCH_SIZE}.
15766
16943
  * @param confirmOptions - Transaction confirmation options.
15767
16944
  * @returns Array of transaction signatures for all upload and finalize transactions.
15768
16945
  */
15769
- async function uploadCircuit(provider, circuitName, mxeProgramId, rawCircuit, logging = true, chunkSize = 500, confirmOptions) {
16946
+ async function uploadCircuit(provider, circuitName, mxeProgramId, rawCircuit, logging = true, chunkSize = DEFAULT_UPLOAD_TX_BATCH_SIZE, confirmOptions) {
15770
16947
  const compDefAccInfo = getCompDefAccInfo(circuitName, mxeProgramId);
15771
16948
  const program = getArciumProgram(provider);
15772
16949
  const compDefAcc = await program.account.computationDefinitionAccount.fetch(compDefAccInfo.pubkey);
@@ -15776,12 +16953,12 @@ async function uploadCircuit(provider, circuitName, mxeProgramId, rawCircuit, lo
15776
16953
  optionalLog(logging, `Circuit ${circuitName} skipped: ${state}`);
15777
16954
  return [];
15778
16955
  }
15779
- // 9 = 8-byte discriminator + 1-byte bump for ComputationDefinitionRaw account
15780
- const numAccs = Math.ceil(rawCircuit.length / (MAX_ACCOUNT_SIZE - 9));
16956
+ assertRawCircuitUploadLength(rawCircuit.length, compDefAcc.definition.circuitLen, circuitName);
16957
+ const numAccs = getRawCircuitAccountCount(rawCircuit.length);
15781
16958
  const sigs = [];
15782
16959
  const uploadPromises = [];
15783
16960
  for (let i = 0; i < numAccs; i++) {
15784
- uploadPromises.push(uploadToCircuitAcc(provider, program, rawCircuit.subarray(i * (MAX_ACCOUNT_SIZE - 9), (i + 1) * (MAX_ACCOUNT_SIZE - 9)), i, compDefAccInfo, mxeProgramId, logging, chunkSize, confirmOptions));
16961
+ uploadPromises.push(uploadToCircuitAcc(provider, program, rawCircuit.subarray(i * MAX_RAW_CIRCUIT_BYTES_PER_ACC, (i + 1) * MAX_RAW_CIRCUIT_BYTES_PER_ACC), i, compDefAccInfo, mxeProgramId, logging, chunkSize, confirmOptions));
15785
16962
  }
15786
16963
  sigs.push(...(await Promise.all(uploadPromises)).flat());
15787
16964
  const finalizeCompDefTx = await buildFinalizeCompDefTx(provider, compDefAccInfo.offset, mxeProgramId);
@@ -15797,8 +16974,6 @@ async function uploadCircuit(provider, circuitName, mxeProgramId, rawCircuit, lo
15797
16974
  */
15798
16975
  async function buildFinalizeCompDefTx(provider, compDefOffset, mxeProgramId) {
15799
16976
  const program = getArciumProgram(provider);
15800
- const compDefOffsetBuffer = Buffer.alloc(OFFSET_BUFFER_SIZE);
15801
- compDefOffsetBuffer.writeUInt32LE(compDefOffset, 0);
15802
16977
  return program.methods
15803
16978
  .finalizeComputationDefinition(compDefOffset, mxeProgramId)
15804
16979
  .accounts({
@@ -15806,12 +16981,11 @@ async function buildFinalizeCompDefTx(provider, compDefOffset, mxeProgramId) {
15806
16981
  })
15807
16982
  .transaction();
15808
16983
  }
15809
- async function uploadToCircuitAcc(provider, program, rawCircuitPart, rawCircuitIndex, compDefAccInfo, mxeProgramId, shouldLog = true, chunkSize = 500, confirmOptions) {
16984
+ async function uploadToCircuitAcc(provider, program, rawCircuitPart, rawCircuitIndex, compDefAccInfo, mxeProgramId, shouldLog = true, chunkSize = DEFAULT_UPLOAD_TX_BATCH_SIZE, confirmOptions) {
15810
16985
  const rawCircuitPda = getRawCircuitAccAddress(compDefAccInfo.pubkey, rawCircuitIndex);
15811
16986
  const existingAcc = await provider.connection.getAccountInfo(rawCircuitPda);
15812
16987
  // Skip entirely if account exists with correct size (pre-seeded at genesis or already uploaded)
15813
- // Account layout: 8-byte discriminator + 1-byte bump + circuit data
15814
- const requiredAccountSize = rawCircuitPart.length + 9;
16988
+ const requiredAccountSize = rawCircuitPart.length + RAW_CIRCUIT_ACCOUNT_HEADER_SIZE;
15815
16989
  if (existingAcc !== null && existingAcc.data.length >= requiredAccountSize) {
15816
16990
  optionalLog(shouldLog, `Raw circuit acc ${rawCircuitIndex} already exists with sufficient size, skipping`);
15817
16991
  return [];
@@ -15945,18 +17119,8 @@ function getArciumProgram(provider) {
15945
17119
  */
15946
17120
  function getCompDefAccInfo(circuitName, mxeProgramId) {
15947
17121
  const offset = getCompDefAccOffset(circuitName);
15948
- const pda = getCompDefAccPDA(getArciumProgramId(), mxeProgramId, offset);
15949
- return { pubkey: pda, offset: Buffer.from(offset).readUInt32LE(0) };
15950
- }
15951
- /**
15952
- * Return the PDA for a computation definition account, given the program ID, MXE program ID, and offset.
15953
- * @param arciumProgramId - Public key of the Arcium program.
15954
- * @param mxeProgramId - Public key of the MXE program.
15955
- * @param offset - Offset as a Uint8Array.
15956
- * @returns PDA for the computation definition account.
15957
- */
15958
- function getCompDefAccPDA(arciumProgramId, mxeProgramId, offset) {
15959
- return anchor__namespace.web3.PublicKey.findProgramAddressSync([Buffer.from(COMP_DEF_ACC_SEED, 'utf-8'), mxeProgramId.toBuffer(), offset], arciumProgramId)[0];
17122
+ const offsetNumber = Buffer.from(offset).readUInt32LE(0);
17123
+ return { pubkey: getCompDefAccAddress(mxeProgramId, offsetNumber), offset: offsetNumber };
15960
17124
  }
15961
17125
  /**
15962
17126
  * Initialize an MXE (part 1). Due to Solana's 10KB per-instruction allocation limit,
@@ -15964,13 +17128,15 @@ function getCompDefAccPDA(arciumProgramId, mxeProgramId, offset) {
15964
17128
  * Call initMxePart2 afterwards to finish allocation and add keygen to mempool.
15965
17129
  * @param provider - Anchor provider to use for transactions.
15966
17130
  * @param mxeProgramId - Public key to use as the MXE program ID.
17131
+ * @param recoveryPeers - Array of 100 node offsets for recovery peers (0 for unused slots).
15967
17132
  * @param confirmOptions - Transaction confirmation options.
15968
17133
  * @returns Transaction signature.
15969
17134
  */
15970
- async function initMxePart1(provider, mxeProgramId, confirmOptions) {
17135
+ async function initMxePart1(provider, mxeProgramId, recoveryPeers, confirmOptions) {
15971
17136
  const program = getArciumProgram(provider);
17137
+ const paddedRecoveryPeers = normalizeRecoveryPeers(recoveryPeers);
15972
17138
  const tx = await program.methods
15973
- .initMxePart1()
17139
+ .initMxePart1(paddedRecoveryPeers)
15974
17140
  .accountsPartial({
15975
17141
  signer: provider.publicKey,
15976
17142
  mxeProgram: mxeProgramId,
@@ -15985,9 +17151,12 @@ async function initMxePart1(provider, mxeProgramId, confirmOptions) {
15985
17151
  * @param provider - Anchor provider to use for transactions.
15986
17152
  * @param clusterOffset - Cluster offset to associate with the MXE.
15987
17153
  * @param mxeProgramId - Public key to use as the MXE program ID.
15988
- * @param recoveryPeers - Array of 100 node offsets for recovery peers (0 for unused slots).
15989
17154
  * @param keygenOffset - Computation offset for the keygen computation.
15990
17155
  * @param keyRecoveryInitOffset - Computation offset for the key_recovery_init computation.
17156
+ * @param recoveryPeers - Recovery peer node offsets. Slots set to 0 are treated as unused.
17157
+ * The non-zero count must be either 0 (recovery disabled) or at least
17158
+ * `MIN_RECOVERY_PEERS` (4). The array is padded with zeros up to
17159
+ * `MAX_RECOVERY_PEERS` (100); passing more than that throws.
15991
17160
  * @param lutOffset - Lookup table offset for the MXE's address lookup table.
15992
17161
  * @param mxeAuthority - Optional authority for the MXE (defaults to provider.publicKey).
15993
17162
  * @param confirmOptions - Transaction confirmation options.
@@ -15995,16 +17164,8 @@ async function initMxePart1(provider, mxeProgramId, confirmOptions) {
15995
17164
  */
15996
17165
  async function initMxePart2(provider, clusterOffset, mxeProgramId, keygenOffset, keyRecoveryInitOffset, recoveryPeers, lutOffset, mxeAuthority, confirmOptions) {
15997
17166
  const program = getArciumProgram(provider);
15998
- // Ensure recoveryPeers has exactly 100 elements
15999
- const paddedRecoveryPeers = [...recoveryPeers];
16000
- while (paddedRecoveryPeers.length < 100) {
16001
- paddedRecoveryPeers.push(0);
16002
- }
16003
- if (paddedRecoveryPeers.length > 100) {
16004
- throw new Error('recoveryPeers must have at most 100 elements');
16005
- }
16006
17167
  const tx = await program.methods
16007
- .initMxePart2(clusterOffset, mxeProgramId, paddedRecoveryPeers, keygenOffset, keyRecoveryInitOffset, lutOffset)
17168
+ .initMxePart2(clusterOffset, keygenOffset, keyRecoveryInitOffset, lutOffset)
16008
17169
  .accountsPartial({
16009
17170
  signer: provider.publicKey,
16010
17171
  mxeProgram: mxeProgramId,
@@ -16015,6 +17176,14 @@ async function initMxePart2(provider, clusterOffset, mxeProgramId, keygenOffset,
16015
17176
  .transaction();
16016
17177
  return signAndSendWithBlockhash(provider, tx, await provider.connection.getLatestBlockhash({ commitment: confirmOptions?.commitment || 'confirmed' }), confirmOptions);
16017
17178
  }
17179
+ /**
17180
+ * Reclaim the rent locked in a finished computation account.
17181
+ * @param provider - Anchor provider to use for transactions.
17182
+ * @param clusterOffset - Offset of the cluster that ran the computation.
17183
+ * @param computationOffset - Offset of the computation whose rent is being claimed.
17184
+ * @param confirmOptions - Transaction confirmation options.
17185
+ * @returns Transaction signature.
17186
+ */
16018
17187
  async function claimComputationRent(provider, clusterOffset, computationOffset, confirmOptions) {
16019
17188
  const program = getArciumProgram(provider);
16020
17189
  const tx = await program.methods
@@ -16163,6 +17332,7 @@ exports.getArciumAccountBaseSeed = getArciumAccountBaseSeed;
16163
17332
  exports.getArciumEnv = getArciumEnv;
16164
17333
  exports.getArciumProgram = getArciumProgram;
16165
17334
  exports.getArciumProgramId = getArciumProgramId;
17335
+ exports.getArciumSignerAccAddress = getArciumSignerAccAddress;
16166
17336
  exports.getArxNodeAccAddress = getArxNodeAccAddress;
16167
17337
  exports.getCircuitState = getCircuitState;
16168
17338
  exports.getClockAccAddress = getClockAccAddress;
@@ -16173,6 +17343,7 @@ exports.getComputationAccAddress = getComputationAccAddress;
16173
17343
  exports.getComputationsInMempool = getComputationsInMempool;
16174
17344
  exports.getExecutingPoolAccAddress = getExecutingPoolAccAddress;
16175
17345
  exports.getExecutingPoolAccInfo = getExecutingPoolAccInfo;
17346
+ exports.getFailureClaimAccAddress = getFailureClaimAccAddress;
16176
17347
  exports.getFeePoolAccAddress = getFeePoolAccAddress;
16177
17348
  exports.getLookupTableAddress = getLookupTableAddress;
16178
17349
  exports.getMXEAccAddress = getMXEAccAddress;
@@ -16182,8 +17353,10 @@ exports.getMempoolAccAddress = getMempoolAccAddress;
16182
17353
  exports.getMempoolAccInfo = getMempoolAccInfo;
16183
17354
  exports.getMempoolPriorityFeeStats = getMempoolPriorityFeeStats;
16184
17355
  exports.getMxeRecoveryAccAddress = getMxeRecoveryAccAddress;
17356
+ exports.getOperatorAccAddress = getOperatorAccAddress;
16185
17357
  exports.getRawCircuitAccAddress = getRawCircuitAccAddress;
16186
17358
  exports.getRecoveryClusterAccAddress = getRecoveryClusterAccAddress;
17359
+ exports.getRecoveryPeerAccAddress = getRecoveryPeerAccAddress;
16187
17360
  exports.initMxePart1 = initMxePart1;
16188
17361
  exports.initMxePart2 = initMxePart2;
16189
17362
  exports.isNullRef = isNullRef;