-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathbrc20.ts
93 lines (74 loc) · 2.93 KB
/
brc20.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
export const isValidContentType = (contentType: string) =>
contentType.startsWith('text/plain') || contentType.startsWith('application/json');
export const isValidFields = (parsedFields: string[], requiredFields: Set<string>, optionalFields?: Set<string>) =>
parsedFields.every((f) => requiredFields.has(f) || optionalFields?.has(f)) &&
[...requiredFields].every((f) => parsedFields.includes(f));
const isNumber = (value: string) => !Number.isNaN(Number(value));
export type Brc20Definition = {
op: 'deploy' | 'mint' | 'transfer';
tick: string;
value: string;
lim?: string;
dec?: string;
};
const utf8ByteSize = (str: string) => new Blob([str]).size;
export const isValidTick = (ticker: string): boolean => utf8ByteSize(ticker) >= 4 && utf8ByteSize(ticker) <= 5;
// brc-20 protocol
// - p (protocol): brc-20
// - op (operation): deploy
// - tick (ticker/token identifier): vers
// - max (supply): xxxxx
// - lim (mint limit for each inbscription): xx - optional
// - dec (decimal): 18 - optional
export const getBrc20Details = (content?: string, contentType?: string): undefined | Brc20Definition => {
if (!content || !contentType) {
return undefined;
}
if (!isValidContentType(contentType)) {
return undefined;
}
try {
const parsedContent = JSON.parse(content);
if (parsedContent.p !== 'brc-20' || !['deploy', 'mint', 'transfer'].includes(parsedContent.op)) {
return undefined;
}
const parsedFields = Object.keys(parsedContent);
const parsedValues = Object.values(parsedContent);
if (parsedValues.some((v) => typeof v !== 'string')) {
return undefined;
}
const deployRequiredFields = new Set(['p', 'op', 'tick', 'max']);
const deployOptionalFields = new Set(['lim', 'dec']);
const mintRequiredFields = new Set(['p', 'op', 'tick', 'amt']);
const transferRequiredFields = new Set(['p', 'op', 'tick', 'amt']);
const isValidDeploy =
parsedContent.op === 'deploy' &&
isValidFields(parsedFields, deployRequiredFields, deployOptionalFields) &&
isValidTick(parsedContent.tick) &&
isNumber(parsedContent.max) &&
(!parsedContent.lim || isNumber(parsedContent.lim)) &&
(!parsedContent.dec || isNumber(parsedContent.dec));
const isValidMint =
parsedContent.op === 'mint' &&
isValidFields(parsedFields, mintRequiredFields) &&
isValidTick(parsedContent.tick) &&
isNumber(parsedContent.amt);
const isValidTransfer =
parsedContent.op === 'transfer' &&
isValidFields(parsedFields, transferRequiredFields) &&
isValidTick(parsedContent.tick) &&
isNumber(parsedContent.amt);
if (!isValidDeploy && !isValidMint && !isValidTransfer) {
return undefined;
}
return {
op: parsedContent.op,
tick: parsedContent.tick.toUpperCase(),
value: parsedContent.max || parsedContent.amt,
lim: parsedContent.lim,
dec: parsedContent.dec,
};
} catch (e) {
return undefined;
}
};