@microslop/ping-directory-sdk 0.1.5
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.
Potentially problematic release.
This version of @microslop/ping-directory-sdk might be problematic. Click here for more details.
- package/LICENSE +201 -0
- package/README.md +152 -0
- package/package.json +51 -0
- package/src/PingDirectory.js +1110 -0
- package/src/constants.js +103 -0
- package/src/deserialize.js +322 -0
- package/src/disc.js +76 -0
- package/src/encoding.js +130 -0
- package/src/fees.js +102 -0
- package/src/format.js +149 -0
- package/src/identicon.js +364 -0
- package/src/index.js +58 -0
- package/src/ix/admin.js +351 -0
- package/src/ix/identity.js +418 -0
- package/src/ix/index.js +10 -0
- package/src/ix/lock.js +63 -0
- package/src/ix/marketplace.js +198 -0
- package/src/ix/photo.js +173 -0
- package/src/ix/pro.js +91 -0
- package/src/ix/revoke.js +41 -0
- package/src/ix/shop.js +322 -0
- package/src/pda.js +75 -0
- package/src/wallet.js +189 -0
package/src/ix/admin.js
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// Admin / config / owner / blocklist / pause / treasury.
|
|
2
|
+
|
|
3
|
+
import { TransactionInstruction, SystemProgram, PublicKey } from '@solana/web3.js';
|
|
4
|
+
import { PROGRAM_ID } from '../constants.js';
|
|
5
|
+
import { borshString, u8, u16LE, u64LE, i64LE, concat, pkBytes } from '../encoding.js';
|
|
6
|
+
import { ixDisc } from '../disc.js';
|
|
7
|
+
import {
|
|
8
|
+
findConfigPDA, findAdminPDA, findBlocklistPDA, findGracePeriodPDA, findUsernamePDA,
|
|
9
|
+
findEd25519AccountPDA, findUidMapPDA, findUserIndexPDA, findSaleListingPDA,
|
|
10
|
+
findInventoryPDA, findProfilePhotoPDA, findReferralBalancePDA,
|
|
11
|
+
findTreasuryWalletPDA,
|
|
12
|
+
} from '../pda.js';
|
|
13
|
+
|
|
14
|
+
const k = (pubkey, isSigner, isWritable) => ({ pubkey, isSigner, isWritable });
|
|
15
|
+
|
|
16
|
+
// ── initialize ──────────────────────────────────────────────────────
|
|
17
|
+
export function initialize({ payer }) {
|
|
18
|
+
const data = ixDisc('initialize');
|
|
19
|
+
const [configPda] = findConfigPDA();
|
|
20
|
+
const ix = new TransactionInstruction({
|
|
21
|
+
programId: PROGRAM_ID,
|
|
22
|
+
keys: [
|
|
23
|
+
k(configPda, false, true),
|
|
24
|
+
k(payer.publicKey, true, true),
|
|
25
|
+
k(SystemProgram.programId, false, false),
|
|
26
|
+
],
|
|
27
|
+
data,
|
|
28
|
+
});
|
|
29
|
+
return { instructions: [ix], signers: [payer] };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ── add_admin (owner-only) ──────────────────────────────────────────
|
|
33
|
+
export function addAdmin({ adminPubkey, owner }) {
|
|
34
|
+
const data = concat(ixDisc('add_admin'), pkBytes(adminPubkey));
|
|
35
|
+
const [configPda] = findConfigPDA();
|
|
36
|
+
const [adminPda] = findAdminPDA(adminPubkey);
|
|
37
|
+
const ix = new TransactionInstruction({
|
|
38
|
+
programId: PROGRAM_ID,
|
|
39
|
+
keys: [
|
|
40
|
+
k(configPda, false, false),
|
|
41
|
+
k(adminPda, false, true),
|
|
42
|
+
k(owner.publicKey, true, true),
|
|
43
|
+
k(SystemProgram.programId, false, false),
|
|
44
|
+
],
|
|
45
|
+
data,
|
|
46
|
+
});
|
|
47
|
+
return { instructions: [ix], signers: [owner] };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function removeAdmin({ adminPubkey, owner }) {
|
|
51
|
+
const data = concat(ixDisc('remove_admin'), pkBytes(adminPubkey));
|
|
52
|
+
const [configPda] = findConfigPDA();
|
|
53
|
+
const [adminPda] = findAdminPDA(adminPubkey);
|
|
54
|
+
const ix = new TransactionInstruction({
|
|
55
|
+
programId: PROGRAM_ID,
|
|
56
|
+
keys: [
|
|
57
|
+
k(configPda, false, false),
|
|
58
|
+
k(adminPda, false, true),
|
|
59
|
+
k(owner.publicKey, true, true),
|
|
60
|
+
],
|
|
61
|
+
data,
|
|
62
|
+
});
|
|
63
|
+
return { instructions: [ix], signers: [owner] };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── two-step ownership ──────────────────────────────────────────────
|
|
67
|
+
export function proposeOwner({ newOwner, owner }) {
|
|
68
|
+
const data = concat(ixDisc('propose_owner'), pkBytes(newOwner));
|
|
69
|
+
const [configPda] = findConfigPDA();
|
|
70
|
+
const ix = new TransactionInstruction({
|
|
71
|
+
programId: PROGRAM_ID,
|
|
72
|
+
keys: [
|
|
73
|
+
k(configPda, false, true),
|
|
74
|
+
k(owner.publicKey, true, false),
|
|
75
|
+
],
|
|
76
|
+
data,
|
|
77
|
+
});
|
|
78
|
+
return { instructions: [ix], signers: [owner] };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function acceptOwner({ newOwner }) {
|
|
82
|
+
const data = ixDisc('accept_owner');
|
|
83
|
+
const [configPda] = findConfigPDA();
|
|
84
|
+
const ix = new TransactionInstruction({
|
|
85
|
+
programId: PROGRAM_ID,
|
|
86
|
+
keys: [
|
|
87
|
+
k(configPda, false, true),
|
|
88
|
+
k(newOwner.publicKey, true, false),
|
|
89
|
+
],
|
|
90
|
+
data,
|
|
91
|
+
});
|
|
92
|
+
return { instructions: [ix], signers: [newOwner] };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// `owner` is the on-chain field name. The constraint accepts EITHER
|
|
96
|
+
// the current owner OR the pending owner (LOW-26): standard two-step
|
|
97
|
+
// ownership pattern letting either side abort the proposal.
|
|
98
|
+
export function cancelProposeOwner({ owner, signer }) {
|
|
99
|
+
const s = owner ?? signer;
|
|
100
|
+
const data = ixDisc('cancel_propose_owner');
|
|
101
|
+
const [configPda] = findConfigPDA();
|
|
102
|
+
const ix = new TransactionInstruction({
|
|
103
|
+
programId: PROGRAM_ID,
|
|
104
|
+
keys: [
|
|
105
|
+
k(configPda, false, true),
|
|
106
|
+
k(s.publicKey, true, false),
|
|
107
|
+
],
|
|
108
|
+
data,
|
|
109
|
+
});
|
|
110
|
+
return { instructions: [ix], signers: [s] };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ── config setters (owner-only) ─────────────────────────────────────
|
|
114
|
+
function configSetterIx(name, payload, owner) {
|
|
115
|
+
const data = concat(ixDisc(name), payload);
|
|
116
|
+
const [configPda] = findConfigPDA();
|
|
117
|
+
const ix = new TransactionInstruction({
|
|
118
|
+
programId: PROGRAM_ID,
|
|
119
|
+
keys: [
|
|
120
|
+
k(configPda, false, true),
|
|
121
|
+
k(owner.publicKey, true, false),
|
|
122
|
+
],
|
|
123
|
+
data,
|
|
124
|
+
});
|
|
125
|
+
return { instructions: [ix], signers: [owner] };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export const setRegistrationFee = ({ tier, fee, owner }) => configSetterIx('set_registration_fee', concat(u8(tier), u64LE(fee)), owner);
|
|
129
|
+
export const setProPriceMonthly = ({ price, owner }) => configSetterIx('set_pro_price_monthly', u64LE(price), owner);
|
|
130
|
+
export const setProPriceLifetime= ({ price, owner }) => configSetterIx('set_pro_price_lifetime', u64LE(price), owner);
|
|
131
|
+
export const setSaleFee = ({ feeBps, owner }) => configSetterIx('set_sale_fee', u16LE(feeBps), owner);
|
|
132
|
+
export const setMinSalePrice = ({ price, owner }) => configSetterIx('set_min_sale_price', u64LE(price), owner);
|
|
133
|
+
export const setGracePeriod = ({ duration, owner }) => configSetterIx('set_grace_period', i64LE(duration), owner);
|
|
134
|
+
export const setUnlockDelay = ({ delay, owner }) => configSetterIx('set_unlock_delay', i64LE(delay), owner);
|
|
135
|
+
export const setUnlockWindow = ({ window, owner }) => configSetterIx('set_unlock_window', i64LE(window), owner);
|
|
136
|
+
export const setAutoUnfreezeDelay = ({ delay, owner }) => configSetterIx('set_auto_unfreeze_delay', i64LE(delay), owner);
|
|
137
|
+
// Per-MIME profile-photo fee (lamports). `mime` ∈ {0=jpeg,1=png,2=webp,3=gif};
|
|
138
|
+
// fee capped at Config::MAX_PHOTO_FEE (100 SOL). Charged at init_profile_photo;
|
|
139
|
+
// non-refundable on clear. Lands in Config lamports — sweepable via withdraw_treasury.
|
|
140
|
+
export const setProfilePhotoFee = ({ mime, fee, owner }) => configSetterIx('set_profile_photo_fee', concat(u8(mime), u64LE(fee)), owner);
|
|
141
|
+
|
|
142
|
+
// ── pause (owner OR admin) ──────────────────────────────────────────
|
|
143
|
+
function pauseIx(name, paused, signer, admin) {
|
|
144
|
+
const data = concat(ixDisc(name), u8(paused ? 1 : 0));
|
|
145
|
+
const [configPda] = findConfigPDA();
|
|
146
|
+
const adminPda = admin ? findAdminPDA(admin)[0] : null;
|
|
147
|
+
const ix = new TransactionInstruction({
|
|
148
|
+
programId: PROGRAM_ID,
|
|
149
|
+
keys: [
|
|
150
|
+
k(configPda, false, true),
|
|
151
|
+
k(signer.publicKey, true, false),
|
|
152
|
+
k(adminPda ?? PROGRAM_ID, false, false),
|
|
153
|
+
],
|
|
154
|
+
data,
|
|
155
|
+
});
|
|
156
|
+
return { instructions: [ix], signers: [signer] };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const pauseRegistration = ({ paused, signer, admin = null }) =>
|
|
160
|
+
pauseIx('pause_registration', paused, signer, admin);
|
|
161
|
+
export const pausePro = ({ paused, signer, admin = null }) =>
|
|
162
|
+
pauseIx('pause_pro', paused, signer, admin);
|
|
163
|
+
|
|
164
|
+
// ── blocklist (owner OR admin) ──────────────────────────────────────
|
|
165
|
+
export function blocklistAdd({ username, signer, admin = null, payer }) {
|
|
166
|
+
const p = payer ?? signer; // rent payer defaults to the signing owner/admin
|
|
167
|
+
const data = concat(ixDisc('blocklist_add'), borshString(username));
|
|
168
|
+
const [configPda] = findConfigPDA();
|
|
169
|
+
const [blocklistPda] = findBlocklistPDA(username);
|
|
170
|
+
const [usernamePda] = findUsernamePDA(username);
|
|
171
|
+
const [gracePda] = findGracePeriodPDA(username);
|
|
172
|
+
const adminPda = admin ? findAdminPDA(admin)[0] : null;
|
|
173
|
+
const ix = new TransactionInstruction({
|
|
174
|
+
programId: PROGRAM_ID,
|
|
175
|
+
keys: [
|
|
176
|
+
k(configPda, false, false),
|
|
177
|
+
k(blocklistPda, false, true),
|
|
178
|
+
k(usernamePda, false, false),
|
|
179
|
+
k(gracePda, false, false),
|
|
180
|
+
k(signer.publicKey, true, false),
|
|
181
|
+
k(adminPda ?? PROGRAM_ID, false, false),
|
|
182
|
+
k(p.publicKey, true, true),
|
|
183
|
+
k(SystemProgram.programId, false, false),
|
|
184
|
+
],
|
|
185
|
+
data,
|
|
186
|
+
});
|
|
187
|
+
// signer + payer may be the same wallet
|
|
188
|
+
const signers = signer.publicKey.equals(p.publicKey) ? [signer] : [signer, p];
|
|
189
|
+
return { instructions: [ix], signers };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function blocklistRemove({ username, signer, admin = null }) {
|
|
193
|
+
const data = concat(ixDisc('blocklist_remove'), borshString(username));
|
|
194
|
+
const [configPda] = findConfigPDA();
|
|
195
|
+
const [blocklistPda] = findBlocklistPDA(username);
|
|
196
|
+
const adminPda = admin ? findAdminPDA(admin)[0] : null;
|
|
197
|
+
const ix = new TransactionInstruction({
|
|
198
|
+
programId: PROGRAM_ID,
|
|
199
|
+
keys: [
|
|
200
|
+
k(configPda, false, false),
|
|
201
|
+
k(blocklistPda, false, true),
|
|
202
|
+
k(signer.publicKey, true, true),
|
|
203
|
+
k(adminPda ?? PROGRAM_ID, false, false),
|
|
204
|
+
],
|
|
205
|
+
data,
|
|
206
|
+
});
|
|
207
|
+
return { instructions: [ix], signers: [signer] };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ── auto_unfreeze_username (permissionless time-gated unfreeze) ─────
|
|
211
|
+
//
|
|
212
|
+
// When an ed25519 key is `mark_compromised`'d, every ed25519-gated handler
|
|
213
|
+
// on its bound username refuses to operate (auto-freeze). After
|
|
214
|
+
// `Config.auto_unfreeze_delay` (default 1 year) elapses since the
|
|
215
|
+
// `mark_compromised` call, anyone may call this handler — no owner gate,
|
|
216
|
+
// no ed25519 sig — to flip the frozen username's UsernameAccount state
|
|
217
|
+
// to UNREGISTERED in place (PDA preserved as a permanent slot) and reset
|
|
218
|
+
// every personal field (premium, equipped cosmetics, account_type,
|
|
219
|
+
// referrer) to a fresh-claim baseline. Side PDAs (Inventory, ProfilePhoto,
|
|
220
|
+
// SaleListing) are closed in place if present; their rent goes to the
|
|
221
|
+
// caller. UidMap is closed → caller. UserIndex is tombstoned. The
|
|
222
|
+
// compromised key's `compromised_at` mark is preserved forever.
|
|
223
|
+
//
|
|
224
|
+
// Caller must supply:
|
|
225
|
+
// - `username`: the frozen username to release
|
|
226
|
+
// - `frozenEd25519Pubkey`: the bound (compromised) key — read from
|
|
227
|
+
// `UsernameAccount.ed25519Pubkey` before calling
|
|
228
|
+
// - `userId`: u64/BigInt — read from UidMap before calling
|
|
229
|
+
// - `caller`: signer paying tx + receiving every closed-PDA rent
|
|
230
|
+
//
|
|
231
|
+
// The high-level `PingDirectory.autoUnfreezeUsername` facade resolves
|
|
232
|
+
// `frozenEd25519Pubkey` and `userId` from chain state automatically.
|
|
233
|
+
export function autoUnfreezeUsername({
|
|
234
|
+
username, frozenEd25519Pubkey, userId, caller,
|
|
235
|
+
}) {
|
|
236
|
+
if (frozenEd25519Pubkey == null) {
|
|
237
|
+
throw new Error('autoUnfreezeUsername: frozenEd25519Pubkey required');
|
|
238
|
+
}
|
|
239
|
+
if (userId == null) {
|
|
240
|
+
throw new Error('autoUnfreezeUsername: userId required');
|
|
241
|
+
}
|
|
242
|
+
if (caller == null) {
|
|
243
|
+
throw new Error('autoUnfreezeUsername: caller required');
|
|
244
|
+
}
|
|
245
|
+
const data = concat(ixDisc('auto_unfreeze_username'), borshString(username));
|
|
246
|
+
const [configPda] = findConfigPDA();
|
|
247
|
+
const [usernamePda] = findUsernamePDA(username);
|
|
248
|
+
const [edPda] = findEd25519AccountPDA(frozenEd25519Pubkey);
|
|
249
|
+
const [uidMapPda] = findUidMapPDA(username);
|
|
250
|
+
const [userIdxPda] = findUserIndexPDA(userId);
|
|
251
|
+
const [inventoryPda] = findInventoryPDA(username);
|
|
252
|
+
const [photoPda] = findProfilePhotoPDA(username);
|
|
253
|
+
const [salePda] = findSaleListingPDA(username);
|
|
254
|
+
const ix = new TransactionInstruction({
|
|
255
|
+
programId: PROGRAM_ID,
|
|
256
|
+
keys: [
|
|
257
|
+
k(configPda, false, true),
|
|
258
|
+
k(usernamePda, false, true),
|
|
259
|
+
k(edPda, false, true),
|
|
260
|
+
k(uidMapPda, false, true),
|
|
261
|
+
k(userIdxPda, false, true),
|
|
262
|
+
k(inventoryPda, false, true),
|
|
263
|
+
k(photoPda, false, true),
|
|
264
|
+
k(salePda, false, true),
|
|
265
|
+
k(caller.publicKey, true, true),
|
|
266
|
+
k(SystemProgram.programId, false, false),
|
|
267
|
+
],
|
|
268
|
+
data,
|
|
269
|
+
});
|
|
270
|
+
return { instructions: [ix], signers: [caller] };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ── withdraw_treasury (owner OR treasury wallet) ────────────────────
|
|
274
|
+
// `signer` (alias `owner` for back-compat) sweeps the surplus to itself.
|
|
275
|
+
// Pass `treasuryWalletPda` when the signer is a treasury wallet (Some);
|
|
276
|
+
// omit it for the owner path (None ⇒ program id sentinel). The high-level
|
|
277
|
+
// `PingDirectory.withdrawTreasury` resolves this from chain automatically.
|
|
278
|
+
export function withdrawTreasury({ signer, owner, treasuryWalletPda = null }) {
|
|
279
|
+
const s = signer ?? owner;
|
|
280
|
+
const data = ixDisc('withdraw_treasury');
|
|
281
|
+
const [configPda] = findConfigPDA();
|
|
282
|
+
const ix = new TransactionInstruction({
|
|
283
|
+
programId: PROGRAM_ID,
|
|
284
|
+
keys: [
|
|
285
|
+
k(configPda, false, true),
|
|
286
|
+
k(s.publicKey, true, true),
|
|
287
|
+
k(treasuryWalletPda ?? PROGRAM_ID, false, false),
|
|
288
|
+
],
|
|
289
|
+
data,
|
|
290
|
+
});
|
|
291
|
+
return { instructions: [ix], signers: [s] };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ── add_treasury_wallet / remove_treasury_wallet (owner-only) ───────
|
|
295
|
+
// The owner designates / revokes addresses allowed to withdraw the
|
|
296
|
+
// treasury. Mirrors add_admin / remove_admin.
|
|
297
|
+
export function addTreasuryWallet({ walletPubkey, owner }) {
|
|
298
|
+
const data = concat(ixDisc('add_treasury_wallet'), pkBytes(walletPubkey));
|
|
299
|
+
const [configPda] = findConfigPDA();
|
|
300
|
+
const [twPda] = findTreasuryWalletPDA(walletPubkey);
|
|
301
|
+
const ix = new TransactionInstruction({
|
|
302
|
+
programId: PROGRAM_ID,
|
|
303
|
+
keys: [
|
|
304
|
+
k(configPda, false, false),
|
|
305
|
+
k(twPda, false, true),
|
|
306
|
+
k(owner.publicKey, true, true),
|
|
307
|
+
k(SystemProgram.programId, false, false),
|
|
308
|
+
],
|
|
309
|
+
data,
|
|
310
|
+
});
|
|
311
|
+
return { instructions: [ix], signers: [owner] };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export function removeTreasuryWallet({ walletPubkey, owner }) {
|
|
315
|
+
const data = concat(ixDisc('remove_treasury_wallet'), pkBytes(walletPubkey));
|
|
316
|
+
const [configPda] = findConfigPDA();
|
|
317
|
+
const [twPda] = findTreasuryWalletPDA(walletPubkey);
|
|
318
|
+
const ix = new TransactionInstruction({
|
|
319
|
+
programId: PROGRAM_ID,
|
|
320
|
+
keys: [
|
|
321
|
+
k(configPda, false, false),
|
|
322
|
+
k(twPda, false, true),
|
|
323
|
+
k(owner.publicKey, true, true),
|
|
324
|
+
],
|
|
325
|
+
data,
|
|
326
|
+
});
|
|
327
|
+
return { instructions: [ix], signers: [owner] };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ── admin_close_zero_referral (owner-only) ─────────────────────────
|
|
331
|
+
// One-shot sweep of the dust ReferralBalance PDA at the zero-pubkey
|
|
332
|
+
// seed. Holds ~0.001 SOL rent that no other handler can recover
|
|
333
|
+
// (nobody can sign as `Pubkey::default()`). Reverts if balance != 0.
|
|
334
|
+
// Will fail with `AccountNotInitialized` if the dust PDA was never
|
|
335
|
+
// created (i.e. no no-referrer register / subscribe / shop call has
|
|
336
|
+
// happened yet) — caller can interpret that as "nothing to sweep".
|
|
337
|
+
export function adminCloseZeroReferral({ owner }) {
|
|
338
|
+
const data = ixDisc('admin_close_zero_referral');
|
|
339
|
+
const [configPda] = findConfigPDA();
|
|
340
|
+
const [referralPda] = findReferralBalancePDA(PublicKey.default);
|
|
341
|
+
const ix = new TransactionInstruction({
|
|
342
|
+
programId: PROGRAM_ID,
|
|
343
|
+
keys: [
|
|
344
|
+
k(configPda, false, false),
|
|
345
|
+
k(referralPda, false, true),
|
|
346
|
+
k(owner.publicKey, true, true),
|
|
347
|
+
],
|
|
348
|
+
data,
|
|
349
|
+
});
|
|
350
|
+
return { instructions: [ix], signers: [owner] };
|
|
351
|
+
}
|