@occa/sdk 0.4.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/src/pda.ts ADDED
@@ -0,0 +1,199 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import {
3
+ AGENT_IDENTITY_SEED,
4
+ COMPANY_SEED,
5
+ DAILY_ANCHOR_SEED,
6
+ DEPLOYMENT_SEED,
7
+ OPERATIONS_SEED,
8
+ POLICY_SEED,
9
+ PROTOCOL_FEES_SEED,
10
+ REGISTRY_PROGRAM_ID,
11
+ TREASURY_PROGRAM_ID,
12
+ TREASURY_SEED,
13
+ type OperationsKind,
14
+ } from "./constants";
15
+
16
+ /**
17
+ * Encode a u32 as little-endian 4 bytes (matches Anchor / Borsh on-chain
18
+ * representation when using a u32 in a PDA seed).
19
+ */
20
+ export function u32LeBytes(value: number): Buffer {
21
+ if (!Number.isInteger(value) || value < 0 || value > 0xff_ff_ff_ff) {
22
+ throw new RangeError(`u32 out of range: ${value}`);
23
+ }
24
+ const buf = Buffer.alloc(4);
25
+ buf.writeUInt32LE(value, 0);
26
+ return buf;
27
+ }
28
+
29
+ /**
30
+ * CompanyAccount PDA.
31
+ *
32
+ * seeds = ["company", owner, nonce_le_u32]
33
+ *
34
+ * Wallet-bound seed: a wallet's companies can be enumerated directly
35
+ * from chain by probing `(owner, nonce=0..N)`. The owner is also the
36
+ * sole authority for state-changing ix on this account.
37
+ */
38
+ export function deriveCompanyPda(
39
+ owner: PublicKey,
40
+ nonce: number,
41
+ programId: PublicKey = REGISTRY_PROGRAM_ID,
42
+ ): { pda: PublicKey; bump: number } {
43
+ const [pda, bump] = PublicKey.findProgramAddressSync(
44
+ [COMPANY_SEED, owner.toBuffer(), u32LeBytes(nonce)],
45
+ programId,
46
+ );
47
+ return { pda, bump };
48
+ }
49
+
50
+ /**
51
+ * AgentIdentity PDA.
52
+ *
53
+ * seeds = ["agent_identity", agent_pubkey]
54
+ *
55
+ * `agent_pubkey` is a stable identity key chosen by the caller (typically
56
+ * a fresh keypair generated client-side). Identity is independent of any
57
+ * company — the same identity may be deployed multiple times across the
58
+ * same owner's companies.
59
+ */
60
+ export function deriveAgentIdentityPda(
61
+ agentPubkey: PublicKey,
62
+ programId: PublicKey = REGISTRY_PROGRAM_ID,
63
+ ): { pda: PublicKey; bump: number } {
64
+ const [pda, bump] = PublicKey.findProgramAddressSync(
65
+ [AGENT_IDENTITY_SEED, agentPubkey.toBuffer()],
66
+ programId,
67
+ );
68
+ return { pda, bump };
69
+ }
70
+
71
+ /**
72
+ * Deployment PDA.
73
+ *
74
+ * seeds = ["deployment", company_pda, deployment_index_le_u32]
75
+ *
76
+ * `deployment_index` is a per-company u32 counter. Maintained by the
77
+ * caller — pick the next free index. Same `agent_identity` may have
78
+ * multiple deployments under the same company (e.g. retired then
79
+ * re-deployed); each deployment gets its own index.
80
+ */
81
+ export function deriveDeploymentPda(
82
+ companyPda: PublicKey,
83
+ deploymentIndex: number,
84
+ programId: PublicKey = REGISTRY_PROGRAM_ID,
85
+ ): { pda: PublicKey; bump: number } {
86
+ const [pda, bump] = PublicKey.findProgramAddressSync(
87
+ [DEPLOYMENT_SEED, companyPda.toBuffer(), u32LeBytes(deploymentIndex)],
88
+ programId,
89
+ );
90
+ return { pda, bump };
91
+ }
92
+
93
+ /**
94
+ * TreasuryAccount PDA — owned by Treasury program.
95
+ *
96
+ * seeds = ["treasury", company_pda]
97
+ *
98
+ * Initialized atomically with PolicyAccount via Registry's `create_company`
99
+ * CPI to `treasury::init_treasury` (design doc §6).
100
+ */
101
+ export function deriveTreasuryPda(
102
+ companyPda: PublicKey,
103
+ programId: PublicKey = TREASURY_PROGRAM_ID,
104
+ ): { pda: PublicKey; bump: number } {
105
+ const [pda, bump] = PublicKey.findProgramAddressSync(
106
+ [TREASURY_SEED, companyPda.toBuffer()],
107
+ programId,
108
+ );
109
+ return { pda, bump };
110
+ }
111
+
112
+ /**
113
+ * PolicyAccount PDA — owned by Treasury program.
114
+ *
115
+ * seeds = ["policy", company_pda]
116
+ *
117
+ * Initialized atomically with TreasuryAccount via the same `create_company`
118
+ * CPI flow.
119
+ */
120
+ export function derivePolicyPda(
121
+ companyPda: PublicKey,
122
+ programId: PublicKey = TREASURY_PROGRAM_ID,
123
+ ): { pda: PublicKey; bump: number } {
124
+ const [pda, bump] = PublicKey.findProgramAddressSync(
125
+ [POLICY_SEED, companyPda.toBuffer()],
126
+ programId,
127
+ );
128
+ return { pda, bump };
129
+ }
130
+
131
+ /**
132
+ * ProtocolFeeAccount PDA — owned by Treasury program. Singleton: one
133
+ * per program deployment, collects the Agent Operating Fee from every
134
+ * intra-company agent disbursement.
135
+ *
136
+ * seeds = ["protocol_fees"]
137
+ */
138
+ export function deriveProtocolFeePda(
139
+ programId: PublicKey = TREASURY_PROGRAM_ID,
140
+ ): { pda: PublicKey; bump: number } {
141
+ const [pda, bump] = PublicKey.findProgramAddressSync(
142
+ [PROTOCOL_FEES_SEED],
143
+ programId,
144
+ );
145
+ return { pda, bump };
146
+ }
147
+
148
+ /**
149
+ * OperationsAccount PDA — owned by Treasury program. One per
150
+ * (company, kind) pair, so Disbursement and Anchor capabilities never
151
+ * share a key.
152
+ *
153
+ * seeds = ["operations", company_pda, kind_byte]
154
+ *
155
+ * `kind_byte` is the single-byte discriminator from `OPERATIONS_KIND`
156
+ * (Disbursement=0, Anchor=1). Order MUST NOT change once any account
157
+ * exists.
158
+ */
159
+ export function deriveOperationsPda(
160
+ companyPda: PublicKey,
161
+ kind: OperationsKind,
162
+ programId: PublicKey = TREASURY_PROGRAM_ID,
163
+ ): { pda: PublicKey; bump: number } {
164
+ const [pda, bump] = PublicKey.findProgramAddressSync(
165
+ [OPERATIONS_SEED, companyPda.toBuffer(), Buffer.from([kind])],
166
+ programId,
167
+ );
168
+ return { pda, bump };
169
+ }
170
+
171
+ /** Encode an i64 as little-endian 8 bytes (matches Anchor / Borsh). */
172
+ function i64LeBytes(value: bigint): Buffer {
173
+ const buf = Buffer.alloc(8);
174
+ buf.writeBigInt64LE(value, 0);
175
+ return buf;
176
+ }
177
+
178
+ /**
179
+ * DailyAnchorAccount PDA — owned by Registry program. One per
180
+ * (deployment, UTC day) — captures the Merkle root over that day's
181
+ * task hashes.
182
+ *
183
+ * seeds = ["daily_anchor", deployment_pda, day_unix_le_i64]
184
+ *
185
+ * `dayUnix` must be aligned to 00:00:00 UTC (multiple of 86400). The
186
+ * on-chain handler enforces alignment; passing an unaligned value will
187
+ * fail with a constraint error.
188
+ */
189
+ export function deriveDailyAnchorPda(
190
+ deploymentPda: PublicKey,
191
+ dayUnix: bigint,
192
+ programId: PublicKey = REGISTRY_PROGRAM_ID,
193
+ ): { pda: PublicKey; bump: number } {
194
+ const [pda, bump] = PublicKey.findProgramAddressSync(
195
+ [DAILY_ANCHOR_SEED, deploymentPda.toBuffer(), i64LeBytes(dayUnix)],
196
+ programId,
197
+ );
198
+ return { pda, bump };
199
+ }