1use crate::cells::StorageKeySpec;
8use serde::{Deserialize, Serialize};
9
10pub type AccountId = [u8; 32];
11
12pub fn system_authority_id() -> AccountId {
13 use sha2::{Digest, Sha256};
14 let mut hasher = Sha256::new();
15 hasher.update(b"truthlinked-system-authority-v1");
16 let hash = hasher.finalize();
17 let mut account_id = [0u8; 32];
18 account_id.copy_from_slice(&hash);
19 account_id
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct BatchTransferEntry {
24 pub recipient: AccountId,
25 pub recipient_pubkey: Option<Vec<u8>>,
27 pub amount: u128,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct NameTransferEntry {
32 pub name: String,
33 pub amount: u128,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct CellCall {
38 pub cell_id: AccountId,
39 pub calldata: Vec<u8>,
40 pub value: u128,
41 pub use_result_from: Option<usize>,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct Transaction {
46 pub sender: AccountId,
47 pub intent: TransactionIntent,
48 pub signature: Vec<u8>,
49 #[serde(default)]
50 pub nonce: u64,
51 pub timestamp: u64,
52 pub genesis_fingerprint: [u8; 32],
53 pub expiration_height: u64,
54}
55
56impl Transaction {
57 pub fn byte_weight(&self) -> Result<usize, postcard::Error> {
59 postcard::to_allocvec(self).map(|bytes| bytes.len())
60 }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64#[allow(clippy::large_enum_variant)]
65pub enum TransactionIntent {
66 Transfer {
67 recipient: AccountId,
68 recipient_pubkey: Option<Vec<u8>>,
70 amount: u128,
71 },
72 TransferToName {
73 name: String,
74 amount: u128,
75 },
76 BatchTransfer {
77 transfers: Vec<BatchTransferEntry>,
78 },
79 BatchTransferToName {
80 transfers: Vec<NameTransferEntry>,
81 },
82 Claim {
83 recipient: AccountId,
84 recipient_pubkey: Option<Vec<u8>>,
86 amount: u128,
87 },
88 RotateKey {
89 new_pubkey: Vec<u8>,
90 },
91 DepositCompute {
92 amount: u128,
93 },
94 WithdrawCompute {
95 amount: u128,
96 },
97 WrapTRTH {
99 amount: u128,
100 },
101 UnwrapTRTH {
103 amount: u128,
104 },
105 Stake {
106 amount: u128,
107 },
108 Unstake {
109 amount: u128,
110 },
111 WithdrawStake,
112 Unjail,
113 MintNFT {
114 nft_id: [u8; 32],
115 name: String,
116 metadata_uri: String,
117 collection: Option<[u8; 32]>,
118 royalty_bps: u16,
119 royalty_recipient: Option<AccountId>,
120 },
121 TransferNFT {
122 nft_id: [u8; 32],
123 recipient: AccountId,
124 recipient_pubkey: Option<Vec<u8>>,
126 sale_price: Option<u128>,
127 },
128 BurnNFT {
129 nft_id: [u8; 32],
130 },
131 ApproveNFT {
132 nft_id: [u8; 32],
133 approved: Option<AccountId>,
134 },
135 DeployCell {
136 cell_id: AccountId,
137 bytecode: Vec<u8>,
138 initial_balance: u128,
139 declared_reads: Vec<[u8; 32]>,
140 declared_writes: Vec<[u8; 32]>,
141 commutative_keys: Vec<[u8; 32]>,
142 storage_key_specs: Vec<StorageKeySpec>,
143 oracle_schema_ids: Vec<[u8; 32]>,
144 },
145 DeployToken {
146 cell_id: AccountId,
147 name: String,
148 symbol: String,
149 decimals: u8,
150 total_supply: u128,
151 transfer_fee_bps: u16,
152 transfer_fee_recipient: Option<AccountId>,
153 non_transferable: bool,
154 },
155 CallCell {
156 cell_id: AccountId,
157 calldata: Vec<u8>,
158 value: u128,
159 gas_limit: u64,
160 },
161 CallCellChain {
162 calls: Vec<CellCall>,
163 gas_limit: u64,
164 },
165 UpgradeCell {
166 cell_id: AccountId,
167 new_bytecode: Vec<u8>,
168 new_declared_reads: Vec<[u8; 32]>,
169 new_declared_writes: Vec<[u8; 32]>,
170 new_commutative_keys: Vec<[u8; 32]>,
171 new_storage_key_specs: Vec<StorageKeySpec>,
172 new_oracle_schema_ids: Vec<[u8; 32]>,
173 },
174 TransferOwnership {
175 cell_id: AccountId,
176 new_owner: AccountId,
177 },
178 AcceptOwnership {
179 cell_id: AccountId,
180 },
181 MakeImmutable {
182 cell_id: AccountId,
183 },
184 CloseCell {
185 cell_id: AccountId,
186 },
187 ProposeCellUpgrade {
188 cell_id: AccountId,
189 new_bytecode: Vec<u8>,
190 new_declared_reads: Vec<[u8; 32]>,
191 new_declared_writes: Vec<[u8; 32]>,
192 new_commutative_keys: Vec<[u8; 32]>,
193 new_storage_key_specs: Vec<StorageKeySpec>,
194 new_oracle_schema_ids: Vec<[u8; 32]>,
195 timelock_blocks: u64,
196 },
197 ProposeCellOwnershipTransfer {
198 cell_id: AccountId,
199 new_owner: AccountId,
200 timelock_blocks: u64,
201 },
202 ProposeCellMakeImmutable {
203 cell_id: AccountId,
204 timelock_blocks: u64,
205 },
206 VoteCellProposal {
207 cell_id: AccountId,
208 approve: bool,
209 },
210 ExecuteCellProposal {
211 cell_id: AccountId,
212 },
213 TokenTransfer {
214 token_cell: AccountId,
215 recipient: AccountId,
216 amount: u128,
217 },
218 TokenMint {
219 token_cell: AccountId,
220 recipient: AccountId,
221 amount: u128,
222 },
223 TokenBurn {
224 token_cell: AccountId,
225 amount: u128,
226 },
227 TokenFreeze {
228 token_cell: AccountId,
229 account: AccountId,
230 },
231 TokenThaw {
232 token_cell: AccountId,
233 account: AccountId,
234 },
235 ProposeTokenAuthority {
236 token_cell: AccountId,
237 set_mint_authority: bool,
238 new_mint_authority: AccountId,
239 set_freeze_authority: bool,
240 new_freeze_authority: AccountId,
241 voting_period_blocks: u64,
242 },
243 VoteTokenAuthority {
244 token_cell: AccountId,
245 approve: bool,
246 },
247 CallSystem {
248 controller: AccountId,
249 calldata: Vec<u8>,
250 },
251 ProposeUrl {
252 url_pattern: String,
253 bond_amount: u128,
254 voting_period_blocks: u64,
255 },
256 VoteUrl {
257 url_pattern: String,
258 approve: bool,
259 },
260 ReportMaliciousUrl {
261 url_pattern: String,
262 evidence: String,
263 },
264 SetCellVisibility {
265 cell_id: AccountId,
266 visibility: u8,
267 },
268 RegisterMcpTool {
270 tool_id: AccountId,
271 bytecode: Vec<u8>,
272 name: String,
273 input_schema_json: Vec<u8>,
274 category: u8,
275 declared_reads: Vec<[u8; 32]>,
276 declared_writes: Vec<[u8; 32]>,
277 commutative_keys: Vec<[u8; 32]>,
278 oracle_schema_ids: Vec<[u8; 32]>,
279 registry_id: AccountId,
280 },
281 RegisterMcpResource {
282 resource_id: AccountId,
283 bytecode: Vec<u8>,
284 name: String,
285 uri_scheme: String,
286 mime_type: String,
287 initial_data: Vec<(Vec<u8>, Vec<u8>)>,
288 declared_reads: Vec<[u8; 32]>,
289 declared_writes: Vec<[u8; 32]>,
290 oracle_schema_ids: Vec<[u8; 32]>,
291 registry_id: AccountId,
292 },
293 RegisterMcpPrompt {
294 prompt_id: AccountId,
295 name: String,
296 template_bytes: Vec<u8>,
297 arguments: Vec<(String, String, bool)>,
298 registry_id: AccountId,
299 },
300 RegisterAgent {
301 agent_id: AccountId,
302 policy_cell_id: AccountId,
303 agent_registry_id: AccountId,
304 },
305 SuspendAgent {
306 agent_id: AccountId,
307 agent_registry_id: AccountId,
308 reason: String,
309 },
310 ReinstateAgent {
311 agent_id: AccountId,
312 agent_registry_id: AccountId,
313 },
314 McpToolCall {
315 agent_id: AccountId,
316 tool_id: AccountId,
317 tool_calldata: Vec<u8>,
318 value: u128,
319 gas_limit: u64,
320 policy_cell_id: AccountId,
321 action_log_id: Option<AccountId>,
322 timestamp: u64,
323 },
324 PrivateBalanceInit {
325 cell_id: AccountId,
326 agent_id: AccountId,
327 encrypted_balance: Vec<u8>,
328 commitment: [u8; 32],
329 commit_nonce: [u8; 16],
330 },
331 PrivateBalanceDeposit {
332 cell_id: AccountId,
333 agent_id: AccountId,
334 amount: u128,
335 new_encrypted_balance: Vec<u8>,
336 new_commitment: [u8; 32],
337 new_commit_nonce: [u8; 16],
338 old_commitment: [u8; 32],
339 },
340 PrivateBalanceWithdraw {
341 cell_id: AccountId,
342 agent_id: AccountId,
343 amount: u128,
344 recipient: AccountId,
345 new_encrypted_balance: Vec<u8>,
346 new_commitment: [u8; 32],
347 new_commit_nonce: [u8; 16],
348 old_commitment: [u8; 32],
349 },
350 PrivateBalanceConfidentialTransfer {
351 sender_cell_id: AccountId,
352 sender_agent_id: AccountId,
353 recipient_cell_id: AccountId,
354 amount_commitment: [u8; 32],
355 stark_proof: Vec<u8>,
356 sender_new_encrypted: Vec<u8>,
357 sender_new_commitment: [u8; 32],
358 sender_new_commit_nonce: [u8; 16],
359 sender_old_commitment: [u8; 32],
360 recipient_new_encrypted: Vec<u8>,
361 recipient_new_commitment: [u8; 32],
362 recipient_new_commit_nonce: [u8; 16],
363 recipient_old_commitment: [u8; 32],
364 proof_sender_old_balance: u64,
365 proof_sender_new_balance: u64,
366 proof_recipient_old_balance: u64,
367 proof_recipient_new_balance: u64,
368 proof_amount: u64,
369 },
370 SubmitOracleCommit {
372 request_id: [u8; 32],
373 commit_hash: [u8; 32],
374 },
375 SubmitOracleReveal {
376 request_id: [u8; 32],
377 response_body: Vec<u8>,
378 response_status: u16,
379 },
380}
381
382pub fn system_cell_id(label: &str) -> AccountId {
383 use sha2::{Digest, Sha256};
384 let mut hasher = Sha256::new();
385 hasher.update(label.as_bytes());
386 hasher.finalize().into()
387}
388
389pub fn staking_system_cell_id() -> AccountId {
390 system_cell_id("truthlinked-staking-v1")
391}
392
393pub fn treasury_system_cell_id() -> AccountId {
394 system_cell_id("truthlinked-treasury-v1")
395}
396
397pub fn governance_system_cell_id() -> AccountId {
398 system_cell_id("truthlinked-governance-v1")
399}
400
401pub fn name_registry_system_cell_id() -> AccountId {
402 system_cell_id("truthlinked-name-registry-v1")
403}
404
405pub fn token_governance_system_cell_id() -> AccountId {
406 system_cell_id("truthlinked-token-governance-v1")
407}
408
409pub fn oracle_governance_system_cell_id() -> AccountId {
410 system_cell_id("truthlinked-oracle-governance-v1")
411}
412
413pub fn usdc_system_cell_id() -> AccountId {
414 system_cell_id("truthlinked-usdc-controller-v1")
415}
416
417pub fn wtrth_system_cell_id() -> AccountId {
418 system_cell_id("truthlinked-wtrth-v1")
419}
420
421pub fn usdt_system_cell_id() -> AccountId {
422 system_cell_id("truthlinked-usdt-controller-v1")
423}
424
425impl Transaction {
426 pub fn current_timestamp() -> u64 {
427 std::time::SystemTime::now()
428 .duration_since(std::time::UNIX_EPOCH)
429 .unwrap()
430 .as_secs()
431 }
432}
433
434impl TransactionIntent {
435 pub fn cell_id_option(&self) -> Option<AccountId> {
436 match self {
437 TransactionIntent::DeployCell { cell_id, .. }
438 | TransactionIntent::DeployToken { cell_id, .. }
439 | TransactionIntent::CallCell { cell_id, .. }
440 | TransactionIntent::UpgradeCell { cell_id, .. }
441 | TransactionIntent::TransferOwnership { cell_id, .. }
442 | TransactionIntent::AcceptOwnership { cell_id }
443 | TransactionIntent::MakeImmutable { cell_id }
444 | TransactionIntent::CloseCell { cell_id }
445 | TransactionIntent::ProposeCellUpgrade { cell_id, .. }
446 | TransactionIntent::ProposeCellOwnershipTransfer { cell_id, .. }
447 | TransactionIntent::ProposeCellMakeImmutable { cell_id, .. }
448 | TransactionIntent::VoteCellProposal { cell_id, .. }
449 | TransactionIntent::ExecuteCellProposal { cell_id, .. }
450 | TransactionIntent::TokenTransfer {
451 token_cell: cell_id,
452 ..
453 }
454 | TransactionIntent::TokenMint {
455 token_cell: cell_id,
456 ..
457 }
458 | TransactionIntent::TokenBurn {
459 token_cell: cell_id,
460 ..
461 } => Some(*cell_id),
462 TransactionIntent::CallCellChain { calls, .. } => calls.first().map(|c| c.cell_id),
463 _ => None,
464 }
465 }
466}