/
Metadata.ts
218 lines (189 loc) · 6.57 KB
/
Metadata.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import {
ProgrammableConfig,
TokenStandard,
UseMethod,
} from '@metaplex-foundation/mpl-token-metadata';
import { PublicKey } from '@solana/web3.js';
import { MetadataAccount } from '../accounts';
import { JsonMetadata } from './JsonMetadata';
import { assert, Option, removeEmptyChars } from '@/utils';
import {
BigNumber,
Creator,
Pda,
toBigNumber,
ReadApiCompressionMetadata,
} from '@/types';
/** @group Models */
export type Metadata<Json extends object = JsonMetadata> = {
/** A model identifier to distinguish models in the SDK. */
readonly model: 'metadata';
/** The address of the Metadata account. */
readonly address: Pda;
/** The address of the Mint account. */
readonly mintAddress: PublicKey;
/**
* The address of the authority that is allowed
* to make changes to the Metadata account.
*/
readonly updateAuthorityAddress: PublicKey;
/** The JSON metadata associated with the metadata account. */
readonly json: Option<Json>;
/**
* Whether or not the JSON metadata was loaded in the first place.
* When this is `false`, the `json` property is should be ignored.
*/
readonly jsonLoaded: boolean;
/**
* The on-chain name of the asset, stored in the Metadata account.
* E.g. "My NFT #123"
*/
readonly name: string;
/**
* The on-chain symbol of the asset, stored in the Metadata account.
* E.g. "MYNFT"
*/
readonly symbol: string;
/**
* The URI that points to the JSON metadata of the asset.
* This URI is used to load the `json` property of this object.
*/
readonly uri: string;
/**
* Whether or not the asset is mutable.
* When set to `false` no one can update the Metadata account,
* not even the update authority.
*/
readonly isMutable: boolean;
/**
* Whether or not the asset has already been sold to its first buyer.
* When set to `false`, all royalties should be paid to the creators.
* When set to `true`, royalties should be calculate as usual.
*/
readonly primarySaleHappened: boolean;
/**
* The royalties in percent basis point (i.e. 250 is 2.5%) that
* should be paid to the creators on each secondary sale.
*/
readonly sellerFeeBasisPoints: number;
/** Stores the bump of the edition PDA. */
readonly editionNonce: Option<number>;
/**
* The creators of the asset.
* Each object within the array contains the address,
* the shares in percent (i.e. 5 is 5%) and whether or not the
* creator is verified (i.e. they signed the asset).
*/
readonly creators: Creator[];
/**
* This enum indicates which type of asset we are dealing with.
* It can be an NFT, a limited edition of an original NFT,
* a fungible asset (i.e. it has zero decimals)
* or a fungible token (i.e. it has more than zero decimals).
*/
readonly tokenStandard: Option<TokenStandard>;
/**
* The parent collection the asset belongs to.
*/
readonly collection: Option<{
/** The mint address of the collection asset. */
address: PublicKey;
/**
* Whether a collection authority signed this asset to
* ensure it is part of the collection.
* If `verified` is `false`, you should not trust
* the asset as being part of the collection.
*/
verified: boolean;
}>;
/**
* When this field is not `null`, it indicates that
* the asset is a collection. Every time an asset is
* verified/unverified as part of this collection,
* the `size` field inside this object will be updated accordingly.
*/
readonly collectionDetails: Option<{
/** The collection details version. For now, there's only one version. */
version: 'V1';
/** The size of the collection, automatically kept up-to-date by the program. */
size: BigNumber;
}>;
/**
* When this field is not `null`, it indicates that the asset
* can be "used" by its owner or any approved "use authorities".
*/
readonly uses: Option<{
/** An enum selecting a strategy for using the asset. */
useMethod: UseMethod;
/** The amount of remaining uses. */
remaining: BigNumber;
/** The total amount of uses that was initially allowed. */
total: BigNumber;
}>;
/** Programmable configuration for the asset. */
readonly programmableConfig: Option<ProgrammableConfig>;
/* Compression metadata only provided via the ReadApi */
readonly compression?: ReadApiCompressionMetadata;
};
/** @group Model Helpers */
export const isMetadata = (value: any): value is Metadata =>
typeof value === 'object' && value.model === 'metadata';
/** @group Model Helpers */
export function assertMetadata(value: any): asserts value is Metadata {
assert(isMetadata(value), `Expected Metadata model`);
}
/** @group Model Helpers */
export const toMetadata = (
account: MetadataAccount,
json?: Option<JsonMetadata>
): Metadata => ({
model: 'metadata',
address: Pda.find(account.owner, [
Buffer.from('metadata', 'utf8'),
account.owner.toBuffer(),
account.data.mint.toBuffer(),
]),
mintAddress: account.data.mint,
updateAuthorityAddress: account.data.updateAuthority,
json: json ?? null,
jsonLoaded: json !== undefined,
name: removeEmptyChars(account.data.data.name),
symbol: removeEmptyChars(account.data.data.symbol),
uri: removeEmptyChars(account.data.data.uri),
isMutable: account.data.isMutable,
primarySaleHappened: account.data.primarySaleHappened,
sellerFeeBasisPoints: account.data.data.sellerFeeBasisPoints,
editionNonce: account.data.editionNonce,
creators: account.data.data.creators ?? [],
tokenStandard: account.data.tokenStandard,
collection: account.data.collection
? {
...account.data.collection,
address: account.data.collection.key,
}
: null,
collectionDetails: account.data.collectionDetails
? {
version: account.data.collectionDetails.__kind,
size: toBigNumber(account.data.collectionDetails.size),
}
: null,
uses: account.data.uses
? {
...account.data.uses,
remaining: toBigNumber(account.data.uses.remaining),
total: toBigNumber(account.data.uses.total),
}
: null,
programmableConfig: account.data.programmableConfig,
});
export const isNonFungible = (nftOrSft: {
tokenStandard: Option<TokenStandard>;
}): boolean =>
nftOrSft.tokenStandard === null ||
nftOrSft.tokenStandard === TokenStandard.NonFungible ||
nftOrSft.tokenStandard === TokenStandard.NonFungibleEdition ||
nftOrSft.tokenStandard === TokenStandard.ProgrammableNonFungible;
export const isProgrammable = (nftOrSft: {
tokenStandard: Option<TokenStandard>;
}): boolean => nftOrSft.tokenStandard === TokenStandard.ProgrammableNonFungible;