@agent-fuel/sdk 0.1.1 → 0.3.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { BN, AnchorError, Program, AnchorProvider, Wallet } from '@coral-xyz/anchor';
2
- import { PublicKey, TransactionInstruction, SystemProgram, Connection } from '@solana/web3.js';
1
+ import { BN, AnchorError, AnchorProvider, Wallet, Program } from '@coral-xyz/anchor';
2
+ import { PublicKey, TransactionInstruction, SystemProgram, Transaction, sendAndConfirmTransaction, Connection } from '@solana/web3.js';
3
3
 
4
4
  // src/client.ts
5
5
  var TOKEN_PROGRAM_ID = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
@@ -61,7 +61,8 @@ function decodeCreditVault(pubkey, raw) {
61
61
  balance: total_deposited - total_withdrawn - total_spent + total_claimed,
62
62
  frozen: raw.frozen,
63
63
  created_slot: bnToNum(raw.createdSlot),
64
- last_active_slot: bnToNum(raw.lastActiveSlot)
64
+ last_active_slot: bnToNum(raw.lastActiveSlot),
65
+ pending_count: bnToNum(raw.pendingCount)
65
66
  };
66
67
  }
67
68
  var DEFAULT_PUBKEY = PublicKey.default.toBase58();
@@ -1951,6 +1952,200 @@ var credit_vault_default = {
1951
1952
  repository: "https://github.com/TODO/agent_fuel"
1952
1953
  },
1953
1954
  instructions: [
1955
+ {
1956
+ name: "approve_spend",
1957
+ discriminator: [
1958
+ 248,
1959
+ 201,
1960
+ 151,
1961
+ 15,
1962
+ 28,
1963
+ 162,
1964
+ 112,
1965
+ 90
1966
+ ],
1967
+ accounts: [
1968
+ {
1969
+ name: "owner",
1970
+ writable: true,
1971
+ signer: true,
1972
+ relations: [
1973
+ "vault"
1974
+ ]
1975
+ },
1976
+ {
1977
+ name: "vault",
1978
+ writable: true,
1979
+ pda: {
1980
+ seeds: [
1981
+ {
1982
+ kind: "const",
1983
+ value: [
1984
+ 118,
1985
+ 97,
1986
+ 117,
1987
+ 108,
1988
+ 116
1989
+ ]
1990
+ },
1991
+ {
1992
+ kind: "account",
1993
+ path: "owner"
1994
+ },
1995
+ {
1996
+ kind: "account",
1997
+ path: "vault.agent",
1998
+ account: "CreditVault"
1999
+ }
2000
+ ]
2001
+ }
2002
+ },
2003
+ {
2004
+ name: "policy",
2005
+ writable: true,
2006
+ pda: {
2007
+ seeds: [
2008
+ {
2009
+ kind: "const",
2010
+ value: [
2011
+ 112,
2012
+ 111,
2013
+ 108,
2014
+ 105,
2015
+ 99,
2016
+ 121
2017
+ ]
2018
+ },
2019
+ {
2020
+ kind: "account",
2021
+ path: "vault"
2022
+ }
2023
+ ]
2024
+ }
2025
+ },
2026
+ {
2027
+ name: "pending_spend",
2028
+ writable: true,
2029
+ pda: {
2030
+ seeds: [
2031
+ {
2032
+ kind: "const",
2033
+ value: [
2034
+ 112,
2035
+ 101,
2036
+ 110,
2037
+ 100,
2038
+ 105,
2039
+ 110,
2040
+ 103
2041
+ ]
2042
+ },
2043
+ {
2044
+ kind: "account",
2045
+ path: "vault"
2046
+ },
2047
+ {
2048
+ kind: "account",
2049
+ path: "pending_spend.nonce",
2050
+ account: "PendingSpend"
2051
+ }
2052
+ ]
2053
+ }
2054
+ },
2055
+ {
2056
+ name: "vault_token_account",
2057
+ writable: true
2058
+ },
2059
+ {
2060
+ name: "service_token_account",
2061
+ writable: true
2062
+ },
2063
+ {
2064
+ name: "token_program",
2065
+ address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
2066
+ }
2067
+ ],
2068
+ args: []
2069
+ },
2070
+ {
2071
+ name: "cancel_spend",
2072
+ discriminator: [
2073
+ 122,
2074
+ 254,
2075
+ 101,
2076
+ 132,
2077
+ 241,
2078
+ 232,
2079
+ 205,
2080
+ 179
2081
+ ],
2082
+ accounts: [
2083
+ {
2084
+ name: "owner",
2085
+ writable: true,
2086
+ signer: true,
2087
+ relations: [
2088
+ "vault"
2089
+ ]
2090
+ },
2091
+ {
2092
+ name: "vault",
2093
+ pda: {
2094
+ seeds: [
2095
+ {
2096
+ kind: "const",
2097
+ value: [
2098
+ 118,
2099
+ 97,
2100
+ 117,
2101
+ 108,
2102
+ 116
2103
+ ]
2104
+ },
2105
+ {
2106
+ kind: "account",
2107
+ path: "owner"
2108
+ },
2109
+ {
2110
+ kind: "account",
2111
+ path: "vault.agent",
2112
+ account: "CreditVault"
2113
+ }
2114
+ ]
2115
+ }
2116
+ },
2117
+ {
2118
+ name: "pending_spend",
2119
+ writable: true,
2120
+ pda: {
2121
+ seeds: [
2122
+ {
2123
+ kind: "const",
2124
+ value: [
2125
+ 112,
2126
+ 101,
2127
+ 110,
2128
+ 100,
2129
+ 105,
2130
+ 110,
2131
+ 103
2132
+ ]
2133
+ },
2134
+ {
2135
+ kind: "account",
2136
+ path: "vault"
2137
+ },
2138
+ {
2139
+ kind: "account",
2140
+ path: "pending_spend.nonce",
2141
+ account: "PendingSpend"
2142
+ }
2143
+ ]
2144
+ }
2145
+ }
2146
+ ],
2147
+ args: []
2148
+ },
1954
2149
  {
1955
2150
  name: "claim",
1956
2151
  discriminator: [
@@ -2357,6 +2552,104 @@ var credit_vault_default = {
2357
2552
  ],
2358
2553
  args: []
2359
2554
  },
2555
+ {
2556
+ name: "request_spend",
2557
+ discriminator: [
2558
+ 127,
2559
+ 12,
2560
+ 23,
2561
+ 75,
2562
+ 137,
2563
+ 178,
2564
+ 148,
2565
+ 71
2566
+ ],
2567
+ accounts: [
2568
+ {
2569
+ name: "agent",
2570
+ writable: true,
2571
+ signer: true,
2572
+ relations: [
2573
+ "vault"
2574
+ ]
2575
+ },
2576
+ {
2577
+ name: "vault",
2578
+ writable: true,
2579
+ pda: {
2580
+ seeds: [
2581
+ {
2582
+ kind: "const",
2583
+ value: [
2584
+ 118,
2585
+ 97,
2586
+ 117,
2587
+ 108,
2588
+ 116
2589
+ ]
2590
+ },
2591
+ {
2592
+ kind: "account",
2593
+ path: "vault.owner",
2594
+ account: "CreditVault"
2595
+ },
2596
+ {
2597
+ kind: "account",
2598
+ path: "vault.agent",
2599
+ account: "CreditVault"
2600
+ }
2601
+ ]
2602
+ }
2603
+ },
2604
+ {
2605
+ name: "service_token_account",
2606
+ docs: [
2607
+ "The recipient token account. We only need it for its `owner` field",
2608
+ "(the service pubkey we record in PendingSpend); mint constraint is",
2609
+ "belt-and-suspenders since `approve_spend` re-checks both."
2610
+ ]
2611
+ },
2612
+ {
2613
+ name: "pending_spend",
2614
+ writable: true,
2615
+ pda: {
2616
+ seeds: [
2617
+ {
2618
+ kind: "const",
2619
+ value: [
2620
+ 112,
2621
+ 101,
2622
+ 110,
2623
+ 100,
2624
+ 105,
2625
+ 110,
2626
+ 103
2627
+ ]
2628
+ },
2629
+ {
2630
+ kind: "account",
2631
+ path: "vault"
2632
+ },
2633
+ {
2634
+ kind: "account",
2635
+ path: "vault.pending_count",
2636
+ account: "CreditVault"
2637
+ }
2638
+ ]
2639
+ }
2640
+ },
2641
+ {
2642
+ name: "system_program",
2643
+ address: "11111111111111111111111111111111"
2644
+ }
2645
+ ],
2646
+ args: [
2647
+ {
2648
+ name: "amount_usdc",
2649
+ type: "u64"
2650
+ }
2651
+ ]
2652
+ },
2360
2653
  {
2361
2654
  name: "spend",
2362
2655
  discriminator: [
@@ -2682,6 +2975,19 @@ var credit_vault_default = {
2682
2975
  70
2683
2976
  ]
2684
2977
  },
2978
+ {
2979
+ name: "PendingSpend",
2980
+ discriminator: [
2981
+ 193,
2982
+ 205,
2983
+ 85,
2984
+ 66,
2985
+ 25,
2986
+ 3,
2987
+ 67,
2988
+ 134
2989
+ ]
2990
+ },
2685
2991
  {
2686
2992
  name: "SpendPolicy",
2687
2993
  discriminator: [
@@ -2736,6 +3042,32 @@ var credit_vault_default = {
2736
3042
  161
2737
3043
  ]
2738
3044
  },
3045
+ {
3046
+ name: "SpendRejected",
3047
+ discriminator: [
3048
+ 22,
3049
+ 233,
3050
+ 208,
3051
+ 109,
3052
+ 202,
3053
+ 231,
3054
+ 175,
3055
+ 22
3056
+ ]
3057
+ },
3058
+ {
3059
+ name: "SpendRequested",
3060
+ discriminator: [
3061
+ 144,
3062
+ 207,
3063
+ 254,
3064
+ 247,
3065
+ 81,
3066
+ 146,
3067
+ 84,
3068
+ 87
3069
+ ]
3070
+ },
2739
3071
  {
2740
3072
  name: "Spent",
2741
3073
  discriminator: [
@@ -2852,6 +3184,16 @@ var credit_vault_default = {
2852
3184
  code: 6009,
2853
3185
  name: "PostPayDisabled",
2854
3186
  msg: "Post-pay claims are disabled for this vault"
3187
+ },
3188
+ {
3189
+ code: 6010,
3190
+ name: "PendingSpendVaultMismatch",
3191
+ msg: "Pending spend belongs to a different vault"
3192
+ },
3193
+ {
3194
+ code: 6011,
3195
+ name: "PendingNonceOverflow",
3196
+ msg: "Pending spend counter would overflow"
2855
3197
  }
2856
3198
  ],
2857
3199
  types: [
@@ -2940,12 +3282,22 @@ var credit_vault_default = {
2940
3282
  name: "bump",
2941
3283
  type: "u8"
2942
3284
  },
3285
+ {
3286
+ name: "pending_count",
3287
+ docs: [
3288
+ "Monotonic counter used as a PDA seed for PendingSpend accounts so",
3289
+ "every approval request gets a unique deterministic address.",
3290
+ "Borrowed 8 bytes from the original 64-byte padding so the account",
3291
+ "size stays at `ACCOUNT_SIZE` and existing vaults need no migration."
3292
+ ],
3293
+ type: "u64"
3294
+ },
2943
3295
  {
2944
3296
  name: "_padding",
2945
3297
  type: {
2946
3298
  array: [
2947
3299
  "u8",
2948
- 64
3300
+ 56
2949
3301
  ]
2950
3302
  }
2951
3303
  }
@@ -2980,6 +3332,65 @@ var credit_vault_default = {
2980
3332
  ]
2981
3333
  }
2982
3334
  },
3335
+ {
3336
+ name: "PendingSpend",
3337
+ docs: [
3338
+ "A spend request that exceeded one of the policy's rate limits. The agent",
3339
+ "creates this account by calling `request_spend`; the owner reviews from",
3340
+ "the mobile Alerts tab and either calls `approve_spend` (PDA-signed CPI",
3341
+ "transfer, account closed) or `cancel_spend` (account closed, no transfer).",
3342
+ "",
3343
+ 'Seeded by `["pending", vault, nonce_le]` where `nonce` is the value of',
3344
+ "`vault.pending_count` at request time, so each request has a unique",
3345
+ "deterministic address that both the agent and the owner can derive."
3346
+ ],
3347
+ type: {
3348
+ kind: "struct",
3349
+ fields: [
3350
+ {
3351
+ name: "vault",
3352
+ type: "pubkey"
3353
+ },
3354
+ {
3355
+ name: "agent",
3356
+ type: "pubkey"
3357
+ },
3358
+ {
3359
+ name: "service",
3360
+ docs: [
3361
+ "Owner of the destination token account (mirrors how `Spent` records",
3362
+ "service: `service_token_account.owner`)."
3363
+ ],
3364
+ type: "pubkey"
3365
+ },
3366
+ {
3367
+ name: "amount_usdc",
3368
+ type: "u64"
3369
+ },
3370
+ {
3371
+ name: "requested_slot",
3372
+ type: "u64"
3373
+ },
3374
+ {
3375
+ name: "nonce",
3376
+ type: "u64"
3377
+ },
3378
+ {
3379
+ name: "bump",
3380
+ type: "u8"
3381
+ },
3382
+ {
3383
+ name: "_padding",
3384
+ type: {
3385
+ array: [
3386
+ "u8",
3387
+ 31
3388
+ ]
3389
+ }
3390
+ }
3391
+ ]
3392
+ }
3393
+ },
2983
3394
  {
2984
3395
  name: "PolicyUpdated",
2985
3396
  type: {
@@ -3083,6 +3494,70 @@ var credit_vault_default = {
3083
3494
  ]
3084
3495
  }
3085
3496
  },
3497
+ {
3498
+ name: "SpendRejected",
3499
+ type: {
3500
+ kind: "struct",
3501
+ fields: [
3502
+ {
3503
+ name: "vault",
3504
+ type: "pubkey"
3505
+ },
3506
+ {
3507
+ name: "owner",
3508
+ type: "pubkey"
3509
+ },
3510
+ {
3511
+ name: "pending_spend",
3512
+ type: "pubkey"
3513
+ },
3514
+ {
3515
+ name: "nonce",
3516
+ type: "u64"
3517
+ },
3518
+ {
3519
+ name: "slot",
3520
+ type: "u64"
3521
+ }
3522
+ ]
3523
+ }
3524
+ },
3525
+ {
3526
+ name: "SpendRequested",
3527
+ type: {
3528
+ kind: "struct",
3529
+ fields: [
3530
+ {
3531
+ name: "vault",
3532
+ type: "pubkey"
3533
+ },
3534
+ {
3535
+ name: "agent",
3536
+ type: "pubkey"
3537
+ },
3538
+ {
3539
+ name: "service",
3540
+ type: "pubkey"
3541
+ },
3542
+ {
3543
+ name: "pending_spend",
3544
+ type: "pubkey"
3545
+ },
3546
+ {
3547
+ name: "amount_usdc",
3548
+ type: "u64"
3549
+ },
3550
+ {
3551
+ name: "nonce",
3552
+ type: "u64"
3553
+ },
3554
+ {
3555
+ name: "slot",
3556
+ type: "u64"
3557
+ }
3558
+ ]
3559
+ }
3560
+ },
3086
3561
  {
3087
3562
  name: "Spent",
3088
3563
  type: {
@@ -3267,6 +3742,15 @@ function agentServiceLinkPda(agentProfile, serviceRegistry) {
3267
3742
  );
3268
3743
  return pda;
3269
3744
  }
3745
+ function pendingSpendPda(vault, nonce) {
3746
+ const nonceBuf = Buffer.alloc(8);
3747
+ nonceBuf.writeBigUInt64LE(typeof nonce === "bigint" ? nonce : BigInt(nonce));
3748
+ const [pda] = PublicKey.findProgramAddressSync(
3749
+ [Buffer.from("pending"), toPubkey(vault).toBuffer(), nonceBuf],
3750
+ PROGRAM_IDS.creditVault
3751
+ );
3752
+ return pda;
3753
+ }
3270
3754
  function receiptUsedPda(receiptHash) {
3271
3755
  if (receiptHash.length !== 32) {
3272
3756
  throw new Error(`receiptUsedPda expects a 32-byte hash, got ${receiptHash.length}`);
@@ -3287,6 +3771,207 @@ function reputationProgram(provider) {
3287
3771
  return new Program(reputation_default, provider);
3288
3772
  }
3289
3773
 
3774
+ // src/pay.ts
3775
+ async function pay(args) {
3776
+ const { agent, service, connection, amountUsdc } = args;
3777
+ const owner = toPubkey(args.owner);
3778
+ if (amountUsdc <= 0) {
3779
+ throw new ZeroAmountError();
3780
+ }
3781
+ if (args.receiptHash.length !== 32) {
3782
+ throw new Error(
3783
+ `pay: receiptHash must be 32 bytes, got ${args.receiptHash.length}`
3784
+ );
3785
+ }
3786
+ const vaultAddr = vaultPda(owner, agent.publicKey);
3787
+ const policyAddr = policyPda(vaultAddr);
3788
+ const provider = buildProvider(connection, agent);
3789
+ const cv = creditVaultProgram(provider);
3790
+ const rep = reputationProgram(provider);
3791
+ const [rawVault, rawPolicy, currentSlot] = await Promise.all([
3792
+ cv.account.creditVault.fetchNullable(vaultAddr),
3793
+ cv.account.spendPolicy.fetchNullable(policyAddr),
3794
+ connection.getSlot()
3795
+ ]);
3796
+ if (!rawVault) throw new AccountNotFoundError(vaultAddr.toBase58());
3797
+ if (!rawPolicy) throw new AccountNotFoundError(policyAddr.toBase58());
3798
+ const vault = decodeCreditVault(vaultAddr, rawVault);
3799
+ const policy = decodeSpendPolicy(policyAddr, rawPolicy);
3800
+ guardSpend({
3801
+ vault,
3802
+ policy,
3803
+ service: service.publicKey,
3804
+ amountUsdc,
3805
+ currentSlot
3806
+ });
3807
+ const serviceTokenAccount = getAssociatedTokenAddress(
3808
+ vault.usdc_mint,
3809
+ service.publicKey
3810
+ );
3811
+ const createAtaIx = createAssociatedTokenAccountIdempotentInstruction(
3812
+ agent.publicKey,
3813
+ serviceTokenAccount,
3814
+ service.publicKey,
3815
+ vault.usdc_mint
3816
+ );
3817
+ const agentProfile = agentProfilePda(agent.publicKey);
3818
+ const serviceRegistry = serviceRegistryPda(service.publicKey);
3819
+ const link = agentServiceLinkPda(agentProfile, serviceRegistry);
3820
+ const receipt = receiptUsedPda(args.receiptHash);
3821
+ const spendBuilder = cv.methods.spend(new BN(amountUsdc)).accounts({
3822
+ agent: agent.publicKey,
3823
+ vault: vaultAddr,
3824
+ policy: policyAddr,
3825
+ vaultTokenAccount: vault.vault_token_account,
3826
+ serviceTokenAccount,
3827
+ tokenProgram: TOKEN_PROGRAM_ID
3828
+ });
3829
+ const recordBuilder = rep.methods.recordPayment(new BN(amountUsdc), args.receiptHash).accounts({
3830
+ service: service.publicKey,
3831
+ agentProfile,
3832
+ serviceRegistry,
3833
+ agentServiceLink: link,
3834
+ receiptUsed: receipt,
3835
+ systemProgram: SystemProgram.programId
3836
+ });
3837
+ const spendIx = await spendBuilder.instruction();
3838
+ const recordIx = await recordBuilder.instruction();
3839
+ const tx = new Transaction().add(createAtaIx, spendIx, recordIx);
3840
+ try {
3841
+ const signature = await sendAndConfirmTransaction(
3842
+ connection,
3843
+ tx,
3844
+ [agent, service],
3845
+ { commitment: "confirmed" }
3846
+ );
3847
+ return { signature };
3848
+ } catch (err) {
3849
+ throw mapPayError(err, {
3850
+ service: service.publicKey,
3851
+ amountUsdc,
3852
+ vault,
3853
+ policy,
3854
+ receiptHash: args.receiptHash
3855
+ });
3856
+ }
3857
+ }
3858
+ function mapPayError(err, ctx) {
3859
+ const message = err instanceof Error ? err.message : String(err);
3860
+ if (/already in use/i.test(message)) {
3861
+ return new ReceiptAlreadyRecordedError(ctx.receiptHash);
3862
+ }
3863
+ if (!(err instanceof AnchorError)) return err;
3864
+ switch (err.error.errorCode.number) {
3865
+ case 6001:
3866
+ return new ZeroAmountError();
3867
+ case 6002:
3868
+ return new VaultFrozenError();
3869
+ case 6003:
3870
+ return new NotWhitelistedError(ctx.service.toBase58());
3871
+ case 6004:
3872
+ return new PerTxLimitExceededError(ctx.amountUsdc, ctx.policy.per_tx_limit_usdc);
3873
+ case 6005:
3874
+ return new HourlyLimitExceededError(
3875
+ ctx.amountUsdc,
3876
+ ctx.policy.hourly_window_spent_usdc,
3877
+ ctx.policy.hourly_limit_usdc
3878
+ );
3879
+ case 6006:
3880
+ return new LifetimeLimitExceededError(
3881
+ ctx.amountUsdc,
3882
+ ctx.vault.total_spent,
3883
+ ctx.policy.lifetime_limit_usdc
3884
+ );
3885
+ // Reputation errors:
3886
+ case 6e3:
3887
+ return new RecordPaymentError("counter overflow on chain");
3888
+ case 6011:
3889
+ return new ServiceInactiveError(ctx.service.toBase58());
3890
+ default:
3891
+ return err;
3892
+ }
3893
+ }
3894
+ async function requestSpend(args) {
3895
+ const { agent, connection, amountUsdc } = args;
3896
+ const owner = toPubkey(args.owner);
3897
+ const service = toPubkey(args.service);
3898
+ if (amountUsdc <= 0) {
3899
+ throw new Error("requestSpend: amountUsdc must be > 0");
3900
+ }
3901
+ const vaultAddr = vaultPda(owner, agent.publicKey);
3902
+ const provider = buildProvider(connection, agent);
3903
+ const cv = creditVaultProgram(provider);
3904
+ const rawVault = await cv.account.creditVault.fetchNullable(vaultAddr);
3905
+ if (!rawVault) throw new AccountNotFoundError(vaultAddr.toBase58());
3906
+ const vault = decodeCreditVault(vaultAddr, rawVault);
3907
+ const nonce = vault.pending_count;
3908
+ const pendingSpend = pendingSpendPda(vaultAddr, nonce);
3909
+ const serviceTokenAccount = getAssociatedTokenAddress(
3910
+ vault.usdc_mint,
3911
+ service
3912
+ );
3913
+ const signature = await cv.methods.requestSpend(new BN(amountUsdc)).accounts({
3914
+ agent: agent.publicKey,
3915
+ vault: vaultAddr,
3916
+ serviceTokenAccount,
3917
+ pendingSpend,
3918
+ systemProgram: SystemProgram.programId
3919
+ }).signers([agent]).rpc();
3920
+ return { signature, pendingSpend, nonce };
3921
+ }
3922
+ var NAME_BYTES = 32;
3923
+ var URI_BYTES = 128;
3924
+ async function registerService(args) {
3925
+ const { sponsor, service, connection } = args;
3926
+ if (args.name.length === 0) {
3927
+ throw new Error("registerService: name must not be empty");
3928
+ }
3929
+ if (Buffer.byteLength(args.name, "utf8") > NAME_BYTES) {
3930
+ throw new Error(
3931
+ `registerService: name exceeds ${NAME_BYTES} bytes (got ${Buffer.byteLength(args.name, "utf8")})`
3932
+ );
3933
+ }
3934
+ const uri = args.serviceUri ?? "";
3935
+ if (Buffer.byteLength(uri, "utf8") > URI_BYTES) {
3936
+ throw new Error(
3937
+ `registerService: serviceUri exceeds ${URI_BYTES} bytes (got ${Buffer.byteLength(uri, "utf8")})`
3938
+ );
3939
+ }
3940
+ const registry = serviceRegistryPda(service.publicKey);
3941
+ const provider = buildProvider(connection, sponsor);
3942
+ const rep = reputationProgram(provider);
3943
+ const signature = await rep.methods.registerService(
3944
+ packFixed(args.name, NAME_BYTES),
3945
+ categoryArg(args.category),
3946
+ packFixed(uri, URI_BYTES)
3947
+ ).accounts({
3948
+ sponsor: sponsor.publicKey,
3949
+ service: service.publicKey,
3950
+ serviceRegistry: registry,
3951
+ systemProgram: SystemProgram.programId
3952
+ }).signers([sponsor, service]).rpc();
3953
+ return { signature };
3954
+ }
3955
+ function packFixed(s, length) {
3956
+ const buf = Buffer.alloc(length);
3957
+ buf.write(s, 0, "utf8");
3958
+ return Array.from(buf);
3959
+ }
3960
+ function categoryArg(c) {
3961
+ switch (c) {
3962
+ case "DataFeed":
3963
+ return { dataFeed: {} };
3964
+ case "Compute":
3965
+ return { compute: {} };
3966
+ case "Swap":
3967
+ return { swap: {} };
3968
+ case "Rpc":
3969
+ return { rpc: {} };
3970
+ case "Other":
3971
+ return { other: {} };
3972
+ }
3973
+ }
3974
+
3290
3975
  // src/client.ts
3291
3976
  var DEFAULT_API_BASE = "http://localhost:8080";
3292
3977
  var AgentFuel = class {
@@ -3385,6 +4070,38 @@ var AgentFuel = class {
3385
4070
  throw mapSpendError(err, { service, amountUsdc, vault, policy });
3386
4071
  }
3387
4072
  }
4073
+ /// Atomic spend + record_payment in one transaction. Use this instead
4074
+ /// of `spend()` + `recordPayment()` when you want the vault burn and
4075
+ /// the reputation accrual to be all-or-nothing. The service keypair
4076
+ /// co-signs.
4077
+ async pay(args) {
4078
+ return pay({
4079
+ agent: this.agent,
4080
+ owner: this.resolveOwner(args.owner),
4081
+ service: args.service,
4082
+ amountUsdc: args.amountUsdc,
4083
+ receiptHash: args.receiptHash,
4084
+ connection: this.connection
4085
+ });
4086
+ }
4087
+ /// Submit an over-limit spend request the owner can approve from the
4088
+ /// mobile app. Returns the `pendingSpend` PDA so the bot can poll for
4089
+ /// resolution.
4090
+ async requestSpend(args) {
4091
+ return requestSpend({
4092
+ agent: this.agent,
4093
+ owner: this.resolveOwner(args.owner),
4094
+ service: args.service,
4095
+ amountUsdc: args.amountUsdc,
4096
+ connection: this.connection
4097
+ });
4098
+ }
4099
+ /// Register a service on chain. The `sponsor` (typically `this.agent`'s
4100
+ /// owner wallet) pays rent; the `service` keypair is the long-lived
4101
+ /// identity that will co-sign every future `record_payment`.
4102
+ async registerService(args) {
4103
+ return registerService({ ...args, connection: this.connection });
4104
+ }
3388
4105
  /// Triggers an on-chain recomputation of the agent's reputation score.
3389
4106
  /// Permissionless — any signer can call it; we use the agent itself since
3390
4107
  /// the SDK already has its keypair available and it already pays tx fees
@@ -3580,6 +4297,6 @@ function truncate(s) {
3580
4297
  return s.length > 80 ? `${s.slice(0, 80)}\u2026` : s;
3581
4298
  }
3582
4299
 
3583
- export { ASSOCIATED_TOKEN_PROGRAM_ID, AccountNotFoundError, AgentFuel, AgentFuelError, HourlyLimitExceededError, HttpError, LifetimeLimitExceededError, NotWhitelistedError, OwnerNotConfiguredError, PROGRAM_IDS, PaymentParseError, PerTxLimitExceededError, ReceiptAlreadyRecordedError, RecordPaymentError, SLOTS_PER_HOUR, ServiceInactiveError, SpendPolicyError, TOKEN_PROGRAM_ID, VaultFrozenError, ZeroAmountError, agentProfilePda, agentServiceLinkPda, createAssociatedTokenAccountIdempotentInstruction, getAssociatedTokenAddress, paymentRequired, policyPda, receiptUsedPda, recordPayment, serviceRegistryPda, subscribeService, subscribeVault, vaultPda };
4300
+ export { ASSOCIATED_TOKEN_PROGRAM_ID, AccountNotFoundError, AgentFuel, AgentFuelError, HourlyLimitExceededError, HttpError, LifetimeLimitExceededError, NotWhitelistedError, OwnerNotConfiguredError, PROGRAM_IDS, PaymentParseError, PerTxLimitExceededError, ReceiptAlreadyRecordedError, RecordPaymentError, SLOTS_PER_HOUR, ServiceInactiveError, SpendPolicyError, TOKEN_PROGRAM_ID, VaultFrozenError, ZeroAmountError, agentProfilePda, agentServiceLinkPda, createAssociatedTokenAccountIdempotentInstruction, getAssociatedTokenAddress, pay, paymentRequired, pendingSpendPda, policyPda, receiptUsedPda, recordPayment, registerService, requestSpend, serviceRegistryPda, subscribeService, subscribeVault, vaultPda };
3584
4301
  //# sourceMappingURL=index.js.map
3585
4302
  //# sourceMappingURL=index.js.map