four-flap-meme-sdk 1.5.5 → 1.5.6
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/abis/common.js +0 -2
- package/dist/contracts/tm-bundle-merkle/config.d.ts +1 -0
- package/dist/contracts/tm-bundle-merkle/config.js +1 -0
- package/dist/contracts/tm-bundle-merkle/core.js +9 -13
- package/dist/flap/portal-bundle-merkle/config.d.ts +1 -0
- package/dist/flap/portal-bundle-merkle/config.js +1 -0
- package/dist/flap/portal-bundle-merkle/create-to-dex.d.ts +2 -8
- package/dist/flap/portal-bundle-merkle/create-to-dex.js +126 -159
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/sol/constants.d.ts +150 -0
- package/dist/sol/constants.js +188 -0
- package/dist/sol/dex/blockrazor/client.d.ts +51 -0
- package/dist/sol/dex/blockrazor/client.js +96 -0
- package/dist/sol/dex/blockrazor/constants.d.ts +34 -0
- package/dist/sol/dex/blockrazor/constants.js +55 -0
- package/dist/sol/dex/blockrazor/geyser.d.ts +128 -0
- package/dist/sol/dex/blockrazor/geyser.js +530 -0
- package/dist/sol/dex/blockrazor/index.d.ts +18 -0
- package/dist/sol/dex/blockrazor/index.js +23 -0
- package/dist/sol/dex/blockrazor/send.d.ts +135 -0
- package/dist/sol/dex/blockrazor/send.js +254 -0
- package/dist/sol/dex/blockrazor/types.d.ts +191 -0
- package/dist/sol/dex/blockrazor/types.js +5 -0
- package/dist/sol/dex/index.d.ts +10 -0
- package/dist/sol/dex/index.js +16 -0
- package/dist/sol/dex/jup/client.d.ts +33 -0
- package/dist/sol/dex/jup/client.js +110 -0
- package/dist/sol/dex/jup/index.d.ts +16 -0
- package/dist/sol/dex/jup/index.js +148 -0
- package/dist/sol/dex/jup/legacy.d.ts +623 -0
- package/dist/sol/dex/jup/legacy.js +416 -0
- package/dist/sol/dex/jup/lend.d.ts +640 -0
- package/dist/sol/dex/jup/lend.js +603 -0
- package/dist/sol/dex/jup/portfolio.d.ts +362 -0
- package/dist/sol/dex/jup/portfolio.js +367 -0
- package/dist/sol/dex/jup/price.d.ts +173 -0
- package/dist/sol/dex/jup/price.js +220 -0
- package/dist/sol/dex/jup/recurring.d.ts +437 -0
- package/dist/sol/dex/jup/recurring.js +320 -0
- package/dist/sol/dex/jup/send.d.ts +282 -0
- package/dist/sol/dex/jup/send.js +295 -0
- package/dist/sol/dex/jup/studio.d.ts +457 -0
- package/dist/sol/dex/jup/studio.js +488 -0
- package/dist/sol/dex/jup/tokens.d.ts +767 -0
- package/dist/sol/dex/jup/tokens.js +697 -0
- package/dist/sol/dex/jup/trigger.d.ts +511 -0
- package/dist/sol/dex/jup/trigger.js +397 -0
- package/dist/sol/dex/jup/types.d.ts +433 -0
- package/dist/sol/dex/jup/types.js +5 -0
- package/dist/sol/dex/jup/ultra.d.ts +646 -0
- package/dist/sol/dex/jup/ultra.js +853 -0
- package/dist/sol/dex/meteora/client.d.ts +76 -0
- package/dist/sol/dex/meteora/client.js +219 -0
- package/dist/sol/dex/meteora/damm-v1-bundle.d.ts +61 -0
- package/dist/sol/dex/meteora/damm-v1-bundle.js +112 -0
- package/dist/sol/dex/meteora/damm-v1.d.ts +118 -0
- package/dist/sol/dex/meteora/damm-v1.js +315 -0
- package/dist/sol/dex/meteora/damm-v2-bundle.d.ts +82 -0
- package/dist/sol/dex/meteora/damm-v2-bundle.js +242 -0
- package/dist/sol/dex/meteora/damm-v2.d.ts +172 -0
- package/dist/sol/dex/meteora/damm-v2.js +632 -0
- package/dist/sol/dex/meteora/dbc-bundle.d.ts +123 -0
- package/dist/sol/dex/meteora/dbc-bundle.js +304 -0
- package/dist/sol/dex/meteora/dbc.d.ts +192 -0
- package/dist/sol/dex/meteora/dbc.js +619 -0
- package/dist/sol/dex/meteora/dlmm-bundle.d.ts +39 -0
- package/dist/sol/dex/meteora/dlmm-bundle.js +189 -0
- package/dist/sol/dex/meteora/dlmm.d.ts +157 -0
- package/dist/sol/dex/meteora/dlmm.js +671 -0
- package/dist/sol/dex/meteora/index.d.ts +25 -0
- package/dist/sol/dex/meteora/index.js +65 -0
- package/dist/sol/dex/meteora/types.d.ts +787 -0
- package/dist/sol/dex/meteora/types.js +110 -0
- package/dist/sol/dex/orca/index.d.ts +10 -0
- package/dist/sol/dex/orca/index.js +16 -0
- package/dist/sol/dex/orca/orca-bundle.d.ts +41 -0
- package/dist/sol/dex/orca/orca-bundle.js +173 -0
- package/dist/sol/dex/orca/orca.d.ts +65 -0
- package/dist/sol/dex/orca/orca.js +474 -0
- package/dist/sol/dex/orca/types.d.ts +263 -0
- package/dist/sol/dex/orca/types.js +38 -0
- package/dist/sol/dex/orca/wavebreak-bundle.d.ts +34 -0
- package/dist/sol/dex/orca/wavebreak-bundle.js +198 -0
- package/dist/sol/dex/orca/wavebreak-types.d.ts +227 -0
- package/dist/sol/dex/orca/wavebreak-types.js +23 -0
- package/dist/sol/dex/orca/wavebreak.d.ts +78 -0
- package/dist/sol/dex/orca/wavebreak.js +497 -0
- package/dist/sol/dex/pump/index.d.ts +9 -0
- package/dist/sol/dex/pump/index.js +14 -0
- package/dist/sol/dex/pump/pump-bundle.d.ts +92 -0
- package/dist/sol/dex/pump/pump-bundle.js +383 -0
- package/dist/sol/dex/pump/pump-swap-bundle.d.ts +103 -0
- package/dist/sol/dex/pump/pump-swap-bundle.js +380 -0
- package/dist/sol/dex/pump/pump-swap.d.ts +46 -0
- package/dist/sol/dex/pump/pump-swap.js +199 -0
- package/dist/sol/dex/pump/pump.d.ts +35 -0
- package/dist/sol/dex/pump/pump.js +352 -0
- package/dist/sol/dex/pump/types.d.ts +215 -0
- package/dist/sol/dex/pump/types.js +5 -0
- package/dist/sol/dex/raydium/index.d.ts +8 -0
- package/dist/sol/dex/raydium/index.js +12 -0
- package/dist/sol/dex/raydium/launchlab.d.ts +68 -0
- package/dist/sol/dex/raydium/launchlab.js +210 -0
- package/dist/sol/dex/raydium/raydium-bundle.d.ts +64 -0
- package/dist/sol/dex/raydium/raydium-bundle.js +324 -0
- package/dist/sol/dex/raydium/raydium.d.ts +40 -0
- package/dist/sol/dex/raydium/raydium.js +366 -0
- package/dist/sol/dex/raydium/types.d.ts +240 -0
- package/dist/sol/dex/raydium/types.js +5 -0
- package/dist/sol/index.d.ts +11 -0
- package/dist/sol/index.js +18 -0
- package/dist/sol/jito/bundle.d.ts +90 -0
- package/dist/sol/jito/bundle.js +263 -0
- package/dist/sol/jito/index.d.ts +7 -0
- package/dist/sol/jito/index.js +7 -0
- package/dist/sol/jito/tip.d.ts +51 -0
- package/dist/sol/jito/tip.js +83 -0
- package/dist/sol/jito/types.d.ts +100 -0
- package/dist/sol/jito/types.js +5 -0
- package/dist/sol/nozomi/client.d.ts +63 -0
- package/dist/sol/nozomi/client.js +222 -0
- package/dist/sol/nozomi/index.d.ts +8 -0
- package/dist/sol/nozomi/index.js +8 -0
- package/dist/sol/nozomi/tip.d.ts +50 -0
- package/dist/sol/nozomi/tip.js +80 -0
- package/dist/sol/nozomi/types.d.ts +96 -0
- package/dist/sol/nozomi/types.js +5 -0
- package/dist/sol/token/create-complete.d.ts +115 -0
- package/dist/sol/token/create-complete.js +235 -0
- package/dist/sol/token/create-token.d.ts +57 -0
- package/dist/sol/token/create-token.js +230 -0
- package/dist/sol/token/index.d.ts +9 -0
- package/dist/sol/token/index.js +14 -0
- package/dist/sol/token/metadata-upload.d.ts +86 -0
- package/dist/sol/token/metadata-upload.js +173 -0
- package/dist/sol/token/metadata.d.ts +92 -0
- package/dist/sol/token/metadata.js +274 -0
- package/dist/sol/token/types.d.ts +153 -0
- package/dist/sol/token/types.js +5 -0
- package/dist/sol/types.d.ts +176 -0
- package/dist/sol/types.js +7 -0
- package/dist/sol/utils/balance.d.ts +160 -0
- package/dist/sol/utils/balance.js +638 -0
- package/dist/sol/utils/connection.d.ts +78 -0
- package/dist/sol/utils/connection.js +168 -0
- package/dist/sol/utils/index.d.ts +9 -0
- package/dist/sol/utils/index.js +9 -0
- package/dist/sol/utils/lp-inspect.d.ts +129 -0
- package/dist/sol/utils/lp-inspect.js +900 -0
- package/dist/sol/utils/transfer.d.ts +196 -0
- package/dist/sol/utils/transfer.js +307 -0
- package/dist/sol/utils/wallet.d.ts +107 -0
- package/dist/sol/utils/wallet.js +210 -0
- package/package.json +41 -5
- package/README.zh-CN.pdf +0 -0
- package/dist/flap/portal-bundle-merkle/encryption.d.ts +0 -16
- package/dist/flap/portal-bundle-merkle/encryption.js +0 -146
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 元数据上传(复用 Flap 官方 IPFS 接口)
|
|
3
|
+
* @module sol/token/metadata-upload
|
|
4
|
+
*/
|
|
5
|
+
// Flap 官方 IPFS API
|
|
6
|
+
const FLAP_IPFS_API = 'https://0pi75kmgw9.execute-api.eu-west-3.amazonaws.com/v1';
|
|
7
|
+
/**
|
|
8
|
+
* 使用 Flap 官方 GraphQL 接口上传文件到 IPFS
|
|
9
|
+
* 同时上传图片和元数据,返回 bafkrei... 格式的 CIDv1
|
|
10
|
+
*
|
|
11
|
+
* @param file 图片文件(File 或 Uint8Array 或 Buffer)
|
|
12
|
+
* @param meta 元数据
|
|
13
|
+
* @returns CID
|
|
14
|
+
*/
|
|
15
|
+
export async function uploadToFlapIPFS(file, meta) {
|
|
16
|
+
try {
|
|
17
|
+
const form = new FormData();
|
|
18
|
+
// 1. 添加文件(key 为 "0")
|
|
19
|
+
if (file instanceof Uint8Array || (typeof Buffer !== 'undefined' && Buffer.isBuffer(file))) {
|
|
20
|
+
const blob = new Blob([file]);
|
|
21
|
+
form.append('0', blob, 'upload.png');
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
form.append('0', file);
|
|
25
|
+
}
|
|
26
|
+
// 2. 添加 GraphQL operations(同时上传图片和元数据)
|
|
27
|
+
const operations = {
|
|
28
|
+
query: `
|
|
29
|
+
mutation Create($file: Upload!, $meta: MetadataInput!) {
|
|
30
|
+
create(file: $file, meta: $meta)
|
|
31
|
+
}
|
|
32
|
+
`,
|
|
33
|
+
variables: {
|
|
34
|
+
file: null,
|
|
35
|
+
meta: {
|
|
36
|
+
buy: null,
|
|
37
|
+
creator: meta.creator || '0x0000000000000000000000000000000000000000',
|
|
38
|
+
description: meta.description || '',
|
|
39
|
+
telegram: meta.telegram || null,
|
|
40
|
+
twitter: meta.twitter || null,
|
|
41
|
+
website: meta.website || null,
|
|
42
|
+
sell: null,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
form.append('operations', JSON.stringify(operations));
|
|
47
|
+
// 3. 添加 map(将文件映射到 GraphQL 变量)
|
|
48
|
+
form.append('map', JSON.stringify({ "0": ["variables.file"] }));
|
|
49
|
+
// 4. 发送请求
|
|
50
|
+
// 注意:不要手动设置 Content-Type,浏览器/Node 会自动添加正确的 multipart/form-data 和 boundary
|
|
51
|
+
const resp = await fetch(FLAP_IPFS_API, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
body: form,
|
|
54
|
+
});
|
|
55
|
+
if (!resp.ok) {
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: `IPFS upload failed: ${resp.status} ${resp.statusText}`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const data = await resp.json();
|
|
62
|
+
const metaCid = data?.data?.create;
|
|
63
|
+
if (!metaCid) {
|
|
64
|
+
const errorMsg = data?.errors?.[0]?.message || 'No CID returned';
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
error: `IPFS upload error: ${errorMsg}`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
success: true,
|
|
72
|
+
cid: metaCid,
|
|
73
|
+
uri: `ipfs://${metaCid}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
error: error.message,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 上传图片和元数据到 IPFS(Flap 官方接口)
|
|
85
|
+
* 这是主要的上传方法
|
|
86
|
+
*
|
|
87
|
+
* @param imageBuffer 图片 Buffer
|
|
88
|
+
* @param metadata 代币元数据
|
|
89
|
+
* @returns 上传结果
|
|
90
|
+
*/
|
|
91
|
+
export async function uploadTokenMetadata(imageBuffer, metadata) {
|
|
92
|
+
return uploadToFlapIPFS(imageBuffer, {
|
|
93
|
+
creator: metadata.creator,
|
|
94
|
+
description: metadata.description,
|
|
95
|
+
telegram: metadata.telegram,
|
|
96
|
+
twitter: metadata.twitter,
|
|
97
|
+
website: metadata.website,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 从 File 对象上传(浏览器环境)
|
|
102
|
+
*/
|
|
103
|
+
export async function uploadTokenMetadataFromFile(file, metadata) {
|
|
104
|
+
return uploadToFlapIPFS(file, {
|
|
105
|
+
creator: metadata.creator,
|
|
106
|
+
description: metadata.description,
|
|
107
|
+
telegram: metadata.telegram,
|
|
108
|
+
twitter: metadata.twitter,
|
|
109
|
+
website: metadata.website,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 构建完整的 Metaplex 元数据 JSON
|
|
114
|
+
* 用于已经上传图片后,构建标准的元数据格式
|
|
115
|
+
*/
|
|
116
|
+
export function buildMetaplexMetadataJson(metadata, imageCid) {
|
|
117
|
+
const imageUri = imageCid.startsWith('ipfs://') ? imageCid : `ipfs://${imageCid}`;
|
|
118
|
+
return {
|
|
119
|
+
name: metadata.name,
|
|
120
|
+
symbol: metadata.symbol,
|
|
121
|
+
description: metadata.description,
|
|
122
|
+
image: imageUri,
|
|
123
|
+
external_url: metadata.externalUrl,
|
|
124
|
+
attributes: metadata.attributes,
|
|
125
|
+
properties: {
|
|
126
|
+
files: [
|
|
127
|
+
{
|
|
128
|
+
uri: imageUri,
|
|
129
|
+
type: 'image/png',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
category: 'image',
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 构建元数据 JSON(不上传,用于已有图片 URL 的情况)
|
|
138
|
+
*/
|
|
139
|
+
export function buildMetadataJson(metadata) {
|
|
140
|
+
return {
|
|
141
|
+
name: metadata.name,
|
|
142
|
+
symbol: metadata.symbol,
|
|
143
|
+
description: metadata.description,
|
|
144
|
+
image: metadata.image,
|
|
145
|
+
external_url: metadata.externalUrl,
|
|
146
|
+
attributes: metadata.attributes,
|
|
147
|
+
properties: {
|
|
148
|
+
files: [
|
|
149
|
+
{
|
|
150
|
+
uri: metadata.image,
|
|
151
|
+
type: 'image/png',
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
category: 'image',
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* CID 转换为 IPFS URI
|
|
160
|
+
*/
|
|
161
|
+
export function cidToUri(cid) {
|
|
162
|
+
if (cid.startsWith('ipfs://')) {
|
|
163
|
+
return cid;
|
|
164
|
+
}
|
|
165
|
+
return `ipfs://${cid}`;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* CID 转换为 HTTP 网关 URL
|
|
169
|
+
*/
|
|
170
|
+
export function cidToHttpUrl(cid, gateway = 'https://ipfs.io/ipfs/') {
|
|
171
|
+
const cleanCid = cid.replace('ipfs://', '');
|
|
172
|
+
return `${gateway}${cleanCid}`;
|
|
173
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metaplex Token Metadata 集成
|
|
3
|
+
* @module sol/token/metadata
|
|
4
|
+
*/
|
|
5
|
+
import { Connection, Keypair, PublicKey, TransactionInstruction } from '@solana/web3.js';
|
|
6
|
+
/**
|
|
7
|
+
* 元数据账户数据
|
|
8
|
+
*/
|
|
9
|
+
export interface MetadataData {
|
|
10
|
+
name: string;
|
|
11
|
+
symbol: string;
|
|
12
|
+
uri: string;
|
|
13
|
+
sellerFeeBasisPoints: number;
|
|
14
|
+
creators?: Array<{
|
|
15
|
+
address: PublicKey;
|
|
16
|
+
verified: boolean;
|
|
17
|
+
share: number;
|
|
18
|
+
}> | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 获取 Metadata PDA 地址
|
|
22
|
+
* @param mint Mint 地址
|
|
23
|
+
*/
|
|
24
|
+
export declare function getMetadataPDA(mint: PublicKey): PublicKey;
|
|
25
|
+
/**
|
|
26
|
+
* 构建 CreateMetadataAccountV3 指令
|
|
27
|
+
* 手动构建指令,避免 Metaplex SDK 版本兼容问题
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildCreateMetadataAccountV3Instruction(params: {
|
|
30
|
+
metadata: PublicKey;
|
|
31
|
+
mint: PublicKey;
|
|
32
|
+
mintAuthority: PublicKey;
|
|
33
|
+
payer: PublicKey;
|
|
34
|
+
updateAuthority: PublicKey;
|
|
35
|
+
name: string;
|
|
36
|
+
symbol: string;
|
|
37
|
+
uri: string;
|
|
38
|
+
sellerFeeBasisPoints?: number;
|
|
39
|
+
creators?: Array<{
|
|
40
|
+
address: PublicKey;
|
|
41
|
+
verified: boolean;
|
|
42
|
+
share: number;
|
|
43
|
+
}> | null;
|
|
44
|
+
isMutable?: boolean;
|
|
45
|
+
}): TransactionInstruction;
|
|
46
|
+
/**
|
|
47
|
+
* 构建并签名创建 Metadata 交易
|
|
48
|
+
* @param connection Solana 连接
|
|
49
|
+
* @param params 参数
|
|
50
|
+
*/
|
|
51
|
+
export declare function signCreateMetadataTransaction(connection: Connection, params: {
|
|
52
|
+
mint: PublicKey;
|
|
53
|
+
mintAuthority: Keypair;
|
|
54
|
+
payer: Keypair;
|
|
55
|
+
name: string;
|
|
56
|
+
symbol: string;
|
|
57
|
+
uri: string;
|
|
58
|
+
sellerFeeBasisPoints?: number;
|
|
59
|
+
creators?: Array<{
|
|
60
|
+
address: PublicKey;
|
|
61
|
+
verified: boolean;
|
|
62
|
+
share: number;
|
|
63
|
+
}> | null;
|
|
64
|
+
isMutable?: boolean;
|
|
65
|
+
}): Promise<{
|
|
66
|
+
success: boolean;
|
|
67
|
+
metadataAddress?: string;
|
|
68
|
+
signedTransaction?: {
|
|
69
|
+
data: string;
|
|
70
|
+
signature: string;
|
|
71
|
+
};
|
|
72
|
+
error?: string;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* 构建 UpdateMetadataAccountV2 指令
|
|
76
|
+
*/
|
|
77
|
+
export declare function buildUpdateMetadataAccountV2Instruction(params: {
|
|
78
|
+
metadata: PublicKey;
|
|
79
|
+
updateAuthority: PublicKey;
|
|
80
|
+
newUpdateAuthority?: PublicKey | null;
|
|
81
|
+
name?: string;
|
|
82
|
+
symbol?: string;
|
|
83
|
+
uri?: string;
|
|
84
|
+
sellerFeeBasisPoints?: number;
|
|
85
|
+
creators?: Array<{
|
|
86
|
+
address: PublicKey;
|
|
87
|
+
verified: boolean;
|
|
88
|
+
share: number;
|
|
89
|
+
}> | null;
|
|
90
|
+
primarySaleHappened?: boolean;
|
|
91
|
+
isMutable?: boolean;
|
|
92
|
+
}): TransactionInstruction;
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metaplex Token Metadata 集成
|
|
3
|
+
* @module sol/token/metadata
|
|
4
|
+
*/
|
|
5
|
+
import { PublicKey, Transaction, TransactionInstruction, } from '@solana/web3.js';
|
|
6
|
+
import { SYSTEM_PROGRAMS } from '../constants.js';
|
|
7
|
+
// Metaplex Token Metadata Program ID
|
|
8
|
+
const TOKEN_METADATA_PROGRAM_ID = new PublicKey(SYSTEM_PROGRAMS.METADATA_PROGRAM);
|
|
9
|
+
/**
|
|
10
|
+
* 获取 Metadata PDA 地址
|
|
11
|
+
* @param mint Mint 地址
|
|
12
|
+
*/
|
|
13
|
+
export function getMetadataPDA(mint) {
|
|
14
|
+
const [pda] = PublicKey.findProgramAddressSync([
|
|
15
|
+
Buffer.from('metadata'),
|
|
16
|
+
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
|
|
17
|
+
mint.toBuffer(),
|
|
18
|
+
], TOKEN_METADATA_PROGRAM_ID);
|
|
19
|
+
return pda;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 构建 CreateMetadataAccountV3 指令
|
|
23
|
+
* 手动构建指令,避免 Metaplex SDK 版本兼容问题
|
|
24
|
+
*/
|
|
25
|
+
export function buildCreateMetadataAccountV3Instruction(params) {
|
|
26
|
+
const { metadata, mint, mintAuthority, payer, updateAuthority, name, symbol, uri, sellerFeeBasisPoints = 0, creators = null, isMutable = true, } = params;
|
|
27
|
+
// 构建指令数据
|
|
28
|
+
// CreateMetadataAccountV3 指令格式
|
|
29
|
+
const data = buildCreateMetadataV3Data({
|
|
30
|
+
name,
|
|
31
|
+
symbol,
|
|
32
|
+
uri,
|
|
33
|
+
sellerFeeBasisPoints,
|
|
34
|
+
creators,
|
|
35
|
+
isMutable,
|
|
36
|
+
});
|
|
37
|
+
return new TransactionInstruction({
|
|
38
|
+
keys: [
|
|
39
|
+
{ pubkey: metadata, isSigner: false, isWritable: true },
|
|
40
|
+
{ pubkey: mint, isSigner: false, isWritable: false },
|
|
41
|
+
{ pubkey: mintAuthority, isSigner: true, isWritable: false },
|
|
42
|
+
{ pubkey: payer, isSigner: true, isWritable: true },
|
|
43
|
+
{ pubkey: updateAuthority, isSigner: false, isWritable: false },
|
|
44
|
+
{ pubkey: new PublicKey(SYSTEM_PROGRAMS.SYSTEM_PROGRAM), isSigner: false, isWritable: false },
|
|
45
|
+
{ pubkey: new PublicKey(SYSTEM_PROGRAMS.RENT_SYSVAR), isSigner: false, isWritable: false },
|
|
46
|
+
],
|
|
47
|
+
programId: TOKEN_METADATA_PROGRAM_ID,
|
|
48
|
+
data,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 构建 CreateMetadataAccountV3 指令数据
|
|
53
|
+
*/
|
|
54
|
+
function buildCreateMetadataV3Data(params) {
|
|
55
|
+
const { name, symbol, uri, sellerFeeBasisPoints, creators, isMutable } = params;
|
|
56
|
+
// 指令判别器:CreateMetadataAccountV3 = 33
|
|
57
|
+
const discriminator = 33;
|
|
58
|
+
// 计算缓冲区大小
|
|
59
|
+
let size = 1; // discriminator
|
|
60
|
+
size += 4 + name.length; // name (string with u32 length prefix)
|
|
61
|
+
size += 4 + symbol.length; // symbol
|
|
62
|
+
size += 4 + uri.length; // uri
|
|
63
|
+
size += 2; // sellerFeeBasisPoints (u16)
|
|
64
|
+
size += 1; // creators option flag
|
|
65
|
+
if (creators) {
|
|
66
|
+
size += 4; // creators vec length
|
|
67
|
+
size += creators.length * (32 + 1 + 1); // each creator: pubkey + verified + share
|
|
68
|
+
}
|
|
69
|
+
size += 1; // collection option flag (None)
|
|
70
|
+
size += 1; // uses option flag (None)
|
|
71
|
+
size += 1; // isMutable
|
|
72
|
+
size += 1; // collectionDetails option flag (None)
|
|
73
|
+
const buffer = Buffer.alloc(size);
|
|
74
|
+
let offset = 0;
|
|
75
|
+
// 写入 discriminator
|
|
76
|
+
buffer.writeUInt8(discriminator, offset);
|
|
77
|
+
offset += 1;
|
|
78
|
+
// 写入 name
|
|
79
|
+
buffer.writeUInt32LE(name.length, offset);
|
|
80
|
+
offset += 4;
|
|
81
|
+
buffer.write(name, offset);
|
|
82
|
+
offset += name.length;
|
|
83
|
+
// 写入 symbol
|
|
84
|
+
buffer.writeUInt32LE(symbol.length, offset);
|
|
85
|
+
offset += 4;
|
|
86
|
+
buffer.write(symbol, offset);
|
|
87
|
+
offset += symbol.length;
|
|
88
|
+
// 写入 uri
|
|
89
|
+
buffer.writeUInt32LE(uri.length, offset);
|
|
90
|
+
offset += 4;
|
|
91
|
+
buffer.write(uri, offset);
|
|
92
|
+
offset += uri.length;
|
|
93
|
+
// 写入 sellerFeeBasisPoints
|
|
94
|
+
buffer.writeUInt16LE(sellerFeeBasisPoints, offset);
|
|
95
|
+
offset += 2;
|
|
96
|
+
// 写入 creators
|
|
97
|
+
if (creators && creators.length > 0) {
|
|
98
|
+
buffer.writeUInt8(1, offset); // Some
|
|
99
|
+
offset += 1;
|
|
100
|
+
buffer.writeUInt32LE(creators.length, offset);
|
|
101
|
+
offset += 4;
|
|
102
|
+
for (const creator of creators) {
|
|
103
|
+
creator.address.toBuffer().copy(buffer, offset);
|
|
104
|
+
offset += 32;
|
|
105
|
+
buffer.writeUInt8(creator.verified ? 1 : 0, offset);
|
|
106
|
+
offset += 1;
|
|
107
|
+
buffer.writeUInt8(creator.share, offset);
|
|
108
|
+
offset += 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
buffer.writeUInt8(0, offset); // None
|
|
113
|
+
offset += 1;
|
|
114
|
+
}
|
|
115
|
+
// 写入 collection (None)
|
|
116
|
+
buffer.writeUInt8(0, offset);
|
|
117
|
+
offset += 1;
|
|
118
|
+
// 写入 uses (None)
|
|
119
|
+
buffer.writeUInt8(0, offset);
|
|
120
|
+
offset += 1;
|
|
121
|
+
// 写入 isMutable
|
|
122
|
+
buffer.writeUInt8(isMutable ? 1 : 0, offset);
|
|
123
|
+
offset += 1;
|
|
124
|
+
// 写入 collectionDetails (None)
|
|
125
|
+
buffer.writeUInt8(0, offset);
|
|
126
|
+
offset += 1;
|
|
127
|
+
return buffer.slice(0, offset);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 构建并签名创建 Metadata 交易
|
|
131
|
+
* @param connection Solana 连接
|
|
132
|
+
* @param params 参数
|
|
133
|
+
*/
|
|
134
|
+
export async function signCreateMetadataTransaction(connection, params) {
|
|
135
|
+
try {
|
|
136
|
+
const { mint, mintAuthority, payer, name, symbol, uri, sellerFeeBasisPoints = 0, creators = null, isMutable = true, } = params;
|
|
137
|
+
// 获取 Metadata PDA
|
|
138
|
+
const metadataPDA = getMetadataPDA(mint);
|
|
139
|
+
// 获取 blockhash
|
|
140
|
+
const { blockhash } = await connection.getLatestBlockhash('finalized');
|
|
141
|
+
// 构建指令
|
|
142
|
+
const instruction = buildCreateMetadataAccountV3Instruction({
|
|
143
|
+
metadata: metadataPDA,
|
|
144
|
+
mint,
|
|
145
|
+
mintAuthority: mintAuthority.publicKey,
|
|
146
|
+
payer: payer.publicKey,
|
|
147
|
+
updateAuthority: mintAuthority.publicKey,
|
|
148
|
+
name,
|
|
149
|
+
symbol,
|
|
150
|
+
uri,
|
|
151
|
+
sellerFeeBasisPoints,
|
|
152
|
+
creators,
|
|
153
|
+
isMutable,
|
|
154
|
+
});
|
|
155
|
+
// 构建交易
|
|
156
|
+
const transaction = new Transaction();
|
|
157
|
+
transaction.add(instruction);
|
|
158
|
+
transaction.recentBlockhash = blockhash;
|
|
159
|
+
transaction.feePayer = payer.publicKey;
|
|
160
|
+
// 签名
|
|
161
|
+
const signers = [payer];
|
|
162
|
+
if (!payer.publicKey.equals(mintAuthority.publicKey)) {
|
|
163
|
+
signers.push(mintAuthority);
|
|
164
|
+
}
|
|
165
|
+
transaction.sign(...signers);
|
|
166
|
+
const serialized = transaction.serialize();
|
|
167
|
+
return {
|
|
168
|
+
success: true,
|
|
169
|
+
metadataAddress: metadataPDA.toBase58(),
|
|
170
|
+
signedTransaction: {
|
|
171
|
+
data: Buffer.from(serialized).toString('base64'),
|
|
172
|
+
signature: transaction.signature ? Buffer.from(transaction.signature).toString('base64') : '',
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
error: error.message,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 构建 UpdateMetadataAccountV2 指令
|
|
185
|
+
*/
|
|
186
|
+
export function buildUpdateMetadataAccountV2Instruction(params) {
|
|
187
|
+
const { metadata, updateAuthority, newUpdateAuthority, name, symbol, uri, sellerFeeBasisPoints, creators, primarySaleHappened, isMutable, } = params;
|
|
188
|
+
// UpdateMetadataAccountV2 指令格式
|
|
189
|
+
// discriminator = 15
|
|
190
|
+
const discriminator = 15;
|
|
191
|
+
// 简化版本:只构建基本的更新数据
|
|
192
|
+
// 完整实现需要更复杂的序列化
|
|
193
|
+
const dataBuffer = Buffer.alloc(1024);
|
|
194
|
+
let offset = 0;
|
|
195
|
+
dataBuffer.writeUInt8(discriminator, offset);
|
|
196
|
+
offset += 1;
|
|
197
|
+
// data option (Some if any field is provided)
|
|
198
|
+
const hasData = name || symbol || uri || sellerFeeBasisPoints !== undefined || creators;
|
|
199
|
+
dataBuffer.writeUInt8(hasData ? 1 : 0, offset);
|
|
200
|
+
offset += 1;
|
|
201
|
+
if (hasData) {
|
|
202
|
+
// name
|
|
203
|
+
const nameStr = name || '';
|
|
204
|
+
dataBuffer.writeUInt32LE(nameStr.length, offset);
|
|
205
|
+
offset += 4;
|
|
206
|
+
dataBuffer.write(nameStr, offset);
|
|
207
|
+
offset += nameStr.length;
|
|
208
|
+
// symbol
|
|
209
|
+
const symbolStr = symbol || '';
|
|
210
|
+
dataBuffer.writeUInt32LE(symbolStr.length, offset);
|
|
211
|
+
offset += 4;
|
|
212
|
+
dataBuffer.write(symbolStr, offset);
|
|
213
|
+
offset += symbolStr.length;
|
|
214
|
+
// uri
|
|
215
|
+
const uriStr = uri || '';
|
|
216
|
+
dataBuffer.writeUInt32LE(uriStr.length, offset);
|
|
217
|
+
offset += 4;
|
|
218
|
+
dataBuffer.write(uriStr, offset);
|
|
219
|
+
offset += uriStr.length;
|
|
220
|
+
// sellerFeeBasisPoints
|
|
221
|
+
dataBuffer.writeUInt16LE(sellerFeeBasisPoints || 0, offset);
|
|
222
|
+
offset += 2;
|
|
223
|
+
// creators (None for simplicity)
|
|
224
|
+
dataBuffer.writeUInt8(0, offset);
|
|
225
|
+
offset += 1;
|
|
226
|
+
// collection (None)
|
|
227
|
+
dataBuffer.writeUInt8(0, offset);
|
|
228
|
+
offset += 1;
|
|
229
|
+
// uses (None)
|
|
230
|
+
dataBuffer.writeUInt8(0, offset);
|
|
231
|
+
offset += 1;
|
|
232
|
+
}
|
|
233
|
+
// newUpdateAuthority option
|
|
234
|
+
if (newUpdateAuthority) {
|
|
235
|
+
dataBuffer.writeUInt8(1, offset);
|
|
236
|
+
offset += 1;
|
|
237
|
+
newUpdateAuthority.toBuffer().copy(dataBuffer, offset);
|
|
238
|
+
offset += 32;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
dataBuffer.writeUInt8(0, offset);
|
|
242
|
+
offset += 1;
|
|
243
|
+
}
|
|
244
|
+
// primarySaleHappened option
|
|
245
|
+
if (primarySaleHappened !== undefined) {
|
|
246
|
+
dataBuffer.writeUInt8(1, offset);
|
|
247
|
+
offset += 1;
|
|
248
|
+
dataBuffer.writeUInt8(primarySaleHappened ? 1 : 0, offset);
|
|
249
|
+
offset += 1;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
dataBuffer.writeUInt8(0, offset);
|
|
253
|
+
offset += 1;
|
|
254
|
+
}
|
|
255
|
+
// isMutable option
|
|
256
|
+
if (isMutable !== undefined) {
|
|
257
|
+
dataBuffer.writeUInt8(1, offset);
|
|
258
|
+
offset += 1;
|
|
259
|
+
dataBuffer.writeUInt8(isMutable ? 1 : 0, offset);
|
|
260
|
+
offset += 1;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
dataBuffer.writeUInt8(0, offset);
|
|
264
|
+
offset += 1;
|
|
265
|
+
}
|
|
266
|
+
return new TransactionInstruction({
|
|
267
|
+
keys: [
|
|
268
|
+
{ pubkey: metadata, isSigner: false, isWritable: true },
|
|
269
|
+
{ pubkey: updateAuthority, isSigner: true, isWritable: false },
|
|
270
|
+
],
|
|
271
|
+
programId: TOKEN_METADATA_PROGRAM_ID,
|
|
272
|
+
data: dataBuffer.slice(0, offset),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token 创建相关类型定义
|
|
3
|
+
* @module sol/token/types
|
|
4
|
+
*/
|
|
5
|
+
import { PublicKey, Keypair } from '@solana/web3.js';
|
|
6
|
+
/**
|
|
7
|
+
* 代币标准
|
|
8
|
+
*/
|
|
9
|
+
export type TokenStandard = 'SPL' | 'TOKEN_2022';
|
|
10
|
+
/**
|
|
11
|
+
* 代币元数据(符合 Metaplex 标准)
|
|
12
|
+
*/
|
|
13
|
+
export interface TokenMetadataInput {
|
|
14
|
+
/** 代币名称 */
|
|
15
|
+
name: string;
|
|
16
|
+
/** 代币符号 */
|
|
17
|
+
symbol: string;
|
|
18
|
+
/** 代币描述 */
|
|
19
|
+
description: string;
|
|
20
|
+
/** 图片 URL(IPFS 或 HTTP) */
|
|
21
|
+
image: string;
|
|
22
|
+
/** 外部链接 */
|
|
23
|
+
externalUrl?: string;
|
|
24
|
+
/** 属性 */
|
|
25
|
+
attributes?: Array<{
|
|
26
|
+
trait_type: string;
|
|
27
|
+
value: string | number;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 上传到 IPFS 的元数据 JSON 格式
|
|
32
|
+
*/
|
|
33
|
+
export interface TokenMetadataJson {
|
|
34
|
+
name: string;
|
|
35
|
+
symbol: string;
|
|
36
|
+
description: string;
|
|
37
|
+
image: string;
|
|
38
|
+
external_url?: string;
|
|
39
|
+
attributes?: Array<{
|
|
40
|
+
trait_type: string;
|
|
41
|
+
value: string | number;
|
|
42
|
+
}>;
|
|
43
|
+
properties?: {
|
|
44
|
+
files?: Array<{
|
|
45
|
+
uri: string;
|
|
46
|
+
type: string;
|
|
47
|
+
}>;
|
|
48
|
+
category?: string;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Token-2022 扩展功能
|
|
53
|
+
*/
|
|
54
|
+
export interface Token2022Extensions {
|
|
55
|
+
/** 转账手续费(基点,如 100 = 1%) */
|
|
56
|
+
transferFee?: {
|
|
57
|
+
feeBasisPoints: number;
|
|
58
|
+
maxFee: bigint;
|
|
59
|
+
};
|
|
60
|
+
/** 不可转让 */
|
|
61
|
+
nonTransferable?: boolean;
|
|
62
|
+
/** 利息 */
|
|
63
|
+
interestBearing?: {
|
|
64
|
+
rate: number;
|
|
65
|
+
};
|
|
66
|
+
/** 永久代理 */
|
|
67
|
+
permanentDelegate?: PublicKey;
|
|
68
|
+
/** 关闭权限 */
|
|
69
|
+
closeAuthority?: PublicKey;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 代币创建参数
|
|
73
|
+
*/
|
|
74
|
+
export interface CreateTokenParams {
|
|
75
|
+
/** 代币名称 */
|
|
76
|
+
name: string;
|
|
77
|
+
/** 代币符号 */
|
|
78
|
+
symbol: string;
|
|
79
|
+
/** 代币描述 */
|
|
80
|
+
description: string;
|
|
81
|
+
/** 精度(小数位数) */
|
|
82
|
+
decimals: number;
|
|
83
|
+
/** 初始供应量(不含精度,如 1000000 表示 100万) */
|
|
84
|
+
initialSupply: bigint;
|
|
85
|
+
/** 图片 Buffer(用于上传 IPFS) */
|
|
86
|
+
imageBuffer?: Buffer;
|
|
87
|
+
/** 图片文件名 */
|
|
88
|
+
imageFilename?: string;
|
|
89
|
+
/** 已上传的图片 URL(如果已有,则不需要 imageBuffer) */
|
|
90
|
+
imageUrl?: string;
|
|
91
|
+
/** 创建者 Keypair */
|
|
92
|
+
creator: Keypair;
|
|
93
|
+
/** Mint 权限(默认为 creator) */
|
|
94
|
+
mintAuthority?: PublicKey;
|
|
95
|
+
/** 冻结权限(null 表示不可冻结) */
|
|
96
|
+
freezeAuthority?: PublicKey | null;
|
|
97
|
+
/** 代币标准(默认 TOKEN_2022) */
|
|
98
|
+
tokenStandard?: TokenStandard;
|
|
99
|
+
/** Token-2022 扩展功能 */
|
|
100
|
+
extensions?: Token2022Extensions;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 代币创建结果
|
|
104
|
+
*/
|
|
105
|
+
export interface CreateTokenResult {
|
|
106
|
+
/** 是否成功 */
|
|
107
|
+
success: boolean;
|
|
108
|
+
/** Mint 地址 */
|
|
109
|
+
mint?: string;
|
|
110
|
+
/** Metadata 账户地址 */
|
|
111
|
+
metadataAddress?: string;
|
|
112
|
+
/** 元数据 URI(IPFS) */
|
|
113
|
+
metadataUri?: string;
|
|
114
|
+
/** 图片 URI(IPFS) */
|
|
115
|
+
imageUri?: string;
|
|
116
|
+
/** 签名后的交易数据(用于提交后端) */
|
|
117
|
+
signedTransactions?: Array<{
|
|
118
|
+
data: string;
|
|
119
|
+
signature: string;
|
|
120
|
+
description: string;
|
|
121
|
+
}>;
|
|
122
|
+
/** 错误信息 */
|
|
123
|
+
error?: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Mint To 参数
|
|
127
|
+
*/
|
|
128
|
+
export interface MintToParams {
|
|
129
|
+
/** Mint 地址 */
|
|
130
|
+
mint: string;
|
|
131
|
+
/** 目标地址 */
|
|
132
|
+
destination: string;
|
|
133
|
+
/** 数量(含精度) */
|
|
134
|
+
amount: bigint;
|
|
135
|
+
/** Mint 权限 Keypair */
|
|
136
|
+
mintAuthority: Keypair;
|
|
137
|
+
/** 代币标准 */
|
|
138
|
+
tokenStandard?: TokenStandard;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Mint To 结果
|
|
142
|
+
*/
|
|
143
|
+
export interface MintToResult {
|
|
144
|
+
success: boolean;
|
|
145
|
+
/** ATA 地址 */
|
|
146
|
+
ataAddress?: string;
|
|
147
|
+
/** 签名后的交易数据 */
|
|
148
|
+
signedTransaction?: {
|
|
149
|
+
data: string;
|
|
150
|
+
signature: string;
|
|
151
|
+
};
|
|
152
|
+
error?: string;
|
|
153
|
+
}
|