UNPKG

9 kBJavaScriptView Raw
1/*
2 * ISC License (ISC)
3 * Copyright (c) 2018 aeternity developers
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18import { describe, it, before } from 'mocha'
19import { getSdk, BaseAe, networkId } from './'
20import { generateKeyPair } from '../../es/utils/crypto'
21import BigNumber from 'bignumber.js'
22import MemoryAccount from '../../es/account/memory'
23import { AE_AMOUNT_FORMATS } from '../../es/utils/amount-formatter'
24
25describe('Accounts', function () {
26 let wallet
27
28 before(async function () {
29 wallet = await getSdk()
30 })
31
32 const receiverKey = generateKeyPair()
33 const receiver = receiverKey.publicKey
34
35 describe('fails on unknown keypairs', () => {
36 let wallet
37
38 before(async function () {
39 wallet = await getSdk()
40 await wallet.addAccount(MemoryAccount({ keypair: generateKeyPair() }), { select: true })
41 })
42
43 it('determining the balance using deprecated `balance` method', async () => {
44 return wallet.balance(await wallet.address()).should.be.rejectedWith(Error)
45 })
46
47 it('determining the balance', async () => {
48 return wallet.getBalance(await wallet.address()).should.eventually.be.equal('0')
49 })
50
51 it('spending tokens', async () => {
52 return wallet.spend(1, receiver).should.be.rejectedWith(Error)
53 })
54
55 it('spending minus amount of tokens', async () => {
56 try {
57 await wallet.spend(-1, receiver)
58 } catch (e) {
59 e.message.should.be.equal('Transaction build error. {"amount":"-1 must be >= 0"}')
60 }
61 })
62 })
63
64 it('determines the balance using `balance`', async () => {
65 return wallet.balance(await wallet.address()).should.eventually.be.a('string')
66 })
67
68 describe('transferFunds', async () => {
69 const spend = async fraction => {
70 const balanceBefore = new BigNumber(await wallet.balance(await wallet.address()))
71 const { tx } = await wallet.transferFunds(fraction, receiver)
72 const balanceAfter = new BigNumber(await wallet.balance(await wallet.address()))
73 return {
74 balanceBefore,
75 balanceAfter,
76 amount: new BigNumber(tx.amount),
77 fee: new BigNumber(tx.fee)
78 }
79 }
80
81 it('throws exception if fraction is out of range', () => wallet.transferFunds(-1, receiver)
82 .should.be.rejectedWith(/Fraction should be a number between 0 and 1, got/))
83
84 it('spends 0% of balance', async () => {
85 const { balanceBefore, balanceAfter, amount } = await spend(0)
86 balanceBefore.should.be.not.eql(balanceAfter)
87 amount.isZero().should.be.equal(true)
88 })
89
90 it('spends 68.97% of balance', async () => {
91 const { balanceBefore, balanceAfter, amount, fee } = await spend(0.6897)
92 balanceBefore.times(0.6897).integerValue(BigNumber.ROUND_HALF_UP).should.be.eql(amount)
93 balanceAfter.plus(amount).plus(fee).should.be.eql(balanceBefore)
94 })
95
96 it('spends 100% of balance', async () => {
97 const { balanceBefore, balanceAfter, amount, fee } = await spend(1)
98 amount.plus(fee).should.be.eql(balanceBefore)
99 balanceAfter.isZero().should.be.equal(true)
100 })
101
102 it('accepts onAccount option', async () => {
103 await wallet.transferFunds(1, await wallet.address(), { onAccount: receiverKey })
104 new BigNumber(await wallet.balance(receiver)).isZero().should.be.equal(true)
105 })
106 })
107
108 it('spends tokens', async () => {
109 const ret = await wallet.spend(1, receiver)
110 ret.should.have.property('tx')
111 ret.tx.should.include({
112 amount: 1, recipientId: receiver
113 })
114 })
115
116 it('spends tokens in AE format', async () => {
117 const ret = await wallet.spend(1, receiver, { denomination: AE_AMOUNT_FORMATS.AE })
118 ret.should.have.property('tx')
119 ret.tx.should.include({
120 amount: `${1e18}`, recipientId: receiver
121 })
122 })
123
124 it('spends big amount of tokens', async () => {
125 const bigAmount = '10000000000000100000000000000000'
126 const genesis = await BaseAe({ networkId })
127 const receiverWallet = generateKeyPair()
128 const ret = await genesis.spend(bigAmount, receiverWallet.publicKey)
129
130 const balanceAfter = await wallet.balance(receiverWallet.publicKey)
131 balanceAfter.should.be.equal(bigAmount)
132 ret.should.have.property('tx')
133 ret.tx.should.include({
134 amount: bigAmount, recipientId: receiverWallet.publicKey
135 })
136 })
137
138 it('Get Account by block height/hash', async () => {
139 const h = await wallet.height()
140 await wallet.awaitHeight(h + 3)
141 const spend = await wallet.spend(123, 'ak_DMNCzsVoZnpV5fe8FTQnNsTfQ48YM5C3WbHPsJyHjAuTXebFi')
142 await wallet.awaitHeight(spend.blockHeight + 2)
143 const accountAfterSpend = await wallet.getAccount(await wallet.address())
144 const accountBeforeSpendByHash = await wallet.getAccount(await wallet.address(), { height: spend.blockHeight - 1 })
145 BigNumber(accountBeforeSpendByHash.balance)
146 .minus(BigNumber(accountAfterSpend.balance))
147 .toString()
148 .should.be
149 .equal(`${spend.tx.fee + spend.tx.amount}`)
150 })
151
152 describe('Make operation on specific account without changing of current account', () => {
153 it('Can make spend on specific account', async () => {
154 const current = await wallet.address()
155 const accounts = wallet.addresses()
156 const onAccount = accounts.find(acc => acc !== current)
157 // SPEND
158 const { tx } = await wallet.spend(1, await wallet.address(), { onAccount })
159 tx.senderId.should.be.equal(onAccount)
160 current.should.be.equal(current)
161 })
162
163 it('Fail on invalid account', async () => {
164 // SPEND
165 try {
166 await wallet.spend(1, await wallet.address(), { onAccount: 1 })
167 } catch (e) {
168 e.message.should.be.equal('Invalid `onAccount` option: should be keyPair object or account address')
169 }
170 })
171
172 it('Fail on non exist account', async () => {
173 // SPEND
174 try {
175 await wallet.spend(1, await wallet.address(), { onAccount: 'ak_q2HatMwDnwCBpdNtN9oXf5gpD9pGSgFxaa8i2Evcam6gjiggk' })
176 } catch (e) {
177 e.message.should.be.equal('Account for ak_q2HatMwDnwCBpdNtN9oXf5gpD9pGSgFxaa8i2Evcam6gjiggk not available')
178 }
179 })
180 it('Invalid on account options', async () => {
181 try {
182 await wallet.sign('tx_Aasdasd', { onAccount: 123 })
183 } catch (e) {
184 e.message.should.be.equal('Invalid `onAccount` option: should be keyPair object or account address')
185 }
186 })
187 it('Make operation on account using keyPair/MemoryAccount', async () => {
188 const keypair = generateKeyPair()
189 const memoryAccount = MemoryAccount({ keypair })
190 const data = 'Hello'
191 const signature = await memoryAccount.sign(data)
192 const sigUsingKeypair = await wallet.sign(data, { onAccount: keypair })
193 const sigUsingMemoryAccount = await wallet.sign(data, { onAccount: memoryAccount })
194 signature.toString('hex').should.be.equal(sigUsingKeypair.toString('hex'))
195 signature.toString('hex').should.be.equal(sigUsingMemoryAccount.toString('hex'))
196 // address
197 const addressFromKeypair = await wallet.address({ onAccount: keypair })
198 const addressFrommemoryAccount = await wallet.address({ onAccount: memoryAccount })
199 addressFromKeypair.should.be.equal(keypair.publicKey)
200 addressFrommemoryAccount.should.be.equal(keypair.publicKey)
201 })
202 it('Make operation on account using keyPair: Invalid keypair', async () => {
203 const keypair = generateKeyPair()
204 keypair.publicKey = 'ak_bev1aPMdAeJTuUiCJ7mHbdQiAizrkRGgoV9FfxHYb6pAxo5WY'
205 const data = 'Hello'
206 try {
207 await wallet.sign(data, { onAccount: keypair })
208 } catch (e) {
209 e.message.should.be.equal('Invalid \'onAccount\' option: Invalid Key Pair')
210 }
211 try {
212 await wallet.address({ onAccount: keypair })
213 } catch (e) {
214 e.message.should.be.equal('Invalid \'onAccount\' option: Invalid Key Pair')
215 }
216 })
217 })
218
219 describe('can be configured to return th', () => {
220 it('on creation', async () => {
221 const wallet = await getSdk()
222 const th = await wallet.spend(1, receiver)
223 th.should.be.a('object')
224 th.hash.slice(0, 3).should.equal('th_')
225 })
226
227 it('on call', async () => {
228 const th = await wallet.spend(1, receiver)
229 th.should.be.a('object')
230 th.hash.slice(0, 3).should.equal('th_')
231 })
232 })
233})