@gl-36/sdk 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +81 -2
- package/dist/account.d.ts +35 -0
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +63 -0
- package/dist/account.js.map +1 -0
- package/dist/constants.d.ts +41 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +39 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +77 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions.d.ts +27 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +137 -0
- package/dist/instructions.js.map +1 -0
- package/dist/logs.d.ts +32 -0
- package/dist/logs.d.ts.map +1 -0
- package/dist/logs.js +63 -0
- package/dist/logs.js.map +1 -0
- package/dist/pda.d.ts +3 -0
- package/dist/pda.d.ts.map +1 -0
- package/dist/pda.js +14 -0
- package/dist/pda.js.map +1 -0
- package/dist/price.d.ts +5 -0
- package/dist/price.d.ts.map +1 -0
- package/dist/price.js +38 -0
- package/dist/price.js.map +1 -0
- package/dist/rpc.d.ts +26 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +70 -0
- package/dist/rpc.js.map +1 -0
- package/dist/seed.d.ts +9 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +18 -0
- package/dist/seed.js.map +1 -0
- package/package.json +56 -4
- package/src/account.ts +109 -0
- package/src/constants.ts +50 -0
- package/src/errors.ts +89 -0
- package/src/index.ts +9 -0
- package/src/instructions.ts +186 -0
- package/src/logs.ts +77 -0
- package/src/pda.ts +14 -0
- package/src/price.ts +39 -0
- package/src/rpc.ts +127 -0
- package/src/seed.ts +30 -0
package/dist/logs.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Address } from "@solana/kit";
|
|
2
|
+
export type Gl36Event = {
|
|
3
|
+
type: "init";
|
|
4
|
+
maxSupply: number;
|
|
5
|
+
} | {
|
|
6
|
+
type: "mint";
|
|
7
|
+
firstId: number;
|
|
8
|
+
count: number;
|
|
9
|
+
} | {
|
|
10
|
+
type: "transfer";
|
|
11
|
+
id: number;
|
|
12
|
+
} | {
|
|
13
|
+
type: "list";
|
|
14
|
+
id: number;
|
|
15
|
+
price: number;
|
|
16
|
+
} | {
|
|
17
|
+
type: "buy";
|
|
18
|
+
id: number;
|
|
19
|
+
price: number;
|
|
20
|
+
} | {
|
|
21
|
+
type: "close";
|
|
22
|
+
minted: number;
|
|
23
|
+
} | {
|
|
24
|
+
type: "settle";
|
|
25
|
+
} | {
|
|
26
|
+
type: "rearm";
|
|
27
|
+
} | {
|
|
28
|
+
type: "withdraw";
|
|
29
|
+
lamports: bigint;
|
|
30
|
+
};
|
|
31
|
+
export declare function parseLogs(logs: readonly string[], programId: Address): Gl36Event[];
|
|
32
|
+
//# sourceMappingURL=logs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AA+C3C,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,SAAS,EAAE,CAkBlF"}
|
package/dist/logs.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const INVOKE = /^Program (\w+) invoke \[\d+\]$/;
|
|
2
|
+
const EXIT = /^Program (\w+) (success|failed)/;
|
|
3
|
+
const LOG = "Program log: ";
|
|
4
|
+
const ints = (parts, n) => parts.length === n && parts.every((p) => /^\d+$/.test(p)) ? parts.map(Number) : null;
|
|
5
|
+
function parseEvent(message) {
|
|
6
|
+
const [kind, ...rest] = message.trim().split(/\s+/);
|
|
7
|
+
switch (kind) {
|
|
8
|
+
case "init": {
|
|
9
|
+
const v = ints(rest, 1);
|
|
10
|
+
return v && { type: "init", maxSupply: v[0] };
|
|
11
|
+
}
|
|
12
|
+
case "mint": {
|
|
13
|
+
const v = ints(rest, 2);
|
|
14
|
+
return v && { type: "mint", firstId: v[0], count: v[1] };
|
|
15
|
+
}
|
|
16
|
+
case "xfer": {
|
|
17
|
+
const v = ints(rest, 1);
|
|
18
|
+
return v && { type: "transfer", id: v[0] };
|
|
19
|
+
}
|
|
20
|
+
case "list": {
|
|
21
|
+
const v = ints(rest, 2);
|
|
22
|
+
return v && { type: "list", id: v[0], price: v[1] };
|
|
23
|
+
}
|
|
24
|
+
case "buy": {
|
|
25
|
+
const v = ints(rest, 2);
|
|
26
|
+
return v && { type: "buy", id: v[0], price: v[1] };
|
|
27
|
+
}
|
|
28
|
+
case "close": {
|
|
29
|
+
const v = ints(rest, 1);
|
|
30
|
+
return v && { type: "close", minted: v[0] };
|
|
31
|
+
}
|
|
32
|
+
case "settle":
|
|
33
|
+
return rest.length === 0 ? { type: "settle" } : null;
|
|
34
|
+
case "rearm":
|
|
35
|
+
return rest.length === 0 ? { type: "rearm" } : null;
|
|
36
|
+
case "withdraw":
|
|
37
|
+
return rest.length === 1 && /^\d+$/.test(rest[0]) ? { type: "withdraw", lamports: BigInt(rest[0]) } : null;
|
|
38
|
+
default:
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function parseLogs(logs, programId) {
|
|
43
|
+
const stack = [];
|
|
44
|
+
const events = [];
|
|
45
|
+
for (const line of logs) {
|
|
46
|
+
const invoke = INVOKE.exec(line);
|
|
47
|
+
if (invoke) {
|
|
48
|
+
stack.push(invoke[1]);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (EXIT.test(line)) {
|
|
52
|
+
stack.pop();
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (stack.at(-1) !== programId || !line.startsWith(LOG))
|
|
56
|
+
continue;
|
|
57
|
+
const event = parseEvent(line.slice(LOG.length));
|
|
58
|
+
if (event)
|
|
59
|
+
events.push(event);
|
|
60
|
+
}
|
|
61
|
+
return events;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=logs.js.map
|
package/dist/logs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"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"}
|
package/dist/pda.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pda.d.ts","sourceRoot":"","sources":["../src/pda.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+C,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAExF,wBAAsB,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAWpH"}
|
package/dist/pda.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getAddressEncoder, getProgramDerivedAddress } from "@solana/kit";
|
|
2
|
+
export async function findCollection(programId, creator, nonce) {
|
|
3
|
+
if (!Number.isInteger(nonce) || nonce < 0 || nonce > 0xffff_ffff) {
|
|
4
|
+
throw new RangeError(`nonce must be a u32, got ${nonce}`);
|
|
5
|
+
}
|
|
6
|
+
const n = new Uint8Array(4);
|
|
7
|
+
new DataView(n.buffer).setUint32(0, nonce, true);
|
|
8
|
+
const [pda, bump] = await getProgramDerivedAddress({
|
|
9
|
+
programAddress: programId,
|
|
10
|
+
seeds: [new TextEncoder().encode("col"), getAddressEncoder().encode(creator), n],
|
|
11
|
+
});
|
|
12
|
+
return [pda, bump];
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=pda.js.map
|
package/dist/pda.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pda.js","sourceRoot":"","sources":["../src/pda.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAgB,MAAM,aAAa,CAAC;AAExF,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,SAAkB,EAAE,OAAgB,EAAE,KAAa;IACtF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,WAAW,EAAE,CAAC;QACjE,MAAM,IAAI,UAAU,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM,wBAAwB,CAAC;QACjD,cAAc,EAAE,SAAS;QACzB,KAAK,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,iBAAiB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;KACjF,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACrB,CAAC"}
|
package/dist/price.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function priceToLamports(price: number): bigint;
|
|
2
|
+
export declare function lamportsToPrice(lamports: bigint): number;
|
|
3
|
+
export declare function solToPrice(sol: string | number): number;
|
|
4
|
+
export declare function priceToSol(price: number): string;
|
|
5
|
+
//# sourceMappingURL=price.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"price.d.ts","sourceRoot":"","sources":["../src/price.ts"],"names":[],"mappings":"AAUA,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CASvD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKhD"}
|
package/dist/price.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MAX_PRICE, PRICE_UNIT } from "./constants.js";
|
|
2
|
+
const DECIMALS = 6;
|
|
3
|
+
function check(price) {
|
|
4
|
+
if (!Number.isInteger(price) || price < 0 || price > MAX_PRICE) {
|
|
5
|
+
throw new RangeError(`price must be an integer from 0 to ${MAX_PRICE} units of 1,000 lamports, got ${price}`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export function priceToLamports(price) {
|
|
9
|
+
check(price);
|
|
10
|
+
return BigInt(price) * PRICE_UNIT;
|
|
11
|
+
}
|
|
12
|
+
export function lamportsToPrice(lamports) {
|
|
13
|
+
if (lamports % PRICE_UNIT !== 0n)
|
|
14
|
+
throw new RangeError(`${lamports} lamports is not a whole number of price units`);
|
|
15
|
+
const price = lamports / PRICE_UNIT;
|
|
16
|
+
if (price < 0n || price > BigInt(MAX_PRICE))
|
|
17
|
+
throw new RangeError(`${lamports} lamports is outside the u32 price range`);
|
|
18
|
+
return Number(price);
|
|
19
|
+
}
|
|
20
|
+
export function solToPrice(sol) {
|
|
21
|
+
const text = typeof sol === "number" ? sol.toFixed(DECIMALS) : sol.trim();
|
|
22
|
+
const m = /^(\d*)(?:[.,](\d*))?$/.exec(text);
|
|
23
|
+
if (!m || (m[1] === "" && !m[2]))
|
|
24
|
+
throw new RangeError(`not a SOL amount: ${sol}`);
|
|
25
|
+
const frac = (m[2] ?? "").replace(/0+$/, "");
|
|
26
|
+
if (frac.length > DECIMALS)
|
|
27
|
+
throw new RangeError(`prices go down to 0.000001 SOL, got ${sol}`);
|
|
28
|
+
const price = Number(BigInt(m[1] || "0") * 10n ** BigInt(DECIMALS) + BigInt(frac.padEnd(DECIMALS, "0") || "0"));
|
|
29
|
+
check(price);
|
|
30
|
+
return price;
|
|
31
|
+
}
|
|
32
|
+
export function priceToSol(price) {
|
|
33
|
+
check(price);
|
|
34
|
+
const whole = Math.floor(price / 10 ** DECIMALS);
|
|
35
|
+
const frac = String(price % 10 ** DECIMALS).padStart(DECIMALS, "0").replace(/0+$/, "");
|
|
36
|
+
return frac ? `${whole}.${frac}` : String(whole);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=price.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"price.js","sourceRoot":"","sources":["../src/price.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEvD,MAAM,QAAQ,GAAG,CAAC,CAAC;AAEnB,SAAS,KAAK,CAAC,KAAa;IAC1B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;QAC/D,MAAM,IAAI,UAAU,CAAC,sCAAsC,SAAS,iCAAiC,KAAK,EAAE,CAAC,CAAC;IAChH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,KAAK,CAAC,KAAK,CAAC,CAAC;IACb,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,IAAI,QAAQ,GAAG,UAAU,KAAK,EAAE;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,QAAQ,gDAAgD,CAAC,CAAC;IACpH,MAAM,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAC;IACpC,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,QAAQ,0CAA0C,CAAC,CAAC;IACzH,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAoB;IAC7C,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1E,MAAM,CAAC,GAAG,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IACnF,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC7C,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ;QAAE,MAAM,IAAI,UAAU,CAAC,uCAAuC,GAAG,EAAE,CAAC,CAAC;IAC/F,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAChH,KAAK,CAAC,KAAK,CAAC,CAAC;IACb,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,KAAK,CAAC,KAAK,CAAC,CAAC;IACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,IAAI,QAAQ,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,EAAE,IAAI,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvF,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnD,CAAC"}
|
package/dist/rpc.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Address, type Commitment, type GetAccountInfoApi, type GetMinimumBalanceForRentExemptionApi, type GetProgramAccountsApi, type Rpc } from "@solana/kit";
|
|
2
|
+
import { type Collection, type CollectionHeader, type Slot } from "./account.ts";
|
|
3
|
+
export interface FetchConfig {
|
|
4
|
+
commitment?: Commitment;
|
|
5
|
+
programId?: Address;
|
|
6
|
+
}
|
|
7
|
+
export interface FetchedCollection {
|
|
8
|
+
address: Address;
|
|
9
|
+
lamports: bigint;
|
|
10
|
+
data: Uint8Array;
|
|
11
|
+
collection: Collection;
|
|
12
|
+
}
|
|
13
|
+
export declare function fetchCollection(rpc: Rpc<GetAccountInfoApi>, address: Address, config?: FetchConfig): Promise<FetchedCollection | null>;
|
|
14
|
+
export declare function fetchHeader(rpc: Rpc<GetAccountInfoApi>, address: Address, config?: FetchConfig): Promise<CollectionHeader | null>;
|
|
15
|
+
export declare function fetchSlot(rpc: Rpc<GetAccountInfoApi>, address: Address, id: number, config?: FetchConfig): Promise<Slot | null>;
|
|
16
|
+
export interface FoundCollection {
|
|
17
|
+
address: Address;
|
|
18
|
+
header: CollectionHeader;
|
|
19
|
+
}
|
|
20
|
+
export declare function findCollections(rpc: Rpc<GetProgramAccountsApi>, programId: Address, options?: {
|
|
21
|
+
creator?: Address;
|
|
22
|
+
commitment?: Commitment;
|
|
23
|
+
}): Promise<FoundCollection[]>;
|
|
24
|
+
export declare function getLamportsPerByte(rpc: Rpc<GetMinimumBalanceForRentExemptionApi>): Promise<bigint>;
|
|
25
|
+
export declare const rentExemptMinimum: (dataLength: number, lamportsPerByte: bigint) => bigint;
|
|
26
|
+
//# sourceMappingURL=rpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,OAAO,EAEZ,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,oCAAoC,EACzC,KAAK,qBAAqB,EAC1B,KAAK,GAAG,EACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,IAAI,EACV,MAAM,cAAc,CAAC;AAGtB,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;CACxB;AAUD,wBAAsB,eAAe,CACnC,GAAG,EAAE,GAAG,CAAC,iBAAiB,CAAC,EAC3B,OAAO,EAAE,OAAO,EAChB,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAQnC;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,GAAG,CAAC,iBAAiB,CAAC,EAC3B,OAAO,EAAE,OAAO,EAChB,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAWlC;AAED,wBAAsB,SAAS,CAC7B,GAAG,EAAE,GAAG,CAAC,iBAAiB,CAAC,EAC3B,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,MAAM,EACV,MAAM,GAAE,WAAgB,GACvB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAYtB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,GAAG,CAAC,qBAAqB,CAAC,EAC/B,SAAS,EAAE,OAAO,EAClB,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAO,GAC3D,OAAO,CAAC,eAAe,EAAE,CAAC,CAiB5B;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,oCAAoC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAGxG;AAED,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,EAAE,iBAAiB,MAAM,KAAG,MACvB,CAAC"}
|
package/dist/rpc.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { getBase58Decoder, getBase64Encoder, } from "@solana/kit";
|
|
2
|
+
import { decodeCollection, decodeHeader, decodeSlot, slotOffset, } from "./account.js";
|
|
3
|
+
import { ACCOUNT_OVERHEAD, COLLECTION_TAG, HEADER_LEN, HEADER_OFFSET, LAYOUT_VERSION, SLOT_LEN } from "./constants.js";
|
|
4
|
+
const bytes = (base64) => new Uint8Array(getBase64Encoder().encode(base64));
|
|
5
|
+
function owned(owner, programId, address) {
|
|
6
|
+
if (programId !== undefined && owner !== programId) {
|
|
7
|
+
throw new Error(`${address} is owned by ${owner}, not by the GL-36 program ${programId}`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export async function fetchCollection(rpc, address, config = {}) {
|
|
11
|
+
const { value } = await rpc
|
|
12
|
+
.getAccountInfo(address, { encoding: "base64", commitment: config.commitment ?? "confirmed" })
|
|
13
|
+
.send();
|
|
14
|
+
if (!value)
|
|
15
|
+
return null;
|
|
16
|
+
owned(value.owner, config.programId, address);
|
|
17
|
+
const data = bytes(value.data[0]);
|
|
18
|
+
return { address, lamports: BigInt(value.lamports), data, collection: decodeCollection(data) };
|
|
19
|
+
}
|
|
20
|
+
export async function fetchHeader(rpc, address, config = {}) {
|
|
21
|
+
const { value } = await rpc
|
|
22
|
+
.getAccountInfo(address, {
|
|
23
|
+
encoding: "base64",
|
|
24
|
+
commitment: config.commitment ?? "confirmed",
|
|
25
|
+
dataSlice: { offset: 0, length: HEADER_LEN },
|
|
26
|
+
})
|
|
27
|
+
.send();
|
|
28
|
+
if (!value)
|
|
29
|
+
return null;
|
|
30
|
+
owned(value.owner, config.programId, address);
|
|
31
|
+
return decodeHeader(bytes(value.data[0]));
|
|
32
|
+
}
|
|
33
|
+
export async function fetchSlot(rpc, address, id, config = {}) {
|
|
34
|
+
const { value } = await rpc
|
|
35
|
+
.getAccountInfo(address, {
|
|
36
|
+
encoding: "base64",
|
|
37
|
+
commitment: config.commitment ?? "confirmed",
|
|
38
|
+
dataSlice: { offset: slotOffset(id), length: SLOT_LEN },
|
|
39
|
+
})
|
|
40
|
+
.send();
|
|
41
|
+
if (!value)
|
|
42
|
+
return null;
|
|
43
|
+
owned(value.owner, config.programId, address);
|
|
44
|
+
const data = bytes(value.data[0]);
|
|
45
|
+
return data.length < SLOT_LEN ? null : decodeSlot(data, id);
|
|
46
|
+
}
|
|
47
|
+
export async function findCollections(rpc, programId, options = {}) {
|
|
48
|
+
const tagAndVersion = getBase58Decoder().decode(new Uint8Array([COLLECTION_TAG, LAYOUT_VERSION]));
|
|
49
|
+
const filters = [
|
|
50
|
+
{ memcmp: { offset: 0n, bytes: tagAndVersion, encoding: "base58" } },
|
|
51
|
+
...(options.creator
|
|
52
|
+
? [{ memcmp: { offset: BigInt(HEADER_OFFSET.creator), bytes: options.creator, encoding: "base58" } }]
|
|
53
|
+
: []),
|
|
54
|
+
];
|
|
55
|
+
const accounts = (await rpc
|
|
56
|
+
.getProgramAccounts(programId, {
|
|
57
|
+
encoding: "base64",
|
|
58
|
+
commitment: options.commitment ?? "confirmed",
|
|
59
|
+
dataSlice: { offset: 0, length: HEADER_LEN },
|
|
60
|
+
filters,
|
|
61
|
+
})
|
|
62
|
+
.send());
|
|
63
|
+
return accounts.map(({ pubkey, account }) => ({ address: pubkey, header: decodeHeader(bytes(account.data[0])) }));
|
|
64
|
+
}
|
|
65
|
+
export async function getLamportsPerByte(rpc) {
|
|
66
|
+
const min = await rpc.getMinimumBalanceForRentExemption(0n).send();
|
|
67
|
+
return BigInt(min) / BigInt(ACCOUNT_OVERHEAD);
|
|
68
|
+
}
|
|
69
|
+
export const rentExemptMinimum = (dataLength, lamportsPerByte) => BigInt(ACCOUNT_OVERHEAD + dataLength) * lamportsPerByte;
|
|
70
|
+
//# sourceMappingURL=rpc.js.map
|
package/dist/rpc.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,GAQjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,UAAU,GAIX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAcvH,MAAM,KAAK,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAEpF,SAAS,KAAK,CAAC,KAAc,EAAE,SAA8B,EAAE,OAAgB;IAC7E,IAAI,SAAS,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,gBAAgB,KAAK,8BAA8B,SAAS,EAAE,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAA2B,EAC3B,OAAgB,EAChB,SAAsB,EAAE;IAExB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG;SACxB,cAAc,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,WAAW,EAAE,CAAC;SAC7F,IAAI,EAAE,CAAC;IACV,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;AACjG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAA2B,EAC3B,OAAgB,EAChB,SAAsB,EAAE;IAExB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG;SACxB,cAAc,CAAC,OAAO,EAAE;QACvB,QAAQ,EAAE,QAAQ;QAClB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,WAAW;QAC5C,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE;KAC7C,CAAC;SACD,IAAI,EAAE,CAAC;IACV,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC9C,OAAO,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAA2B,EAC3B,OAAgB,EAChB,EAAU,EACV,SAAsB,EAAE;IAExB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG;SACxB,cAAc,CAAC,OAAO,EAAE;QACvB,QAAQ,EAAE,QAAQ;QAClB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,WAAW;QAC5C,SAAS,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE;KACxD,CAAC;SACD,IAAI,EAAE,CAAC;IACV,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC9D,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAA+B,EAC/B,SAAkB,EAClB,UAA0D,EAAE;IAE5D,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,CAAuB,CAAC;IACxH,MAAM,OAAO,GAAG;QACd,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAiB,EAAE,EAAE;QAC7E,GAAG,CAAC,OAAO,CAAC,OAAO;YACjB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,OAAuC,EAAE,QAAQ,EAAE,QAAiB,EAAE,EAAE,CAAC;YAC9I,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;IACF,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG;SACxB,kBAAkB,CAAC,SAAS,EAAE;QAC7B,QAAQ,EAAE,QAAQ;QAClB,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,WAAW;QAC7C,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE;QAC5C,OAAO;KACR,CAAC;SACD,IAAI,EAAE,CAA4F,CAAC;IACtG,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACpH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAA8C;IACrF,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,iCAAiC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnE,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,UAAkB,EAAE,eAAuB,EAAU,EAAE,CACvF,MAAM,CAAC,gBAAgB,GAAG,UAAU,CAAC,GAAG,eAAe,CAAC"}
|
package/dist/seed.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Address } from "@solana/kit";
|
|
2
|
+
export interface TokenSeedArgs {
|
|
3
|
+
domain: string;
|
|
4
|
+
collection: Address;
|
|
5
|
+
entropy: Uint8Array;
|
|
6
|
+
id: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function tokenSeed({ domain, collection, entropy, id }: TokenSeedArgs): Promise<Uint8Array>;
|
|
9
|
+
//# sourceMappingURL=seed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAa9D,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,UAAU,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CASjG"}
|
package/dist/seed.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getAddressEncoder } from "@solana/kit";
|
|
2
|
+
import { MAX_SUPPLY } from "./constants.js";
|
|
3
|
+
async function sha256(...parts) {
|
|
4
|
+
const buf = new Uint8Array(new ArrayBuffer(parts.reduce((n, p) => n + p.length, 0)));
|
|
5
|
+
let off = 0;
|
|
6
|
+
for (const p of parts) {
|
|
7
|
+
buf.set(p, off);
|
|
8
|
+
off += p.length;
|
|
9
|
+
}
|
|
10
|
+
return new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", buf));
|
|
11
|
+
}
|
|
12
|
+
export function tokenSeed({ domain, collection, entropy, id }) {
|
|
13
|
+
if (!Number.isInteger(id) || id < 0 || id >= MAX_SUPPLY)
|
|
14
|
+
throw new RangeError(`id must be a u16 below ${MAX_SUPPLY}, got ${id}`);
|
|
15
|
+
const idLe = new Uint8Array([id & 0xff, id >> 8]);
|
|
16
|
+
return sha256(new TextEncoder().encode(domain), new Uint8Array(getAddressEncoder().encode(collection)), entropy, idLe);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=seed.js.map
|
package/dist/seed.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAgB,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,KAAK,UAAU,MAAM,CAAC,GAAG,KAAmB;IAC1C,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAChB,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;AAC/E,CAAC;AASD,MAAM,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAiB;IAC1E,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,UAAU;QAAE,MAAM,IAAI,UAAU,CAAC,0BAA0B,UAAU,SAAS,EAAE,EAAE,CAAC,CAAC;IACjI,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAClD,OAAO,MAAM,CACX,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAChC,IAAI,UAAU,CAAC,iBAAiB,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EACtD,OAAO,EACP,IAAI,CACL,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gl-36/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for GL-36, an NFT standard for Solana where a token takes 36 bytes.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"source": "./src/index.ts",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
25
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
26
|
+
"test": "node --test test/*.test.ts",
|
|
27
|
+
"prepack": "npm run typecheck && npm test && npm run build"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@solana/kit": "^8.5.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@solana/kit": "8.5.0",
|
|
34
|
+
"@types/node": "24.19.2",
|
|
35
|
+
"litesvm": "1.6.1",
|
|
36
|
+
"typescript": "5.9.3"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20.19"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://gl36.org/docs/client/",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/genloss-36/gl-36.git",
|
|
45
|
+
"directory": "packages/sdk"
|
|
46
|
+
},
|
|
47
|
+
"bugs": "https://github.com/genloss-36/gl-36/issues",
|
|
48
|
+
"keywords": [
|
|
49
|
+
"solana",
|
|
50
|
+
"nft",
|
|
51
|
+
"gl-36",
|
|
52
|
+
"kit",
|
|
53
|
+
"sdk"
|
|
54
|
+
],
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/account.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { getAddressDecoder, type Address } from "@solana/kit";
|
|
2
|
+
import {
|
|
3
|
+
COLLECTION_TAG,
|
|
4
|
+
FLAG_CLOSED,
|
|
5
|
+
FLAG_SETTLED,
|
|
6
|
+
HEADER_LEN,
|
|
7
|
+
HEADER_OFFSET as O,
|
|
8
|
+
LAYOUT_VERSION,
|
|
9
|
+
SETTLE_DELAY,
|
|
10
|
+
SLOT_LEN,
|
|
11
|
+
SLOT_OFFSET,
|
|
12
|
+
} from "./constants.ts";
|
|
13
|
+
|
|
14
|
+
export interface Slot {
|
|
15
|
+
id: number;
|
|
16
|
+
owner: Address;
|
|
17
|
+
price: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CollectionHeader {
|
|
21
|
+
bump: number;
|
|
22
|
+
flags: number;
|
|
23
|
+
maxSupply: number;
|
|
24
|
+
minted: number;
|
|
25
|
+
feeBps: number;
|
|
26
|
+
nonce: number;
|
|
27
|
+
mintPrice: bigint;
|
|
28
|
+
creator: Address;
|
|
29
|
+
treasury: Address;
|
|
30
|
+
closeSlot: bigint;
|
|
31
|
+
entropy: Uint8Array;
|
|
32
|
+
generatorHash: Uint8Array;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface Collection extends CollectionHeader {
|
|
36
|
+
slots: Slot[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type CollectionState = "open" | "closed" | "settled";
|
|
40
|
+
|
|
41
|
+
export const accountLength = (minted: number) => HEADER_LEN + minted * SLOT_LEN;
|
|
42
|
+
|
|
43
|
+
export const slotOffset = (id: number) => HEADER_LEN + id * SLOT_LEN;
|
|
44
|
+
|
|
45
|
+
const view = (data: Uint8Array) => new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
46
|
+
|
|
47
|
+
const key = (data: Uint8Array, off: number) => getAddressDecoder().decode(data.subarray(off, off + 32));
|
|
48
|
+
|
|
49
|
+
export function isCollectionAccount(data: Uint8Array): boolean {
|
|
50
|
+
if (data.length < HEADER_LEN || data[O.tag] !== COLLECTION_TAG || data[O.version] !== LAYOUT_VERSION) return false;
|
|
51
|
+
return data.length === accountLength(view(data).getUint16(O.minted, true));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function decodeHeader(data: Uint8Array): CollectionHeader {
|
|
55
|
+
if (data.length < HEADER_LEN || data[O.tag] !== COLLECTION_TAG || data[O.version] !== LAYOUT_VERSION) {
|
|
56
|
+
throw new Error("not a GL-36 collection account");
|
|
57
|
+
}
|
|
58
|
+
const v = view(data);
|
|
59
|
+
return {
|
|
60
|
+
bump: data[O.bump],
|
|
61
|
+
flags: data[O.flags],
|
|
62
|
+
maxSupply: v.getUint16(O.maxSupply, true),
|
|
63
|
+
minted: v.getUint16(O.minted, true),
|
|
64
|
+
feeBps: v.getUint16(O.feeBps, true),
|
|
65
|
+
nonce: v.getUint32(O.nonce, true),
|
|
66
|
+
mintPrice: v.getBigUint64(O.mintPrice, true),
|
|
67
|
+
creator: key(data, O.creator),
|
|
68
|
+
treasury: key(data, O.treasury),
|
|
69
|
+
closeSlot: v.getBigUint64(O.closeSlot, true),
|
|
70
|
+
entropy: data.slice(O.entropy, O.entropy + 32),
|
|
71
|
+
generatorHash: data.slice(O.generatorHash, O.generatorHash + 32),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function decodeSlot(bytes: Uint8Array, id: number): Slot {
|
|
76
|
+
if (bytes.length < SLOT_LEN) throw new Error(`a slot is ${SLOT_LEN} bytes, got ${bytes.length}`);
|
|
77
|
+
return {
|
|
78
|
+
id,
|
|
79
|
+
owner: key(bytes, SLOT_OFFSET.owner),
|
|
80
|
+
price: view(bytes).getUint32(SLOT_OFFSET.price, true),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function decodeCollection(data: Uint8Array): Collection {
|
|
85
|
+
const header = decodeHeader(data);
|
|
86
|
+
if (data.length < accountLength(header.minted)) {
|
|
87
|
+
throw new Error(`account holds ${data.length} bytes, ${accountLength(header.minted)} needed for ${header.minted} slots`);
|
|
88
|
+
}
|
|
89
|
+
const slots: Slot[] = [];
|
|
90
|
+
for (let id = 0; id < header.minted; id++) {
|
|
91
|
+
const o = slotOffset(id);
|
|
92
|
+
slots.push(decodeSlot(data.subarray(o, o + SLOT_LEN), id));
|
|
93
|
+
}
|
|
94
|
+
return { ...header, slots };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function collectionState(c: Pick<CollectionHeader, "flags">): CollectionState {
|
|
98
|
+
if (c.flags & FLAG_SETTLED) return "settled";
|
|
99
|
+
if (c.flags & FLAG_CLOSED) return "closed";
|
|
100
|
+
return "open";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const entropySlot = (c: Pick<CollectionHeader, "closeSlot">): bigint => c.closeSlot + SETTLE_DELAY;
|
|
104
|
+
|
|
105
|
+
export const listedSlots = (c: Pick<Collection, "slots">): Slot[] =>
|
|
106
|
+
c.slots.filter((s) => s.price > 0).sort((a, b) => a.price - b.price || a.id - b.id);
|
|
107
|
+
|
|
108
|
+
export const slotsOwnedBy = (c: Pick<Collection, "slots">, owner: Address): Slot[] =>
|
|
109
|
+
c.slots.filter((s) => s.owner === owner);
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Address } from "@solana/kit";
|
|
2
|
+
|
|
3
|
+
export const PROGRAM_ID = {
|
|
4
|
+
mainnet: "GtUakBxu2UXwv68PkLYmkzyAUtLXwqhtbi7W8GUmPmTb" as Address,
|
|
5
|
+
} as const;
|
|
6
|
+
|
|
7
|
+
export type Cluster = keyof typeof PROGRAM_ID;
|
|
8
|
+
|
|
9
|
+
export const SYSTEM_PROGRAM = "11111111111111111111111111111111" as Address;
|
|
10
|
+
export const SLOT_HASHES = "SysvarS1otHashes111111111111111111111111111" as Address;
|
|
11
|
+
|
|
12
|
+
export const COLLECTION_TAG = 1;
|
|
13
|
+
export const LAYOUT_VERSION = 1;
|
|
14
|
+
|
|
15
|
+
export const HEADER_LEN = 224;
|
|
16
|
+
export const SLOT_LEN = 36;
|
|
17
|
+
export const ACCOUNT_OVERHEAD = 128;
|
|
18
|
+
|
|
19
|
+
export const PRICE_UNIT = 1_000n;
|
|
20
|
+
export const MAX_PRICE = 0xffff_ffff;
|
|
21
|
+
export const MAX_SUPPLY = 0xffff;
|
|
22
|
+
export const MAX_MINT_BATCH = 10;
|
|
23
|
+
export const MAX_FEE_BPS = 1_000;
|
|
24
|
+
|
|
25
|
+
export const FLAG_SETTLED = 1;
|
|
26
|
+
export const FLAG_CLOSED = 2;
|
|
27
|
+
|
|
28
|
+
export const SETTLE_DELAY = 32n;
|
|
29
|
+
|
|
30
|
+
export const HEADER_OFFSET = {
|
|
31
|
+
tag: 0,
|
|
32
|
+
version: 1,
|
|
33
|
+
bump: 2,
|
|
34
|
+
flags: 3,
|
|
35
|
+
maxSupply: 4,
|
|
36
|
+
minted: 6,
|
|
37
|
+
feeBps: 8,
|
|
38
|
+
nonce: 12,
|
|
39
|
+
mintPrice: 16,
|
|
40
|
+
creator: 24,
|
|
41
|
+
treasury: 56,
|
|
42
|
+
closeSlot: 88,
|
|
43
|
+
entropy: 152,
|
|
44
|
+
generatorHash: 184,
|
|
45
|
+
} as const;
|
|
46
|
+
|
|
47
|
+
export const SLOT_OFFSET = {
|
|
48
|
+
owner: 0,
|
|
49
|
+
price: 32,
|
|
50
|
+
} as const;
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { isSolanaError, SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM, type Address } from "@solana/kit";
|
|
2
|
+
import { SYSTEM_PROGRAM } from "./constants.ts";
|
|
3
|
+
|
|
4
|
+
export const ERR = {
|
|
5
|
+
SoldOut: 1,
|
|
6
|
+
BadBatch: 2,
|
|
7
|
+
NotOwner: 3,
|
|
8
|
+
NotListed: 4,
|
|
9
|
+
PriceAboveMax: 5,
|
|
10
|
+
SellerMismatch: 6,
|
|
11
|
+
SelfBuy: 7,
|
|
12
|
+
NotClosed: 8,
|
|
13
|
+
AlreadySettled: 9,
|
|
14
|
+
MintClosed: 10,
|
|
15
|
+
BadFee: 11,
|
|
16
|
+
BadSupply: 12,
|
|
17
|
+
WrongCreator: 13,
|
|
18
|
+
WrongTreasury: 14,
|
|
19
|
+
BadId: 15,
|
|
20
|
+
SameOwner: 16,
|
|
21
|
+
BadSysvar: 17,
|
|
22
|
+
TooEarly: 18,
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
export type ErrorName = keyof typeof ERR;
|
|
26
|
+
|
|
27
|
+
const NAMES = new Map<number, ErrorName>(Object.entries(ERR).map(([k, v]) => [v, k as ErrorName]));
|
|
28
|
+
|
|
29
|
+
export const errorName = (code: number): ErrorName | undefined => NAMES.get(code);
|
|
30
|
+
|
|
31
|
+
export interface ProgramError {
|
|
32
|
+
code: number;
|
|
33
|
+
name: ErrorName | undefined;
|
|
34
|
+
program?: Address;
|
|
35
|
+
instructionIndex?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const FAILED = /^Program (\w+) failed: custom program error: 0x([0-9a-f]+)/i;
|
|
39
|
+
const CUSTOM = /custom program error: 0x([0-9a-f]+)/i;
|
|
40
|
+
|
|
41
|
+
function chain(error: unknown): unknown[] {
|
|
42
|
+
const out: unknown[] = [];
|
|
43
|
+
for (let e = error, depth = 0; e != null && depth < 8; depth++) {
|
|
44
|
+
out.push(e);
|
|
45
|
+
e = typeof e === "object" ? (e as { cause?: unknown }).cause : undefined;
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function logsOf(error: unknown): string[] {
|
|
51
|
+
if (Array.isArray(error)) return error.filter((l): l is string => typeof l === "string");
|
|
52
|
+
for (const e of chain(error)) {
|
|
53
|
+
const logs = (e as { context?: { logs?: unknown } })?.context?.logs ?? (e as { logs?: unknown })?.logs;
|
|
54
|
+
if (Array.isArray(logs)) return logs.filter((l): l is string => typeof l === "string");
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function named(code: number, program: Address | undefined, programId: Address | undefined): ErrorName | undefined {
|
|
60
|
+
if (program === undefined) return errorName(code);
|
|
61
|
+
if (programId !== undefined) return program === programId ? errorName(code) : undefined;
|
|
62
|
+
return program === SYSTEM_PROGRAM ? undefined : errorName(code);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function parseProgramError(error: unknown, options: { programId?: Address } = {}): ProgramError | null {
|
|
66
|
+
for (const line of logsOf(error)) {
|
|
67
|
+
const m = FAILED.exec(line);
|
|
68
|
+
if (m) {
|
|
69
|
+
const program = m[1] as Address;
|
|
70
|
+
const code = Number.parseInt(m[2], 16);
|
|
71
|
+
return { code, name: named(code, program, options.programId), program };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (const e of chain(error)) {
|
|
75
|
+
if (isSolanaError(e, SOLANA_ERROR__INSTRUCTION_ERROR__CUSTOM)) {
|
|
76
|
+
const { code, index } = e.context;
|
|
77
|
+
return { code, name: errorName(code), instructionIndex: index };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const e of chain(error)) {
|
|
81
|
+
const text = typeof e === "string" ? e : e instanceof Error ? e.message : "";
|
|
82
|
+
const m = CUSTOM.exec(text);
|
|
83
|
+
if (m) {
|
|
84
|
+
const code = Number.parseInt(m[1], 16);
|
|
85
|
+
return { code, name: errorName(code) };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|