nara-sdk 1.0.62 → 1.0.64

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/nara-chain/nara-web/main/public/favicon.png" width="48" />
2
+ <img src="https://raw.githubusercontent.com/nara-chain/nara-web/main/public/favicon-v3.svg" width="48" />
3
3
  </p>
4
4
 
5
5
  <h3 align="center">Nara SDK</h3>
package/index.ts CHANGED
@@ -126,6 +126,7 @@ export {
126
126
  // Twitter verification
127
127
  getAgentTwitter,
128
128
  getTweetVerify,
129
+ getTweetRecord,
129
130
  getPendingTwitterVerifications,
130
131
  getPendingTweetVerifications,
131
132
  setTwitter,
@@ -152,6 +153,7 @@ export {
152
153
  type AgentInfo,
153
154
  type AgentTwitterInfo,
154
155
  type TweetVerifyInfo,
156
+ type TweetRecordInfo,
155
157
  type MemoryMode,
156
158
  type AgentRegistryOptions,
157
159
  } from "./src/agent_registry";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nara-sdk",
3
- "version": "1.0.62",
3
+ "version": "1.0.64",
4
4
  "description": "SDK for the Nara chain (Solana-compatible)",
5
5
  "module": "index.ts",
6
6
  "main": "index.ts",
@@ -12,6 +12,7 @@ import {
12
12
  } from "@solana/web3.js";
13
13
  import * as anchor from "@coral-xyz/anchor";
14
14
  import { Program, AnchorProvider, Wallet } from "@coral-xyz/anchor";
15
+ import BN from "bn.js";
15
16
  import { getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
16
17
  import type { NaraAgentRegistry } from "./idls/nara_agent_registry";
17
18
  import { DEFAULT_AGENT_REGISTRY_PROGRAM_ID } from "./constants";
@@ -65,7 +66,13 @@ export interface TweetVerifyInfo {
65
66
  status: number;
66
67
  submittedAt: number;
67
68
  lastRewardedAt: number;
68
- tweetUrl: string;
69
+ tweetId: bigint;
70
+ }
71
+
72
+ export interface TweetRecordInfo {
73
+ agent: PublicKey;
74
+ approvedAt: number;
75
+ tweetId: bigint;
69
76
  }
70
77
 
71
78
  export type MemoryMode = "new" | "update" | "append" | "auto";
@@ -295,9 +302,8 @@ function parseTweetVerifyData(data: Buffer | Uint8Array): TweetVerifyInfo {
295
302
  const status = Number(buf.readBigUInt64LE(offset)); offset += 8;
296
303
  const submittedAt = Number(buf.readBigInt64LE(offset)); offset += 8;
297
304
  const lastRewardedAt = Number(buf.readBigInt64LE(offset)); offset += 8;
298
- const tweetUrlLen = Number(buf.readBigUInt64LE(offset)); offset += 8;
299
- const tweetUrl = buf.subarray(offset, offset + tweetUrlLen).toString("utf-8");
300
- return { agentId, status, submittedAt, lastRewardedAt, tweetUrl };
305
+ const tweetId = buf.readBigUInt64LE(offset) | (buf.readBigUInt64LE(offset + 8) << 64n); offset += 16;
306
+ return { agentId, status, submittedAt, lastRewardedAt, tweetId };
301
307
  }
302
308
 
303
309
  /**
@@ -980,11 +986,11 @@ export async function updateAdmin(
980
986
  export async function withdrawFees(
981
987
  connection: Connection,
982
988
  wallet: Keypair,
983
- amount: number | anchor.BN,
989
+ amount: number | BN,
984
990
  options?: AgentRegistryOptions
985
991
  ): Promise<string> {
986
992
  const program = createProgram(connection, wallet, options?.programId);
987
- const amt = typeof amount === "number" ? new anchor.BN(amount) : amount;
993
+ const amt = typeof amount === "number" ? new BN(amount) : amount;
988
994
  const ix = await program.methods
989
995
  .withdrawFees(amt)
990
996
  .accounts({ admin: wallet.publicKey } as any)
@@ -998,11 +1004,11 @@ export async function withdrawFees(
998
1004
  export async function updateRegisterFee(
999
1005
  connection: Connection,
1000
1006
  wallet: Keypair,
1001
- newFee: number | anchor.BN,
1007
+ newFee: number | BN,
1002
1008
  options?: AgentRegistryOptions
1003
1009
  ): Promise<string> {
1004
1010
  const program = createProgram(connection, wallet, options?.programId);
1005
- const fee = typeof newFee === "number" ? new anchor.BN(newFee) : newFee;
1011
+ const fee = typeof newFee === "number" ? new BN(newFee) : newFee;
1006
1012
  const ix = await program.methods
1007
1013
  .updateRegisterFee(fee)
1008
1014
  .accounts({ admin: wallet.publicKey } as any)
@@ -1017,13 +1023,13 @@ export async function updateRegisterFee(
1017
1023
  export async function updatePointsConfig(
1018
1024
  connection: Connection,
1019
1025
  wallet: Keypair,
1020
- pointsSelf: number | anchor.BN,
1021
- pointsReferral: number | anchor.BN,
1026
+ pointsSelf: number | BN,
1027
+ pointsReferral: number | BN,
1022
1028
  options?: AgentRegistryOptions
1023
1029
  ): Promise<string> {
1024
1030
  const program = createProgram(connection, wallet, options?.programId);
1025
- const ps = typeof pointsSelf === "number" ? new anchor.BN(pointsSelf) : pointsSelf;
1026
- const pr = typeof pointsReferral === "number" ? new anchor.BN(pointsReferral) : pointsReferral;
1031
+ const ps = typeof pointsSelf === "number" ? new BN(pointsSelf) : pointsSelf;
1032
+ const pr = typeof pointsReferral === "number" ? new BN(pointsReferral) : pointsReferral;
1027
1033
  const ix = await program.methods
1028
1034
  .updatePointsConfig(ps, pr)
1029
1035
  .accounts({ admin: wallet.publicKey } as any)
@@ -1040,15 +1046,15 @@ export async function updatePointsConfig(
1040
1046
  export async function updateReferralConfig(
1041
1047
  connection: Connection,
1042
1048
  wallet: Keypair,
1043
- referralRegisterFee: number | anchor.BN,
1044
- referralFeeShare: number | anchor.BN,
1045
- referralRegisterPoints: number | anchor.BN,
1049
+ referralRegisterFee: number | BN,
1050
+ referralFeeShare: number | BN,
1051
+ referralRegisterPoints: number | BN,
1046
1052
  options?: AgentRegistryOptions
1047
1053
  ): Promise<string> {
1048
1054
  const program = createProgram(connection, wallet, options?.programId);
1049
- const fee = typeof referralRegisterFee === "number" ? new anchor.BN(referralRegisterFee) : referralRegisterFee;
1050
- const share = typeof referralFeeShare === "number" ? new anchor.BN(referralFeeShare) : referralFeeShare;
1051
- const pts = typeof referralRegisterPoints === "number" ? new anchor.BN(referralRegisterPoints) : referralRegisterPoints;
1055
+ const fee = typeof referralRegisterFee === "number" ? new BN(referralRegisterFee) : referralRegisterFee;
1056
+ const share = typeof referralFeeShare === "number" ? new BN(referralFeeShare) : referralFeeShare;
1057
+ const pts = typeof referralRegisterPoints === "number" ? new BN(referralRegisterPoints) : referralRegisterPoints;
1052
1058
  const ix = await program.methods
1053
1059
  .updateReferralConfig(fee, share, pts)
1054
1060
  .accounts({ admin: wallet.publicKey } as any)
@@ -1064,13 +1070,13 @@ export async function updateReferralConfig(
1064
1070
  export async function updateActivityConfig(
1065
1071
  connection: Connection,
1066
1072
  wallet: Keypair,
1067
- activityReward: number | anchor.BN,
1068
- referralActivityReward: number | anchor.BN,
1073
+ activityReward: number | BN,
1074
+ referralActivityReward: number | BN,
1069
1075
  options?: AgentRegistryOptions
1070
1076
  ): Promise<string> {
1071
1077
  const program = createProgram(connection, wallet, options?.programId);
1072
- const ar = typeof activityReward === "number" ? new anchor.BN(activityReward) : activityReward;
1073
- const rar = typeof referralActivityReward === "number" ? new anchor.BN(referralActivityReward) : referralActivityReward;
1078
+ const ar = typeof activityReward === "number" ? new BN(activityReward) : activityReward;
1079
+ const rar = typeof referralActivityReward === "number" ? new BN(referralActivityReward) : referralActivityReward;
1074
1080
  const ix = await program.methods
1075
1081
  .updateActivityConfig(ar, rar)
1076
1082
  .accounts({ admin: wallet.publicKey } as any)
@@ -1084,11 +1090,11 @@ export async function updateActivityConfig(
1084
1090
  export async function expandConfig(
1085
1091
  connection: Connection,
1086
1092
  wallet: Keypair,
1087
- extendSize: number | anchor.BN,
1093
+ extendSize: number | BN,
1088
1094
  options?: AgentRegistryOptions
1089
1095
  ): Promise<string> {
1090
1096
  const program = createProgram(connection, wallet, options?.programId);
1091
- const size = typeof extendSize === "number" ? new anchor.BN(extendSize) : extendSize;
1097
+ const size = typeof extendSize === "number" ? new BN(extendSize) : extendSize;
1092
1098
  const ix = await program.methods
1093
1099
  .expandConfig(size)
1094
1100
  .accounts({ admin: wallet.publicKey } as any)
@@ -1122,15 +1128,15 @@ export async function updateTwitterVerifier(
1122
1128
  export async function updateTwitterVerificationConfig(
1123
1129
  connection: Connection,
1124
1130
  wallet: Keypair,
1125
- fee: number | anchor.BN,
1126
- reward: number | anchor.BN,
1127
- points: number | anchor.BN,
1131
+ fee: number | BN,
1132
+ reward: number | BN,
1133
+ points: number | BN,
1128
1134
  options?: AgentRegistryOptions
1129
1135
  ): Promise<string> {
1130
1136
  const program = createProgram(connection, wallet, options?.programId);
1131
- const f = typeof fee === "number" ? new anchor.BN(fee) : fee;
1132
- const r = typeof reward === "number" ? new anchor.BN(reward) : reward;
1133
- const p = typeof points === "number" ? new anchor.BN(points) : points;
1137
+ const f = typeof fee === "number" ? new BN(fee) : fee;
1138
+ const r = typeof reward === "number" ? new BN(reward) : reward;
1139
+ const p = typeof points === "number" ? new BN(points) : points;
1134
1140
  const ix = await program.methods
1135
1141
  .updateTwitterVerificationConfig(f, r, p)
1136
1142
  .accounts({ admin: wallet.publicKey } as any)
@@ -1146,13 +1152,13 @@ export async function updateTwitterVerificationConfig(
1146
1152
  export async function updateTweetVerifyConfig(
1147
1153
  connection: Connection,
1148
1154
  wallet: Keypair,
1149
- reward: number | anchor.BN,
1150
- points: number | anchor.BN,
1155
+ reward: number | BN,
1156
+ points: number | BN,
1151
1157
  options?: AgentRegistryOptions
1152
1158
  ): Promise<string> {
1153
1159
  const program = createProgram(connection, wallet, options?.programId);
1154
- const r = typeof reward === "number" ? new anchor.BN(reward) : reward;
1155
- const p = typeof points === "number" ? new anchor.BN(points) : points;
1160
+ const r = typeof reward === "number" ? new BN(reward) : reward;
1161
+ const p = typeof points === "number" ? new BN(points) : points;
1156
1162
  const ix = await program.methods
1157
1163
  .updateTweetVerifyConfig(r, p)
1158
1164
  .accounts({ admin: wallet.publicKey } as any)
@@ -1166,11 +1172,11 @@ export async function updateTweetVerifyConfig(
1166
1172
  export async function withdrawTwitterVerifyFees(
1167
1173
  connection: Connection,
1168
1174
  wallet: Keypair,
1169
- amount: number | anchor.BN,
1175
+ amount: number | BN,
1170
1176
  options?: AgentRegistryOptions
1171
1177
  ): Promise<string> {
1172
1178
  const program = createProgram(connection, wallet, options?.programId);
1173
- const amt = typeof amount === "number" ? new anchor.BN(amount) : amount;
1179
+ const amt = typeof amount === "number" ? new BN(amount) : amount;
1174
1180
  const ix = await program.methods
1175
1181
  .withdrawTwitterVerifyFees(amt)
1176
1182
  .accounts({ admin: wallet.publicKey } as any)
@@ -1214,6 +1220,34 @@ export async function getTweetVerify(
1214
1220
  return parseTweetVerifyData(accountInfo.data);
1215
1221
  }
1216
1222
 
1223
+ /**
1224
+ * Read a tweet record by tweet ID.
1225
+ * Returns null if no record exists.
1226
+ */
1227
+ export async function getTweetRecord(
1228
+ connection: Connection,
1229
+ tweetId: bigint,
1230
+ options?: AgentRegistryOptions
1231
+ ): Promise<TweetRecordInfo | null> {
1232
+ const pid = new PublicKey(options?.programId ?? DEFAULT_AGENT_REGISTRY_PROGRAM_ID);
1233
+ const tweetIdBuf = Buffer.alloc(16);
1234
+ tweetIdBuf.writeBigUInt64LE(tweetId & 0xFFFFFFFFFFFFFFFFn, 0);
1235
+ tweetIdBuf.writeBigUInt64LE(tweetId >> 64n, 8);
1236
+ const [pda] = PublicKey.findProgramAddressSync(
1237
+ [Buffer.from("tweet_record"), tweetIdBuf],
1238
+ pid
1239
+ );
1240
+ const accountInfo = await connection.getAccountInfo(pda);
1241
+ if (!accountInfo) return null;
1242
+
1243
+ const buf = Buffer.from(accountInfo.data);
1244
+ let offset = 8; // skip discriminator
1245
+ const agent = new PublicKey(buf.subarray(offset, offset + 32)); offset += 32;
1246
+ const approvedAt = Number(buf.readBigInt64LE(offset)); offset += 8;
1247
+ const recordTweetId = buf.readBigUInt64LE(offset) | (buf.readBigUInt64LE(offset + 8) << 64n);
1248
+ return { agent, approvedAt, tweetId: recordTweetId };
1249
+ }
1250
+
1217
1251
  /** Batch getMultipleAccountsInfo in chunks of 100 (RPC limit). */
1218
1252
  async function batchGetMultipleAccounts(
1219
1253
  connection: Connection,
@@ -1329,12 +1363,12 @@ export async function submitTweet(
1329
1363
  connection: Connection,
1330
1364
  wallet: Keypair,
1331
1365
  agentId: string,
1332
- tweetUrl: string,
1366
+ tweetId: bigint,
1333
1367
  options?: AgentRegistryOptions
1334
1368
  ): Promise<string> {
1335
1369
  const program = createProgram(connection, wallet, options?.programId);
1336
1370
  const ix = await program.methods
1337
- .submitTweet(agentId, tweetUrl)
1371
+ .submitTweet(agentId, new BN(tweetId.toString()))
1338
1372
  .accounts({ authority: wallet.publicKey } as any)
1339
1373
  .instruction();
1340
1374
  return sendTx(connection, wallet, [ix]);
@@ -1370,7 +1404,7 @@ export async function verifyTwitter(
1370
1404
  username: string,
1371
1405
  options?: AgentRegistryOptions,
1372
1406
  freeStakeDelta?: number,
1373
- tweetUrl?: string
1407
+ freeStakeReason?: string
1374
1408
  ): Promise<string> {
1375
1409
  const program = createProgram(connection, wallet, options?.programId);
1376
1410
  const agentPda = getAgentPda(program.programId, agentId);
@@ -1398,7 +1432,7 @@ export async function verifyTwitter(
1398
1432
  if (freeStakeDelta !== undefined && freeStakeDelta !== 0) {
1399
1433
  const { makeAdjustFreeStakeIx } = await import("./quest");
1400
1434
  const freeStakeIx = await makeAdjustFreeStakeIx(
1401
- connection, wallet.publicKey, authority, freeStakeDelta, tweetUrl ?? ""
1435
+ connection, wallet.publicKey, authority, freeStakeDelta, freeStakeReason ?? ""
1402
1436
  );
1403
1437
  ixs.push(freeStakeIx);
1404
1438
  }
@@ -1432,9 +1466,10 @@ export async function approveTweet(
1432
1466
  connection: Connection,
1433
1467
  wallet: Keypair,
1434
1468
  agentId: string,
1469
+ tweetId: bigint,
1435
1470
  options?: AgentRegistryOptions,
1436
1471
  freeStakeDelta?: number,
1437
- tweetUrl?: string
1472
+ freeStakeReason?: string
1438
1473
  ): Promise<string> {
1439
1474
  const program = createProgram(connection, wallet, options?.programId);
1440
1475
  const agentPda = getAgentPda(program.programId, agentId);
@@ -1450,7 +1485,7 @@ export async function approveTweet(
1450
1485
  );
1451
1486
 
1452
1487
  const ix = await program.methods
1453
- .approveTweet(agentId)
1488
+ .approveTweet(agentId, new BN(tweetId.toString()))
1454
1489
  .accounts({
1455
1490
  verifier: wallet.publicKey,
1456
1491
  authority,
@@ -1462,7 +1497,7 @@ export async function approveTweet(
1462
1497
  if (freeStakeDelta !== undefined && freeStakeDelta !== 0) {
1463
1498
  const { makeAdjustFreeStakeIx } = await import("./quest");
1464
1499
  const freeStakeIx = await makeAdjustFreeStakeIx(
1465
- connection, wallet.publicKey, authority, freeStakeDelta, tweetUrl ?? ""
1500
+ connection, wallet.publicKey, authority, freeStakeDelta, freeStakeReason ?? ""
1466
1501
  );
1467
1502
  ixs.push(freeStakeIx);
1468
1503
  }
@@ -93,6 +93,35 @@
93
93
  ]
94
94
  }
95
95
  },
96
+ {
97
+ "name": "tweet_record",
98
+ "writable": true,
99
+ "pda": {
100
+ "seeds": [
101
+ {
102
+ "kind": "const",
103
+ "value": [
104
+ 116,
105
+ 119,
106
+ 101,
107
+ 101,
108
+ 116,
109
+ 95,
110
+ 114,
111
+ 101,
112
+ 99,
113
+ 111,
114
+ 114,
115
+ 100
116
+ ]
117
+ },
118
+ {
119
+ "kind": "arg",
120
+ "path": "tweet_id"
121
+ }
122
+ ]
123
+ }
124
+ },
96
125
  {
97
126
  "name": "authority",
98
127
  "writable": true
@@ -305,6 +334,10 @@
305
334
  {
306
335
  "name": "agent_id",
307
336
  "type": "string"
337
+ },
338
+ {
339
+ "name": "tweet_id",
340
+ "type": "u128"
308
341
  }
309
342
  ]
310
343
  },
@@ -2804,6 +2837,34 @@
2804
2837
  ]
2805
2838
  }
2806
2839
  },
2840
+ {
2841
+ "name": "tweet_record",
2842
+ "pda": {
2843
+ "seeds": [
2844
+ {
2845
+ "kind": "const",
2846
+ "value": [
2847
+ 116,
2848
+ 119,
2849
+ 101,
2850
+ 101,
2851
+ 116,
2852
+ 95,
2853
+ 114,
2854
+ 101,
2855
+ 99,
2856
+ 111,
2857
+ 114,
2858
+ 100
2859
+ ]
2860
+ },
2861
+ {
2862
+ "kind": "arg",
2863
+ "path": "tweet_id"
2864
+ }
2865
+ ]
2866
+ }
2867
+ },
2807
2868
  {
2808
2869
  "name": "system_program",
2809
2870
  "address": "11111111111111111111111111111111"
@@ -2815,8 +2876,8 @@
2815
2876
  "type": "string"
2816
2877
  },
2817
2878
  {
2818
- "name": "tweet_url",
2819
- "type": "string"
2879
+ "name": "tweet_id",
2880
+ "type": "u128"
2820
2881
  }
2821
2882
  ]
2822
2883
  },
@@ -4040,6 +4101,19 @@
4040
4101
  63
4041
4102
  ]
4042
4103
  },
4104
+ {
4105
+ "name": "TweetRecord",
4106
+ "discriminator": [
4107
+ 13,
4108
+ 25,
4109
+ 5,
4110
+ 236,
4111
+ 64,
4112
+ 149,
4113
+ 72,
4114
+ 215
4115
+ ]
4116
+ },
4043
4117
  {
4044
4118
  "name": "TweetVerify",
4045
4119
  "discriminator": [
@@ -4302,6 +4376,16 @@
4302
4376
  "code": 6043,
4303
4377
  "name": "TwitterAlreadyVerified",
4304
4378
  "msg": "Twitter is already verified, unbind first"
4379
+ },
4380
+ {
4381
+ "code": 6044,
4382
+ "name": "InvalidTweetUrlFormat",
4383
+ "msg": "Invalid tweet URL format"
4384
+ },
4385
+ {
4386
+ "code": 6045,
4387
+ "name": "TweetAlreadyApproved",
4388
+ "msg": "Tweet has already been approved"
4305
4389
  }
4306
4390
  ],
4307
4391
  "types": [
@@ -4664,6 +4748,53 @@
4664
4748
  ]
4665
4749
  }
4666
4750
  },
4751
+ {
4752
+ "name": "TweetRecord",
4753
+ "docs": [
4754
+ "Records an approved tweet to prevent duplicate submissions.",
4755
+ "Seeds: [SEED_TWEET_RECORD, &tweet_id.to_le_bytes()]"
4756
+ ],
4757
+ "serialization": "bytemuck",
4758
+ "repr": {
4759
+ "kind": "c",
4760
+ "packed": true
4761
+ },
4762
+ "type": {
4763
+ "kind": "struct",
4764
+ "fields": [
4765
+ {
4766
+ "name": "agent",
4767
+ "docs": [
4768
+ "The agent PDA that submitted this tweet"
4769
+ ],
4770
+ "type": "pubkey"
4771
+ },
4772
+ {
4773
+ "name": "approved_at",
4774
+ "docs": [
4775
+ "Unix timestamp when this tweet was approved"
4776
+ ],
4777
+ "type": "i64"
4778
+ },
4779
+ {
4780
+ "name": "tweet_id",
4781
+ "docs": [
4782
+ "Tweet ID (Twitter snowflake ID)"
4783
+ ],
4784
+ "type": "u128"
4785
+ },
4786
+ {
4787
+ "name": "_reserved",
4788
+ "type": {
4789
+ "array": [
4790
+ "u8",
4791
+ 64
4792
+ ]
4793
+ }
4794
+ }
4795
+ ]
4796
+ }
4797
+ },
4667
4798
  {
4668
4799
  "name": "TweetVerify",
4669
4800
  "docs": [
@@ -4672,7 +4803,8 @@
4672
4803
  ],
4673
4804
  "serialization": "bytemuck",
4674
4805
  "repr": {
4675
- "kind": "c"
4806
+ "kind": "c",
4807
+ "packed": true
4676
4808
  },
4677
4809
  "type": {
4678
4810
  "kind": "struct",
@@ -4712,17 +4844,14 @@
4712
4844
  "type": "i64"
4713
4845
  },
4714
4846
  {
4715
- "name": "tweet_url_len",
4847
+ "name": "tweet_id",
4716
4848
  "docs": [
4717
- "Actual byte length of tweet_url"
4849
+ "Tweet ID (Twitter snowflake ID)"
4718
4850
  ],
4719
- "type": "u64"
4851
+ "type": "u128"
4720
4852
  },
4721
4853
  {
4722
- "name": "tweet_url",
4723
- "docs": [
4724
- "Tweet URL (max 256 bytes)"
4725
- ],
4854
+ "name": "_reserved",
4726
4855
  "type": {
4727
4856
  "array": [
4728
4857
  "u8",
@@ -4731,7 +4860,7 @@
4731
4860
  }
4732
4861
  },
4733
4862
  {
4734
- "name": "_reserved",
4863
+ "name": "_reserved2",
4735
4864
  "type": {
4736
4865
  "array": [
4737
4866
  "u8",
@@ -4740,11 +4869,38 @@
4740
4869
  }
4741
4870
  },
4742
4871
  {
4743
- "name": "_reserved2",
4872
+ "name": "_reserved3",
4744
4873
  "type": {
4745
4874
  "array": [
4746
4875
  "u8",
4747
- 128
4876
+ 64
4877
+ ]
4878
+ }
4879
+ },
4880
+ {
4881
+ "name": "_reserved4",
4882
+ "type": {
4883
+ "array": [
4884
+ "u8",
4885
+ 32
4886
+ ]
4887
+ }
4888
+ },
4889
+ {
4890
+ "name": "_reserved5",
4891
+ "type": {
4892
+ "array": [
4893
+ "u8",
4894
+ 16
4895
+ ]
4896
+ }
4897
+ },
4898
+ {
4899
+ "name": "_reserved6",
4900
+ "type": {
4901
+ "array": [
4902
+ "u8",
4903
+ 8
4748
4904
  ]
4749
4905
  }
4750
4906
  }
@@ -99,6 +99,35 @@ export type NaraAgentRegistry = {
99
99
  ]
100
100
  }
101
101
  },
102
+ {
103
+ "name": "tweetRecord",
104
+ "writable": true,
105
+ "pda": {
106
+ "seeds": [
107
+ {
108
+ "kind": "const",
109
+ "value": [
110
+ 116,
111
+ 119,
112
+ 101,
113
+ 101,
114
+ 116,
115
+ 95,
116
+ 114,
117
+ 101,
118
+ 99,
119
+ 111,
120
+ 114,
121
+ 100
122
+ ]
123
+ },
124
+ {
125
+ "kind": "arg",
126
+ "path": "tweetId"
127
+ }
128
+ ]
129
+ }
130
+ },
102
131
  {
103
132
  "name": "authority",
104
133
  "writable": true
@@ -311,6 +340,10 @@ export type NaraAgentRegistry = {
311
340
  {
312
341
  "name": "agentId",
313
342
  "type": "string"
343
+ },
344
+ {
345
+ "name": "tweetId",
346
+ "type": "u128"
314
347
  }
315
348
  ]
316
349
  },
@@ -2810,6 +2843,34 @@ export type NaraAgentRegistry = {
2810
2843
  ]
2811
2844
  }
2812
2845
  },
2846
+ {
2847
+ "name": "tweetRecord",
2848
+ "pda": {
2849
+ "seeds": [
2850
+ {
2851
+ "kind": "const",
2852
+ "value": [
2853
+ 116,
2854
+ 119,
2855
+ 101,
2856
+ 101,
2857
+ 116,
2858
+ 95,
2859
+ 114,
2860
+ 101,
2861
+ 99,
2862
+ 111,
2863
+ 114,
2864
+ 100
2865
+ ]
2866
+ },
2867
+ {
2868
+ "kind": "arg",
2869
+ "path": "tweetId"
2870
+ }
2871
+ ]
2872
+ }
2873
+ },
2813
2874
  {
2814
2875
  "name": "systemProgram",
2815
2876
  "address": "11111111111111111111111111111111"
@@ -2821,8 +2882,8 @@ export type NaraAgentRegistry = {
2821
2882
  "type": "string"
2822
2883
  },
2823
2884
  {
2824
- "name": "tweetUrl",
2825
- "type": "string"
2885
+ "name": "tweetId",
2886
+ "type": "u128"
2826
2887
  }
2827
2888
  ]
2828
2889
  },
@@ -4046,6 +4107,19 @@ export type NaraAgentRegistry = {
4046
4107
  63
4047
4108
  ]
4048
4109
  },
4110
+ {
4111
+ "name": "tweetRecord",
4112
+ "discriminator": [
4113
+ 13,
4114
+ 25,
4115
+ 5,
4116
+ 236,
4117
+ 64,
4118
+ 149,
4119
+ 72,
4120
+ 215
4121
+ ]
4122
+ },
4049
4123
  {
4050
4124
  "name": "tweetVerify",
4051
4125
  "discriminator": [
@@ -4308,6 +4382,16 @@ export type NaraAgentRegistry = {
4308
4382
  "code": 6043,
4309
4383
  "name": "twitterAlreadyVerified",
4310
4384
  "msg": "Twitter is already verified, unbind first"
4385
+ },
4386
+ {
4387
+ "code": 6044,
4388
+ "name": "invalidTweetUrlFormat",
4389
+ "msg": "Invalid tweet URL format"
4390
+ },
4391
+ {
4392
+ "code": 6045,
4393
+ "name": "tweetAlreadyApproved",
4394
+ "msg": "Tweet has already been approved"
4311
4395
  }
4312
4396
  ],
4313
4397
  "types": [
@@ -4670,6 +4754,53 @@ export type NaraAgentRegistry = {
4670
4754
  ]
4671
4755
  }
4672
4756
  },
4757
+ {
4758
+ "name": "tweetRecord",
4759
+ "docs": [
4760
+ "Records an approved tweet to prevent duplicate submissions.",
4761
+ "Seeds: [SEED_TWEET_RECORD, &tweet_id.to_le_bytes()]"
4762
+ ],
4763
+ "serialization": "bytemuck",
4764
+ "repr": {
4765
+ "kind": "c",
4766
+ "packed": true
4767
+ },
4768
+ "type": {
4769
+ "kind": "struct",
4770
+ "fields": [
4771
+ {
4772
+ "name": "agent",
4773
+ "docs": [
4774
+ "The agent PDA that submitted this tweet"
4775
+ ],
4776
+ "type": "pubkey"
4777
+ },
4778
+ {
4779
+ "name": "approvedAt",
4780
+ "docs": [
4781
+ "Unix timestamp when this tweet was approved"
4782
+ ],
4783
+ "type": "i64"
4784
+ },
4785
+ {
4786
+ "name": "tweetId",
4787
+ "docs": [
4788
+ "Tweet ID (Twitter snowflake ID)"
4789
+ ],
4790
+ "type": "u128"
4791
+ },
4792
+ {
4793
+ "name": "reserved",
4794
+ "type": {
4795
+ "array": [
4796
+ "u8",
4797
+ 64
4798
+ ]
4799
+ }
4800
+ }
4801
+ ]
4802
+ }
4803
+ },
4673
4804
  {
4674
4805
  "name": "tweetVerify",
4675
4806
  "docs": [
@@ -4678,7 +4809,8 @@ export type NaraAgentRegistry = {
4678
4809
  ],
4679
4810
  "serialization": "bytemuck",
4680
4811
  "repr": {
4681
- "kind": "c"
4812
+ "kind": "c",
4813
+ "packed": true
4682
4814
  },
4683
4815
  "type": {
4684
4816
  "kind": "struct",
@@ -4718,17 +4850,14 @@ export type NaraAgentRegistry = {
4718
4850
  "type": "i64"
4719
4851
  },
4720
4852
  {
4721
- "name": "tweetUrlLen",
4853
+ "name": "tweetId",
4722
4854
  "docs": [
4723
- "Actual byte length of tweet_url"
4855
+ "Tweet ID (Twitter snowflake ID)"
4724
4856
  ],
4725
- "type": "u64"
4857
+ "type": "u128"
4726
4858
  },
4727
4859
  {
4728
- "name": "tweetUrl",
4729
- "docs": [
4730
- "Tweet URL (max 256 bytes)"
4731
- ],
4860
+ "name": "reserved",
4732
4861
  "type": {
4733
4862
  "array": [
4734
4863
  "u8",
@@ -4737,7 +4866,7 @@ export type NaraAgentRegistry = {
4737
4866
  }
4738
4867
  },
4739
4868
  {
4740
- "name": "reserved",
4869
+ "name": "reserved2",
4741
4870
  "type": {
4742
4871
  "array": [
4743
4872
  "u8",
@@ -4746,11 +4875,38 @@ export type NaraAgentRegistry = {
4746
4875
  }
4747
4876
  },
4748
4877
  {
4749
- "name": "reserved2",
4878
+ "name": "reserved3",
4750
4879
  "type": {
4751
4880
  "array": [
4752
4881
  "u8",
4753
- 128
4882
+ 64
4883
+ ]
4884
+ }
4885
+ },
4886
+ {
4887
+ "name": "reserved4",
4888
+ "type": {
4889
+ "array": [
4890
+ "u8",
4891
+ 32
4892
+ ]
4893
+ }
4894
+ },
4895
+ {
4896
+ "name": "reserved5",
4897
+ "type": {
4898
+ "array": [
4899
+ "u8",
4900
+ 16
4901
+ ]
4902
+ }
4903
+ },
4904
+ {
4905
+ "name": "reserved6",
4906
+ "type": {
4907
+ "array": [
4908
+ "u8",
4909
+ 8
4754
4910
  ]
4755
4911
  }
4756
4912
  }