@alephium/web3 0.22.0 → 0.23.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/dist/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/src/api/types.d.ts +2 -2
- package/dist/src/contract/contract.js +3 -3
- package/dist/src/utils/exchange.d.ts +7 -0
- package/dist/src/utils/exchange.js +119 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.js +6 -0
- package/dist/src/utils/utils.d.ts +7 -0
- package/dist/src/utils/utils.js +9 -5
- package/package.json +2 -2
- package/src/api/types.ts +2 -2
- package/src/contract/contract.ts +3 -3
- package/src/utils/exchange.ts +120 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/utils.ts +8 -4
package/dist/src/api/types.d.ts
CHANGED
|
@@ -38,15 +38,15 @@ export declare enum StdInterfaceIds {
|
|
|
38
38
|
NFTCollectionWithRoyalty = "000201"
|
|
39
39
|
}
|
|
40
40
|
export interface FungibleTokenMetaData {
|
|
41
|
-
name: string;
|
|
42
41
|
symbol: string;
|
|
42
|
+
name: string;
|
|
43
43
|
decimals: number;
|
|
44
44
|
totalSupply: Number256;
|
|
45
45
|
}
|
|
46
46
|
export interface NFTMetaData {
|
|
47
|
+
tokenUri: string;
|
|
47
48
|
collectionId: string;
|
|
48
49
|
nftIndex: Number256;
|
|
49
|
-
tokenUri: string;
|
|
50
50
|
}
|
|
51
51
|
export interface NFTCollectionMetaData {
|
|
52
52
|
collectionUri: string;
|
|
@@ -556,9 +556,9 @@ class Contract extends Artifact {
|
|
|
556
556
|
const fields = this.stdInterfaceId === undefined
|
|
557
557
|
? this.fieldsSig
|
|
558
558
|
: {
|
|
559
|
-
names: this.fieldsSig.names.slice(-1),
|
|
560
|
-
types: this.fieldsSig.types.slice(-1),
|
|
561
|
-
isMutable: this.fieldsSig.isMutable.slice(-1)
|
|
559
|
+
names: this.fieldsSig.names.slice(0, -1),
|
|
560
|
+
types: this.fieldsSig.types.slice(0, -1),
|
|
561
|
+
isMutable: this.fieldsSig.isMutable.slice(0, -1)
|
|
562
562
|
};
|
|
563
563
|
return fields.names.reduce((acc, key, index) => {
|
|
564
564
|
acc[`${key}`] = (0, api_1.getDefaultValue)(fields.types[`${index}`]);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Transaction } from '../api/api-alephium';
|
|
2
|
+
import { Address } from '../signer';
|
|
3
|
+
export declare function isExchangeAddress(address: string): boolean;
|
|
4
|
+
export declare function isDepositALPHTransaction(tx: Transaction, exchangeAddress: string): boolean;
|
|
5
|
+
export declare function isDepositTokenTransaction(tx: Transaction, exchangeAddress: string): boolean;
|
|
6
|
+
export declare function getDepositAddress(tx: Transaction): Address;
|
|
7
|
+
export declare function getAddressFromUnlockScript(unlockScript: string): Address;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright 2018 - 2022 The Alephium Authors
|
|
4
|
+
This file is part of the alephium project.
|
|
5
|
+
|
|
6
|
+
The library is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
The library is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU Lesser General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.getAddressFromUnlockScript = exports.getDepositAddress = exports.isDepositTokenTransaction = exports.isDepositALPHTransaction = exports.isExchangeAddress = void 0;
|
|
21
|
+
const __1 = require("..");
|
|
22
|
+
function isExchangeAddress(address) {
|
|
23
|
+
const decoded = __1.bs58.decode(address);
|
|
24
|
+
if (decoded.length === 0)
|
|
25
|
+
throw new Error('Address is empty');
|
|
26
|
+
const addressType = decoded[0];
|
|
27
|
+
return (addressType === __1.AddressType.P2PKH || addressType === __1.AddressType.P2SH) && decoded.length === 33;
|
|
28
|
+
}
|
|
29
|
+
exports.isExchangeAddress = isExchangeAddress;
|
|
30
|
+
function isDepositALPHTransaction(tx, exchangeAddress) {
|
|
31
|
+
return isDepositTransaction(tx, exchangeAddress) && checkALPHOutput(tx);
|
|
32
|
+
}
|
|
33
|
+
exports.isDepositALPHTransaction = isDepositALPHTransaction;
|
|
34
|
+
function isDepositTokenTransaction(tx, exchangeAddress) {
|
|
35
|
+
return isDepositTransaction(tx, exchangeAddress) && checkTokenOutput(tx, exchangeAddress);
|
|
36
|
+
}
|
|
37
|
+
exports.isDepositTokenTransaction = isDepositTokenTransaction;
|
|
38
|
+
// we assume that the tx is deposit transaction
|
|
39
|
+
function getDepositAddress(tx) {
|
|
40
|
+
return getAddressFromUnlockScript(tx.unsigned.inputs[0].unlockScript);
|
|
41
|
+
}
|
|
42
|
+
exports.getDepositAddress = getDepositAddress;
|
|
43
|
+
var UnlockScriptType;
|
|
44
|
+
(function (UnlockScriptType) {
|
|
45
|
+
UnlockScriptType[UnlockScriptType["P2PKH"] = 0] = "P2PKH";
|
|
46
|
+
UnlockScriptType[UnlockScriptType["P2MPKH"] = 1] = "P2MPKH";
|
|
47
|
+
UnlockScriptType[UnlockScriptType["P2SH"] = 2] = "P2SH";
|
|
48
|
+
})(UnlockScriptType || (UnlockScriptType = {}));
|
|
49
|
+
function getAddressFromUnlockScript(unlockScript) {
|
|
50
|
+
const decoded = (0, __1.hexToBinUnsafe)(unlockScript);
|
|
51
|
+
if (decoded.length === 0)
|
|
52
|
+
throw new Error('UnlockScript is empty');
|
|
53
|
+
const unlockScriptType = decoded[0];
|
|
54
|
+
const unlockScriptBody = decoded.slice(1);
|
|
55
|
+
if (unlockScriptType === UnlockScriptType.P2PKH) {
|
|
56
|
+
return (0, __1.addressFromPublicKey)((0, __1.binToHex)(unlockScriptBody));
|
|
57
|
+
}
|
|
58
|
+
else if (unlockScriptType === UnlockScriptType.P2MPKH) {
|
|
59
|
+
throw new Error('Naive multi-sig address is not supported for exchanges as it will be replaced by P2SH');
|
|
60
|
+
}
|
|
61
|
+
else if (unlockScriptType === UnlockScriptType.P2SH) {
|
|
62
|
+
// FIXEME: for now we assume that the params is empty, so we need to
|
|
63
|
+
// remove the last byte from the `unlockScriptBody`, we can decode
|
|
64
|
+
// the unlock script once the codec PR is merged
|
|
65
|
+
const script = unlockScriptBody.slice(0, -1);
|
|
66
|
+
return (0, __1.addressFromScript)(script);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new Error('Invalid unlock script type');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.getAddressFromUnlockScript = getAddressFromUnlockScript;
|
|
73
|
+
function getFromAddress(tx) {
|
|
74
|
+
try {
|
|
75
|
+
const inputAddresses = tx.unsigned.inputs.map((i) => getAddressFromUnlockScript(i.unlockScript));
|
|
76
|
+
// we have checked that the inputs is not empty
|
|
77
|
+
const from = inputAddresses[0];
|
|
78
|
+
return inputAddresses.slice(1).every((addr) => addr === from) ? from : undefined;
|
|
79
|
+
}
|
|
80
|
+
catch (_) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function checkOutputAddress(tx, from, to) {
|
|
85
|
+
let fromCount = 0;
|
|
86
|
+
let toCount = 0;
|
|
87
|
+
tx.unsigned.fixedOutputs.forEach((o) => {
|
|
88
|
+
if (o.address === from) {
|
|
89
|
+
fromCount += 1;
|
|
90
|
+
}
|
|
91
|
+
else if (o.address === to) {
|
|
92
|
+
toCount += 1;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const outputCount = tx.unsigned.fixedOutputs.length;
|
|
96
|
+
return toCount === 1 && fromCount === outputCount - 1;
|
|
97
|
+
}
|
|
98
|
+
function checkALPHOutput(tx) {
|
|
99
|
+
const outputs = tx.unsigned.fixedOutputs;
|
|
100
|
+
return outputs.every((o) => o.tokens.length === 0);
|
|
101
|
+
}
|
|
102
|
+
function checkTokenOutput(tx, to) {
|
|
103
|
+
// we have checked the output address
|
|
104
|
+
const output = tx.unsigned.fixedOutputs.find((o) => o.address === to);
|
|
105
|
+
return output.attoAlphAmount === __1.DUST_AMOUNT.toString() && output.tokens.length === 1;
|
|
106
|
+
}
|
|
107
|
+
function isDepositTransaction(tx, exchangeAddress) {
|
|
108
|
+
if (tx.contractInputs.length !== 0 ||
|
|
109
|
+
tx.generatedOutputs.length !== 0 ||
|
|
110
|
+
tx.unsigned.inputs.length === 0 ||
|
|
111
|
+
tx.unsigned.scriptOpt !== undefined) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const from = getFromAddress(tx);
|
|
115
|
+
if (from === undefined) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return checkOutputAddress(tx, from, exchangeAddress);
|
|
119
|
+
}
|
package/dist/src/utils/index.js
CHANGED
|
@@ -31,6 +31,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
31
31
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
32
32
|
};
|
|
33
33
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.getDepositAddress = exports.isDepositTokenTransaction = exports.isDepositALPHTransaction = exports.isExchangeAddress = void 0;
|
|
34
35
|
__exportStar(require("./webcrypto"), exports);
|
|
35
36
|
__exportStar(require("./address"), exports);
|
|
36
37
|
__exportStar(require("./bs58"), exports);
|
|
@@ -39,3 +40,8 @@ __exportStar(require("./utils"), exports);
|
|
|
39
40
|
__exportStar(require("./subscription"), exports);
|
|
40
41
|
__exportStar(require("./sign"), exports);
|
|
41
42
|
__exportStar(require("./number"), exports);
|
|
43
|
+
var exchange_1 = require("./exchange");
|
|
44
|
+
Object.defineProperty(exports, "isExchangeAddress", { enumerable: true, get: function () { return exchange_1.isExchangeAddress; } });
|
|
45
|
+
Object.defineProperty(exports, "isDepositALPHTransaction", { enumerable: true, get: function () { return exchange_1.isDepositALPHTransaction; } });
|
|
46
|
+
Object.defineProperty(exports, "isDepositTokenTransaction", { enumerable: true, get: function () { return exchange_1.isDepositTokenTransaction; } });
|
|
47
|
+
Object.defineProperty(exports, "getDepositAddress", { enumerable: true, get: function () { return exchange_1.getDepositAddress; } });
|
|
@@ -13,6 +13,12 @@ export declare function signatureDecode(ec: EC, signature: string): SignatureInp
|
|
|
13
13
|
export declare function xorByte(intValue: number): number;
|
|
14
14
|
export declare function isHexString(input: string): boolean;
|
|
15
15
|
export declare function toNonNegativeBigInt(input: string): bigint | undefined;
|
|
16
|
+
export declare enum AddressType {
|
|
17
|
+
P2PKH = 0,
|
|
18
|
+
P2MPKH = 1,
|
|
19
|
+
P2SH = 2,
|
|
20
|
+
P2C = 3
|
|
21
|
+
}
|
|
16
22
|
export declare function groupOfAddress(address: string): number;
|
|
17
23
|
export declare function contractIdFromAddress(address: string): Uint8Array;
|
|
18
24
|
export declare function tokenIdFromAddress(address: string): Uint8Array;
|
|
@@ -21,6 +27,7 @@ export declare function binToHex(bin: Uint8Array): string;
|
|
|
21
27
|
export declare function groupOfPrivateKey(privateKey: string, keyType?: KeyType): number;
|
|
22
28
|
export declare function publicKeyFromPrivateKey(privateKey: string, _keyType?: KeyType): string;
|
|
23
29
|
export declare function addressFromPublicKey(publicKey: string, _keyType?: KeyType): string;
|
|
30
|
+
export declare function addressFromScript(script: Uint8Array): string;
|
|
24
31
|
export declare function addressFromContractId(contractId: string): string;
|
|
25
32
|
export declare function addressFromTokenId(tokenId: string): string;
|
|
26
33
|
export declare function contractIdFromTx(txId: string, outputIndex: number): string;
|
package/dist/src/utils/utils.js
CHANGED
|
@@ -20,7 +20,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
20
20
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
21
|
};
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.assertType = exports.sleep = exports.hexToString = exports.stringToHex = exports.blockChainIndex = exports.subContractId = exports.contractIdFromTx = exports.addressFromTokenId = exports.addressFromContractId = exports.addressFromPublicKey = exports.publicKeyFromPrivateKey = exports.groupOfPrivateKey = exports.binToHex = exports.hexToBinUnsafe = exports.tokenIdFromAddress = exports.contractIdFromAddress = exports.groupOfAddress = exports.toNonNegativeBigInt = exports.isHexString = exports.xorByte = exports.signatureDecode = exports.encodeHexSignature = exports.encodeSignature = exports.networkIds = void 0;
|
|
23
|
+
exports.assertType = exports.sleep = exports.hexToString = exports.stringToHex = exports.blockChainIndex = exports.subContractId = exports.contractIdFromTx = exports.addressFromTokenId = exports.addressFromContractId = exports.addressFromScript = exports.addressFromPublicKey = exports.publicKeyFromPrivateKey = exports.groupOfPrivateKey = exports.binToHex = exports.hexToBinUnsafe = exports.tokenIdFromAddress = exports.contractIdFromAddress = exports.groupOfAddress = exports.AddressType = exports.toNonNegativeBigInt = exports.isHexString = exports.xorByte = exports.signatureDecode = exports.encodeHexSignature = exports.encodeSignature = exports.networkIds = void 0;
|
|
24
24
|
const elliptic_1 = require("elliptic");
|
|
25
25
|
const bn_js_1 = __importDefault(require("bn.js"));
|
|
26
26
|
const blakejs_1 = __importDefault(require("blakejs"));
|
|
@@ -88,7 +88,7 @@ var AddressType;
|
|
|
88
88
|
AddressType[AddressType["P2MPKH"] = 1] = "P2MPKH";
|
|
89
89
|
AddressType[AddressType["P2SH"] = 2] = "P2SH";
|
|
90
90
|
AddressType[AddressType["P2C"] = 3] = "P2C";
|
|
91
|
-
})(AddressType || (AddressType = {}));
|
|
91
|
+
})(AddressType = exports.AddressType || (exports.AddressType = {}));
|
|
92
92
|
function groupOfAddress(address) {
|
|
93
93
|
const decoded = bs58_1.default.decode(address);
|
|
94
94
|
if (decoded.length == 0)
|
|
@@ -189,12 +189,16 @@ function addressFromPublicKey(publicKey, _keyType) {
|
|
|
189
189
|
}
|
|
190
190
|
else {
|
|
191
191
|
const lockupScript = buffer_1.Buffer.from(`0101000000000458144020${publicKey}8685`, 'hex');
|
|
192
|
-
|
|
193
|
-
const addressType = buffer_1.Buffer.from([AddressType.P2SH]);
|
|
194
|
-
return bs58_1.default.encode(buffer_1.Buffer.concat([addressType, lockupScriptHash]));
|
|
192
|
+
return addressFromScript(lockupScript);
|
|
195
193
|
}
|
|
196
194
|
}
|
|
197
195
|
exports.addressFromPublicKey = addressFromPublicKey;
|
|
196
|
+
function addressFromScript(script) {
|
|
197
|
+
const scriptHash = blakejs_1.default.blake2b(script, undefined, 32);
|
|
198
|
+
const addressType = buffer_1.Buffer.from([AddressType.P2SH]);
|
|
199
|
+
return bs58_1.default.encode(buffer_1.Buffer.concat([addressType, scriptHash]));
|
|
200
|
+
}
|
|
201
|
+
exports.addressFromScript = addressFromScript;
|
|
198
202
|
function addressFromContractId(contractId) {
|
|
199
203
|
const addressType = buffer_1.Buffer.from([AddressType.P2C]);
|
|
200
204
|
const hash = buffer_1.Buffer.from(hexToBinUnsafe(contractId));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alephium/web3",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "A JS/TS library to interact with the Alephium platform",
|
|
5
5
|
"license": "GPL",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"webpack-cli": "^4.10.0"
|
|
83
83
|
},
|
|
84
84
|
"engines": {
|
|
85
|
-
"node": ">=
|
|
85
|
+
"node": ">=14.0.0",
|
|
86
86
|
"npm": ">=7.0.0"
|
|
87
87
|
},
|
|
88
88
|
"scripts": {
|
package/src/api/types.ts
CHANGED
|
@@ -291,16 +291,16 @@ export enum StdInterfaceIds {
|
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
export interface FungibleTokenMetaData {
|
|
294
|
-
name: string
|
|
295
294
|
symbol: string
|
|
295
|
+
name: string
|
|
296
296
|
decimals: number
|
|
297
297
|
totalSupply: Number256
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
export interface NFTMetaData {
|
|
301
|
+
tokenUri: string
|
|
301
302
|
collectionId: string
|
|
302
303
|
nftIndex: Number256
|
|
303
|
-
tokenUri: string
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
export interface NFTCollectionMetaData {
|
package/src/contract/contract.ts
CHANGED
|
@@ -850,9 +850,9 @@ export class Contract extends Artifact {
|
|
|
850
850
|
this.stdInterfaceId === undefined
|
|
851
851
|
? this.fieldsSig
|
|
852
852
|
: {
|
|
853
|
-
names: this.fieldsSig.names.slice(-1),
|
|
854
|
-
types: this.fieldsSig.types.slice(-1),
|
|
855
|
-
isMutable: this.fieldsSig.isMutable.slice(-1)
|
|
853
|
+
names: this.fieldsSig.names.slice(0, -1),
|
|
854
|
+
types: this.fieldsSig.types.slice(0, -1),
|
|
855
|
+
isMutable: this.fieldsSig.isMutable.slice(0, -1)
|
|
856
856
|
}
|
|
857
857
|
return fields.names.reduce((acc, key, index) => {
|
|
858
858
|
acc[`${key}`] = getDefaultValue(fields.types[`${index}`])
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2018 - 2022 The Alephium Authors
|
|
3
|
+
This file is part of the alephium project.
|
|
4
|
+
|
|
5
|
+
The library is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
The library is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Lesser General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { AddressType, DUST_AMOUNT, addressFromPublicKey, addressFromScript, binToHex, bs58, hexToBinUnsafe } from '..'
|
|
20
|
+
import { Transaction } from '../api/api-alephium'
|
|
21
|
+
import { Address } from '../signer'
|
|
22
|
+
|
|
23
|
+
export function isExchangeAddress(address: string): boolean {
|
|
24
|
+
const decoded = bs58.decode(address)
|
|
25
|
+
if (decoded.length === 0) throw new Error('Address is empty')
|
|
26
|
+
const addressType = decoded[0]
|
|
27
|
+
return (addressType === AddressType.P2PKH || addressType === AddressType.P2SH) && decoded.length === 33
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function isDepositALPHTransaction(tx: Transaction, exchangeAddress: string): boolean {
|
|
31
|
+
return isDepositTransaction(tx, exchangeAddress) && checkALPHOutput(tx)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function isDepositTokenTransaction(tx: Transaction, exchangeAddress: string): boolean {
|
|
35
|
+
return isDepositTransaction(tx, exchangeAddress) && checkTokenOutput(tx, exchangeAddress)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// we assume that the tx is deposit transaction
|
|
39
|
+
export function getDepositAddress(tx: Transaction): Address {
|
|
40
|
+
return getAddressFromUnlockScript(tx.unsigned.inputs[0].unlockScript)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
enum UnlockScriptType {
|
|
44
|
+
P2PKH = 0x00,
|
|
45
|
+
P2MPKH = 0x01,
|
|
46
|
+
P2SH = 0x02
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getAddressFromUnlockScript(unlockScript: string): Address {
|
|
50
|
+
const decoded = hexToBinUnsafe(unlockScript)
|
|
51
|
+
if (decoded.length === 0) throw new Error('UnlockScript is empty')
|
|
52
|
+
const unlockScriptType = decoded[0]
|
|
53
|
+
const unlockScriptBody = decoded.slice(1)
|
|
54
|
+
|
|
55
|
+
if (unlockScriptType === UnlockScriptType.P2PKH) {
|
|
56
|
+
return addressFromPublicKey(binToHex(unlockScriptBody))
|
|
57
|
+
} else if (unlockScriptType === UnlockScriptType.P2MPKH) {
|
|
58
|
+
throw new Error('Naive multi-sig address is not supported for exchanges as it will be replaced by P2SH')
|
|
59
|
+
} else if (unlockScriptType === UnlockScriptType.P2SH) {
|
|
60
|
+
// FIXEME: for now we assume that the params is empty, so we need to
|
|
61
|
+
// remove the last byte from the `unlockScriptBody`, we can decode
|
|
62
|
+
// the unlock script once the codec PR is merged
|
|
63
|
+
const script = unlockScriptBody.slice(0, -1)
|
|
64
|
+
return addressFromScript(script)
|
|
65
|
+
} else {
|
|
66
|
+
throw new Error('Invalid unlock script type')
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getFromAddress(tx: Transaction): Address | undefined {
|
|
71
|
+
try {
|
|
72
|
+
const inputAddresses = tx.unsigned.inputs.map((i) => getAddressFromUnlockScript(i.unlockScript))
|
|
73
|
+
// we have checked that the inputs is not empty
|
|
74
|
+
const from = inputAddresses[0]
|
|
75
|
+
return inputAddresses.slice(1).every((addr) => addr === from) ? from : undefined
|
|
76
|
+
} catch (_) {
|
|
77
|
+
return undefined
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function checkOutputAddress(tx: Transaction, from: Address, to: Address): boolean {
|
|
82
|
+
let fromCount = 0
|
|
83
|
+
let toCount = 0
|
|
84
|
+
tx.unsigned.fixedOutputs.forEach((o) => {
|
|
85
|
+
if (o.address === from) {
|
|
86
|
+
fromCount += 1
|
|
87
|
+
} else if (o.address === to) {
|
|
88
|
+
toCount += 1
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
const outputCount = tx.unsigned.fixedOutputs.length
|
|
92
|
+
return toCount === 1 && fromCount === outputCount - 1
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function checkALPHOutput(tx: Transaction): boolean {
|
|
96
|
+
const outputs = tx.unsigned.fixedOutputs
|
|
97
|
+
return outputs.every((o) => o.tokens.length === 0)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function checkTokenOutput(tx: Transaction, to: Address): boolean {
|
|
101
|
+
// we have checked the output address
|
|
102
|
+
const output = tx.unsigned.fixedOutputs.find((o) => o.address === to)!
|
|
103
|
+
return output.attoAlphAmount === DUST_AMOUNT.toString() && output.tokens.length === 1
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isDepositTransaction(tx: Transaction, exchangeAddress: string): boolean {
|
|
107
|
+
if (
|
|
108
|
+
tx.contractInputs.length !== 0 ||
|
|
109
|
+
tx.generatedOutputs.length !== 0 ||
|
|
110
|
+
tx.unsigned.inputs.length === 0 ||
|
|
111
|
+
tx.unsigned.scriptOpt !== undefined
|
|
112
|
+
) {
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
const from = getFromAddress(tx)
|
|
116
|
+
if (from === undefined) {
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
119
|
+
return checkOutputAddress(tx, from, exchangeAddress)
|
|
120
|
+
}
|
package/src/utils/index.ts
CHANGED
package/src/utils/utils.ts
CHANGED
|
@@ -84,7 +84,7 @@ export function toNonNegativeBigInt(input: string): bigint | undefined {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
enum AddressType {
|
|
87
|
+
export enum AddressType {
|
|
88
88
|
P2PKH = 0x00,
|
|
89
89
|
P2MPKH = 0x01,
|
|
90
90
|
P2SH = 0x02,
|
|
@@ -196,12 +196,16 @@ export function addressFromPublicKey(publicKey: string, _keyType?: KeyType): str
|
|
|
196
196
|
return bs58.encode(bytes)
|
|
197
197
|
} else {
|
|
198
198
|
const lockupScript = Buffer.from(`0101000000000458144020${publicKey}8685`, 'hex')
|
|
199
|
-
|
|
200
|
-
const addressType = Buffer.from([AddressType.P2SH])
|
|
201
|
-
return bs58.encode(Buffer.concat([addressType, lockupScriptHash]))
|
|
199
|
+
return addressFromScript(lockupScript)
|
|
202
200
|
}
|
|
203
201
|
}
|
|
204
202
|
|
|
203
|
+
export function addressFromScript(script: Uint8Array): string {
|
|
204
|
+
const scriptHash = blake.blake2b(script, undefined, 32)
|
|
205
|
+
const addressType = Buffer.from([AddressType.P2SH])
|
|
206
|
+
return bs58.encode(Buffer.concat([addressType, scriptHash]))
|
|
207
|
+
}
|
|
208
|
+
|
|
205
209
|
export function addressFromContractId(contractId: string): string {
|
|
206
210
|
const addressType = Buffer.from([AddressType.P2C])
|
|
207
211
|
const hash = Buffer.from(hexToBinUnsafe(contractId))
|