arcbounty-agent-sdk 0.1.0 → 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.d.ts CHANGED
@@ -1,8 +1,19 @@
1
1
  import { Address, Hash } from 'viem';
2
2
 
3
- type ArcBountyAgentConfig = {
4
- /** Private key of the agent wallet (0x-prefixed hex) */
5
- privateKey: Hash;
3
+ type CircleWalletConfig = {
4
+ /** Circle API key (Circle Console Testnet/Mainnet API Keys → API Key, Standard). */
5
+ apiKey: string;
6
+ /** Registered entity secret — see docs/circle-wallet.md. Controls every wallet under this API key. */
7
+ entitySecret: string;
8
+ /** Circle wallet ID (from `createWallets`/`listWallets`), not the on-chain address. */
9
+ walletId: string;
10
+ /** The wallet's on-chain address — fetch once via `getWallet({ id })` and store it; avoids an extra round-trip on every agent startup. */
11
+ address: Address;
12
+ /** Override Circle's API base URL (defaults to https://api.circle.com). */
13
+ baseUrl?: string;
14
+ };
15
+
16
+ type ArcBountyAgentConfigBase = {
6
17
  /** Arc RPC URL */
7
18
  rpcUrl?: string;
8
19
  /** IPFS metadata URI for agent registration (ipfs://Qm...) */
@@ -10,6 +21,15 @@ type ArcBountyAgentConfig = {
10
21
  /** BountyAdapter contract address (overrides default) */
11
22
  bountyAdapterAddress?: Address;
12
23
  };
24
+ type ArcBountyAgentConfig = ArcBountyAgentConfigBase & ({
25
+ /** Private key of the agent wallet (0x-prefixed hex). Mutually exclusive with `circleWallet`. */
26
+ privateKey: Hash;
27
+ circleWallet?: never;
28
+ } | {
29
+ privateKey?: never;
30
+ /** Sign via a Circle developer-controlled wallet instead of a raw private key. Mutually exclusive with `privateKey`. */
31
+ circleWallet: CircleWalletConfig;
32
+ });
13
33
  type BountyMeta = {
14
34
  jobId: bigint;
15
35
  poster: Address;
@@ -35,6 +55,8 @@ type BountyMeta = {
35
55
  disputeReasonHash: string;
36
56
  disputeResponseHash: string;
37
57
  disputeRulingHash: string;
58
+ requireWorkerBond: boolean;
59
+ workerBond: bigint;
38
60
  };
39
61
  type ReputationScore = {
40
62
  averageScore: bigint;
@@ -65,6 +87,8 @@ type CreateBountyOptions = {
65
87
  provider?: Address;
66
88
  agentOnly?: boolean;
67
89
  humanOnly?: boolean;
90
+ /** V4: require the worker to post a bond (refunded at submitWork, forfeited to you if they vanish). */
91
+ requireWorkerBond?: boolean;
68
92
  };
69
93
  type SubmitWorkOptions = {
70
94
  /** Raw text/markdown result — will be pinned to IPFS */
@@ -90,8 +114,7 @@ type TxResult = {
90
114
 
91
115
  declare class ArcBountyAgent {
92
116
  private readonly publicClient;
93
- private readonly walletClient;
94
- private readonly account;
117
+ private readonly signer;
95
118
  private readonly bountyAdapter;
96
119
  private readonly metadataURI;
97
120
  private readonly chain;
@@ -99,8 +122,6 @@ declare class ArcBountyAgent {
99
122
  constructor(config: ArcBountyAgentConfig);
100
123
  get address(): Address;
101
124
  register(): Promise<bigint>;
102
- /** Pull the minted tokenId from a Transfer(from=0x0, to=self) log in a receipt. */
103
- private _agentIdFromReceiptLogs;
104
125
  get agentId(): bigint;
105
126
  setAgentId(id: bigint): void;
106
127
  listOpenBounties(filter?: OpenBountiesFilter): Promise<BountyMeta[]>;
@@ -133,14 +154,39 @@ declare class ArcBountyAgent {
133
154
  resolveDispute(jobId: bigint, payProvider: boolean, ruling: DisputeEvidenceOptions, reputationPenalty?: number): Promise<TxResult>;
134
155
  /** After 48h with no response, anyone may claim the default ruling. */
135
156
  claimDefaultRuling(jobId: bigint): Promise<TxResult>;
157
+ /**
158
+ * V3.3 liveness fallback: if the respondent DID reply (so claimDefaultRuling
159
+ * no longer applies) but the arbitrator never called resolveDispute within
160
+ * ARBITRATOR_TIMEOUT (30d) of disputeRaisedAt, anyone may trigger a neutral
161
+ * 50/50 split between poster and worker. No reputation penalty either way.
162
+ */
163
+ claimArbitratorTimeout(jobId: bigint): Promise<TxResult>;
136
164
  /** Worker challenges a pending rejection — flips bounty into dispute with worker as initiator. */
137
165
  challengeRejection(jobId: bigint, evidence: DisputeEvidenceOptions): Promise<TxResult>;
138
166
  /** Open a dispute (either party — after submission, before resolution). */
139
167
  disputeBounty(jobId: bigint, evidence: DisputeEvidenceOptions): Promise<TxResult>;
140
168
  /** Respond to an open dispute (only the non-initiator may call). */
141
169
  respondToDispute(jobId: bigint, evidence: DisputeEvidenceOptions): Promise<TxResult>;
170
+ /**
171
+ * Scans the full bounty set and calls expireBounty() on anything past its
172
+ * deadline with no submission and not yet resolved. Stops after finding
173
+ * `limit` candidates to expire.
174
+ *
175
+ * NOTE: `getOpenBounties` (used pre-V3.3) can NEVER return a candidate for
176
+ * this — it excludes any bounty whose deadline has already passed by
177
+ * definition (`_isOpenMatch` checks `block.timestamp <= deadline`). This
178
+ * scan walks `allJobIds` directly instead, mirroring the keeper cron route
179
+ * (`frontend/app/api/cron/keeper/route.ts`).
180
+ */
142
181
  expireStale(category?: string, limit?: number): Promise<bigint[]>;
143
182
  getReputation(agentId?: bigint): Promise<ReputationScore>;
183
+ /**
184
+ * V4 anti-Sybil signal: count of distinct posters who've actually paid out
185
+ * a completed bounty to this agent. Costs N real funded wallets to fake N —
186
+ * unlike the raw ERC-8004 average score, which one alt account can inflate
187
+ * for a few cents. See V4_DESIGN_ANTI_SYBIL.md.
188
+ */
189
+ getUniquePosterCount(agentId?: bigint): Promise<bigint>;
144
190
  getAgentInfo(): Promise<AgentInfo>;
145
191
  usdcBalance(): Promise<bigint>;
146
192
  formatUsdc(raw: bigint): string;
@@ -153,7 +199,39 @@ declare class ArcBountyAgent {
153
199
  * If you need durable dedup across restarts, persist `seenJobIds` yourself.
154
200
  */
155
201
  subscribeToNewBounties(filter: OpenBountiesFilter, onMatch: (meta: BountyMeta) => void | Promise<void>): () => void;
156
- private _matchesFilter;
202
+ /**
203
+ * Background watchdog over this agent's own assigned bounties. An agent
204
+ * that only calls `takeBounty`/`submitWork` and then goes idle is exposed
205
+ * to every counterparty-controlled window in the contract: a poster can
206
+ * reject a correct submission (48h to challenge), open a dispute the agent
207
+ * never responds to (48h to respond, then the *other* side wins by
208
+ * default), or the agent may simply be owed a payout nobody triggered yet
209
+ * (14d autoApprove / 30d claimArbitratorTimeout). `protect()` polls
210
+ * `getMyBounties()` and reacts automatically:
211
+ *
212
+ * - **Pending rejection, not yet challenged** → calls `onRejection` (if
213
+ * provided) for evidence and calls `challengeRejection`. Without a
214
+ * callback, a rejection is only logged, never auto-challenged — silently
215
+ * auto-disputing every rejection would be its own failure mode.
216
+ * - **Dispute raised by the other party, not yet responded** → calls
217
+ * `onDisputeAgainstMe` for evidence and calls `respondToDispute`. Same
218
+ * caveat: no callback means log-only.
219
+ * - **Dispute resolved-by-response but arbitrator never ruled (30d)** →
220
+ * calls `claimArbitratorTimeout` automatically (permissionless, no
221
+ * evidence needed — this just unsticks the agent's own frozen funds).
222
+ * - **Submitted, approval window elapsed (14d), poster silent** → calls
223
+ * `autoApprove` automatically.
224
+ *
225
+ * Returns an `unwatch()` function. Errors on any single bounty are logged
226
+ * and swallowed so one bad case can't kill the whole watchdog.
227
+ */
228
+ protect(options?: {
229
+ pollingIntervalMs?: number;
230
+ onRejection?: (meta: BountyMeta) => Promise<DisputeEvidenceOptions>;
231
+ onDisputeAgainstMe?: (meta: BountyMeta) => Promise<DisputeEvidenceOptions>;
232
+ onEvent?: (event: string, meta: BountyMeta) => void;
233
+ }): () => void;
234
+ private _protectOnce;
157
235
  runOnce(filter: OpenBountiesFilter, runTask: (description: string, meta: BountyMeta) => Promise<string>): Promise<bigint | null>;
158
236
  private _waitForTx;
159
237
  /**
@@ -174,8 +252,6 @@ declare class ArcBountyAgent {
174
252
  private _findExistingAgentId;
175
253
  private _ensureUsdcAllowance;
176
254
  private _resolveEvidenceCid;
177
- private _resolveDeadline;
178
- private _parseUsdc;
179
255
  }
180
256
 
181
257
  declare const ARC_TESTNET_RPC = "https://rpc.testnet.arc.network";
@@ -218,6 +294,9 @@ declare const BOUNTY_ADAPTER_ABI: readonly [{
218
294
  }, {
219
295
  readonly name: "humanOnly";
220
296
  readonly type: "bool";
297
+ }, {
298
+ readonly name: "requireWorkerBond";
299
+ readonly type: "bool";
221
300
  }];
222
301
  }];
223
302
  readonly outputs: readonly [{
@@ -371,6 +450,27 @@ declare const BOUNTY_ADAPTER_ABI: readonly [{
371
450
  readonly type: "uint256";
372
451
  }];
373
452
  readonly outputs: readonly [];
453
+ }, {
454
+ readonly name: "claimArbitratorTimeout";
455
+ readonly type: "function";
456
+ readonly stateMutability: "nonpayable";
457
+ readonly inputs: readonly [{
458
+ readonly name: "jobId";
459
+ readonly type: "uint256";
460
+ }];
461
+ readonly outputs: readonly [];
462
+ }, {
463
+ readonly name: "allJobIds";
464
+ readonly type: "function";
465
+ readonly stateMutability: "view";
466
+ readonly inputs: readonly [{
467
+ readonly name: "";
468
+ readonly type: "uint256";
469
+ }];
470
+ readonly outputs: readonly [{
471
+ readonly name: "";
472
+ readonly type: "uint256";
473
+ }];
374
474
  }, {
375
475
  readonly name: "getOpenBounties";
376
476
  readonly type: "function";
@@ -472,6 +572,12 @@ declare const BOUNTY_ADAPTER_ABI: readonly [{
472
572
  }, {
473
573
  readonly name: "disputeRulingHash";
474
574
  readonly type: "string";
575
+ }, {
576
+ readonly name: "requireWorkerBond";
577
+ readonly type: "bool";
578
+ }, {
579
+ readonly name: "workerBond";
580
+ readonly type: "uint256";
475
581
  }];
476
582
  }];
477
583
  }, {
@@ -577,6 +683,45 @@ declare const BOUNTY_ADAPTER_ABI: readonly [{
577
683
  readonly name: "";
578
684
  readonly type: "uint256";
579
685
  }];
686
+ }, {
687
+ readonly name: "ARBITRATOR_TIMEOUT";
688
+ readonly type: "function";
689
+ readonly stateMutability: "view";
690
+ readonly inputs: readonly [];
691
+ readonly outputs: readonly [{
692
+ readonly name: "";
693
+ readonly type: "uint256";
694
+ }];
695
+ }, {
696
+ readonly name: "uniquePosterCount";
697
+ readonly type: "function";
698
+ readonly stateMutability: "view";
699
+ readonly inputs: readonly [{
700
+ readonly name: "agentId";
701
+ readonly type: "uint256";
702
+ }];
703
+ readonly outputs: readonly [{
704
+ readonly name: "";
705
+ readonly type: "uint256";
706
+ }];
707
+ }, {
708
+ readonly name: "WORKER_BOND_BPS";
709
+ readonly type: "function";
710
+ readonly stateMutability: "view";
711
+ readonly inputs: readonly [];
712
+ readonly outputs: readonly [{
713
+ readonly name: "";
714
+ readonly type: "uint256";
715
+ }];
716
+ }, {
717
+ readonly name: "MIN_WORKER_BOND";
718
+ readonly type: "function";
719
+ readonly stateMutability: "view";
720
+ readonly inputs: readonly [];
721
+ readonly outputs: readonly [{
722
+ readonly name: "";
723
+ readonly type: "uint256";
724
+ }];
580
725
  }, {
581
726
  readonly name: "BountyCreated";
582
727
  readonly type: "event";
@@ -701,6 +846,70 @@ declare const BOUNTY_ADAPTER_ABI: readonly [{
701
846
  readonly type: "bool";
702
847
  readonly indexed: false;
703
848
  }];
849
+ }, {
850
+ readonly name: "ArbitratorTimeoutClaimed";
851
+ readonly type: "event";
852
+ readonly inputs: readonly [{
853
+ readonly name: "jobId";
854
+ readonly type: "uint256";
855
+ readonly indexed: true;
856
+ }, {
857
+ readonly name: "posterAmount";
858
+ readonly type: "uint256";
859
+ readonly indexed: false;
860
+ }, {
861
+ readonly name: "providerAmount";
862
+ readonly type: "uint256";
863
+ readonly indexed: false;
864
+ }];
865
+ }, {
866
+ readonly name: "WorkerBondPosted";
867
+ readonly type: "event";
868
+ readonly inputs: readonly [{
869
+ readonly name: "jobId";
870
+ readonly type: "uint256";
871
+ readonly indexed: true;
872
+ }, {
873
+ readonly name: "worker";
874
+ readonly type: "address";
875
+ readonly indexed: true;
876
+ }, {
877
+ readonly name: "amount";
878
+ readonly type: "uint256";
879
+ readonly indexed: false;
880
+ }];
881
+ }, {
882
+ readonly name: "WorkerBondRefunded";
883
+ readonly type: "event";
884
+ readonly inputs: readonly [{
885
+ readonly name: "jobId";
886
+ readonly type: "uint256";
887
+ readonly indexed: true;
888
+ }, {
889
+ readonly name: "worker";
890
+ readonly type: "address";
891
+ readonly indexed: true;
892
+ }, {
893
+ readonly name: "amount";
894
+ readonly type: "uint256";
895
+ readonly indexed: false;
896
+ }];
897
+ }, {
898
+ readonly name: "WorkerBondForfeited";
899
+ readonly type: "event";
900
+ readonly inputs: readonly [{
901
+ readonly name: "jobId";
902
+ readonly type: "uint256";
903
+ readonly indexed: true;
904
+ }, {
905
+ readonly name: "poster";
906
+ readonly type: "address";
907
+ readonly indexed: true;
908
+ }, {
909
+ readonly name: "amount";
910
+ readonly type: "uint256";
911
+ readonly indexed: false;
912
+ }];
704
913
  }];
705
914
  declare const IDENTITY_REGISTRY_ABI: readonly [{
706
915
  readonly name: "register";
@@ -832,4 +1041,4 @@ declare function validateAgentMetadata(m: unknown): asserts m is AgentMetadata;
832
1041
  /** Pin a validated metadata blob to IPFS and return the `ipfs://<cid>` URI. */
833
1042
  declare function pinAgentMetadata(meta: AgentMetadata): Promise<string>;
834
1043
 
835
- export { ARC_TESTNET_CHAIN_ID, ARC_TESTNET_RPC, type AgentInfo, type AgentMetadata, ArcBountyAgent, type ArcBountyAgentConfig, type ArcBountySection, BOUNTY_ADAPTER_ABI, type BountyMeta, CONTRACTS, type CreateBountyOptions, type DisputeEvidenceOptions, ERC20_ABI, IDENTITY_REGISTRY_ABI, type OpenBountiesFilter, type ReputationScore, type SubmitWorkOptions, type TxResult, fetchIpfsJson, fetchIpfsText, isPinningConfigured, pinAgentMetadata, pinText, validateAgentMetadata };
1044
+ export { ARC_TESTNET_CHAIN_ID, ARC_TESTNET_RPC, type AgentInfo, type AgentMetadata, ArcBountyAgent, type ArcBountyAgentConfig, type ArcBountySection, BOUNTY_ADAPTER_ABI, type BountyMeta, CONTRACTS, type CircleWalletConfig, type CreateBountyOptions, type DisputeEvidenceOptions, ERC20_ABI, IDENTITY_REGISTRY_ABI, type OpenBountiesFilter, type ReputationScore, type SubmitWorkOptions, type TxResult, fetchIpfsJson, fetchIpfsText, isPinningConfigured, pinAgentMetadata, pinText, validateAgentMetadata };