@aeternity/aepp-sdk 8.2.0 → 10.0.0-beta.1
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/README.md +16 -9
- package/dist/aepp-sdk.browser-script.js +1 -1
- package/dist/aepp-sdk.browser-script.js.LICENSE.txt +0 -9
- package/dist/aepp-sdk.browser-script.js.map +1 -1
- package/dist/aepp-sdk.browser.js +1 -1
- package/dist/aepp-sdk.browser.js.map +1 -1
- package/dist/aepp-sdk.js +1 -1
- package/dist/aepp-sdk.js.map +1 -1
- package/es/account/base.js +33 -119
- package/es/account/base.js.map +1 -1
- package/es/account/memory.js +17 -19
- package/es/account/memory.js.map +1 -1
- package/es/account/multiple.js +75 -154
- package/es/account/multiple.js.map +1 -1
- package/es/ae/aens.js +164 -599
- package/es/ae/aens.js.map +1 -1
- package/es/ae/contract.js +108 -916
- package/es/ae/contract.js.map +1 -1
- package/es/ae/index.js +89 -250
- package/es/ae/index.js.map +1 -1
- package/es/ae/oracle.js +132 -500
- package/es/ae/oracle.js.map +1 -1
- package/es/chain/index.js +4 -23
- package/es/chain/index.js.map +1 -1
- package/es/chain/node.js +292 -1018
- package/es/chain/node.js.map +1 -1
- package/es/channel/handlers.js +597 -1086
- package/es/channel/handlers.js.map +1 -1
- package/es/channel/index.js +203 -451
- package/es/channel/index.js.map +1 -1
- package/es/channel/internal.js +129 -301
- package/es/channel/internal.js.map +1 -1
- package/es/contract/aci/index.js +319 -491
- package/es/contract/aci/index.js.map +1 -1
- package/es/contract/aci/transformation.js +35 -711
- package/es/contract/aci/transformation.js.map +1 -1
- package/es/contract/compiler.js +129 -203
- package/es/contract/compiler.js.map +1 -1
- package/es/contract/ga/helpers.js +17 -122
- package/es/contract/ga/helpers.js.map +1 -1
- package/es/contract/ga/index.js +102 -247
- package/es/contract/ga/index.js.map +1 -1
- package/es/contract/index.js +1 -1
- package/es/contract/index.js.map +1 -1
- package/es/index.js +2 -3
- package/es/index.js.map +1 -1
- package/es/node-pool/index.js +54 -73
- package/es/node-pool/index.js.map +1 -1
- package/es/node.js +56 -157
- package/es/node.js.map +1 -1
- package/es/other.d.ts +1 -1
- package/es/tx/builder/helpers.js +49 -89
- package/es/tx/builder/helpers.js.map +1 -1
- package/es/tx/builder/index.js +205 -303
- package/es/tx/builder/index.js.map +1 -1
- package/es/tx/builder/schema.js +585 -573
- package/es/tx/builder/schema.js.map +1 -1
- package/es/tx/index.js +1 -1
- package/es/tx/index.js.map +1 -1
- package/es/tx/tx-object.js +105 -135
- package/es/tx/tx-object.js.map +1 -1
- package/es/tx/tx.js +810 -1586
- package/es/tx/tx.js.map +1 -1
- package/es/tx/validator.js +191 -426
- package/es/tx/validator.js.map +1 -1
- package/es/utils/aepp-wallet-communication/connection/browser-runtime.js +17 -21
- package/es/utils/aepp-wallet-communication/connection/browser-runtime.js.map +1 -1
- package/es/utils/aepp-wallet-communication/connection/browser-window-message.js +38 -74
- package/es/utils/aepp-wallet-communication/connection/browser-window-message.js.map +1 -1
- package/es/utils/aepp-wallet-communication/content-script-bridge.js +14 -15
- package/es/utils/aepp-wallet-communication/content-script-bridge.js.map +1 -1
- package/es/utils/aepp-wallet-communication/helpers.js +60 -105
- package/es/utils/aepp-wallet-communication/helpers.js.map +1 -1
- package/es/utils/aepp-wallet-communication/rpc/aepp-rpc.js +179 -510
- package/es/utils/aepp-wallet-communication/rpc/aepp-rpc.js.map +1 -1
- package/es/utils/aepp-wallet-communication/rpc/rpc-client.js +70 -89
- package/es/utils/aepp-wallet-communication/rpc/rpc-client.js.map +1 -1
- package/es/utils/aepp-wallet-communication/rpc/wallet-rpc.js +354 -603
- package/es/utils/aepp-wallet-communication/rpc/wallet-rpc.js.map +1 -1
- package/es/utils/aepp-wallet-communication/schema.js +43 -39
- package/es/utils/aepp-wallet-communication/schema.js.map +1 -1
- package/es/utils/aepp-wallet-communication/wallet-detector.js +32 -58
- package/es/utils/aepp-wallet-communication/wallet-detector.js.map +1 -1
- package/es/utils/amount-formatter.js +41 -61
- package/es/utils/amount-formatter.js.map +1 -1
- package/es/utils/async-init.js +28 -64
- package/es/utils/async-init.js.map +1 -1
- package/es/utils/bignumber.js +3 -11
- package/es/utils/bignumber.js.map +1 -1
- package/es/utils/bytes.js +5 -9
- package/es/utils/bytes.js.map +1 -1
- package/es/utils/crypto.js +49 -75
- package/es/utils/crypto.js.map +1 -1
- package/es/utils/hd-wallet.js +45 -81
- package/es/utils/hd-wallet.js.map +1 -1
- package/es/utils/json-big.js +16 -49
- package/es/utils/json-big.js.map +1 -1
- package/es/utils/keystore.js +81 -246
- package/es/utils/keystore.js.map +1 -1
- package/es/utils/mptree.js +88 -134
- package/es/utils/mptree.js.map +1 -1
- package/es/utils/other.js +10 -60
- package/es/utils/other.js.map +1 -1
- package/es/utils/semver-satisfies.js +9 -28
- package/es/utils/semver-satisfies.js.map +1 -1
- package/es/utils/string.js +4 -13
- package/es/utils/string.js.map +1 -1
- package/es/utils/swagger.js +85 -218
- package/es/utils/swagger.js.map +1 -1
- package/package.json +52 -43
- package/src/account/base.js +8 -9
- package/src/account/multiple.js +20 -16
- package/src/ae/aens.js +25 -21
- package/src/ae/contract.js +65 -246
- package/src/ae/index.js +31 -7
- package/src/ae/oracle.js +21 -17
- package/src/chain/index.js +2 -12
- package/src/chain/node.js +26 -29
- package/src/channel/handlers.js +0 -1
- package/src/channel/index.js +4 -5
- package/src/contract/aci/index.js +221 -106
- package/src/contract/aci/transformation.js +30 -422
- package/src/contract/compiler.js +45 -4
- package/src/contract/ga/helpers.js +2 -12
- package/src/contract/ga/index.js +22 -26
- package/src/index.js +2 -4
- package/src/node-pool/index.js +21 -12
- package/src/node.js +22 -26
- package/src/tx/builder/helpers.js +12 -24
- package/src/tx/builder/index.js +18 -15
- package/src/tx/builder/schema.js +43 -108
- package/src/tx/tx-object.js +0 -2
- package/src/tx/tx.js +157 -144
- package/src/tx/validator.js +134 -202
- package/src/utils/aepp-wallet-communication/rpc/aepp-rpc.js +1 -3
- package/src/utils/aepp-wallet-communication/rpc/wallet-rpc.js +9 -10
- package/src/utils/aepp-wallet-communication/schema.js +1 -3
- package/src/utils/amount-formatter.ts +1 -1
- package/src/utils/bignumber.ts +2 -1
- package/src/utils/crypto.js +4 -17
- package/src/utils/other.ts +1 -1
- package/src/utils/semver-satisfies.ts +1 -1
- package/src/utils/swagger.js +24 -7
- package/CHANGELOG.md +0 -1716
- package/src/contract/aci/helpers.js +0 -140
package/src/tx/validator.js
CHANGED
|
@@ -1,229 +1,161 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
decodeBase58Check,
|
|
4
|
-
assertedType
|
|
5
|
-
} from '../utils/crypto'
|
|
6
|
-
import { encode } from '../tx/builder/helpers'
|
|
1
|
+
import { verify, hash } from '../utils/crypto'
|
|
2
|
+
import { encode, decode } from './builder/helpers'
|
|
7
3
|
|
|
8
4
|
import BigNumber from 'bignumber.js'
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
CONTRACT_VERIFICATION_SCHEMA,
|
|
12
|
-
MIN_GAS_PRICE,
|
|
13
|
-
NAME_CLAIM_VERIFICATION_SCHEMA,
|
|
14
|
-
OBJECT_ID_TX_TYPE,
|
|
15
|
-
OBJECT_TAG_SIGNED_TRANSACTION,
|
|
16
|
-
PROTOCOL_VM_ABI,
|
|
17
|
-
SIGNATURE_VERIFICATION_SCHEMA,
|
|
18
|
-
TX_TYPE
|
|
19
|
-
} from './builder/schema'
|
|
20
|
-
import { buildTxHash, calculateFee, unpackTx } from './builder'
|
|
21
|
-
import NodePool from '../node-pool'
|
|
5
|
+
import { MIN_GAS_PRICE, PROTOCOL_VM_ABI, TX_TYPE } from './builder/schema'
|
|
6
|
+
import { calculateFee, unpackTx } from './builder'
|
|
22
7
|
|
|
23
8
|
/**
|
|
24
9
|
* Transaction validator
|
|
25
10
|
* @module @aeternity/aepp-sdk/es/tx/validator
|
|
26
|
-
* @export
|
|
27
|
-
* @example import {
|
|
11
|
+
* @export verifyTransaction
|
|
12
|
+
* @example import { verifyTransaction } from '@aeternity/aepp-sdk'
|
|
28
13
|
*/
|
|
29
14
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
15
|
+
const validators = [
|
|
16
|
+
async ({ encodedTx, signatures }, { account, node, parentTxTypes }) => {
|
|
17
|
+
if ((encodedTx ?? signatures) === undefined) return []
|
|
18
|
+
if (signatures.length !== 1) return [] // TODO: Support multisignature?
|
|
19
|
+
const prefix = Buffer.from([
|
|
20
|
+
node.nodeNetworkId,
|
|
21
|
+
...parentTxTypes.includes(TX_TYPE.payingFor) ? ['inner_tx'] : []
|
|
22
|
+
].join('-'))
|
|
23
|
+
const txWithNetworkId = Buffer.concat([prefix, encodedTx.rlpEncoded])
|
|
24
|
+
const txHashWithNetworkId = Buffer.concat([prefix, hash(encodedTx.rlpEncoded)])
|
|
25
|
+
const decodedPub = decode(account.id, 'ak')
|
|
26
|
+
if (verify(txWithNetworkId, signatures[0], decodedPub) ||
|
|
27
|
+
verify(txHashWithNetworkId, signatures[0], decodedPub)) return []
|
|
28
|
+
return [{
|
|
29
|
+
message: 'Signature cannot be verified, please ensure that you transaction have' +
|
|
30
|
+
' the correct prefix and the correct private key for the sender address',
|
|
31
|
+
key: 'InvalidSignature',
|
|
32
|
+
checkedKeys: ['encodedTx', 'signatures']
|
|
33
|
+
}]
|
|
37
34
|
},
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return
|
|
35
|
+
async ({ encodedTx, tx }, { node, parentTxTypes, txType }) => {
|
|
36
|
+
if ((encodedTx ?? tx) === undefined) return []
|
|
37
|
+
return verifyTransaction(
|
|
38
|
+
encode((encodedTx ?? tx).rlpEncoded, 'tx'),
|
|
39
|
+
node,
|
|
40
|
+
[...parentTxTypes, txType]
|
|
41
|
+
)
|
|
41
42
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return
|
|
43
|
+
(tx, { txType }) => {
|
|
44
|
+
if (tx.fee === undefined) return []
|
|
45
|
+
const minFee = calculateFee(0, txType, {
|
|
46
|
+
gas: +tx.gas || 0, params: tx, showWarning: false, vsn: tx.VSN
|
|
47
|
+
})
|
|
48
|
+
if (new BigNumber(minFee).lte(tx.fee)) return []
|
|
49
|
+
return [{
|
|
50
|
+
message: `Fee ${tx.fee} is too low, minimum fee for this transaction is ${minFee}`,
|
|
51
|
+
key: 'InsufficientFee',
|
|
52
|
+
checkedKeys: ['fee']
|
|
53
|
+
}]
|
|
49
54
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
({ ttl }, { height }) => {
|
|
56
|
+
if (ttl === undefined) return []
|
|
57
|
+
ttl = +ttl
|
|
58
|
+
if (ttl === 0 || ttl >= height) return []
|
|
59
|
+
return [{
|
|
60
|
+
message: `TTL ${ttl} is already expired, current height is ${height}`,
|
|
61
|
+
key: 'ExpiredTTL',
|
|
62
|
+
checkedKeys: ['ttl']
|
|
63
|
+
}]
|
|
53
64
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
({ amount, fee, nameFee, tx }, { account, parentTxTypes, txType }) => {
|
|
66
|
+
if ((amount ?? fee ?? nameFee) === undefined) return []
|
|
67
|
+
const cost = new BigNumber(fee).plus(nameFee || 0).plus(amount || 0)
|
|
68
|
+
.plus(txType === TX_TYPE.payingFor ? tx.tx.encodedTx.tx.fee : 0)
|
|
69
|
+
.minus(parentTxTypes.includes(TX_TYPE.payingFor) ? fee : 0)
|
|
70
|
+
if (cost.lte(account.balance)) return []
|
|
71
|
+
return [{
|
|
72
|
+
message: `Account balance ${account.balance} is not enough to execute the transaction that costs ${cost.toFixed()}`,
|
|
73
|
+
key: 'InsufficientBalance',
|
|
74
|
+
checkedKeys: ['amount', 'fee', 'nameFee']
|
|
75
|
+
}]
|
|
57
76
|
},
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
77
|
+
({ nonce }, { account, parentTxTypes }) => {
|
|
78
|
+
if (nonce === undefined || parentTxTypes.includes(TX_TYPE.gaMeta)) return []
|
|
79
|
+
nonce = +nonce
|
|
80
|
+
const validNonce = account.nonce + 1
|
|
81
|
+
if (nonce === validNonce) return []
|
|
82
|
+
return [{
|
|
83
|
+
...nonce < validNonce
|
|
84
|
+
? {
|
|
85
|
+
message: `Nonce ${nonce} is already used, valid nonce is ${validNonce}`,
|
|
86
|
+
key: 'NonceAlreadyUsed'
|
|
87
|
+
}
|
|
88
|
+
: {
|
|
89
|
+
message: `Nonce ${nonce} is too high, valid nonce is ${validNonce}`,
|
|
90
|
+
key: 'NonceHigh'
|
|
91
|
+
},
|
|
92
|
+
checkedKeys: ['nonce']
|
|
93
|
+
}]
|
|
61
94
|
},
|
|
62
|
-
|
|
63
|
-
|
|
95
|
+
({ gasPrice }) => {
|
|
96
|
+
if (gasPrice === undefined) return []
|
|
97
|
+
if (gasPrice >= MIN_GAS_PRICE) return []
|
|
98
|
+
return [{
|
|
99
|
+
message: `Gas price ${gasPrice} must be bigger then ${MIN_GAS_PRICE}`,
|
|
100
|
+
key: 'MinGasPrice',
|
|
101
|
+
checkedKeys: ['gasPrice']
|
|
102
|
+
}]
|
|
64
103
|
},
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
104
|
+
({ ctVersion, abiVersion }, { txType, node }) => {
|
|
105
|
+
const { consensusProtocolVersion } = node.getNodeInfo()
|
|
106
|
+
const protocol = PROTOCOL_VM_ABI[consensusProtocolVersion]
|
|
107
|
+
if (!protocol) throw new Error(`Unsupported protocol: ${consensusProtocolVersion}`)
|
|
108
|
+
// If not contract create tx
|
|
68
109
|
if (!ctVersion) ctVersion = { abiVersion }
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
if (!
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
[...acc, value === undefined ? true : txProtocol[key].includes(parseInt(value))],
|
|
78
|
-
[]).includes(false)
|
|
79
|
-
},
|
|
80
|
-
insufficientBalanceForFeeNameFee ({ nameFee, fee, balance, VSN }) {
|
|
81
|
-
return VSN === 1 || BigNumber(balance).gte(BigNumber(nameFee).plus(fee))
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const resolveDataForBase = async (chain, { ownerPublicKey }) => {
|
|
86
|
-
let accountNonce = 0
|
|
87
|
-
let accountBalance = 0
|
|
88
|
-
try {
|
|
89
|
-
const { nonce, balance } = await chain.api.getAccountByPubkey(ownerPublicKey)
|
|
90
|
-
accountNonce = nonce
|
|
91
|
-
accountBalance = balance
|
|
92
|
-
} catch (e) { console.log('We can not get info about this publicKey') }
|
|
93
|
-
return {
|
|
94
|
-
height: (await chain.api.getCurrentKeyBlockHeight()).height,
|
|
95
|
-
balance: accountBalance,
|
|
96
|
-
accountNonce,
|
|
97
|
-
ownerPublicKey,
|
|
98
|
-
...chain.getNodeInfo()
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Verification using SCHEMA
|
|
103
|
-
const verifySchema = (schema, data) => {
|
|
104
|
-
// Verify through schema
|
|
105
|
-
return schema.reduce(
|
|
106
|
-
(acc, [msg, validatorKey, { key, type, txKey }]) => {
|
|
107
|
-
if (!VALIDATORS[validatorKey](data)) acc.push({ msg: msg(data), txKey, type })
|
|
108
|
-
return acc
|
|
109
|
-
},
|
|
110
|
-
[]
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Unpack and verify transaction (verify nonce, ttl, fee, signature, account balance)
|
|
116
|
-
* @function
|
|
117
|
-
* @alias module:@aeternity/aepp-sdk/es/tx/validator
|
|
118
|
-
*
|
|
119
|
-
* @param {String} txHash Base64Check transaction hash
|
|
120
|
-
* @param {Object} [options={}] Options
|
|
121
|
-
* @param {String} [options.networkId] networkId Use in signature verification
|
|
122
|
-
* @return {Promise<Object>} Object with verification errors and warnings
|
|
123
|
-
*/
|
|
124
|
-
async function unpackAndVerify (txHash, { networkId } = {}) {
|
|
125
|
-
const { tx: unpackedTx, rlpEncoded, txType } = unpackTx(txHash)
|
|
126
|
-
|
|
127
|
-
if (+unpackedTx.tag === OBJECT_TAG_SIGNED_TRANSACTION) {
|
|
128
|
-
const { txType, tx } = unpackedTx.encodedTx
|
|
129
|
-
const signatures = unpackedTx.signatures.map(raw => ({ raw, hash: encode(raw, 'sg') }))
|
|
130
|
-
const rlpEncodedTx = unpackedTx.encodedTx.rlpEncoded
|
|
131
|
-
|
|
132
|
-
return {
|
|
133
|
-
validation: await this.verifyTx({ tx, signatures, rlpEncoded: rlpEncodedTx }, networkId),
|
|
134
|
-
tx,
|
|
135
|
-
signatures,
|
|
136
|
-
txType
|
|
110
|
+
const txProtocol = protocol[txType]
|
|
111
|
+
if (!txProtocol) return []
|
|
112
|
+
if (Object.entries(ctVersion).some(([key, value]) => !txProtocol[key].includes(+value))) {
|
|
113
|
+
return [{
|
|
114
|
+
message: `ABI/VM version ${JSON.stringify(ctVersion)} is wrong, supported is: ${JSON.stringify(txProtocol)}`,
|
|
115
|
+
key: 'VmAndAbiVersionMismatch',
|
|
116
|
+
checkedKeys: ['ctVersion', 'abiVersion']
|
|
117
|
+
}]
|
|
137
118
|
}
|
|
119
|
+
return []
|
|
138
120
|
}
|
|
139
|
-
|
|
140
|
-
validation: await this.verifyTx({ tx: unpackedTx, rlpEncoded }, networkId),
|
|
141
|
-
tx: unpackedTx,
|
|
142
|
-
txType
|
|
143
|
-
}
|
|
144
|
-
}
|
|
121
|
+
]
|
|
145
122
|
|
|
146
|
-
const
|
|
147
|
-
|
|
123
|
+
const getSenderAddress = tx => [
|
|
124
|
+
'senderId', 'accountId', 'ownerId', 'callerId',
|
|
125
|
+
'oracleId', 'fromId', 'initiator', 'gaId', 'payerId'
|
|
126
|
+
]
|
|
127
|
+
.map(key => tx[key])
|
|
128
|
+
.filter(a => a)
|
|
129
|
+
.map(a => a.replace(/^ok_/, 'ak_'))[0]
|
|
148
130
|
|
|
149
131
|
/**
|
|
150
|
-
*
|
|
132
|
+
* Transaction Validator
|
|
133
|
+
* This function validates some of transaction properties,
|
|
134
|
+
* to make sure it can be posted it to the chain
|
|
151
135
|
* @function
|
|
152
136
|
* @alias module:@aeternity/aepp-sdk/es/tx/validator
|
|
153
|
-
*
|
|
154
|
-
* @param {
|
|
155
|
-
* @param {
|
|
156
|
-
* @param {
|
|
157
|
-
* @
|
|
158
|
-
* @
|
|
159
|
-
* @return {Promise<Array>} Object with verification errors and warnings
|
|
137
|
+
* @rtype (tx: String, node) => void
|
|
138
|
+
* @param {String} transaction Base64Check-encoded transaction
|
|
139
|
+
* @param {Object} node Node to validate transaction against
|
|
140
|
+
* @param {String[]} [parentTxTypes] Types of parent transactions
|
|
141
|
+
* @return {Promise<Object[]>} Array with verification errors
|
|
142
|
+
* @example const errors = await verifyTransaction(transaction, node)
|
|
160
143
|
*/
|
|
161
|
-
async function
|
|
162
|
-
|
|
163
|
-
// Fetch data for verification
|
|
164
|
-
const ownerPublicKey = getOwnerPublicKey(tx)
|
|
165
|
-
const gas = Object.prototype.hasOwnProperty.call(tx, 'gas') ? +tx.gas : 0
|
|
166
|
-
const txType = OBJECT_ID_TX_TYPE[+tx.tag]
|
|
167
|
-
const resolvedData = {
|
|
168
|
-
minFee: calculateFee(0, txType, { gas, params: tx, showWarning: false, vsn: tx.VSN }),
|
|
169
|
-
...(await resolveDataForBase(this, { ownerPublicKey })),
|
|
170
|
-
...tx,
|
|
171
|
-
txType
|
|
172
|
-
}
|
|
173
|
-
const signatureVerification = signatures && signatures.length
|
|
174
|
-
? verifySchema(SIGNATURE_VERIFICATION_SCHEMA, {
|
|
175
|
-
rlpEncoded,
|
|
176
|
-
signature: signatures[0].raw,
|
|
177
|
-
ownerPublicKey,
|
|
178
|
-
networkId
|
|
179
|
-
})
|
|
180
|
-
: []
|
|
181
|
-
const baseVerification = verifySchema(BASE_VERIFICATION_SCHEMA, resolvedData)
|
|
144
|
+
export default async function verifyTransaction (transaction, node, parentTxTypes = []) {
|
|
145
|
+
const { tx, txType } = unpackTx(transaction)
|
|
182
146
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
147
|
+
const address = getSenderAddress(tx) ??
|
|
148
|
+
(txType === TX_TYPE.signed ? getSenderAddress(tx.encodedTx.tx) : null)
|
|
149
|
+
const [account, height] = await Promise.all([
|
|
150
|
+
address && node.api.getAccountByPubkey(address).catch(() => ({
|
|
151
|
+
id: address,
|
|
152
|
+
balance: new BigNumber(0),
|
|
153
|
+
nonce: 0
|
|
154
|
+
})),
|
|
155
|
+
node.api.getCurrentKeyBlockHeight().then(({ height }) => height)
|
|
156
|
+
])
|
|
189
157
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
* @param data
|
|
194
|
-
* @return {Array}
|
|
195
|
-
*/
|
|
196
|
-
function customVerification (txType, data) {
|
|
197
|
-
switch (txType) {
|
|
198
|
-
case TX_TYPE.contractCreate:
|
|
199
|
-
case TX_TYPE.contractCall:
|
|
200
|
-
case TX_TYPE.oracleRegister:
|
|
201
|
-
return verifySchema(CONTRACT_VERIFICATION_SCHEMA, data)
|
|
202
|
-
case TX_TYPE.nameClaim:
|
|
203
|
-
return verifySchema(NAME_CLAIM_VERIFICATION_SCHEMA, data)
|
|
204
|
-
default:
|
|
205
|
-
return []
|
|
206
|
-
}
|
|
158
|
+
return (await Promise.all(
|
|
159
|
+
validators.map(v => v(tx, { txType, node, account, height, parentTxTypes })))
|
|
160
|
+
).flat()
|
|
207
161
|
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Transaction Validator Stamp
|
|
211
|
-
* This stamp give us possibility to unpack and validate some of transaction properties,
|
|
212
|
-
* to make sure we can post it to the chain
|
|
213
|
-
* @function
|
|
214
|
-
* @alias module:@aeternity/aepp-sdk/es/tx/validator
|
|
215
|
-
* @rtype Stamp
|
|
216
|
-
* @param {Object} [options={}] - Initializer object
|
|
217
|
-
* @param {Object} [options.url] - Node url
|
|
218
|
-
* @param {Object} [options.internalUrl] - Node internal url
|
|
219
|
-
* @return {Object} Transaction Validator instance
|
|
220
|
-
* @example TransactionValidator({url: 'https://testnet.aeternity.io'})
|
|
221
|
-
*/
|
|
222
|
-
const TransactionValidator = NodePool.compose({
|
|
223
|
-
methods: {
|
|
224
|
-
verifyTx,
|
|
225
|
-
unpackAndVerify
|
|
226
|
-
}
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
export default TransactionValidator
|
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
* @export AeppRpc
|
|
6
6
|
* @example import ContentScriptBridge from '@aeternity/aepp-sdk/es/utils/aepp-wallet-communication/rpc/aepp-rpc'
|
|
7
7
|
*/
|
|
8
|
-
import * as R from 'ramda'
|
|
9
8
|
import { v4 as uuid } from 'uuid'
|
|
10
|
-
|
|
11
9
|
import Ae from '../../../ae'
|
|
12
10
|
import RpcClient from './rpc-client'
|
|
13
11
|
import { getHandler, message, voidFn } from '../helpers'
|
|
@@ -236,7 +234,7 @@ export default Ae.compose({
|
|
|
236
234
|
if (!this.rpcClient || !this.rpcClient.isConnected()) throw new Error('You are not connected to Wallet')
|
|
237
235
|
if (!this.rpcClient.currentAccount) throw new Error('You are not subscribed for an account.')
|
|
238
236
|
if (options.onAccount && !this.rpcClient.hasAccessToAccount(options.onAccount)) throw new Error(`You do not have access to account ${options.onAccount}`)
|
|
239
|
-
const opt =
|
|
237
|
+
const opt = { ...this.Ae.defaults, ...options }
|
|
240
238
|
if (!opt.walletBroadcast) {
|
|
241
239
|
const signed = await this.signTransaction(tx, { onAccount: opt.onAccount })
|
|
242
240
|
return this.sendTransaction(signed, opt)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { v4 as uuid } from 'uuid'
|
|
9
9
|
import Ae from '../../../ae'
|
|
10
|
+
import verifyTransaction from '../../../tx/validator'
|
|
10
11
|
import AccountMultiple from '../../../account/multiple'
|
|
11
12
|
import TxObject from '../../../tx/tx-object'
|
|
12
13
|
import RpcClient from './rpc-client'
|
|
@@ -73,7 +74,7 @@ const REQUESTS = {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
} catch (e) {
|
|
76
|
-
console.error(e)
|
|
77
|
+
if (instance.debug) console.error(e)
|
|
77
78
|
return { error: ERRORS.internalError({ msg: e.message }) }
|
|
78
79
|
}
|
|
79
80
|
},
|
|
@@ -111,22 +112,20 @@ const REQUESTS = {
|
|
|
111
112
|
try {
|
|
112
113
|
onAcc = resolveOnAccount(instance.addresses(), address, opt)
|
|
113
114
|
} catch (e) {
|
|
114
|
-
console.error(e)
|
|
115
|
+
if (instance.debug) console.error(e)
|
|
115
116
|
return { error: ERRORS.internalError({ msg: e.message }) }
|
|
116
117
|
}
|
|
117
118
|
try {
|
|
118
119
|
return {
|
|
119
|
-
result:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
: { transactionHash: await instance.send(rawTx || tx, { onAccount: onAcc, verify: false }) }
|
|
123
|
-
}
|
|
120
|
+
result: returnSigned
|
|
121
|
+
? { signedTransaction: await instance.signTransaction(rawTx || tx, { onAccount: onAcc }) }
|
|
122
|
+
: { transactionHash: await instance.send(rawTx || tx, { onAccount: onAcc, verify: false }) }
|
|
124
123
|
}
|
|
125
124
|
} catch (e) {
|
|
126
125
|
if (!returnSigned) {
|
|
127
126
|
// Validate transaction
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
127
|
+
const validation = await verifyTransaction(rawTx || tx, instance.selectedNode.instance)
|
|
128
|
+
if (validation.length) return { error: ERRORS.invalidTransaction(validation) }
|
|
130
129
|
// Send broadcast failed error to aepp
|
|
131
130
|
return { error: ERRORS.broadcastFailed(e.message) }
|
|
132
131
|
}
|
|
@@ -157,7 +156,7 @@ const REQUESTS = {
|
|
|
157
156
|
}
|
|
158
157
|
}
|
|
159
158
|
} catch (e) {
|
|
160
|
-
console.error(e)
|
|
159
|
+
if (instance.debug) console.error(e)
|
|
161
160
|
return { error: ERRORS.internalError({ msg: e.message }) }
|
|
162
161
|
}
|
|
163
162
|
},
|
|
@@ -88,7 +88,7 @@ export const formatAmount = (
|
|
|
88
88
|
const denominations = Object.values(AE_AMOUNT_FORMATS)
|
|
89
89
|
if (!denominations.includes(denomination)) throw new Error(`Invalid denomination: ${denomination}`)
|
|
90
90
|
if (!denominations.includes(targetDenomination)) throw new Error(`Invalid target denomination: ${targetDenomination}`)
|
|
91
|
-
if (!isBigNumber(value)) throw new Error(`Value ${value
|
|
91
|
+
if (!isBigNumber(value)) throw new Error(`Value ${value?.toString()} is not type of number`)
|
|
92
92
|
|
|
93
93
|
return new BigNumber(value)
|
|
94
94
|
.shiftedBy(DENOMINATION_MAGNITUDE[denomination] - DENOMINATION_MAGNITUDE[targetDenomination])
|
package/src/utils/bignumber.ts
CHANGED
|
@@ -19,7 +19,8 @@ export const parseBigNumber = (number: string | number | BigNumber): string =>
|
|
|
19
19
|
* @return {Boolean}
|
|
20
20
|
*/
|
|
21
21
|
export const isBigNumber = (number: string | number | BigNumber): boolean =>
|
|
22
|
-
|
|
22
|
+
['number', 'object', 'string', 'bigint'].includes(typeof number) &&
|
|
23
|
+
(!isNaN(number as number) || Number.isInteger(number) || BigNumber.isBigNumber(number))
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* BigNumber ceil operation
|
package/src/utils/crypto.js
CHANGED
|
@@ -28,6 +28,7 @@ import aesjs from 'aes-js'
|
|
|
28
28
|
import shajs from 'sha.js'
|
|
29
29
|
|
|
30
30
|
import { str2buf, toBytes } from './bytes'
|
|
31
|
+
import { decode } from '../tx/builder/helpers'
|
|
31
32
|
import { hash } from './crypto-ts'
|
|
32
33
|
|
|
33
34
|
export * from './crypto-ts'
|
|
@@ -56,7 +57,7 @@ export function getAddressFromPriv (secret) {
|
|
|
56
57
|
export function isAddressValid (address, prefix = 'ak') {
|
|
57
58
|
if (typeof address !== 'string') return false
|
|
58
59
|
try {
|
|
59
|
-
return
|
|
60
|
+
return decode(address, prefix).length === 32
|
|
60
61
|
} catch (e) {
|
|
61
62
|
return false
|
|
62
63
|
}
|
|
@@ -173,7 +174,7 @@ export function encodeUnsigned (value) {
|
|
|
173
174
|
* @return {String} - Contract address
|
|
174
175
|
*/
|
|
175
176
|
export function encodeContractAddress (owner, nonce) {
|
|
176
|
-
const publicKey =
|
|
177
|
+
const publicKey = decode(owner, 'ak')
|
|
177
178
|
const binary = Buffer.concat([publicKey, encodeUnsigned(nonce)])
|
|
178
179
|
return `ct_${encodeBase58Check(hash(binary))}`
|
|
179
180
|
}
|
|
@@ -296,20 +297,6 @@ export function aeEncodeKey (binaryKey) {
|
|
|
296
297
|
return `ak_${pubKeyAddress}`
|
|
297
298
|
}
|
|
298
299
|
|
|
299
|
-
/**
|
|
300
|
-
* Assert encoded type and return its payload
|
|
301
|
-
* @rtype (data: String, type: String) => String, throws: Error
|
|
302
|
-
* @param {String} data - ae data
|
|
303
|
-
* @param {String} type - Prefix
|
|
304
|
-
* @param {Boolean} omitError - Return false instead of throwing the error if data doesn't match expected type
|
|
305
|
-
* @return {String|Boolean} Payload
|
|
306
|
-
*/
|
|
307
|
-
export function assertedType (data, type, omitError) {
|
|
308
|
-
if (RegExp(`^${type}_.+$`).test(data)) return data.split('_')[1]
|
|
309
|
-
else if (omitError) return false
|
|
310
|
-
else throw new Error(`Data doesn't match expected type ${type}`)
|
|
311
|
-
}
|
|
312
|
-
|
|
313
300
|
/**
|
|
314
301
|
* Check key pair for validity
|
|
315
302
|
*
|
|
@@ -336,7 +323,7 @@ export function isValidKeypair (privateKey, publicKey) {
|
|
|
336
323
|
*/
|
|
337
324
|
export function encryptData (msg, publicKey) {
|
|
338
325
|
const ephemeralKeyPair = nacl.box.keyPair()
|
|
339
|
-
const pubKeyUInt8Array =
|
|
326
|
+
const pubKeyUInt8Array = decode(publicKey, 'ak')
|
|
340
327
|
const nonce = nacl.randomBytes(nacl.box.nonceLength)
|
|
341
328
|
|
|
342
329
|
const encryptedMessage = nacl.box(
|
package/src/utils/other.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { snakeToPascal, pascalToSnake } from './string'
|
|
2
2
|
|
|
3
|
-
export const pause = async (duration: number): Promise<
|
|
3
|
+
export const pause = async (duration: number): Promise<void> =>
|
|
4
4
|
await new Promise(resolve => setTimeout(resolve, duration))
|
|
5
5
|
|
|
6
6
|
export const mapObject = (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export default function (version: string, geVersion: string, ltVersion: string): boolean {
|
|
2
2
|
const getComponents = (v: string): number[] => v
|
|
3
|
-
.split(
|
|
3
|
+
.split(/[-+]/)[0].split('.').map(i => +i)
|
|
4
4
|
|
|
5
5
|
const versionComponents = getComponents(version)
|
|
6
6
|
const geComponents = getComponents(geVersion)
|
package/src/utils/swagger.js
CHANGED
|
@@ -39,13 +39,27 @@ let warnedAboutInternalApiUsage = false
|
|
|
39
39
|
* @param {String} [options.internalUrl] - Node internal URL
|
|
40
40
|
* @param {Boolean} [options.disableBigNumbers]
|
|
41
41
|
* @param {Boolean} [options.disableCaseConversion]
|
|
42
|
+
* @param {Function} [options.responseInterceptor]
|
|
42
43
|
* @return {Object} Swagger client
|
|
43
44
|
* @example (await genSwaggerClient('https://mainnet.aeternity.io/api')).getAccountByPubkey('ak_jupBUgZNbcC4krDLR3tAkw1iBZoBbkNeShAq4atBtpFWmz36r')
|
|
44
45
|
*/
|
|
45
|
-
export default async (
|
|
46
|
+
export default async (
|
|
47
|
+
specUrl,
|
|
48
|
+
{ spec, internalUrl, disableBigNumbers, disableCaseConversion, responseInterceptor } = {}
|
|
49
|
+
) => {
|
|
46
50
|
spec = spec || await (await fetch(specUrl)).json()
|
|
47
51
|
const jsonImp = disableBigNumbers ? JSON : JsonBig
|
|
48
52
|
|
|
53
|
+
if (
|
|
54
|
+
[
|
|
55
|
+
'https://compiler.aepps.com',
|
|
56
|
+
'https://latest.compiler.aepps.com'
|
|
57
|
+
].includes(new URL(specUrl).origin) ||
|
|
58
|
+
new URL(specUrl).origin.includes('https://')
|
|
59
|
+
) {
|
|
60
|
+
spec.schemes = ['https']
|
|
61
|
+
}
|
|
62
|
+
|
|
49
63
|
const [external, internal] = await Promise.all([specUrl, internalUrl].map((url) => {
|
|
50
64
|
if (!url) return null
|
|
51
65
|
return SwaggerClient({
|
|
@@ -54,9 +68,10 @@ export default async (specUrl, { spec, internalUrl, disableBigNumbers, disableCa
|
|
|
54
68
|
responseInterceptor: response => {
|
|
55
69
|
if (!response.text) return response
|
|
56
70
|
const body = jsonImp.parse(response.text)
|
|
57
|
-
|
|
71
|
+
Object.assign(response, {
|
|
58
72
|
body: disableCaseConversion ? body : pascalizeKeys(body)
|
|
59
73
|
})
|
|
74
|
+
return (responseInterceptor && responseInterceptor(response)) || response
|
|
60
75
|
}
|
|
61
76
|
})
|
|
62
77
|
}))
|
|
@@ -87,11 +102,13 @@ export default async (specUrl, { spec, internalUrl, disableBigNumbers, disableCa
|
|
|
87
102
|
const opSpec = opSpecs[opId]
|
|
88
103
|
const parameters = [
|
|
89
104
|
...opSpec.parameters,
|
|
90
|
-
...opSpec.requestBody
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
...opSpec.requestBody
|
|
106
|
+
? [{
|
|
107
|
+
required: opSpec.requestBody.required,
|
|
108
|
+
schema: Object.values(opSpec.requestBody.content)[0].schema,
|
|
109
|
+
name: '__requestBody'
|
|
110
|
+
}]
|
|
111
|
+
: []
|
|
95
112
|
]
|
|
96
113
|
const required = parameters.filter(param => param.required).map(p => p.name)
|
|
97
114
|
if (args.length < required.length) throw new Error('swagger: Not enough arguments')
|