Fix and add validations to block signing etc
This commit is contained in:
parent
7928ad9cb1
commit
a6159a3325
8 changed files with 205 additions and 35 deletions
14
README.md
14
README.md
|
|
@ -73,9 +73,6 @@ const data = {
|
||||||
// Your current balance in RAW
|
// Your current balance in RAW
|
||||||
walletBalanceRaw: '18618869000000000000000000000000',
|
walletBalanceRaw: '18618869000000000000000000000000',
|
||||||
|
|
||||||
// From the pending transaction
|
|
||||||
fromAddress: 'nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx',
|
|
||||||
|
|
||||||
// Your address
|
// Your address
|
||||||
toAddress: 'nano_3kyb49tqpt39ekc49kbej51ecsjqnimnzw1swxz4boix4ctm93w517umuiw8',
|
toAddress: 'nano_3kyb49tqpt39ekc49kbej51ecsjqnimnzw1swxz4boix4ctm93w517umuiw8',
|
||||||
|
|
||||||
|
|
@ -85,10 +82,13 @@ const data = {
|
||||||
// From wallet info
|
// From wallet info
|
||||||
frontier: '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D',
|
frontier: '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D',
|
||||||
|
|
||||||
|
// From the pending transaction
|
||||||
|
transactionHash: 'CBC911F57B6827649423C92C88C0C56637A4274FF019E77E24D61D12B5338783',
|
||||||
|
|
||||||
// From the pending transaction in RAW
|
// From the pending transaction in RAW
|
||||||
amountRaw: '7000000000000000000000000000000',
|
amountRaw: '7000000000000000000000000000000',
|
||||||
|
|
||||||
// Generate the work server-side or a DPOW service
|
// Generate the work server-side or with a DPOW service
|
||||||
work: 'c5cf86de24b24419',
|
work: 'c5cf86de24b24419',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,7 +120,7 @@ const data = {
|
||||||
// The amount to send in RAW
|
// The amount to send in RAW
|
||||||
amountRaw: '2000000000000000000000000000000',
|
amountRaw: '2000000000000000000000000000000',
|
||||||
|
|
||||||
// Generate work on server-side or a DPOW service
|
// Generate work on server-side or with a DPOW service
|
||||||
work: 'fbffed7c73b61367',
|
work: 'fbffed7c73b61367',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,7 +146,7 @@ const data = {
|
||||||
// Previous block, from account info
|
// Previous block, from account info
|
||||||
frontier: '128106287002E595F479ACD615C818117FCB3860EC112670557A2467386249D4',
|
frontier: '128106287002E595F479ACD615C818117FCB3860EC112670557A2467386249D4',
|
||||||
|
|
||||||
// Generate work on the server side or a DPOW service
|
// Generate work on the server side or with a DPOW service
|
||||||
work: '0000000000000000',
|
work: '0000000000000000',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +168,7 @@ const converted = converter.convert('1000000000000000000000000000000', 'RAW', 'N
|
||||||
### In web
|
### In web
|
||||||
|
|
||||||
```
|
```
|
||||||
<script src="https://unpkg.com/nanocurrency-web@1.0.3" type="text/javascript"></script>
|
<script src="https://unpkg.com/nanocurrency-web@1.0.5" type="text/javascript"></script>
|
||||||
<scrypt type="text/javascript">
|
<scrypt type="text/javascript">
|
||||||
NanocurrencyWeb.wallet.generate(...);
|
NanocurrencyWeb.wallet.generate(...);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
38
index.ts
38
index.ts
|
|
@ -1,6 +1,6 @@
|
||||||
import AddressGenerator from './lib/address-generator'
|
import AddressGenerator from './lib/address-generator'
|
||||||
import AddressImporter, { Account, Wallet } from './lib/address-importer'
|
import AddressImporter, { Account, Wallet } from './lib/address-importer'
|
||||||
import BlockSigner, { TransactionBlock, RepresentativeBlock, SignedBlock } from './lib/block-signer'
|
import BlockSigner, { SendBlock, ReceiveBlock, RepresentativeBlock, SignedBlock } from './lib/block-signer'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import NanoConverter from './lib/nano-converter'
|
import NanoConverter from './lib/nano-converter'
|
||||||
|
|
||||||
|
|
@ -92,7 +92,8 @@ const block = {
|
||||||
/**
|
/**
|
||||||
* Sign a send block with the input parameters
|
* Sign a send block with the input parameters
|
||||||
*
|
*
|
||||||
* For a receive block, put your own address to the 'toAddress' property.
|
* For a send block, put your own address to the 'fromAddress' property and
|
||||||
|
* the recipient address to the 'toAddress' property.
|
||||||
* All the NANO amounts should be input in RAW format. The addresses should be
|
* All the NANO amounts should be input in RAW format. The addresses should be
|
||||||
* valid Nano addresses. Fetch the current balance, frontier (previous block) and
|
* valid Nano addresses. Fetch the current balance, frontier (previous block) and
|
||||||
* representative address from the blockchain and generate work for the signature.
|
* representative address from the blockchain and generate work for the signature.
|
||||||
|
|
@ -105,10 +106,33 @@ const block = {
|
||||||
* @param {SendBlock} data The data for the block
|
* @param {SendBlock} data The data for the block
|
||||||
* @param {string} privateKey Private key to sign the block
|
* @param {string} privateKey Private key to sign the block
|
||||||
*/
|
*/
|
||||||
sign: (data: TransactionBlock, privateKey: string): SignedBlock => {
|
send: (data: SendBlock, privateKey: string): SignedBlock => {
|
||||||
return blockSigner.sign(data, privateKey)
|
return blockSigner.send(data, privateKey)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a receive block with the input parameters
|
||||||
|
*
|
||||||
|
* For a receive block, put your own address to the 'toAddress' property.
|
||||||
|
* All the NANO amounts should be input in RAW format. The addresses should be
|
||||||
|
* valid Nano addresses. Fetch the current balance, frontier (previous block) and
|
||||||
|
* representative address from the blockchain and generate work for the signature.
|
||||||
|
* Input the receive amount and transaction hash from the pending block.
|
||||||
|
*
|
||||||
|
* The return value of this function is ready to be published to the blockchain.
|
||||||
|
*
|
||||||
|
* NOTICE: Always fetch up-to-date account info from the blockchain
|
||||||
|
* before signing the block
|
||||||
|
*
|
||||||
|
* @param {ReceiveBlock} data The data for the block
|
||||||
|
* @param {string} privateKey Private key to sign the block
|
||||||
|
*/
|
||||||
|
receive: (data: ReceiveBlock, privateKey: string): SignedBlock => {
|
||||||
|
return blockSigner.receive(data, privateKey)
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign a representative change block with the input parameters
|
* Sign a representative change block with the input parameters
|
||||||
*
|
*
|
||||||
|
|
@ -126,14 +150,14 @@ const block = {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
representative: (data: RepresentativeBlock, privateKey: string): SignedBlock => {
|
representative: (data: RepresentativeBlock, privateKey: string): SignedBlock => {
|
||||||
const block: TransactionBlock = {
|
const block: SendBlock = {
|
||||||
...data,
|
...data,
|
||||||
fromAddress: data.address,
|
fromAddress: data.address,
|
||||||
amountRaw: '0',
|
amountRaw: '0',
|
||||||
toAddress: 'nano_1111111111111111111111111111111111111111111111111111hifc8npp' // Burn address
|
toAddress: 'nano_1111111111111111111111111111111111111111111111111111hifc8npp', // Burn address
|
||||||
}
|
}
|
||||||
|
|
||||||
return blockSigner.sign(block, privateKey)
|
return blockSigner.send(block, privateKey)
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import Convert from './util/convert'
|
|
||||||
import Ed25519 from './ed25519'
|
import Ed25519 from './ed25519'
|
||||||
|
import Convert from './util/convert'
|
||||||
import NanoAddress from './nano-address'
|
import NanoAddress from './nano-address'
|
||||||
import NanoConverter from './nano-converter'
|
import NanoConverter from './nano-converter'
|
||||||
|
|
||||||
|
|
@ -14,22 +14,110 @@ export default class BlockSigner {
|
||||||
|
|
||||||
preamble = 0x6.toString().padStart(64, '0')
|
preamble = 0x6.toString().padStart(64, '0')
|
||||||
|
|
||||||
sign(data: TransactionBlock, privateKey: string): SignedBlock {
|
receive(data: ReceiveBlock, privateKey: string): SignedBlock {
|
||||||
|
const validateInputRaw = (input: string) => !!input && !isNaN(+input)
|
||||||
|
if (!validateInputRaw(data.walletBalanceRaw)) {
|
||||||
|
throw new Error('Invalid format in wallet balance')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateInputRaw(data.amountRaw)) {
|
||||||
|
throw new Error('Invalid format in send amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.nanoAddress.validateNanoAddress(data.toAddress)) {
|
||||||
|
throw new Error('Invalid toAddress')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.nanoAddress.validateNanoAddress(data.representativeAddress)) {
|
||||||
|
throw new Error('Invalid representativeAddress')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.transactionHash) {
|
||||||
|
throw new Error('No transaction hash')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.frontier) {
|
||||||
|
throw new Error('No frontier')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.work) {
|
||||||
|
throw new Error('No work')
|
||||||
|
}
|
||||||
|
|
||||||
if (!privateKey) {
|
if (!privateKey) {
|
||||||
throw new Error('Please input the private key to sign the block')
|
throw new Error('Please input the private key to sign the block')
|
||||||
}
|
}
|
||||||
|
|
||||||
const balance = NanoConverter.convert(data.walletBalanceRaw, 'RAW', 'NANO')
|
const balanceNano = NanoConverter.convert(data.walletBalanceRaw, 'RAW', 'NANO')
|
||||||
const amount = NanoConverter.convert(data.amountRaw, 'RAW', 'NANO')
|
const amountNano = NanoConverter.convert(data.amountRaw, 'RAW', 'NANO')
|
||||||
const newBalance = new BigNumber(balance).minus(new BigNumber(amount))
|
const newBalanceNano = new BigNumber(balanceNano).plus(new BigNumber(amountNano))
|
||||||
const rawBalance = NanoConverter.convert(newBalance, 'NANO', 'RAW')
|
const newBalanceRaw = NanoConverter.convert(newBalanceNano, 'NANO', 'RAW')
|
||||||
const hexBalance = Convert.dec2hex(rawBalance, 16).toUpperCase()
|
const newBalanceHex = Convert.dec2hex(newBalanceRaw, 16).toUpperCase()
|
||||||
|
const account = this.nanoAddressToHexString(data.toAddress)
|
||||||
|
const link = data.transactionHash
|
||||||
|
const representative = this.nanoAddressToHexString(data.representativeAddress)
|
||||||
|
|
||||||
|
const signatureBytes = this.ed25519.sign(
|
||||||
|
this.generateHash(this.preamble, account, data.frontier, representative, newBalanceHex, link),
|
||||||
|
Convert.hex2ab(privateKey))
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'state',
|
||||||
|
account: data.toAddress,
|
||||||
|
previous: data.frontier,
|
||||||
|
representative: data.representativeAddress,
|
||||||
|
balance: newBalanceRaw,
|
||||||
|
link: link,
|
||||||
|
signature: Convert.ab2hex(signatureBytes),
|
||||||
|
work: data.work,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send(data: SendBlock, privateKey: string): SignedBlock {
|
||||||
|
const validateInputRaw = (input: string) => !!input && !isNaN(+input)
|
||||||
|
if (!validateInputRaw(data.walletBalanceRaw)) {
|
||||||
|
throw new Error('Invalid format in wallet balance')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateInputRaw(data.amountRaw)) {
|
||||||
|
throw new Error('Invalid format in send amount')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.nanoAddress.validateNanoAddress(data.toAddress)) {
|
||||||
|
throw new Error('Invalid toAddress')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.nanoAddress.validateNanoAddress(data.fromAddress)) {
|
||||||
|
throw new Error('Invalid fromAddress')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.nanoAddress.validateNanoAddress(data.representativeAddress)) {
|
||||||
|
throw new Error('Invalid representativeAddress')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.frontier) {
|
||||||
|
throw new Error('No frontier')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.work) {
|
||||||
|
throw new Error('No work')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!privateKey) {
|
||||||
|
throw new Error('Please input the private key to sign the block')
|
||||||
|
}
|
||||||
|
|
||||||
|
const balanceNano = NanoConverter.convert(data.walletBalanceRaw, 'RAW', 'NANO')
|
||||||
|
const amountNano = NanoConverter.convert(data.amountRaw, 'RAW', 'NANO')
|
||||||
|
const newBalanceNano = new BigNumber(balanceNano).minus(new BigNumber(amountNano))
|
||||||
|
const newBalanceRaw = NanoConverter.convert(newBalanceNano, 'NANO', 'RAW')
|
||||||
|
const newBalanceHex = Convert.dec2hex(newBalanceRaw, 16).toUpperCase()
|
||||||
const account = this.nanoAddressToHexString(data.fromAddress)
|
const account = this.nanoAddressToHexString(data.fromAddress)
|
||||||
const link = this.nanoAddressToHexString(data.toAddress)
|
const link = this.nanoAddressToHexString(data.toAddress)
|
||||||
const representative = this.nanoAddressToHexString(data.representativeAddress)
|
const representative = this.nanoAddressToHexString(data.representativeAddress)
|
||||||
|
|
||||||
const signatureBytes = this.ed25519.sign(
|
const signatureBytes = this.ed25519.sign(
|
||||||
this.generateHash(this.preamble, account, data.frontier, representative, hexBalance, link),
|
this.generateHash(this.preamble, account, data.frontier, representative, newBalanceHex, link),
|
||||||
Convert.hex2ab(privateKey))
|
Convert.hex2ab(privateKey))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -37,8 +125,8 @@ export default class BlockSigner {
|
||||||
account: data.fromAddress,
|
account: data.fromAddress,
|
||||||
previous: data.frontier,
|
previous: data.frontier,
|
||||||
representative: data.representativeAddress,
|
representative: data.representativeAddress,
|
||||||
balance: rawBalance,
|
balance: newBalanceRaw,
|
||||||
link,
|
link: link,
|
||||||
signature: Convert.ab2hex(signatureBytes),
|
signature: Convert.ab2hex(signatureBytes),
|
||||||
work: data.work,
|
work: data.work,
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +162,17 @@ export default class BlockSigner {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransactionBlock {
|
export interface ReceiveBlock {
|
||||||
|
walletBalanceRaw: string
|
||||||
|
toAddress: string
|
||||||
|
transactionHash: string
|
||||||
|
frontier: string
|
||||||
|
representativeAddress: string
|
||||||
|
amountRaw: string
|
||||||
|
work: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SendBlock {
|
||||||
walletBalanceRaw: string
|
walletBalanceRaw: string
|
||||||
fromAddress: string
|
fromAddress: string
|
||||||
toAddress: string
|
toAddress: string
|
||||||
|
|
|
||||||
|
|
@ -74,11 +74,59 @@ export default class NanoAddress {
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a Nano address with 'nano' and 'xrb' prefixes
|
||||||
|
*
|
||||||
|
* Derived from https://github.com/alecrios/nano-address-validator
|
||||||
|
*
|
||||||
|
* @param {string} address Nano address
|
||||||
|
*/
|
||||||
|
validateNanoAddress = (address: string): boolean => {
|
||||||
|
/** Ensure the address is provided */
|
||||||
|
if (address === undefined) {
|
||||||
|
throw Error('Address must be defined.')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ensure the address is a string */
|
||||||
|
if (typeof address !== 'string') {
|
||||||
|
throw TypeError('Address must be a string.')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The array of allowed prefixes */
|
||||||
|
const allowedPrefixes: string[] = ['nano', 'xrb']
|
||||||
|
|
||||||
|
/** The regex pattern for validating the address */
|
||||||
|
const pattern = new RegExp(
|
||||||
|
`^(${allowedPrefixes.join('|')})_[13]{1}[13456789abcdefghijkmnopqrstuwxyz]{59}$`,
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Validate the syntax of the address */
|
||||||
|
if (!pattern.test(address)) return false
|
||||||
|
|
||||||
|
/** The expected checksum as a base32-encoded string */
|
||||||
|
const expectedChecksum = address.slice(-8)
|
||||||
|
|
||||||
|
/** The public key as a base32-encoded string */
|
||||||
|
const publicKey = address.slice(address.indexOf('_') + 1, -8)
|
||||||
|
|
||||||
|
/** The public key as an array buffer */
|
||||||
|
const publicKeyBuffer = this.decodeNanoBase32(publicKey)
|
||||||
|
|
||||||
|
/** The actual checksum as an array buffer */
|
||||||
|
const actualChecksumBuffer = blake2b(publicKeyBuffer, null, 5).reverse()
|
||||||
|
|
||||||
|
/** The actual checksum as a base32-encoded string */
|
||||||
|
const actualChecksum = this.encodeNanoBase32(actualChecksumBuffer)
|
||||||
|
|
||||||
|
/** Validate the provided checksum against the derived checksum */
|
||||||
|
return expectedChecksum === actualChecksum
|
||||||
|
}
|
||||||
|
|
||||||
readChar(char: string): number {
|
readChar(char: string): number {
|
||||||
const idx = this.alphabet.indexOf(char)
|
const idx = this.alphabet.indexOf(char)
|
||||||
|
|
||||||
if (idx === -1) {
|
if (idx === -1) {
|
||||||
throw `Invalid character found: ${char}`
|
throw new Error(`Invalid character found: ${char}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return idx
|
return idx
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export default class NanoConverter {
|
||||||
value = value.shiftedBy(24)
|
value = value.shiftedBy(24)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
throw `Unkown input unit ${inputUnit}, expected one of the following: RAW, NANO, MRAI, KRAI, RAI`
|
throw new Error(`Unkown input unit ${inputUnit}, expected one of the following: RAW, NANO, MRAI, KRAI, RAI`)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (outputUnit) {
|
switch (outputUnit) {
|
||||||
|
|
@ -41,7 +41,7 @@ export default class NanoConverter {
|
||||||
case 'RAI':
|
case 'RAI':
|
||||||
return value.shiftedBy(-24).toFixed(9, 1)
|
return value.shiftedBy(-24).toFixed(9, 1)
|
||||||
default:
|
default:
|
||||||
throw `Unknown output unit ${outputUnit}, expected one of the following: RAW, NANO, MRAI, KRAI, RAI`
|
throw new Error(`Unknown output unit ${outputUnit}, expected one of the following: RAW, NANO, MRAI, KRAI, RAI`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nanocurrency-web",
|
"name": "nanocurrency-web",
|
||||||
"version": "1.0.1",
|
"version": "1.0.5",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nanocurrency-web",
|
"name": "nanocurrency-web",
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"description": "Toolkit for Nano cryptocurrency client side offline integrations",
|
"description": "Toolkit for Nano cryptocurrency client side offline integrations",
|
||||||
"author": "Miro Metsänheimo <miro@metsanheimo.fi>",
|
"author": "Miro Metsänheimo <miro@metsanheimo.fi>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
||||||
10
test/test.js
10
test/test.js
|
|
@ -117,20 +117,20 @@ describe('derive more accounts from the same seed test', () => {
|
||||||
describe('block signing tests using official test vectors', () => {
|
describe('block signing tests using official test vectors', () => {
|
||||||
|
|
||||||
it('should create a valid signature for a receive block', () => {
|
it('should create a valid signature for a receive block', () => {
|
||||||
const result = block.sign({
|
const result = block.receive({
|
||||||
walletBalanceRaw: '18618869000000000000000000000000',
|
walletBalanceRaw: '18618869000000000000000000000000',
|
||||||
fromAddress: 'nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx',
|
transactionHash: 'CBC911F57B6827649423C92C88C0C56637A4274FF019E77E24D61D12B5338783',
|
||||||
toAddress: 'nano_3kyb49tqpt39ekc49kbej51ecsjqnimnzw1swxz4boix4ctm93w517umuiw8',
|
toAddress: 'nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx',
|
||||||
representativeAddress: 'nano_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou',
|
representativeAddress: 'nano_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou',
|
||||||
frontier: '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D',
|
frontier: '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D',
|
||||||
amountRaw: '7000000000000000000000000000000',
|
amountRaw: '7000000000000000000000000000000',
|
||||||
work: 'c5cf86de24b24419',
|
work: 'c5cf86de24b24419',
|
||||||
}, '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3')
|
}, '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3')
|
||||||
expect(result.signature.toUpperCase()).to.equal('EEFFE1EFCCC8F2F6F2F1B79B80ABE855939DD9D6341323186494ADEE775DAADB3B6A6A07A85511F2185F6E739C4A54F1454436E22255A542ED879FD04FEED001')
|
expect(result.signature.toUpperCase()).to.equal('F25D751AD0379A5718E08F3773DA6061A9E18842EF5615163C7F207B804CC2C5DD2720CFCE5FE6A78E4CC108DD9CAB65051526403FA2C24A1ED943BB4EA7880B')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should create a valid signature for a send block', () => {
|
it('should create a valid signature for a send block', () => {
|
||||||
const result = block.sign({
|
const result = block.send({
|
||||||
walletBalanceRaw: '5618869000000000000000000000000',
|
walletBalanceRaw: '5618869000000000000000000000000',
|
||||||
fromAddress: 'nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx',
|
fromAddress: 'nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx',
|
||||||
toAddress: 'nano_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p',
|
toAddress: 'nano_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue