mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-07-31 14:11:45 +00:00
Redsign qortal-ui repo
This commit is contained in:
22
crypto/api.js
Normal file
22
crypto/api.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Sha256 } from 'asmcrypto.js'
|
||||
import Base58 from './api/deps/Base58'
|
||||
import Base64 from './api/deps/Base64'
|
||||
import { base58PublicKeyToAddress } from './api/wallet/base58PublicKeyToAddress'
|
||||
import { validateAddress } from './api/wallet/validateAddress'
|
||||
import { decryptChatMessage, decryptChatMessageBase64 } from './api/transactions/chat/decryptChatMessage'
|
||||
import _ from 'lodash'
|
||||
|
||||
window.Sha256 = Sha256
|
||||
window.Base58 = Base58
|
||||
window.Base64 = Base64
|
||||
window._ = _
|
||||
window.base58PublicKeyToAddress = base58PublicKeyToAddress
|
||||
window.validateAddress = validateAddress
|
||||
window.decryptChatMessage = decryptChatMessage
|
||||
window.decryptChatMessageBase64 = decryptChatMessageBase64
|
||||
|
||||
export { initApi, store } from './api_deps.js'
|
||||
export * from './api/deps/deps.js'
|
||||
export * from './api/api.js'
|
||||
export * from './api/registerUsername.js'
|
||||
export { createWallet } from './api/createWallet.js'
|
209
crypto/api/PhraseWallet.js
Normal file
209
crypto/api/PhraseWallet.js
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
Copyright 2017-2018 @ irontiga and vbcs (original developer)
|
||||
*/
|
||||
'use strict'
|
||||
import Base58 from './deps/Base58.js'
|
||||
import { Sha256, Sha512 } from 'asmcrypto.js'
|
||||
import nacl from './deps/nacl-fast.js'
|
||||
import utils from './deps/utils.js'
|
||||
|
||||
import { generateSaveWalletData } from './storeWallet.js'
|
||||
|
||||
import publicKeyToAddress from './wallet/publicKeyToAddress.js'
|
||||
import AltcoinHDWallet from "./bitcoin/AltcoinHDWallet"
|
||||
|
||||
export default class PhraseWallet {
|
||||
constructor(seed, walletVersion) {
|
||||
|
||||
this._walletVersion = walletVersion || 2
|
||||
this.seed = seed
|
||||
|
||||
this.savedSeedData = {}
|
||||
this.hasBeenSaved = false
|
||||
}
|
||||
|
||||
set seed(seed) {
|
||||
this._byteSeed = seed
|
||||
this._base58Seed = Base58.encode(seed)
|
||||
|
||||
this._addresses = []
|
||||
|
||||
this.genAddress(0)
|
||||
}
|
||||
|
||||
getAddress(nonce) {
|
||||
return this._addresses[nonce]
|
||||
}
|
||||
|
||||
get addresses() {
|
||||
return this._addresses
|
||||
}
|
||||
|
||||
get addressIDs() {
|
||||
return this._addresses.map(addr => {
|
||||
return addr.address
|
||||
})
|
||||
}
|
||||
|
||||
get seed() {
|
||||
return this._byteSeed
|
||||
}
|
||||
|
||||
addressExists(nonce) {
|
||||
return this._addresses[nonce] != undefined
|
||||
}
|
||||
|
||||
_genAddressSeed(seed) {
|
||||
let newSeed = new Sha512().process(seed).finish().result
|
||||
newSeed = new Sha512().process(utils.appendBuffer(newSeed, seed)).finish().result
|
||||
return newSeed
|
||||
}
|
||||
|
||||
genAddress(nonce) {
|
||||
if (nonce >= this._addresses.length) {
|
||||
this._addresses.length = nonce + 1
|
||||
}
|
||||
|
||||
if (this.addressExists(nonce)) {
|
||||
return this.addresses[nonce]
|
||||
}
|
||||
|
||||
const nonceBytes = utils.int32ToBytes(nonce)
|
||||
|
||||
let addrSeed = new Uint8Array()
|
||||
addrSeed = utils.appendBuffer(addrSeed, nonceBytes)
|
||||
addrSeed = utils.appendBuffer(addrSeed, this._byteSeed)
|
||||
addrSeed = utils.appendBuffer(addrSeed, nonceBytes)
|
||||
|
||||
if (this._walletVersion == 1) {
|
||||
addrSeed = new Sha256().process(
|
||||
new Sha256()
|
||||
.process(addrSeed)
|
||||
.finish()
|
||||
.result
|
||||
).finish().result
|
||||
|
||||
addrSeed = this._byteSeed
|
||||
} else {
|
||||
addrSeed = this._genAddressSeed(addrSeed).slice(0, 32)
|
||||
}
|
||||
|
||||
const addrKeyPair = nacl.sign.keyPair.fromSeed(new Uint8Array(addrSeed));
|
||||
|
||||
const address = publicKeyToAddress(addrKeyPair.publicKey);
|
||||
const qoraAddress = publicKeyToAddress(addrKeyPair.publicKey, true);
|
||||
|
||||
// Create Bitcoin HD Wallet
|
||||
const btcSeed = [...addrSeed];
|
||||
const btcWallet = new AltcoinHDWallet({
|
||||
mainnet: {
|
||||
private: 0x0488ADE4,
|
||||
public: 0x0488B21E,
|
||||
prefix: 0
|
||||
},
|
||||
testnet: {
|
||||
private: 0x04358394,
|
||||
public: 0x043587CF,
|
||||
prefix: 0x6F
|
||||
}
|
||||
}).createWallet(new Uint8Array(btcSeed), false);
|
||||
|
||||
// Create Litecoin HD Wallet
|
||||
const ltcSeed = [...addrSeed];
|
||||
const ltcWallet = new AltcoinHDWallet({
|
||||
mainnet: {
|
||||
private: 0x0488ADE4,
|
||||
public: 0x0488B21E,
|
||||
prefix: 0x30
|
||||
},
|
||||
testnet: {
|
||||
private: 0x04358394,
|
||||
public: 0x043587CF,
|
||||
prefix: 0x6F
|
||||
}
|
||||
}).createWallet(new Uint8Array(ltcSeed), false, 'LTC');
|
||||
|
||||
// Create Dogecoin HD Wallet
|
||||
const dogeSeed = [...addrSeed];
|
||||
const dogeWallet = new AltcoinHDWallet({
|
||||
mainnet: {
|
||||
private: 0x02FAC398,
|
||||
public: 0x02FACAFD,
|
||||
prefix: 0x1E
|
||||
},
|
||||
testnet: {
|
||||
private: 0x04358394,
|
||||
public: 0x043587CF,
|
||||
prefix: 0x71
|
||||
}
|
||||
}).createWallet(new Uint8Array(dogeSeed), false, 'DOGE');
|
||||
|
||||
// Create Digibyte HD Wallet
|
||||
const dgbSeed = [...addrSeed];
|
||||
const dgbWallet = new AltcoinHDWallet({
|
||||
mainnet: {
|
||||
private: 0x0488ADE4,
|
||||
public: 0x0488B21E,
|
||||
prefix: 0x1E
|
||||
},
|
||||
testnet: {
|
||||
private: 0x04358394,
|
||||
public: 0x043587CF,
|
||||
prefix: 0x7E
|
||||
}
|
||||
}).createWallet(new Uint8Array(dgbSeed), false, 'DGB');
|
||||
|
||||
// Create Ravencoin HD Wallet
|
||||
const rvnSeed = [...addrSeed];
|
||||
const rvnWallet = new AltcoinHDWallet({
|
||||
mainnet: {
|
||||
private: 0x0488ADE4,
|
||||
public: 0x0488B21E,
|
||||
prefix: 0x3C
|
||||
},
|
||||
testnet: {
|
||||
private: 0x04358394,
|
||||
public: 0x043587CF,
|
||||
prefix: 0x6F
|
||||
}
|
||||
}).createWallet(new Uint8Array(rvnSeed), false, 'RVN');
|
||||
|
||||
// Create Pirate Chain HD Wallet
|
||||
const arrrSeed = [...addrSeed];
|
||||
const arrrWallet = new AltcoinHDWallet({
|
||||
mainnet: {
|
||||
private: 0x0488ADE4,
|
||||
public: 0x0488B21E,
|
||||
prefix: [0x16, 0x9A]
|
||||
},
|
||||
testnet: {
|
||||
private: 0x04358394,
|
||||
public: 0x043587CF,
|
||||
prefix: [0x14, 0x51]
|
||||
}
|
||||
}).createWallet(new Uint8Array(arrrSeed), false, 'ARRR');
|
||||
|
||||
this._addresses[nonce] = {
|
||||
address,
|
||||
btcWallet,
|
||||
ltcWallet,
|
||||
dogeWallet,
|
||||
dgbWallet,
|
||||
rvnWallet,
|
||||
arrrWallet,
|
||||
qoraAddress,
|
||||
keyPair: {
|
||||
publicKey: addrKeyPair.publicKey,
|
||||
privateKey: addrKeyPair.secretKey
|
||||
},
|
||||
base58PublicKey: Base58.encode(addrKeyPair.publicKey),
|
||||
seed: addrSeed,
|
||||
nonce: nonce
|
||||
}
|
||||
return this._addresses[nonce]
|
||||
}
|
||||
|
||||
generateSaveWalletData(...args) {
|
||||
return generateSaveWalletData(this, ...args)
|
||||
}
|
||||
}
|
5
crypto/api/api.js
Normal file
5
crypto/api/api.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export { request } from './fetch-request.js'
|
||||
export { transactionTypes as transactions } from './transactions/transactions.js'
|
||||
export { processTransaction, processTransactionVersion2, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction, signArbitraryWithFeeTransaction } from './createTransaction.js'
|
||||
export { tradeBotCreateRequest, tradeBotRespondRequest, signTradeBotTxn, deleteTradeOffer, sendBtc, sendLtc, sendDoge, sendDgb, sendRvn, sendArrr } from './tradeRequest.js'
|
||||
export { cancelAllOffers } from './transactions/trade-portal/tradeoffer/cancelAllOffers.js'
|
862
crypto/api/bitcoin/AltcoinHDWallet.js
Normal file
862
crypto/api/bitcoin/AltcoinHDWallet.js
Normal file
@@ -0,0 +1,862 @@
|
||||
'use strict';
|
||||
import Base58 from '../deps/Base58.js'
|
||||
import { Sha256, Sha512 } from 'asmcrypto.js'
|
||||
import jsSHA from 'jssha'
|
||||
import RIPEMD160 from '../deps/ripemd160.js'
|
||||
import utils from '../deps/utils.js'
|
||||
import { EllipticCurve, BigInteger } from './ecbn.js'
|
||||
|
||||
export default class AltcoinHDWallet {
|
||||
|
||||
constructor(addressParams) {
|
||||
|
||||
/**
|
||||
* Seed - 32 bytes
|
||||
*/
|
||||
|
||||
this.seed = new Uint8Array(32)
|
||||
|
||||
/**
|
||||
* Version Bytes - 4 byte
|
||||
*/
|
||||
|
||||
this.versionBytes = addressParams
|
||||
|
||||
/**
|
||||
* Depth - 1 byte
|
||||
*/
|
||||
|
||||
this.depth = 0
|
||||
|
||||
/**
|
||||
* Parent Fingerprint - 4 bytes
|
||||
*/
|
||||
|
||||
this.parentFingerprint = '0x00000000' // master key
|
||||
|
||||
/**
|
||||
* Child Index - 4 bytes
|
||||
*/
|
||||
|
||||
this.childIndex = '0x00000000' // master key
|
||||
|
||||
/**
|
||||
* Chain Code - 32 bytes
|
||||
*/
|
||||
|
||||
this.chainCode = new Uint8Array(32)
|
||||
|
||||
/**
|
||||
* Key Data - 33 bytes
|
||||
*/
|
||||
|
||||
this.keyData = new Uint8Array(33)
|
||||
|
||||
/**
|
||||
* Seed Hash - 64 bytes
|
||||
*/
|
||||
|
||||
this.seedHash = new Uint8Array(64)
|
||||
|
||||
/**
|
||||
* Private Key - 32 bytes
|
||||
*/
|
||||
|
||||
this.privateKey = new Uint8Array(32)
|
||||
|
||||
/**
|
||||
* Public Key - 33 bytes (compressed)
|
||||
*/
|
||||
|
||||
this.publicKey = new Uint8Array(33)
|
||||
|
||||
/**
|
||||
* Public Key Hash160 (used to derive the parent fingerprint for derived)
|
||||
*/
|
||||
|
||||
this.publicKeyHash = new Uint8Array(20)
|
||||
|
||||
/**
|
||||
* Master Private Key (Base58 encoded)
|
||||
*/
|
||||
|
||||
this.masterPrivateKey = ''
|
||||
|
||||
/**
|
||||
* Master Public Key (Base58 encoded)
|
||||
*/
|
||||
|
||||
this.masterPublicKey = ''
|
||||
|
||||
/**
|
||||
* Testnet Master Private Key (Base58 encoded) - THIS IS TESTNET
|
||||
*/
|
||||
|
||||
this._tMasterPrivateKey = ''
|
||||
|
||||
/**
|
||||
* Testnet Master Public Key (Base58 encoded) - THIS IS TESTNET
|
||||
*/
|
||||
|
||||
this._tmasterPublicKey = ''
|
||||
|
||||
/**
|
||||
* Child Keys Derivation from the Parent Keys
|
||||
*/
|
||||
|
||||
/**
|
||||
* Child Private Key - 32 bytes
|
||||
*/
|
||||
|
||||
this.childPrivateKey = new Uint8Array(32)
|
||||
|
||||
/**
|
||||
* Child Chain Code - 32 bytes
|
||||
*/
|
||||
|
||||
this.childChainCode = new Uint8Array(32)
|
||||
|
||||
/**
|
||||
* Child Public Key - 33 bytes (compressed)
|
||||
*/
|
||||
|
||||
this.childPublicKey = new Uint8Array(33)
|
||||
|
||||
/**
|
||||
* Child Public Key Hash160 (used to derive the parent fingerprint for derived)
|
||||
*/
|
||||
|
||||
this.childPublicKeyHash = new Uint8Array(20)
|
||||
|
||||
/**
|
||||
* Extended Private Child Key - Base58 encoded
|
||||
*/
|
||||
|
||||
this.xPrivateChildKey = ''
|
||||
|
||||
/**
|
||||
* Extended Public Child Key - Base58 encoded
|
||||
*/
|
||||
|
||||
this.xPublicChildKey = ''
|
||||
|
||||
/**
|
||||
* Grand Child Keys Derivation from the Child Keys
|
||||
*/
|
||||
|
||||
/**
|
||||
* Grand Child Private Key - 32 bytes
|
||||
*/
|
||||
|
||||
this.grandChildPrivateKey = new Uint8Array(32)
|
||||
|
||||
/**
|
||||
* Grand Child Chain Code - 32 bytes
|
||||
*/
|
||||
|
||||
this.grandChildChainCode = new Uint8Array(32)
|
||||
|
||||
/**
|
||||
* Grand Child Public Key - 33 bytes (compressed)
|
||||
*/
|
||||
|
||||
this.grandChildPublicKey = new Uint8Array(33)
|
||||
|
||||
/**
|
||||
* Grand Public Key Hash160 (used to derive the parent fingerprint for derived)
|
||||
*/
|
||||
|
||||
this.grandChildPublicKeyHash = new Uint8Array(20)
|
||||
|
||||
/**
|
||||
* Extended Private Grand Child Key - Base58 encoded
|
||||
*/
|
||||
|
||||
this.xPrivateGrandChildKey = ''
|
||||
|
||||
/**
|
||||
* Extended Public Grand Child Key - Base58 encoded
|
||||
*/
|
||||
|
||||
this.xPublicGrandChildKey = ''
|
||||
|
||||
/**
|
||||
* Litecoin Legacy Address - Derived from the Grand Child Public Key Hash
|
||||
*/
|
||||
|
||||
this.litecoinLegacyAddress = ''
|
||||
|
||||
/**
|
||||
* TESTNET Litecoin Legacy Address (Derived from the Grand Child Public Key Hash) - THIS IS TESTNET
|
||||
*/
|
||||
|
||||
this._tlitecoinLegacyAddress = ''
|
||||
|
||||
/**
|
||||
* Wallet - Wallet Object (keys...)
|
||||
*/
|
||||
|
||||
this.wallet = {}
|
||||
}
|
||||
|
||||
setSeed(seed) {
|
||||
this.seed = seed
|
||||
}
|
||||
|
||||
createWallet(seed, isBIP44, indicator = null) {
|
||||
|
||||
// Set Seeed
|
||||
this.setSeed(seed)
|
||||
|
||||
// Generate Seed Hash
|
||||
this.generateSeedHash(this.seed, isBIP44, indicator)
|
||||
|
||||
// Generate Private Key
|
||||
this.generatePrivateKey(this.seedHash)
|
||||
|
||||
// Generate Chain Code
|
||||
this.generateChainCode(this.seedHash)
|
||||
|
||||
// Generate Public Key from Private Key
|
||||
this.generatePublicKey(this.privateKey)
|
||||
|
||||
// Generate Mainnet Master Private Key
|
||||
this.generateMainnetMasterPrivateKey()
|
||||
|
||||
// Generate Mainnet Master Public Key
|
||||
this.generateMainnetMasterPublicKey()
|
||||
|
||||
// Generate Testnet Master Private Key
|
||||
this.generateTestnetMasterPrivateKey()
|
||||
|
||||
// Generate Testnet Master Public Key
|
||||
this.generateTestnetMasterPublicKey()
|
||||
|
||||
// Generate Child and Grand Child Keys
|
||||
this.generateDerivedChildKeys()
|
||||
|
||||
// Return Wallet Object Specification
|
||||
return this.returnWallet()
|
||||
}
|
||||
|
||||
|
||||
generateSeedHash(seed, isBIP44, indicator = null) {
|
||||
let buffer
|
||||
|
||||
if (isBIP44) {
|
||||
buffer = utils.appendBuffer(seed.reverse(), utils.int32ToBytes(indicator))
|
||||
} else {
|
||||
if(indicator !== null) {
|
||||
const indicatorString = utils.stringtoUTF8Array(indicator)
|
||||
buffer = utils.appendBuffer(seed.reverse(), indicatorString)
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = seed.reverse()
|
||||
}
|
||||
}
|
||||
|
||||
const _reverseSeedHash = new Sha256().process(buffer).finish().result
|
||||
this.seedHash = new Sha512().process(utils.appendBuffer(seed, _reverseSeedHash)).finish().result
|
||||
}
|
||||
|
||||
generatePrivateKey(seedHash) {
|
||||
const SECP256K1_CURVE_ORDER = new BigInteger("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
|
||||
|
||||
const privateKeyHash = seedHash.slice(0, 32)
|
||||
|
||||
this.seed58 = Base58.encode(privateKeyHash)
|
||||
|
||||
const _privateKeyHash = [...privateKeyHash]
|
||||
let privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKeyHash)
|
||||
|
||||
const privateKey = (privateKeyBigInt.mod(SECP256K1_CURVE_ORDER.subtract(BigInteger.ONE))).add(BigInteger.ONE)
|
||||
this.privateKey = privateKey.toByteArrayUnsigned()
|
||||
}
|
||||
|
||||
generateChainCode(seedHash) {
|
||||
this.chainCode = new Sha256().process(seedHash.slice(32, 64)).finish().result
|
||||
}
|
||||
|
||||
generatePublicKey(privateKey) {
|
||||
const _privateKey = [...privateKey]
|
||||
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
|
||||
|
||||
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
|
||||
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
|
||||
|
||||
|
||||
const x = curvePoints.getX().toBigInteger()
|
||||
const y = curvePoints.getY().toBigInteger()
|
||||
|
||||
/**
|
||||
* Deriving Uncompressed Public Key (65 bytes)
|
||||
*
|
||||
* const publicKeyBytes = EllipticCurve.integerToBytes(x, 32)
|
||||
* this.publicKey = publicKeyBytes.concat(EllipticCurve.integerToBytes(y, 32))
|
||||
* this.publicKey.unshift(0x04) // append point indicator
|
||||
*/
|
||||
|
||||
// Compressed Public Key (33 bytes)
|
||||
this.publicKey = EllipticCurve.integerToBytes(x, 32)
|
||||
|
||||
|
||||
if (y.isEven()) {
|
||||
this.publicKey.unshift(0x02) // append point indicator
|
||||
} else {
|
||||
this.publicKey.unshift(0x03) // append point indicator
|
||||
}
|
||||
|
||||
// PublicKey Hash
|
||||
const publicKeySHA256 = new Sha256().process(new Uint8Array(this.publicKey)).finish().result
|
||||
const _publicKeyHash = new RIPEMD160().update(Buffer.from(publicKeySHA256)).digest('hex')
|
||||
this.publicKeyHash = _publicKeyHash
|
||||
}
|
||||
|
||||
generateMainnetMasterPrivateKey() {
|
||||
// Serialization Variable
|
||||
const s = []
|
||||
|
||||
// Append Version Byte
|
||||
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
|
||||
|
||||
// Append Depth
|
||||
s.push(this.depth)
|
||||
|
||||
// Append Parent Fingerprint
|
||||
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
|
||||
|
||||
// Append Child Number
|
||||
s.push(...(utils.int32ToBytes(this.childIndex)))
|
||||
|
||||
// Append Chain Code
|
||||
s.push(...this.chainCode)
|
||||
|
||||
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
|
||||
s.push(0)
|
||||
|
||||
//if the private key length is less than 32 let's add leading zeros
|
||||
if(this.privateKey.length<32){
|
||||
for(let i=this.privateKey.length;i<32;i++){
|
||||
s.push(0)
|
||||
}
|
||||
}
|
||||
|
||||
// Append Private Key
|
||||
s.push(...this.privateKey)
|
||||
|
||||
// Generate CheckSum
|
||||
const _s = new Uint8Array(s)
|
||||
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
|
||||
const checkSum = _checkSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
s.push(...checkSum) // And this brings us to the end of the serialization...
|
||||
|
||||
// Save to Private Key as Base58 encoded
|
||||
this.masterPrivateKey = Base58.encode(s)
|
||||
}
|
||||
|
||||
generateMainnetMasterPublicKey() {
|
||||
// Serialization Variable
|
||||
const s = []
|
||||
|
||||
// Append Version Byte
|
||||
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
|
||||
|
||||
// Append Depth
|
||||
s.push(this.depth)
|
||||
|
||||
// Append Parent Fingerprint
|
||||
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
|
||||
|
||||
// Append Child Number
|
||||
s.push(...(utils.int32ToBytes(this.childIndex)))
|
||||
|
||||
// Append Chain Code
|
||||
s.push(...this.chainCode)
|
||||
|
||||
// Append Public Key
|
||||
s.push(...this.publicKey)
|
||||
|
||||
// Generate CheckSum
|
||||
const _s = new Uint8Array(s)
|
||||
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
|
||||
const checkSum = _checkSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
s.push(...checkSum) // And this brings us to the end of the serialization...
|
||||
|
||||
// Save to Public Key as Base58 encoded
|
||||
this.masterPublicKey = Base58.encode(s)
|
||||
}
|
||||
|
||||
generateTestnetMasterPrivateKey() {
|
||||
|
||||
// To be Used ONLY in Testnet...
|
||||
|
||||
// Serialization Variable
|
||||
const s = []
|
||||
|
||||
// Append Version Byte
|
||||
s.push(...(utils.int32ToBytes(this.versionBytes.testnet.private)))
|
||||
|
||||
// Append Depth
|
||||
s.push(this.depth)
|
||||
|
||||
// Append Parent Fingerprint
|
||||
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
|
||||
|
||||
// Append Child Number
|
||||
s.push(...(utils.int32ToBytes(this.childIndex)))
|
||||
|
||||
// Append Chain Code
|
||||
s.push(...this.chainCode)
|
||||
|
||||
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
|
||||
s.push(0)
|
||||
|
||||
// Append Private Key
|
||||
s.push(...this.privateKey)
|
||||
|
||||
// Generate CheckSum
|
||||
const _s = new Uint8Array(s)
|
||||
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
|
||||
const checkSum = _checkSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
s.push(...checkSum) // And this brings us to the end of the serialization...
|
||||
|
||||
// Save to Private Key as Base58 encoded
|
||||
this._tMasterPrivateKey = Base58.encode(s)
|
||||
}
|
||||
|
||||
generateTestnetMasterPublicKey() {
|
||||
|
||||
// To be Used ONLY in Testnet...
|
||||
|
||||
// Serialization Variable
|
||||
const s = []
|
||||
|
||||
// Append Version Byte
|
||||
s.push(...(utils.int32ToBytes(this.versionBytes.testnet.public)))
|
||||
|
||||
// Append Depth
|
||||
s.push(this.depth)
|
||||
|
||||
// Append Parent Fingerprint
|
||||
s.push(...(utils.int32ToBytes(this.parentFingerprint)))
|
||||
|
||||
// Append Child Number
|
||||
s.push(...(utils.int32ToBytes(this.childIndex)))
|
||||
|
||||
// Append Chain Code
|
||||
s.push(...this.chainCode)
|
||||
|
||||
// Append Private Key
|
||||
s.push(...this.publicKey)
|
||||
|
||||
// Generate CheckSum
|
||||
const _s = new Uint8Array(s)
|
||||
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
|
||||
const checkSum = _checkSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
s.push(...checkSum) // And this brings us to the end of the serialization...
|
||||
|
||||
// Save to Private Key as Base58 encoded
|
||||
this._tmasterPublicKey = Base58.encode(s)
|
||||
}
|
||||
|
||||
generateDerivedChildKeys() {
|
||||
|
||||
// SPEC INFO: https://en.bitcoin.it/wiki/BIP_0032#Child_key_derivation_.28CKD.29_functions
|
||||
// NOTE: will not be using some of derivations func as the value is known. (So I'd rather shove in the values and rewrite out the derivations later ?)
|
||||
|
||||
// NOTE: I "re-wrote" and "reduplicate" the code for child and grandChild keys derivations inorder to get the child and grandchild from the child
|
||||
// TODO: Make this more better in the future
|
||||
|
||||
const path = 'm/0/0'
|
||||
// let p = path.split('/')
|
||||
|
||||
// Get Public kEY
|
||||
const derivePublicChildKey = () => {
|
||||
|
||||
const _privateKey = [...this.childPrivateKey]
|
||||
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
|
||||
|
||||
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
|
||||
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
|
||||
|
||||
const x = curvePoints.getX().toBigInteger()
|
||||
const y = curvePoints.getY().toBigInteger()
|
||||
|
||||
// Compressed Public Key (33 bytes)
|
||||
this.childPublicKey = EllipticCurve.integerToBytes(x, 32)
|
||||
|
||||
|
||||
if (y.isEven()) {
|
||||
|
||||
this.childPublicKey.unshift(0x02) // append point indicator
|
||||
} else {
|
||||
|
||||
this.childPublicKey.unshift(0x03) // append point indicator
|
||||
}
|
||||
|
||||
// PublicKey Hash
|
||||
const childPublicKeySHA256 = new Sha256().process(new Uint8Array(this.childPublicKey)).finish().result
|
||||
const _childPublicKeyHash = new RIPEMD160().update(Buffer.from(childPublicKeySHA256)).digest('hex')
|
||||
this.childPublicKeyHash = _childPublicKeyHash
|
||||
|
||||
|
||||
// Call deriveExtendedPublicChildKey // WIll be hardcoding the values...
|
||||
deriveExtendedPublicChildKey(1, 0)
|
||||
}
|
||||
|
||||
const derivePrivateChildKey = (cI) => {
|
||||
|
||||
let ib = []
|
||||
ib.push((cI >> 24) & 0xff)
|
||||
ib.push((cI >> 16) & 0xff)
|
||||
ib.push((cI >> 8) & 0xff)
|
||||
ib.push(cI & 0xff)
|
||||
|
||||
const s = [...this.publicKey].concat(ib)
|
||||
|
||||
const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.chainCode, format: "UINT8ARRAY" } })
|
||||
_hmacSha512.update(new Uint8Array(s))
|
||||
|
||||
|
||||
const IL = BigInteger.fromByteArrayUnsigned([..._hmacSha512.getHMAC('UINT8ARRAY').slice(0, 32)])
|
||||
this.childChainCode = _hmacSha512.getHMAC('UINT8ARRAY').slice(32, 64) // IR according to the SPEC
|
||||
|
||||
|
||||
// SECP256k1 init
|
||||
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
|
||||
|
||||
|
||||
const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.privateKey)).mod(epCurve.getN()) // parse256(IL) + kpar (mod n) ==> ki
|
||||
this.childPrivateKey = ki.toByteArrayUnsigned()
|
||||
|
||||
// Call deriveExtendedPrivateChildKey
|
||||
deriveExtendedPrivateChildKey(1, 0)
|
||||
}
|
||||
|
||||
|
||||
const deriveExtendedPrivateChildKey = (i, childIndex) => {
|
||||
|
||||
// Serialization Variable
|
||||
const s = []
|
||||
|
||||
// Append Version Byte
|
||||
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
|
||||
|
||||
// Append Depth (using the index as depth)
|
||||
i = parseInt(i)
|
||||
s.push(i)
|
||||
|
||||
// Append Parent Fingerprint
|
||||
s.push(...(this.publicKeyHash.slice(0, 4)))
|
||||
|
||||
// Append Child Index
|
||||
s.push(childIndex >>> 24)
|
||||
s.push((childIndex >>> 16) & 0xff)
|
||||
s.push((childIndex >>> 8) & 0xff)
|
||||
s.push(childIndex & 0xff)
|
||||
|
||||
// Append Chain Code
|
||||
s.push(...this.childChainCode)
|
||||
|
||||
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
|
||||
s.push(0)
|
||||
|
||||
// Append Private Key
|
||||
s.push(...this.childPrivateKey)
|
||||
|
||||
// Generate CheckSum
|
||||
const _s = new Uint8Array(s)
|
||||
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
|
||||
const checkSum = _checkSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
s.push(...checkSum) // And this brings us to the end of the serialization...
|
||||
|
||||
// Save to Private Key as Base58 encoded
|
||||
this.xPrivateChildKey = Base58.encode(s)
|
||||
}
|
||||
|
||||
const deriveExtendedPublicChildKey = (i, childIndex) => {
|
||||
|
||||
// Serialization Variable
|
||||
const s = []
|
||||
|
||||
// Append Version Byte
|
||||
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
|
||||
|
||||
// Append Depth
|
||||
i = parseInt(i)
|
||||
s.push(i)
|
||||
|
||||
// Append Parent Fingerprint
|
||||
s.push(...(this.publicKeyHash.slice(0, 4)))
|
||||
|
||||
// Append Child Index
|
||||
s.push(childIndex >>> 24)
|
||||
s.push((childIndex >>> 16) & 0xff)
|
||||
s.push((childIndex >>> 8) & 0xff)
|
||||
s.push(childIndex & 0xff)
|
||||
|
||||
// Append Chain Code
|
||||
s.push(...this.childChainCode)
|
||||
|
||||
// Append Public Key
|
||||
s.push(...this.childPublicKey)
|
||||
|
||||
// Generate CheckSum
|
||||
const _s = new Uint8Array(s)
|
||||
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
|
||||
const checkSum = _checkSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
s.push(...checkSum) // And this brings us to the end of the serialization...
|
||||
|
||||
|
||||
// Save to Public Key as Base58 encoded
|
||||
this.xPublicChildKey = Base58.encode(s)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* GRAND CHILD KEYS
|
||||
*
|
||||
* NOTE: I know this is not the best way to generate this (even though it works the way it ought)
|
||||
* Things to rewrite will be and not limited to deriving this through a for loop, removing hard code values, etc...
|
||||
*/
|
||||
|
||||
const derivePublicGrandChildKey = () => {
|
||||
|
||||
const _privateKey = [...this.grandChildPrivateKey]
|
||||
const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey)
|
||||
|
||||
|
||||
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
|
||||
const curvePoints = epCurve.getG().multiply(privateKeyBigInt)
|
||||
|
||||
const x = curvePoints.getX().toBigInteger()
|
||||
const y = curvePoints.getY().toBigInteger()
|
||||
|
||||
// Compressed Public Key (33 bytes)
|
||||
this.grandChildPublicKey = EllipticCurve.integerToBytes(x, 32)
|
||||
|
||||
|
||||
if (y.isEven()) {
|
||||
this.grandChildPublicKey.unshift(0x02) // append point indicator
|
||||
} else {
|
||||
this.grandChildPublicKey.unshift(0x03) // append point indicator
|
||||
}
|
||||
|
||||
|
||||
// PublicKey Hash
|
||||
const grandChildPublicKeySHA256 = new Sha256().process(new Uint8Array(this.grandChildPublicKey)).finish().result
|
||||
const _grandChildPublicKeyHash = new RIPEMD160().update(Buffer.from(grandChildPublicKeySHA256)).digest('hex')
|
||||
this.grandChildPublicKeyHash = _grandChildPublicKeyHash
|
||||
|
||||
|
||||
// Call deriveExtendedPublicChildKey // WIll be hardcoding the values...
|
||||
deriveExtendedPublicGrandChildKey(2, 0)
|
||||
|
||||
/**
|
||||
* Derive Litecoin Legacy Address
|
||||
*/
|
||||
|
||||
// Append Address Prefix
|
||||
let prefix = [this.versionBytes.mainnet.prefix]
|
||||
if (2 == this.versionBytes.mainnet.prefix.length) {
|
||||
prefix = [this.versionBytes.mainnet.prefix[0]]
|
||||
prefix.push([this.versionBytes.mainnet.prefix[1]])
|
||||
}
|
||||
|
||||
const k = prefix.concat(...this.grandChildPublicKeyHash)
|
||||
|
||||
// Derive Checksum
|
||||
const _addressCheckSum = new Sha256().process(new Sha256().process(new Uint8Array(k)).finish().result).finish().result
|
||||
const addressCheckSum = _addressCheckSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
const _litecoinLegacyAddress = k.concat(...addressCheckSum)
|
||||
|
||||
// Convert to Base58
|
||||
this.litecoinLegacyAddress = Base58.encode(_litecoinLegacyAddress)
|
||||
|
||||
|
||||
/**
|
||||
* Derive TESTNET Litecoin Legacy Address
|
||||
*/
|
||||
|
||||
// Append Version Byte
|
||||
const tK = [this.versionBytes.testnet.prefix].concat(...this.grandChildPublicKeyHash)
|
||||
|
||||
// Derive Checksum
|
||||
const _tAddressCheckSum = new Sha256().process(new Sha256().process(new Uint8Array(tK)).finish().result).finish().result
|
||||
const tAddressCheckSum = _tAddressCheckSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
const _tlitecoinLegacyAddress = tK.concat(...tAddressCheckSum)
|
||||
|
||||
// Convert to Base58
|
||||
this._tlitecoinLegacyAddress = Base58.encode(_tlitecoinLegacyAddress)
|
||||
}
|
||||
|
||||
const derivePrivateGrandChildKey = (cI, i) => {
|
||||
|
||||
let ib = []
|
||||
ib.push((cI >> 24) & 0xff)
|
||||
ib.push((cI >> 16) & 0xff)
|
||||
ib.push((cI >> 8) & 0xff)
|
||||
ib.push(cI & 0xff)
|
||||
|
||||
const s = [...this.childPublicKey].concat(ib)
|
||||
|
||||
|
||||
const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.childChainCode, format: "UINT8ARRAY" } })
|
||||
_hmacSha512.update(new Uint8Array(s))
|
||||
|
||||
|
||||
const IL = BigInteger.fromByteArrayUnsigned([..._hmacSha512.getHMAC('UINT8ARRAY').slice(0, 32)])
|
||||
this.grandChildChainCode = _hmacSha512.getHMAC('UINT8ARRAY').slice(32, 64) // IR according to the SPEC
|
||||
|
||||
// SECP256k1 init
|
||||
const epCurve = EllipticCurve.getSECCurveByName("secp256k1")
|
||||
|
||||
|
||||
const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.childPrivateKey)).mod(epCurve.getN()) // parse256(IL) + kpar (mod n) ==> ki
|
||||
this.grandChildPrivateKey = ki.toByteArrayUnsigned()
|
||||
|
||||
|
||||
// Call deriveExtendedPrivateChildKey
|
||||
deriveExtendedPrivateGrandChildKey(2, 0)
|
||||
}
|
||||
|
||||
|
||||
const deriveExtendedPrivateGrandChildKey = (i, childIndex) => {
|
||||
|
||||
// Serialization Variable
|
||||
const s = []
|
||||
|
||||
// Append Version Byte
|
||||
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.private)))
|
||||
|
||||
// Append Depth (using the index as depth)
|
||||
i = parseInt(i)
|
||||
s.push(i)
|
||||
|
||||
// Append Parent Fingerprint
|
||||
s.push(...(this.childPublicKeyHash.slice(0, 4)))
|
||||
|
||||
// Append Child Index
|
||||
s.push(childIndex >>> 24)
|
||||
s.push((childIndex >>> 16) & 0xff)
|
||||
s.push((childIndex >>> 8) & 0xff)
|
||||
s.push(childIndex & 0xff)
|
||||
|
||||
// Append Chain Code
|
||||
s.push(...this.grandChildChainCode)
|
||||
|
||||
// Append 1 byte '0x00' (to make the key data 33 bytes, DO THIS ONLY FOR PRIVATE KEYS )
|
||||
s.push(0)
|
||||
|
||||
// Append Private Key
|
||||
s.push(...this.grandChildPrivateKey)
|
||||
|
||||
// Generate CheckSum
|
||||
const _s = new Uint8Array(s)
|
||||
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
|
||||
const checkSum = _checkSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
s.push(...checkSum) // And this brings us to the end of the serialization...
|
||||
|
||||
// Save to Private Key as Base58 encoded
|
||||
this.xPrivateGrandChildKey = Base58.encode(s)
|
||||
}
|
||||
|
||||
const deriveExtendedPublicGrandChildKey = (i, childIndex) => {
|
||||
|
||||
// Serialization Variable
|
||||
const s = []
|
||||
|
||||
// Append Version Byte
|
||||
s.push(...(utils.int32ToBytes(this.versionBytes.mainnet.public)))
|
||||
|
||||
// Append Depth
|
||||
i = parseInt(i)
|
||||
s.push(i)
|
||||
|
||||
// Append Parent Fingerprint
|
||||
s.push(...(this.childPublicKeyHash.slice(0, 4)))
|
||||
|
||||
// Append Child Index
|
||||
s.push(childIndex >>> 24)
|
||||
s.push((childIndex >>> 16) & 0xff)
|
||||
s.push((childIndex >>> 8) & 0xff)
|
||||
s.push(childIndex & 0xff)
|
||||
|
||||
// Append Chain Code
|
||||
s.push(...this.grandChildChainCode)
|
||||
|
||||
// Append Public Key
|
||||
s.push(...this.grandChildPublicKey)
|
||||
|
||||
// Generate CheckSum
|
||||
const _s = new Uint8Array(s)
|
||||
const _checkSum = new Sha256().process(new Sha256().process(_s).finish().result).finish().result
|
||||
const checkSum = _checkSum.slice(0, 4)
|
||||
|
||||
// Append CheckSum
|
||||
s.push(...checkSum) // And this brings us to the end of the serialization...
|
||||
|
||||
// Save to Public Key as Base58 encoded
|
||||
this.xPublicGrandChildKey = Base58.encode(s)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Hard Code value..
|
||||
let childIndex = 0
|
||||
|
||||
// Call derivePrivateChildKey //Hard code value
|
||||
derivePrivateChildKey(childIndex)
|
||||
|
||||
// Call derivePublicChildKey
|
||||
derivePublicChildKey()
|
||||
|
||||
|
||||
// Call derivePrivateGrandChildKey // Hard Code value...
|
||||
derivePrivateGrandChildKey(0, 2)
|
||||
|
||||
// Call derivePublicGrandChildKey
|
||||
derivePublicGrandChildKey()
|
||||
}
|
||||
|
||||
returnWallet() {
|
||||
|
||||
// Will be limiting the exported Wallet Object to just the Master keys and Legacy Addresses
|
||||
|
||||
const wallet = {
|
||||
derivedMasterPrivateKey: this.masterPrivateKey,
|
||||
derivedMasterPublicKey: this.masterPublicKey,
|
||||
_tDerivedMasterPrivateKey: this._tMasterPrivateKey,
|
||||
_tDerivedmasterPublicKey: this._tmasterPublicKey,
|
||||
seed58: this.seed58,
|
||||
// derivedPrivateChildKey: this.xPrivateChildKey,
|
||||
// derivedPublicChildKey: this.xPublicChildKey,
|
||||
// derivedPrivateGrandChildKey: this.xPrivateGrandChildKey,
|
||||
// derivedPublicGrandChildKey: this.xPublicGrandChildKey,
|
||||
address: this.litecoinLegacyAddress,
|
||||
_taddress: this._tlitecoinLegacyAddress
|
||||
}
|
||||
|
||||
this.wallet = wallet
|
||||
return wallet
|
||||
}
|
||||
}
|
2620
crypto/api/bitcoin/ecbn.js
Normal file
2620
crypto/api/bitcoin/ecbn.js
Normal file
File diff suppressed because it is too large
Load Diff
1940
crypto/api/bitcoin/jsbn.js
Normal file
1940
crypto/api/bitcoin/jsbn.js
Normal file
File diff suppressed because it is too large
Load Diff
171
crypto/api/constants.js
Normal file
171
crypto/api/constants.js
Normal file
@@ -0,0 +1,171 @@
|
||||
'use strict'
|
||||
|
||||
// Qortal TX types
|
||||
const TX_TYPES = {
|
||||
1: "Genesis",
|
||||
2: "Payment",
|
||||
3: "Name registration",
|
||||
4: "Name update",
|
||||
5: "Sell name",
|
||||
6: "Cancel sell name",
|
||||
7: "Buy name",
|
||||
8: "Create poll",
|
||||
9: "Vote in poll",
|
||||
10: "Arbitrary",
|
||||
11: "Issue asset",
|
||||
12: "Transfer asset",
|
||||
13: "Create asset order",
|
||||
14: "Cancel asset order",
|
||||
15: "Multi-payment transaction",
|
||||
16: "Deploy AT",
|
||||
17: "Message",
|
||||
18: "Chat",
|
||||
19: "Publicize",
|
||||
20: "Airdrop",
|
||||
21: "AT",
|
||||
22: "Create group",
|
||||
23: "Update group",
|
||||
24: "Add group admin",
|
||||
25: "Remove group admin",
|
||||
26: "Group ban",
|
||||
27: "Cancel group ban",
|
||||
28: "Group kick",
|
||||
29: "Group invite",
|
||||
30: "Cancel group invite",
|
||||
31: "Join group",
|
||||
32: "Leave group",
|
||||
33: "Group approval",
|
||||
34: "Set group",
|
||||
35: "Update asset",
|
||||
36: "Account flags",
|
||||
37: "Enable forging",
|
||||
38: "Reward share",
|
||||
39: "Account level",
|
||||
40: "Transfer privs",
|
||||
41: "Presence"
|
||||
}
|
||||
|
||||
// Qortal error codes
|
||||
const ERROR_CODES = {
|
||||
1: "Valid OK",
|
||||
2: "Invalid address",
|
||||
3: "Negative amount",
|
||||
4: "Nagative fee",
|
||||
5: "No balance",
|
||||
6: "Invalid reference",
|
||||
7: "Invalid time length",
|
||||
8: "Invalid value length",
|
||||
9: "Name already registered",
|
||||
10: "Name does not exist",
|
||||
11: "Invalid name owner",
|
||||
12: "Name already for sale",
|
||||
13: "Name not for sale",
|
||||
14: "Name buyer already owner",
|
||||
15: "Invalid amount",
|
||||
16: "Invalid seller",
|
||||
17: "Name not lowercase",
|
||||
18: "Invalid description length",
|
||||
19: "Invalid options length",
|
||||
20: "Invalid option length",
|
||||
21: "Duplicate option",
|
||||
22: "Poll already created",
|
||||
23: "Poll already has votes",
|
||||
24: "Poll does not exist",
|
||||
25: "Option does not exist",
|
||||
26: "Already voted for that option",
|
||||
27: "Invalid data length",
|
||||
28: "Invalid quantity",
|
||||
29: "Asset does not exist",
|
||||
30: "Invalid return",
|
||||
31: "Have equals want",
|
||||
32: "Order does not exist",
|
||||
33: "Invalid order creator",
|
||||
34: "Invalid payments length",
|
||||
35: "Negative price",
|
||||
36: "Invalid creation bytes",
|
||||
37: "Invalid tags length",
|
||||
38: "Invalid type length",
|
||||
39: "Invalid AT transaction",
|
||||
40: "Insufficient fee",
|
||||
41: "Asset does not match AT",
|
||||
|
||||
43: "Asset already exists",
|
||||
44: "Missing creator",
|
||||
45: "Timestamp too old",
|
||||
46: "Timestamp too new",
|
||||
47: "Too many unconfirmed",
|
||||
48: "Group already exists",
|
||||
49: "Group does not exist",
|
||||
50: "Invalid group owner",
|
||||
51: "Already group memeber",
|
||||
52: "Group owner can not leave",
|
||||
53: "Not group member",
|
||||
54: "Already group admin",
|
||||
55: "Not group admin",
|
||||
56: "Invalid lifetime",
|
||||
57: "Invite unknown",
|
||||
58: "Ban exists",
|
||||
59: "Ban unknown",
|
||||
60: "Banned from group",
|
||||
61: "Join request",
|
||||
62: "Invalid group approval threshold",
|
||||
63: "Group ID mismatch",
|
||||
64: "Invalid group ID",
|
||||
65: "Transaction unknown",
|
||||
66: "Transaction already confirmed",
|
||||
67: "Invalid TX group",
|
||||
68: "TX group ID mismatch",
|
||||
69: "Multiple names forbidden",
|
||||
70: "Invalid asset owner",
|
||||
71: "AT is finished",
|
||||
72: "No flag permission",
|
||||
73: "Not minting accout",
|
||||
|
||||
77: "Invalid rewardshare percent",
|
||||
78: "Public key unknown",
|
||||
79: "Invalid public key",
|
||||
80: "AT unknown",
|
||||
81: "AT already exists",
|
||||
82: "Group approval not required",
|
||||
83: "Group approval decided",
|
||||
84: "Maximum reward shares",
|
||||
85: "Transaction already exists",
|
||||
86: "No blockchain lock",
|
||||
87: "Order already closed",
|
||||
88: "Clock not synced",
|
||||
89: "Asset not spendable",
|
||||
90: "Account can not reward share",
|
||||
91: "Self share exists",
|
||||
92: "Account already exists",
|
||||
93: "Invalid group block delay",
|
||||
94: "Incorrect nonce",
|
||||
95: "Ivalid timestamp signature",
|
||||
96: "Address blocked",
|
||||
97: "Name Blocked",
|
||||
98: "Group approval required",
|
||||
99: "Account not transferable",
|
||||
|
||||
999: "Ivalid but ok",
|
||||
1000: "Not yet released."
|
||||
}
|
||||
|
||||
// Qortal 8 decimals
|
||||
const QORT_DECIMALS = 1e8
|
||||
|
||||
// Q for Qortal
|
||||
const ADDRESS_VERSION = 58
|
||||
|
||||
// Proxy for api calls
|
||||
const PROXY_URL = "/proxy/"
|
||||
|
||||
// Chat reference timestamp
|
||||
const CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP = 1674316800000
|
||||
|
||||
// Used as a salt for all qora addresses. Salts used for storing your private keys in local storage will be randomly generated
|
||||
const STATIC_SALT = new Uint8Array([54, 190, 201, 206, 65, 29, 123, 129, 147, 231, 180, 166, 171, 45, 95, 165, 78, 200, 208, 194, 44, 207, 221, 146, 45, 238, 68, 68, 69, 102, 62, 6])
|
||||
const BCRYPT_ROUNDS = 10 // Remember that the total work spent on key derivation is BCRYPT_ROUNDS * KDF_THREADS
|
||||
const BCRYPT_VERSION = "2a"
|
||||
const STATIC_BCRYPT_SALT = `$${BCRYPT_VERSION}$${BCRYPT_ROUNDS}$IxVE941tXVUD4cW0TNVm.O`
|
||||
const KDF_THREADS = 16
|
||||
|
||||
export { TX_TYPES, ERROR_CODES, QORT_DECIMALS, PROXY_URL, STATIC_SALT, ADDRESS_VERSION, KDF_THREADS, STATIC_BCRYPT_SALT, CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP }
|
51
crypto/api/createTransaction.js
Normal file
51
crypto/api/createTransaction.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { transactionTypes as transactions } from './transactions/transactions.js'
|
||||
import Base58 from './deps/Base58.js'
|
||||
import { request } from './fetch-request'
|
||||
import signChat from './transactions/chat/signChat.js'
|
||||
import signArbitrary from './transactions/arbitrary/signArbitrary.js'
|
||||
import signArbitraryWithFee from './transactions/arbitrary/signArbitraryWithFee.js'
|
||||
|
||||
|
||||
export const createTransaction = (type, keyPair, params) => {
|
||||
const tx = new transactions[type]()
|
||||
tx.keyPair = keyPair
|
||||
Object.keys(params).forEach(param => {
|
||||
tx[param] = params[param]
|
||||
})
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
// Compute Chat Nonce
|
||||
export const computeChatNonce = bytes => request('/chat/compute', {
|
||||
method: 'POST',
|
||||
body: Base58.encode(bytes)
|
||||
})
|
||||
|
||||
// Sign Chat Transactions
|
||||
export const signChatTransaction = (chatBytes, nonce, keyPair) => {
|
||||
return signChat(chatBytes, nonce, keyPair)
|
||||
}
|
||||
|
||||
// Sign Arbitrary Transactions
|
||||
export const signArbitraryTransaction = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair) => {
|
||||
return signArbitrary(arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair)
|
||||
}
|
||||
|
||||
export const signArbitraryWithFeeTransaction = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair) => {
|
||||
return signArbitraryWithFee(arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Process Transactions
|
||||
export const processTransaction = bytes => request('/transactions/process', {
|
||||
method: 'POST',
|
||||
body: Base58.encode(bytes)
|
||||
})
|
||||
|
||||
export const processTransactionVersion2 = bytes => request('/transactions/process?apiVersion=2', {
|
||||
method: 'POST',
|
||||
body: Base58.encode(bytes)
|
||||
})
|
||||
|
29
crypto/api/createWallet.js
Normal file
29
crypto/api/createWallet.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { kdf } from './kdf.js'
|
||||
import PhraseWallet from './PhraseWallet.js'
|
||||
import Base58 from './deps/Base58.js'
|
||||
import { decryptStoredWallet } from './decryptStoredWallet.js'
|
||||
|
||||
export const createWallet = async (sourceType, source, statusUpdateFn) => {
|
||||
let version, seed
|
||||
|
||||
switch (sourceType) {
|
||||
case 'phrase':
|
||||
version = 2
|
||||
seed = await kdf(source.seedPhrase, void 0, statusUpdateFn)
|
||||
break
|
||||
case 'seed':
|
||||
version = 1
|
||||
seed = Base58.decode(source.seed)
|
||||
break
|
||||
case 'storedWallet':
|
||||
case 'backedUpSeed':
|
||||
version = source.wallet.version
|
||||
seed = await decryptStoredWallet(source.password, source.wallet, statusUpdateFn)
|
||||
break
|
||||
default:
|
||||
throw 'sourceType ' + sourceType + ' not recognized'
|
||||
}
|
||||
|
||||
const wallet = new PhraseWallet(seed, version)
|
||||
return wallet
|
||||
}
|
23
crypto/api/decryptStoredWallet.js
Normal file
23
crypto/api/decryptStoredWallet.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import Base58 from './deps/Base58.js'
|
||||
import { kdf } from './kdf.js'
|
||||
import { HmacSha512, AES_CBC } from 'asmcrypto.js'
|
||||
|
||||
export const decryptStoredWallet = async (password, wallet, statusFn = () => { }) => {
|
||||
statusFn('Decoding saved data')
|
||||
const encryptedSeedBytes = Base58.decode(wallet.encryptedSeed)
|
||||
const iv = Base58.decode(wallet.iv)
|
||||
const salt = Base58.decode(wallet.salt)
|
||||
statusFn('Generating decryption key')
|
||||
const key = await kdf(password, salt, statusFn)
|
||||
const encryptionKey = key.slice(0, 32)
|
||||
const macKey = key.slice(32, 63)
|
||||
|
||||
statusFn('Checking key')
|
||||
const mac = new HmacSha512(macKey).process(encryptedSeedBytes).finish().result
|
||||
if (Base58.encode(mac) !== wallet.mac) {
|
||||
throw new Error('Incorrect password')
|
||||
}
|
||||
statusFn('Decrypting')
|
||||
const decryptedBytes = AES_CBC.decrypt(encryptedSeedBytes, encryptionKey, false, iv)
|
||||
return decryptedBytes
|
||||
}
|
108
crypto/api/deps/Base58.js
Normal file
108
crypto/api/deps/Base58.js
Normal file
@@ -0,0 +1,108 @@
|
||||
// Generated by CoffeeScript 1.8.0
|
||||
|
||||
// == Changed for ES6 modules == //
|
||||
//(function() {
|
||||
//var ALPHABET, ALPHABET_MAP, Base58, i;
|
||||
|
||||
//const Base58 = (typeof module !== "undefined" && module !== null ? module.exports : void 0) || (window.Base58 = {});
|
||||
const Base58 = {};
|
||||
|
||||
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
const ALPHABET_MAP = {};
|
||||
|
||||
let i = 0;
|
||||
|
||||
while (i < ALPHABET.length) {
|
||||
ALPHABET_MAP[ALPHABET.charAt(i)] = i;
|
||||
i++;
|
||||
}
|
||||
|
||||
Base58.encode = function(buffer) {
|
||||
buffer = new Uint8Array(buffer);
|
||||
var carry, digits, j;
|
||||
if (buffer.length === 0) {
|
||||
return "";
|
||||
}
|
||||
i = void 0;
|
||||
j = void 0;
|
||||
digits = [0];
|
||||
i = 0;
|
||||
while (i < buffer.length) {
|
||||
j = 0;
|
||||
while (j < digits.length) {
|
||||
digits[j] <<= 8;
|
||||
j++;
|
||||
}
|
||||
digits[0] += buffer[i];
|
||||
carry = 0;
|
||||
j = 0;
|
||||
while (j < digits.length) {
|
||||
digits[j] += carry;
|
||||
carry = (digits[j] / 58) | 0;
|
||||
digits[j] %= 58;
|
||||
++j;
|
||||
}
|
||||
while (carry) {
|
||||
digits.push(carry % 58);
|
||||
carry = (carry / 58) | 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
while (buffer[i] === 0 && i < buffer.length - 1) {
|
||||
digits.push(0);
|
||||
i++;
|
||||
}
|
||||
return digits.reverse().map(function(digit) {
|
||||
return ALPHABET[digit];
|
||||
}).join("");
|
||||
};
|
||||
|
||||
Base58.decode = function(string) {
|
||||
var bytes, c, carry, j;
|
||||
if (string.length === 0) {
|
||||
return new (typeof Uint8Array !== "undefined" && Uint8Array !== null ? Uint8Array : Buffer)(0);
|
||||
}
|
||||
i = void 0;
|
||||
j = void 0;
|
||||
bytes = [0];
|
||||
i = 0;
|
||||
while (i < string.length) {
|
||||
c = string[i];
|
||||
if (!(c in ALPHABET_MAP)) {
|
||||
throw "Base58.decode received unacceptable input. Character '" + c + "' is not in the Base58 alphabet.";
|
||||
}
|
||||
j = 0;
|
||||
while (j < bytes.length) {
|
||||
bytes[j] *= 58;
|
||||
j++;
|
||||
}
|
||||
bytes[0] += ALPHABET_MAP[c];
|
||||
carry = 0;
|
||||
j = 0;
|
||||
while (j < bytes.length) {
|
||||
bytes[j] += carry;
|
||||
carry = bytes[j] >> 8;
|
||||
bytes[j] &= 0xff;
|
||||
++j;
|
||||
}
|
||||
while (carry) {
|
||||
bytes.push(carry & 0xff);
|
||||
carry >>= 8;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
while (string[i] === "1" && i < string.length - 1) {
|
||||
bytes.push(0);
|
||||
i++;
|
||||
}
|
||||
return new (typeof Uint8Array !== "undefined" && Uint8Array !== null ? Uint8Array : Buffer)(bytes.reverse());
|
||||
};
|
||||
|
||||
|
||||
// == Changed for ES6 modules == //
|
||||
//}).call(this);
|
||||
|
||||
export default Base58;
|
24
crypto/api/deps/Base64.js
Normal file
24
crypto/api/deps/Base64.js
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
const Base64 = {};
|
||||
|
||||
|
||||
|
||||
Base64.decode = function (string) {
|
||||
|
||||
const binaryString = atob(string);
|
||||
const binaryLength = binaryString.length;
|
||||
const bytes = new Uint8Array(binaryLength);
|
||||
|
||||
for (let i = 0; i < binaryLength; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
const decoder = new TextDecoder();
|
||||
const decodedString = decoder.decode(bytes);
|
||||
return decodedString;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
export default Base64;
|
1379
crypto/api/deps/bcrypt.js
Normal file
1379
crypto/api/deps/bcrypt.js
Normal file
File diff suppressed because it is too large
Load Diff
180
crypto/api/deps/broken-ripemd160.js
Normal file
180
crypto/api/deps/broken-ripemd160.js
Normal file
@@ -0,0 +1,180 @@
|
||||
// "Generated from Java with JSweet 1.0.0 - http://www.jsweet.org";
|
||||
// BAD IMPLEMENTATION. BROKEN, BUT MUST KEEP CAUSE OF NETWORK
|
||||
//const RIPEMD160 = (function () {
|
||||
// == Convert to ES6 module for export == //
|
||||
const RIPEMD160 = (function () {
|
||||
function RIPEMD160() {
|
||||
this.MDbuf = [];
|
||||
this.MDbuf[0] = 1732584193;
|
||||
this.MDbuf[1] = -271733879;
|
||||
this.MDbuf[2] = -1732584194;
|
||||
this.MDbuf[3] = 271733878;
|
||||
this.MDbuf[4] = -1009589776;
|
||||
this.working = new Int32Array(16);
|
||||
|
||||
this.working_ptr = 0;
|
||||
this.msglen = 0;
|
||||
}
|
||||
RIPEMD160.prototype.reset = function () {
|
||||
this.MDbuf = [];
|
||||
this.MDbuf[0] = 1732584193;
|
||||
this.MDbuf[1] = -271733879;
|
||||
this.MDbuf[2] = -1732584194;
|
||||
this.MDbuf[3] = 271733878;
|
||||
this.MDbuf[4] = -1009589776;
|
||||
this.working = new Int32Array(16);
|
||||
this.working_ptr = 0;
|
||||
this.msglen = 0;
|
||||
};
|
||||
RIPEMD160.prototype.compress = function (X) {
|
||||
var index = 0;
|
||||
var a;
|
||||
var b;
|
||||
var c;
|
||||
var d;
|
||||
var e;
|
||||
var A;
|
||||
var B;
|
||||
var C;
|
||||
var D;
|
||||
var E;
|
||||
var temp;
|
||||
var s;
|
||||
A = a = this.MDbuf[0];
|
||||
B = b = this.MDbuf[1];
|
||||
C = c = this.MDbuf[2];
|
||||
D = d = this.MDbuf[3];
|
||||
E = e = this.MDbuf[4];
|
||||
for (; index < 16; index++) {
|
||||
temp = a + (b ^ c ^ d) + X[RIPEMD160.IndexArray[0][index]];
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + (B ^ (C | ~D)) + X[RIPEMD160.IndexArray[1][index]] + 1352829926;
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
for (; index < 32; index++) {
|
||||
temp = a + ((b & c) | (~b & d)) + X[RIPEMD160.IndexArray[0][index]] + 1518500249;
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + ((B & D) | (C & ~D)) + X[RIPEMD160.IndexArray[1][index]] + 1548603684;
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
for (; index < 48; index++) {
|
||||
temp = a + ((b | ~c) ^ d) + X[RIPEMD160.IndexArray[0][index]] + 1859775393;
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + ((B | ~C) ^ D) + X[RIPEMD160.IndexArray[1][index]] + 1836072691;
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
for (; index < 64; index++) {
|
||||
temp = a + ((b & d) | (c & ~d)) + X[RIPEMD160.IndexArray[0][index]] + -1894007588;
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + ((B & C) | (~B & D)) + X[RIPEMD160.IndexArray[1][index]] + 2053994217;
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
for (; index < 80; index++) {
|
||||
temp = a + (b ^ (c | ~d)) + X[RIPEMD160.IndexArray[0][index]] + -1454113458;
|
||||
a = e;
|
||||
e = d;
|
||||
d = (c << 10) | (c >>> 22);
|
||||
c = b;
|
||||
s = RIPEMD160.ArgArray[0][index];
|
||||
b = ((temp << s) | (temp >>> (32 - s))) + a;
|
||||
temp = A + (B ^ C ^ D) + X[RIPEMD160.IndexArray[1][index]];
|
||||
A = E;
|
||||
E = D;
|
||||
D = (C << 10) | (C >>> 22);
|
||||
C = B;
|
||||
s = RIPEMD160.ArgArray[1][index];
|
||||
B = ((temp << s) | (temp >>> (32 - s))) + A;
|
||||
}
|
||||
D += c + this.MDbuf[1];
|
||||
this.MDbuf[1] = this.MDbuf[2] + d + E;
|
||||
this.MDbuf[2] = this.MDbuf[3] + e + A;
|
||||
this.MDbuf[3] = this.MDbuf[4] + a + B;
|
||||
this.MDbuf[4] = this.MDbuf[0] + b + C;
|
||||
this.MDbuf[0] = D;
|
||||
};
|
||||
RIPEMD160.prototype.MDfinish = function (array, lswlen, mswlen) {
|
||||
var X = array;
|
||||
X[(lswlen >> 2) & 15] ^= 1 << (((lswlen & 3) << 3) + 7);
|
||||
if (((lswlen & 63) > 55)) {
|
||||
this.compress(X);
|
||||
for (var i = 0; i < 14; i++) {
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
X[14] = lswlen << 3;
|
||||
X[15] = (lswlen >> 29) | (mswlen << 3);
|
||||
this.compress(X);
|
||||
};
|
||||
RIPEMD160.prototype.update = function (input) {
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
this.working[this.working_ptr >> 2] ^= input[i] << ((this.working_ptr & 3) << 3);
|
||||
this.working_ptr++;
|
||||
if ((this.working_ptr == 64)) {
|
||||
this.compress(this.working);
|
||||
for (var j = 0; j < 16; j++) {
|
||||
this.working[j] = 0;
|
||||
}
|
||||
this.working_ptr = 0;
|
||||
}
|
||||
}
|
||||
this.msglen += input.length;
|
||||
};
|
||||
RIPEMD160.prototype.digestBin = function () {
|
||||
this.MDfinish(this.working, this.msglen, 0);
|
||||
//var res = new Int8Array();
|
||||
var res = [];
|
||||
for (var i = 0; i < 20; i++) {
|
||||
res[i] = ((this.MDbuf[i >> 2] >>> ((i & 3) << 3)) & 255);
|
||||
}
|
||||
return new Uint8Array(res);
|
||||
};
|
||||
RIPEMD160.prototype.digest = function (input) {
|
||||
this.update(new Int8Array(input));
|
||||
return this.digestBin();
|
||||
};
|
||||
RIPEMD160.ArgArray = [[11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6], [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11]];
|
||||
RIPEMD160.IndexArray = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13], [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]];
|
||||
return RIPEMD160;
|
||||
})();
|
||||
|
||||
export default RIPEMD160
|
3
crypto/api/deps/deps.js
Normal file
3
crypto/api/deps/deps.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as Base58 } from './Base58.js'
|
||||
|
||||
export { default as utils } from './utils.js'
|
264
crypto/api/deps/ed2curve.js
Normal file
264
crypto/api/deps/ed2curve.js
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* ed2curve: convert Ed25519 signing key pair into Curve25519
|
||||
* key pair suitable for Diffie-Hellman key exchange.
|
||||
*
|
||||
* Written by Dmitry Chestnykh in 2014. Public domain.
|
||||
*/
|
||||
/* jshint newcap: false */
|
||||
|
||||
/*
|
||||
Change to es6 import/export
|
||||
*/
|
||||
|
||||
import nacl from './nacl-fast.js'
|
||||
|
||||
// (function(root, f) {
|
||||
// 'use strict';
|
||||
// if (typeof module !== 'undefined' && module.exports) module.exports = f(require('tweetnacl'));
|
||||
// else root.ed2curve = f(root.nacl);
|
||||
// }(this, function(nacl) {
|
||||
// 'use strict';
|
||||
// if (!nacl) throw new Error('tweetnacl not loaded');
|
||||
|
||||
// -- Operations copied from TweetNaCl.js. --
|
||||
|
||||
var gf = function(init) {
|
||||
var i, r = new Float64Array(16);
|
||||
if (init) for (i = 0; i < init.length; i++) r[i] = init[i];
|
||||
return r;
|
||||
};
|
||||
|
||||
var gf0 = gf(),
|
||||
gf1 = gf([1]),
|
||||
D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]),
|
||||
I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]);
|
||||
|
||||
function car25519(o) {
|
||||
var c;
|
||||
var i;
|
||||
for (i = 0; i < 16; i++) {
|
||||
o[i] += 65536;
|
||||
c = Math.floor(o[i] / 65536);
|
||||
o[(i+1)*(i<15?1:0)] += c - 1 + 37 * (c-1) * (i===15?1:0);
|
||||
o[i] -= (c * 65536);
|
||||
}
|
||||
}
|
||||
|
||||
function sel25519(p, q, b) {
|
||||
var t, c = ~(b-1);
|
||||
for (var i = 0; i < 16; i++) {
|
||||
t = c & (p[i] ^ q[i]);
|
||||
p[i] ^= t;
|
||||
q[i] ^= t;
|
||||
}
|
||||
}
|
||||
|
||||
function unpack25519(o, n) {
|
||||
var i;
|
||||
for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8);
|
||||
o[15] &= 0x7fff;
|
||||
}
|
||||
|
||||
// addition
|
||||
function A(o, a, b) {
|
||||
var i;
|
||||
for (i = 0; i < 16; i++) o[i] = (a[i] + b[i])|0;
|
||||
}
|
||||
|
||||
// subtraction
|
||||
function Z(o, a, b) {
|
||||
var i;
|
||||
for (i = 0; i < 16; i++) o[i] = (a[i] - b[i])|0;
|
||||
}
|
||||
|
||||
// multiplication
|
||||
function M(o, a, b) {
|
||||
var i, j, t = new Float64Array(31);
|
||||
for (i = 0; i < 31; i++) t[i] = 0;
|
||||
for (i = 0; i < 16; i++) {
|
||||
for (j = 0; j < 16; j++) {
|
||||
t[i+j] += a[i] * b[j];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 15; i++) {
|
||||
t[i] += 38 * t[i+16];
|
||||
}
|
||||
for (i = 0; i < 16; i++) o[i] = t[i];
|
||||
car25519(o);
|
||||
car25519(o);
|
||||
}
|
||||
|
||||
// squaring
|
||||
function S(o, a) {
|
||||
M(o, a, a);
|
||||
}
|
||||
|
||||
// inversion
|
||||
function inv25519(o, i) {
|
||||
var c = gf();
|
||||
var a;
|
||||
for (a = 0; a < 16; a++) c[a] = i[a];
|
||||
for (a = 253; a >= 0; a--) {
|
||||
S(c, c);
|
||||
if(a !== 2 && a !== 4) M(c, c, i);
|
||||
}
|
||||
for (a = 0; a < 16; a++) o[a] = c[a];
|
||||
}
|
||||
|
||||
function pack25519(o, n) {
|
||||
var i, j, b;
|
||||
var m = gf(), t = gf();
|
||||
for (i = 0; i < 16; i++) t[i] = n[i];
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
for (j = 0; j < 2; j++) {
|
||||
m[0] = t[0] - 0xffed;
|
||||
for (i = 1; i < 15; i++) {
|
||||
m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1);
|
||||
m[i-1] &= 0xffff;
|
||||
}
|
||||
m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1);
|
||||
b = (m[15]>>16) & 1;
|
||||
m[14] &= 0xffff;
|
||||
sel25519(t, m, 1-b);
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
o[2*i] = t[i] & 0xff;
|
||||
o[2*i+1] = t[i] >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
function par25519(a) {
|
||||
var d = new Uint8Array(32);
|
||||
pack25519(d, a);
|
||||
return d[0] & 1;
|
||||
}
|
||||
|
||||
function vn(x, xi, y, yi, n) {
|
||||
var i, d = 0;
|
||||
for (i = 0; i < n; i++) d |= x[xi + i] ^ y[yi + i];
|
||||
return (1 & ((d - 1) >>> 8)) - 1;
|
||||
}
|
||||
|
||||
function crypto_verify_32(x, xi, y, yi) {
|
||||
return vn(x, xi, y, yi, 32);
|
||||
}
|
||||
|
||||
function neq25519(a, b) {
|
||||
var c = new Uint8Array(32), d = new Uint8Array(32);
|
||||
pack25519(c, a);
|
||||
pack25519(d, b);
|
||||
return crypto_verify_32(c, 0, d, 0);
|
||||
}
|
||||
|
||||
function pow2523(o, i) {
|
||||
var c = gf();
|
||||
var a;
|
||||
for (a = 0; a < 16; a++) c[a] = i[a];
|
||||
for (a = 250; a >= 0; a--) {
|
||||
S(c, c);
|
||||
if (a !== 1) M(c, c, i);
|
||||
}
|
||||
for (a = 0; a < 16; a++) o[a] = c[a];
|
||||
}
|
||||
|
||||
function set25519(r, a) {
|
||||
var i;
|
||||
for (i = 0; i < 16; i++) r[i] = a[i] | 0;
|
||||
}
|
||||
|
||||
function unpackneg(r, p) {
|
||||
var t = gf(), chk = gf(), num = gf(),
|
||||
den = gf(), den2 = gf(), den4 = gf(),
|
||||
den6 = gf();
|
||||
|
||||
set25519(r[2], gf1);
|
||||
unpack25519(r[1], p);
|
||||
S(num, r[1]);
|
||||
M(den, num, D);
|
||||
Z(num, num, r[2]);
|
||||
A(den, r[2], den);
|
||||
|
||||
S(den2, den);
|
||||
S(den4, den2);
|
||||
M(den6, den4, den2);
|
||||
M(t, den6, num);
|
||||
M(t, t, den);
|
||||
|
||||
pow2523(t, t);
|
||||
M(t, t, num);
|
||||
M(t, t, den);
|
||||
M(t, t, den);
|
||||
M(r[0], t, den);
|
||||
|
||||
S(chk, r[0]);
|
||||
M(chk, chk, den);
|
||||
if (neq25519(chk, num)) M(r[0], r[0], I);
|
||||
|
||||
S(chk, r[0]);
|
||||
M(chk, chk, den);
|
||||
if (neq25519(chk, num)) return -1;
|
||||
|
||||
if (par25519(r[0]) === (p[31] >> 7)) Z(r[0], gf0, r[0]);
|
||||
|
||||
M(r[3], r[0], r[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
// Converts Ed25519 public key to Curve25519 public key.
|
||||
// montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p
|
||||
function convertPublicKey(pk) {
|
||||
var z = new Uint8Array(32),
|
||||
q = [gf(), gf(), gf(), gf()],
|
||||
a = gf(), b = gf();
|
||||
|
||||
if (unpackneg(q, pk)) return null; // reject invalid key
|
||||
|
||||
var y = q[1];
|
||||
|
||||
A(a, gf1, y);
|
||||
Z(b, gf1, y);
|
||||
inv25519(b, b);
|
||||
M(a, a, b);
|
||||
|
||||
pack25519(z, a);
|
||||
return z;
|
||||
}
|
||||
|
||||
// Converts Ed25519 secret key to Curve25519 secret key.
|
||||
function convertSecretKey(sk) {
|
||||
var d = new Uint8Array(64), o = new Uint8Array(32), i;
|
||||
nacl.lowlevel.crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
for (i = 0; i < 32; i++) o[i] = d[i];
|
||||
for (i = 0; i < 64; i++) d[i] = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
function convertKeyPair(edKeyPair) {
|
||||
var publicKey = convertPublicKey(edKeyPair.publicKey);
|
||||
if (!publicKey) return null;
|
||||
return {
|
||||
publicKey: publicKey,
|
||||
secretKey: convertSecretKey(edKeyPair.secretKey)
|
||||
};
|
||||
}
|
||||
|
||||
// return {
|
||||
// convertPublicKey: convertPublicKey,
|
||||
// convertSecretKey: convertSecretKey,
|
||||
// convertKeyPair: convertKeyPair,
|
||||
// };
|
||||
|
||||
export default {
|
||||
convertPublicKey: convertPublicKey,
|
||||
convertSecretKey: convertSecretKey,
|
||||
convertKeyPair: convertKeyPair,
|
||||
}
|
||||
|
||||
// }));
|
2422
crypto/api/deps/nacl-fast.js
Normal file
2422
crypto/api/deps/nacl-fast.js
Normal file
File diff suppressed because it is too large
Load Diff
336
crypto/api/deps/qora.js
Normal file
336
crypto/api/deps/qora.js
Normal file
@@ -0,0 +1,336 @@
|
||||
// QORA
|
||||
|
||||
const TYPES = {
|
||||
GENESIS_TRANSACTION: 1,
|
||||
PAYMENT_TRANSACTION: 2,
|
||||
|
||||
REGISTER_NAME_TRANSACTION: 3,
|
||||
UPDATE_NAME_TRANSACTION: 4,
|
||||
SELL_NAME_TRANSACTION: 5,
|
||||
CANCEL_SELL_NAME_TRANSACTION: 6,
|
||||
BUY_NAME_TRANSACTION: 7,
|
||||
|
||||
CREATE_POLL_TRANSACTION: 8,
|
||||
VOTE_ON_POLL_TRANSACTION: 9,
|
||||
|
||||
ARBITRARY_TRANSACTION: 10,
|
||||
|
||||
ISSUE_ASSET_TRANSACTION: 11,
|
||||
TRANSFER_ASSET_TRANSACTION: 12,
|
||||
CREATE_ORDER_TRANSACTION: 13,
|
||||
CANCEL_ORDER_TRANSACTION: 14,
|
||||
MULTI_PAYMENT_TRANSACTION: 15,
|
||||
|
||||
DEPLOY_AT_TRANSACTION: 16,
|
||||
|
||||
MESSAGE_TRANSACTION: 17
|
||||
};
|
||||
|
||||
function getKeyPairFromSeed(seed, returnBase58)
|
||||
{
|
||||
if(typeof(seed) == "string") {
|
||||
seed = new Uint8Array(Base58.decode(seed));
|
||||
}
|
||||
|
||||
var keyPair = nacl.sign.keyPair.fromSeed(seed);
|
||||
|
||||
var base58privateKey = Base58.encode(keyPair.secretKey);
|
||||
var base58publicKey = Base58.encode(keyPair.publicKey);
|
||||
if(returnBase58) {
|
||||
return {
|
||||
privateKey: Base58.encode(keyPair.secretKey),
|
||||
publicKey: Base58.encode(keyPair.publicKey)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
privateKey: keyPair.secretKey,
|
||||
publicKey: keyPair.publicKey
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function stringtoUTF8Array(message) {
|
||||
if (typeof message == 'string') {
|
||||
var s = unescape(encodeURIComponent(message)); // UTF-8
|
||||
message = new Uint8Array(s.length);
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
message[i] = s.charCodeAt(i) & 0xff;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
function int32ToBytes (word) {
|
||||
var byteArray = [];
|
||||
for (var b = 0; b < 32; b += 8) {
|
||||
byteArray.push((word >>> (24 - b % 32)) & 0xFF);
|
||||
}
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
function int64ToBytes (int64) {
|
||||
// we want to represent the input as a 8-bytes array
|
||||
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
for ( var index = 0; index < byteArray.length; index ++ ) {
|
||||
var byte = int64 & 0xff;
|
||||
byteArray [ byteArray.length - index - 1 ] = byte;
|
||||
int64 = (int64 - byte) / 256 ;
|
||||
}
|
||||
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
function appendBuffer (buffer1, buffer2) {
|
||||
buffer1 = new Uint8Array(buffer1);
|
||||
buffer2 = new Uint8Array(buffer2);
|
||||
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
|
||||
tmp.set(buffer1, 0);
|
||||
tmp.set(buffer2, buffer1.byteLength);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
function equal (buf1, buf2)
|
||||
{
|
||||
if (buf1.byteLength != buf2.byteLength) return false;
|
||||
var dv1 = new Uint8Array(buf1);
|
||||
var dv2 = new Uint8Array(buf2);
|
||||
for (var i = 0; i != buf1.byteLength; i++)
|
||||
{
|
||||
if (dv1[i] != dv2[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function generateAccountSeed(seed, nonce, returnBase58)
|
||||
{
|
||||
if(typeof(seed) == "string") {
|
||||
seed = Base58.decode(seed);
|
||||
}
|
||||
|
||||
nonceBytes = int32ToBytes(nonce);
|
||||
|
||||
var resultSeed = new Uint8Array();
|
||||
|
||||
resultSeed = appendBuffer(resultSeed, nonceBytes);
|
||||
resultSeed = appendBuffer(resultSeed, seed);
|
||||
resultSeed = appendBuffer(resultSeed, nonceBytes);
|
||||
|
||||
if(returnBase58) {
|
||||
return Base58.encode(SHA256.digest(SHA256.digest(resultSeed)));
|
||||
} else {
|
||||
return new SHA256.digest(SHA256.digest(resultSeed));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getAccountAddressFromPublicKey(publicKey)
|
||||
{
|
||||
var ADDRESS_VERSION = 58; // Q
|
||||
|
||||
if(typeof(publicKey) == "string") {
|
||||
publicKey = Base58.decode(publicKey);
|
||||
}
|
||||
|
||||
var publicKeyHashSHA256 = SHA256.digest(publicKey);
|
||||
|
||||
var ripemd160 = new RIPEMD160();
|
||||
|
||||
var publicKeyHash = ripemd160.digest(publicKeyHashSHA256);
|
||||
|
||||
var addressArray = new Uint8Array();
|
||||
|
||||
addressArray = appendBuffer(addressArray, [ADDRESS_VERSION]);
|
||||
addressArray = appendBuffer(addressArray, publicKeyHash);
|
||||
|
||||
var checkSum = SHA256.digest(SHA256.digest(addressArray));
|
||||
|
||||
addressArray = appendBuffer(addressArray, checkSum.subarray(0, 4));
|
||||
|
||||
return Base58.encode(addressArray);
|
||||
}
|
||||
|
||||
function getAccountAddressType(address)
|
||||
{
|
||||
try {
|
||||
var ADDRESS_VERSION = 58; // Q
|
||||
var AT_ADDRESS_VERSION = 23; // A
|
||||
|
||||
if(typeof(address) == "string") {
|
||||
address = Base58.decode(address);
|
||||
}
|
||||
|
||||
var checkSum = address.subarray(address.length - 4, address.length)
|
||||
var addressWitoutChecksum = address.subarray(0, address.length - 4);
|
||||
|
||||
var checkSumTwo = SHA256.digest(SHA256.digest(addressWitoutChecksum));
|
||||
checkSumTwo = checkSumTwo.subarray(0, 4);
|
||||
|
||||
if (equal(checkSum, checkSumTwo))
|
||||
{
|
||||
if(address[0] == ADDRESS_VERSION)
|
||||
{
|
||||
return "standard";
|
||||
}
|
||||
if(address[0] == AT_ADDRESS_VERSION)
|
||||
{
|
||||
return "at";
|
||||
}
|
||||
}
|
||||
|
||||
return "invalid";
|
||||
|
||||
} catch (e) {
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
function isValidAddress(address)
|
||||
{
|
||||
return (getAccountAddressType(address) != "invalid");
|
||||
}
|
||||
|
||||
function generateSignaturePaymentTransaction(keyPair, lastReference, recipient, amount, fee, timestamp) {
|
||||
const data = generatePaymentTransactionBase(keyPair.publicKey, lastReference, recipient, amount, fee, timestamp);
|
||||
return nacl.sign.detached(data, keyPair.privateKey);
|
||||
}
|
||||
|
||||
function generatePaymentTransaction(keyPair, lastReference, recipient, amount, fee, timestamp, signature) {
|
||||
return appendBuffer(generatePaymentTransactionBase(keyPair.publicKey, lastReference, recipient, amount, fee, timestamp),
|
||||
signature);
|
||||
}
|
||||
|
||||
function generatePaymentTransactionBase(publicKey, lastReference, recipient, amount, fee, timestamp) {
|
||||
const txType = TYPES.PAYMENT_TRANSACTION;
|
||||
const typeBytes = int32ToBytes(txType);
|
||||
const timestampBytes = int64ToBytes(timestamp);
|
||||
const amountBytes = int64ToBytes(amount * 100000000);
|
||||
const feeBytes = int64ToBytes(fee * 100000000);
|
||||
|
||||
var data = new Uint8Array();
|
||||
|
||||
data = appendBuffer(data, typeBytes);
|
||||
data = appendBuffer(data, timestampBytes);
|
||||
data = appendBuffer(data, lastReference);
|
||||
data = appendBuffer(data, publicKey);
|
||||
data = appendBuffer(data, recipient);
|
||||
data = appendBuffer(data, amountBytes);
|
||||
data = appendBuffer(data, feeBytes);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function generateSignatureMessageTransaction(keyPair, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted) {
|
||||
const data = generateMessageTransactionBase(keyPair.publicKey, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted);
|
||||
return nacl.sign.detached(data, keyPair.privateKey);
|
||||
}
|
||||
|
||||
function generateMessageTransaction(keyPair, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted, signature) {
|
||||
return appendBuffer(generateMessageTransactionBase(keyPair.publicKey, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted),
|
||||
signature);
|
||||
}
|
||||
|
||||
function generateMessageTransactionBase(publicKey, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted) {
|
||||
txType = TYPES.MESSAGE_TRANSACTION;
|
||||
|
||||
const typeBytes = int32ToBytes(txType);
|
||||
const timestampBytes = int64ToBytes(timestamp);
|
||||
const amountBytes = int64ToBytes(amount * 100000000);
|
||||
const feeBytes = int64ToBytes(fee * 100000000);
|
||||
const messageLength = int32ToBytes(message.length);
|
||||
const key = int64ToBytes(0);
|
||||
|
||||
isTextB = new Uint8Array(1);
|
||||
isTextB[0] = isText;
|
||||
|
||||
isEncryptedB = new Uint8Array(1);
|
||||
isEncryptedB[0] = isEncrypted;
|
||||
|
||||
var data = new Uint8Array();
|
||||
|
||||
data = appendBuffer(data, typeBytes);
|
||||
data = appendBuffer(data, timestampBytes);
|
||||
data = appendBuffer(data, lastReference);
|
||||
data = appendBuffer(data, publicKey);
|
||||
data = appendBuffer(data, recipient);
|
||||
data = appendBuffer(data, key);
|
||||
data = appendBuffer(data, amountBytes);
|
||||
data = appendBuffer(data, messageLength);
|
||||
data = appendBuffer(data, message);
|
||||
data = appendBuffer(data, isEncryptedB);
|
||||
data = appendBuffer(data, isTextB);
|
||||
data = appendBuffer(data, feeBytes);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
function generateSignatureArbitraryTransactionV3(keyPair, lastReference, service, arbitraryData, fee, timestamp) {
|
||||
const data = generateArbitraryTransactionV3Base(keyPair.publicKey, lastReference, service, arbitraryData, fee, timestamp);
|
||||
return nacl.sign.detached(data, keyPair.privateKey);
|
||||
}
|
||||
|
||||
function generateArbitraryTransactionV3(keyPair, lastReference, service, arbitraryData, fee, timestamp, signature) {
|
||||
return appendBuffer(generateArbitraryTransactionV3Base(keyPair.publicKey, lastReference, service, arbitraryData, fee, timestamp),
|
||||
signature);
|
||||
}
|
||||
|
||||
function generateArbitraryTransactionV3Base(publicKey, lastReference, service, arbitraryData, fee, timestamp) {
|
||||
const txType = TYPES.ARBITRARY_TRANSACTION;
|
||||
const typeBytes = int32ToBytes(txType);
|
||||
const timestampBytes = int64ToBytes(timestamp);
|
||||
const feeBytes = int64ToBytes(fee * 100000000);
|
||||
const serviceBytes = int32ToBytes(service);
|
||||
const dataSizeBytes = int32ToBytes(arbitraryData.length);
|
||||
const paymentsLengthBytes = int32ToBytes(0); // Support payments - not yet.
|
||||
|
||||
var data = new Uint8Array();
|
||||
|
||||
data = appendBuffer(data, typeBytes);
|
||||
data = appendBuffer(data, timestampBytes);
|
||||
data = appendBuffer(data, lastReference);
|
||||
data = appendBuffer(data, publicKey);
|
||||
data = appendBuffer(data, paymentsLengthBytes);
|
||||
// Here it is necessary to insert the payments, if there are
|
||||
data = appendBuffer(data, serviceBytes);
|
||||
data = appendBuffer(data, dataSizeBytes);
|
||||
data = appendBuffer(data, arbitraryData);
|
||||
data = appendBuffer(data, feeBytes);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
function generateSignatureRegisterNameTransaction(keyPair, lastReference, owner, name, value, fee, timestamp) {
|
||||
const data = generateRegisterNameTransactionBase(keyPair.publicKey, lastReference, owner, name, value, fee, timestamp);
|
||||
return nacl.sign.detached(data, keyPair.privateKey);
|
||||
}
|
||||
|
||||
function generateRegisterNameTransaction(keyPair, lastReference, owner, name, value, fee, timestamp, signature) {
|
||||
return appendBuffer( generateRegisterNameTransactionBase(keyPair.publicKey, lastReference, owner, name, value, fee, timestamp),
|
||||
signature );
|
||||
}
|
||||
|
||||
function generateRegisterNameTransactionBase(publicKey, lastReference, owner, name, value, fee, timestamp) {
|
||||
const txType = TYPES.REGISTER_NAME_TRANSACTION;
|
||||
const typeBytes = int32ToBytes(txType);
|
||||
const timestampBytes = int64ToBytes(timestamp);
|
||||
const feeBytes = int64ToBytes(fee * 100000000);
|
||||
const nameSizeBytes = int32ToBytes(name.length);
|
||||
const valueSizeBytes = int32ToBytes(value.length);
|
||||
|
||||
var data = new Uint8Array();
|
||||
|
||||
data = appendBuffer(data, typeBytes);
|
||||
data = appendBuffer(data, timestampBytes);
|
||||
data = appendBuffer(data, lastReference);
|
||||
data = appendBuffer(data, publicKey);
|
||||
data = appendBuffer(data, owner);
|
||||
data = appendBuffer(data, nameSizeBytes);
|
||||
data = appendBuffer(data, name);
|
||||
data = appendBuffer(data, valueSizeBytes);
|
||||
data = appendBuffer(data, value);
|
||||
data = appendBuffer(data, feeBytes);
|
||||
|
||||
return data;
|
||||
}
|
226
crypto/api/deps/ripemd160.js
Normal file
226
crypto/api/deps/ripemd160.js
Normal file
@@ -0,0 +1,226 @@
|
||||
// Extracted from https://github.com/crypto-browserify/ripemd160
|
||||
const ARRAY16 = new Array(16);
|
||||
const zl = initU8Array([
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
|
||||
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
|
||||
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
|
||||
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
|
||||
]);
|
||||
const zr = initU8Array([
|
||||
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
|
||||
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
|
||||
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
|
||||
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
|
||||
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
|
||||
]);
|
||||
const sl = initU8Array([
|
||||
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
|
||||
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
|
||||
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
|
||||
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
|
||||
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
|
||||
]);
|
||||
const sr = initU8Array([
|
||||
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
|
||||
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
|
||||
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
|
||||
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
|
||||
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
|
||||
]);
|
||||
const hl = initU32Array([0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e]);
|
||||
const hr = initU32Array([0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000]);
|
||||
function rotl(x, n) {
|
||||
return (x << n) | (x >>> (32 - n));
|
||||
}
|
||||
function fn1(a, b, c, d, e, m, k, s) {
|
||||
return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + e) | 0;
|
||||
}
|
||||
function fn2(a, b, c, d, e, m, k, s) {
|
||||
return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + e) | 0;
|
||||
}
|
||||
function fn3(a, b, c, d, e, m, k, s) {
|
||||
return (rotl((a + ((b | (~c)) ^ d) + m + k) | 0, s) + e) | 0;
|
||||
}
|
||||
function fn4(a, b, c, d, e, m, k, s) {
|
||||
return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + e) | 0;
|
||||
}
|
||||
function fn5(a, b, c, d, e, m, k, s) {
|
||||
return (rotl((a + (b ^ (c | (~d))) + m + k) | 0, s) + e) | 0;
|
||||
}
|
||||
function readInt32LE(buffer, offset) {
|
||||
offset >>>= 0;
|
||||
return (buffer[offset])
|
||||
| (buffer[offset + 1] << 8)
|
||||
| (buffer[offset + 2] << 16)
|
||||
| (buffer[offset + 3] << 24);
|
||||
}
|
||||
function writeUInt32LE(buffer, value, offset) {
|
||||
value = +value;
|
||||
offset >>>= 0;
|
||||
buffer[offset + 3] = (value >>> 24);
|
||||
buffer[offset + 2] = (value >>> 16);
|
||||
buffer[offset + 1] = (value >>> 8);
|
||||
buffer[offset] = (value & 0xff);
|
||||
return offset + 4;
|
||||
}
|
||||
function writeInt32LE(buffer, value, offset) {
|
||||
value = +value;
|
||||
offset >>>= 0;
|
||||
buffer[offset] = (value & 0xff);
|
||||
buffer[offset + 1] = (value >>> 8);
|
||||
buffer[offset + 2] = (value >>> 16);
|
||||
buffer[offset + 3] = (value >>> 24);
|
||||
return offset + 4;
|
||||
}
|
||||
function initU32Array(data) {
|
||||
if (typeof Uint32Array !== 'undefined') {
|
||||
return new Uint32Array(data);
|
||||
}
|
||||
else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
function initU8Array(data) {
|
||||
if (typeof Uint8Array !== 'undefined') {
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
function createU8Array(size) {
|
||||
if (typeof Uint8Array !== 'undefined') {
|
||||
return new Uint8Array(size);
|
||||
}
|
||||
else {
|
||||
return new Array(size);
|
||||
}
|
||||
}
|
||||
export class RIPEMD160 {
|
||||
constructor() {
|
||||
this._block = createU8Array(64);
|
||||
this._blockSize = 64;
|
||||
this._blockOffset = 0;
|
||||
this._length = [0, 0, 0, 0];
|
||||
this._finalized = false;
|
||||
this._a = 0x67452301;
|
||||
this._b = 0xefcdab89;
|
||||
this._c = 0x98badcfe;
|
||||
this._d = 0x10325476;
|
||||
this._e = 0xc3d2e1f0;
|
||||
}
|
||||
update(data) {
|
||||
if (this._finalized)
|
||||
throw new Error('Digest already called');
|
||||
// consume data
|
||||
const block = this._block;
|
||||
let offset = 0;
|
||||
while (this._blockOffset + data.length - offset >= this._blockSize) {
|
||||
for (let i = this._blockOffset; i < this._blockSize;)
|
||||
block[i++] = data[offset++];
|
||||
this._update();
|
||||
this._blockOffset = 0;
|
||||
}
|
||||
while (offset < data.length)
|
||||
block[this._blockOffset++] = data[offset++];
|
||||
// update length
|
||||
for (let j = 0, carry = data.length * 8; carry > 0; ++j) {
|
||||
this._length[j] += carry;
|
||||
carry = (this._length[j] / 0x0100000000) | 0;
|
||||
if (carry > 0)
|
||||
this._length[j] -= 0x0100000000 * carry;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
_update() {
|
||||
const words = ARRAY16;
|
||||
for (let j = 0; j < 16; ++j) {
|
||||
words[j] = readInt32LE(this._block, j * 4);
|
||||
}
|
||||
let al = this._a | 0;
|
||||
let bl = this._b | 0;
|
||||
let cl = this._c | 0;
|
||||
let dl = this._d | 0;
|
||||
let el = this._e | 0;
|
||||
let ar = this._a | 0;
|
||||
let br = this._b | 0;
|
||||
let cr = this._c | 0;
|
||||
let dr = this._d | 0;
|
||||
let er = this._e | 0;
|
||||
// computation
|
||||
for (let i = 0; i < 80; i += 1) {
|
||||
let tl;
|
||||
let tr;
|
||||
if (i < 16) {
|
||||
tl = fn1(al, bl, cl, dl, el, words[zl[i]], hl[0], sl[i]);
|
||||
tr = fn5(ar, br, cr, dr, er, words[zr[i]], hr[0], sr[i]);
|
||||
}
|
||||
else if (i < 32) {
|
||||
tl = fn2(al, bl, cl, dl, el, words[zl[i]], hl[1], sl[i]);
|
||||
tr = fn4(ar, br, cr, dr, er, words[zr[i]], hr[1], sr[i]);
|
||||
}
|
||||
else if (i < 48) {
|
||||
tl = fn3(al, bl, cl, dl, el, words[zl[i]], hl[2], sl[i]);
|
||||
tr = fn3(ar, br, cr, dr, er, words[zr[i]], hr[2], sr[i]);
|
||||
}
|
||||
else if (i < 64) {
|
||||
tl = fn4(al, bl, cl, dl, el, words[zl[i]], hl[3], sl[i]);
|
||||
tr = fn2(ar, br, cr, dr, er, words[zr[i]], hr[3], sr[i]);
|
||||
}
|
||||
else { // if (i<80) {
|
||||
tl = fn5(al, bl, cl, dl, el, words[zl[i]], hl[4], sl[i]);
|
||||
tr = fn1(ar, br, cr, dr, er, words[zr[i]], hr[4], sr[i]);
|
||||
}
|
||||
al = el;
|
||||
el = dl;
|
||||
dl = rotl(cl, 10);
|
||||
cl = bl;
|
||||
bl = tl;
|
||||
ar = er;
|
||||
er = dr;
|
||||
dr = rotl(cr, 10);
|
||||
cr = br;
|
||||
br = tr;
|
||||
}
|
||||
// update state
|
||||
const t = (this._b + cl + dr) | 0;
|
||||
this._b = (this._c + dl + er) | 0;
|
||||
this._c = (this._d + el + ar) | 0;
|
||||
this._d = (this._e + al + br) | 0;
|
||||
this._e = (this._a + bl + cr) | 0;
|
||||
this._a = t;
|
||||
}
|
||||
digest() {
|
||||
if (this._finalized) {
|
||||
throw new Error('Digest already called');
|
||||
}
|
||||
this._finalized = true;
|
||||
// create padding and handle blocks
|
||||
this._block[this._blockOffset++] = 0x80;
|
||||
if (this._blockOffset > 56) {
|
||||
this._block.fill(0, this._blockOffset, 64);
|
||||
this._update();
|
||||
this._blockOffset = 0;
|
||||
}
|
||||
this._block.fill(0, this._blockOffset, 56);
|
||||
writeUInt32LE(this._block, this._length[0], 56);
|
||||
writeUInt32LE(this._block, this._length[1], 60);
|
||||
this._update();
|
||||
// produce result
|
||||
const buffer = createU8Array(20);
|
||||
writeInt32LE(buffer, this._a, 0);
|
||||
writeInt32LE(buffer, this._b, 4);
|
||||
writeInt32LE(buffer, this._c, 8);
|
||||
writeInt32LE(buffer, this._d, 12);
|
||||
writeInt32LE(buffer, this._e, 16);
|
||||
// reset state
|
||||
this._block.fill(0);
|
||||
this._blockOffset = 0;
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
this._length[i] = 0;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
export default RIPEMD160;
|
142
crypto/api/deps/sha256.js
Normal file
142
crypto/api/deps/sha256.js
Normal file
@@ -0,0 +1,142 @@
|
||||
// SHA-256 hash function. Copyright-free.
|
||||
// Requires typed arrays.
|
||||
const SHA256 = {};
|
||||
|
||||
SHA256.K = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
|
||||
0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
|
||||
0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
|
||||
0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
|
||||
0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
||||
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
|
||||
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
|
||||
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
];
|
||||
|
||||
// The digest function returns the hash value (digest)
|
||||
// as a 32 byte (typed) array.
|
||||
// message: the string or byte array to hash
|
||||
SHA256.digest = function(message) {
|
||||
var h0 = 0x6a09e667;
|
||||
var h1 = 0xbb67ae85;
|
||||
var h2 = 0x3c6ef372;
|
||||
var h3 = 0xa54ff53a;
|
||||
var h4 = 0x510e527f;
|
||||
var h5 = 0x9b05688c;
|
||||
var h6 = 0x1f83d9ab;
|
||||
var h7 = 0x5be0cd19;
|
||||
var K = SHA256.K;
|
||||
if (typeof message == 'string') {
|
||||
var s = unescape(encodeURIComponent(message)); // UTF-8
|
||||
message = new Uint8Array(s.length);
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
message[i] = s.charCodeAt(i) & 0xff;
|
||||
}
|
||||
}
|
||||
var length = message.length;
|
||||
var byteLength = Math.floor((length + 72) / 64) * 64;
|
||||
var wordLength = byteLength / 4;
|
||||
var bitLength = length * 8;
|
||||
var m = new Uint8Array(byteLength);
|
||||
m.set(message);
|
||||
m[length] = 0x80;
|
||||
m[byteLength - 4] = bitLength >>> 24;
|
||||
m[byteLength - 3] = (bitLength >>> 16) & 0xff;
|
||||
m[byteLength - 2] = (bitLength >>> 8) & 0xff;
|
||||
m[byteLength - 1] = bitLength & 0xff;
|
||||
var words = new Int32Array(wordLength);
|
||||
var byteIndex = 0;
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var word = m[byteIndex++] << 24;
|
||||
word |= m[byteIndex++] << 16;
|
||||
word |= m[byteIndex++] << 8;
|
||||
word |= m[byteIndex++];
|
||||
words[i] = word;
|
||||
}
|
||||
var w = new Int32Array(64);
|
||||
for (var j = 0; j < wordLength; j += 16) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
w[i] = words[j + i];
|
||||
}
|
||||
for (i = 16; i < 64; i++) {
|
||||
var v = w[i - 15];
|
||||
var s0 = (v >>> 7) | (v << 25);
|
||||
s0 ^= (v >>> 18) | (v << 14);
|
||||
s0 ^= (v >>> 3);
|
||||
v = w[i - 2];
|
||||
var s1 = (v >>> 17) | (v << 15);
|
||||
s1 ^= (v >>> 19) | (v << 13);
|
||||
s1 ^= (v >>> 10);
|
||||
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & 0xffffffff;
|
||||
}
|
||||
var a = h0;
|
||||
var b = h1;
|
||||
var c = h2;
|
||||
var d = h3;
|
||||
var e = h4;
|
||||
var f = h5;
|
||||
var g = h6;
|
||||
var h = h7;
|
||||
for (i = 0; i < 64; i++) {
|
||||
s1 = (e >>> 6) | (e << 26);
|
||||
s1 ^= (e >>> 11) | (e << 21);
|
||||
s1 ^= (e >>> 25) | (e << 7);
|
||||
var ch = (e & f) ^ (~e & g);
|
||||
var temp1 = (h + s1 + ch + K[i] + w[i]) & 0xffffffff;
|
||||
s0 = (a >>> 2) | (a << 30);
|
||||
s0 ^= (a >>> 13) | (a << 19);
|
||||
s0 ^= (a >>> 22) | (a << 10);
|
||||
var maj = (a & b) ^ (a & c) ^ (b & c);
|
||||
var temp2 = (s0 + maj) & 0xffffffff;
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = (d + temp1) & 0xffffffff;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = (temp1 + temp2) & 0xffffffff;
|
||||
}
|
||||
h0 = (h0 + a) & 0xffffffff;
|
||||
h1 = (h1 + b) & 0xffffffff;
|
||||
h2 = (h2 + c) & 0xffffffff;
|
||||
h3 = (h3 + d) & 0xffffffff;
|
||||
h4 = (h4 + e) & 0xffffffff;
|
||||
h5 = (h5 + f) & 0xffffffff;
|
||||
h6 = (h6 + g) & 0xffffffff;
|
||||
h7 = (h7 + h) & 0xffffffff;
|
||||
}
|
||||
var hash = new Uint8Array(32);
|
||||
for (var i = 0; i < 4; i++) {
|
||||
hash[i] = (h0 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 4] = (h1 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 8] = (h2 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 12] = (h3 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 16] = (h4 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 20] = (h5 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 24] = (h6 >>> (8 * (3 - i))) & 0xff;
|
||||
hash[i + 28] = (h7 >>> (8 * (3 - i))) & 0xff;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// The hash function returns the hash value as a hex string.
|
||||
// message: the string or byte array to hash
|
||||
SHA256.hash = function(message) {
|
||||
var digest = SHA256.digest(message);
|
||||
var hex = '';
|
||||
for (var i = 0; i < digest.length; i++) {
|
||||
var s = '0' + digest[i].toString(16);
|
||||
hex += s.length > 2 ? s.substring(1) : s;
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
|
||||
// == Convert to ES6 Module == //
|
||||
export default SHA256;
|
74
crypto/api/deps/utils.js
Normal file
74
crypto/api/deps/utils.js
Normal file
@@ -0,0 +1,74 @@
|
||||
'use strict'
|
||||
const utils = {
|
||||
int32ToBytes(word) {
|
||||
var byteArray = []
|
||||
for (var b = 0; b < 32; b += 8) {
|
||||
byteArray.push((word >>> (24 - b % 32)) & 0xFF)
|
||||
}
|
||||
return byteArray
|
||||
},
|
||||
|
||||
stringtoUTF8Array(message) {
|
||||
if (typeof message === 'string') {
|
||||
var s = unescape(encodeURIComponent(message)) // UTF-8
|
||||
message = new Uint8Array(s.length)
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
message[i] = s.charCodeAt(i) & 0xff
|
||||
}
|
||||
}
|
||||
return message
|
||||
},
|
||||
// ...buffers then buffers.foreach and append to buffer1
|
||||
appendBuffer(buffer1, buffer2) {
|
||||
buffer1 = new Uint8Array(buffer1)
|
||||
buffer2 = new Uint8Array(buffer2)
|
||||
let tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength)
|
||||
tmp.set(buffer1, 0)
|
||||
tmp.set(buffer2, buffer1.byteLength)
|
||||
return tmp
|
||||
},
|
||||
|
||||
int64ToBytes(int64) {
|
||||
// we want to represent the input as a 8-bytes array
|
||||
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||
|
||||
for (var index = 0; index < byteArray.length; index++) {
|
||||
var byte = int64 & 0xff
|
||||
byteArray[byteArray.length - index - 1] = byte
|
||||
int64 = (int64 - byte) / 256
|
||||
}
|
||||
|
||||
return byteArray
|
||||
},
|
||||
|
||||
hexToBytes(hexString) {
|
||||
return new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)))
|
||||
},
|
||||
|
||||
stringToHex(bytes) {
|
||||
return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')
|
||||
},
|
||||
|
||||
equal(buf1, buf2) {
|
||||
if (buf1.byteLength != buf2.byteLength) return false
|
||||
var dv1 = new Uint8Array(buf1)
|
||||
var dv2 = new Uint8Array(buf2)
|
||||
for (var i = 0; i != buf1.byteLength; i++) {
|
||||
if (dv1[i] != dv2[i]) return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
bytesToHex(byteArray) {
|
||||
var _byteArrayToHex = []
|
||||
|
||||
for (var index = 0; index < byteArray.length; index++) {
|
||||
_byteArrayToHex.push((byteArray[index] >>> 4).toString(16))
|
||||
_byteArrayToHex.push((byteArray[index] & 15).toString(16));
|
||||
}
|
||||
|
||||
return _byteArrayToHex.join("")
|
||||
}
|
||||
}
|
||||
|
||||
export default utils
|
30
crypto/api/fetch-request.js
Normal file
30
crypto/api/fetch-request.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import { watchConfig, waitForConfig } from '../config.js'
|
||||
|
||||
let config = {}
|
||||
watchConfig((c) => {
|
||||
config = c
|
||||
})
|
||||
|
||||
export async function request(url, options) {
|
||||
options = options || {}
|
||||
const body = options.body
|
||||
const method = options.method || 'GET'
|
||||
const headers = options.headers || {}
|
||||
|
||||
await waitForConfig()
|
||||
|
||||
const n = config.nodeConfig.knownNodes[config.nodeConfig.node]
|
||||
const node = n.protocol + '://' + n.domain + ':' + n.port
|
||||
return fetch(node + url, {
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
}).then(async (response) => {
|
||||
try {
|
||||
const json = await response.clone().json()
|
||||
return json
|
||||
} catch (e) {
|
||||
return await response.text()
|
||||
}
|
||||
})
|
||||
}
|
39
crypto/api/kdf.js
Normal file
39
crypto/api/kdf.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import { store } from '../api_deps.js'
|
||||
import { stateAwait } from './utils/stateAwait.js'
|
||||
import { Sha512 } from 'asmcrypto.js'
|
||||
import utils from '../api/deps/utils.js'
|
||||
|
||||
export const kdf = async (seed, salt, status = () => { }) => {
|
||||
const state = store.getState()
|
||||
const config = state.config
|
||||
const workers = state.app.workers.workers
|
||||
status('Waiting for workers to be ready')
|
||||
await stateAwait(state => state.app.workers.ready)
|
||||
status('Deriving key parts')
|
||||
salt = new Uint8Array(salt)
|
||||
const seedParts = await Promise.all(workers.map((worker, index) => {
|
||||
const nonce = index
|
||||
return worker.request('kdf', {
|
||||
key: seed,
|
||||
salt,
|
||||
nonce,
|
||||
staticSalt: config.crypto.staticSalt,
|
||||
staticBcryptSalt: config.crypto.staticBcryptSalt
|
||||
}).then(data => {
|
||||
let jsonData
|
||||
try {
|
||||
jsonData = JSON.parse(data)
|
||||
data = jsonData
|
||||
} catch (e) {
|
||||
// ...
|
||||
}
|
||||
if (seed !== data.key) throw new Error('Error, incorrect key. ' + seed + ' !== ' + data.key)
|
||||
if (nonce !== data.nonce) throw new Error('Error, incorrect nonce')
|
||||
return data.result
|
||||
})
|
||||
}))
|
||||
status('Combining key parts')
|
||||
const result = new Sha512().process(utils.stringtoUTF8Array(config.crypto.staticSalt + seedParts.reduce((a, c) => a + c))).finish().result
|
||||
status('Key is ready ')
|
||||
return result
|
||||
}
|
39
crypto/api/registerUsername.js
Normal file
39
crypto/api/registerUsername.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Not to be confused with register name...this is a special use case
|
||||
*/
|
||||
import { request, createTransaction, processTransaction } from './api.js'
|
||||
|
||||
const TX_TYPE = 3 // NAME_REGISTRATION
|
||||
const CHECK_LAST_REF_INTERVAL = 30 * 1000 // err 30 seconds
|
||||
|
||||
const pendingAddresses = {}
|
||||
|
||||
const checkLastRefs = () => {
|
||||
Object.entries(pendingAddresses).forEach(([address, fn]) => {
|
||||
request('addresses/lastreference/' + address).then(res => {
|
||||
if (res === 'false') return
|
||||
fn(res)
|
||||
delete pendingAddresses[address]
|
||||
clearInterval(lastRefInterval)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const lastRefInterval = setInterval(() => checkLastRefs(), CHECK_LAST_REF_INTERVAL)
|
||||
|
||||
const callOnLastRef = (address, fn) => {
|
||||
pendingAddresses[address] = fn
|
||||
}
|
||||
|
||||
export const registerUsername = async ({ name, address, lastRef, keyPair }) => {
|
||||
callOnLastRef(address, lastreference => {
|
||||
const txBytes = createTransaction(TX_TYPE, keyPair, {
|
||||
registrantPublicKey: keyPair.publicKey,
|
||||
registrantAddress: address,
|
||||
name,
|
||||
value: address,
|
||||
lastReference: lastreference
|
||||
})
|
||||
processTransaction(txBytes).then(res => { })
|
||||
})
|
||||
}
|
29
crypto/api/storeWallet.js
Normal file
29
crypto/api/storeWallet.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { HmacSha512, AES_CBC } from 'asmcrypto.js'
|
||||
import { kdf } from './kdf.js'
|
||||
import Base58 from './deps/Base58.js'
|
||||
|
||||
const getRandomValues = window.crypto ? window.crypto.getRandomValues.bind(window.crypto) : window.msCrypto.getRandomValues.bind(window.msCrypto)
|
||||
|
||||
export const generateSaveWalletData = async (wallet, password, kdfThreads, statusUpdateFn) => {
|
||||
statusUpdateFn('Generating random values')
|
||||
let iv = new Uint8Array(16)
|
||||
getRandomValues(iv)
|
||||
let salt = new Uint8Array(32)
|
||||
getRandomValues(salt)
|
||||
const key = await kdf(password, salt, statusUpdateFn)
|
||||
statusUpdateFn('Encrypting seed')
|
||||
const encryptionKey = key.slice(0, 32)
|
||||
const macKey = key.slice(32, 63)
|
||||
const encryptedSeed = AES_CBC.encrypt(wallet._byteSeed, encryptionKey, false, iv)
|
||||
statusUpdateFn('Generating mac')
|
||||
const mac = new HmacSha512(macKey).process(encryptedSeed).finish().result
|
||||
return {
|
||||
address0: wallet._addresses[0].address,
|
||||
encryptedSeed: Base58.encode(encryptedSeed),
|
||||
salt: Base58.encode(salt),
|
||||
iv: Base58.encode(iv),
|
||||
version: wallet._walletVersion,
|
||||
mac: Base58.encode(mac),
|
||||
kdfThreads
|
||||
}
|
||||
}
|
140
crypto/api/tradeRequest.js
Normal file
140
crypto/api/tradeRequest.js
Normal file
@@ -0,0 +1,140 @@
|
||||
// Trade Bot
|
||||
import TradeBotCreateRequest from './transactions/trade-portal/tradebot/TradeBotCreateRequest.js'
|
||||
import TradeBotRespondRequest from './transactions/trade-portal/tradebot/TradeBotRespondRequest.js'
|
||||
import signTradeBotTransaction from './transactions/trade-portal/tradebot/signTradeBotTransaction.js'
|
||||
import DeleteTradeOffer from './transactions/trade-portal/tradeoffer/DeleteTradeOffer.js'
|
||||
import { request } from './fetch-request'
|
||||
|
||||
// TradeBotCreateRequest
|
||||
export const tradeBotCreateRequest = (requestObject) => {
|
||||
const txn = new TradeBotCreateRequest().createTransaction(requestObject)
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/tradebot/create?apiKey=${myNode.apiKey}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'text/plain',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(txn)
|
||||
})
|
||||
}
|
||||
|
||||
// TradeBotRespondRequest
|
||||
export const tradeBotRespondRequest = (requestObject) => {
|
||||
const txn = new TradeBotRespondRequest().createTransaction(requestObject)
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/tradebot/respond?apiKey=${myNode.apiKey}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(txn)
|
||||
})
|
||||
}
|
||||
|
||||
// Sign Trade Transactions
|
||||
export const signTradeBotTxn = (unsignedTxn, keyPair) => {
|
||||
return signTradeBotTransaction(unsignedTxn, keyPair)
|
||||
}
|
||||
|
||||
// Delete Trade Offer
|
||||
export const deleteTradeOffer = (requestObject) => {
|
||||
const txn = new DeleteTradeOffer().createTransaction(requestObject)
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/tradeoffer?apiKey=${myNode.apiKey}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(txn)
|
||||
})
|
||||
}
|
||||
|
||||
// Send BTC
|
||||
export const sendBtc = (requestObject) => {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/btc/send?apiKey=${myNode.apiKey}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestObject)
|
||||
})
|
||||
}
|
||||
|
||||
// Send LTC
|
||||
export const sendLtc = (requestObject) => {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/ltc/send?apiKey=${myNode.apiKey}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestObject)
|
||||
})
|
||||
}
|
||||
|
||||
// Send DOGE
|
||||
export const sendDoge = (requestObject) => {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/doge/send?apiKey=${myNode.apiKey}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestObject)
|
||||
})
|
||||
}
|
||||
|
||||
// Send DGB
|
||||
export const sendDgb = (requestObject) => {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/dgb/send?apiKey=${myNode.apiKey}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestObject)
|
||||
})
|
||||
}
|
||||
|
||||
// Send RVN
|
||||
export const sendRvn = (requestObject) => {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/rvn/send?apiKey=${myNode.apiKey}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestObject)
|
||||
})
|
||||
}
|
||||
|
||||
// Send ARRR
|
||||
export const sendArrr = (requestObject) => {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
|
||||
return request(`/crosschain/arrr/send?apiKey=${myNode.apiKey}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestObject)
|
||||
})
|
||||
}
|
35
crypto/api/transactions/AirdropTransaction.js
Normal file
35
crypto/api/transactions/AirdropTransaction.js
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict'
|
||||
import TransactionBase from './TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../constants.js'
|
||||
|
||||
export default class PaymentTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 20
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
}
|
||||
|
||||
set amount(amount) {
|
||||
this._amount = amount * QORT_DECIMALS
|
||||
this._amountBytes = this.constructor.utils.int64ToBytes(amount)
|
||||
}
|
||||
|
||||
set reference(seed) {
|
||||
const sha = seed => new Sha512().process(seed).finish().result
|
||||
let reference = sha(sha(seed))
|
||||
reference += reference
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._recipient,
|
||||
this._amountBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
22
crypto/api/transactions/DelegationTransaction.js
Normal file
22
crypto/api/transactions/DelegationTransaction.js
Normal file
@@ -0,0 +1,22 @@
|
||||
'use strict'
|
||||
import TransactionBase from './TransactionBase.js'
|
||||
|
||||
export default class DelegationTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 18
|
||||
}
|
||||
|
||||
set superNodeAddress(superNodeAddress) {
|
||||
this._superNodeAddress = superNodeAddress instanceof Uint8Array ? superNodeAddress : this.constructor.Base58.decode(superNodeAddress)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._superNodeAddress,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
91
crypto/api/transactions/DeployAtTransaction.js
Normal file
91
crypto/api/transactions/DeployAtTransaction.js
Normal file
@@ -0,0 +1,91 @@
|
||||
'use strict'
|
||||
import TransactionBase from './TransactionBase.js'
|
||||
import { store } from '../../api.js'
|
||||
|
||||
export default class DeployAtTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 16
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._groupdialog5}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<div>${this._atDeployDialog1}: <span style="color: #000;">${this._rName}</span></div>
|
||||
<br>
|
||||
<div>${this.atDeployDialog2}: <span style="color: #000;">${this._rDescription}</span></div>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
${this._groupdialog6}
|
||||
`
|
||||
}
|
||||
|
||||
set atDeployDialog1(atDeployDialog1) {
|
||||
this._atDeployDialog1 = atDeployDialog1
|
||||
}
|
||||
set atDeployDialog2(atDeployDialog2) {
|
||||
this._atDeployDialog2 = atDeployDialog2
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
set rAmount(rAmount) {
|
||||
this._rAmount = Math.round(rAmount * store.getState().config.coin.decimals)
|
||||
this._rAmountBytes = this.constructor.utils.int64ToBytes(this._rAmount)
|
||||
}
|
||||
|
||||
set rName(rName) {
|
||||
this._rName = rName
|
||||
this._rNameBytes = this.constructor.utils.stringtoUTF8Array(this._rName.toLocaleLowerCase())
|
||||
this._rNameLength = this.constructor.utils.int32ToBytes(this._rNameBytes.length)
|
||||
}
|
||||
|
||||
set rDescription(rDescription) {
|
||||
this._rDescription = rDescription
|
||||
this._rDescriptionBytes = this.constructor.utils.stringtoUTF8Array(this._rDescription.toLocaleLowerCase())
|
||||
this._rDescriptionLength = this.constructor.utils.int32ToBytes(this._rDescriptionBytes.length)
|
||||
}
|
||||
set atType(atType) {
|
||||
this._atType = atType
|
||||
this._atTypeBytes = this.constructor.utils.stringtoUTF8Array(this._atType)
|
||||
this._atTypeLength = this.constructor.utils.int32ToBytes(this._atTypeBytes.length)
|
||||
}
|
||||
set rTags(rTags) {
|
||||
this._rTags = rTags
|
||||
this._rTagsBytes = this.constructor.utils.stringtoUTF8Array(this._rTags.toLocaleLowerCase())
|
||||
this._rTagsLength = this.constructor.utils.int32ToBytes(this._rTagsBytes.length)
|
||||
}
|
||||
set rCreationBytes(rCreationBytes) {
|
||||
const decode = this.constructor.Base58.decode(rCreationBytes)
|
||||
this._rCreationBytes = this.constructor.utils.stringtoUTF8Array(decode)
|
||||
this._rCreationBytesLength = this.constructor.utils.int32ToBytes(this._rCreationBytes.length)
|
||||
}
|
||||
set rAssetId(rAssetId) {
|
||||
this._rAssetId = this.constructor.utils.int64ToBytes(rAssetId)
|
||||
}
|
||||
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rNameLength,
|
||||
this._rNameBytes,
|
||||
this._rDescriptionLength,
|
||||
this._rDescriptionBytes,
|
||||
this._atTypeLength,
|
||||
this._atTypeBytes,
|
||||
this._rTagsLength,
|
||||
this._rTagsBytes,
|
||||
this._rCreationBytesLength,
|
||||
this._rCreationBytes,
|
||||
this._rAmountBytes,
|
||||
this._rAssetId,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
47
crypto/api/transactions/MessageTransaction.js
Normal file
47
crypto/api/transactions/MessageTransaction.js
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict'
|
||||
import PaymentTransaction from './PaymentTransaction.js'
|
||||
import { QORT_DECIMALS } from '../constants.js'
|
||||
|
||||
export default class MessageTransaction extends PaymentTransaction {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 17
|
||||
this._key = this.constructor.utils.int64ToBytes(0);
|
||||
this._isEncrypted = new Uint8Array(1); // Defaults to false
|
||||
this._isText = new Uint8Array(1); // Defaults to false
|
||||
}
|
||||
|
||||
set message(message /* UTF8 String */) {
|
||||
// ...yes? no?
|
||||
this.messageText = message
|
||||
|
||||
// Not sure about encoding here...
|
||||
this._message = this.constructor.utils.stringtoUTF8Array(message)
|
||||
this._messageLength = this.constructor.utils.int64ToBytes(this._message.length)
|
||||
}
|
||||
|
||||
set isEncrypted(isEncrypted) {
|
||||
this._isEncrypted[0] = isEncrypted
|
||||
}
|
||||
|
||||
set isText(isText) {
|
||||
this._isText[0] = isText
|
||||
}
|
||||
|
||||
get _params() {
|
||||
return [
|
||||
this._typeBytes,
|
||||
this._timestampBytes,
|
||||
this._lastReference,
|
||||
this._keyPair.publicKey,
|
||||
this._recipient,
|
||||
this._key,
|
||||
this._amountBytes,
|
||||
this._messageLength,
|
||||
this._message,
|
||||
this._isEncrypted,
|
||||
this._isText,
|
||||
this._feeBytes
|
||||
]
|
||||
}
|
||||
}
|
63
crypto/api/transactions/PaymentTransaction.js
Normal file
63
crypto/api/transactions/PaymentTransaction.js
Normal file
@@ -0,0 +1,63 @@
|
||||
'use strict'
|
||||
import TransactionBase from './TransactionBase.js'
|
||||
import Base58 from '../deps/Base58.js'
|
||||
import { store } from '../../api.js'
|
||||
|
||||
export default class PaymentTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 2
|
||||
}
|
||||
|
||||
render(html) {
|
||||
const conf = store.getState().config
|
||||
return html`
|
||||
<table>
|
||||
<tr>
|
||||
<th>${this._dialogto}:</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>${this.dialogAddress} ${' '}-</td>
|
||||
<td>${Base58.encode(this._recipient)}</td>
|
||||
</tr>
|
||||
${this.recipientName ? html`
|
||||
<tr>
|
||||
<td>${this.dialogName} ${' '}-</td>
|
||||
<td>${this.recipientName}</td>
|
||||
</tr>
|
||||
` : ''}
|
||||
<tr>
|
||||
<th>${this._dialogamount}</th>
|
||||
<td>${this._amount / conf.coin.decimals} ${conf.coin.symbol}</td>
|
||||
</tr>
|
||||
</table>
|
||||
`
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
}
|
||||
|
||||
set dialogto(dialogto) {
|
||||
this._dialogto = dialogto
|
||||
}
|
||||
|
||||
set dialogamount(dialogamount) {
|
||||
this._dialogamount = dialogamount
|
||||
}
|
||||
|
||||
set amount(amount) {
|
||||
this._amount = Math.round(amount * store.getState().config.coin.decimals)
|
||||
this._amountBytes = this.constructor.utils.int64ToBytes(this._amount)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._recipient,
|
||||
this._amountBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
27
crypto/api/transactions/PublicizeTransaction.js
Normal file
27
crypto/api/transactions/PublicizeTransaction.js
Normal file
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
import ChatBase from "./chat/ChatBase.js"
|
||||
import { QORT_DECIMALS } from "../constants.js"
|
||||
|
||||
export default class PublicizeTransaction extends ChatBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 19
|
||||
this.fee = 0
|
||||
}
|
||||
|
||||
set proofOfWorkNonce(proofOfWorkNonce) {
|
||||
this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce)
|
||||
}
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
get params() {
|
||||
const params = super.params;
|
||||
params.push(
|
||||
this._proofOfWorkNonce,
|
||||
this._feeBytes
|
||||
)
|
||||
return params;
|
||||
}
|
||||
}
|
168
crypto/api/transactions/TransactionBase.js
Normal file
168
crypto/api/transactions/TransactionBase.js
Normal file
@@ -0,0 +1,168 @@
|
||||
'use strict'
|
||||
import { TX_TYPES, QORT_DECIMALS } from '../constants.js'
|
||||
import nacl from '../deps/nacl-fast.js'
|
||||
import Base58 from '../deps/Base58.js'
|
||||
import utils from '../deps/utils.js'
|
||||
|
||||
export default class TransactionBase {
|
||||
static get utils() {
|
||||
return utils
|
||||
}
|
||||
static get nacl() {
|
||||
return nacl
|
||||
}
|
||||
static get Base58() {
|
||||
return Base58
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.fee = 0
|
||||
this.groupID = 0
|
||||
this.timestamp = Date.now()
|
||||
this.tests = [
|
||||
() => {
|
||||
if (!(this._type >= 1 && this._type in TX_TYPES)) {
|
||||
return 'Invalid type: ' + this.type
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (this._fee < 0) {
|
||||
return 'Invalid fee: ' + this._fee / QORT_DECIMALS
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (this._groupID < 0 || !Number.isInteger(this._groupID)) {
|
||||
return 'Invalid groupID: ' + this._groupID
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (!(new Date(this._timestamp)).getTime() > 0) {
|
||||
return 'Invalid timestamp: ' + this._timestamp
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) {
|
||||
if (this._lastReference == 0) {
|
||||
return 'Invalid last reference. Please ensure that you have at least 0.001 QORT for the transaction fee.'
|
||||
}
|
||||
return 'Invalid last reference: ' + this._lastReference
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (!(this._keyPair)) {
|
||||
return 'keyPair must be specified'
|
||||
}
|
||||
if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) {
|
||||
return 'Invalid publicKey'
|
||||
}
|
||||
if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) {
|
||||
return 'Invalid privateKey'
|
||||
}
|
||||
return true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`render method to display requested transaction info`
|
||||
}
|
||||
|
||||
set keyPair(keyPair) {
|
||||
this._keyPair = keyPair
|
||||
}
|
||||
|
||||
set type(type) {
|
||||
this.typeText = TX_TYPES[type]
|
||||
this._type = type
|
||||
this._typeBytes = this.constructor.utils.int32ToBytes(this._type)
|
||||
}
|
||||
|
||||
set groupID(groupID) {
|
||||
this._groupID = groupID
|
||||
this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID)
|
||||
}
|
||||
|
||||
set timestamp(timestamp) {
|
||||
this._timestamp = timestamp
|
||||
this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp)
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set lastReference(lastReference) {
|
||||
this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference)
|
||||
}
|
||||
|
||||
get params() {
|
||||
return [
|
||||
this._typeBytes,
|
||||
this._timestampBytes,
|
||||
this._groupIDBytes,
|
||||
this._lastReference,
|
||||
this._keyPair.publicKey
|
||||
]
|
||||
}
|
||||
|
||||
get signedBytes() {
|
||||
if (!this._signedBytes) {
|
||||
this.sign()
|
||||
}
|
||||
return this._signedBytes
|
||||
}
|
||||
|
||||
validParams() {
|
||||
let finalResult = {
|
||||
valid: true
|
||||
}
|
||||
this.tests.some(test => {
|
||||
const result = test()
|
||||
if (result !== true) {
|
||||
finalResult = {
|
||||
valid: false,
|
||||
message: result
|
||||
}
|
||||
return true // exists the loop
|
||||
}
|
||||
})
|
||||
return finalResult
|
||||
}
|
||||
|
||||
generateBase() {
|
||||
const isValid = this.validParams()
|
||||
if (!isValid.valid) {
|
||||
throw new Error(isValid.message)
|
||||
}
|
||||
let result = new Uint8Array()
|
||||
|
||||
this.params.forEach(item => {
|
||||
result = this.constructor.utils.appendBuffer(result, item)
|
||||
})
|
||||
|
||||
this._base = result
|
||||
return result
|
||||
}
|
||||
|
||||
sign() {
|
||||
if (!this._keyPair) {
|
||||
throw new Error('keyPair not defined')
|
||||
}
|
||||
|
||||
if (!this._base) {
|
||||
this.generateBase()
|
||||
}
|
||||
|
||||
this._signature = this.constructor.nacl.sign.detached(this._base, this._keyPair.privateKey)
|
||||
|
||||
this._signedBytes = this.constructor.utils.appendBuffer(this._base, this._signature)
|
||||
|
||||
return this._signature
|
||||
}
|
||||
}
|
42
crypto/api/transactions/TransferPrivsTransaction.js
Normal file
42
crypto/api/transactions/TransferPrivsTransaction.js
Normal file
@@ -0,0 +1,42 @@
|
||||
'use strict'
|
||||
import TransactionBase from './TransactionBase.js'
|
||||
import Base58 from '../deps/Base58.js'
|
||||
import { store } from '../../api.js'
|
||||
import { QORT_DECIMALS } from '../constants.js'
|
||||
|
||||
export default class TransferPrivsTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 40
|
||||
}
|
||||
|
||||
render(html) {
|
||||
const conf = store.getState().config
|
||||
return html`
|
||||
Are you sure to transfer privileges to this account ?
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.theRecipient}</span>
|
||||
</div>
|
||||
On pressing confirm, the transfer privileges request will be sent!
|
||||
`
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._recipient,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
38
crypto/api/transactions/arbitrary/signArbitrary.js
Normal file
38
crypto/api/transactions/arbitrary/signArbitrary.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import nacl from '../../deps/nacl-fast.js'
|
||||
import utils from '../../deps/utils.js'
|
||||
import Base58 from '../../deps/Base58.js'
|
||||
|
||||
const signArbitrary = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair) => {
|
||||
|
||||
if (!arbitraryBytesBase58) {
|
||||
throw new Error('ArbitraryBytesBase58 not defined')
|
||||
}
|
||||
|
||||
if (!nonce) {
|
||||
throw new Error('Nonce not defined')
|
||||
}
|
||||
|
||||
if (!keyPair) {
|
||||
throw new Error('keyPair not defined')
|
||||
}
|
||||
|
||||
const arbitraryBytes = Base58.decode(arbitraryBytesBase58)
|
||||
const _arbitraryBytesBuffer = Object.keys(arbitraryBytes).map(function (key) { return arbitraryBytes[key]; })
|
||||
const arbitraryBytesBuffer = new Uint8Array(_arbitraryBytesBuffer)
|
||||
|
||||
const arbitraryBytesForSigning = Base58.decode(arbitraryBytesForSigningBase58)
|
||||
const _arbitraryBytesForSigningBuffer = Object.keys(arbitraryBytesForSigning).map(function (key) { return arbitraryBytesForSigning[key]; })
|
||||
const arbitraryBytesForSigningBuffer = new Uint8Array(_arbitraryBytesForSigningBuffer)
|
||||
|
||||
const _nonce = utils.int32ToBytes(nonce)
|
||||
arbitraryBytesBuffer.set(_nonce, 112)
|
||||
arbitraryBytesForSigningBuffer.set(_nonce, 112)
|
||||
|
||||
const signature = nacl.sign.detached(arbitraryBytesForSigningBuffer, keyPair.privateKey)
|
||||
|
||||
const signedBytes = utils.appendBuffer(arbitraryBytesBuffer, signature)
|
||||
|
||||
return signedBytes
|
||||
}
|
||||
|
||||
export default signArbitrary
|
33
crypto/api/transactions/arbitrary/signArbitraryWithFee.js
Normal file
33
crypto/api/transactions/arbitrary/signArbitraryWithFee.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import nacl from '../../deps/nacl-fast.js'
|
||||
import utils from '../../deps/utils.js'
|
||||
import Base58 from '../../deps/Base58.js'
|
||||
|
||||
const signArbitraryWithFee = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair) => {
|
||||
|
||||
if (!arbitraryBytesBase58) {
|
||||
throw new Error('ArbitraryBytesBase58 not defined')
|
||||
}
|
||||
|
||||
|
||||
if (!keyPair) {
|
||||
throw new Error('keyPair not defined')
|
||||
}
|
||||
|
||||
const arbitraryBytes = Base58.decode(arbitraryBytesBase58)
|
||||
const _arbitraryBytesBuffer = Object.keys(arbitraryBytes).map(function (key) { return arbitraryBytes[key]; })
|
||||
const arbitraryBytesBuffer = new Uint8Array(_arbitraryBytesBuffer)
|
||||
|
||||
const arbitraryBytesForSigning = Base58.decode(arbitraryBytesForSigningBase58)
|
||||
const _arbitraryBytesForSigningBuffer = Object.keys(arbitraryBytesForSigning).map(function (key) { return arbitraryBytesForSigning[key]; })
|
||||
const arbitraryBytesForSigningBuffer = new Uint8Array(_arbitraryBytesForSigningBuffer)
|
||||
|
||||
|
||||
|
||||
const signature = nacl.sign.detached(arbitraryBytesForSigningBuffer, keyPair.privateKey)
|
||||
|
||||
const signedBytes = utils.appendBuffer(arbitraryBytesBuffer, signature)
|
||||
|
||||
return signedBytes
|
||||
}
|
||||
|
||||
export default signArbitraryWithFee
|
37
crypto/api/transactions/arbitraryV3.js
Normal file
37
crypto/api/transactions/arbitraryV3.js
Normal file
@@ -0,0 +1,37 @@
|
||||
'use strict'
|
||||
|
||||
(function () {
|
||||
function generateSignatureArbitraryTransactionV3(keyPair, lastReference, service, arbitraryData, fee, timestamp) => {
|
||||
const data = generateArbitraryTransactionV3Base(keyPair.publicKey, lastReference, service, arbitraryData, fee, timestamp)
|
||||
return nacl.sign.detached(data, keyPair.privateKey)
|
||||
}
|
||||
|
||||
function generateArbitraryTransactionV3(keyPair, lastReference, service, arbitraryData, fee, timestamp, signature) => {
|
||||
return appendBuffer(generateArbitraryTransactionV3Base(keyPair.publicKey, lastReference, service, arbitraryData, fee, timestamp), signature)
|
||||
}
|
||||
|
||||
function generateArbitraryTransactionV3Base(publicKey, lastReference, service, arbitraryData, fee, timestamp) => {
|
||||
const txType = TYPES.ARBITRARY_TRANSACTION
|
||||
const typeBytes = int32ToBytes(txType)
|
||||
const timestampBytes = int64ToBytes(timestamp)
|
||||
const feeBytes = int64ToBytes(fee * 100000000)
|
||||
const serviceBytes = int32ToBytes(service)
|
||||
const dataSizeBytes = int32ToBytes(arbitraryData.length)
|
||||
const paymentsLengthBytes = int32ToBytes(0) // Support payments - not yet.
|
||||
|
||||
var data = new Uint8Array()
|
||||
|
||||
data = appendBuffer(data, typeBytes)
|
||||
data = appendBuffer(data, timestampBytes)
|
||||
data = appendBuffer(data, lastReference)
|
||||
data = appendBuffer(data, publicKey)
|
||||
data = appendBuffer(data, paymentsLengthBytes)
|
||||
// Here it is necessary to insert the payments, if there are
|
||||
data = appendBuffer(data, serviceBytes)
|
||||
data = appendBuffer(data, dataSizeBytes)
|
||||
data = appendBuffer(data, arbitraryData)
|
||||
data = appendBuffer(data, feeBytes)
|
||||
|
||||
return data
|
||||
}
|
||||
}())
|
141
crypto/api/transactions/chat/ChatBase.js
Normal file
141
crypto/api/transactions/chat/ChatBase.js
Normal file
@@ -0,0 +1,141 @@
|
||||
'use strict'
|
||||
import { TX_TYPES, QORT_DECIMALS } from '../../constants.js'
|
||||
import nacl from '../../deps/nacl-fast.js'
|
||||
import Base58 from '../../deps/Base58.js'
|
||||
import utils from '../../deps/utils.js'
|
||||
|
||||
export default class ChatBase {
|
||||
static get utils() {
|
||||
return utils
|
||||
}
|
||||
static get nacl() {
|
||||
return nacl
|
||||
}
|
||||
static get Base58() {
|
||||
return Base58
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.fee = 0
|
||||
this.groupID = 0
|
||||
this.tests = [
|
||||
() => {
|
||||
if (!(this._type >= 1 && this._type in TX_TYPES)) {
|
||||
return 'Invalid type: ' + this.type
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (this._fee < 0) {
|
||||
return 'Invalid fee: ' + this._fee / QORT_DECIMALS
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (this._groupID < 0 || !Number.isInteger(this._groupID)) {
|
||||
return 'Invalid groupID: ' + this._groupID
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (!(new Date(this._timestamp)).getTime() > 0) {
|
||||
return 'Invalid timestamp: ' + this._timestamp
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) {
|
||||
return 'Invalid last reference: ' + this._lastReference
|
||||
}
|
||||
return true
|
||||
},
|
||||
() => {
|
||||
if (!(this._keyPair)) {
|
||||
return 'keyPair must be specified'
|
||||
}
|
||||
if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) {
|
||||
return 'Invalid publicKey'
|
||||
}
|
||||
if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) {
|
||||
return 'Invalid privateKey'
|
||||
}
|
||||
return true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
set keyPair(keyPair) {
|
||||
this._keyPair = keyPair
|
||||
}
|
||||
|
||||
set type(type) {
|
||||
this.typeText = TX_TYPES[type]
|
||||
this._type = type
|
||||
this._typeBytes = this.constructor.utils.int32ToBytes(this._type)
|
||||
}
|
||||
|
||||
set groupID(groupID) {
|
||||
this._groupID = groupID
|
||||
this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID)
|
||||
}
|
||||
|
||||
set timestamp(timestamp) {
|
||||
this._timestamp = timestamp
|
||||
this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp)
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set lastReference(lastReference) {
|
||||
this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference)
|
||||
}
|
||||
|
||||
get params() {
|
||||
return [
|
||||
this._typeBytes,
|
||||
this._timestampBytes,
|
||||
this._groupIDBytes,
|
||||
this._lastReference,
|
||||
this._keyPair.publicKey
|
||||
]
|
||||
}
|
||||
|
||||
get chatBytes() {
|
||||
const isValid = this.validParams()
|
||||
if (!isValid.valid) {
|
||||
throw new Error(isValid.message)
|
||||
}
|
||||
|
||||
let result = new Uint8Array()
|
||||
|
||||
this.params.forEach(item => {
|
||||
result = this.constructor.utils.appendBuffer(result, item)
|
||||
})
|
||||
|
||||
this._chatBytes = result
|
||||
|
||||
return this._chatBytes
|
||||
}
|
||||
|
||||
validParams() {
|
||||
let finalResult = {
|
||||
valid: true
|
||||
}
|
||||
|
||||
this.tests.some(test => {
|
||||
const result = test()
|
||||
if (result !== true) {
|
||||
finalResult = {
|
||||
valid: false,
|
||||
message: result
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
return finalResult
|
||||
}
|
||||
|
||||
}
|
92
crypto/api/transactions/chat/ChatTransaction.js
Normal file
92
crypto/api/transactions/chat/ChatTransaction.js
Normal file
@@ -0,0 +1,92 @@
|
||||
'use strict'
|
||||
import ChatBase from "./ChatBase.js"
|
||||
import nacl from '../../deps/nacl-fast.js'
|
||||
import ed2curve from '../../deps/ed2curve.js'
|
||||
import { Sha256 } from 'asmcrypto.js'
|
||||
import { CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP } from '../../constants.js'
|
||||
|
||||
|
||||
export default class ChatTransaction extends ChatBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 18
|
||||
this.fee = 0
|
||||
}
|
||||
|
||||
set recipientPublicKey(recipientPublicKey) {
|
||||
this._base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? this.constructor.Base58.encode(recipientPublicKey) : recipientPublicKey
|
||||
this._recipientPublicKey = this.constructor.Base58.decode(this._base58RecipientPublicKey)
|
||||
}
|
||||
|
||||
set proofOfWorkNonce(proofOfWorkNonce) {
|
||||
this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this._hasReceipient = new Uint8Array(1)
|
||||
this._hasReceipient[0] = 1
|
||||
}
|
||||
|
||||
set hasChatReference(hasChatReference) {
|
||||
this._hasChatReference = new Uint8Array(1)
|
||||
this._hasChatReference[0] = hasChatReference
|
||||
}
|
||||
|
||||
set chatReference(chatReference) {
|
||||
this._chatReference = chatReference instanceof Uint8Array ? chatReference : this.constructor.Base58.decode(chatReference)
|
||||
}
|
||||
|
||||
set message(message) {
|
||||
this.messageText = message;
|
||||
this._message = this.constructor.utils.stringtoUTF8Array(message)
|
||||
this._messageLength = this.constructor.utils.int32ToBytes(this._message.length)
|
||||
}
|
||||
|
||||
set isEncrypted(isEncrypted) {
|
||||
this._isEncrypted = new Uint8Array(1)
|
||||
this._isEncrypted[0] = isEncrypted
|
||||
|
||||
if (isEncrypted === 1) {
|
||||
const convertedPrivateKey = ed2curve.convertSecretKey(this._keyPair.privateKey)
|
||||
const convertedPublicKey = ed2curve.convertPublicKey(this._recipientPublicKey)
|
||||
const sharedSecret = new Uint8Array(32)
|
||||
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
|
||||
|
||||
this._chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result
|
||||
this._encryptedMessage = nacl.secretbox(this._message, this._lastReference.slice(0, 24), this._chatEncryptionSeed)
|
||||
}
|
||||
|
||||
this._myMessage = isEncrypted === 1 ? this._encryptedMessage : this._message
|
||||
this._myMessageLenth = isEncrypted === 1 ? this.constructor.utils.int32ToBytes(this._myMessage.length) : this._messageLength
|
||||
}
|
||||
|
||||
set isText(isText) {
|
||||
this._isText = new Uint8Array(1)
|
||||
this._isText[0] = isText
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._proofOfWorkNonce,
|
||||
this._hasReceipient,
|
||||
this._recipient,
|
||||
this._myMessageLenth,
|
||||
this._myMessage,
|
||||
this._isEncrypted,
|
||||
this._isText,
|
||||
this._feeBytes
|
||||
)
|
||||
|
||||
// After the feature trigger timestamp we need to include chat reference
|
||||
if (new Date(this._timestamp).getTime() >= CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP) {
|
||||
params.push(this._hasChatReference)
|
||||
|
||||
if (this._hasChatReference[0] == 1) {
|
||||
params.push(this._chatReference)
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
}
|
68
crypto/api/transactions/chat/GroupChatTransaction.js
Normal file
68
crypto/api/transactions/chat/GroupChatTransaction.js
Normal file
@@ -0,0 +1,68 @@
|
||||
'use strict'
|
||||
import ChatBase from "./ChatBase.js"
|
||||
import { CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP } from '../../constants.js'
|
||||
|
||||
export default class GroupChatTransaction extends ChatBase {
|
||||
constructor() {
|
||||
super();
|
||||
this.type = 18
|
||||
this.fee = 0
|
||||
}
|
||||
|
||||
set proofOfWorkNonce(proofOfWorkNonce) {
|
||||
this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce)
|
||||
}
|
||||
|
||||
set hasReceipient(hasReceipient) {
|
||||
this._hasReceipient = new Uint8Array(1)
|
||||
this._hasReceipient[0] = hasReceipient
|
||||
}
|
||||
|
||||
set message(message) {
|
||||
this.messageText = message
|
||||
this._message = this.constructor.utils.stringtoUTF8Array(message)
|
||||
this._messageLength = this.constructor.utils.int32ToBytes(this._message.length)
|
||||
}
|
||||
|
||||
set hasChatReference(hasChatReference) {
|
||||
this._hasChatReference = new Uint8Array(1)
|
||||
this._hasChatReference[0] = hasChatReference
|
||||
}
|
||||
|
||||
set chatReference(chatReference) {
|
||||
this._chatReference = chatReference instanceof Uint8Array ? chatReference : this.constructor.Base58.decode(chatReference)
|
||||
}
|
||||
|
||||
set isEncrypted(isEncrypted) {
|
||||
this._isEncrypted = new Uint8Array(1);
|
||||
this._isEncrypted[0] = isEncrypted
|
||||
}
|
||||
|
||||
set isText(isText) {
|
||||
this._isText = new Uint8Array(1)
|
||||
this._isText[0] = isText
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._proofOfWorkNonce,
|
||||
this._hasReceipient,
|
||||
this._messageLength,
|
||||
this._message,
|
||||
this._isEncrypted,
|
||||
this._isText,
|
||||
this._feeBytes
|
||||
)
|
||||
|
||||
// After the feature trigger timestamp we need to include chat reference
|
||||
if (new Date(this._timestamp).getTime() >= CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP) {
|
||||
params.push(this._hasChatReference)
|
||||
|
||||
if (this._hasChatReference[0] == 1) {
|
||||
params.push(this._chatReference)
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
}
|
57
crypto/api/transactions/chat/decryptChatMessage.js
Normal file
57
crypto/api/transactions/chat/decryptChatMessage.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import nacl from '../../deps/nacl-fast.js'
|
||||
import Base58 from '../../deps/Base58.js'
|
||||
import ed2curve from '../../deps/ed2curve.js'
|
||||
import { Sha256 } from 'asmcrypto.js'
|
||||
|
||||
export const decryptChatMessage = (encryptedMessage, privateKey, recipientPublicKey, lastReference) => {
|
||||
let _encryptedMessage = Base58.decode(encryptedMessage)
|
||||
|
||||
const _base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? Base58.encode(recipientPublicKey) : recipientPublicKey
|
||||
const _recipientPublicKey = Base58.decode(_base58RecipientPublicKey)
|
||||
|
||||
const _lastReference = lastReference instanceof Uint8Array ? lastReference : Base58.decode(lastReference)
|
||||
|
||||
const convertedPrivateKey = ed2curve.convertSecretKey(privateKey)
|
||||
const convertedPublicKey = ed2curve.convertPublicKey(_recipientPublicKey)
|
||||
const sharedSecret = new Uint8Array(32);
|
||||
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
|
||||
|
||||
const _chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result
|
||||
const _decryptedMessage = nacl.secretbox.open(_encryptedMessage, _lastReference.slice(0, 24), _chatEncryptionSeed)
|
||||
|
||||
let decryptedMessage = ''
|
||||
|
||||
_decryptedMessage === false ? decryptedMessage : decryptedMessage = new TextDecoder('utf-8').decode(_decryptedMessage)
|
||||
return decryptedMessage
|
||||
}
|
||||
|
||||
export const decryptChatMessageBase64 = (encryptedMessage, privateKey, recipientPublicKey, lastReference) => {
|
||||
let _encryptedMessage = atob(encryptedMessage);
|
||||
const binaryLength = _encryptedMessage.length;
|
||||
const bytes = new Uint8Array(binaryLength);
|
||||
|
||||
for (let i = 0; i < binaryLength; i++) {
|
||||
bytes[i] = _encryptedMessage.charCodeAt(i);
|
||||
}
|
||||
|
||||
const _base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? Base58.encode(recipientPublicKey) : recipientPublicKey
|
||||
const _recipientPublicKey = Base58.decode(_base58RecipientPublicKey)
|
||||
|
||||
const _lastReference = lastReference instanceof Uint8Array ? lastReference : Base58.decode(lastReference)
|
||||
|
||||
const convertedPrivateKey = ed2curve.convertSecretKey(privateKey)
|
||||
const convertedPublicKey = ed2curve.convertPublicKey(_recipientPublicKey)
|
||||
const sharedSecret = new Uint8Array(32);
|
||||
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
|
||||
|
||||
const _chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result
|
||||
const _decryptedMessage = nacl.secretbox.open(bytes, _lastReference.slice(0, 24), _chatEncryptionSeed)
|
||||
|
||||
|
||||
if (_decryptedMessage === false) {
|
||||
return _decryptedMessage
|
||||
}
|
||||
return new TextDecoder('utf-8').decode(_decryptedMessage)
|
||||
|
||||
|
||||
}
|
43
crypto/api/transactions/chat/signChat.js
Normal file
43
crypto/api/transactions/chat/signChat.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import nacl from '../../deps/nacl-fast.js'
|
||||
import utils from '../../deps/utils.js'
|
||||
|
||||
const signChat = (chatBytes, nonce, keyPair) => {
|
||||
|
||||
if (!chatBytes) {
|
||||
throw new Error('Chat Bytes not defined')
|
||||
}
|
||||
|
||||
if (!nonce) {
|
||||
throw new Error('Nonce not defined')
|
||||
}
|
||||
|
||||
if (!keyPair) {
|
||||
throw new Error('keyPair not defined')
|
||||
}
|
||||
|
||||
const _nonce = utils.int32ToBytes(nonce)
|
||||
|
||||
if (chatBytes.length === undefined) {
|
||||
const _chatBytesBuffer = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; })
|
||||
|
||||
const chatBytesBuffer = new Uint8Array(_chatBytesBuffer)
|
||||
chatBytesBuffer.set(_nonce, 112)
|
||||
|
||||
const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey)
|
||||
|
||||
const signedBytes = utils.appendBuffer(chatBytesBuffer, signature)
|
||||
|
||||
return signedBytes
|
||||
} else {
|
||||
const chatBytesBuffer = new Uint8Array(chatBytes)
|
||||
chatBytesBuffer.set(_nonce, 112)
|
||||
|
||||
const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey)
|
||||
|
||||
const signedBytes = utils.appendBuffer(chatBytesBuffer, signature)
|
||||
|
||||
return signedBytes
|
||||
}
|
||||
}
|
||||
|
||||
export default signChat
|
53
crypto/api/transactions/groups/AddGroupAdminTransaction.js
Normal file
53
crypto/api/transactions/groups/AddGroupAdminTransaction.js
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class AddGroupAdminTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 24
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._addAdminDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.theRecipient}</span>
|
||||
</div>
|
||||
${this._addAdminDialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set addAdminDialog1(addAdminDialog1) {
|
||||
this._addAdminDialog1 = addAdminDialog1
|
||||
}
|
||||
|
||||
set addAdminDialog2(addAdminDialog2) {
|
||||
this._addAdminDialog2 = addAdminDialog2
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._recipient,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
53
crypto/api/transactions/groups/CancelGroupBanTransaction.js
Normal file
53
crypto/api/transactions/groups/CancelGroupBanTransaction.js
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class CancelGroupBanTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 27
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._cancelBanMemberDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.theRecipient}</span>
|
||||
</div>
|
||||
${this._cancelBanMemberDialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set cancelBanMemberDialog1(cancelBanMemberDialog1) {
|
||||
this._cancelBanMemberDialog1 = cancelBanMemberDialog1
|
||||
}
|
||||
|
||||
set cancelBanMemberDialog2(cancelBanMemberDialog2) {
|
||||
this._cancelBanMemberDialog2 = cancelBanMemberDialog2
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._recipient,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class CancelGroupInviteTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 30
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._cancelInviteDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this._memberName}</span>
|
||||
</div>
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.theRecipient}</span>
|
||||
</div>
|
||||
${this._cancelInviteDialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set memberName(memberName) {
|
||||
this._memberName = memberName
|
||||
}
|
||||
|
||||
set cancelInviteDialog1(cancelInviteDialog1) {
|
||||
this._cancelInviteDialog1 = cancelInviteDialog1
|
||||
}
|
||||
|
||||
set cancelInviteDialog2(cancelInviteDialog2) {
|
||||
this._cancelInviteDialog2 = cancelInviteDialog2
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._recipient,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
98
crypto/api/transactions/groups/CreateGroupTransaction.js
Normal file
98
crypto/api/transactions/groups/CreateGroupTransaction.js
Normal file
@@ -0,0 +1,98 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class CreateGroupTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 22
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._groupdialog5}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<div>${this._groupdialog7}: <span style="color: #000;">${this._rGroupName}</span></div>
|
||||
<br>
|
||||
<div>${this._groupdialog8}: <span style="color: #000;">${this._rGroupDesc}</span></div>
|
||||
<br>
|
||||
<div>${this._groupdialog9}: <span style="color: #000;">${this.myGroupType === 1 ? "Public" : "Private"}</span></div>
|
||||
</div>
|
||||
${this._groupdialog6}
|
||||
`
|
||||
}
|
||||
|
||||
set groupdialog5(groupdialog5) {
|
||||
this._groupdialog5 = groupdialog5
|
||||
}
|
||||
|
||||
set groupdialog6(groupdialog6) {
|
||||
this._groupdialog6 = groupdialog6
|
||||
}
|
||||
|
||||
set groupdialog7(groupdialog7) {
|
||||
this._groupdialog7 = groupdialog7
|
||||
}
|
||||
|
||||
set groupdialog8(groupdialog8) {
|
||||
this._groupdialog8 = groupdialog8
|
||||
}
|
||||
|
||||
set groupdialog9(groupdialog9) {
|
||||
this._groupdialog9 = groupdialog9
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set rGroupName(rGroupName) {
|
||||
this._rGroupName = rGroupName
|
||||
this._rGroupNameBytes = this.constructor.utils.stringtoUTF8Array(this._rGroupName.toLocaleLowerCase())
|
||||
this._rGroupNameLength = this.constructor.utils.int32ToBytes(this._rGroupNameBytes.length)
|
||||
}
|
||||
|
||||
set rGroupDesc(rGroupDesc) {
|
||||
this._rGroupDesc = rGroupDesc
|
||||
this._rGroupDescBytes = this.constructor.utils.stringtoUTF8Array(this._rGroupDesc.toLocaleLowerCase())
|
||||
this._rGroupDescLength = this.constructor.utils.int32ToBytes(this._rGroupDescBytes.length)
|
||||
}
|
||||
|
||||
set rGroupType(rGroupType) {
|
||||
this.myGroupType = rGroupType
|
||||
this._rGroupType = new Uint8Array(1)
|
||||
this._rGroupType[0] = rGroupType
|
||||
}
|
||||
|
||||
set rGroupApprovalThreshold(rGroupApprovalThreshold) {
|
||||
this._rGroupApprovalThreshold = new Uint8Array(1)
|
||||
this._rGroupApprovalThreshold[0] = rGroupApprovalThreshold
|
||||
}
|
||||
|
||||
set rGroupMinimumBlockDelay(rGroupMinimumBlockDelay) {
|
||||
this._rGroupMinimumBlockDelay = rGroupMinimumBlockDelay
|
||||
this._rGroupMinimumBlockDelayBytes = this.constructor.utils.int32ToBytes(this._rGroupMinimumBlockDelay)
|
||||
}
|
||||
|
||||
set rGroupMaximumBlockDelay(rGroupMaximumBlockDelay) {
|
||||
this._rGroupMaximumBlockDelay = rGroupMaximumBlockDelay
|
||||
this._rGroupMaximumBlockDelayBytes = this.constructor.utils.int32ToBytes(this._rGroupMaximumBlockDelay)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupNameLength,
|
||||
this._rGroupNameBytes,
|
||||
this._rGroupDescLength,
|
||||
this._rGroupDescBytes,
|
||||
this._rGroupType,
|
||||
this._rGroupApprovalThreshold,
|
||||
this._rGroupMinimumBlockDelayBytes,
|
||||
this._rGroupMaximumBlockDelayBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
67
crypto/api/transactions/groups/GroupBanTransaction.js
Normal file
67
crypto/api/transactions/groups/GroupBanTransaction.js
Normal file
@@ -0,0 +1,67 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class GroupBanTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 26
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._banMemberDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.theRecipient}</span>
|
||||
</div>
|
||||
${this._banMemberDialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set banMemberDialog1(banMemberDialog1) {
|
||||
this._banMemberDialog1 = banMemberDialog1
|
||||
}
|
||||
|
||||
set banMemberDialog2(banMemberDialog2) {
|
||||
this._banMemberDialog2 = banMemberDialog2
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set rBanReason(rBanReason) {
|
||||
this._rBanReason = rBanReason
|
||||
this._rBanReasonBytes = this.constructor.utils.stringtoUTF8Array(this._rBanReason.toLocaleLowerCase())
|
||||
this._rBanReasonLength = this.constructor.utils.int32ToBytes(this._rBanReasonBytes.length)
|
||||
}
|
||||
|
||||
set rBanTime(rBanTime) {
|
||||
this._rBanTime = rBanTime
|
||||
this._rBanTimeBytes = this.constructor.utils.int32ToBytes(this._rBanTime)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._recipient,
|
||||
this._rBanReasonLength,
|
||||
this._rBanReasonBytes,
|
||||
this._rBanTimeBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
59
crypto/api/transactions/groups/GroupInviteTransaction.js
Normal file
59
crypto/api/transactions/groups/GroupInviteTransaction.js
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class GroupInviteTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 29
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._inviteMemberDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.theRecipient}</span>
|
||||
</div>
|
||||
${this._inviteMemberDialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set inviteMemberDialog1(inviteMemberDialog1) {
|
||||
this._inviteMemberDialog1 = inviteMemberDialog1
|
||||
}
|
||||
|
||||
set inviteMemberDialog2(inviteMemberDialog2) {
|
||||
this._inviteMemberDialog2 = inviteMemberDialog2
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set rInviteTime(rInviteTime) {
|
||||
this._rInviteTime = rInviteTime
|
||||
this._rInviteTimeBytes = this.constructor.utils.int32ToBytes(this._rInviteTime)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._recipient,
|
||||
this._rInviteTimeBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
61
crypto/api/transactions/groups/GroupKickTransaction.js
Normal file
61
crypto/api/transactions/groups/GroupKickTransaction.js
Normal file
@@ -0,0 +1,61 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class GroupKickTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 28
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._kickMemberDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.theRecipient}</span>
|
||||
</div>
|
||||
${this._kickMemberDialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set kickMemberDialog1(kickMemberDialog1) {
|
||||
this._kickMemberDialog1 = kickMemberDialog1
|
||||
}
|
||||
|
||||
set kickMemberDialog2(kickMemberDialog2) {
|
||||
this._kickMemberDialog2 = kickMemberDialog2
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set rBanReason(rBanReason) {
|
||||
this._rBanReason = rBanReason
|
||||
this._rBanReasonBytes = this.constructor.utils.stringtoUTF8Array(this._rBanReason.toLocaleLowerCase())
|
||||
this._rBanReasonLength = this.constructor.utils.int32ToBytes(this._rBanReasonBytes.length)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._recipient,
|
||||
this._rBanReasonLength,
|
||||
this._rBanReasonBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
55
crypto/api/transactions/groups/JoinGroupTransaction.js
Normal file
55
crypto/api/transactions/groups/JoinGroupTransaction.js
Normal file
@@ -0,0 +1,55 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class JoinGroupTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 31
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._groupdialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this._rGroupName}</span>
|
||||
</div>
|
||||
${this._groupdialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set groupdialog1(groupdialog1) {
|
||||
this._groupdialog1 = groupdialog1
|
||||
}
|
||||
|
||||
set groupdialog2(groupdialog2) {
|
||||
this._groupdialog2 = groupdialog2
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set registrantAddress(registrantAddress) {
|
||||
this._registrantAddress = registrantAddress instanceof Uint8Array ? registrantAddress : this.constructor.Base58.decode(registrantAddress)
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set rGroupName(rGroupName) {
|
||||
this._rGroupName = rGroupName
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
55
crypto/api/transactions/groups/LeaveGroupTransaction.js
Normal file
55
crypto/api/transactions/groups/LeaveGroupTransaction.js
Normal file
@@ -0,0 +1,55 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class LeaveGroupTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 32
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._groupdialog3}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this._rGroupName}</span>
|
||||
</div>
|
||||
${this._groupdialog4}
|
||||
`
|
||||
}
|
||||
|
||||
set groupdialog3(groupdialog3) {
|
||||
this._groupdialog3 = groupdialog3
|
||||
}
|
||||
|
||||
set groupdialog4(groupdialog4) {
|
||||
this._groupdialog4 = groupdialog4
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set registrantAddress(registrantAddress) {
|
||||
this._registrantAddress = registrantAddress instanceof Uint8Array ? registrantAddress : this.constructor.Base58.decode(registrantAddress)
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set rGroupName(rGroupName) {
|
||||
this._rGroupName = rGroupName
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class RemoveGroupAdminTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 25
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._kickAdminDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.theRecipient}</span>
|
||||
</div>
|
||||
${this._kickAdminDialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set kickAdminDialog1(kickAdminDialog1) {
|
||||
this._kickAdminDialog1 = kickAdminDialog1
|
||||
}
|
||||
|
||||
set kickAdminDialog2(kickAdminDialog2) {
|
||||
this._kickAdminDialog2 = kickAdminDialog2
|
||||
}
|
||||
|
||||
set rGroupId(rGroupId) {
|
||||
this._rGroupId = rGroupId
|
||||
this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._rGroupIdBytes,
|
||||
this._recipient,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
72
crypto/api/transactions/groups/UpdateGroupTransaction.js
Normal file
72
crypto/api/transactions/groups/UpdateGroupTransaction.js
Normal file
@@ -0,0 +1,72 @@
|
||||
'use strict';
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import Base58 from '../../deps/Base58.js'
|
||||
import { store } from '../../../api.js'
|
||||
import { QORT_DECIMALS } from "../../constants.js"
|
||||
|
||||
export default class UpdateGroupTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 23
|
||||
}
|
||||
|
||||
render(html) {
|
||||
const conf = store.getState().config
|
||||
return html`
|
||||
Are you sure to update this group ?
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
|
||||
</div>
|
||||
On pressing confirm, the group details will be updated!
|
||||
`
|
||||
}
|
||||
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
set newOwner(newOwner) {
|
||||
this._newOwner = newOwner instanceof Uint8Array ? newOwner : this.constructor.Base58.decode(newOwner)
|
||||
}
|
||||
set newIsOpen(newIsOpen) {
|
||||
|
||||
this._rGroupType = new Uint8Array(1)
|
||||
this._rGroupType[0] = newIsOpen
|
||||
}
|
||||
set newDescription(newDescription) {
|
||||
this._rGroupDescBytes = this.constructor.utils.stringtoUTF8Array(newDescription.toLocaleLowerCase())
|
||||
this._rGroupDescLength = this.constructor.utils.int32ToBytes(this._rGroupDescBytes.length)
|
||||
}
|
||||
set newApprovalThreshold(newApprovalThreshold) {
|
||||
this._rGroupApprovalThreshold = new Uint8Array(1)
|
||||
this._rGroupApprovalThreshold[0] = newApprovalThreshold;
|
||||
}
|
||||
set newMinimumBlockDelay(newMinimumBlockDelay) {
|
||||
this._rGroupMinimumBlockDelayBytes = this.constructor.utils.int32ToBytes(newMinimumBlockDelay)
|
||||
}
|
||||
set newMaximumBlockDelay(newMaximumBlockDelay) {
|
||||
|
||||
this._rGroupMaximumBlockDelayBytes = this.constructor.utils.int32ToBytes(newMaximumBlockDelay)
|
||||
}
|
||||
|
||||
set _groupId(_groupId){
|
||||
this._groupBytes = this.constructor.utils.int32ToBytes(_groupId)
|
||||
}
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._groupBytes,
|
||||
this._newOwner,
|
||||
this._rGroupDescLength,
|
||||
this._rGroupDescBytes,
|
||||
this._rGroupType,
|
||||
this._rGroupApprovalThreshold,
|
||||
this._rGroupMinimumBlockDelayBytes,
|
||||
this._rGroupMaximumBlockDelayBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
console.log('verify params', params)
|
||||
return params
|
||||
}
|
||||
}
|
70
crypto/api/transactions/names/BuyNameTransacion.js
Normal file
70
crypto/api/transactions/names/BuyNameTransacion.js
Normal file
@@ -0,0 +1,70 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class BuyNameTransacion extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 7
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._buyNameDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.nameText}</span>
|
||||
</div>
|
||||
${this._buyNameDialog2}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.showSellPrice}</span>
|
||||
</div>
|
||||
${this._buyNameDialog3}
|
||||
`
|
||||
}
|
||||
|
||||
set buyNameDialog1(buyNameDialog1) {
|
||||
this._buyNameDialog1 = buyNameDialog1
|
||||
}
|
||||
|
||||
set buyNameDialog2(buyNameDialog2) {
|
||||
this._buyNameDialog2 = buyNameDialog2
|
||||
}
|
||||
|
||||
set buyNameDialog3(buyNameDialog3) {
|
||||
this._buyNameDialog3 = buyNameDialog3
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set name(name) {
|
||||
this.nameText = name
|
||||
this._nameBytes = this.constructor.utils.stringtoUTF8Array(name)
|
||||
this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length)
|
||||
}
|
||||
|
||||
set sellPrice(sellPrice) {
|
||||
this.showSellPrice = sellPrice
|
||||
this._sellPrice = sellPrice * QORT_DECIMALS
|
||||
this._sellPriceBytes = this.constructor.utils.int64ToBytes(this._sellPrice)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.theRecipient = recipient
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._nameLength,
|
||||
this._nameBytes,
|
||||
this._sellPriceBytes,
|
||||
this._recipient,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
49
crypto/api/transactions/names/CancelSellNameTransacion.js
Normal file
49
crypto/api/transactions/names/CancelSellNameTransacion.js
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class CancelSellNameTransacion extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 6
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._cancelSellNameDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.nameText}</span>
|
||||
</div>
|
||||
${this._cancelSellNameDialog2}
|
||||
`
|
||||
}
|
||||
|
||||
set cancelSellNameDialog1(cancelSellNameDialog1) {
|
||||
this._cancelSellNameDialog1 = cancelSellNameDialog1
|
||||
}
|
||||
|
||||
set cancelSellNameDialog2(cancelSellNameDialog2) {
|
||||
this._cancelSellNameDialog2 = cancelSellNameDialog2
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set name(name) {
|
||||
this.nameText = name
|
||||
this._nameBytes = this.constructor.utils.stringtoUTF8Array(name)
|
||||
this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._nameLength,
|
||||
this._nameBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
57
crypto/api/transactions/names/RegisterNameTransaction.js
Normal file
57
crypto/api/transactions/names/RegisterNameTransaction.js
Normal file
@@ -0,0 +1,57 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class RegisterNameTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 3
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._dialogyou}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.nameText}</span>
|
||||
</div>
|
||||
${this._dialogonpress}
|
||||
`
|
||||
}
|
||||
|
||||
set dialogyou(dialogyou) {
|
||||
this._dialogyou = dialogyou
|
||||
}
|
||||
|
||||
set dialogonpress(dialogonpress) {
|
||||
this._dialogonpress = dialogonpress
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set name(name) {
|
||||
this.nameText = name
|
||||
this._nameBytes = this.constructor.utils.stringtoUTF8Array(name)
|
||||
this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length)
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
this.valueText = value.length === 0 ? "Registered Name on the Qortal Chain" : value
|
||||
this._valueBytes = this.constructor.utils.stringtoUTF8Array(this.valueText)
|
||||
this._valueLength = this.constructor.utils.int32ToBytes(this._valueBytes.length)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._nameLength,
|
||||
this._nameBytes,
|
||||
this._valueLength,
|
||||
this._valueBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
64
crypto/api/transactions/names/SellNameTransacion.js
Normal file
64
crypto/api/transactions/names/SellNameTransacion.js
Normal file
@@ -0,0 +1,64 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class SellNameTransacion extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 5
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._sellNameDialog1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.nameText}</span>
|
||||
</div>
|
||||
${this._sellNameDialog2}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.showSellPrice}</span>
|
||||
</div>
|
||||
${this._sellNameDialog3}
|
||||
`
|
||||
}
|
||||
|
||||
set sellNameDialog1(sellNameDialog1) {
|
||||
this._sellNameDialog1 = sellNameDialog1
|
||||
}
|
||||
|
||||
set sellNameDialog2(sellNameDialog2) {
|
||||
this._sellNameDialog2 = sellNameDialog2
|
||||
}
|
||||
|
||||
set sellNameDialog3(sellNameDialog3) {
|
||||
this._sellNameDialog3 = sellNameDialog3
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set name(name) {
|
||||
this.nameText = name
|
||||
this._nameBytes = this.constructor.utils.stringtoUTF8Array(name)
|
||||
this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length)
|
||||
}
|
||||
|
||||
set sellPrice(sellPrice) {
|
||||
this.showSellPrice = sellPrice
|
||||
this._sellPrice = sellPrice * QORT_DECIMALS
|
||||
this._sellPriceBytes = this.constructor.utils.int64ToBytes(this._sellPrice)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._nameLength,
|
||||
this._nameBytes,
|
||||
this._sellPriceBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
73
crypto/api/transactions/names/UpdateNameTransaction.js
Normal file
73
crypto/api/transactions/names/UpdateNameTransaction.js
Normal file
@@ -0,0 +1,73 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import { QORT_DECIMALS } from '../../constants.js'
|
||||
|
||||
export default class UpdateNameTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 4
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._dialogUpdateName1}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.nameText}</span>
|
||||
</div>
|
||||
${this._dialogUpdateName2}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.newNameText}</span>
|
||||
</div>
|
||||
${this._dialogUpdateName3}
|
||||
`
|
||||
}
|
||||
|
||||
set dialogUpdateName1(dialogUpdateName1) {
|
||||
this._dialogUpdateName1 = dialogUpdateName1
|
||||
}
|
||||
|
||||
set dialogUpdateName2(dialogUpdateName2) {
|
||||
this._dialogUpdateName2 = dialogUpdateName2
|
||||
}
|
||||
|
||||
set dialogUpdateName3(dialogUpdateName3) {
|
||||
this._dialogUpdateName3 = dialogUpdateName3
|
||||
}
|
||||
|
||||
set fee(fee) {
|
||||
this._fee = fee * QORT_DECIMALS
|
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||
}
|
||||
|
||||
set name(name) {
|
||||
this.nameText = name
|
||||
this._nameBytes = this.constructor.utils.stringtoUTF8Array(name)
|
||||
this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length)
|
||||
}
|
||||
|
||||
set newName(newName) {
|
||||
this.newNameText = newName
|
||||
this._newNameBytes = this.constructor.utils.stringtoUTF8Array(newName)
|
||||
this._newNameLength = this.constructor.utils.int32ToBytes(this._newNameBytes.length)
|
||||
}
|
||||
|
||||
set newData(newData) {
|
||||
this.newDataText = newData.length === 0 ? "Registered Name on the Qortal Chain" : newData
|
||||
this._newDataBytes = this.constructor.utils.stringtoUTF8Array(this.newDataText)
|
||||
this._newDataLength = this.constructor.utils.int32ToBytes(this._newDataBytes.length)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._nameLength,
|
||||
this._nameBytes,
|
||||
this._newNameLength,
|
||||
this._newNameBytes,
|
||||
this._newDataLength,
|
||||
this._newDataBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
0
crypto/api/transactions/processTransaction.js
Normal file
0
crypto/api/transactions/processTransaction.js
Normal file
36
crypto/api/transactions/registerName_dnsthing.js
Normal file
36
crypto/api/transactions/registerName_dnsthing.js
Normal file
@@ -0,0 +1,36 @@
|
||||
'use strict'
|
||||
|
||||
(function () {
|
||||
function generateSignatureRegisterNameTransaction(keyPair, lastReference, owner, name, value, fee, timestamp) => {
|
||||
const data = generateRegisterNameTransactionBase(keyPair.publicKey, lastReference, owner, name, value, fee, timestamp)
|
||||
return nacl.sign.detached(data, keyPair.privateKey)
|
||||
}
|
||||
|
||||
function generateRegisterNameTransaction(keyPair, lastReference, owner, name, value, fee, timestamp, signature) => {
|
||||
return appendBuffer(generateRegisterNameTransactionBase(keyPair.publicKey, lastReference, owner, name, value, fee, timestamp), signature)
|
||||
}
|
||||
|
||||
function generateRegisterNameTransactionBase(publicKey, lastReference, owner, name, value, fee, timestamp) => {
|
||||
const txType = TYPES.REGISTER_NAME_TRANSACTION
|
||||
const typeBytes = int32ToBytes(txType)
|
||||
const timestampBytes = int64ToBytes(timestamp)
|
||||
const feeBytes = int64ToBytes(fee * 100000000)
|
||||
const nameSizeBytes = int32ToBytes(name.length)
|
||||
const valueSizeBytes = int32ToBytes(value.length)
|
||||
|
||||
let data = new Uint8Array()
|
||||
|
||||
data = appendBuffer(data, typeBytes)
|
||||
data = appendBuffer(data, timestampBytes)
|
||||
data = appendBuffer(data, lastReference)
|
||||
data = appendBuffer(data, publicKey)
|
||||
data = appendBuffer(data, owner)
|
||||
data = appendBuffer(data, nameSizeBytes)
|
||||
data = appendBuffer(data, name)
|
||||
data = appendBuffer(data, valueSizeBytes)
|
||||
data = appendBuffer(data, value)
|
||||
data = appendBuffer(data, feeBytes)
|
||||
|
||||
return data
|
||||
}
|
||||
}())
|
@@ -0,0 +1,55 @@
|
||||
'use strict'
|
||||
import TransactionBase from '../TransactionBase.js'
|
||||
import publicKeyToAddress from '../../wallet/publicKeyToAddress.js'
|
||||
import { Base58 } from '../../deps/deps.js'
|
||||
|
||||
export default class RemoveRewardShareTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 38
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._rewarddialog5}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this.constructor.Base58.encode(this._recipient)}</span>
|
||||
</div>
|
||||
${this._rewarddialog6}
|
||||
`
|
||||
}
|
||||
|
||||
set rewarddialog5(rewarddialog5) {
|
||||
this._rewarddialog5 = rewarddialog5
|
||||
}
|
||||
|
||||
set rewarddialog6(rewarddialog6) {
|
||||
this._rewarddialog6 = rewarddialog6
|
||||
}
|
||||
|
||||
set rewardShareKeyPairPublicKey(rewardShareKeyPairPublicKey) {
|
||||
this._rewardShareKeyPairPublicKey = Base58.decode(rewardShareKeyPairPublicKey)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
const _address = publicKeyToAddress(this._keyPair.publicKey)
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
this.fee = _address === recipient ? 0 : 0.001
|
||||
}
|
||||
|
||||
set percentageShare(share) {
|
||||
this._percentageShare = share * 100
|
||||
this._percentageShareBytes = this.constructor.utils.int64ToBytes(this._percentageShare)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._recipient,
|
||||
this._rewardShareKeyPairPublicKey,
|
||||
this._percentageShareBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
'use strict'
|
||||
import publicKeyToAddress from '../../wallet/publicKeyToAddress.js'
|
||||
import TransactionBase from "../TransactionBase.js"
|
||||
import nacl from '../../deps/nacl-fast.js'
|
||||
import ed2curve from '../../deps/ed2curve.js'
|
||||
import { Sha256 } from 'asmcrypto.js'
|
||||
|
||||
export default class RewardShareTransaction extends TransactionBase {
|
||||
constructor() {
|
||||
super()
|
||||
this.type = 38
|
||||
}
|
||||
|
||||
render(html) {
|
||||
return html`
|
||||
${this._rewarddialog1} <strong>${this._percentageShare / 1e8}%</strong> ${this._rewarddialog2} <strong>${this.constructor.Base58.encode(this._recipient)}</strong>?
|
||||
${this._rewarddialog3}
|
||||
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||
<span style="color: #000;">${this._base58RewardShareSeed}</span>
|
||||
</div>
|
||||
${this._rewarddialog4}
|
||||
`
|
||||
}
|
||||
|
||||
set rewarddialog1(rewarddialog1) {
|
||||
this._rewarddialog1 = rewarddialog1
|
||||
}
|
||||
|
||||
set rewarddialog2(rewarddialog2) {
|
||||
this._rewarddialog2 = rewarddialog2
|
||||
}
|
||||
|
||||
set rewarddialog3(rewarddialog3) {
|
||||
this._rewarddialog3 = rewarddialog3
|
||||
}
|
||||
|
||||
set rewarddialog4(rewarddialog4) {
|
||||
this._rewarddialog4 = rewarddialog4
|
||||
}
|
||||
|
||||
set recipientPublicKey(recipientPublicKey) {
|
||||
this._base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? this.constructor.Base58.encode(recipientPublicKey) : recipientPublicKey
|
||||
this._recipientPublicKey = this.constructor.Base58.decode(this._base58RecipientPublicKey)
|
||||
|
||||
this.recipient = publicKeyToAddress(this._recipientPublicKey)
|
||||
|
||||
this.fee = (recipientPublicKey === this.constructor.Base58.encode(this._keyPair.publicKey) ? 0 : 0.001)
|
||||
|
||||
const convertedPrivateKey = ed2curve.convertSecretKey(this._keyPair.privateKey)
|
||||
const convertedPublicKey = ed2curve.convertPublicKey(this._recipientPublicKey)
|
||||
const sharedSecret = new Uint8Array(32);
|
||||
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey);
|
||||
this._rewardShareSeed = new Sha256().process(sharedSecret).finish().result
|
||||
this._base58RewardShareSeed = this.constructor.Base58.encode(this._rewardShareSeed)
|
||||
|
||||
this._rewardShareKeyPair = nacl.sign.keyPair.fromSeed(this._rewardShareSeed)
|
||||
}
|
||||
|
||||
set recipient(recipient) {
|
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||
}
|
||||
|
||||
set percentageShare(share) {
|
||||
this._percentageShare = share * 100
|
||||
this._percentageShareBytes = this.constructor.utils.int64ToBytes(this._percentageShare)
|
||||
}
|
||||
|
||||
get params() {
|
||||
const params = super.params
|
||||
params.push(
|
||||
this._recipient,
|
||||
this._rewardShareKeyPair.publicKey,
|
||||
this._percentageShareBytes,
|
||||
this._feeBytes
|
||||
)
|
||||
return params
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* CrossChain - TradeBot Create Request (Sell Action)
|
||||
*
|
||||
* These are special types of transactions (JSON ENCODED)
|
||||
*/
|
||||
|
||||
export default class TradeBotCreateRequest {
|
||||
constructor() {
|
||||
// ...
|
||||
}
|
||||
|
||||
createTransaction(txnReq) {
|
||||
this.creatorPublicKey(txnReq.creatorPublicKey)
|
||||
this.qortAmount(txnReq.qortAmount)
|
||||
this.fundingQortAmount(txnReq.fundingQortAmount)
|
||||
this.foreignBlockchain(txnReq.foreignBlockchain)
|
||||
this.foreignAmount(txnReq.foreignAmount)
|
||||
this.tradeTimeout(txnReq.tradeTimeout)
|
||||
this.receivingAddress(txnReq.receivingAddress)
|
||||
|
||||
return this.txnRequest()
|
||||
}
|
||||
|
||||
creatorPublicKey(creatorPublicKey) {
|
||||
this._creatorPublicKey = creatorPublicKey
|
||||
}
|
||||
|
||||
qortAmount(qortAmount) {
|
||||
this._qortAmount = qortAmount
|
||||
}
|
||||
|
||||
fundingQortAmount(fundingQortAmount) {
|
||||
this._fundingQortAmount = fundingQortAmount
|
||||
}
|
||||
|
||||
foreignBlockchain(foreignBlockchain) {
|
||||
this._foreignBlockchain = foreignBlockchain
|
||||
}
|
||||
|
||||
foreignAmount(foreignAmount) {
|
||||
this._foreignAmount = foreignAmount
|
||||
}
|
||||
|
||||
tradeTimeout(tradeTimeout) {
|
||||
this._tradeTimeout = tradeTimeout
|
||||
}
|
||||
|
||||
receivingAddress(receivingAddress) {
|
||||
this._receivingAddress = receivingAddress
|
||||
}
|
||||
|
||||
txnRequest() {
|
||||
return {
|
||||
creatorPublicKey: this._creatorPublicKey,
|
||||
qortAmount: this._qortAmount,
|
||||
fundingQortAmount: this._fundingQortAmount,
|
||||
foreignBlockchain: this._foreignBlockchain,
|
||||
foreignAmount: this._foreignAmount,
|
||||
tradeTimeout: this._tradeTimeout,
|
||||
receivingAddress: this._receivingAddress
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* CrossChain - TradeBot Respond Request (Buy Action)
|
||||
*
|
||||
* These are special types of transactions (JSON ENCODED)
|
||||
*/
|
||||
|
||||
export default class TradeBotRespondRequest {
|
||||
constructor() {
|
||||
// ...
|
||||
}
|
||||
|
||||
createTransaction(txnReq) {
|
||||
this.atAddress(txnReq.atAddress)
|
||||
this.foreignKey(txnReq.foreignKey)
|
||||
this.receivingAddress(txnReq.receivingAddress)
|
||||
|
||||
return this.txnRequest()
|
||||
}
|
||||
|
||||
atAddress(atAddress) {
|
||||
this._atAddress = atAddress
|
||||
}
|
||||
|
||||
foreignKey(foreignKey) {
|
||||
this._foreignKey = foreignKey
|
||||
}
|
||||
|
||||
receivingAddress(receivingAddress) {
|
||||
this._receivingAddress = receivingAddress
|
||||
}
|
||||
|
||||
txnRequest() {
|
||||
return {
|
||||
atAddress: this._atAddress,
|
||||
foreignKey: this._foreignKey,
|
||||
receivingAddress: this._receivingAddress
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
import Base58 from '../../../deps/Base58.js'
|
||||
import nacl from '../../../deps/nacl-fast.js'
|
||||
import utils from '../../../deps/utils.js'
|
||||
|
||||
const signTradeBotTransaction = (unsignedTxn, keyPair) => {
|
||||
if (!unsignedTxn) {
|
||||
throw new Error('Unsigned Transaction Bytes not defined')
|
||||
}
|
||||
|
||||
if (!keyPair) {
|
||||
throw new Error('keyPair not defined')
|
||||
}
|
||||
|
||||
const txnBuffer = Base58.decode(unsignedTxn)
|
||||
|
||||
if (keyPair.privateKey.length === undefined) {
|
||||
const _privateKey = Object.keys(keyPair.privateKey).map(function (key) { return keyPair.privateKey[key]; })
|
||||
const privateKey = new Uint8Array(_privateKey)
|
||||
const signature = nacl.sign.detached(txnBuffer, privateKey)
|
||||
const signedBytes = utils.appendBuffer(txnBuffer, signature)
|
||||
|
||||
return signedBytes
|
||||
} else {
|
||||
const signature = nacl.sign.detached(txnBuffer, keyPair.privateKey)
|
||||
const signedBytes = utils.appendBuffer(txnBuffer, signature)
|
||||
|
||||
return signedBytes
|
||||
}
|
||||
}
|
||||
|
||||
export default signTradeBotTransaction
|
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* CrossChain - DELETE TradeOffer
|
||||
*
|
||||
* These are special types of transactions (JSON ENCODED)
|
||||
*/
|
||||
|
||||
export default class DeleteTradeOffer {
|
||||
constructor() {
|
||||
// ...
|
||||
}
|
||||
|
||||
createTransaction(txnReq) {
|
||||
this.creatorPublicKey(txnReq.creatorPublicKey)
|
||||
this.atAddress(txnReq.atAddress)
|
||||
|
||||
return this.txnRequest()
|
||||
}
|
||||
|
||||
creatorPublicKey(creatorPublicKey) {
|
||||
this._creatorPublicKey = creatorPublicKey
|
||||
}
|
||||
|
||||
atAddress(atAddress) {
|
||||
this._atAddress = atAddress
|
||||
}
|
||||
|
||||
txnRequest() {
|
||||
return {
|
||||
creatorPublicKey: this._creatorPublicKey,
|
||||
atAddress: this._atAddress
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { request } from '../../../fetch-request.js'
|
||||
import { deleteTradeOffer, signTradeBotTxn } from '../../../tradeRequest.js'
|
||||
import { processTransaction } from '../../../createTransaction.js'
|
||||
|
||||
export const cancelAllOffers = async (requestObject) => {
|
||||
const keyPair = requestObject.keyPair
|
||||
const publicKey = requestObject.base58PublicKey
|
||||
const address = requestObject.address
|
||||
|
||||
const getMyOpenOffers = async () => {
|
||||
const res = await request('/crosschain/tradeoffers')
|
||||
const myOpenTradeOrders = await res.filter(order => order.mode === "OFFERING" && order.qortalCreator === address)
|
||||
return myOpenTradeOrders
|
||||
}
|
||||
|
||||
const myOpenOffers = await getMyOpenOffers()
|
||||
let response = true
|
||||
|
||||
myOpenOffers.forEach(async (openOffer) => {
|
||||
let unsignedTxn = await deleteTradeOffer({ creatorPublicKey: publicKey, atAddress: openOffer.qortalAtAddress })
|
||||
let signedTxnBytes = await signTradeBotTxn(unsignedTxn, keyPair)
|
||||
await processTransaction(signedTxnBytes)
|
||||
})
|
||||
return response
|
||||
}
|
52
crypto/api/transactions/transactions.js
Normal file
52
crypto/api/transactions/transactions.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import PaymentTransaction from './PaymentTransaction.js'
|
||||
import RegisterNameTransaction from './names/RegisterNameTransaction.js'
|
||||
import UpdateNameTransaction from './names/UpdateNameTransaction.js'
|
||||
import SellNameTransacion from './names/SellNameTransacion.js'
|
||||
import CancelSellNameTransacion from './names/CancelSellNameTransacion.js'
|
||||
import BuyNameTransacion from './names/BuyNameTransacion.js'
|
||||
import MessageTransaction from './MessageTransaction.js'
|
||||
import ChatTransaction from './chat/ChatTransaction.js'
|
||||
import GroupChatTransaction from './chat/GroupChatTransaction.js'
|
||||
import PublicizeTransaction from './PublicizeTransaction.js'
|
||||
import CreateGroupTransaction from './groups/CreateGroupTransaction.js'
|
||||
import AddGroupAdminTransaction from './groups/AddGroupAdminTransaction.js'
|
||||
import RemoveGroupAdminTransaction from './groups/RemoveGroupAdminTransaction.js'
|
||||
import GroupBanTransaction from './groups/GroupBanTransaction.js'
|
||||
import CancelGroupBanTransaction from './groups/CancelGroupBanTransaction.js'
|
||||
import GroupKickTransaction from './groups/GroupKickTransaction.js'
|
||||
import GroupInviteTransaction from './groups/GroupInviteTransaction.js'
|
||||
import CancelGroupInviteTransaction from './groups/CancelGroupInviteTransaction.js'
|
||||
import JoinGroupTransaction from './groups/JoinGroupTransaction.js'
|
||||
import UpdateGroupTransaction from './groups/UpdateGroupTransaction.js'
|
||||
import LeaveGroupTransaction from './groups/LeaveGroupTransaction.js'
|
||||
import RewardShareTransaction from './reward-share/RewardShareTransaction.js'
|
||||
import RemoveRewardShareTransaction from './reward-share/RemoveRewardShareTransaction.js'
|
||||
import TransferPrivsTransaction from './TransferPrivsTransaction.js'
|
||||
import DeployAtTransaction from './DeployAtTransaction.js'
|
||||
|
||||
export const transactionTypes = {
|
||||
2: PaymentTransaction,
|
||||
3: RegisterNameTransaction,
|
||||
4: UpdateNameTransaction,
|
||||
5: SellNameTransacion,
|
||||
6: CancelSellNameTransacion,
|
||||
7: BuyNameTransacion,
|
||||
16: DeployAtTransaction,
|
||||
17: MessageTransaction,
|
||||
18: ChatTransaction,
|
||||
181: GroupChatTransaction,
|
||||
19: PublicizeTransaction,
|
||||
22: CreateGroupTransaction,
|
||||
24: AddGroupAdminTransaction,
|
||||
25: RemoveGroupAdminTransaction,
|
||||
26: GroupBanTransaction,
|
||||
27: CancelGroupBanTransaction,
|
||||
28: GroupKickTransaction,
|
||||
29: GroupInviteTransaction,
|
||||
30: CancelGroupInviteTransaction,
|
||||
31: JoinGroupTransaction,
|
||||
32: LeaveGroupTransaction,
|
||||
38: RewardShareTransaction,
|
||||
381: RemoveRewardShareTransaction,
|
||||
40: TransferPrivsTransaction
|
||||
}
|
11
crypto/api/utils/randomBase58Generator.js
Normal file
11
crypto/api/utils/randomBase58Generator.js
Normal file
@@ -0,0 +1,11 @@
|
||||
export const randomBase58Generator = (digits) => {
|
||||
digits = digits || 0
|
||||
let base58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split('')
|
||||
let result = ''
|
||||
let char
|
||||
while (result.length < digits) {
|
||||
char = base58[Math.random() * 57 >> 0]
|
||||
if (result.indexOf(char) === -1) result += char
|
||||
}
|
||||
return result
|
||||
}
|
31
crypto/api/utils/stateAwait.js
Normal file
31
crypto/api/utils/stateAwait.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { store } from '../../api.js'
|
||||
|
||||
let subscriptions = []
|
||||
|
||||
// Have to wait with init because something import stateAwait before the store gets initialized
|
||||
let initialized = false
|
||||
const init = () => {
|
||||
initialized = true
|
||||
store.subscribe(() => {
|
||||
const state = store.getState()
|
||||
|
||||
subscriptions = subscriptions.filter(fn => fn(state))
|
||||
})
|
||||
}
|
||||
|
||||
export const stateAwait = fn => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Check immediately...then if not true store it
|
||||
if (!initialized) {
|
||||
init()
|
||||
}
|
||||
if (fn(store.getState())) resolve()
|
||||
subscriptions.push(state => {
|
||||
if (fn(state)) {
|
||||
resolve()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
})
|
||||
}
|
8
crypto/api/wallet/base58PublicKeyToAddress.js
Normal file
8
crypto/api/wallet/base58PublicKeyToAddress.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import publicKeyToAddress from './publicKeyToAddress'
|
||||
import Base58 from '../deps/Base58.js'
|
||||
|
||||
export const base58PublicKeyToAddress = (base58pubkey, qora = false) => {
|
||||
const decodePubKey = Base58.decode(base58pubkey)
|
||||
const address = publicKeyToAddress(decodePubKey, qora)
|
||||
return address
|
||||
}
|
35
crypto/api/wallet/publicKeyToAddress.js
Normal file
35
crypto/api/wallet/publicKeyToAddress.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import Base58 from '../deps/Base58.js'
|
||||
import BROKEN_RIPEMD160 from '../deps/broken-ripemd160.js'
|
||||
import RIPEMD160 from '../deps/ripemd160.js'
|
||||
import utils from '../deps/utils.js'
|
||||
import { ADDRESS_VERSION } from '../constants.js'
|
||||
import { Buffer } from 'buffer'
|
||||
import { Sha256 } from 'asmcrypto.js'
|
||||
|
||||
const repeatSHA256 = (passphrase, hashes) => {
|
||||
let hash = passphrase
|
||||
for (let i = 0; i < hashes; i++) {
|
||||
hash = new Sha256().process(hash).finish().result
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
const publicKeyToAddress = (publicKey, qora = false) => {
|
||||
const publicKeySha256 = new Sha256().process(publicKey).finish().result
|
||||
const _publicKeyHash = qora ? new BROKEN_RIPEMD160().digest(publicKeySha256) : new RIPEMD160().update(Buffer.from(publicKeySha256)).digest('hex')
|
||||
const publicKeyHash = qora ? _publicKeyHash : _publicKeyHash
|
||||
|
||||
let address = new Uint8Array()
|
||||
|
||||
address = utils.appendBuffer(address, [ADDRESS_VERSION])
|
||||
address = utils.appendBuffer(address, publicKeyHash)
|
||||
|
||||
const checkSum = repeatSHA256(address, 2)
|
||||
address = utils.appendBuffer(address, checkSum.subarray(0, 4))
|
||||
|
||||
address = Base58.encode(address)
|
||||
|
||||
return address
|
||||
}
|
||||
|
||||
export default publicKeyToAddress
|
10
crypto/api/wallet/validateAddress.js
Normal file
10
crypto/api/wallet/validateAddress.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import Base58 from '../deps/Base58.js'
|
||||
|
||||
export const validateAddress = (address) => {
|
||||
const decodePubKey = Base58.decode(address)
|
||||
|
||||
if (!(decodePubKey instanceof Uint8Array && decodePubKey.length == 25)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
3
crypto/api_deps.js
Normal file
3
crypto/api_deps.js
Normal file
@@ -0,0 +1,3 @@
|
||||
let store
|
||||
export { store }
|
||||
export const initApi = (s) => { store = s }
|
37
crypto/config.js
Normal file
37
crypto/config.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { store } from './api.js'
|
||||
|
||||
let config = false
|
||||
let loaded = false
|
||||
const configWatchers = []
|
||||
const waitingForConfig = []
|
||||
|
||||
const subscribeToStore = () => {
|
||||
if (!store) return setTimeout(() => subscribeToStore(), 50)
|
||||
|
||||
store.subscribe(() => {
|
||||
const cA = store.getState().app
|
||||
const c = store.getState().config
|
||||
if (!c.loaded) return
|
||||
if (!loaded) waitingForConfig.forEach(r => r(cA))
|
||||
configWatchers.forEach(fn => fn(cA))
|
||||
config = cA
|
||||
})
|
||||
}
|
||||
|
||||
subscribeToStore()
|
||||
|
||||
export function getConfig() {
|
||||
return config
|
||||
}
|
||||
|
||||
export function watchConfig(fn) {
|
||||
fn(config)
|
||||
configWatchers.push(fn)
|
||||
}
|
||||
|
||||
export function waitForConfig() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (config) return resolve(config)
|
||||
waitingForConfig.push(resolve)
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user