pyre-world-kit 1.0.16 → 1.0.18
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/actions.d.ts +1 -11
- package/dist/actions.js +4 -125
- package/dist/intel.js +16 -10
- package/package.json +2 -2
- package/src/actions.ts +5 -150
- package/src/intel.ts +17 -11
package/dist/actions.d.ts
CHANGED
|
@@ -37,17 +37,7 @@ export declare function getWarChest(connection: Connection, mint: string): Promi
|
|
|
37
37
|
export declare function getWarLoan(connection: Connection, mint: string, wallet: string): Promise<WarLoan>;
|
|
38
38
|
/** Get all war loans for a faction */
|
|
39
39
|
export declare function getAllWarLoans(connection: Connection, mint: string): Promise<AllWarLoansResult>;
|
|
40
|
-
/**
|
|
41
|
-
* Compute max borrowable SOL for a given collateral amount.
|
|
42
|
-
*
|
|
43
|
-
* Mirrors the burnfun LendingDashboard logic — effective max borrow is the
|
|
44
|
-
* minimum of three caps:
|
|
45
|
-
* 1. LTV limit: collateral_value_sol * (max_ltv_bps / 10000)
|
|
46
|
-
* 2. Pool available: treasury_sol * utilization_cap - total_lent
|
|
47
|
-
* 3. Per-user cap: (collateral / total_supply) * borrow_share_multiplier * max_lendable
|
|
48
|
-
*
|
|
49
|
-
* All values in lamports. Accounts for Token-2022 transfer fee (4 bps).
|
|
50
|
-
*/
|
|
40
|
+
/** Compute max borrowable SOL for a given collateral amount */
|
|
51
41
|
export declare function getMaxWarLoan(connection: Connection, mint: string, collateralAmount: number): Promise<WarLoanQuote>;
|
|
52
42
|
/** Launch a new faction (create token) */
|
|
53
43
|
export declare function launchFaction(connection: Connection, params: LaunchFactionParams): Promise<LaunchFactionResult>;
|
package/dist/actions.js
CHANGED
|
@@ -5,9 +5,6 @@
|
|
|
5
5
|
* Thin wrappers that call torchsdk functions and map params/results
|
|
6
6
|
* into game-semantic Pyre types. No new on-chain logic.
|
|
7
7
|
*/
|
|
8
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
-
};
|
|
11
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
9
|
exports.createEphemeralAgent = void 0;
|
|
13
10
|
exports.blacklistMints = blacklistMints;
|
|
@@ -54,7 +51,6 @@ exports.confirmAction = confirmAction;
|
|
|
54
51
|
exports.getDexPool = getDexPool;
|
|
55
52
|
exports.getDexVaults = getDexVaults;
|
|
56
53
|
const web3_js_1 = require("@solana/web3.js");
|
|
57
|
-
const bs58_1 = __importDefault(require("bs58"));
|
|
58
54
|
const torchsdk_1 = require("torchsdk");
|
|
59
55
|
const mappers_1 = require("./mappers");
|
|
60
56
|
const vanity_1 = require("./vanity");
|
|
@@ -124,82 +120,8 @@ async function getMembers(connection, mint, limit) {
|
|
|
124
120
|
}
|
|
125
121
|
/** Get faction comms (trade-bundled messages, including post-ascension DEX messages) */
|
|
126
122
|
async function getComms(connection, mint, limit) {
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
// Fetch bonding curve messages AND pool state messages in parallel
|
|
130
|
-
const bondingCommsPromise = (0, torchsdk_1.getMessages)(connection, mint, safeLimit)
|
|
131
|
-
.then(r => (0, mappers_1.mapMessagesResult)(r))
|
|
132
|
-
.catch(() => ({ comms: [], total: 0 }));
|
|
133
|
-
const poolCommsPromise = (async () => {
|
|
134
|
-
try {
|
|
135
|
-
const mintPubkey = new web3_js_1.PublicKey(mint);
|
|
136
|
-
const { poolState } = (0, torchsdk_1.getRaydiumMigrationAccounts)(mintPubkey);
|
|
137
|
-
const signatures = await connection.getSignaturesForAddress(poolState, { limit: Math.min(safeLimit, 50) }, 'confirmed');
|
|
138
|
-
if (signatures.length === 0)
|
|
139
|
-
return { comms: [], total: 0 };
|
|
140
|
-
const txs = await connection.getParsedTransactions(signatures.map(s => s.signature), { maxSupportedTransactionVersion: 0 });
|
|
141
|
-
const comms = [];
|
|
142
|
-
for (let i = 0; i < txs.length; i++) {
|
|
143
|
-
const tx = txs[i];
|
|
144
|
-
if (!tx?.meta || tx.meta.err)
|
|
145
|
-
continue;
|
|
146
|
-
const sig = signatures[i];
|
|
147
|
-
// Check top-level and inner instructions for memo
|
|
148
|
-
const allInstructions = [
|
|
149
|
-
...tx.transaction.message.instructions,
|
|
150
|
-
...(tx.meta.innerInstructions || []).flatMap(inner => inner.instructions),
|
|
151
|
-
];
|
|
152
|
-
for (const ix of allInstructions) {
|
|
153
|
-
const programId = 'programId' in ix ? ix.programId.toString() : '';
|
|
154
|
-
const programName = 'program' in ix ? ix.program : '';
|
|
155
|
-
const isMemo = programId === MEMO_PROGRAM || programName === 'spl-memo';
|
|
156
|
-
if (isMemo) {
|
|
157
|
-
let memoText = '';
|
|
158
|
-
if ('parsed' in ix) {
|
|
159
|
-
memoText = typeof ix.parsed === 'string' ? ix.parsed : JSON.stringify(ix.parsed);
|
|
160
|
-
}
|
|
161
|
-
else if ('data' in ix && typeof ix.data === 'string') {
|
|
162
|
-
try {
|
|
163
|
-
memoText = new TextDecoder().decode(bs58_1.default.decode(ix.data));
|
|
164
|
-
}
|
|
165
|
-
catch {
|
|
166
|
-
memoText = ix.data;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (memoText && memoText.trim()) {
|
|
170
|
-
const sender = tx.transaction.message.accountKeys[0]?.pubkey?.toString() || 'Unknown';
|
|
171
|
-
comms.push({
|
|
172
|
-
signature: sig.signature,
|
|
173
|
-
memo: memoText.trim(),
|
|
174
|
-
sender,
|
|
175
|
-
timestamp: sig.blockTime || 0,
|
|
176
|
-
});
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return { comms, total: comms.length };
|
|
183
|
-
}
|
|
184
|
-
catch {
|
|
185
|
-
return { comms: [], total: 0 };
|
|
186
|
-
}
|
|
187
|
-
})();
|
|
188
|
-
const [bondingResult, poolResult] = await Promise.all([bondingCommsPromise, poolCommsPromise]);
|
|
189
|
-
// Merge, dedupe by signature, sort newest first, trim to limit
|
|
190
|
-
const seen = new Set();
|
|
191
|
-
const allComms = [];
|
|
192
|
-
for (const c of [...bondingResult.comms, ...poolResult.comms]) {
|
|
193
|
-
if (!seen.has(c.signature)) {
|
|
194
|
-
seen.add(c.signature);
|
|
195
|
-
allComms.push(c);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
allComms.sort((a, b) => b.timestamp - a.timestamp);
|
|
199
|
-
return {
|
|
200
|
-
comms: allComms.slice(0, safeLimit),
|
|
201
|
-
total: allComms.length,
|
|
202
|
-
};
|
|
123
|
+
const result = await (0, torchsdk_1.getMessages)(connection, mint, limit);
|
|
124
|
+
return (0, mappers_1.mapMessagesResult)(result);
|
|
203
125
|
}
|
|
204
126
|
/** Get a quote for joining a faction (buying tokens) */
|
|
205
127
|
async function getJoinQuote(connection, mint, amountSolLamports) {
|
|
@@ -239,52 +161,9 @@ async function getAllWarLoans(connection, mint) {
|
|
|
239
161
|
const result = await (0, torchsdk_1.getAllLoanPositions)(connection, mint);
|
|
240
162
|
return (0, mappers_1.mapAllLoansResult)(result);
|
|
241
163
|
}
|
|
242
|
-
/**
|
|
243
|
-
* Compute max borrowable SOL for a given collateral amount.
|
|
244
|
-
*
|
|
245
|
-
* Mirrors the burnfun LendingDashboard logic — effective max borrow is the
|
|
246
|
-
* minimum of three caps:
|
|
247
|
-
* 1. LTV limit: collateral_value_sol * (max_ltv_bps / 10000)
|
|
248
|
-
* 2. Pool available: treasury_sol * utilization_cap - total_lent
|
|
249
|
-
* 3. Per-user cap: (collateral / total_supply) * borrow_share_multiplier * max_lendable
|
|
250
|
-
*
|
|
251
|
-
* All values in lamports. Accounts for Token-2022 transfer fee (4 bps).
|
|
252
|
-
*/
|
|
164
|
+
/** Compute max borrowable SOL for a given collateral amount */
|
|
253
165
|
async function getMaxWarLoan(connection, mint, collateralAmount) {
|
|
254
|
-
|
|
255
|
-
const TRANSFER_FEE_BPS = 4;
|
|
256
|
-
const LAMPORTS_PER_SOL = 1_000_000_000;
|
|
257
|
-
const [lending, detail] = await Promise.all([
|
|
258
|
-
(0, torchsdk_1.getLendingInfo)(connection, mint),
|
|
259
|
-
(0, torchsdk_1.getToken)(connection, mint),
|
|
260
|
-
]);
|
|
261
|
-
// Price per base-unit token in SOL (lamports)
|
|
262
|
-
const pricePerToken = detail.price_sol; // SOL per display token
|
|
263
|
-
const TOKEN_MULTIPLIER = 1_000_000;
|
|
264
|
-
// Collateral value in SOL (lamports)
|
|
265
|
-
const collateralDisplayTokens = collateralAmount / TOKEN_MULTIPLIER;
|
|
266
|
-
const collateralValueSol = collateralDisplayTokens * pricePerToken * LAMPORTS_PER_SOL;
|
|
267
|
-
// 1. LTV cap
|
|
268
|
-
const ltvMaxSol = collateralValueSol * (lending.max_ltv_bps / 10000);
|
|
269
|
-
// 2. Pool available
|
|
270
|
-
const treasurySol = detail.treasury_sol_balance * LAMPORTS_PER_SOL;
|
|
271
|
-
const maxLendableSol = treasurySol * lending.utilization_cap_bps / 10000;
|
|
272
|
-
const totalLent = (lending.total_sol_lent ?? 0);
|
|
273
|
-
const poolAvailableSol = Math.max(0, maxLendableSol - totalLent);
|
|
274
|
-
// 3. Per-user cap (accounts for transfer fee reducing net collateral)
|
|
275
|
-
const netCollateral = collateralAmount * (1 - TRANSFER_FEE_BPS / 10000);
|
|
276
|
-
const borrowMultiplier = lending.borrow_share_multiplier || 3;
|
|
277
|
-
const perUserCapSol = maxLendableSol * netCollateral * borrowMultiplier / TOTAL_SUPPLY;
|
|
278
|
-
const maxBorrowSol = Math.max(0, Math.min(ltvMaxSol, poolAvailableSol, perUserCapSol));
|
|
279
|
-
return {
|
|
280
|
-
max_borrow_sol: Math.floor(maxBorrowSol),
|
|
281
|
-
collateral_value_sol: Math.floor(collateralValueSol),
|
|
282
|
-
ltv_max_sol: Math.floor(ltvMaxSol),
|
|
283
|
-
pool_available_sol: Math.floor(poolAvailableSol),
|
|
284
|
-
per_user_cap_sol: Math.floor(perUserCapSol),
|
|
285
|
-
interest_rate_bps: lending.interest_rate_bps,
|
|
286
|
-
liquidation_threshold_bps: lending.liquidation_threshold_bps,
|
|
287
|
-
};
|
|
166
|
+
return (0, torchsdk_1.getBorrowQuote)(connection, mint, collateralAmount);
|
|
288
167
|
}
|
|
289
168
|
// ─── Faction Operations (controller) ───────────────────────────────
|
|
290
169
|
/** Launch a new faction (create token) */
|
package/dist/intel.js
CHANGED
|
@@ -16,6 +16,7 @@ exports.getWorldFeed = getWorldFeed;
|
|
|
16
16
|
exports.getWorldStats = getWorldStats;
|
|
17
17
|
const torchsdk_1 = require("torchsdk");
|
|
18
18
|
const mappers_1 = require("./mappers");
|
|
19
|
+
const vanity_1 = require("./vanity");
|
|
19
20
|
// ─── Faction Power & Rankings ──────────────────────────────────────
|
|
20
21
|
/**
|
|
21
22
|
* Calculate a faction's power score.
|
|
@@ -54,7 +55,8 @@ async function getFactionLeaderboard(connection, opts) {
|
|
|
54
55
|
};
|
|
55
56
|
const sdkStatus = opts?.status ? statusMap[opts.status] : 'all';
|
|
56
57
|
const result = await (0, torchsdk_1.getTokens)(connection, { limit: opts?.limit ?? 100, status: sdkStatus });
|
|
57
|
-
const
|
|
58
|
+
const pyreFactions = result.tokens.filter(t => (0, vanity_1.isPyreMint)(t.mint));
|
|
59
|
+
const powers = pyreFactions.map((t) => ({
|
|
58
60
|
mint: t.mint,
|
|
59
61
|
name: t.name,
|
|
60
62
|
symbol: t.symbol,
|
|
@@ -118,7 +120,7 @@ async function getFactionRivals(connection, mint, limit = 50) {
|
|
|
118
120
|
const rivalCounts = new Map();
|
|
119
121
|
// Get all factions to cross-reference
|
|
120
122
|
const allFactions = await (0, torchsdk_1.getTokens)(connection, { limit: 20, sort: 'volume' });
|
|
121
|
-
for (const faction of allFactions.tokens) {
|
|
123
|
+
for (const faction of allFactions.tokens.filter(t => (0, vanity_1.isPyreMint)(t.mint))) {
|
|
122
124
|
if (faction.mint === mint)
|
|
123
125
|
continue;
|
|
124
126
|
const holders = await (0, torchsdk_1.getHolders)(connection, faction.mint, 50);
|
|
@@ -163,7 +165,7 @@ async function getAgentProfile(connection, wallet) {
|
|
|
163
165
|
const factions = await getAgentFactions(connection, wallet);
|
|
164
166
|
// Find factions this wallet created
|
|
165
167
|
const allFactions = await (0, torchsdk_1.getTokens)(connection, { limit: 100 });
|
|
166
|
-
const founded = allFactions.tokens
|
|
168
|
+
const founded = allFactions.tokens.filter(t => (0, vanity_1.isPyreMint)(t.mint))
|
|
167
169
|
.filter(t => t.mint) // TokenSummary doesn't have creator, so we skip for now
|
|
168
170
|
.map(t => t.mint);
|
|
169
171
|
const totalValue = factions.reduce((sum, f) => sum + f.value_sol, 0);
|
|
@@ -194,9 +196,10 @@ async function getAgentProfile(connection, wallet) {
|
|
|
194
196
|
*/
|
|
195
197
|
async function getAgentFactions(connection, wallet, factionLimit = 50) {
|
|
196
198
|
const allFactions = await (0, torchsdk_1.getTokens)(connection, { limit: factionLimit });
|
|
199
|
+
const pyreFactions = allFactions.tokens.filter(t => (0, vanity_1.isPyreMint)(t.mint));
|
|
197
200
|
const positions = [];
|
|
198
201
|
// Check each faction for this holder
|
|
199
|
-
await Promise.all(
|
|
202
|
+
await Promise.all(pyreFactions.map(async (faction) => {
|
|
200
203
|
try {
|
|
201
204
|
const holders = await (0, torchsdk_1.getHolders)(connection, faction.mint, 100);
|
|
202
205
|
const holding = holders.holders.find(h => h.address === wallet);
|
|
@@ -230,7 +233,7 @@ async function getWorldFeed(connection, opts) {
|
|
|
230
233
|
const allFactions = await (0, torchsdk_1.getTokens)(connection, { limit: factionLimit, sort: 'newest' });
|
|
231
234
|
const events = [];
|
|
232
235
|
// Add launch events for each faction
|
|
233
|
-
for (const faction of allFactions.tokens) {
|
|
236
|
+
for (const faction of allFactions.tokens.filter(t => (0, vanity_1.isPyreMint)(t.mint))) {
|
|
234
237
|
events.push({
|
|
235
238
|
type: 'launch',
|
|
236
239
|
faction_mint: faction.mint,
|
|
@@ -284,11 +287,14 @@ async function getWorldFeed(connection, opts) {
|
|
|
284
287
|
*/
|
|
285
288
|
async function getWorldStats(connection) {
|
|
286
289
|
const [all, rising, ascended] = await Promise.all([
|
|
287
|
-
(0, torchsdk_1.getTokens)(connection, { limit:
|
|
290
|
+
(0, torchsdk_1.getTokens)(connection, { limit: 200, status: 'all' }),
|
|
288
291
|
(0, torchsdk_1.getTokens)(connection, { limit: 100, status: 'bonding' }),
|
|
289
292
|
(0, torchsdk_1.getTokens)(connection, { limit: 100, status: 'migrated' }),
|
|
290
293
|
]);
|
|
291
|
-
const
|
|
294
|
+
const pyreAll = all.tokens.filter(t => (0, vanity_1.isPyreMint)(t.mint));
|
|
295
|
+
const pyreRising = rising.tokens.filter(t => (0, vanity_1.isPyreMint)(t.mint));
|
|
296
|
+
const pyreAscended = ascended.tokens.filter(t => (0, vanity_1.isPyreMint)(t.mint));
|
|
297
|
+
const allFactions = [...pyreRising, ...pyreAscended];
|
|
292
298
|
const totalSolLocked = allFactions.reduce((sum, t) => sum + t.market_cap_sol, 0);
|
|
293
299
|
// Find most powerful
|
|
294
300
|
let mostPowerful = null;
|
|
@@ -312,9 +318,9 @@ async function getWorldStats(connection) {
|
|
|
312
318
|
}
|
|
313
319
|
}
|
|
314
320
|
return {
|
|
315
|
-
total_factions:
|
|
316
|
-
rising_factions:
|
|
317
|
-
ascended_factions:
|
|
321
|
+
total_factions: pyreAll.length,
|
|
322
|
+
rising_factions: pyreRising.length,
|
|
323
|
+
ascended_factions: pyreAscended.length,
|
|
318
324
|
total_sol_locked: totalSolLocked,
|
|
319
325
|
most_powerful: mostPowerful,
|
|
320
326
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pyre-world-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"description": "Agent-first faction warfare kit — game-semantic wrapper over torchsdk",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"@solana/spl-token": "^0.4.6",
|
|
16
16
|
"@solana/web3.js": "^1.98.4",
|
|
17
17
|
"bs58": "^6.0.0",
|
|
18
|
-
"torchsdk": "^3.7.
|
|
18
|
+
"torchsdk": "^3.7.35"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^22.15.0",
|
package/src/actions.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
9
|
-
import bs58 from 'bs58';
|
|
10
9
|
import {
|
|
11
10
|
// Read operations
|
|
12
11
|
getTokens,
|
|
@@ -15,6 +14,7 @@ import {
|
|
|
15
14
|
getMessages,
|
|
16
15
|
getBuyQuote,
|
|
17
16
|
getSellQuote,
|
|
17
|
+
getBorrowQuote,
|
|
18
18
|
getVault,
|
|
19
19
|
getVaultForWallet,
|
|
20
20
|
getVaultWalletLink,
|
|
@@ -197,102 +197,8 @@ export async function getComms(
|
|
|
197
197
|
mint: string,
|
|
198
198
|
limit?: number,
|
|
199
199
|
): Promise<CommsResult> {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
// Fetch bonding curve messages AND pool state messages in parallel
|
|
204
|
-
const bondingCommsPromise = getMessages(connection, mint, safeLimit)
|
|
205
|
-
.then(r => mapMessagesResult(r))
|
|
206
|
-
.catch(() => ({ comms: [], total: 0 } as CommsResult));
|
|
207
|
-
|
|
208
|
-
const poolCommsPromise = (async (): Promise<CommsResult> => {
|
|
209
|
-
try {
|
|
210
|
-
const mintPubkey = new PublicKey(mint);
|
|
211
|
-
const { poolState } = getRaydiumMigrationAccounts(mintPubkey);
|
|
212
|
-
|
|
213
|
-
const signatures = await connection.getSignaturesForAddress(
|
|
214
|
-
poolState,
|
|
215
|
-
{ limit: Math.min(safeLimit, 50) },
|
|
216
|
-
'confirmed',
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
if (signatures.length === 0) return { comms: [], total: 0 };
|
|
220
|
-
|
|
221
|
-
const txs = await connection.getParsedTransactions(
|
|
222
|
-
signatures.map(s => s.signature),
|
|
223
|
-
{ maxSupportedTransactionVersion: 0 },
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
const comms: CommsResult['comms'] = [];
|
|
227
|
-
|
|
228
|
-
for (let i = 0; i < txs.length; i++) {
|
|
229
|
-
const tx = txs[i];
|
|
230
|
-
if (!tx?.meta || tx.meta.err) continue;
|
|
231
|
-
|
|
232
|
-
const sig = signatures[i];
|
|
233
|
-
|
|
234
|
-
// Check top-level and inner instructions for memo
|
|
235
|
-
const allInstructions = [
|
|
236
|
-
...tx.transaction.message.instructions,
|
|
237
|
-
...(tx.meta.innerInstructions || []).flatMap(inner => inner.instructions),
|
|
238
|
-
];
|
|
239
|
-
|
|
240
|
-
for (const ix of allInstructions) {
|
|
241
|
-
const programId = 'programId' in ix ? ix.programId.toString() : '';
|
|
242
|
-
const programName = 'program' in ix ? (ix as { program: string }).program : '';
|
|
243
|
-
const isMemo = programId === MEMO_PROGRAM || programName === 'spl-memo';
|
|
244
|
-
|
|
245
|
-
if (isMemo) {
|
|
246
|
-
let memoText = '';
|
|
247
|
-
if ('parsed' in ix) {
|
|
248
|
-
memoText = typeof ix.parsed === 'string' ? ix.parsed : JSON.stringify(ix.parsed);
|
|
249
|
-
} else if ('data' in ix && typeof ix.data === 'string') {
|
|
250
|
-
try {
|
|
251
|
-
memoText = new TextDecoder().decode(bs58.decode(ix.data));
|
|
252
|
-
} catch {
|
|
253
|
-
memoText = ix.data;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (memoText && memoText.trim()) {
|
|
258
|
-
const sender = tx.transaction.message.accountKeys[0]?.pubkey?.toString() || 'Unknown';
|
|
259
|
-
comms.push({
|
|
260
|
-
signature: sig.signature,
|
|
261
|
-
memo: memoText.trim(),
|
|
262
|
-
sender,
|
|
263
|
-
timestamp: sig.blockTime || 0,
|
|
264
|
-
});
|
|
265
|
-
break;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return { comms, total: comms.length };
|
|
272
|
-
} catch {
|
|
273
|
-
return { comms: [], total: 0 };
|
|
274
|
-
}
|
|
275
|
-
})();
|
|
276
|
-
|
|
277
|
-
const [bondingResult, poolResult] = await Promise.all([bondingCommsPromise, poolCommsPromise]);
|
|
278
|
-
|
|
279
|
-
// Merge, dedupe by signature, sort newest first, trim to limit
|
|
280
|
-
const seen = new Set<string>();
|
|
281
|
-
const allComms: CommsResult['comms'] = [];
|
|
282
|
-
|
|
283
|
-
for (const c of [...bondingResult.comms, ...poolResult.comms]) {
|
|
284
|
-
if (!seen.has(c.signature)) {
|
|
285
|
-
seen.add(c.signature);
|
|
286
|
-
allComms.push(c);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
allComms.sort((a, b) => b.timestamp - a.timestamp);
|
|
291
|
-
|
|
292
|
-
return {
|
|
293
|
-
comms: allComms.slice(0, safeLimit),
|
|
294
|
-
total: allComms.length,
|
|
295
|
-
};
|
|
200
|
+
const result = await getMessages(connection, mint, limit);
|
|
201
|
+
return mapMessagesResult(result);
|
|
296
202
|
}
|
|
297
203
|
|
|
298
204
|
/** Get a quote for joining a faction (buying tokens) */
|
|
@@ -368,64 +274,13 @@ export async function getAllWarLoans(
|
|
|
368
274
|
return mapAllLoansResult(result);
|
|
369
275
|
}
|
|
370
276
|
|
|
371
|
-
/**
|
|
372
|
-
* Compute max borrowable SOL for a given collateral amount.
|
|
373
|
-
*
|
|
374
|
-
* Mirrors the burnfun LendingDashboard logic — effective max borrow is the
|
|
375
|
-
* minimum of three caps:
|
|
376
|
-
* 1. LTV limit: collateral_value_sol * (max_ltv_bps / 10000)
|
|
377
|
-
* 2. Pool available: treasury_sol * utilization_cap - total_lent
|
|
378
|
-
* 3. Per-user cap: (collateral / total_supply) * borrow_share_multiplier * max_lendable
|
|
379
|
-
*
|
|
380
|
-
* All values in lamports. Accounts for Token-2022 transfer fee (4 bps).
|
|
381
|
-
*/
|
|
277
|
+
/** Compute max borrowable SOL for a given collateral amount */
|
|
382
278
|
export async function getMaxWarLoan(
|
|
383
279
|
connection: Connection,
|
|
384
280
|
mint: string,
|
|
385
281
|
collateralAmount: number,
|
|
386
282
|
): Promise<WarLoanQuote> {
|
|
387
|
-
|
|
388
|
-
const TRANSFER_FEE_BPS = 4;
|
|
389
|
-
const LAMPORTS_PER_SOL = 1_000_000_000;
|
|
390
|
-
|
|
391
|
-
const [lending, detail] = await Promise.all([
|
|
392
|
-
getLendingInfo(connection, mint),
|
|
393
|
-
getToken(connection, mint),
|
|
394
|
-
]);
|
|
395
|
-
|
|
396
|
-
// Price per base-unit token in SOL (lamports)
|
|
397
|
-
const pricePerToken = detail.price_sol; // SOL per display token
|
|
398
|
-
const TOKEN_MULTIPLIER = 1_000_000;
|
|
399
|
-
|
|
400
|
-
// Collateral value in SOL (lamports)
|
|
401
|
-
const collateralDisplayTokens = collateralAmount / TOKEN_MULTIPLIER;
|
|
402
|
-
const collateralValueSol = collateralDisplayTokens * pricePerToken * LAMPORTS_PER_SOL;
|
|
403
|
-
|
|
404
|
-
// 1. LTV cap
|
|
405
|
-
const ltvMaxSol = collateralValueSol * (lending.max_ltv_bps / 10000);
|
|
406
|
-
|
|
407
|
-
// 2. Pool available
|
|
408
|
-
const treasurySol = detail.treasury_sol_balance * LAMPORTS_PER_SOL;
|
|
409
|
-
const maxLendableSol = treasurySol * lending.utilization_cap_bps / 10000;
|
|
410
|
-
const totalLent = (lending.total_sol_lent ?? 0);
|
|
411
|
-
const poolAvailableSol = Math.max(0, maxLendableSol - totalLent);
|
|
412
|
-
|
|
413
|
-
// 3. Per-user cap (accounts for transfer fee reducing net collateral)
|
|
414
|
-
const netCollateral = collateralAmount * (1 - TRANSFER_FEE_BPS / 10000);
|
|
415
|
-
const borrowMultiplier = lending.borrow_share_multiplier || 3;
|
|
416
|
-
const perUserCapSol = maxLendableSol * netCollateral * borrowMultiplier / TOTAL_SUPPLY;
|
|
417
|
-
|
|
418
|
-
const maxBorrowSol = Math.max(0, Math.min(ltvMaxSol, poolAvailableSol, perUserCapSol));
|
|
419
|
-
|
|
420
|
-
return {
|
|
421
|
-
max_borrow_sol: Math.floor(maxBorrowSol),
|
|
422
|
-
collateral_value_sol: Math.floor(collateralValueSol),
|
|
423
|
-
ltv_max_sol: Math.floor(ltvMaxSol),
|
|
424
|
-
pool_available_sol: Math.floor(poolAvailableSol),
|
|
425
|
-
per_user_cap_sol: Math.floor(perUserCapSol),
|
|
426
|
-
interest_rate_bps: lending.interest_rate_bps,
|
|
427
|
-
liquidation_threshold_bps: lending.liquidation_threshold_bps,
|
|
428
|
-
};
|
|
283
|
+
return getBorrowQuote(connection, mint, collateralAmount);
|
|
429
284
|
}
|
|
430
285
|
|
|
431
286
|
// ─── Faction Operations (controller) ───────────────────────────────
|
package/src/intel.ts
CHANGED
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
} from 'torchsdk';
|
|
18
18
|
import type { TokenDetail, TokenSummary } from 'torchsdk';
|
|
19
19
|
|
|
20
|
-
import { mapFactionStatus
|
|
20
|
+
import { mapFactionStatus } from './mappers';
|
|
21
|
+
import { isPyreMint } from './vanity';
|
|
21
22
|
import type {
|
|
22
23
|
FactionPower,
|
|
23
24
|
AllianceCluster,
|
|
@@ -75,8 +76,9 @@ export async function getFactionLeaderboard(
|
|
|
75
76
|
};
|
|
76
77
|
const sdkStatus = opts?.status ? statusMap[opts.status] as any : 'all';
|
|
77
78
|
const result = await getTokens(connection, { limit: opts?.limit ?? 100, status: sdkStatus });
|
|
79
|
+
const pyreFactions = result.tokens.filter(t => isPyreMint(t.mint));
|
|
78
80
|
|
|
79
|
-
const powers: FactionPower[] =
|
|
81
|
+
const powers: FactionPower[] = pyreFactions.map((t) => ({
|
|
80
82
|
mint: t.mint,
|
|
81
83
|
name: t.name,
|
|
82
84
|
symbol: t.symbol,
|
|
@@ -158,7 +160,7 @@ export async function getFactionRivals(
|
|
|
158
160
|
|
|
159
161
|
// Get all factions to cross-reference
|
|
160
162
|
const allFactions = await getTokens(connection, { limit: 20, sort: 'volume' });
|
|
161
|
-
for (const faction of allFactions.tokens) {
|
|
163
|
+
for (const faction of allFactions.tokens.filter(t => isPyreMint(t.mint))) {
|
|
162
164
|
if (faction.mint === mint) continue;
|
|
163
165
|
const holders = await getHolders(connection, faction.mint, 50);
|
|
164
166
|
const holderAddrs = new Set(holders.holders.map(h => h.address));
|
|
@@ -211,7 +213,7 @@ export async function getAgentProfile(
|
|
|
211
213
|
|
|
212
214
|
// Find factions this wallet created
|
|
213
215
|
const allFactions = await getTokens(connection, { limit: 100 });
|
|
214
|
-
const founded = allFactions.tokens
|
|
216
|
+
const founded = allFactions.tokens.filter(t => isPyreMint(t.mint))
|
|
215
217
|
.filter(t => t.mint) // TokenSummary doesn't have creator, so we skip for now
|
|
216
218
|
.map(t => t.mint);
|
|
217
219
|
|
|
@@ -249,11 +251,12 @@ export async function getAgentFactions(
|
|
|
249
251
|
factionLimit = 50,
|
|
250
252
|
): Promise<AgentFactionPosition[]> {
|
|
251
253
|
const allFactions = await getTokens(connection, { limit: factionLimit });
|
|
254
|
+
const pyreFactions = allFactions.tokens.filter(t => isPyreMint(t.mint));
|
|
252
255
|
const positions: AgentFactionPosition[] = [];
|
|
253
256
|
|
|
254
257
|
// Check each faction for this holder
|
|
255
258
|
await Promise.all(
|
|
256
|
-
|
|
259
|
+
pyreFactions.map(async (faction) => {
|
|
257
260
|
try {
|
|
258
261
|
const holders = await getHolders(connection, faction.mint, 100);
|
|
259
262
|
const holding = holders.holders.find(h => h.address === wallet);
|
|
@@ -295,7 +298,7 @@ export async function getWorldFeed(
|
|
|
295
298
|
const events: WorldEvent[] = [];
|
|
296
299
|
|
|
297
300
|
// Add launch events for each faction
|
|
298
|
-
for (const faction of allFactions.tokens) {
|
|
301
|
+
for (const faction of allFactions.tokens.filter(t => isPyreMint(t.mint))) {
|
|
299
302
|
events.push({
|
|
300
303
|
type: 'launch',
|
|
301
304
|
faction_mint: faction.mint,
|
|
@@ -355,12 +358,15 @@ export async function getWorldStats(
|
|
|
355
358
|
connection: Connection,
|
|
356
359
|
): Promise<WorldStats> {
|
|
357
360
|
const [all, rising, ascended] = await Promise.all([
|
|
358
|
-
getTokens(connection, { limit:
|
|
361
|
+
getTokens(connection, { limit: 200, status: 'all' }),
|
|
359
362
|
getTokens(connection, { limit: 100, status: 'bonding' }),
|
|
360
363
|
getTokens(connection, { limit: 100, status: 'migrated' }),
|
|
361
364
|
]);
|
|
362
365
|
|
|
363
|
-
const
|
|
366
|
+
const pyreAll = all.tokens.filter(t => isPyreMint(t.mint));
|
|
367
|
+
const pyreRising = rising.tokens.filter(t => isPyreMint(t.mint));
|
|
368
|
+
const pyreAscended = ascended.tokens.filter(t => isPyreMint(t.mint));
|
|
369
|
+
const allFactions = [...pyreRising, ...pyreAscended];
|
|
364
370
|
const totalSolLocked = allFactions.reduce((sum, t) => sum + t.market_cap_sol, 0);
|
|
365
371
|
|
|
366
372
|
// Find most powerful
|
|
@@ -386,9 +392,9 @@ export async function getWorldStats(
|
|
|
386
392
|
}
|
|
387
393
|
|
|
388
394
|
return {
|
|
389
|
-
total_factions:
|
|
390
|
-
rising_factions:
|
|
391
|
-
ascended_factions:
|
|
395
|
+
total_factions: pyreAll.length,
|
|
396
|
+
rising_factions: pyreRising.length,
|
|
397
|
+
ascended_factions: pyreAscended.length,
|
|
392
398
|
total_sol_locked: totalSolLocked,
|
|
393
399
|
most_powerful: mostPowerful,
|
|
394
400
|
};
|