pyre-world-kit 3.0.1 → 3.0.3
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.d.ts +6 -8
- package/dist/index.js +2 -2
- package/dist/providers/action.provider.d.ts +5 -2
- package/dist/providers/action.provider.js +52 -1
- package/dist/providers/mapper.provider.d.ts +0 -5
- package/dist/providers/mapper.provider.js +0 -5
- package/dist/providers/registry.provider.d.ts +4 -10
- package/dist/providers/registry.provider.js +2 -16
- package/dist/providers/state.provider.d.ts +3 -12
- package/dist/providers/state.provider.js +4 -33
- package/dist/types/action.types.d.ts +1 -0
- package/dist/types/registry.types.d.ts +10 -0
- package/dist/types/registry.types.js +1 -0
- package/package.json +1 -1
- package/readme.md +3 -0
- package/src/index.ts +12 -8
- package/src/providers/action.provider.ts +71 -11
- package/src/providers/intel.provider.ts +3 -3
- package/src/providers/mapper.provider.ts +0 -6
- package/src/providers/registry.provider.ts +7 -28
- package/src/providers/state.provider.ts +8 -46
- package/src/types/action.types.ts +1 -0
- package/src/types/registry.types.ts +21 -0
- package/tests/test_e2e.ts +22 -0
package/dist/index.d.ts
CHANGED
|
@@ -6,17 +6,15 @@
|
|
|
6
6
|
* so agents think in factions, not tokens.
|
|
7
7
|
*/
|
|
8
8
|
import { Connection } from '@solana/web3.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { Action } from './types/action.types';
|
|
10
|
+
import { Intel } from './types/intel.types';
|
|
11
|
+
import { Registry } from './types/registry.types';
|
|
12
12
|
import { StateProvider } from './providers/state.provider';
|
|
13
|
-
import type { Action } from './types/action.types';
|
|
14
|
-
import type { Intel } from './types/intel.types';
|
|
15
13
|
import type { CheckpointConfig } from './types/state.types';
|
|
16
14
|
export declare class PyreKit {
|
|
17
|
-
readonly actions:
|
|
18
|
-
readonly intel:
|
|
19
|
-
readonly registry:
|
|
15
|
+
readonly actions: Action;
|
|
16
|
+
readonly intel: Intel;
|
|
17
|
+
readonly registry: Registry;
|
|
20
18
|
readonly state: StateProvider;
|
|
21
19
|
constructor(connection: Connection, publicKey: string);
|
|
22
20
|
/** Callback fired when checkpoint interval is reached */
|
package/dist/index.js
CHANGED
|
@@ -20,8 +20,8 @@ class PyreKit {
|
|
|
20
20
|
state;
|
|
21
21
|
constructor(connection, publicKey) {
|
|
22
22
|
this.registry = new registry_provider_1.RegistryProvider(connection);
|
|
23
|
-
this.state = new state_provider_1.StateProvider(connection,
|
|
24
|
-
this.actions = new action_provider_1.ActionProvider(connection);
|
|
23
|
+
this.state = new state_provider_1.StateProvider(connection, this.registry, publicKey);
|
|
24
|
+
this.actions = new action_provider_1.ActionProvider(connection, this.registry);
|
|
25
25
|
this.intel = new intel_provider_1.IntelProvider(connection, this.actions);
|
|
26
26
|
// Wire auto-checkpoint callback
|
|
27
27
|
this.state.onCheckpointDue = () => this.onCheckpointDue?.();
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Connection } from '@solana/web3.js';
|
|
2
|
-
import { Action } from '../types/action.types';
|
|
3
2
|
import { BuyQuoteResult, SellQuoteResult, TransactionResult } from 'torchsdk';
|
|
4
3
|
import { AgentLink, AllWarLoansResult, AscendParams, ClaimSpoilsParams, CommsResult, CoupParams, CreateStrongholdParams, DefectParams, ExileAgentParams, FactionDetail, FactionListParams, FactionListResult, FactionStatus, FudFactionParams, FundStrongholdParams, JoinFactionParams, JoinFactionResult, LaunchFactionParams, LaunchFactionResult, MembersResult, MessageFactionParams, RallyParams, RazeParams, RecruitAgentParams, RepayWarLoanParams, RequestWarLoanParams, SiegeParams, Stronghold, TitheParams, WarChest, WarLoan, WarLoanQuote, WithdrawAssetsParams, WithdrawFromStrongholdParams } from '../types';
|
|
4
|
+
import { Action } from '../types/action.types';
|
|
5
|
+
import { Registry } from '../types/registry.types';
|
|
5
6
|
export declare class ActionProvider implements Action {
|
|
6
7
|
private connection;
|
|
8
|
+
private registryProvider;
|
|
7
9
|
private mapper;
|
|
8
|
-
constructor(connection: Connection);
|
|
10
|
+
constructor(connection: Connection, registryProvider: Registry);
|
|
9
11
|
createStronghold(params: CreateStrongholdParams): Promise<TransactionResult>;
|
|
10
12
|
coup(params: CoupParams): Promise<TransactionResult>;
|
|
11
13
|
exileAgent(params: ExileAgentParams): Promise<TransactionResult>;
|
|
@@ -41,6 +43,7 @@ export declare class ActionProvider implements Action {
|
|
|
41
43
|
raze(params: RazeParams): Promise<TransactionResult>;
|
|
42
44
|
repayWarLoan(params: RepayWarLoanParams): Promise<TransactionResult>;
|
|
43
45
|
requestWarLoan(params: RequestWarLoanParams): Promise<TransactionResult>;
|
|
46
|
+
scout(targetAddress: string): Promise<string>;
|
|
44
47
|
siege(params: SiegeParams): Promise<TransactionResult>;
|
|
45
48
|
tithe(params: TitheParams): Promise<TransactionResult>;
|
|
46
49
|
}
|
|
@@ -8,9 +8,11 @@ const vanity_1 = require("../vanity");
|
|
|
8
8
|
const util_1 = require("../util");
|
|
9
9
|
class ActionProvider {
|
|
10
10
|
connection;
|
|
11
|
+
registryProvider;
|
|
11
12
|
mapper = new mapper_provider_1.MapperProvider();
|
|
12
|
-
constructor(connection) {
|
|
13
|
+
constructor(connection, registryProvider) {
|
|
13
14
|
this.connection = connection;
|
|
15
|
+
this.registryProvider = registryProvider;
|
|
14
16
|
}
|
|
15
17
|
async createStronghold(params) {
|
|
16
18
|
return (0, torchsdk_1.buildCreateVaultTransaction)(this.connection, { creator: params.creator });
|
|
@@ -310,6 +312,55 @@ class ActionProvider {
|
|
|
310
312
|
vault: params.stronghold,
|
|
311
313
|
});
|
|
312
314
|
}
|
|
315
|
+
async scout(targetAddress) {
|
|
316
|
+
try {
|
|
317
|
+
const p = await this.registryProvider.getProfile(targetAddress);
|
|
318
|
+
if (!p)
|
|
319
|
+
return ` @${targetAddress.slice(0, 8)}: no pyre identity found`;
|
|
320
|
+
const total = p.joins +
|
|
321
|
+
p.defects +
|
|
322
|
+
p.rallies +
|
|
323
|
+
p.launches +
|
|
324
|
+
p.messages +
|
|
325
|
+
p.fuds +
|
|
326
|
+
p.infiltrates +
|
|
327
|
+
p.reinforces +
|
|
328
|
+
p.war_loans +
|
|
329
|
+
p.repay_loans +
|
|
330
|
+
p.sieges +
|
|
331
|
+
p.ascends +
|
|
332
|
+
p.razes +
|
|
333
|
+
p.tithes;
|
|
334
|
+
const topActions = [
|
|
335
|
+
{ n: 'joins', v: p.joins },
|
|
336
|
+
{ n: 'defects', v: p.defects },
|
|
337
|
+
{ n: 'rallies', v: p.rallies },
|
|
338
|
+
{ n: 'messages', v: p.messages },
|
|
339
|
+
{ n: 'fuds', v: p.fuds },
|
|
340
|
+
{ n: 'infiltrates', v: p.infiltrates },
|
|
341
|
+
{ n: 'reinforces', v: p.reinforces },
|
|
342
|
+
{ n: 'war_loans', v: p.war_loans },
|
|
343
|
+
{ n: 'sieges', v: p.sieges },
|
|
344
|
+
]
|
|
345
|
+
.sort((a, b) => b.v - a.v)
|
|
346
|
+
.filter((a) => a.v > 0)
|
|
347
|
+
.slice(0, 4)
|
|
348
|
+
.map((a) => `${a.n}:${a.v}`)
|
|
349
|
+
.join(', ');
|
|
350
|
+
const personality = p.personality_summary || 'unknown';
|
|
351
|
+
const checkpoint = p.last_checkpoint > 0
|
|
352
|
+
? new Date(p.last_checkpoint * 1000).toISOString().slice(0, 10)
|
|
353
|
+
: 'never';
|
|
354
|
+
const spent = (p.total_sol_spent ?? 0) / 1e9;
|
|
355
|
+
const received = (p.total_sol_received ?? 0) / 1e9;
|
|
356
|
+
const pnl = received - spent;
|
|
357
|
+
const pnlStr = pnl >= 0 ? `+${pnl.toFixed(3)}` : pnl.toFixed(3);
|
|
358
|
+
return ` @${targetAddress.slice(0, 8)}: "${personality}" | ${total} actions (${topActions}) | P&L: ${pnlStr} SOL | last seen: ${checkpoint}`;
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return ` @${targetAddress.slice(0, 8)}: lookup failed`;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
313
364
|
async siege(params) {
|
|
314
365
|
return (0, torchsdk_1.buildLiquidateTransaction)(this.connection, {
|
|
315
366
|
mint: params.mint,
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pyre Kit Mappers
|
|
3
|
-
*
|
|
4
|
-
* Internal mapping functions between Torch SDK types and Pyre game types.
|
|
5
|
-
*/
|
|
6
1
|
import type { AllLoanPositionsResult, BuyTransactionResult, CreateTokenResult, Holder, HoldersResult, LendingInfo, LoanPositionInfo, LoanPositionWithKey, MessagesResult, TokenDetail, TokenListResult, TokenMessage, TokenStatus, TokenSummary, VaultInfo, VaultWalletLinkInfo } from 'torchsdk';
|
|
7
2
|
import type { FactionStatus, FactionStatusFilter, Strategy } from '../types';
|
|
8
3
|
import { Mapper } from '../types/mapper.types';
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Pyre Kit Mappers
|
|
4
|
-
*
|
|
5
|
-
* Internal mapping functions between Torch SDK types and Pyre game types.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.MapperProvider = void 0;
|
|
9
4
|
const mapper_types_1 = require("../types/mapper.types");
|
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pyre World Agent Registry Provider
|
|
3
|
-
*
|
|
4
|
-
* On-chain agent identity and state persistence.
|
|
5
|
-
* Agents checkpoint their action distributions and personality summaries
|
|
6
|
-
* so any machine with the wallet key can reconstruct the agent.
|
|
7
|
-
*/
|
|
8
1
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
9
2
|
import type { TransactionResult } from 'torchsdk';
|
|
10
3
|
import type { RegistryProfile, RegistryWalletLink, RegisterAgentParams, CheckpointParams, LinkAgentWalletParams, UnlinkAgentWalletParams, TransferAgentAuthorityParams } from '../types';
|
|
4
|
+
import { Registry } from '../types/registry.types';
|
|
11
5
|
export declare const REGISTRY_PROGRAM_ID: PublicKey;
|
|
12
6
|
export declare function getAgentProfilePda(creator: PublicKey): [PublicKey, number];
|
|
13
7
|
export declare function getAgentWalletLinkPda(wallet: PublicKey): [PublicKey, number];
|
|
14
|
-
export declare class RegistryProvider {
|
|
8
|
+
export declare class RegistryProvider implements Registry {
|
|
15
9
|
private connection;
|
|
16
10
|
constructor(connection: Connection);
|
|
17
11
|
private getProgram;
|
|
18
|
-
getProfile(creator: string): Promise<RegistryProfile |
|
|
19
|
-
getWalletLink(wallet: string): Promise<RegistryWalletLink |
|
|
12
|
+
getProfile(creator: string): Promise<RegistryProfile | undefined>;
|
|
13
|
+
getWalletLink(wallet: string): Promise<RegistryWalletLink | undefined>;
|
|
20
14
|
register(params: RegisterAgentParams): Promise<TransactionResult>;
|
|
21
15
|
checkpoint(params: CheckpointParams): Promise<TransactionResult>;
|
|
22
16
|
linkWallet(params: LinkAgentWalletParams): Promise<TransactionResult>;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Pyre World Agent Registry Provider
|
|
4
|
-
*
|
|
5
|
-
* On-chain agent identity and state persistence.
|
|
6
|
-
* Agents checkpoint their action distributions and personality summaries
|
|
7
|
-
* so any machine with the wallet key can reconstruct the agent.
|
|
8
|
-
*/
|
|
9
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
4
|
};
|
|
@@ -16,19 +9,15 @@ exports.getAgentWalletLinkPda = getAgentWalletLinkPda;
|
|
|
16
9
|
const web3_js_1 = require("@solana/web3.js");
|
|
17
10
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
18
11
|
const pyre_world_json_1 = __importDefault(require("../pyre_world.json"));
|
|
19
|
-
// ─── Program ID ─────────────────────────────────────────────────────
|
|
20
12
|
exports.REGISTRY_PROGRAM_ID = new web3_js_1.PublicKey(pyre_world_json_1.default.address);
|
|
21
|
-
// ─── PDA Seeds ──────────────────────────────────────────────────────
|
|
22
13
|
const AGENT_SEED = 'pyre_agent';
|
|
23
14
|
const AGENT_WALLET_SEED = 'pyre_agent_wallet';
|
|
24
|
-
// ─── PDA Helpers ────────────────────────────────────────────────────
|
|
25
15
|
function getAgentProfilePda(creator) {
|
|
26
16
|
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(AGENT_SEED), creator.toBuffer()], exports.REGISTRY_PROGRAM_ID);
|
|
27
17
|
}
|
|
28
18
|
function getAgentWalletLinkPda(wallet) {
|
|
29
19
|
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(AGENT_WALLET_SEED), wallet.toBuffer()], exports.REGISTRY_PROGRAM_ID);
|
|
30
20
|
}
|
|
31
|
-
// ─── Anchor Program Helper ──────────────────────────────────────────
|
|
32
21
|
function makeDummyProvider(connection, payer) {
|
|
33
22
|
const dummyWallet = {
|
|
34
23
|
publicKey: payer,
|
|
@@ -42,7 +31,6 @@ async function finalizeTransaction(connection, tx, feePayer) {
|
|
|
42
31
|
tx.recentBlockhash = blockhash;
|
|
43
32
|
tx.feePayer = feePayer;
|
|
44
33
|
}
|
|
45
|
-
// ─── Provider ───────────────────────────────────────────────────────
|
|
46
34
|
class RegistryProvider {
|
|
47
35
|
connection;
|
|
48
36
|
constructor(connection) {
|
|
@@ -52,7 +40,6 @@ class RegistryProvider {
|
|
|
52
40
|
const provider = makeDummyProvider(this.connection, payer);
|
|
53
41
|
return new anchor_1.Program(pyre_world_json_1.default, provider);
|
|
54
42
|
}
|
|
55
|
-
// ─── Read Operations ──────────────────────────────────────────────
|
|
56
43
|
async getProfile(creator) {
|
|
57
44
|
const creatorPk = new web3_js_1.PublicKey(creator);
|
|
58
45
|
const [profilePda] = getAgentProfilePda(creatorPk);
|
|
@@ -87,7 +74,7 @@ class RegistryProvider {
|
|
|
87
74
|
};
|
|
88
75
|
}
|
|
89
76
|
catch {
|
|
90
|
-
return
|
|
77
|
+
return undefined;
|
|
91
78
|
}
|
|
92
79
|
}
|
|
93
80
|
async getWalletLink(wallet) {
|
|
@@ -105,10 +92,9 @@ class RegistryProvider {
|
|
|
105
92
|
};
|
|
106
93
|
}
|
|
107
94
|
catch {
|
|
108
|
-
return
|
|
95
|
+
return undefined;
|
|
109
96
|
}
|
|
110
97
|
}
|
|
111
|
-
// ─── Transaction Builders ─────────────────────────────────────────
|
|
112
98
|
async register(params) {
|
|
113
99
|
const creator = new web3_js_1.PublicKey(params.creator);
|
|
114
100
|
const [profile] = getAgentProfilePda(creator);
|
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pyre Kit State Provider
|
|
3
|
-
*
|
|
4
|
-
* Objective game state tracking for an agent.
|
|
5
|
-
* Owns holdings, action counts, vault resolution, tick counter.
|
|
6
|
-
* Injected into ActionProvider so every action automatically updates state.
|
|
7
|
-
*/
|
|
8
1
|
import { Connection } from '@solana/web3.js';
|
|
9
2
|
import type { State, AgentGameState, SerializedGameState, TrackedAction, CheckpointConfig } from '../types/state.types';
|
|
10
|
-
import {
|
|
3
|
+
import { Registry } from '../types/registry.types';
|
|
11
4
|
export declare class StateProvider implements State {
|
|
12
5
|
private connection;
|
|
13
|
-
private publicKey;
|
|
14
6
|
private registry;
|
|
7
|
+
private publicKey;
|
|
15
8
|
private _state;
|
|
16
9
|
private checkpointConfig;
|
|
17
10
|
private ticksSinceCheckpoint;
|
|
18
|
-
constructor(connection: Connection,
|
|
11
|
+
constructor(connection: Connection, registry: Registry, publicKey: string);
|
|
19
12
|
get state(): AgentGameState | null;
|
|
20
13
|
get vaultCreator(): string | null;
|
|
21
14
|
get initialized(): boolean;
|
|
@@ -24,9 +17,7 @@ export declare class StateProvider implements State {
|
|
|
24
17
|
setCheckpointConfig(config: CheckpointConfig): void;
|
|
25
18
|
init(): Promise<AgentGameState>;
|
|
26
19
|
record(action: TrackedAction, mint?: string, description?: string): Promise<void>;
|
|
27
|
-
/** Update sentiment score for a faction based on action type */
|
|
28
20
|
private updateSentiment;
|
|
29
|
-
/** Callback set by PyreKit to handle checkpoint triggers */
|
|
30
21
|
onCheckpointDue: (() => void) | null;
|
|
31
22
|
refreshHoldings(): Promise<void>;
|
|
32
23
|
getSentiment(mint: string): number;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Pyre Kit State Provider
|
|
4
|
-
*
|
|
5
|
-
* Objective game state tracking for an agent.
|
|
6
|
-
* Owns holdings, action counts, vault resolution, tick counter.
|
|
7
|
-
* Injected into ActionProvider so every action automatically updates state.
|
|
8
|
-
*/
|
|
9
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
3
|
if (k2 === undefined) k2 = k;
|
|
11
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -62,17 +55,16 @@ const EMPTY_COUNTS = {
|
|
|
62
55
|
};
|
|
63
56
|
class StateProvider {
|
|
64
57
|
connection;
|
|
65
|
-
publicKey;
|
|
66
58
|
registry;
|
|
59
|
+
publicKey;
|
|
67
60
|
_state = null;
|
|
68
61
|
checkpointConfig = null;
|
|
69
62
|
ticksSinceCheckpoint = 0;
|
|
70
|
-
constructor(connection,
|
|
63
|
+
constructor(connection, registry, publicKey) {
|
|
71
64
|
this.connection = connection;
|
|
72
|
-
this.publicKey = publicKey;
|
|
73
65
|
this.registry = registry;
|
|
66
|
+
this.publicKey = publicKey;
|
|
74
67
|
}
|
|
75
|
-
// ─── Readonly accessors ─────────────────────────────────────────
|
|
76
68
|
get state() {
|
|
77
69
|
return this._state;
|
|
78
70
|
}
|
|
@@ -85,12 +77,10 @@ class StateProvider {
|
|
|
85
77
|
get tick() {
|
|
86
78
|
return this._state?.tick ?? 0;
|
|
87
79
|
}
|
|
88
|
-
// ─── Configuration ──────────────────────────────────────────────
|
|
89
80
|
/** Configure auto-checkpoint behavior */
|
|
90
81
|
setCheckpointConfig(config) {
|
|
91
82
|
this.checkpointConfig = config;
|
|
92
83
|
}
|
|
93
|
-
// ─── Initialization ─────────────────────────────────────────────
|
|
94
84
|
async init() {
|
|
95
85
|
if (this._state?.initialized)
|
|
96
86
|
return this._state;
|
|
@@ -113,7 +103,7 @@ class StateProvider {
|
|
|
113
103
|
initialized: false,
|
|
114
104
|
};
|
|
115
105
|
this._state = state;
|
|
116
|
-
//
|
|
106
|
+
// resolve vault link
|
|
117
107
|
const { getVaultForWallet } = await Promise.resolve().then(() => __importStar(require('torchsdk')));
|
|
118
108
|
try {
|
|
119
109
|
const vault = await getVaultForWallet(this.connection, this.publicKey);
|
|
@@ -134,14 +124,12 @@ class StateProvider {
|
|
|
134
124
|
}
|
|
135
125
|
}
|
|
136
126
|
catch { }
|
|
137
|
-
// Load registry profile — personality, action counts, SOL totals
|
|
138
127
|
try {
|
|
139
128
|
const profile = await this.registry.getProfile(this.publicKey);
|
|
140
129
|
if (profile) {
|
|
141
130
|
state.personalitySummary = profile.personality_summary || null;
|
|
142
131
|
state.totalSolSpent = profile.total_sol_spent;
|
|
143
132
|
state.totalSolReceived = profile.total_sol_received;
|
|
144
|
-
// Seed action counts from on-chain checkpoint
|
|
145
133
|
state.actionCounts.join = Math.max(state.actionCounts.join, profile.joins);
|
|
146
134
|
state.actionCounts.defect = Math.max(state.actionCounts.defect, profile.defects);
|
|
147
135
|
state.actionCounts.rally = Math.max(state.actionCounts.rally, profile.rallies);
|
|
@@ -156,48 +144,39 @@ class StateProvider {
|
|
|
156
144
|
state.actionCounts.ascend = Math.max(state.actionCounts.ascend, profile.ascends);
|
|
157
145
|
state.actionCounts.raze = Math.max(state.actionCounts.raze, profile.razes);
|
|
158
146
|
state.actionCounts.tithe = Math.max(state.actionCounts.tithe, profile.tithes);
|
|
159
|
-
// Set tick to total actions from checkpoint
|
|
160
147
|
const totalFromCheckpoint = Object.values(state.actionCounts).reduce((a, b) => a + b, 0);
|
|
161
148
|
state.tick = totalFromCheckpoint;
|
|
162
149
|
}
|
|
163
150
|
}
|
|
164
151
|
catch { }
|
|
165
|
-
// Load holdings (wallet + vault token accounts)
|
|
166
152
|
await this.refreshHoldings();
|
|
167
153
|
state.initialized = true;
|
|
168
154
|
return state;
|
|
169
155
|
}
|
|
170
|
-
// ─── Action Recording ───────────────────────────────────────────
|
|
171
156
|
async record(action, mint, description) {
|
|
172
157
|
if (!this._state)
|
|
173
158
|
throw new Error('State not initialized — call init() first');
|
|
174
159
|
this._state.tick++;
|
|
175
160
|
this._state.actionCounts[action]++;
|
|
176
161
|
this.ticksSinceCheckpoint++;
|
|
177
|
-
// Track founded factions
|
|
178
162
|
if (action === 'launch' && mint) {
|
|
179
163
|
this._state.founded.push(mint);
|
|
180
164
|
}
|
|
181
|
-
// Update sentiment for the target faction
|
|
182
165
|
if (mint) {
|
|
183
166
|
this.updateSentiment(action, mint);
|
|
184
167
|
}
|
|
185
|
-
// Track recent history for LLM memory block
|
|
186
168
|
if (description) {
|
|
187
169
|
this._state.recentHistory.push(description);
|
|
188
170
|
if (this._state.recentHistory.length > 20) {
|
|
189
171
|
this._state.recentHistory = this._state.recentHistory.slice(-20);
|
|
190
172
|
}
|
|
191
173
|
}
|
|
192
|
-
// Refresh holdings after any trade action
|
|
193
174
|
await this.refreshHoldings();
|
|
194
|
-
// Auto-checkpoint check
|
|
195
175
|
if (this.checkpointConfig && this.ticksSinceCheckpoint >= this.checkpointConfig.interval) {
|
|
196
176
|
this.ticksSinceCheckpoint = 0;
|
|
197
177
|
this.onCheckpointDue?.();
|
|
198
178
|
}
|
|
199
179
|
}
|
|
200
|
-
/** Update sentiment score for a faction based on action type */
|
|
201
180
|
updateSentiment(action, mint) {
|
|
202
181
|
if (!this._state)
|
|
203
182
|
return;
|
|
@@ -218,15 +197,12 @@ class StateProvider {
|
|
|
218
197
|
this._state.sentiment.set(mint, Math.max(-10, Math.min(10, current + delta)));
|
|
219
198
|
}
|
|
220
199
|
}
|
|
221
|
-
/** Callback set by PyreKit to handle checkpoint triggers */
|
|
222
200
|
onCheckpointDue = null;
|
|
223
|
-
// ─── Holdings ───────────────────────────────────────────────────
|
|
224
201
|
async refreshHoldings() {
|
|
225
202
|
if (!this._state)
|
|
226
203
|
return;
|
|
227
204
|
const { TOKEN_2022_PROGRAM_ID } = await Promise.resolve().then(() => __importStar(require('@solana/spl-token')));
|
|
228
205
|
const walletPk = new web3_js_1.PublicKey(this.publicKey);
|
|
229
|
-
// Scan wallet token accounts
|
|
230
206
|
let walletValues = [];
|
|
231
207
|
try {
|
|
232
208
|
const walletAccounts = await this.connection.getParsedTokenAccountsByOwner(walletPk, {
|
|
@@ -235,7 +211,6 @@ class StateProvider {
|
|
|
235
211
|
walletValues = walletAccounts.value;
|
|
236
212
|
}
|
|
237
213
|
catch { }
|
|
238
|
-
// Scan vault token accounts
|
|
239
214
|
let vaultValues = [];
|
|
240
215
|
if (this._state.stronghold) {
|
|
241
216
|
try {
|
|
@@ -247,7 +222,6 @@ class StateProvider {
|
|
|
247
222
|
}
|
|
248
223
|
catch { }
|
|
249
224
|
}
|
|
250
|
-
// Merge balances
|
|
251
225
|
const newHoldings = new Map();
|
|
252
226
|
for (const a of [...walletValues, ...vaultValues]) {
|
|
253
227
|
const mint = a.account.data.parsed.info.mint;
|
|
@@ -256,7 +230,6 @@ class StateProvider {
|
|
|
256
230
|
newHoldings.set(mint, (newHoldings.get(mint) ?? 0) + balance);
|
|
257
231
|
}
|
|
258
232
|
}
|
|
259
|
-
// Update — clear stale, set fresh
|
|
260
233
|
this._state.holdings.clear();
|
|
261
234
|
for (const [mint, balance] of newHoldings) {
|
|
262
235
|
this._state.holdings.set(mint, balance);
|
|
@@ -274,7 +247,6 @@ class StateProvider {
|
|
|
274
247
|
getBalance(mint) {
|
|
275
248
|
return this._state?.holdings.get(mint) ?? 0;
|
|
276
249
|
}
|
|
277
|
-
// ─── Dedup Guards ───────────────────────────────────────────────
|
|
278
250
|
hasVoted(mint) {
|
|
279
251
|
return this._state?.voted.has(mint) ?? false;
|
|
280
252
|
}
|
|
@@ -287,7 +259,6 @@ class StateProvider {
|
|
|
287
259
|
markRallied(mint) {
|
|
288
260
|
this._state?.rallied.add(mint);
|
|
289
261
|
}
|
|
290
|
-
// ─── Serialization ──────────────────────────────────────────────
|
|
291
262
|
serialize() {
|
|
292
263
|
if (!this._state) {
|
|
293
264
|
return {
|
|
@@ -36,6 +36,7 @@ export interface Action {
|
|
|
36
36
|
raze(params: RazeParams): Promise<TransactionResult>;
|
|
37
37
|
repayWarLoan(params: RepayWarLoanParams): Promise<TransactionResult>;
|
|
38
38
|
requestWarLoan(params: RequestWarLoanParams): Promise<TransactionResult>;
|
|
39
|
+
scout(targetAddress: string): Promise<string>;
|
|
39
40
|
siege(params: SiegeParams): Promise<TransactionResult>;
|
|
40
41
|
tithe(params: TitheParams): Promise<TransactionResult>;
|
|
41
42
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CheckpointParams, LinkAgentWalletParams, RegisterAgentParams, RegistryProfile, RegistryWalletLink, TransactionResult, TransferAgentAuthorityParams, UnlinkAgentWalletParams } from '../types';
|
|
2
|
+
export interface Registry {
|
|
3
|
+
getProfile(creator: string): Promise<RegistryProfile | undefined>;
|
|
4
|
+
getWalletLink(wallet: string): Promise<RegistryWalletLink | undefined>;
|
|
5
|
+
register(params: RegisterAgentParams): Promise<TransactionResult>;
|
|
6
|
+
checkpoint(params: CheckpointParams): Promise<TransactionResult>;
|
|
7
|
+
linkWallet(params: LinkAgentWalletParams): Promise<TransactionResult>;
|
|
8
|
+
unlinkWallet(params: UnlinkAgentWalletParams): Promise<TransactionResult>;
|
|
9
|
+
transferAuthority(params: TransferAgentAuthorityParams): Promise<TransactionResult>;
|
|
10
|
+
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -192,6 +192,7 @@ kit.actions.getMembers(mint) // top holders
|
|
|
192
192
|
kit.actions.getComms(mint, opts) // trade-bundled messages
|
|
193
193
|
kit.actions.getJoinQuote(mint, sol) // buy price quote
|
|
194
194
|
kit.actions.getDefectQuote(mint, n) // sell price quote
|
|
195
|
+
kit.actions.scout(address) // look up agent's on-chain identity (read-only)
|
|
195
196
|
```
|
|
196
197
|
|
|
197
198
|
### StateProvider
|
|
@@ -260,6 +261,8 @@ score = (market_cap_sol * 0.4) + (members * 0.2) + (war_chest_sol * 0.2)
|
|
|
260
261
|
|
|
261
262
|
## Tests
|
|
262
263
|
|
|
264
|
+
46/46 passing tests.
|
|
265
|
+
|
|
263
266
|
Requires [surfpool](https://github.com/txtx/surfpool) running a local Solana fork:
|
|
264
267
|
|
|
265
268
|
```bash
|
package/src/index.ts
CHANGED
|
@@ -7,26 +7,30 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { Connection } from '@solana/web3.js'
|
|
10
|
+
|
|
11
|
+
import { Action } from './types/action.types'
|
|
12
|
+
import { Intel } from './types/intel.types'
|
|
13
|
+
import { Registry } from './types/registry.types'
|
|
14
|
+
|
|
10
15
|
import { ActionProvider } from './providers/action.provider'
|
|
11
16
|
import { IntelProvider } from './providers/intel.provider'
|
|
12
17
|
import { RegistryProvider } from './providers/registry.provider'
|
|
13
18
|
import { StateProvider } from './providers/state.provider'
|
|
14
|
-
|
|
15
|
-
import type {
|
|
16
|
-
import type { State, CheckpointConfig, TrackedAction } from './types/state.types'
|
|
19
|
+
|
|
20
|
+
import type { CheckpointConfig, TrackedAction } from './types/state.types'
|
|
17
21
|
|
|
18
22
|
// ─── Top-level Kit ────────────────────────────────────────────────
|
|
19
23
|
|
|
20
24
|
export class PyreKit {
|
|
21
|
-
readonly actions:
|
|
22
|
-
readonly intel:
|
|
23
|
-
readonly registry:
|
|
25
|
+
readonly actions: Action
|
|
26
|
+
readonly intel: Intel
|
|
27
|
+
readonly registry: Registry
|
|
24
28
|
readonly state: StateProvider
|
|
25
29
|
|
|
26
30
|
constructor(connection: Connection, publicKey: string) {
|
|
27
31
|
this.registry = new RegistryProvider(connection)
|
|
28
|
-
this.state = new StateProvider(connection,
|
|
29
|
-
this.actions = new ActionProvider(connection)
|
|
32
|
+
this.state = new StateProvider(connection, this.registry, publicKey)
|
|
33
|
+
this.actions = new ActionProvider(connection, this.registry)
|
|
30
34
|
this.intel = new IntelProvider(connection, this.actions)
|
|
31
35
|
|
|
32
36
|
// Wire auto-checkpoint callback
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Connection, GetProgramAccountsFilter, PublicKey } from '@solana/web3.js'
|
|
2
|
-
import { Action } from '../types/action.types'
|
|
3
2
|
import {
|
|
4
3
|
buildBorrowTransaction,
|
|
5
4
|
buildBuyTransaction,
|
|
@@ -37,6 +36,16 @@ import {
|
|
|
37
36
|
SellQuoteResult,
|
|
38
37
|
TransactionResult,
|
|
39
38
|
} from 'torchsdk'
|
|
39
|
+
|
|
40
|
+
import { MapperProvider } from './mapper.provider'
|
|
41
|
+
import {
|
|
42
|
+
buildCreateFactionTransaction,
|
|
43
|
+
getBondingCurvePda,
|
|
44
|
+
getTokenTreasuryPda,
|
|
45
|
+
getTreasuryLockPda,
|
|
46
|
+
isPyreMint,
|
|
47
|
+
} from '../vanity'
|
|
48
|
+
import { isBlacklistedMint } from '../util'
|
|
40
49
|
import {
|
|
41
50
|
AgentLink,
|
|
42
51
|
AllWarLoansResult,
|
|
@@ -74,19 +83,15 @@ import {
|
|
|
74
83
|
WithdrawAssetsParams,
|
|
75
84
|
WithdrawFromStrongholdParams,
|
|
76
85
|
} from '../types'
|
|
77
|
-
import {
|
|
78
|
-
import {
|
|
79
|
-
buildCreateFactionTransaction,
|
|
80
|
-
getBondingCurvePda,
|
|
81
|
-
getTokenTreasuryPda,
|
|
82
|
-
getTreasuryLockPda,
|
|
83
|
-
isPyreMint,
|
|
84
|
-
} from '../vanity'
|
|
85
|
-
import { isBlacklistedMint } from '../util'
|
|
86
|
+
import { Action } from '../types/action.types'
|
|
87
|
+
import { Registry } from '../types/registry.types'
|
|
86
88
|
|
|
87
89
|
export class ActionProvider implements Action {
|
|
88
90
|
private mapper = new MapperProvider()
|
|
89
|
-
constructor(
|
|
91
|
+
constructor(
|
|
92
|
+
private connection: Connection,
|
|
93
|
+
private registryProvider: Registry,
|
|
94
|
+
) {}
|
|
90
95
|
|
|
91
96
|
async createStronghold(params: CreateStrongholdParams): Promise<TransactionResult> {
|
|
92
97
|
return buildCreateVaultTransaction(this.connection, { creator: params.creator })
|
|
@@ -422,6 +427,61 @@ export class ActionProvider implements Action {
|
|
|
422
427
|
})
|
|
423
428
|
}
|
|
424
429
|
|
|
430
|
+
async scout(targetAddress: string): Promise<string> {
|
|
431
|
+
try {
|
|
432
|
+
const p = await this.registryProvider.getProfile(targetAddress)
|
|
433
|
+
if (!p) return ` @${targetAddress.slice(0, 8)}: no pyre identity found`
|
|
434
|
+
|
|
435
|
+
const total =
|
|
436
|
+
p.joins +
|
|
437
|
+
p.defects +
|
|
438
|
+
p.rallies +
|
|
439
|
+
p.launches +
|
|
440
|
+
p.messages +
|
|
441
|
+
p.fuds +
|
|
442
|
+
p.infiltrates +
|
|
443
|
+
p.reinforces +
|
|
444
|
+
p.war_loans +
|
|
445
|
+
p.repay_loans +
|
|
446
|
+
p.sieges +
|
|
447
|
+
p.ascends +
|
|
448
|
+
p.razes +
|
|
449
|
+
p.tithes
|
|
450
|
+
|
|
451
|
+
const topActions = [
|
|
452
|
+
{ n: 'joins', v: p.joins },
|
|
453
|
+
{ n: 'defects', v: p.defects },
|
|
454
|
+
{ n: 'rallies', v: p.rallies },
|
|
455
|
+
{ n: 'messages', v: p.messages },
|
|
456
|
+
{ n: 'fuds', v: p.fuds },
|
|
457
|
+
{ n: 'infiltrates', v: p.infiltrates },
|
|
458
|
+
{ n: 'reinforces', v: p.reinforces },
|
|
459
|
+
{ n: 'war_loans', v: p.war_loans },
|
|
460
|
+
{ n: 'sieges', v: p.sieges },
|
|
461
|
+
]
|
|
462
|
+
.sort((a, b) => b.v - a.v)
|
|
463
|
+
.filter((a) => a.v > 0)
|
|
464
|
+
.slice(0, 4)
|
|
465
|
+
.map((a) => `${a.n}:${a.v}`)
|
|
466
|
+
.join(', ')
|
|
467
|
+
|
|
468
|
+
const personality = p.personality_summary || 'unknown'
|
|
469
|
+
const checkpoint =
|
|
470
|
+
p.last_checkpoint > 0
|
|
471
|
+
? new Date(p.last_checkpoint * 1000).toISOString().slice(0, 10)
|
|
472
|
+
: 'never'
|
|
473
|
+
|
|
474
|
+
const spent = (p.total_sol_spent ?? 0) / 1e9
|
|
475
|
+
const received = (p.total_sol_received ?? 0) / 1e9
|
|
476
|
+
const pnl = received - spent
|
|
477
|
+
const pnlStr = pnl >= 0 ? `+${pnl.toFixed(3)}` : pnl.toFixed(3)
|
|
478
|
+
|
|
479
|
+
return ` @${targetAddress.slice(0, 8)}: "${personality}" | ${total} actions (${topActions}) | P&L: ${pnlStr} SOL | last seen: ${checkpoint}`
|
|
480
|
+
} catch {
|
|
481
|
+
return ` @${targetAddress.slice(0, 8)}: lookup failed`
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
425
485
|
async siege(params: SiegeParams): Promise<TransactionResult> {
|
|
426
486
|
return buildLiquidateTransaction(this.connection, {
|
|
427
487
|
mint: params.mint,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Connection, PublicKey } from '@solana/web3.js'
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import { getBondingCurvePda, getTokenTreasuryPda, getTreasuryLockPda, isPyreMint } from '../vanity'
|
|
4
|
+
import { isBlacklistedMint } from '../util'
|
|
3
5
|
import {
|
|
4
6
|
AgentFactionPosition,
|
|
5
7
|
AgentProfile,
|
|
@@ -13,8 +15,6 @@ import {
|
|
|
13
15
|
RivalFaction,
|
|
14
16
|
} from '../types'
|
|
15
17
|
import { Intel } from '../types/intel.types'
|
|
16
|
-
import { getBondingCurvePda, getTokenTreasuryPda, getTreasuryLockPda, isPyreMint } from '../vanity'
|
|
17
|
-
import { isBlacklistedMint } from '../util'
|
|
18
18
|
import { Action } from '../types/action.types'
|
|
19
19
|
|
|
20
20
|
export class IntelProvider implements Intel {
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pyre World Agent Registry Provider
|
|
3
|
-
*
|
|
4
|
-
* On-chain agent identity and state persistence.
|
|
5
|
-
* Agents checkpoint their action distributions and personality summaries
|
|
6
|
-
* so any machine with the wallet key can reconstruct the agent.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { Connection, PublicKey, Transaction, SystemProgram } from '@solana/web3.js'
|
|
10
2
|
import { BN, Program, AnchorProvider, type Wallet } from '@coral-xyz/anchor'
|
|
11
3
|
import type { TransactionResult } from 'torchsdk'
|
|
4
|
+
|
|
12
5
|
import type {
|
|
13
6
|
RegistryProfile,
|
|
14
7
|
RegistryWalletLink,
|
|
@@ -18,20 +11,14 @@ import type {
|
|
|
18
11
|
UnlinkAgentWalletParams,
|
|
19
12
|
TransferAgentAuthorityParams,
|
|
20
13
|
} from '../types'
|
|
14
|
+
import { Registry } from '../types/registry.types'
|
|
21
15
|
|
|
22
16
|
import idl from '../pyre_world.json'
|
|
23
17
|
|
|
24
|
-
// ─── Program ID ─────────────────────────────────────────────────────
|
|
25
|
-
|
|
26
18
|
export const REGISTRY_PROGRAM_ID = new PublicKey(idl.address)
|
|
27
|
-
|
|
28
|
-
// ─── PDA Seeds ──────────────────────────────────────────────────────
|
|
29
|
-
|
|
30
19
|
const AGENT_SEED = 'pyre_agent'
|
|
31
20
|
const AGENT_WALLET_SEED = 'pyre_agent_wallet'
|
|
32
21
|
|
|
33
|
-
// ─── PDA Helpers ────────────────────────────────────────────────────
|
|
34
|
-
|
|
35
22
|
export function getAgentProfilePda(creator: PublicKey): [PublicKey, number] {
|
|
36
23
|
return PublicKey.findProgramAddressSync(
|
|
37
24
|
[Buffer.from(AGENT_SEED), creator.toBuffer()],
|
|
@@ -46,8 +33,6 @@ export function getAgentWalletLinkPda(wallet: PublicKey): [PublicKey, number] {
|
|
|
46
33
|
)
|
|
47
34
|
}
|
|
48
35
|
|
|
49
|
-
// ─── Anchor Program Helper ──────────────────────────────────────────
|
|
50
|
-
|
|
51
36
|
function makeDummyProvider(connection: Connection, payer: PublicKey): AnchorProvider {
|
|
52
37
|
const dummyWallet = {
|
|
53
38
|
publicKey: payer,
|
|
@@ -67,9 +52,7 @@ async function finalizeTransaction(
|
|
|
67
52
|
tx.feePayer = feePayer
|
|
68
53
|
}
|
|
69
54
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
export class RegistryProvider {
|
|
55
|
+
export class RegistryProvider implements Registry {
|
|
73
56
|
constructor(private connection: Connection) {}
|
|
74
57
|
|
|
75
58
|
private getProgram(payer: PublicKey): Program {
|
|
@@ -77,9 +60,7 @@ export class RegistryProvider {
|
|
|
77
60
|
return new Program(idl as any, provider)
|
|
78
61
|
}
|
|
79
62
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
async getProfile(creator: string): Promise<RegistryProfile | null> {
|
|
63
|
+
async getProfile(creator: string): Promise<RegistryProfile | undefined> {
|
|
83
64
|
const creatorPk = new PublicKey(creator)
|
|
84
65
|
const [profilePda] = getAgentProfilePda(creatorPk)
|
|
85
66
|
const program = this.getProgram(creatorPk)
|
|
@@ -113,11 +94,11 @@ export class RegistryProvider {
|
|
|
113
94
|
total_sol_received: account.totalSolReceived?.toNumber() ?? 0,
|
|
114
95
|
}
|
|
115
96
|
} catch {
|
|
116
|
-
return
|
|
97
|
+
return undefined
|
|
117
98
|
}
|
|
118
99
|
}
|
|
119
100
|
|
|
120
|
-
async getWalletLink(wallet: string): Promise<RegistryWalletLink |
|
|
101
|
+
async getWalletLink(wallet: string): Promise<RegistryWalletLink | undefined> {
|
|
121
102
|
const walletPk = new PublicKey(wallet)
|
|
122
103
|
const [linkPda] = getAgentWalletLinkPda(walletPk)
|
|
123
104
|
const program = this.getProgram(walletPk)
|
|
@@ -132,12 +113,10 @@ export class RegistryProvider {
|
|
|
132
113
|
bump: account.bump,
|
|
133
114
|
}
|
|
134
115
|
} catch {
|
|
135
|
-
return
|
|
116
|
+
return undefined
|
|
136
117
|
}
|
|
137
118
|
}
|
|
138
119
|
|
|
139
|
-
// ─── Transaction Builders ─────────────────────────────────────────
|
|
140
|
-
|
|
141
120
|
async register(params: RegisterAgentParams): Promise<TransactionResult> {
|
|
142
121
|
const creator = new PublicKey(params.creator)
|
|
143
122
|
const [profile] = getAgentProfilePda(creator)
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pyre Kit State Provider
|
|
3
|
-
*
|
|
4
|
-
* Objective game state tracking for an agent.
|
|
5
|
-
* Owns holdings, action counts, vault resolution, tick counter.
|
|
6
|
-
* Injected into ActionProvider so every action automatically updates state.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { Connection, PublicKey } from '@solana/web3.js'
|
|
2
|
+
|
|
3
|
+
import { isPyreMint } from '../vanity'
|
|
4
|
+
import { isBlacklistedMint } from '../util'
|
|
10
5
|
import type {
|
|
11
6
|
State,
|
|
12
7
|
AgentGameState,
|
|
@@ -14,9 +9,7 @@ import type {
|
|
|
14
9
|
TrackedAction,
|
|
15
10
|
CheckpointConfig,
|
|
16
11
|
} from '../types/state.types'
|
|
17
|
-
import {
|
|
18
|
-
import { isPyreMint } from '../vanity'
|
|
19
|
-
import { isBlacklistedMint } from '../util'
|
|
12
|
+
import { Registry } from '../types/registry.types'
|
|
20
13
|
|
|
21
14
|
const EMPTY_COUNTS: Record<TrackedAction, number> = {
|
|
22
15
|
join: 0,
|
|
@@ -42,12 +35,10 @@ export class StateProvider implements State {
|
|
|
42
35
|
|
|
43
36
|
constructor(
|
|
44
37
|
private connection: Connection,
|
|
38
|
+
private registry: Registry,
|
|
45
39
|
private publicKey: string,
|
|
46
|
-
private registry: RegistryProvider,
|
|
47
40
|
) {}
|
|
48
41
|
|
|
49
|
-
// ─── Readonly accessors ─────────────────────────────────────────
|
|
50
|
-
|
|
51
42
|
get state() {
|
|
52
43
|
return this._state
|
|
53
44
|
}
|
|
@@ -61,15 +52,11 @@ export class StateProvider implements State {
|
|
|
61
52
|
return this._state?.tick ?? 0
|
|
62
53
|
}
|
|
63
54
|
|
|
64
|
-
// ─── Configuration ──────────────────────────────────────────────
|
|
65
|
-
|
|
66
55
|
/** Configure auto-checkpoint behavior */
|
|
67
56
|
setCheckpointConfig(config: CheckpointConfig) {
|
|
68
57
|
this.checkpointConfig = config
|
|
69
58
|
}
|
|
70
59
|
|
|
71
|
-
// ─── Initialization ─────────────────────────────────────────────
|
|
72
|
-
|
|
73
60
|
async init(): Promise<AgentGameState> {
|
|
74
61
|
if (this._state?.initialized) return this._state
|
|
75
62
|
|
|
@@ -94,7 +81,7 @@ export class StateProvider implements State {
|
|
|
94
81
|
|
|
95
82
|
this._state = state
|
|
96
83
|
|
|
97
|
-
//
|
|
84
|
+
// resolve vault link
|
|
98
85
|
const { getVaultForWallet } = await import('torchsdk')
|
|
99
86
|
try {
|
|
100
87
|
const vault = await getVaultForWallet(this.connection, this.publicKey)
|
|
@@ -115,14 +102,13 @@ export class StateProvider implements State {
|
|
|
115
102
|
}
|
|
116
103
|
} catch {}
|
|
117
104
|
|
|
118
|
-
// Load registry profile — personality, action counts, SOL totals
|
|
119
105
|
try {
|
|
120
106
|
const profile = await this.registry.getProfile(this.publicKey)
|
|
121
107
|
if (profile) {
|
|
122
108
|
state.personalitySummary = profile.personality_summary || null
|
|
123
109
|
state.totalSolSpent = profile.total_sol_spent
|
|
124
110
|
state.totalSolReceived = profile.total_sol_received
|
|
125
|
-
|
|
111
|
+
|
|
126
112
|
state.actionCounts.join = Math.max(state.actionCounts.join, profile.joins)
|
|
127
113
|
state.actionCounts.defect = Math.max(state.actionCounts.defect, profile.defects)
|
|
128
114
|
state.actionCounts.rally = Math.max(state.actionCounts.rally, profile.rallies)
|
|
@@ -137,21 +123,17 @@ export class StateProvider implements State {
|
|
|
137
123
|
state.actionCounts.ascend = Math.max(state.actionCounts.ascend, profile.ascends)
|
|
138
124
|
state.actionCounts.raze = Math.max(state.actionCounts.raze, profile.razes)
|
|
139
125
|
state.actionCounts.tithe = Math.max(state.actionCounts.tithe, profile.tithes)
|
|
140
|
-
|
|
126
|
+
|
|
141
127
|
const totalFromCheckpoint = Object.values(state.actionCounts).reduce((a, b) => a + b, 0)
|
|
142
128
|
state.tick = totalFromCheckpoint
|
|
143
129
|
}
|
|
144
130
|
} catch {}
|
|
145
131
|
|
|
146
|
-
// Load holdings (wallet + vault token accounts)
|
|
147
132
|
await this.refreshHoldings()
|
|
148
|
-
|
|
149
133
|
state.initialized = true
|
|
150
134
|
return state
|
|
151
135
|
}
|
|
152
136
|
|
|
153
|
-
// ─── Action Recording ───────────────────────────────────────────
|
|
154
|
-
|
|
155
137
|
async record(action: TrackedAction, mint?: string, description?: string): Promise<void> {
|
|
156
138
|
if (!this._state) throw new Error('State not initialized — call init() first')
|
|
157
139
|
|
|
@@ -159,17 +141,14 @@ export class StateProvider implements State {
|
|
|
159
141
|
this._state.actionCounts[action]++
|
|
160
142
|
this.ticksSinceCheckpoint++
|
|
161
143
|
|
|
162
|
-
// Track founded factions
|
|
163
144
|
if (action === 'launch' && mint) {
|
|
164
145
|
this._state.founded.push(mint)
|
|
165
146
|
}
|
|
166
147
|
|
|
167
|
-
// Update sentiment for the target faction
|
|
168
148
|
if (mint) {
|
|
169
149
|
this.updateSentiment(action, mint)
|
|
170
150
|
}
|
|
171
151
|
|
|
172
|
-
// Track recent history for LLM memory block
|
|
173
152
|
if (description) {
|
|
174
153
|
this._state.recentHistory.push(description)
|
|
175
154
|
if (this._state.recentHistory.length > 20) {
|
|
@@ -177,22 +156,16 @@ export class StateProvider implements State {
|
|
|
177
156
|
}
|
|
178
157
|
}
|
|
179
158
|
|
|
180
|
-
// Refresh holdings after any trade action
|
|
181
159
|
await this.refreshHoldings()
|
|
182
|
-
|
|
183
|
-
// Auto-checkpoint check
|
|
184
160
|
if (this.checkpointConfig && this.ticksSinceCheckpoint >= this.checkpointConfig.interval) {
|
|
185
161
|
this.ticksSinceCheckpoint = 0
|
|
186
162
|
this.onCheckpointDue?.()
|
|
187
163
|
}
|
|
188
164
|
}
|
|
189
165
|
|
|
190
|
-
/** Update sentiment score for a faction based on action type */
|
|
191
166
|
private updateSentiment(action: TrackedAction, mint: string): void {
|
|
192
167
|
if (!this._state) return
|
|
193
|
-
|
|
194
168
|
const current = this._state.sentiment.get(mint) ?? 0
|
|
195
|
-
|
|
196
169
|
const SENTIMENT_DELTAS: Partial<Record<TrackedAction, number>> = {
|
|
197
170
|
join: 1,
|
|
198
171
|
reinforce: 1.5,
|
|
@@ -211,18 +184,14 @@ export class StateProvider implements State {
|
|
|
211
184
|
}
|
|
212
185
|
}
|
|
213
186
|
|
|
214
|
-
/** Callback set by PyreKit to handle checkpoint triggers */
|
|
215
187
|
onCheckpointDue: (() => void) | null = null
|
|
216
188
|
|
|
217
|
-
// ─── Holdings ───────────────────────────────────────────────────
|
|
218
|
-
|
|
219
189
|
async refreshHoldings(): Promise<void> {
|
|
220
190
|
if (!this._state) return
|
|
221
191
|
|
|
222
192
|
const { TOKEN_2022_PROGRAM_ID } = await import('@solana/spl-token')
|
|
223
193
|
const walletPk = new PublicKey(this.publicKey)
|
|
224
194
|
|
|
225
|
-
// Scan wallet token accounts
|
|
226
195
|
let walletValues: any[] = []
|
|
227
196
|
try {
|
|
228
197
|
const walletAccounts = await this.connection.getParsedTokenAccountsByOwner(walletPk, {
|
|
@@ -231,7 +200,6 @@ export class StateProvider implements State {
|
|
|
231
200
|
walletValues = walletAccounts.value
|
|
232
201
|
} catch {}
|
|
233
202
|
|
|
234
|
-
// Scan vault token accounts
|
|
235
203
|
let vaultValues: any[] = []
|
|
236
204
|
if (this._state.stronghold) {
|
|
237
205
|
try {
|
|
@@ -243,7 +211,6 @@ export class StateProvider implements State {
|
|
|
243
211
|
} catch {}
|
|
244
212
|
}
|
|
245
213
|
|
|
246
|
-
// Merge balances
|
|
247
214
|
const newHoldings = new Map<string, number>()
|
|
248
215
|
for (const a of [...walletValues, ...vaultValues]) {
|
|
249
216
|
const mint = a.account.data.parsed.info.mint as string
|
|
@@ -253,7 +220,6 @@ export class StateProvider implements State {
|
|
|
253
220
|
}
|
|
254
221
|
}
|
|
255
222
|
|
|
256
|
-
// Update — clear stale, set fresh
|
|
257
223
|
this._state.holdings.clear()
|
|
258
224
|
for (const [mint, balance] of newHoldings) {
|
|
259
225
|
this._state.holdings.set(mint, balance)
|
|
@@ -276,8 +242,6 @@ export class StateProvider implements State {
|
|
|
276
242
|
return this._state?.holdings.get(mint) ?? 0
|
|
277
243
|
}
|
|
278
244
|
|
|
279
|
-
// ─── Dedup Guards ───────────────────────────────────────────────
|
|
280
|
-
|
|
281
245
|
hasVoted(mint: string): boolean {
|
|
282
246
|
return this._state?.voted.has(mint) ?? false
|
|
283
247
|
}
|
|
@@ -294,8 +258,6 @@ export class StateProvider implements State {
|
|
|
294
258
|
this._state?.rallied.add(mint)
|
|
295
259
|
}
|
|
296
260
|
|
|
297
|
-
// ─── Serialization ──────────────────────────────────────────────
|
|
298
|
-
|
|
299
261
|
serialize(): SerializedGameState {
|
|
300
262
|
if (!this._state) {
|
|
301
263
|
return {
|
|
@@ -71,6 +71,7 @@ export interface Action {
|
|
|
71
71
|
raze(params: RazeParams): Promise<TransactionResult>
|
|
72
72
|
repayWarLoan(params: RepayWarLoanParams): Promise<TransactionResult>
|
|
73
73
|
requestWarLoan(params: RequestWarLoanParams): Promise<TransactionResult>
|
|
74
|
+
scout(targetAddress: string): Promise<string>
|
|
74
75
|
siege(params: SiegeParams): Promise<TransactionResult>
|
|
75
76
|
tithe(params: TitheParams): Promise<TransactionResult>
|
|
76
77
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CheckpointParams,
|
|
3
|
+
LinkAgentWalletParams,
|
|
4
|
+
RegisterAgentParams,
|
|
5
|
+
RegistryProfile,
|
|
6
|
+
RegistryWalletLink,
|
|
7
|
+
TransactionResult,
|
|
8
|
+
TransferAgentAuthorityParams,
|
|
9
|
+
UnlinkAgentWalletParams,
|
|
10
|
+
} from '../types'
|
|
11
|
+
|
|
12
|
+
export interface Registry {
|
|
13
|
+
getProfile(creator: string): Promise<RegistryProfile | undefined>
|
|
14
|
+
getWalletLink(wallet: string): Promise<RegistryWalletLink | undefined>
|
|
15
|
+
|
|
16
|
+
register(params: RegisterAgentParams): Promise<TransactionResult>
|
|
17
|
+
checkpoint(params: CheckpointParams): Promise<TransactionResult>
|
|
18
|
+
linkWallet(params: LinkAgentWalletParams): Promise<TransactionResult>
|
|
19
|
+
unlinkWallet(params: UnlinkAgentWalletParams): Promise<TransactionResult>
|
|
20
|
+
transferAuthority(params: TransferAgentAuthorityParams): Promise<TransactionResult>
|
|
21
|
+
}
|
package/tests/test_e2e.ts
CHANGED
|
@@ -345,6 +345,28 @@ async function main() {
|
|
|
345
345
|
assert(kitRestored.state.state!.actionCounts.defect === kit.state.state!.actionCounts.defect, `hydrated defect count matches`)
|
|
346
346
|
assert(kitRestored.state.history.length === kit.state.history.length, `hydrated history length matches: ${kitRestored.state.history.length}`)
|
|
347
347
|
|
|
348
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
349
|
+
// TEST: SCOUT
|
|
350
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
351
|
+
|
|
352
|
+
console.log('\n═══ TEST: Scout ═══')
|
|
353
|
+
// Scout agent 1 from agent 2's perspective
|
|
354
|
+
const scoutResult = await kit2.actions.scout(agent.publicKey)
|
|
355
|
+
console.log(` ${scoutResult}`)
|
|
356
|
+
assert(typeof scoutResult === 'string', `scout returns string`)
|
|
357
|
+
assert(scoutResult.includes(agent.publicKey.slice(0, 8)), `scout result contains target address: ${agent.publicKey.slice(0, 8)}`)
|
|
358
|
+
|
|
359
|
+
// Scout a nonexistent address
|
|
360
|
+
const fakeAddress = 'FakeAddress1111111111111111111111111111111111'
|
|
361
|
+
const scoutFake = await kit2.actions.scout(fakeAddress)
|
|
362
|
+
console.log(` ${scoutFake}`)
|
|
363
|
+
assert(scoutFake.includes('no pyre identity') || scoutFake.includes('lookup failed'), `scout handles unknown agent`)
|
|
364
|
+
|
|
365
|
+
// Scout via exec (read-only — no tick increment)
|
|
366
|
+
const { result: scoutExecResult } = await kit2.exec('actions', 'scout', agent.publicKey)
|
|
367
|
+
console.log(` exec scout: ${scoutExecResult}`)
|
|
368
|
+
assert(kit2.state.tick === 2, `agent 2 tick unchanged after scout (read-only): ${kit2.state.tick}`)
|
|
369
|
+
|
|
348
370
|
// ═══════════════════════════════════════════════════════════════════
|
|
349
371
|
// TEST: MEMBERS
|
|
350
372
|
// ═══════════════════════════════════════════════════════════════════
|