dxs-stas-sdk 1.0.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.
Files changed (49) hide show
  1. package/jest.config.js +6 -0
  2. package/package.json +38 -0
  3. package/rollup.config.ts +26 -0
  4. package/src/base.ts +4 -0
  5. package/src/bitcoin/address.ts +42 -0
  6. package/src/bitcoin/destination.ts +7 -0
  7. package/src/bitcoin/index.ts +15 -0
  8. package/src/bitcoin/mnemonic.ts +40 -0
  9. package/src/bitcoin/network.ts +11 -0
  10. package/src/bitcoin/op-codes.ts +143 -0
  11. package/src/bitcoin/out-point.ts +61 -0
  12. package/src/bitcoin/payment.ts +8 -0
  13. package/src/bitcoin/private-key.ts +57 -0
  14. package/src/bitcoin/script-type.ts +9 -0
  15. package/src/bitcoin/sig-hash-type.ts +7 -0
  16. package/src/bitcoin/token-scheme.ts +28 -0
  17. package/src/bitcoin/transaction-input.ts +33 -0
  18. package/src/bitcoin/transaction-output.ts +105 -0
  19. package/src/bitcoin/transaction.ts +31 -0
  20. package/src/bitcoin/wallet.ts +59 -0
  21. package/src/buffer/buffer-reader.ts +88 -0
  22. package/src/buffer/buffer-utils.ts +116 -0
  23. package/src/buffer/buffer-writer.ts +74 -0
  24. package/src/buffer/index.ts +3 -0
  25. package/src/hashes.ts +13 -0
  26. package/src/index.ts +8 -0
  27. package/src/script/build/null-data-builder.ts +21 -0
  28. package/src/script/build/p2pkh-builder.ts +34 -0
  29. package/src/script/build/p2stas-builder.ts +38 -0
  30. package/src/script/build/script-builder.ts +128 -0
  31. package/src/script/index.ts +10 -0
  32. package/src/script/read/script-reader.ts +79 -0
  33. package/src/script/script-samples.ts +27 -0
  34. package/src/script/script-token.ts +66 -0
  35. package/src/script/script-utils.ts +12 -0
  36. package/src/stas-bundle-factory.ts +367 -0
  37. package/src/transaction/build/input-builder.ts +270 -0
  38. package/src/transaction/build/output-builder.ts +25 -0
  39. package/src/transaction/build/transaction-builder.ts +163 -0
  40. package/src/transaction/index.ts +4 -0
  41. package/src/transaction/read/transaction-reader.ts +54 -0
  42. package/src/transaction-factory.ts +221 -0
  43. package/tests/script-build.test.ts +41 -0
  44. package/tests/script-read.test.ts +34 -0
  45. package/tests/stas-transactios.ts +41 -0
  46. package/tests/transaction-build.test.ts +394 -0
  47. package/tests/transaction-reader.test.ts +50 -0
  48. package/tsconfig.json +110 -0
  49. package/tslint.json +3 -0
package/jest.config.js ADDED
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ transform: { "^.+\\.ts?$": "ts-jest" },
3
+ testEnvironment: "node",
4
+ testRegex: "/tests/.*\\.(test|spec)?\\.(ts|tsx)$",
5
+ moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
6
+ };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "dxs-stas-sdk",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "dxs.stas.sdk.ts",
6
+ "scripts": {
7
+ "test": "jest",
8
+ "start": "tsnd ./src/index.ts",
9
+ "publish": "rollup -c rollup.config.ts -w --configPlugin typescript"
10
+ },
11
+ "directories": {
12
+ "test": "tests"
13
+ },
14
+ "author": "oleg@dxs.app",
15
+ "license": "MIT",
16
+ "devDependencies": {
17
+ "@rollup/plugin-commonjs": "^24.0.0",
18
+ "@rollup/plugin-node-resolve": "^15.0.1",
19
+ "@rollup/plugin-typescript": "^11.0.0",
20
+ "@types/jest": "^29.2.5",
21
+ "@types/typedarray-to-buffer": "^4.0.0",
22
+ "jest": "^29.3.1",
23
+ "rollup": "^3.10.0",
24
+ "ts-jest": "^29.0.5",
25
+ "ts-node-dev": "^2.0.0",
26
+ "tslib": "^2.4.1",
27
+ "tslint-config-prettier": "^1.18.0"
28
+ },
29
+ "dependencies": {
30
+ "@noble/hashes": "^1.2.0",
31
+ "@noble/secp256k1": "^1.7.1",
32
+ "@scure/base": "^1.1.1",
33
+ "@scure/bip32": "^1.1.5",
34
+ "@scure/bip39": "^1.1.1",
35
+ "buffer": "^6.0.3",
36
+ "typedarray-to-buffer": "^4.0.0"
37
+ }
38
+ }
@@ -0,0 +1,26 @@
1
+ import resolve from "@rollup/plugin-node-resolve";
2
+ import commonjs from "@rollup/plugin-commonjs";
3
+ import typescript from "@rollup/plugin-typescript";
4
+
5
+ export default {
6
+ input: `src/index.ts`,
7
+ output: [
8
+ {
9
+ file: "./dist/dxs.stas.sdk.js",
10
+ format: "cjs",
11
+ treeshake: true,
12
+ sourcemap: true,
13
+ },
14
+ ],
15
+ watch: {
16
+ include: "src/**",
17
+ },
18
+ plugins: [
19
+ commonjs(),
20
+ typescript(),
21
+ resolve({
22
+ preferBuiltins: true,
23
+ extensions: [".mjs", ".js", ".json", ".node", ".ts"],
24
+ }),
25
+ ],
26
+ };
package/src/base.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { sha256 } from "@noble/hashes/sha256";
2
+ import { base58check } from "@scure/base";
3
+
4
+ export const bs58check = base58check(sha256);
@@ -0,0 +1,42 @@
1
+ import { bs58check } from "../base";
2
+ import { toBuffer } from "../buffer/buffer-utils";
3
+ import { hash160 } from "../hashes";
4
+ import { Network, Networks } from "./network";
5
+
6
+ export class Address {
7
+ Value: string;
8
+ Hash160: Buffer;
9
+ Network: Network = Networks.Mainnet;
10
+
11
+ /*
12
+ Only p2pkh and mainnet supports now
13
+ */
14
+ constructor(hash160: Buffer) {
15
+ if (hash160.length !== 20) throw new Error("Invalid hash160");
16
+
17
+ const buffer = Buffer.allocUnsafe(21);
18
+
19
+ buffer.writeUInt8(this.Network.pubKeyHash, 0);
20
+ hash160.copy(buffer, 1);
21
+
22
+ this.Value = bs58check.encode(buffer);
23
+ this.Hash160 = hash160;
24
+ }
25
+
26
+ static fromBase58 = (address: string) => {
27
+ const buffer = toBuffer(bs58check.decode(address));
28
+
29
+ if (buffer[0] !== Networks.Mainnet.pubKeyHash)
30
+ throw new Error("Only mainnet supported");
31
+
32
+ const hash160 = Buffer.allocUnsafe(20);
33
+ buffer.copy(hash160, 0, 1);
34
+
35
+ return new Address(hash160);
36
+ };
37
+
38
+ static fromPublicKey = (publicKey: Buffer) => new Address(hash160(publicKey));
39
+
40
+ static fromHash160Hex = (hash160: string) =>
41
+ new Address(Buffer.from(hash160, "hex"));
42
+ }
@@ -0,0 +1,7 @@
1
+ import { Address } from "./address";
2
+
3
+ export type TDestination = {
4
+ Address: Address;
5
+ Satoshis: number;
6
+ Data?: Buffer[];
7
+ };
@@ -0,0 +1,15 @@
1
+ export * from "./address";
2
+ export * from "./destination";
3
+ export * from "./mnemonic";
4
+ export * from "./network";
5
+ export * from "./op-codes";
6
+ export * from "./out-point";
7
+ export * from "./payment";
8
+ export * from "./private-key";
9
+ export * from "./script-type";
10
+ export * from "./sig-hash-type";
11
+ export * from "./token-scheme";
12
+ export * from "./transaction-input";
13
+ export * from "./transaction-output";
14
+ export * from "./transaction";
15
+ export * from "./wallet";
@@ -0,0 +1,40 @@
1
+ import { generateMnemonic, validateMnemonic } from "@scure/bip39";
2
+ import { wordlist } from "@scure/bip39/wordlists/english";
3
+
4
+ export { wordlist } from "@scure/bip39/wordlists/english";
5
+
6
+ export type TWords = { [idxs: string]: string };
7
+
8
+ export class Mnemonic {
9
+ constructor(public phrase: string, public words: TWords) {}
10
+
11
+ public static generate = (): Mnemonic =>
12
+ Mnemonic.fromPhrase(generateMnemonic(wordlist, 128));
13
+
14
+ public static fromWords = (words: TWords): Mnemonic => {
15
+ var phrase = Object.values(words).join(" ");
16
+
17
+ return new Mnemonic(phrase, words);
18
+ };
19
+
20
+ public static fromPhrase = (phrase: string): Mnemonic => {
21
+ var words = phrase.split(" ").reduce<TWords>((a, v, i) => {
22
+ a[`${i}`] = v;
23
+
24
+ return a;
25
+ }, {});
26
+
27
+ return new Mnemonic(phrase, words);
28
+ };
29
+
30
+ public static fromRandomText = (text: string): Mnemonic | undefined => {
31
+ const sanitized = text
32
+ .replace(/\r?\n|\r/g, " ")
33
+ .replace(/\s{2,}/g, " ")
34
+ .replace(/^\s+/, "")
35
+ .replace(/\s+$/, "");
36
+
37
+ if (validateMnemonic(sanitized, wordlist))
38
+ return Mnemonic.fromPhrase(sanitized);
39
+ };
40
+ }
@@ -0,0 +1,11 @@
1
+ export type Network = {
2
+ pubKeyHash: number;
3
+ wif: number;
4
+ };
5
+
6
+ export const Networks: { [name: string]: Network } = {
7
+ Mainnet: {
8
+ pubKeyHash: 0x00,
9
+ wif: 0x80,
10
+ },
11
+ };
@@ -0,0 +1,143 @@
1
+ export enum OpCode {
2
+ // push value
3
+ OP_0 = 0x00,
4
+ OP_PUSHDATA1 = 0x4c,
5
+ OP_PUSHDATA2 = 0x4d,
6
+ OP_PUSHDATA4 = 0x4e,
7
+ OP_1NEGATE = 0x4f,
8
+ OP_RESERVED = 0x50,
9
+ OP_TRUE = 0x51,
10
+ OP_1 = 0x51,
11
+ OP_2 = 0x52,
12
+ OP_3 = 0x53,
13
+ OP_4 = 0x54,
14
+ OP_5 = 0x55,
15
+ OP_6 = 0x56,
16
+ OP_7 = 0x57,
17
+ OP_8 = 0x58,
18
+ OP_9 = 0x59,
19
+ OP_10 = 0x5a,
20
+ OP_11 = 0x5b,
21
+ OP_12 = 0x5c,
22
+ OP_13 = 0x5d,
23
+ OP_14 = 0x5e,
24
+ OP_15 = 0x5f,
25
+ OP_16 = 0x60,
26
+
27
+ // control
28
+ OP_NOP = 0x61,
29
+ OP_VER = 0x62,
30
+ OP_IF = 0x63,
31
+ OP_NOTIF = 0x64,
32
+ OP_VERIF = 0x65,
33
+ OP_VERNOTIF = 0x66,
34
+ OP_ELSE = 0x67,
35
+ OP_ENDIF = 0x68,
36
+ OP_VERIFY = 0x69,
37
+ OP_RETURN = 0x6a,
38
+
39
+ // stack ops
40
+ OP_TOALTSTACK = 0x6b,
41
+ OP_FROMALTSTACK = 0x6c,
42
+ OP_2DROP = 0x6d,
43
+ OP_2DUP = 0x6e,
44
+ OP_3DUP = 0x6f,
45
+ OP_2OVER = 0x70,
46
+ OP_2ROT = 0x71,
47
+ OP_2SWAP = 0x72,
48
+ OP_IFDUP = 0x73,
49
+ OP_DEPTH = 0x74,
50
+ OP_DROP = 0x75,
51
+ OP_DUP = 0x76,
52
+ OP_NIP = 0x77,
53
+ OP_OVER = 0x78,
54
+ OP_PICK = 0x79,
55
+ OP_ROLL = 0x7a,
56
+ OP_ROT = 0x7b,
57
+ OP_SWAP = 0x7c,
58
+ OP_TUCK = 0x7d,
59
+
60
+ // data manipulation ops
61
+ OP_CAT = 0x7e,
62
+ OP_SPLIT = 0x7f,
63
+ OP_NUM2BIN = 0x80,
64
+ OP_BIN2NUM = 0x81,
65
+ OP_SIZE = 0x82,
66
+
67
+ // bit logic
68
+ OP_INVERT = 0x83,
69
+ OP_AND = 0x84,
70
+ OP_OR = 0x85,
71
+ OP_XOR = 0x86,
72
+ OP_EQUAL = 0x87,
73
+ OP_EQUALVERIFY = 0x88,
74
+ OP_RESERVED1 = 0x89,
75
+ OP_RESERVED2 = 0x8a,
76
+
77
+ // numeric
78
+ OP_1ADD = 0x8b,
79
+ OP_1SUB = 0x8c,
80
+ OP_2MUL = 0x8d,
81
+ OP_2DIV = 0x8e,
82
+ OP_NEGATE = 0x8f,
83
+ OP_ABS = 0x90,
84
+ OP_NOT = 0x91,
85
+ OP_0NOTEQUAL = 0x92,
86
+
87
+ OP_ADD = 0x93,
88
+ OP_SUB = 0x94,
89
+ OP_MUL = 0x95,
90
+ OP_DIV = 0x96,
91
+ OP_MOD = 0x97,
92
+ OP_LSHIFT = 0x98,
93
+ OP_RSHIFT = 0x99,
94
+
95
+ OP_BOOLAND = 0x9a,
96
+ OP_BOOLOR = 0x9b,
97
+ OP_NUMEQUAL = 0x9c,
98
+ OP_NUMEQUALVERIFY = 0x9d,
99
+ OP_NUMNOTEQUAL = 0x9e,
100
+ OP_LESSTHAN = 0x9f,
101
+ OP_GREATERTHAN = 0xa0,
102
+ OP_LESSTHANOREQUAL = 0xa1,
103
+ OP_GREATERTHANOREQUAL = 0xa2,
104
+ OP_MIN = 0xa3,
105
+ OP_MAX = 0xa4,
106
+
107
+ OP_WITHIN = 0xa5,
108
+
109
+ // crypto
110
+ OP_RIPEMD160 = 0xa6,
111
+ OP_SHA1 = 0xa7,
112
+ OP_SHA256 = 0xa8,
113
+ OP_HASH160 = 0xa9,
114
+ OP_HASH256 = 0xaa,
115
+ OP_CODESEPARATOR = 0xab,
116
+ OP_CHECKSIG = 0xac,
117
+ OP_CHECKSIGVERIFY = 0xad,
118
+ OP_CHECKMULTISIG = 0xae,
119
+ OP_CHECKMULTISIGVERIFY = 0xaf,
120
+
121
+ // expansion
122
+ OP_NOP1 = 0xb0,
123
+ OP_NOP2 = 0xb1,
124
+ OP_CHECKLOCKTIMEVERIFY = 0xb1,
125
+ OP_NOP3 = 0xb2,
126
+ OP_CHECKSEQUENCEVERIFY = 0xb2,
127
+ OP_NOP4 = 0xb3,
128
+ OP_NOP5 = 0xb4,
129
+ OP_NOP6 = 0xb5,
130
+ OP_NOP7 = 0xb6,
131
+ OP_NOP8 = 0xb7,
132
+ OP_NOP9 = 0xb8,
133
+ OP_NOP10 = 0xb9,
134
+
135
+ // template matching params
136
+ OP_SMALLDATA = 0xf9,
137
+ OP_SMALLINTEGER = 0xfa,
138
+ OP_PUBKEYS = 0xfb,
139
+ OP_PUBKEYHASH = 0xfd,
140
+ OP_PUBKEY = 0xfe,
141
+
142
+ OP_INVALIDOPCODE = 0xff,
143
+ }
@@ -0,0 +1,61 @@
1
+ import { TransactionReader } from "../transaction";
2
+ import { Address } from "./address";
3
+ import { ScriptType } from "./script-type";
4
+ import { Transaction } from "./transaction";
5
+
6
+ export class OutPoint {
7
+ TxId: string;
8
+ Vout: number;
9
+ LockignScript: Buffer;
10
+ Satoshis: number;
11
+ Address: Address;
12
+ ScriptType: ScriptType;
13
+ Transaction?: Transaction;
14
+
15
+ constructor(
16
+ txId: string,
17
+ vout: number,
18
+ lockignScript: Buffer,
19
+ satoshis: number,
20
+ address: Address,
21
+ scriptType: ScriptType
22
+ ) {
23
+ this.TxId = txId;
24
+ this.Vout = vout;
25
+ this.LockignScript = lockignScript;
26
+ this.Satoshis = satoshis;
27
+ this.Address = address;
28
+ this.ScriptType = scriptType;
29
+ }
30
+
31
+ static fromTransaction = (transaction: Transaction, vout: number) =>
32
+ new OutPointFull(transaction, vout);
33
+
34
+ static fromHex = (hex: string, vout: number) =>
35
+ new OutPointFull(TransactionReader.readHex(hex), vout);
36
+
37
+ toString = () => `${this.TxId}:${this.Vout}`;
38
+ }
39
+
40
+ export class OutPointFull extends OutPoint {
41
+ constructor(transaction: Transaction, vout: number) {
42
+ const output = transaction.Outputs[vout];
43
+
44
+ if (
45
+ output.ScriptType !== ScriptType.p2pkh &&
46
+ output.ScriptType !== ScriptType.p2stas
47
+ )
48
+ throw new Error("p2pkh or p2stat output must be provided");
49
+
50
+ super(
51
+ transaction.Id,
52
+ vout,
53
+ output.LockignScript,
54
+ output.Satoshis,
55
+ output.Address!,
56
+ output.ScriptType
57
+ );
58
+
59
+ this.Transaction = transaction;
60
+ }
61
+ }
@@ -0,0 +1,8 @@
1
+ import { OutPoint } from "./out-point";
2
+ import { PrivateKey } from "./private-key";
3
+ import { Wallet } from "./wallet";
4
+
5
+ export type TPayment = {
6
+ OutPoint: OutPoint;
7
+ Owner: PrivateKey | Wallet;
8
+ };
@@ -0,0 +1,57 @@
1
+ import {
2
+ getPublicKey,
3
+ Signature,
4
+ signSync,
5
+ utils,
6
+ verify,
7
+ } from "@noble/secp256k1";
8
+ import { hmac } from "@noble/hashes/hmac";
9
+ import { sha256 } from "@noble/hashes/sha256";
10
+ import { getChunkSize, toBuffer } from "../buffer/buffer-utils";
11
+ import { Address } from "./address";
12
+ import { BufferWriter } from "../buffer";
13
+ import { hash256 } from "../hashes";
14
+
15
+ export { verify } from "@noble/secp256k1";
16
+
17
+ utils.hmacSha256Sync = (key, ...msgs) =>
18
+ hmac(sha256, key, utils.concatBytes(...msgs));
19
+
20
+ utils.sha256Sync = (...msgs) => sha256(utils.concatBytes(...msgs));
21
+
22
+ export class PrivateKey {
23
+ private _pk: Buffer;
24
+
25
+ Address: Address;
26
+ PublicKey: Buffer;
27
+
28
+ constructor(pk: Buffer) {
29
+ this._pk = pk;
30
+ this.PublicKey = toBuffer(getPublicKey(this._pk, true));
31
+ this.Address = Address.fromPublicKey(toBuffer(this.PublicKey));
32
+ }
33
+
34
+ sign = (message: Uint8Array) =>
35
+ toBuffer(signSync(message, this._pk, { der: true }));
36
+
37
+ verify = (signature: Buffer, message: Buffer) =>
38
+ verify(signature, message, this.PublicKey);
39
+ }
40
+
41
+ export const verifyBitcoinSignedMessage = (
42
+ message: Buffer,
43
+ publicKey: Buffer,
44
+ signature: Buffer
45
+ ) => {
46
+ const prefix = Buffer.from("Bitcoin Signed Message:\n");
47
+ const writer = BufferWriter.fromSize(
48
+ getChunkSize(prefix) + getChunkSize(message)
49
+ );
50
+
51
+ writer.writeVarChunk(prefix);
52
+ writer.writeVarChunk(message);
53
+
54
+ const sig = Signature.fromCompact(signature);
55
+
56
+ return verify(sig, hash256(writer.buffer), publicKey);
57
+ };
@@ -0,0 +1,9 @@
1
+ export enum ScriptType {
2
+ unknown = 0,
3
+ p2pk = 1,
4
+ p2pkh = 2,
5
+ p2sh = 3,
6
+ p2ms = 4,
7
+ nullData = 5,
8
+ p2stas = 6,
9
+ }
@@ -0,0 +1,7 @@
1
+ export enum SignatureHashType {
2
+ SIGHASH_ALL = 0x01,
3
+ SIGHASH_NONE = 0x02,
4
+ SIGHASH_SINGLE = 0x03,
5
+ SIGHASH_FORKID = 0x40,
6
+ SIGHASH_ANYONECANPAY = 0x80,
7
+ }
@@ -0,0 +1,28 @@
1
+ export class TokenScheme {
2
+ Name: string;
3
+ TokenId: string;
4
+ Symbol: string;
5
+ SatoshisPerToken: number;
6
+
7
+ constructor(
8
+ name: string,
9
+ tokenId: string,
10
+ symbol: string,
11
+ satoshisPerToken: number
12
+ ) {
13
+ this.Name = name;
14
+ this.TokenId = tokenId;
15
+ this.Symbol = symbol;
16
+ this.SatoshisPerToken = satoshisPerToken;
17
+ }
18
+
19
+ toJson = () =>
20
+ JSON.stringify({
21
+ name: this.Name,
22
+ tokenId: this.TokenId,
23
+ symbol: this.Symbol,
24
+ satoshisPerToken: this.SatoshisPerToken,
25
+ });
26
+
27
+ toBuffer = () => Buffer.from(this.toJson(), "utf8");
28
+ }
@@ -0,0 +1,33 @@
1
+ import { ScriptReader } from "../script/read/script-reader";
2
+ import { Address } from "./address";
3
+
4
+ export class TransactionInput {
5
+ TxId: string;
6
+ Vout: number;
7
+ UnlockingScript: Buffer;
8
+ Sequence: number;
9
+
10
+ constructor(
11
+ txId: string,
12
+ vout: number,
13
+ unlockingScript: Buffer,
14
+ sequence: number
15
+ ) {
16
+ this.TxId = txId;
17
+ this.Vout = vout;
18
+ this.UnlockingScript = unlockingScript;
19
+ this.Sequence = sequence;
20
+ }
21
+
22
+ tryGetAddress = () => {
23
+ const scriptTokens = ScriptReader.read(this.UnlockingScript);
24
+ const lastToken = scriptTokens[scriptTokens.length - 1];
25
+
26
+ if (
27
+ lastToken.DataLength === 33 &&
28
+ (lastToken.Data![0] === 2 || lastToken.Data![0] === 3)
29
+ ) {
30
+ return Address.fromPublicKey(lastToken.Data!);
31
+ }
32
+ };
33
+ }
@@ -0,0 +1,105 @@
1
+ import { ScriptReader } from "../script/read/script-reader";
2
+ import { p2phkTokens, getP2stasTokens } from "../script/script-samples";
3
+ import { ScriptToken } from "../script/script-token";
4
+ import { Address } from "./address";
5
+ import { OpCode } from "./op-codes";
6
+ import { ScriptType } from "./script-type";
7
+
8
+ export class TransactionOutput {
9
+ Satoshis: number;
10
+ LockignScript: Buffer;
11
+ ScriptType: ScriptType = ScriptType.unknown;
12
+ Address?: Address;
13
+ TokenId?: string;
14
+ Symbol?: string;
15
+ data: Buffer[] = [];
16
+
17
+ constructor(satoshis: number, lockignScript: Buffer) {
18
+ this.Satoshis = satoshis;
19
+ this.LockignScript = lockignScript;
20
+
21
+ const scriptTokens = ScriptReader.read(this.LockignScript);
22
+
23
+ if (!this._isNulData(scriptTokens)) {
24
+ if (!this._isP2pkh(scriptTokens)) {
25
+ this._isP2stas(scriptTokens);
26
+ }
27
+ }
28
+ }
29
+
30
+ private _isNulData = (scriptTokens: ScriptToken[]): boolean => {
31
+ if (
32
+ scriptTokens.length > 2 &&
33
+ scriptTokens[0].OpCodeNum === OpCode.OP_0 &&
34
+ scriptTokens[1].OpCodeNum === OpCode.OP_RETURN
35
+ ) {
36
+ for (let i = 2; i < scriptTokens.length; i++)
37
+ this.data.push(scriptTokens[i].Data!);
38
+
39
+ this.ScriptType = ScriptType.nullData;
40
+
41
+ return true;
42
+ }
43
+
44
+ return false;
45
+ };
46
+
47
+ private _isP2pkh = (scriptTokens: ScriptToken[]): boolean => {
48
+ if (scriptTokens.length > p2phkTokens.length) return false;
49
+
50
+ let opReturnReached = false;
51
+
52
+ for (let i = 0; i < scriptTokens.length; i++) {
53
+ const token = scriptTokens[i];
54
+
55
+ if (!opReturnReached) {
56
+ if (token.OpCodeNum === OpCode.OP_RETURN) {
57
+ opReturnReached = true;
58
+ } else {
59
+ if (token.OpCodeNum !== p2phkTokens[i].OpCodeNum) return false;
60
+
61
+ if (p2phkTokens[i].IsReceiverId)
62
+ this.Address = new Address(token.Data!);
63
+ }
64
+ } else {
65
+ this.data.push(token.Data!);
66
+ }
67
+ }
68
+
69
+ this.ScriptType = ScriptType.p2pkh;
70
+
71
+ return true;
72
+ };
73
+
74
+ private _isP2stas = (scriptTokens: ScriptToken[]): boolean => {
75
+ const p2stasTokens = getP2stasTokens();
76
+
77
+ if (scriptTokens.length < p2stasTokens.length) return false;
78
+
79
+ let opReturnIdx = -1;
80
+
81
+ for (let i = 0; i < scriptTokens.length; i++) {
82
+ const token = scriptTokens[i];
83
+
84
+ if (opReturnIdx === -1) {
85
+ if (token.OpCodeNum === OpCode.OP_RETURN) {
86
+ opReturnIdx = i;
87
+ } else {
88
+ if (token.OpCodeNum !== p2stasTokens[i].OpCodeNum) return false;
89
+
90
+ if (p2stasTokens[i].IsReceiverId)
91
+ this.Address = new Address(token.Data!);
92
+ }
93
+ } else {
94
+ if (i === opReturnIdx + 1) this.TokenId = token.Data!.toString("hex");
95
+ else if (i === opReturnIdx + 2)
96
+ this.Symbol = token.Data!.toString("utf8");
97
+ else this.data.push(token.Data!);
98
+ }
99
+ }
100
+
101
+ this.ScriptType = ScriptType.p2stas;
102
+
103
+ return true;
104
+ };
105
+ }
@@ -0,0 +1,31 @@
1
+ import { reverseBuffer } from "../buffer/buffer-utils";
2
+ import { hash256 } from "../hashes";
3
+ import { TransactionInput } from "./transaction-input";
4
+ import { TransactionOutput } from "./transaction-output";
5
+
6
+ export class Transaction {
7
+ Inputs: TransactionInput[];
8
+ Outputs: TransactionOutput[];
9
+ Version: number;
10
+ LockTime: number;
11
+ Raw: Buffer;
12
+ Hex: string;
13
+ Id: string;
14
+
15
+ constructor(
16
+ raw: Buffer,
17
+ inputs: TransactionInput[],
18
+ outputs: TransactionOutput[],
19
+ version: number,
20
+ lockTime: number
21
+ ) {
22
+ this.Inputs = inputs;
23
+ this.Outputs = outputs;
24
+ this.Version = version;
25
+ this.LockTime = lockTime;
26
+
27
+ this.Raw = raw;
28
+ this.Hex = raw.toString("hex");
29
+ this.Id = reverseBuffer(hash256(raw)).toString("hex");
30
+ }
31
+ }