@txtcel/mcp 0.1.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/index.js +316 -377
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
47883
|
-
var CONTENT_SLOTS =
|
|
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(),
|
|
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(),
|
|
@@ -48048,7 +48043,8 @@ var InitThreadAccessInstr = import_zorsh.b.struct({
|
|
|
48048
48043
|
var RequestAccessInstr = import_zorsh.b.struct({
|
|
48049
48044
|
tag: import_zorsh.b.u8(),
|
|
48050
48045
|
treasuryShardIdx: import_zorsh.b.u16(),
|
|
48051
|
-
authorFeeShardIdx: import_zorsh.b.u8()
|
|
48046
|
+
authorFeeShardIdx: import_zorsh.b.u8(),
|
|
48047
|
+
maxFee: import_zorsh.b.u64()
|
|
48052
48048
|
});
|
|
48053
48049
|
var LikeContentInstr = import_zorsh.b.struct({
|
|
48054
48050
|
tag: import_zorsh.b.u8(),
|
|
@@ -48062,7 +48058,8 @@ var AppendContentInstr = import_zorsh.b.struct({
|
|
|
48062
48058
|
tag: import_zorsh.b.u8(),
|
|
48063
48059
|
chunk: import_zorsh.b.bytes(),
|
|
48064
48060
|
treasuryShardIdx: import_zorsh.b.u16(),
|
|
48065
|
-
authorFeeShardIdx: import_zorsh.b.u8()
|
|
48061
|
+
authorFeeShardIdx: import_zorsh.b.u8(),
|
|
48062
|
+
maxFee: import_zorsh.b.u64()
|
|
48066
48063
|
});
|
|
48067
48064
|
var textDecoder = new TextDecoder();
|
|
48068
48065
|
function decodeContent(pubkey, data) {
|
|
@@ -48083,17 +48080,6 @@ function decodeContent(pubkey, data) {
|
|
|
48083
48080
|
text: raw.kind === KIND_TEXT ? textDecoder.decode(raw.body) : ""
|
|
48084
48081
|
};
|
|
48085
48082
|
}
|
|
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
48083
|
var textDecoder2 = new TextDecoder();
|
|
48098
48084
|
function decodeThread(pubkey, data) {
|
|
48099
48085
|
const raw = ThreadNodeSchema.deserialize(data);
|
|
@@ -48250,47 +48236,46 @@ function randomTreasuryShard() {
|
|
|
48250
48236
|
function randomAuthorFeeShard() {
|
|
48251
48237
|
return Math.floor(Math.random() * N_AUTHOR_FEE_SHARDS);
|
|
48252
48238
|
}
|
|
48239
|
+
function assertOwnedTag(info, programId, tag, name) {
|
|
48240
|
+
if (!info.owner.equals(programId)) throw new Error(`${name} not owned by program`);
|
|
48241
|
+
if (info.data.length === 0 || info.data[0] !== tag) throw new Error(`Invalid ${name} data`);
|
|
48242
|
+
}
|
|
48243
|
+
async function fetchRequiredAccount(connection, programId, key, tag, name) {
|
|
48244
|
+
const info = await connection.getAccountInfo(key, "confirmed");
|
|
48245
|
+
if (!info) throw new Error(`${name} not found`);
|
|
48246
|
+
assertOwnedTag(info, programId, tag, name);
|
|
48247
|
+
return info;
|
|
48248
|
+
}
|
|
48249
|
+
async function fetchOptionalAccount(connection, programId, key, tag, name) {
|
|
48250
|
+
const info = await connection.getAccountInfo(key, "confirmed");
|
|
48251
|
+
if (!info) return null;
|
|
48252
|
+
assertOwnedTag(info, programId, tag, name);
|
|
48253
|
+
return info;
|
|
48254
|
+
}
|
|
48255
|
+
function isOwnedTag(info, programId, tag) {
|
|
48256
|
+
return info !== null && info.owner.equals(programId) && info.data.length > 0 && info.data[0] === tag;
|
|
48257
|
+
}
|
|
48253
48258
|
async function loadThreadNode(connection, programId, pubkey) {
|
|
48254
|
-
const info = await connection
|
|
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");
|
|
48259
|
+
const info = await fetchRequiredAccount(connection, programId, pubkey, TAG_THREAD, "ThreadNode");
|
|
48258
48260
|
return decodeThread(pubkey.toBase58(), info.data);
|
|
48259
48261
|
}
|
|
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
48262
|
async function loadContentNode(connection, programId, pubkey) {
|
|
48268
|
-
const info = await connection
|
|
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");
|
|
48263
|
+
const info = await fetchRequiredAccount(connection, programId, pubkey, TAG_CONTENT, "ContentNode");
|
|
48272
48264
|
return decodeContent(pubkey.toBase58(), info.data);
|
|
48273
48265
|
}
|
|
48274
48266
|
async function loadProgramSettings(connection, programId) {
|
|
48275
48267
|
const settingsKey = deriveSettingsPda(programId);
|
|
48276
|
-
const info = await connection
|
|
48268
|
+
const info = await fetchOptionalAccount(connection, programId, settingsKey, TAG_SETTINGS, "ProgramSettings");
|
|
48277
48269
|
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
48270
|
return decodeSettings(settingsKey.toBase58(), info.data);
|
|
48281
48271
|
}
|
|
48282
48272
|
async function loadThreadAccess(connection, programId, accessKey) {
|
|
48283
|
-
const info = await connection
|
|
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");
|
|
48273
|
+
const info = await fetchRequiredAccount(connection, programId, accessKey, TAG_ACCESS, "ThreadAccess");
|
|
48287
48274
|
return decodeThreadAccess(accessKey.toBase58(), info.data);
|
|
48288
48275
|
}
|
|
48289
48276
|
async function loadAllocLikes(connection, programId, pubkey) {
|
|
48290
|
-
const info = await connection
|
|
48277
|
+
const info = await fetchOptionalAccount(connection, programId, pubkey, TAG_LIKES, "AllocLikes");
|
|
48291
48278
|
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
48279
|
return decodeAllocLikes(pubkey.toBase58(), info.data);
|
|
48295
48280
|
}
|
|
48296
48281
|
async function loadAccessEntries(connection, programId, seed) {
|
|
@@ -48315,10 +48300,8 @@ async function loadAccessEntries(connection, programId, seed) {
|
|
|
48315
48300
|
}
|
|
48316
48301
|
async function loadFollowRegistry(connection, programId, owner) {
|
|
48317
48302
|
const registryKey = deriveFollowRegistryPda(programId, owner);
|
|
48318
|
-
const info = await connection
|
|
48303
|
+
const info = await fetchOptionalAccount(connection, programId, registryKey, TAG_FOLLOW_REGISTRY, "FollowRegistry");
|
|
48319
48304
|
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
48305
|
return decodeFollowRegistry(registryKey.toBase58(), info.data);
|
|
48323
48306
|
}
|
|
48324
48307
|
async function loadFollowerCount(connection, programId, seed) {
|
|
@@ -48330,8 +48313,7 @@ async function loadFollowerCount(connection, programId, seed) {
|
|
|
48330
48313
|
let total = 0n;
|
|
48331
48314
|
for (let i = 0; i < infos.length; i++) {
|
|
48332
48315
|
const info = infos[i];
|
|
48333
|
-
if (!info
|
|
48334
|
-
if (info.data.length === 0 || info.data[0] !== TAG_FOLLOWER_SHARD) continue;
|
|
48316
|
+
if (!isOwnedTag(info, programId, TAG_FOLLOWER_SHARD)) continue;
|
|
48335
48317
|
total += decodeFollowerShard(shardKeys[i].toBase58(), info.data).count;
|
|
48336
48318
|
}
|
|
48337
48319
|
return total;
|
|
@@ -48344,41 +48326,21 @@ async function loadThreadNodesBatched(connection, programId, channels) {
|
|
|
48344
48326
|
const infos = await connection.getMultipleAccountsInfo(chunk, "confirmed");
|
|
48345
48327
|
for (let j = 0; j < infos.length; j++) {
|
|
48346
48328
|
const info = infos[j];
|
|
48347
|
-
if (!info
|
|
48348
|
-
if (info.data.length === 0 || info.data[0] !== TAG_THREAD) continue;
|
|
48329
|
+
if (!isOwnedTag(info, programId, TAG_THREAD)) continue;
|
|
48349
48330
|
const key = chunk[j].toBase58();
|
|
48350
48331
|
result.set(key, decodeThread(key, info.data));
|
|
48351
48332
|
}
|
|
48352
48333
|
}
|
|
48353
48334
|
return result;
|
|
48354
48335
|
}
|
|
48355
|
-
function
|
|
48356
|
-
|
|
48357
|
-
|
|
48358
|
-
|
|
48359
|
-
}
|
|
48360
|
-
|
|
48361
|
-
|
|
48362
|
-
|
|
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
|
-
});
|
|
48336
|
+
function signerMeta(pubkey) {
|
|
48337
|
+
return { pubkey, isSigner: true, isWritable: true };
|
|
48338
|
+
}
|
|
48339
|
+
function writableMeta(pubkey) {
|
|
48340
|
+
return { pubkey, isSigner: false, isWritable: true };
|
|
48341
|
+
}
|
|
48342
|
+
function readonlyMeta(pubkey) {
|
|
48343
|
+
return { pubkey, isSigner: false, isWritable: false };
|
|
48382
48344
|
}
|
|
48383
48345
|
function buildFillSlotInstruction(opts) {
|
|
48384
48346
|
const {
|
|
@@ -48391,7 +48353,6 @@ function buildFillSlotInstruction(opts) {
|
|
|
48391
48353
|
bodyBytes,
|
|
48392
48354
|
kind = KIND_TEXT,
|
|
48393
48355
|
maxFee,
|
|
48394
|
-
extendInfo,
|
|
48395
48356
|
replyAllocSeq: replyAllocSeqRaw,
|
|
48396
48357
|
replySlot: replySlotRaw
|
|
48397
48358
|
} = opts;
|
|
@@ -48402,22 +48363,18 @@ function buildFillSlotInstruction(opts) {
|
|
|
48402
48363
|
const accessAccount = deriveAccessPda(programId, seed);
|
|
48403
48364
|
const entryAccount = deriveAccessEntryPda(programId, seed, payer);
|
|
48404
48365
|
const keys = [
|
|
48405
|
-
|
|
48406
|
-
|
|
48407
|
-
|
|
48408
|
-
|
|
48409
|
-
|
|
48410
|
-
|
|
48366
|
+
signerMeta(payer),
|
|
48367
|
+
readonlyMeta(threadAccount),
|
|
48368
|
+
readonlyMeta(settingsAccount),
|
|
48369
|
+
writableMeta(treasuryShard),
|
|
48370
|
+
writableMeta(authorFeeShard),
|
|
48371
|
+
readonlyMeta(SystemProgram.programId)
|
|
48411
48372
|
];
|
|
48412
|
-
for (const
|
|
48413
|
-
keys.push(
|
|
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 });
|
|
48373
|
+
for (const candidate of candidates) {
|
|
48374
|
+
keys.push(writableMeta(candidate.pda));
|
|
48420
48375
|
}
|
|
48376
|
+
keys.push(readonlyMeta(accessAccount));
|
|
48377
|
+
keys.push(readonlyMeta(entryAccount));
|
|
48421
48378
|
return new TransactionInstruction({
|
|
48422
48379
|
programId,
|
|
48423
48380
|
keys,
|
|
@@ -48425,8 +48382,7 @@ function buildFillSlotInstruction(opts) {
|
|
|
48425
48382
|
tag: Instruction.FillSlot,
|
|
48426
48383
|
kind,
|
|
48427
48384
|
body: bodyBytes,
|
|
48428
|
-
candidates: candidates.map((
|
|
48429
|
-
extend: extendInfo ? 1 : 0,
|
|
48385
|
+
candidates: candidates.map((candidate) => ({ allocSeq: candidate.allocSeq, slot: candidate.slot })),
|
|
48430
48386
|
treasuryShardIdx,
|
|
48431
48387
|
authorFeeShardIdx,
|
|
48432
48388
|
replyAllocSeq: replyAllocSeqRaw ?? INDEX_NONE,
|
|
@@ -48435,26 +48391,58 @@ function buildFillSlotInstruction(opts) {
|
|
|
48435
48391
|
}))
|
|
48436
48392
|
});
|
|
48437
48393
|
}
|
|
48438
|
-
function
|
|
48394
|
+
function buildPrepareAllocInstruction(programId, payer, seed, allocSeq) {
|
|
48395
|
+
const currentAllocPda = deriveAllocPda(programId, seed, allocSeq);
|
|
48396
|
+
const newAllocPda = deriveAllocPda(programId, seed, allocSeq + 1);
|
|
48397
|
+
const threadAccount = deriveThreadPda(programId, seed);
|
|
48398
|
+
return new TransactionInstruction({
|
|
48399
|
+
programId,
|
|
48400
|
+
keys: [
|
|
48401
|
+
signerMeta(payer),
|
|
48402
|
+
writableMeta(currentAllocPda),
|
|
48403
|
+
writableMeta(newAllocPda),
|
|
48404
|
+
writableMeta(threadAccount),
|
|
48405
|
+
readonlyMeta(SystemProgram.programId)
|
|
48406
|
+
],
|
|
48407
|
+
data: Buffer3.from(PrepareAllocInstr.serialize({
|
|
48408
|
+
tag: Instruction.PrepareAlloc,
|
|
48409
|
+
allocSeq
|
|
48410
|
+
}))
|
|
48411
|
+
});
|
|
48412
|
+
}
|
|
48413
|
+
function buildAppendContentInstruction(programId, payer, contentAccount, threadAccount, settingsAccount, treasuryShard, authorFeeShard, chunk, treasuryShardIdx, authorFeeShardIdx, maxFee) {
|
|
48439
48414
|
return new TransactionInstruction({
|
|
48440
48415
|
programId,
|
|
48441
48416
|
keys: [
|
|
48442
|
-
|
|
48443
|
-
|
|
48444
|
-
|
|
48445
|
-
|
|
48446
|
-
|
|
48447
|
-
|
|
48448
|
-
|
|
48417
|
+
signerMeta(payer),
|
|
48418
|
+
writableMeta(contentAccount),
|
|
48419
|
+
readonlyMeta(threadAccount),
|
|
48420
|
+
readonlyMeta(settingsAccount),
|
|
48421
|
+
writableMeta(treasuryShard),
|
|
48422
|
+
writableMeta(authorFeeShard),
|
|
48423
|
+
readonlyMeta(SystemProgram.programId)
|
|
48449
48424
|
],
|
|
48450
48425
|
data: Buffer3.from(AppendContentInstr.serialize({
|
|
48451
48426
|
tag: Instruction.AppendContent,
|
|
48452
48427
|
chunk,
|
|
48453
48428
|
treasuryShardIdx,
|
|
48454
|
-
authorFeeShardIdx
|
|
48429
|
+
authorFeeShardIdx,
|
|
48430
|
+
maxFee
|
|
48455
48431
|
}))
|
|
48456
48432
|
});
|
|
48457
48433
|
}
|
|
48434
|
+
var TX_SIZE_LIMIT = 1232;
|
|
48435
|
+
var TX_OVERHEAD = 1 + 64 + 3 + 32;
|
|
48436
|
+
var FILL_SLOT_FIXED_OVERHEAD = 1 + 2 + 4 + 4 + 2 + 1 + 4 + 1 + 8;
|
|
48437
|
+
var CANDIDATE_SIZE = 4 + 1;
|
|
48438
|
+
var ACCOUNT_KEY_SIZE = 32;
|
|
48439
|
+
var FILL_SLOT_BASE_ACCOUNTS = 6;
|
|
48440
|
+
var FILL_SLOT_ACCESS_ACCOUNTS = 2;
|
|
48441
|
+
var PREPARE_ALLOC_MARGINAL_SIZE = 2 * ACCOUNT_KEY_SIZE + 1 + 1 + 5 + 1 + (1 + 4);
|
|
48442
|
+
var CONTENT_NODE_FIXED_SIZE = 89;
|
|
48443
|
+
var MAX_FEE_SLIPPAGE_NUM = 2n;
|
|
48444
|
+
var APPEND_INSTR_ACCOUNTS = 7;
|
|
48445
|
+
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
48446
|
function ensureTextBytes(text) {
|
|
48459
48447
|
const bytes = new TextEncoder().encode(text);
|
|
48460
48448
|
if (bytes.length === 0) {
|
|
@@ -48473,74 +48461,41 @@ function shuffle(arr) {
|
|
|
48473
48461
|
}
|
|
48474
48462
|
return result;
|
|
48475
48463
|
}
|
|
48476
|
-
|
|
48477
|
-
|
|
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);
|
|
48464
|
+
function estimateFillSlotTxSize(nCandidates, textLen) {
|
|
48465
|
+
const nAccounts = FILL_SLOT_BASE_ACCOUNTS + nCandidates + FILL_SLOT_ACCESS_ACCOUNTS;
|
|
48489
48466
|
const accountsSize = 1 + (nAccounts + 1) * ACCOUNT_KEY_SIZE;
|
|
48490
48467
|
const instrDataSize = FILL_SLOT_FIXED_OVERHEAD + textLen + nCandidates * CANDIDATE_SIZE;
|
|
48491
48468
|
const instrOverhead = 1 + 1 + 1 + nAccounts + 2;
|
|
48492
48469
|
return TX_OVERHEAD + accountsSize + instrOverhead + instrDataSize;
|
|
48493
48470
|
}
|
|
48494
|
-
function maxFillSlotTextLen(nCandidates,
|
|
48495
|
-
const withoutText = estimateFillSlotTxSize(nCandidates,
|
|
48496
|
-
return TX_SIZE_LIMIT - withoutText;
|
|
48471
|
+
function maxFillSlotTextLen(nCandidates, reserve = 0) {
|
|
48472
|
+
const withoutText = estimateFillSlotTxSize(nCandidates, 0);
|
|
48473
|
+
return TX_SIZE_LIMIT - withoutText - reserve;
|
|
48497
48474
|
}
|
|
48498
48475
|
function maxAppendChunkLen() {
|
|
48499
48476
|
return TX_SIZE_LIMIT - APPEND_TX_OVERHEAD;
|
|
48500
48477
|
}
|
|
48478
|
+
function pageCandidates(programId, seed, allocSeq) {
|
|
48479
|
+
return Array.from({ length: CONTENT_SLOTS }, (_, slot) => ({
|
|
48480
|
+
pda: deriveContentPda(programId, seed, allocSeq, slot),
|
|
48481
|
+
allocSeq,
|
|
48482
|
+
slot
|
|
48483
|
+
}));
|
|
48484
|
+
}
|
|
48501
48485
|
async function buildSendMessageTransactions(connection, programId, payerKey, seed, text, replyTo) {
|
|
48502
48486
|
const textBytes = ensureTextBytes(text);
|
|
48503
48487
|
const threadPda = deriveThreadPda(programId, seed);
|
|
48504
48488
|
const thread = await loadThreadNode(connection, programId, threadPda);
|
|
48505
48489
|
const lastAllocSeq = thread.lastAllocSeq;
|
|
48506
|
-
const
|
|
48507
|
-
const
|
|
48508
|
-
const
|
|
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);
|
|
48490
|
+
const windowCandidates = lastAllocSeq >= 1 ? [...pageCandidates(programId, seed, lastAllocSeq - 1), ...pageCandidates(programId, seed, lastAllocSeq)] : pageCandidates(programId, seed, lastAllocSeq);
|
|
48491
|
+
const windowInfos = await connection.getMultipleAccountsInfo(windowCandidates.map((c) => c.pda));
|
|
48492
|
+
const freeInWindow = windowCandidates.filter((_, i) => windowInfos[i] === null);
|
|
48533
48493
|
const treasuryShardIdx = randomTreasuryShard();
|
|
48534
48494
|
const authorFeeShardIdx = randomAuthorFeeShard();
|
|
48535
|
-
const
|
|
48536
|
-
|
|
48537
|
-
|
|
48538
|
-
|
|
48539
|
-
currentAllocPda: lastAllocPda,
|
|
48540
|
-
newAllocPda: deriveAllocPda(programId, seed, lastAllocSeq + 1)
|
|
48541
|
-
};
|
|
48542
|
-
}
|
|
48543
|
-
const maxFirst = maxFillSlotTextLen(selected.length, !!extendInfo);
|
|
48495
|
+
const extendInline = freeInWindow.length === 0;
|
|
48496
|
+
const selected = extendInline ? pageCandidates(programId, seed, lastAllocSeq + 1).slice(0, DESIRED_CANDIDATES) : shuffle(freeInWindow).slice(0, DESIRED_CANDIDATES);
|
|
48497
|
+
const reserve = extendInline ? PREPARE_ALLOC_MARGINAL_SIZE : 0;
|
|
48498
|
+
const maxFirst = maxFillSlotTextLen(selected.length, reserve);
|
|
48544
48499
|
const firstChunkLen = Math.min(textBytes.length, maxFirst);
|
|
48545
48500
|
const firstChunk = textBytes.subarray(0, firstChunkLen);
|
|
48546
48501
|
const settings = await loadProgramSettings(connection, programId);
|
|
@@ -48560,38 +48515,86 @@ async function buildSendMessageTransactions(connection, programId, payerKey, see
|
|
|
48560
48515
|
authorFeeShardIdx,
|
|
48561
48516
|
bodyBytes: firstChunk,
|
|
48562
48517
|
maxFee,
|
|
48563
|
-
extendInfo,
|
|
48564
48518
|
replyAllocSeq: replyTo?.allocSeq ?? null,
|
|
48565
48519
|
replySlot: replyTo?.slot ?? null
|
|
48566
48520
|
});
|
|
48567
|
-
const
|
|
48521
|
+
const firstTx = new Transaction();
|
|
48522
|
+
if (extendInline) {
|
|
48523
|
+
firstTx.add(buildPrepareAllocInstruction(programId, payerKey, seed, lastAllocSeq));
|
|
48524
|
+
}
|
|
48525
|
+
firstTx.add(fillSlotIx);
|
|
48526
|
+
const transactions = [firstTx];
|
|
48568
48527
|
if (firstChunkLen < textBytes.length) {
|
|
48569
48528
|
const remaining = textBytes.subarray(firstChunkLen);
|
|
48570
48529
|
const appendMax = maxAppendChunkLen();
|
|
48571
48530
|
const contentPda = selected[0].pda;
|
|
48572
|
-
const threadPda2 = deriveThreadPda(programId, seed);
|
|
48573
48531
|
const settingsPda = deriveSettingsPda(programId);
|
|
48574
48532
|
const treasuryShardPda = deriveTreasuryShardPda(programId, treasuryShardIdx);
|
|
48575
48533
|
const authorFeeShardPda = deriveAuthorFeePda(programId, seed, authorFeeShardIdx);
|
|
48534
|
+
const emptyRent = BigInt(await connection.getMinimumBalanceForRentExemption(0, "confirmed"));
|
|
48535
|
+
const oneByteRent = BigInt(await connection.getMinimumBalanceForRentExemption(1, "confirmed"));
|
|
48536
|
+
const rentPerByte = oneByteRent - emptyRent;
|
|
48576
48537
|
for (let offset2 = 0; offset2 < remaining.length; offset2 += appendMax) {
|
|
48577
48538
|
const chunk = remaining.subarray(offset2, offset2 + appendMax);
|
|
48539
|
+
const appendBaseFee = BigInt(chunk.length) * rentPerByte * baseFeeBps / 10000n;
|
|
48540
|
+
const appendMaxFee = appendBaseFee * MAX_FEE_SLIPPAGE_NUM + 1n;
|
|
48578
48541
|
const appendIx = buildAppendContentInstruction(
|
|
48579
48542
|
programId,
|
|
48580
48543
|
payerKey,
|
|
48581
48544
|
contentPda,
|
|
48582
|
-
|
|
48545
|
+
threadPda,
|
|
48583
48546
|
settingsPda,
|
|
48584
48547
|
treasuryShardPda,
|
|
48585
48548
|
authorFeeShardPda,
|
|
48586
48549
|
chunk,
|
|
48587
48550
|
treasuryShardIdx,
|
|
48588
|
-
authorFeeShardIdx
|
|
48551
|
+
authorFeeShardIdx,
|
|
48552
|
+
appendMaxFee
|
|
48589
48553
|
);
|
|
48590
48554
|
transactions.push(new Transaction().add(appendIx));
|
|
48591
48555
|
}
|
|
48592
48556
|
}
|
|
48593
48557
|
return transactions;
|
|
48594
48558
|
}
|
|
48559
|
+
async function buildExtendAllocTransaction(connection, programId, payerKey, seed) {
|
|
48560
|
+
const threadPda = deriveThreadPda(programId, seed);
|
|
48561
|
+
const thread = await loadThreadNode(connection, programId, threadPda);
|
|
48562
|
+
const lastAllocSeq = thread.lastAllocSeq;
|
|
48563
|
+
const tailCandidates = pageCandidates(programId, seed, lastAllocSeq);
|
|
48564
|
+
const tailInfos = await connection.getMultipleAccountsInfo(tailCandidates.map((c) => c.pda));
|
|
48565
|
+
const freeOnPageN = tailInfos.filter((info) => info === null).length;
|
|
48566
|
+
const filled = CONTENT_SLOTS - freeOnPageN;
|
|
48567
|
+
if (filled < EXTEND_THRESHOLD) return null;
|
|
48568
|
+
return new Transaction().add(buildPrepareAllocInstruction(programId, payerKey, seed, lastAllocSeq));
|
|
48569
|
+
}
|
|
48570
|
+
function buildCreateRootAllocInstruction(programId, payer, seed, messageFee = 0n, title = "") {
|
|
48571
|
+
const titleBytes = new TextEncoder().encode(title);
|
|
48572
|
+
if (titleBytes.length > MAX_TITLE_LEN) {
|
|
48573
|
+
throw new Error(`Title is too long (max ${MAX_TITLE_LEN} bytes)`);
|
|
48574
|
+
}
|
|
48575
|
+
const threadAccount = deriveThreadPda(programId, seed);
|
|
48576
|
+
const allocAccount = deriveAllocPda(programId, seed, 0);
|
|
48577
|
+
const settingsAccount = deriveSettingsPda(programId);
|
|
48578
|
+
const treasuryShardIdx = randomTreasuryShard();
|
|
48579
|
+
const treasuryShard = deriveTreasuryShardPda(programId, treasuryShardIdx);
|
|
48580
|
+
return new TransactionInstruction({
|
|
48581
|
+
programId,
|
|
48582
|
+
keys: [
|
|
48583
|
+
signerMeta(payer),
|
|
48584
|
+
signerMeta(threadAccount),
|
|
48585
|
+
writableMeta(allocAccount),
|
|
48586
|
+
readonlyMeta(settingsAccount),
|
|
48587
|
+
writableMeta(treasuryShard),
|
|
48588
|
+
readonlyMeta(SystemProgram.programId)
|
|
48589
|
+
],
|
|
48590
|
+
data: Buffer3.from(CreateRootAllocInstr.serialize({
|
|
48591
|
+
tag: Instruction.CreateRootAlloc,
|
|
48592
|
+
messageFee,
|
|
48593
|
+
treasuryShardIdx,
|
|
48594
|
+
title: titleBytes
|
|
48595
|
+
}))
|
|
48596
|
+
});
|
|
48597
|
+
}
|
|
48595
48598
|
async function createRootAlloc(connection, programId, payer, messageFee = 0n, title = "", onSent) {
|
|
48596
48599
|
const programKey = new PublicKey(programId);
|
|
48597
48600
|
const threadKeypair = Keypair.generate();
|
|
@@ -48610,60 +48613,48 @@ async function createRootAlloc(connection, programId, payer, messageFee = 0n, ti
|
|
|
48610
48613
|
allocPda: deriveAllocPda(programKey, seed, 0).toBase58()
|
|
48611
48614
|
};
|
|
48612
48615
|
}
|
|
48613
|
-
function
|
|
48614
|
-
const currentAllocPda = deriveAllocPda(programId, seed, allocSeq);
|
|
48615
|
-
const newAllocPda = deriveAllocPda(programId, seed, allocSeq + 1);
|
|
48616
|
-
const threadAccount = deriveThreadPda(programId, seed);
|
|
48616
|
+
function buildCloseAccountInstruction(programId, payer, targetAccount, likesAccount) {
|
|
48617
48617
|
return new TransactionInstruction({
|
|
48618
48618
|
programId,
|
|
48619
48619
|
keys: [
|
|
48620
|
-
|
|
48621
|
-
|
|
48622
|
-
|
|
48623
|
-
{ pubkey: threadAccount, isSigner: false, isWritable: true },
|
|
48624
|
-
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
|
|
48620
|
+
signerMeta(payer),
|
|
48621
|
+
writableMeta(targetAccount),
|
|
48622
|
+
writableMeta(likesAccount)
|
|
48625
48623
|
],
|
|
48626
|
-
data: Buffer3.from(
|
|
48627
|
-
tag: Instruction.PrepareAlloc,
|
|
48628
|
-
allocSeq
|
|
48629
|
-
}))
|
|
48624
|
+
data: Buffer3.from(TagOnlyInstr.serialize({ tag: Instruction.CloseAccount }))
|
|
48630
48625
|
});
|
|
48631
48626
|
}
|
|
48632
|
-
function
|
|
48633
|
-
const
|
|
48634
|
-
|
|
48635
|
-
|
|
48636
|
-
|
|
48637
|
-
|
|
48638
|
-
|
|
48639
|
-
|
|
48640
|
-
|
|
48641
|
-
isWritable: true
|
|
48642
|
-
});
|
|
48643
|
-
}
|
|
48627
|
+
function buildLikeContentInstruction(programId, payer, seed, allocSeq, slot, maxFee) {
|
|
48628
|
+
const likesAccount = deriveLikesPda(programId, seed, allocSeq);
|
|
48629
|
+
const contentAccount = deriveContentPda(programId, seed, allocSeq, slot);
|
|
48630
|
+
const threadAccount = deriveThreadPda(programId, seed);
|
|
48631
|
+
const settingsAccount = deriveSettingsPda(programId);
|
|
48632
|
+
const treasuryShardIdx = randomTreasuryShard();
|
|
48633
|
+
const authorFeeShardIdx = randomAuthorFeeShard();
|
|
48634
|
+
const treasuryShard = deriveTreasuryShardPda(programId, treasuryShardIdx);
|
|
48635
|
+
const authorFeeShard = deriveAuthorFeePda(programId, seed, authorFeeShardIdx);
|
|
48644
48636
|
return new TransactionInstruction({
|
|
48645
48637
|
programId,
|
|
48646
|
-
keys
|
|
48647
|
-
|
|
48648
|
-
|
|
48649
|
-
|
|
48638
|
+
keys: [
|
|
48639
|
+
signerMeta(payer),
|
|
48640
|
+
writableMeta(likesAccount),
|
|
48641
|
+
readonlyMeta(contentAccount),
|
|
48642
|
+
readonlyMeta(threadAccount),
|
|
48643
|
+
readonlyMeta(settingsAccount),
|
|
48644
|
+
writableMeta(treasuryShard),
|
|
48645
|
+
writableMeta(authorFeeShard),
|
|
48646
|
+
readonlyMeta(SystemProgram.programId)
|
|
48647
|
+
],
|
|
48648
|
+
data: Buffer3.from(LikeContentInstr.serialize({
|
|
48649
|
+
tag: Instruction.LikeContent,
|
|
48650
|
+
allocSeq,
|
|
48651
|
+
slot,
|
|
48652
|
+
treasuryShardIdx,
|
|
48653
|
+
authorFeeShardIdx,
|
|
48654
|
+
maxFee
|
|
48650
48655
|
}))
|
|
48651
48656
|
});
|
|
48652
48657
|
}
|
|
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
|
-
}
|
|
48661
|
-
return new TransactionInstruction({
|
|
48662
|
-
programId,
|
|
48663
|
-
keys,
|
|
48664
|
-
data: Buffer3.from(TagOnlyInstr.serialize({ tag: Instruction.CloseAccount }))
|
|
48665
|
-
});
|
|
48666
|
-
}
|
|
48667
48658
|
function buildInitThreadAccessInstruction(programId, authority, seed, enabled) {
|
|
48668
48659
|
const threadAccount = deriveThreadPda(programId, seed);
|
|
48669
48660
|
const accessAccount = deriveAccessPda(programId, seed);
|
|
@@ -48672,11 +48663,11 @@ function buildInitThreadAccessInstruction(programId, authority, seed, enabled) {
|
|
|
48672
48663
|
return new TransactionInstruction({
|
|
48673
48664
|
programId,
|
|
48674
48665
|
keys: [
|
|
48675
|
-
|
|
48676
|
-
|
|
48677
|
-
|
|
48678
|
-
|
|
48679
|
-
|
|
48666
|
+
signerMeta(authority),
|
|
48667
|
+
readonlyMeta(threadAccount),
|
|
48668
|
+
writableMeta(accessAccount),
|
|
48669
|
+
writableMeta(treasuryShard),
|
|
48670
|
+
readonlyMeta(SystemProgram.programId)
|
|
48680
48671
|
],
|
|
48681
48672
|
data: Buffer3.from(InitThreadAccessInstr.serialize({
|
|
48682
48673
|
tag: Instruction.InitThreadAccess,
|
|
@@ -48689,8 +48680,8 @@ function buildSetThreadAccessInstruction(programId, authority, accessAccount, en
|
|
|
48689
48680
|
return new TransactionInstruction({
|
|
48690
48681
|
programId,
|
|
48691
48682
|
keys: [
|
|
48692
|
-
|
|
48693
|
-
|
|
48683
|
+
signerMeta(authority),
|
|
48684
|
+
writableMeta(accessAccount)
|
|
48694
48685
|
],
|
|
48695
48686
|
data: Buffer3.from(SetThreadAccessInstr.serialize({
|
|
48696
48687
|
tag: Instruction.SetThreadAccess,
|
|
@@ -48698,71 +48689,7 @@ function buildSetThreadAccessInstruction(programId, authority, accessAccount, en
|
|
|
48698
48689
|
}))
|
|
48699
48690
|
});
|
|
48700
48691
|
}
|
|
48701
|
-
function
|
|
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
|
-
function buildRequestAccessInstruction(programId, payer, seed) {
|
|
48692
|
+
function buildRequestAccessInstruction(programId, payer, seed, maxFee) {
|
|
48766
48693
|
const accessAccount = deriveAccessPda(programId, seed);
|
|
48767
48694
|
const entryAccount = deriveAccessEntryPda(programId, seed, payer);
|
|
48768
48695
|
const threadAccount = deriveThreadPda(programId, seed);
|
|
@@ -48774,127 +48701,111 @@ function buildRequestAccessInstruction(programId, payer, seed) {
|
|
|
48774
48701
|
return new TransactionInstruction({
|
|
48775
48702
|
programId,
|
|
48776
48703
|
keys: [
|
|
48777
|
-
|
|
48778
|
-
|
|
48779
|
-
|
|
48780
|
-
|
|
48781
|
-
|
|
48782
|
-
|
|
48783
|
-
|
|
48784
|
-
|
|
48704
|
+
signerMeta(payer),
|
|
48705
|
+
writableMeta(accessAccount),
|
|
48706
|
+
writableMeta(entryAccount),
|
|
48707
|
+
readonlyMeta(threadAccount),
|
|
48708
|
+
readonlyMeta(settingsAccount),
|
|
48709
|
+
writableMeta(treasuryShard),
|
|
48710
|
+
writableMeta(authorFeeShard),
|
|
48711
|
+
readonlyMeta(SystemProgram.programId)
|
|
48785
48712
|
],
|
|
48786
48713
|
data: Buffer3.from(RequestAccessInstr.serialize({
|
|
48787
48714
|
tag: Instruction.RequestAccess,
|
|
48788
48715
|
treasuryShardIdx,
|
|
48789
|
-
authorFeeShardIdx
|
|
48790
|
-
}))
|
|
48791
|
-
});
|
|
48792
|
-
}
|
|
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
48716
|
authorFeeShardIdx,
|
|
48820
48717
|
maxFee
|
|
48821
48718
|
}))
|
|
48822
48719
|
});
|
|
48823
48720
|
}
|
|
48824
|
-
function
|
|
48721
|
+
function buildAclEntryInstruction(tag, programId, authority, seed, wallet) {
|
|
48825
48722
|
const accessAccount = deriveAccessPda(programId, seed);
|
|
48826
48723
|
const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
|
|
48827
48724
|
return new TransactionInstruction({
|
|
48828
48725
|
programId,
|
|
48829
48726
|
keys: [
|
|
48830
|
-
|
|
48831
|
-
|
|
48832
|
-
|
|
48833
|
-
|
|
48727
|
+
signerMeta(authority),
|
|
48728
|
+
writableMeta(accessAccount),
|
|
48729
|
+
writableMeta(entryAccount),
|
|
48730
|
+
readonlyMeta(SystemProgram.programId)
|
|
48834
48731
|
],
|
|
48835
48732
|
data: Buffer3.from(WalletArgInstr.serialize({
|
|
48836
|
-
tag
|
|
48733
|
+
tag,
|
|
48837
48734
|
wallet: wallet.toBytes()
|
|
48838
48735
|
}))
|
|
48839
48736
|
});
|
|
48840
48737
|
}
|
|
48738
|
+
function buildAddToWhitelistInstruction(programId, authority, seed, wallet) {
|
|
48739
|
+
return buildAclEntryInstruction(Instruction.AddToWhitelist, programId, authority, seed, wallet);
|
|
48740
|
+
}
|
|
48741
|
+
function buildRemoveFromWhitelistInstruction(programId, authority, seed, wallet) {
|
|
48742
|
+
return buildAclEntryInstruction(Instruction.RemoveFromWhitelist, programId, authority, seed, wallet);
|
|
48743
|
+
}
|
|
48744
|
+
function buildAddToBlacklistInstruction(programId, authority, seed, wallet) {
|
|
48745
|
+
return buildAclEntryInstruction(Instruction.AddToBlacklist, programId, authority, seed, wallet);
|
|
48746
|
+
}
|
|
48841
48747
|
function buildRemoveFromBlacklistInstruction(programId, authority, seed, wallet) {
|
|
48842
|
-
|
|
48843
|
-
|
|
48748
|
+
return buildAclEntryInstruction(Instruction.RemoveFromBlacklist, programId, authority, seed, wallet);
|
|
48749
|
+
}
|
|
48750
|
+
function buildAddToFeeWhitelistInstruction(programId, authority, seed, wallet) {
|
|
48751
|
+
return buildAclEntryInstruction(Instruction.AddToFeeWhitelist, programId, authority, seed, wallet);
|
|
48752
|
+
}
|
|
48753
|
+
function buildRemoveFromFeeWhitelistInstruction(programId, authority, seed, wallet) {
|
|
48754
|
+
return buildAclEntryInstruction(Instruction.RemoveFromFeeWhitelist, programId, authority, seed, wallet);
|
|
48755
|
+
}
|
|
48756
|
+
var FEE_TAG = {
|
|
48757
|
+
base: Instruction.SetBaseFee,
|
|
48758
|
+
authorCut: Instruction.SetAuthorFeeCut,
|
|
48759
|
+
entryCut: Instruction.SetEntryCut,
|
|
48760
|
+
likeCut: Instruction.SetLikeCut
|
|
48761
|
+
};
|
|
48762
|
+
function buildSetMessageFeeInstruction(programId, authority, threadAccount, fee) {
|
|
48844
48763
|
return new TransactionInstruction({
|
|
48845
48764
|
programId,
|
|
48846
48765
|
keys: [
|
|
48847
|
-
|
|
48848
|
-
|
|
48849
|
-
{ pubkey: entryAccount, isSigner: false, isWritable: true },
|
|
48850
|
-
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
|
|
48766
|
+
signerMeta(authority),
|
|
48767
|
+
writableMeta(threadAccount)
|
|
48851
48768
|
],
|
|
48852
|
-
data: Buffer3.from(
|
|
48853
|
-
tag: Instruction.RemoveFromBlacklist,
|
|
48854
|
-
wallet: wallet.toBytes()
|
|
48855
|
-
}))
|
|
48769
|
+
data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetMessageFee, fee }))
|
|
48856
48770
|
});
|
|
48857
48771
|
}
|
|
48858
|
-
function
|
|
48859
|
-
const accessAccount = deriveAccessPda(programId, seed);
|
|
48860
|
-
const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
|
|
48772
|
+
function buildSetLikeFeeInstruction(programId, authority, threadAccount, fee) {
|
|
48861
48773
|
return new TransactionInstruction({
|
|
48862
48774
|
programId,
|
|
48863
48775
|
keys: [
|
|
48864
|
-
|
|
48865
|
-
|
|
48866
|
-
{ pubkey: entryAccount, isSigner: false, isWritable: true },
|
|
48867
|
-
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
|
|
48776
|
+
signerMeta(authority),
|
|
48777
|
+
writableMeta(threadAccount)
|
|
48868
48778
|
],
|
|
48869
|
-
data: Buffer3.from(
|
|
48870
|
-
tag: Instruction.AddToFeeWhitelist,
|
|
48871
|
-
wallet: wallet.toBytes()
|
|
48872
|
-
}))
|
|
48779
|
+
data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetLikeFee, fee }))
|
|
48873
48780
|
});
|
|
48874
48781
|
}
|
|
48875
|
-
function
|
|
48876
|
-
const accessAccount = deriveAccessPda(programId, seed);
|
|
48877
|
-
const entryAccount = deriveAccessEntryPda(programId, seed, wallet);
|
|
48782
|
+
function buildSetEntryFeeInstruction(programId, authority, accessAccount, fee) {
|
|
48878
48783
|
return new TransactionInstruction({
|
|
48879
48784
|
programId,
|
|
48880
48785
|
keys: [
|
|
48881
|
-
|
|
48882
|
-
|
|
48883
|
-
{ pubkey: entryAccount, isSigner: false, isWritable: true },
|
|
48884
|
-
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false }
|
|
48786
|
+
signerMeta(authority),
|
|
48787
|
+
writableMeta(accessAccount)
|
|
48885
48788
|
],
|
|
48886
|
-
data: Buffer3.from(
|
|
48887
|
-
|
|
48888
|
-
|
|
48789
|
+
data: Buffer3.from(FeeU64Instr.serialize({ tag: Instruction.SetEntryFee, fee }))
|
|
48790
|
+
});
|
|
48791
|
+
}
|
|
48792
|
+
function buildSweepAuthorFeesInstruction(programId, seed, threadAccount, authorWallet, shardIndices) {
|
|
48793
|
+
const keys = [
|
|
48794
|
+
readonlyMeta(threadAccount),
|
|
48795
|
+
signerMeta(authorWallet)
|
|
48796
|
+
];
|
|
48797
|
+
for (const idx of shardIndices) {
|
|
48798
|
+
keys.push(writableMeta(deriveAuthorFeePda(programId, seed, idx)));
|
|
48799
|
+
}
|
|
48800
|
+
return new TransactionInstruction({
|
|
48801
|
+
programId,
|
|
48802
|
+
keys,
|
|
48803
|
+
data: Buffer3.from(SweepAuthorFeesInstr.serialize({
|
|
48804
|
+
tag: Instruction.SweepAuthorFees,
|
|
48805
|
+
shardIndices: Uint8Array.from(shardIndices)
|
|
48889
48806
|
}))
|
|
48890
48807
|
});
|
|
48891
48808
|
}
|
|
48892
|
-
var FEE_TAG = {
|
|
48893
|
-
base: Instruction.SetBaseFee,
|
|
48894
|
-
authorCut: Instruction.SetAuthorFeeCut,
|
|
48895
|
-
entryCut: Instruction.SetEntryCut,
|
|
48896
|
-
likeCut: Instruction.SetLikeCut
|
|
48897
|
-
};
|
|
48898
48809
|
function buildFollowInstruction(tag, opts) {
|
|
48899
48810
|
const { programId, user, seed } = opts;
|
|
48900
48811
|
const threadAccount = deriveThreadPda(programId, seed);
|
|
@@ -48903,11 +48814,11 @@ function buildFollowInstruction(tag, opts) {
|
|
|
48903
48814
|
return new TransactionInstruction({
|
|
48904
48815
|
programId,
|
|
48905
48816
|
keys: [
|
|
48906
|
-
|
|
48907
|
-
|
|
48908
|
-
|
|
48909
|
-
|
|
48910
|
-
|
|
48817
|
+
signerMeta(user),
|
|
48818
|
+
writableMeta(followRegistry),
|
|
48819
|
+
writableMeta(followerShard),
|
|
48820
|
+
readonlyMeta(threadAccount),
|
|
48821
|
+
readonlyMeta(SystemProgram.programId)
|
|
48911
48822
|
],
|
|
48912
48823
|
data: Buffer3.from(TagOnlyInstr.serialize({ tag }))
|
|
48913
48824
|
});
|
|
@@ -48981,6 +48892,18 @@ async function sendTransactions(payer, txs) {
|
|
|
48981
48892
|
}
|
|
48982
48893
|
return sigs;
|
|
48983
48894
|
}
|
|
48895
|
+
async function trySendBestEffort(payer, tx) {
|
|
48896
|
+
try {
|
|
48897
|
+
const { connection } = loadConfig();
|
|
48898
|
+
tx.feePayer = payer.publicKey;
|
|
48899
|
+
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
48900
|
+
tx.recentBlockhash = blockhash;
|
|
48901
|
+
tx.sign(payer);
|
|
48902
|
+
return await connection.sendRawTransaction(tx.serialize());
|
|
48903
|
+
} catch {
|
|
48904
|
+
return null;
|
|
48905
|
+
}
|
|
48906
|
+
}
|
|
48984
48907
|
function explorerTx(signature) {
|
|
48985
48908
|
const { rpcUrl } = loadConfig();
|
|
48986
48909
|
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 +49036,7 @@ function registerMessagingTools(server) {
|
|
|
49113
49036
|
"send_message",
|
|
49114
49037
|
{
|
|
49115
49038
|
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.",
|
|
49039
|
+
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
49040
|
inputSchema: {
|
|
49118
49041
|
channel: channelArg,
|
|
49119
49042
|
text: external_exports.string().min(1).describe("Message text (UTF-8, up to 8192 bytes)."),
|
|
@@ -49135,10 +49058,19 @@ function registerMessagingTools(server) {
|
|
|
49135
49058
|
replyTo
|
|
49136
49059
|
);
|
|
49137
49060
|
const signatures = await sendTransactions(payer, txs);
|
|
49061
|
+
let extendSignature = null;
|
|
49062
|
+
try {
|
|
49063
|
+
const extendTx = await buildExtendAllocTransaction(connection, programId, payer.publicKey, seed);
|
|
49064
|
+
if (extendTx) extendSignature = await trySendBestEffort(payer, extendTx);
|
|
49065
|
+
} catch {
|
|
49066
|
+
extendSignature = null;
|
|
49067
|
+
}
|
|
49138
49068
|
return jsonResult({
|
|
49139
49069
|
channel: seedToAddress(seed),
|
|
49140
49070
|
signatures,
|
|
49141
|
-
explorer: signatures.map(explorerTx)
|
|
49071
|
+
explorer: signatures.map(explorerTx),
|
|
49072
|
+
extendSignature,
|
|
49073
|
+
extendExplorer: extendSignature ? explorerTx(extendSignature) : null
|
|
49142
49074
|
});
|
|
49143
49075
|
})
|
|
49144
49076
|
);
|
|
@@ -49151,15 +49083,17 @@ function registerMessagingTools(server) {
|
|
|
49151
49083
|
channel: channelArg,
|
|
49152
49084
|
allocSeq: external_exports.number().int().describe("allocSeq of the target message."),
|
|
49153
49085
|
slot: external_exports.number().int().describe("slot of the target message."),
|
|
49154
|
-
text: external_exports.string().min(1).describe("Text chunk to append.")
|
|
49086
|
+
text: external_exports.string().min(1).describe("Text chunk to append."),
|
|
49087
|
+
maxFee: external_exports.union([external_exports.number(), external_exports.string()]).optional().describe("Max base fee in lamports willing to pay for the append (slippage cap). Default 100000000 (0.1 SOL).")
|
|
49155
49088
|
}
|
|
49156
49089
|
},
|
|
49157
|
-
handler(async ({ channel, allocSeq, slot, text }) => {
|
|
49090
|
+
handler(async ({ channel, allocSeq, slot, text, maxFee }) => {
|
|
49158
49091
|
const { programId } = loadConfig();
|
|
49159
49092
|
const payer = loadWallet();
|
|
49160
49093
|
const seed = resolveSeed(channel);
|
|
49161
49094
|
const treasuryShardIdx = randomTreasuryShard();
|
|
49162
49095
|
const authorFeeShardIdx = randomAuthorFeeShard();
|
|
49096
|
+
const cap = maxFee === void 0 ? 100000000n : toLamports(maxFee);
|
|
49163
49097
|
const ix = buildAppendContentInstruction(
|
|
49164
49098
|
programId,
|
|
49165
49099
|
payer.publicKey,
|
|
@@ -49170,7 +49104,8 @@ function registerMessagingTools(server) {
|
|
|
49170
49104
|
deriveAuthorFeePda(programId, seed, authorFeeShardIdx),
|
|
49171
49105
|
new TextEncoder().encode(text),
|
|
49172
49106
|
treasuryShardIdx,
|
|
49173
|
-
authorFeeShardIdx
|
|
49107
|
+
authorFeeShardIdx,
|
|
49108
|
+
cap
|
|
49174
49109
|
);
|
|
49175
49110
|
const signature = await sendInstructions(payer, [ix]);
|
|
49176
49111
|
return jsonResult({ signature, explorer: explorerTx(signature) });
|
|
@@ -49180,7 +49115,7 @@ function registerMessagingTools(server) {
|
|
|
49180
49115
|
"prepare_alloc",
|
|
49181
49116
|
{
|
|
49182
49117
|
title: "Prepare alloc",
|
|
49183
|
-
description: "
|
|
49118
|
+
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
49119
|
inputSchema: {
|
|
49185
49120
|
channel: channelArg,
|
|
49186
49121
|
allocSeq: external_exports.number().int().describe("Current alloc seq to extend from.")
|
|
@@ -49246,14 +49181,18 @@ function registerMessagingTools(server) {
|
|
|
49246
49181
|
"request_access",
|
|
49247
49182
|
{
|
|
49248
49183
|
title: "Request channel access",
|
|
49249
|
-
description: "Pay the entry fee to join a gated channel so the agent wallet can post in it.",
|
|
49250
|
-
inputSchema: {
|
|
49184
|
+
description: "Pay the entry fee to join a gated channel so the agent wallet can post in it. The current on-chain entry fee is used as the slippage cap unless maxFee is given.",
|
|
49185
|
+
inputSchema: {
|
|
49186
|
+
channel: channelArg,
|
|
49187
|
+
maxFee: external_exports.union([external_exports.number(), external_exports.string()]).optional().describe("Max entry fee in lamports willing to pay (slippage cap). Defaults to the current on-chain entry fee.")
|
|
49188
|
+
}
|
|
49251
49189
|
},
|
|
49252
|
-
handler(async ({ channel }) => {
|
|
49253
|
-
const { programId } = loadConfig();
|
|
49190
|
+
handler(async ({ channel, maxFee }) => {
|
|
49191
|
+
const { connection, programId } = loadConfig();
|
|
49254
49192
|
const payer = loadWallet();
|
|
49255
49193
|
const seed = resolveSeed(channel);
|
|
49256
|
-
const
|
|
49194
|
+
const cap = maxFee === void 0 ? (await loadThreadAccess(connection, programId, deriveAccessPda(programId, seed))).entryFee : toLamports(maxFee);
|
|
49195
|
+
const ix = buildRequestAccessInstruction(programId, payer.publicKey, seed, cap);
|
|
49257
49196
|
const signature = await sendInstructions(payer, [ix]);
|
|
49258
49197
|
return jsonResult({ signature, explorer: explorerTx(signature) });
|
|
49259
49198
|
})
|
|
@@ -49644,7 +49583,7 @@ function registerThreadAdminTools(server) {
|
|
|
49644
49583
|
async function main() {
|
|
49645
49584
|
const config2 = loadConfig();
|
|
49646
49585
|
const wallet = loadWallet();
|
|
49647
|
-
const server = new McpServer({ name: "txtcel-mcp", version: "0.
|
|
49586
|
+
const server = new McpServer({ name: "txtcel-mcp", version: "0.2.0" });
|
|
49648
49587
|
registerMessagingTools(server);
|
|
49649
49588
|
registerFollowTools(server);
|
|
49650
49589
|
registerReadTools(server);
|