@txtcel/mcp 0.1.2 → 0.2.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
@@ -47867,7 +47867,6 @@ function loadWallet() {
47867
47867
  var import_zorsh = __toESM(require_src2(), 1);
47868
47868
  import { Buffer as Buffer3 } from "buffer";
47869
47869
  var TAG_CONTENT = 1;
47870
- var TAG_ALLOC = 2;
47871
47870
  var TAG_THREAD = 3;
47872
47871
  var TAG_SETTINGS = 5;
47873
47872
  var TAG_ACCESS = 6;
@@ -47875,12 +47874,11 @@ var TAG_LIKES = 7;
47875
47874
  var TAG_ACCESS_ENTRY = 9;
47876
47875
  var TAG_FOLLOW_REGISTRY = 10;
47877
47876
  var TAG_FOLLOWER_SHARD = 11;
47878
- var KIND_TEXT = 0;
47879
47877
  var ACCESS_ALLOWED = 0;
47880
47878
  var ACCESS_DENIED = 1;
47881
47879
  var ACCESS_FEE_EXEMPT = 2;
47882
- var NEXT_ALLOC_INDEX = 31;
47883
- var CONTENT_SLOTS = 31;
47880
+ var KIND_TEXT = 0;
47881
+ var CONTENT_SLOTS = 32;
47884
47882
  var EXTEND_THRESHOLD = 16;
47885
47883
  var MAX_BODY_LEN = 8192;
47886
47884
  var MAX_TITLE_LEN = 64;
@@ -47954,9 +47952,7 @@ var ContentNodeSchema = import_zorsh.b.struct({
47954
47952
  var AllocNodeSchema = import_zorsh.b.struct({
47955
47953
  tag: import_zorsh.b.u8(),
47956
47954
  thread: Pubkey,
47957
- allocSeq: import_zorsh.b.u32(),
47958
- upperAllocSeq: import_zorsh.b.u32(),
47959
- nextAllocSeq: import_zorsh.b.u32()
47955
+ allocSeq: import_zorsh.b.u32()
47960
47956
  });
47961
47957
  var ThreadNodeSchema = import_zorsh.b.struct({
47962
47958
  tag: import_zorsh.b.u8(),
@@ -47993,7 +47989,7 @@ var AccessEntrySchema = import_zorsh.b.struct({
47993
47989
  var AllocLikesSchema = import_zorsh.b.struct({
47994
47990
  tag: import_zorsh.b.u8(),
47995
47991
  allocSeq: import_zorsh.b.u32(),
47996
- counts: import_zorsh.b.array(import_zorsh.b.u32(), NEXT_ALLOC_INDEX)
47992
+ counts: import_zorsh.b.array(import_zorsh.b.u32(), CONTENT_SLOTS)
47997
47993
  });
47998
47994
  var FollowRegistrySchema = import_zorsh.b.struct({
47999
47995
  tag: import_zorsh.b.u8(),
@@ -48029,7 +48025,6 @@ var FillSlotInstr = import_zorsh.b.struct({
48029
48025
  kind: import_zorsh.b.u16(),
48030
48026
  body: import_zorsh.b.bytes(),
48031
48027
  candidates: import_zorsh.b.vec(CandidateSlotSchema),
48032
- extend: import_zorsh.b.u8(),
48033
48028
  treasuryShardIdx: import_zorsh.b.u16(),
48034
48029
  authorFeeShardIdx: import_zorsh.b.u8(),
48035
48030
  replyAllocSeq: import_zorsh.b.u32(),
@@ -48083,17 +48078,6 @@ function decodeContent(pubkey, data) {
48083
48078
  text: raw.kind === KIND_TEXT ? textDecoder.decode(raw.body) : ""
48084
48079
  };
48085
48080
  }
48086
- function decodeAlloc(pubkey, data) {
48087
- const raw = AllocNodeSchema.deserialize(data);
48088
- if (raw.tag !== TAG_ALLOC) throw new Error("Invalid AllocNode tag");
48089
- return {
48090
- pubkey,
48091
- seed: raw.thread,
48092
- allocSeq: raw.allocSeq,
48093
- upperAllocSeq: raw.upperAllocSeq === INDEX_NONE ? null : raw.upperAllocSeq,
48094
- nextAllocSeq: raw.nextAllocSeq === INDEX_NONE ? null : raw.nextAllocSeq
48095
- };
48096
- }
48097
48081
  var textDecoder2 = new TextDecoder();
48098
48082
  function decodeThread(pubkey, data) {
48099
48083
  const raw = ThreadNodeSchema.deserialize(data);
@@ -48250,47 +48234,46 @@ function randomTreasuryShard() {
48250
48234
  function randomAuthorFeeShard() {
48251
48235
  return Math.floor(Math.random() * N_AUTHOR_FEE_SHARDS);
48252
48236
  }
48237
+ function assertOwnedTag(info, programId, tag, name) {
48238
+ if (!info.owner.equals(programId)) throw new Error(`${name} not owned by program`);
48239
+ if (info.data.length === 0 || info.data[0] !== tag) throw new Error(`Invalid ${name} data`);
48240
+ }
48241
+ async function fetchRequiredAccount(connection, programId, key, tag, name) {
48242
+ const info = await connection.getAccountInfo(key, "confirmed");
48243
+ if (!info) throw new Error(`${name} not found`);
48244
+ assertOwnedTag(info, programId, tag, name);
48245
+ return info;
48246
+ }
48247
+ async function fetchOptionalAccount(connection, programId, key, tag, name) {
48248
+ const info = await connection.getAccountInfo(key, "confirmed");
48249
+ if (!info) return null;
48250
+ assertOwnedTag(info, programId, tag, name);
48251
+ return info;
48252
+ }
48253
+ function isOwnedTag(info, programId, tag) {
48254
+ return info !== null && info.owner.equals(programId) && info.data.length > 0 && info.data[0] === tag;
48255
+ }
48253
48256
  async function loadThreadNode(connection, programId, pubkey) {
48254
- const info = await connection.getAccountInfo(pubkey, "confirmed");
48255
- if (!info) throw new Error("ThreadNode not found");
48256
- if (!info.owner.equals(programId)) throw new Error("ThreadNode not owned by program");
48257
- if (info.data.length === 0 || info.data[0] !== TAG_THREAD) throw new Error("Invalid ThreadNode data");
48257
+ const info = await fetchRequiredAccount(connection, programId, pubkey, TAG_THREAD, "ThreadNode");
48258
48258
  return decodeThread(pubkey.toBase58(), info.data);
48259
48259
  }
48260
- async function loadAllocNode(connection, programId, pubkey) {
48261
- const info = await connection.getAccountInfo(pubkey, "confirmed");
48262
- if (!info) throw new Error("AllocNode not found");
48263
- if (!info.owner.equals(programId)) throw new Error("AllocNode not owned by program");
48264
- if (info.data.length === 0 || info.data[0] !== TAG_ALLOC) throw new Error("Invalid AllocNode data");
48265
- return decodeAlloc(pubkey.toBase58(), info.data);
48266
- }
48267
48260
  async function loadContentNode(connection, programId, pubkey) {
48268
- const info = await connection.getAccountInfo(pubkey, "confirmed");
48269
- if (!info) throw new Error("ContentNode not found");
48270
- if (!info.owner.equals(programId)) throw new Error("ContentNode not owned by program");
48271
- if (info.data.length === 0 || info.data[0] !== TAG_CONTENT) throw new Error("Invalid ContentNode data");
48261
+ const info = await fetchRequiredAccount(connection, programId, pubkey, TAG_CONTENT, "ContentNode");
48272
48262
  return decodeContent(pubkey.toBase58(), info.data);
48273
48263
  }
48274
48264
  async function loadProgramSettings(connection, programId) {
48275
48265
  const settingsKey = deriveSettingsPda(programId);
48276
- const info = await connection.getAccountInfo(settingsKey, "confirmed");
48266
+ const info = await fetchOptionalAccount(connection, programId, settingsKey, TAG_SETTINGS, "ProgramSettings");
48277
48267
  if (!info) return null;
48278
- if (!info.owner.equals(programId)) throw new Error("ProgramSettings not owned by program");
48279
- if (info.data.length === 0 || info.data[0] !== TAG_SETTINGS) throw new Error("Invalid ProgramSettings data");
48280
48268
  return decodeSettings(settingsKey.toBase58(), info.data);
48281
48269
  }
48282
48270
  async function loadThreadAccess(connection, programId, accessKey) {
48283
- const info = await connection.getAccountInfo(accessKey, "confirmed");
48284
- if (!info) throw new Error("ThreadAccess not found");
48285
- if (!info.owner.equals(programId)) throw new Error("ThreadAccess not owned by program");
48286
- if (info.data.length === 0 || info.data[0] !== TAG_ACCESS) throw new Error("Invalid ThreadAccess data");
48271
+ const info = await fetchRequiredAccount(connection, programId, accessKey, TAG_ACCESS, "ThreadAccess");
48287
48272
  return decodeThreadAccess(accessKey.toBase58(), info.data);
48288
48273
  }
48289
48274
  async function loadAllocLikes(connection, programId, pubkey) {
48290
- const info = await connection.getAccountInfo(pubkey, "confirmed");
48275
+ const info = await fetchOptionalAccount(connection, programId, pubkey, TAG_LIKES, "AllocLikes");
48291
48276
  if (!info) return null;
48292
- if (!info.owner.equals(programId)) throw new Error("AllocLikes not owned by program");
48293
- if (info.data.length === 0 || info.data[0] !== TAG_LIKES) throw new Error("Invalid AllocLikes data");
48294
48277
  return decodeAllocLikes(pubkey.toBase58(), info.data);
48295
48278
  }
48296
48279
  async function loadAccessEntries(connection, programId, seed) {
@@ -48315,10 +48298,8 @@ async function loadAccessEntries(connection, programId, seed) {
48315
48298
  }
48316
48299
  async function loadFollowRegistry(connection, programId, owner) {
48317
48300
  const registryKey = deriveFollowRegistryPda(programId, owner);
48318
- const info = await connection.getAccountInfo(registryKey, "confirmed");
48301
+ const info = await fetchOptionalAccount(connection, programId, registryKey, TAG_FOLLOW_REGISTRY, "FollowRegistry");
48319
48302
  if (!info) return null;
48320
- if (!info.owner.equals(programId)) throw new Error("FollowRegistry not owned by program");
48321
- if (info.data.length === 0 || info.data[0] !== TAG_FOLLOW_REGISTRY) throw new Error("Invalid FollowRegistry data");
48322
48303
  return decodeFollowRegistry(registryKey.toBase58(), info.data);
48323
48304
  }
48324
48305
  async function loadFollowerCount(connection, programId, seed) {
@@ -48330,8 +48311,7 @@ async function loadFollowerCount(connection, programId, seed) {
48330
48311
  let total = 0n;
48331
48312
  for (let i = 0; i < infos.length; i++) {
48332
48313
  const info = infos[i];
48333
- if (!info || !info.owner.equals(programId)) continue;
48334
- if (info.data.length === 0 || info.data[0] !== TAG_FOLLOWER_SHARD) continue;
48314
+ if (!isOwnedTag(info, programId, TAG_FOLLOWER_SHARD)) continue;
48335
48315
  total += decodeFollowerShard(shardKeys[i].toBase58(), info.data).count;
48336
48316
  }
48337
48317
  return total;
@@ -48344,41 +48324,21 @@ async function loadThreadNodesBatched(connection, programId, channels) {
48344
48324
  const infos = await connection.getMultipleAccountsInfo(chunk, "confirmed");
48345
48325
  for (let j = 0; j < infos.length; j++) {
48346
48326
  const info = infos[j];
48347
- if (!info || !info.owner.equals(programId)) continue;
48348
- if (info.data.length === 0 || info.data[0] !== TAG_THREAD) continue;
48327
+ if (!isOwnedTag(info, programId, TAG_THREAD)) continue;
48349
48328
  const key = chunk[j].toBase58();
48350
48329
  result.set(key, decodeThread(key, info.data));
48351
48330
  }
48352
48331
  }
48353
48332
  return result;
48354
48333
  }
48355
- function buildCreateRootAllocInstruction(programId, payer, seed, messageFee = 0n, title = "") {
48356
- const titleBytes = new TextEncoder().encode(title);
48357
- if (titleBytes.length > MAX_TITLE_LEN) {
48358
- throw new Error(`Title is too long (max ${MAX_TITLE_LEN} bytes)`);
48359
- }
48360
- const threadAccount = deriveThreadPda(programId, seed);
48361
- const allocAccount = deriveAllocPda(programId, seed, 0);
48362
- const settingsAccount = deriveSettingsPda(programId);
48363
- const treasuryShardIdx = randomTreasuryShard();
48364
- const treasuryShard = deriveTreasuryShardPda(programId, treasuryShardIdx);
48365
- return new TransactionInstruction({
48366
- programId,
48367
- keys: [
48368
- { pubkey: payer, isSigner: true, isWritable: true },
48369
- { pubkey: threadAccount, isSigner: true, isWritable: true },
48370
- { pubkey: allocAccount, isSigner: false, isWritable: true },
48371
- { pubkey: settingsAccount, isSigner: false, isWritable: false },
48372
- { pubkey: treasuryShard, isSigner: false, isWritable: true },
48373
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48374
- ],
48375
- data: Buffer3.from(CreateRootAllocInstr.serialize({
48376
- tag: Instruction.CreateRootAlloc,
48377
- messageFee,
48378
- treasuryShardIdx,
48379
- title: titleBytes
48380
- }))
48381
- });
48334
+ function signerMeta(pubkey) {
48335
+ return { pubkey, isSigner: true, isWritable: true };
48336
+ }
48337
+ function writableMeta(pubkey) {
48338
+ return { pubkey, isSigner: false, isWritable: true };
48339
+ }
48340
+ function readonlyMeta(pubkey) {
48341
+ return { pubkey, isSigner: false, isWritable: false };
48382
48342
  }
48383
48343
  function buildFillSlotInstruction(opts) {
48384
48344
  const {
@@ -48391,7 +48351,6 @@ function buildFillSlotInstruction(opts) {
48391
48351
  bodyBytes,
48392
48352
  kind = KIND_TEXT,
48393
48353
  maxFee,
48394
- extendInfo,
48395
48354
  replyAllocSeq: replyAllocSeqRaw,
48396
48355
  replySlot: replySlotRaw
48397
48356
  } = opts;
@@ -48402,22 +48361,18 @@ function buildFillSlotInstruction(opts) {
48402
48361
  const accessAccount = deriveAccessPda(programId, seed);
48403
48362
  const entryAccount = deriveAccessEntryPda(programId, seed, payer);
48404
48363
  const keys = [
48405
- { pubkey: payer, isSigner: true, isWritable: true },
48406
- { pubkey: threadAccount, isSigner: false, isWritable: !!extendInfo },
48407
- { pubkey: settingsAccount, isSigner: false, isWritable: false },
48408
- { pubkey: treasuryShard, isSigner: false, isWritable: true },
48409
- { pubkey: authorFeeShard, isSigner: false, isWritable: true },
48410
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48364
+ signerMeta(payer),
48365
+ readonlyMeta(threadAccount),
48366
+ readonlyMeta(settingsAccount),
48367
+ writableMeta(treasuryShard),
48368
+ writableMeta(authorFeeShard),
48369
+ readonlyMeta(SystemProgram.programId)
48411
48370
  ];
48412
- for (const c of candidates) {
48413
- keys.push({ pubkey: c.pda, isSigner: false, isWritable: true });
48414
- }
48415
- keys.push({ pubkey: accessAccount, isSigner: false, isWritable: false });
48416
- keys.push({ pubkey: entryAccount, isSigner: false, isWritable: false });
48417
- if (extendInfo) {
48418
- keys.push({ pubkey: extendInfo.currentAllocPda, isSigner: false, isWritable: true });
48419
- keys.push({ pubkey: extendInfo.newAllocPda, isSigner: false, isWritable: true });
48371
+ for (const candidate of candidates) {
48372
+ keys.push(writableMeta(candidate.pda));
48420
48373
  }
48374
+ keys.push(readonlyMeta(accessAccount));
48375
+ keys.push(readonlyMeta(entryAccount));
48421
48376
  return new TransactionInstruction({
48422
48377
  programId,
48423
48378
  keys,
@@ -48425,8 +48380,7 @@ function buildFillSlotInstruction(opts) {
48425
48380
  tag: Instruction.FillSlot,
48426
48381
  kind,
48427
48382
  body: bodyBytes,
48428
- candidates: candidates.map((c) => ({ allocSeq: c.allocSeq, slot: c.slot })),
48429
- extend: extendInfo ? 1 : 0,
48383
+ candidates: candidates.map((candidate) => ({ allocSeq: candidate.allocSeq, slot: candidate.slot })),
48430
48384
  treasuryShardIdx,
48431
48385
  authorFeeShardIdx,
48432
48386
  replyAllocSeq: replyAllocSeqRaw ?? INDEX_NONE,
@@ -48435,17 +48389,36 @@ function buildFillSlotInstruction(opts) {
48435
48389
  }))
48436
48390
  });
48437
48391
  }
48392
+ function buildPrepareAllocInstruction(programId, payer, seed, allocSeq) {
48393
+ const currentAllocPda = deriveAllocPda(programId, seed, allocSeq);
48394
+ const newAllocPda = deriveAllocPda(programId, seed, allocSeq + 1);
48395
+ const threadAccount = deriveThreadPda(programId, seed);
48396
+ return new TransactionInstruction({
48397
+ programId,
48398
+ keys: [
48399
+ signerMeta(payer),
48400
+ writableMeta(currentAllocPda),
48401
+ writableMeta(newAllocPda),
48402
+ writableMeta(threadAccount),
48403
+ readonlyMeta(SystemProgram.programId)
48404
+ ],
48405
+ data: Buffer3.from(PrepareAllocInstr.serialize({
48406
+ tag: Instruction.PrepareAlloc,
48407
+ allocSeq
48408
+ }))
48409
+ });
48410
+ }
48438
48411
  function buildAppendContentInstruction(programId, payer, contentAccount, threadAccount, settingsAccount, treasuryShard, authorFeeShard, chunk, treasuryShardIdx, authorFeeShardIdx) {
48439
48412
  return new TransactionInstruction({
48440
48413
  programId,
48441
48414
  keys: [
48442
- { pubkey: payer, isSigner: true, isWritable: true },
48443
- { pubkey: contentAccount, isSigner: false, isWritable: true },
48444
- { pubkey: threadAccount, isSigner: false, isWritable: false },
48445
- { pubkey: settingsAccount, isSigner: false, isWritable: false },
48446
- { pubkey: treasuryShard, isSigner: false, isWritable: true },
48447
- { pubkey: authorFeeShard, isSigner: false, isWritable: true },
48448
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48415
+ signerMeta(payer),
48416
+ writableMeta(contentAccount),
48417
+ readonlyMeta(threadAccount),
48418
+ readonlyMeta(settingsAccount),
48419
+ writableMeta(treasuryShard),
48420
+ writableMeta(authorFeeShard),
48421
+ readonlyMeta(SystemProgram.programId)
48449
48422
  ],
48450
48423
  data: Buffer3.from(AppendContentInstr.serialize({
48451
48424
  tag: Instruction.AppendContent,
@@ -48455,6 +48428,18 @@ function buildAppendContentInstruction(programId, payer, contentAccount, threadA
48455
48428
  }))
48456
48429
  });
48457
48430
  }
48431
+ var TX_SIZE_LIMIT = 1232;
48432
+ var TX_OVERHEAD = 1 + 64 + 3 + 32;
48433
+ var FILL_SLOT_FIXED_OVERHEAD = 1 + 2 + 4 + 4 + 2 + 1 + 4 + 1 + 8;
48434
+ var CANDIDATE_SIZE = 4 + 1;
48435
+ var ACCOUNT_KEY_SIZE = 32;
48436
+ var FILL_SLOT_BASE_ACCOUNTS = 6;
48437
+ var FILL_SLOT_ACCESS_ACCOUNTS = 2;
48438
+ var PREPARE_ALLOC_MARGINAL_SIZE = 2 * ACCOUNT_KEY_SIZE + 1 + 1 + 5 + 1 + (1 + 4);
48439
+ var CONTENT_NODE_FIXED_SIZE = 89;
48440
+ var MAX_FEE_SLIPPAGE_NUM = 2n;
48441
+ var APPEND_INSTR_ACCOUNTS = 7;
48442
+ var APPEND_TX_OVERHEAD = TX_OVERHEAD + 1 + (APPEND_INSTR_ACCOUNTS + 1) * ACCOUNT_KEY_SIZE + 1 + 1 + 1 + APPEND_INSTR_ACCOUNTS + 2 + 1 + 4 + 2 + 1;
48458
48443
  function ensureTextBytes(text) {
48459
48444
  const bytes = new TextEncoder().encode(text);
48460
48445
  if (bytes.length === 0) {
@@ -48473,74 +48458,41 @@ function shuffle(arr) {
48473
48458
  }
48474
48459
  return result;
48475
48460
  }
48476
- var TX_SIZE_LIMIT = 1232;
48477
- var TX_OVERHEAD = 1 + 64 + 3 + 32;
48478
- var FILL_SLOT_FIXED_OVERHEAD = 1 + 2 + 4 + 4 + 1 + 2 + 1 + 4 + 1 + 8;
48479
- var CANDIDATE_SIZE = 4 + 1;
48480
- var ACCOUNT_KEY_SIZE = 32;
48481
- var FILL_SLOT_BASE_ACCOUNTS = 6;
48482
- var FILL_SLOT_ACCESS_ACCOUNTS = 2;
48483
- var CONTENT_NODE_FIXED_SIZE = 89;
48484
- var MAX_FEE_SLIPPAGE_NUM = 2n;
48485
- var APPEND_INSTR_ACCOUNTS = 7;
48486
- var APPEND_TX_OVERHEAD = TX_OVERHEAD + 1 + (APPEND_INSTR_ACCOUNTS + 1) * ACCOUNT_KEY_SIZE + 1 + 1 + 1 + APPEND_INSTR_ACCOUNTS + 2 + 1 + 4 + 2 + 1;
48487
- function estimateFillSlotTxSize(nCandidates, hasExtend, textLen) {
48488
- const nAccounts = FILL_SLOT_BASE_ACCOUNTS + nCandidates + FILL_SLOT_ACCESS_ACCOUNTS + (hasExtend ? 2 : 0);
48461
+ function estimateFillSlotTxSize(nCandidates, textLen) {
48462
+ const nAccounts = FILL_SLOT_BASE_ACCOUNTS + nCandidates + FILL_SLOT_ACCESS_ACCOUNTS;
48489
48463
  const accountsSize = 1 + (nAccounts + 1) * ACCOUNT_KEY_SIZE;
48490
48464
  const instrDataSize = FILL_SLOT_FIXED_OVERHEAD + textLen + nCandidates * CANDIDATE_SIZE;
48491
48465
  const instrOverhead = 1 + 1 + 1 + nAccounts + 2;
48492
48466
  return TX_OVERHEAD + accountsSize + instrOverhead + instrDataSize;
48493
48467
  }
48494
- function maxFillSlotTextLen(nCandidates, hasExtend) {
48495
- const withoutText = estimateFillSlotTxSize(nCandidates, hasExtend, 0);
48496
- return TX_SIZE_LIMIT - withoutText;
48468
+ function maxFillSlotTextLen(nCandidates, reserve = 0) {
48469
+ const withoutText = estimateFillSlotTxSize(nCandidates, 0);
48470
+ return TX_SIZE_LIMIT - withoutText - reserve;
48497
48471
  }
48498
48472
  function maxAppendChunkLen() {
48499
48473
  return TX_SIZE_LIMIT - APPEND_TX_OVERHEAD;
48500
48474
  }
48475
+ function pageCandidates(programId, seed, allocSeq) {
48476
+ return Array.from({ length: CONTENT_SLOTS }, (_, slot) => ({
48477
+ pda: deriveContentPda(programId, seed, allocSeq, slot),
48478
+ allocSeq,
48479
+ slot
48480
+ }));
48481
+ }
48501
48482
  async function buildSendMessageTransactions(connection, programId, payerKey, seed, text, replyTo) {
48502
48483
  const textBytes = ensureTextBytes(text);
48503
48484
  const threadPda = deriveThreadPda(programId, seed);
48504
48485
  const thread = await loadThreadNode(connection, programId, threadPda);
48505
48486
  const lastAllocSeq = thread.lastAllocSeq;
48506
- const lastAllocPda = deriveAllocPda(programId, seed, lastAllocSeq);
48507
- const lastAlloc = await loadAllocNode(connection, programId, lastAllocPda);
48508
- const lastAllocCandidates = Array.from({ length: CONTENT_SLOTS }, (_, slot) => ({
48509
- pda: deriveContentPda(programId, seed, lastAllocSeq, slot),
48510
- allocSeq: lastAllocSeq,
48511
- slot
48512
- }));
48513
- const lastInfos = await connection.getMultipleAccountsInfo(
48514
- lastAllocCandidates.map((c) => c.pda)
48515
- );
48516
- const freeInLast = lastAllocCandidates.filter((_, i) => lastInfos[i] === null);
48517
- let freeInNext = [];
48518
- if (freeInLast.length < DESIRED_CANDIDATES && lastAlloc.nextAllocSeq !== null) {
48519
- const nextSeq = lastAlloc.nextAllocSeq;
48520
- const nextAllocCandidates = Array.from({ length: CONTENT_SLOTS }, (_, slot) => ({
48521
- pda: deriveContentPda(programId, seed, nextSeq, slot),
48522
- allocSeq: nextSeq,
48523
- slot
48524
- }));
48525
- const nextInfos = await connection.getMultipleAccountsInfo(
48526
- nextAllocCandidates.map((c) => c.pda)
48527
- );
48528
- freeInNext = nextAllocCandidates.filter((_, i) => nextInfos[i] === null);
48529
- }
48530
- const allFree = [...freeInLast, ...freeInNext];
48531
- if (allFree.length === 0) throw new Error("No free slots in thread");
48532
- const selected = shuffle(allFree).slice(0, DESIRED_CANDIDATES);
48487
+ const windowCandidates = lastAllocSeq >= 1 ? [...pageCandidates(programId, seed, lastAllocSeq - 1), ...pageCandidates(programId, seed, lastAllocSeq)] : pageCandidates(programId, seed, lastAllocSeq);
48488
+ const windowInfos = await connection.getMultipleAccountsInfo(windowCandidates.map((c) => c.pda));
48489
+ const freeInWindow = windowCandidates.filter((_, i) => windowInfos[i] === null);
48533
48490
  const treasuryShardIdx = randomTreasuryShard();
48534
48491
  const authorFeeShardIdx = randomAuthorFeeShard();
48535
- const filledInLast = CONTENT_SLOTS - freeInLast.length;
48536
- let extendInfo;
48537
- if (filledInLast >= EXTEND_THRESHOLD && lastAlloc.nextAllocSeq === null) {
48538
- extendInfo = {
48539
- currentAllocPda: lastAllocPda,
48540
- newAllocPda: deriveAllocPda(programId, seed, lastAllocSeq + 1)
48541
- };
48542
- }
48543
- const maxFirst = maxFillSlotTextLen(selected.length, !!extendInfo);
48492
+ const extendInline = freeInWindow.length === 0;
48493
+ const selected = extendInline ? pageCandidates(programId, seed, lastAllocSeq + 1).slice(0, DESIRED_CANDIDATES) : shuffle(freeInWindow).slice(0, DESIRED_CANDIDATES);
48494
+ const reserve = extendInline ? PREPARE_ALLOC_MARGINAL_SIZE : 0;
48495
+ const maxFirst = maxFillSlotTextLen(selected.length, reserve);
48544
48496
  const firstChunkLen = Math.min(textBytes.length, maxFirst);
48545
48497
  const firstChunk = textBytes.subarray(0, firstChunkLen);
48546
48498
  const settings = await loadProgramSettings(connection, programId);
@@ -48560,16 +48512,19 @@ async function buildSendMessageTransactions(connection, programId, payerKey, see
48560
48512
  authorFeeShardIdx,
48561
48513
  bodyBytes: firstChunk,
48562
48514
  maxFee,
48563
- extendInfo,
48564
48515
  replyAllocSeq: replyTo?.allocSeq ?? null,
48565
48516
  replySlot: replyTo?.slot ?? null
48566
48517
  });
48567
- const transactions = [new Transaction().add(fillSlotIx)];
48518
+ const firstTx = new Transaction();
48519
+ if (extendInline) {
48520
+ firstTx.add(buildPrepareAllocInstruction(programId, payerKey, seed, lastAllocSeq));
48521
+ }
48522
+ firstTx.add(fillSlotIx);
48523
+ const transactions = [firstTx];
48568
48524
  if (firstChunkLen < textBytes.length) {
48569
48525
  const remaining = textBytes.subarray(firstChunkLen);
48570
48526
  const appendMax = maxAppendChunkLen();
48571
48527
  const contentPda = selected[0].pda;
48572
- const threadPda2 = deriveThreadPda(programId, seed);
48573
48528
  const settingsPda = deriveSettingsPda(programId);
48574
48529
  const treasuryShardPda = deriveTreasuryShardPda(programId, treasuryShardIdx);
48575
48530
  const authorFeeShardPda = deriveAuthorFeePda(programId, seed, authorFeeShardIdx);
@@ -48579,7 +48534,7 @@ async function buildSendMessageTransactions(connection, programId, payerKey, see
48579
48534
  programId,
48580
48535
  payerKey,
48581
48536
  contentPda,
48582
- threadPda2,
48537
+ threadPda,
48583
48538
  settingsPda,
48584
48539
  treasuryShardPda,
48585
48540
  authorFeeShardPda,
@@ -48592,6 +48547,45 @@ async function buildSendMessageTransactions(connection, programId, payerKey, see
48592
48547
  }
48593
48548
  return transactions;
48594
48549
  }
48550
+ async function buildExtendAllocTransaction(connection, programId, payerKey, seed) {
48551
+ const threadPda = deriveThreadPda(programId, seed);
48552
+ const thread = await loadThreadNode(connection, programId, threadPda);
48553
+ const lastAllocSeq = thread.lastAllocSeq;
48554
+ const tailCandidates = pageCandidates(programId, seed, lastAllocSeq);
48555
+ const tailInfos = await connection.getMultipleAccountsInfo(tailCandidates.map((c) => c.pda));
48556
+ const freeOnPageN = tailInfos.filter((info) => info === null).length;
48557
+ const filled = CONTENT_SLOTS - freeOnPageN;
48558
+ if (filled < EXTEND_THRESHOLD) return null;
48559
+ return new Transaction().add(buildPrepareAllocInstruction(programId, payerKey, seed, lastAllocSeq));
48560
+ }
48561
+ function buildCreateRootAllocInstruction(programId, payer, seed, messageFee = 0n, title = "") {
48562
+ const titleBytes = new TextEncoder().encode(title);
48563
+ if (titleBytes.length > MAX_TITLE_LEN) {
48564
+ throw new Error(`Title is too long (max ${MAX_TITLE_LEN} bytes)`);
48565
+ }
48566
+ const threadAccount = deriveThreadPda(programId, seed);
48567
+ const allocAccount = deriveAllocPda(programId, seed, 0);
48568
+ const settingsAccount = deriveSettingsPda(programId);
48569
+ const treasuryShardIdx = randomTreasuryShard();
48570
+ const treasuryShard = deriveTreasuryShardPda(programId, treasuryShardIdx);
48571
+ return new TransactionInstruction({
48572
+ programId,
48573
+ keys: [
48574
+ signerMeta(payer),
48575
+ signerMeta(threadAccount),
48576
+ writableMeta(allocAccount),
48577
+ readonlyMeta(settingsAccount),
48578
+ writableMeta(treasuryShard),
48579
+ readonlyMeta(SystemProgram.programId)
48580
+ ],
48581
+ data: Buffer3.from(CreateRootAllocInstr.serialize({
48582
+ tag: Instruction.CreateRootAlloc,
48583
+ messageFee,
48584
+ treasuryShardIdx,
48585
+ title: titleBytes
48586
+ }))
48587
+ });
48588
+ }
48595
48589
  async function createRootAlloc(connection, programId, payer, messageFee = 0n, title = "", onSent) {
48596
48590
  const programKey = new PublicKey(programId);
48597
48591
  const threadKeypair = Keypair.generate();
@@ -48610,58 +48604,49 @@ async function createRootAlloc(connection, programId, payer, messageFee = 0n, ti
48610
48604
  allocPda: deriveAllocPda(programKey, seed, 0).toBase58()
48611
48605
  };
48612
48606
  }
48613
- function buildPrepareAllocInstruction(programId, payer, seed, allocSeq) {
48614
- const currentAllocPda = deriveAllocPda(programId, seed, allocSeq);
48615
- const newAllocPda = deriveAllocPda(programId, seed, allocSeq + 1);
48616
- const threadAccount = deriveThreadPda(programId, seed);
48617
- return new TransactionInstruction({
48618
- programId,
48619
- keys: [
48620
- { pubkey: payer, isSigner: true, isWritable: true },
48621
- { pubkey: currentAllocPda, isSigner: false, isWritable: true },
48622
- { pubkey: newAllocPda, isSigner: false, isWritable: true },
48623
- { pubkey: threadAccount, isSigner: false, isWritable: true },
48624
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48625
- ],
48626
- data: Buffer3.from(PrepareAllocInstr.serialize({
48627
- tag: Instruction.PrepareAlloc,
48628
- allocSeq
48629
- }))
48630
- });
48631
- }
48632
- function buildSweepAuthorFeesInstruction(programId, seed, threadAccount, authorWallet, shardIndices) {
48607
+ function buildCloseAccountInstruction(programId, payer, targetAccount, likesAccount) {
48633
48608
  const keys = [
48634
- { pubkey: threadAccount, isSigner: false, isWritable: false },
48635
- { pubkey: authorWallet, isSigner: true, isWritable: true }
48609
+ signerMeta(payer),
48610
+ writableMeta(targetAccount)
48636
48611
  ];
48637
- for (const idx of shardIndices) {
48638
- keys.push({
48639
- pubkey: deriveAuthorFeePda(programId, seed, idx),
48640
- isSigner: false,
48641
- isWritable: true
48642
- });
48612
+ if (likesAccount) {
48613
+ keys.push(writableMeta(likesAccount));
48643
48614
  }
48644
48615
  return new TransactionInstruction({
48645
48616
  programId,
48646
48617
  keys,
48647
- data: Buffer3.from(SweepAuthorFeesInstr.serialize({
48648
- tag: Instruction.SweepAuthorFees,
48649
- shardIndices: Uint8Array.from(shardIndices)
48650
- }))
48618
+ data: Buffer3.from(TagOnlyInstr.serialize({ tag: Instruction.CloseAccount }))
48651
48619
  });
48652
48620
  }
48653
- function buildCloseAccountInstruction(programId, payer, targetAccount, likesAccount) {
48654
- const keys = [
48655
- { pubkey: payer, isSigner: true, isWritable: true },
48656
- { pubkey: targetAccount, isSigner: false, isWritable: true }
48657
- ];
48658
- if (likesAccount) {
48659
- keys.push({ pubkey: likesAccount, isSigner: false, isWritable: true });
48660
- }
48621
+ function buildLikeContentInstruction(programId, payer, seed, allocSeq, slot, maxFee) {
48622
+ const likesAccount = deriveLikesPda(programId, seed, allocSeq);
48623
+ const contentAccount = deriveContentPda(programId, seed, allocSeq, slot);
48624
+ const threadAccount = deriveThreadPda(programId, seed);
48625
+ const settingsAccount = deriveSettingsPda(programId);
48626
+ const treasuryShardIdx = randomTreasuryShard();
48627
+ const authorFeeShardIdx = randomAuthorFeeShard();
48628
+ const treasuryShard = deriveTreasuryShardPda(programId, treasuryShardIdx);
48629
+ const authorFeeShard = deriveAuthorFeePda(programId, seed, authorFeeShardIdx);
48661
48630
  return new TransactionInstruction({
48662
48631
  programId,
48663
- keys,
48664
- data: Buffer3.from(TagOnlyInstr.serialize({ tag: Instruction.CloseAccount }))
48632
+ keys: [
48633
+ signerMeta(payer),
48634
+ writableMeta(likesAccount),
48635
+ readonlyMeta(contentAccount),
48636
+ readonlyMeta(threadAccount),
48637
+ readonlyMeta(settingsAccount),
48638
+ writableMeta(treasuryShard),
48639
+ writableMeta(authorFeeShard),
48640
+ readonlyMeta(SystemProgram.programId)
48641
+ ],
48642
+ data: Buffer3.from(LikeContentInstr.serialize({
48643
+ tag: Instruction.LikeContent,
48644
+ allocSeq,
48645
+ slot,
48646
+ treasuryShardIdx,
48647
+ authorFeeShardIdx,
48648
+ maxFee
48649
+ }))
48665
48650
  });
48666
48651
  }
48667
48652
  function buildInitThreadAccessInstruction(programId, authority, seed, enabled) {
@@ -48672,11 +48657,11 @@ function buildInitThreadAccessInstruction(programId, authority, seed, enabled) {
48672
48657
  return new TransactionInstruction({
48673
48658
  programId,
48674
48659
  keys: [
48675
- { pubkey: authority, isSigner: true, isWritable: true },
48676
- { pubkey: threadAccount, isSigner: false, isWritable: false },
48677
- { pubkey: accessAccount, isSigner: false, isWritable: true },
48678
- { pubkey: treasuryShard, isSigner: false, isWritable: true },
48679
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48660
+ signerMeta(authority),
48661
+ readonlyMeta(threadAccount),
48662
+ writableMeta(accessAccount),
48663
+ writableMeta(treasuryShard),
48664
+ readonlyMeta(SystemProgram.programId)
48680
48665
  ],
48681
48666
  data: Buffer3.from(InitThreadAccessInstr.serialize({
48682
48667
  tag: Instruction.InitThreadAccess,
@@ -48689,8 +48674,8 @@ function buildSetThreadAccessInstruction(programId, authority, accessAccount, en
48689
48674
  return new TransactionInstruction({
48690
48675
  programId,
48691
48676
  keys: [
48692
- { pubkey: authority, isSigner: true, isWritable: true },
48693
- { pubkey: accessAccount, isSigner: false, isWritable: true }
48677
+ signerMeta(authority),
48678
+ writableMeta(accessAccount)
48694
48679
  ],
48695
48680
  data: Buffer3.from(SetThreadAccessInstr.serialize({
48696
48681
  tag: Instruction.SetThreadAccess,
@@ -48698,70 +48683,6 @@ function buildSetThreadAccessInstruction(programId, authority, accessAccount, en
48698
48683
  }))
48699
48684
  });
48700
48685
  }
48701
- function buildAddToWhitelistInstruction(programId, authority, seed, wallet) {
48702
- const accessAccount = deriveAccessPda(programId, seed);
48703
- const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
48704
- return new TransactionInstruction({
48705
- programId,
48706
- keys: [
48707
- { pubkey: authority, isSigner: true, isWritable: true },
48708
- { pubkey: accessAccount, isSigner: false, isWritable: true },
48709
- { pubkey: entryAccount, isSigner: false, isWritable: true },
48710
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48711
- ],
48712
- data: Buffer3.from(WalletArgInstr.serialize({
48713
- tag: Instruction.AddToWhitelist,
48714
- wallet: wallet.toBytes()
48715
- }))
48716
- });
48717
- }
48718
- function buildRemoveFromWhitelistInstruction(programId, authority, seed, wallet) {
48719
- const accessAccount = deriveAccessPda(programId, seed);
48720
- const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
48721
- return new TransactionInstruction({
48722
- programId,
48723
- keys: [
48724
- { pubkey: authority, isSigner: true, isWritable: true },
48725
- { pubkey: accessAccount, isSigner: false, isWritable: true },
48726
- { pubkey: entryAccount, isSigner: false, isWritable: true },
48727
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48728
- ],
48729
- data: Buffer3.from(WalletArgInstr.serialize({
48730
- tag: Instruction.RemoveFromWhitelist,
48731
- wallet: wallet.toBytes()
48732
- }))
48733
- });
48734
- }
48735
- function buildSetMessageFeeInstruction(programId, authority, threadAccount, fee) {
48736
- return new TransactionInstruction({
48737
- programId,
48738
- keys: [
48739
- { pubkey: authority, isSigner: true, isWritable: true },
48740
- { pubkey: threadAccount, isSigner: false, isWritable: true }
48741
- ],
48742
- data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetMessageFee, fee }))
48743
- });
48744
- }
48745
- function buildSetLikeFeeInstruction(programId, authority, threadAccount, fee) {
48746
- return new TransactionInstruction({
48747
- programId,
48748
- keys: [
48749
- { pubkey: authority, isSigner: true, isWritable: true },
48750
- { pubkey: threadAccount, isSigner: false, isWritable: true }
48751
- ],
48752
- data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetLikeFee, fee }))
48753
- });
48754
- }
48755
- function buildSetEntryFeeInstruction(programId, authority, accessAccount, fee) {
48756
- return new TransactionInstruction({
48757
- programId,
48758
- keys: [
48759
- { pubkey: authority, isSigner: true, isWritable: true },
48760
- { pubkey: accessAccount, isSigner: false, isWritable: true }
48761
- ],
48762
- data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetEntryFee, fee }))
48763
- });
48764
- }
48765
48686
  function buildRequestAccessInstruction(programId, payer, seed) {
48766
48687
  const accessAccount = deriveAccessPda(programId, seed);
48767
48688
  const entryAccount = deriveAccessEntryPda(programId, seed, payer);
@@ -48774,14 +48695,14 @@ function buildRequestAccessInstruction(programId, payer, seed) {
48774
48695
  return new TransactionInstruction({
48775
48696
  programId,
48776
48697
  keys: [
48777
- { pubkey: payer, isSigner: true, isWritable: true },
48778
- { pubkey: accessAccount, isSigner: false, isWritable: true },
48779
- { pubkey: entryAccount, isSigner: false, isWritable: true },
48780
- { pubkey: threadAccount, isSigner: false, isWritable: false },
48781
- { pubkey: settingsAccount, isSigner: false, isWritable: false },
48782
- { pubkey: treasuryShard, isSigner: false, isWritable: true },
48783
- { pubkey: authorFeeShard, isSigner: false, isWritable: true },
48784
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48698
+ signerMeta(payer),
48699
+ writableMeta(accessAccount),
48700
+ writableMeta(entryAccount),
48701
+ readonlyMeta(threadAccount),
48702
+ readonlyMeta(settingsAccount),
48703
+ writableMeta(treasuryShard),
48704
+ writableMeta(authorFeeShard),
48705
+ readonlyMeta(SystemProgram.programId)
48785
48706
  ],
48786
48707
  data: Buffer3.from(RequestAccessInstr.serialize({
48787
48708
  tag: Instruction.RequestAccess,
@@ -48790,111 +48711,94 @@ function buildRequestAccessInstruction(programId, payer, seed) {
48790
48711
  }))
48791
48712
  });
48792
48713
  }
48793
- function buildLikeContentInstruction(programId, payer, seed, allocSeq, slot, maxFee) {
48794
- const likesAccount = deriveLikesPda(programId, seed, allocSeq);
48795
- const contentAccount = deriveContentPda(programId, seed, allocSeq, slot);
48796
- const threadAccount = deriveThreadPda(programId, seed);
48797
- const settingsAccount = deriveSettingsPda(programId);
48798
- const treasuryShardIdx = randomTreasuryShard();
48799
- const authorFeeShardIdx = randomAuthorFeeShard();
48800
- const treasuryShard = deriveTreasuryShardPda(programId, treasuryShardIdx);
48801
- const authorFeeShard = deriveAuthorFeePda(programId, seed, authorFeeShardIdx);
48802
- return new TransactionInstruction({
48803
- programId,
48804
- keys: [
48805
- { pubkey: payer, isSigner: true, isWritable: true },
48806
- { pubkey: likesAccount, isSigner: false, isWritable: true },
48807
- { pubkey: contentAccount, isSigner: false, isWritable: false },
48808
- { pubkey: threadAccount, isSigner: false, isWritable: false },
48809
- { pubkey: settingsAccount, isSigner: false, isWritable: false },
48810
- { pubkey: treasuryShard, isSigner: false, isWritable: true },
48811
- { pubkey: authorFeeShard, isSigner: false, isWritable: true },
48812
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48813
- ],
48814
- data: Buffer3.from(LikeContentInstr.serialize({
48815
- tag: Instruction.LikeContent,
48816
- allocSeq,
48817
- slot,
48818
- treasuryShardIdx,
48819
- authorFeeShardIdx,
48820
- maxFee
48821
- }))
48822
- });
48823
- }
48824
- function buildAddToBlacklistInstruction(programId, authority, seed, wallet) {
48714
+ function buildAclEntryInstruction(tag, programId, authority, seed, wallet) {
48825
48715
  const accessAccount = deriveAccessPda(programId, seed);
48826
48716
  const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
48827
48717
  return new TransactionInstruction({
48828
48718
  programId,
48829
48719
  keys: [
48830
- { pubkey: authority, isSigner: true, isWritable: true },
48831
- { pubkey: accessAccount, isSigner: false, isWritable: true },
48832
- { pubkey: entryAccount, isSigner: false, isWritable: true },
48833
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48720
+ signerMeta(authority),
48721
+ writableMeta(accessAccount),
48722
+ writableMeta(entryAccount),
48723
+ readonlyMeta(SystemProgram.programId)
48834
48724
  ],
48835
48725
  data: Buffer3.from(WalletArgInstr.serialize({
48836
- tag: Instruction.AddToBlacklist,
48726
+ tag,
48837
48727
  wallet: wallet.toBytes()
48838
48728
  }))
48839
48729
  });
48840
48730
  }
48731
+ function buildAddToWhitelistInstruction(programId, authority, seed, wallet) {
48732
+ return buildAclEntryInstruction(Instruction.AddToWhitelist, programId, authority, seed, wallet);
48733
+ }
48734
+ function buildRemoveFromWhitelistInstruction(programId, authority, seed, wallet) {
48735
+ return buildAclEntryInstruction(Instruction.RemoveFromWhitelist, programId, authority, seed, wallet);
48736
+ }
48737
+ function buildAddToBlacklistInstruction(programId, authority, seed, wallet) {
48738
+ return buildAclEntryInstruction(Instruction.AddToBlacklist, programId, authority, seed, wallet);
48739
+ }
48841
48740
  function buildRemoveFromBlacklistInstruction(programId, authority, seed, wallet) {
48842
- const accessAccount = deriveAccessPda(programId, seed);
48843
- const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
48741
+ return buildAclEntryInstruction(Instruction.RemoveFromBlacklist, programId, authority, seed, wallet);
48742
+ }
48743
+ function buildAddToFeeWhitelistInstruction(programId, authority, seed, wallet) {
48744
+ return buildAclEntryInstruction(Instruction.AddToFeeWhitelist, programId, authority, seed, wallet);
48745
+ }
48746
+ function buildRemoveFromFeeWhitelistInstruction(programId, authority, seed, wallet) {
48747
+ return buildAclEntryInstruction(Instruction.RemoveFromFeeWhitelist, programId, authority, seed, wallet);
48748
+ }
48749
+ var FEE_TAG = {
48750
+ base: Instruction.SetBaseFee,
48751
+ authorCut: Instruction.SetAuthorFeeCut,
48752
+ entryCut: Instruction.SetEntryCut,
48753
+ likeCut: Instruction.SetLikeCut
48754
+ };
48755
+ function buildSetMessageFeeInstruction(programId, authority, threadAccount, fee) {
48844
48756
  return new TransactionInstruction({
48845
48757
  programId,
48846
48758
  keys: [
48847
- { pubkey: authority, isSigner: true, isWritable: true },
48848
- { pubkey: accessAccount, isSigner: false, isWritable: true },
48849
- { pubkey: entryAccount, isSigner: false, isWritable: true },
48850
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48759
+ signerMeta(authority),
48760
+ writableMeta(threadAccount)
48851
48761
  ],
48852
- data: Buffer3.from(WalletArgInstr.serialize({
48853
- tag: Instruction.RemoveFromBlacklist,
48854
- wallet: wallet.toBytes()
48855
- }))
48762
+ data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetMessageFee, fee }))
48856
48763
  });
48857
48764
  }
48858
- function buildAddToFeeWhitelistInstruction(programId, authority, seed, wallet) {
48859
- const accessAccount = deriveAccessPda(programId, seed);
48860
- const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
48765
+ function buildSetLikeFeeInstruction(programId, authority, threadAccount, fee) {
48861
48766
  return new TransactionInstruction({
48862
48767
  programId,
48863
48768
  keys: [
48864
- { pubkey: authority, isSigner: true, isWritable: true },
48865
- { pubkey: accessAccount, isSigner: false, isWritable: true },
48866
- { pubkey: entryAccount, isSigner: false, isWritable: true },
48867
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48769
+ signerMeta(authority),
48770
+ writableMeta(threadAccount)
48868
48771
  ],
48869
- data: Buffer3.from(WalletArgInstr.serialize({
48870
- tag: Instruction.AddToFeeWhitelist,
48871
- wallet: wallet.toBytes()
48872
- }))
48772
+ data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetLikeFee, fee }))
48873
48773
  });
48874
48774
  }
48875
- function buildRemoveFromFeeWhitelistInstruction(programId, authority, seed, wallet) {
48876
- const accessAccount = deriveAccessPda(programId, seed);
48877
- const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
48775
+ function buildSetEntryFeeInstruction(programId, authority, accessAccount, fee) {
48878
48776
  return new TransactionInstruction({
48879
48777
  programId,
48880
48778
  keys: [
48881
- { pubkey: authority, isSigner: true, isWritable: true },
48882
- { pubkey: accessAccount, isSigner: false, isWritable: true },
48883
- { pubkey: entryAccount, isSigner: false, isWritable: true },
48884
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48779
+ signerMeta(authority),
48780
+ writableMeta(accessAccount)
48885
48781
  ],
48886
- data: Buffer3.from(WalletArgInstr.serialize({
48887
- tag: Instruction.RemoveFromFeeWhitelist,
48888
- wallet: wallet.toBytes()
48782
+ data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetEntryFee, fee }))
48783
+ });
48784
+ }
48785
+ function buildSweepAuthorFeesInstruction(programId, seed, threadAccount, authorWallet, shardIndices) {
48786
+ const keys = [
48787
+ readonlyMeta(threadAccount),
48788
+ signerMeta(authorWallet)
48789
+ ];
48790
+ for (const idx of shardIndices) {
48791
+ keys.push(writableMeta(deriveAuthorFeePda(programId, seed, idx)));
48792
+ }
48793
+ return new TransactionInstruction({
48794
+ programId,
48795
+ keys,
48796
+ data: Buffer3.from(SweepAuthorFeesInstr.serialize({
48797
+ tag: Instruction.SweepAuthorFees,
48798
+ shardIndices: Uint8Array.from(shardIndices)
48889
48799
  }))
48890
48800
  });
48891
48801
  }
48892
- var FEE_TAG = {
48893
- base: Instruction.SetBaseFee,
48894
- authorCut: Instruction.SetAuthorFeeCut,
48895
- entryCut: Instruction.SetEntryCut,
48896
- likeCut: Instruction.SetLikeCut
48897
- };
48898
48802
  function buildFollowInstruction(tag, opts) {
48899
48803
  const { programId, user, seed } = opts;
48900
48804
  const threadAccount = deriveThreadPda(programId, seed);
@@ -48903,11 +48807,11 @@ function buildFollowInstruction(tag, opts) {
48903
48807
  return new TransactionInstruction({
48904
48808
  programId,
48905
48809
  keys: [
48906
- { pubkey: user, isSigner: true, isWritable: true },
48907
- { pubkey: followRegistry, isSigner: false, isWritable: true },
48908
- { pubkey: followerShard, isSigner: false, isWritable: true },
48909
- { pubkey: threadAccount, isSigner: false, isWritable: false },
48910
- { pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
48810
+ signerMeta(user),
48811
+ writableMeta(followRegistry),
48812
+ writableMeta(followerShard),
48813
+ readonlyMeta(threadAccount),
48814
+ readonlyMeta(SystemProgram.programId)
48911
48815
  ],
48912
48816
  data: Buffer3.from(TagOnlyInstr.serialize({ tag }))
48913
48817
  });
@@ -48981,6 +48885,18 @@ async function sendTransactions(payer, txs) {
48981
48885
  }
48982
48886
  return sigs;
48983
48887
  }
48888
+ async function trySendBestEffort(payer, tx) {
48889
+ try {
48890
+ const { connection } = loadConfig();
48891
+ tx.feePayer = payer.publicKey;
48892
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
48893
+ tx.recentBlockhash = blockhash;
48894
+ tx.sign(payer);
48895
+ return await connection.sendRawTransaction(tx.serialize());
48896
+ } catch {
48897
+ return null;
48898
+ }
48899
+ }
48984
48900
  function explorerTx(signature) {
48985
48901
  const { rpcUrl } = loadConfig();
48986
48902
  const cluster = rpcUrl.includes("devnet") ? "?cluster=devnet" : rpcUrl.includes("testnet") ? "?cluster=testnet" : rpcUrl.includes("localhost") || rpcUrl.includes("127.0.0.1") ? "?cluster=custom" : "";
@@ -49113,7 +49029,7 @@ function registerMessagingTools(server) {
49113
49029
  "send_message",
49114
49030
  {
49115
49031
  title: "Send message",
49116
- description: "Post a text message to a channel as the agent wallet. Handles fees, slot selection and chunking of long messages automatically.",
49032
+ description: "Post a text message to a channel as the agent wallet. Handles fees, slot selection and chunking of long messages automatically. Posting is decoupled from growing the alloc chain: after the post confirms, a best-effort page extension is fired when the tail page is filling up (its failure never affects the post).",
49117
49033
  inputSchema: {
49118
49034
  channel: channelArg,
49119
49035
  text: external_exports.string().min(1).describe("Message text (UTF-8, up to 8192 bytes)."),
@@ -49135,10 +49051,19 @@ function registerMessagingTools(server) {
49135
49051
  replyTo
49136
49052
  );
49137
49053
  const signatures = await sendTransactions(payer, txs);
49054
+ let extendSignature = null;
49055
+ try {
49056
+ const extendTx = await buildExtendAllocTransaction(connection, programId, payer.publicKey, seed);
49057
+ if (extendTx) extendSignature = await trySendBestEffort(payer, extendTx);
49058
+ } catch {
49059
+ extendSignature = null;
49060
+ }
49138
49061
  return jsonResult({
49139
49062
  channel: seedToAddress(seed),
49140
49063
  signatures,
49141
- explorer: signatures.map(explorerTx)
49064
+ explorer: signatures.map(explorerTx),
49065
+ extendSignature,
49066
+ extendExplorer: extendSignature ? explorerTx(extendSignature) : null
49142
49067
  });
49143
49068
  })
49144
49069
  );
@@ -49180,7 +49105,7 @@ function registerMessagingTools(server) {
49180
49105
  "prepare_alloc",
49181
49106
  {
49182
49107
  title: "Prepare alloc",
49183
- description: "Pre-create the next alloc page in a channel so there are free slots ahead of demand. Mostly useful for high-traffic channels.",
49108
+ description: "Manually pre-create the next alloc page (allocSeq + 1) in a channel so there are free slots ahead of demand. send_message already does this best-effort; use this to force-extend a high-traffic channel. Racy by design: it fails with InvalidAllocSeq if the chain tail moved on.",
49184
49109
  inputSchema: {
49185
49110
  channel: channelArg,
49186
49111
  allocSeq: external_exports.number().int().describe("Current alloc seq to extend from.")
@@ -49644,7 +49569,7 @@ function registerThreadAdminTools(server) {
49644
49569
  async function main() {
49645
49570
  const config2 = loadConfig();
49646
49571
  const wallet = loadWallet();
49647
- const server = new McpServer({ name: "txtcel-mcp", version: "0.1.2" });
49572
+ const server = new McpServer({ name: "txtcel-mcp", version: "0.2.0" });
49648
49573
  registerMessagingTools(server);
49649
49574
  registerFollowTools(server);
49650
49575
  registerReadTools(server);