hive-stream 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +35 -0
- package/DOCUMENTATION.md +380 -0
- package/README.md +113 -22
- package/dist/actions.d.ts +3 -3
- package/dist/actions.js +7 -7
- package/dist/actions.js.map +1 -1
- package/dist/adapters/base.adapter.d.ts +19 -1
- package/dist/adapters/base.adapter.js +16 -0
- package/dist/adapters/base.adapter.js.map +1 -1
- package/dist/adapters/mongodb.adapter.d.ts +5 -11
- package/dist/adapters/mongodb.adapter.js +10 -10
- package/dist/adapters/mongodb.adapter.js.map +1 -1
- package/dist/adapters/postgresql.adapter.d.ts +17 -0
- package/dist/adapters/postgresql.adapter.js +99 -8
- package/dist/adapters/postgresql.adapter.js.map +1 -1
- package/dist/adapters/sqlite.adapter.d.ts +17 -0
- package/dist/adapters/sqlite.adapter.js +99 -8
- package/dist/adapters/sqlite.adapter.js.map +1 -1
- package/dist/api.js +86 -0
- package/dist/api.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.js +6 -3
- package/dist/config.js.map +1 -1
- package/dist/contracts/coinflip.contract.d.ts +8 -26
- package/dist/contracts/coinflip.contract.js +123 -144
- package/dist/contracts/coinflip.contract.js.map +1 -1
- package/dist/contracts/contract.d.ts +3 -0
- package/dist/contracts/contract.js +26 -0
- package/dist/contracts/contract.js.map +1 -0
- package/dist/contracts/dice.contract.d.ts +9 -36
- package/dist/contracts/dice.contract.js +135 -200
- package/dist/contracts/dice.contract.js.map +1 -1
- package/dist/contracts/exchange.contract.d.ts +11 -0
- package/dist/contracts/exchange.contract.js +492 -0
- package/dist/contracts/exchange.contract.js.map +1 -0
- package/dist/contracts/lotto.contract.d.ts +15 -19
- package/dist/contracts/lotto.contract.js +154 -162
- package/dist/contracts/lotto.contract.js.map +1 -1
- package/dist/contracts/nft.contract.d.ts +4 -0
- package/dist/contracts/nft.contract.js +65 -0
- package/dist/contracts/nft.contract.js.map +1 -1
- package/dist/contracts/poll.contract.d.ts +4 -0
- package/dist/contracts/poll.contract.js +105 -0
- package/dist/contracts/poll.contract.js.map +1 -0
- package/dist/contracts/rps.contract.d.ts +9 -0
- package/dist/contracts/rps.contract.js +217 -0
- package/dist/contracts/rps.contract.js.map +1 -0
- package/dist/contracts/tipjar.contract.d.ts +4 -0
- package/dist/contracts/tipjar.contract.js +60 -0
- package/dist/contracts/tipjar.contract.js.map +1 -0
- package/dist/contracts/token.contract.d.ts +3 -17
- package/dist/contracts/token.contract.js +128 -80
- package/dist/contracts/token.contract.js.map +1 -1
- package/dist/exchanges/coingecko.d.ts +7 -1
- package/dist/exchanges/coingecko.js +38 -21
- package/dist/exchanges/coingecko.js.map +1 -1
- package/dist/exchanges/exchange.d.ts +15 -8
- package/dist/exchanges/exchange.js +65 -11
- package/dist/exchanges/exchange.js.map +1 -1
- package/dist/hive-rates.d.ts +29 -4
- package/dist/hive-rates.js +179 -92
- package/dist/hive-rates.js.map +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.js +18 -4
- package/dist/index.js.map +1 -1
- package/dist/streamer.d.ts +101 -8
- package/dist/streamer.js +410 -140
- package/dist/streamer.js.map +1 -1
- package/dist/test.js +11 -12
- package/dist/test.js.map +1 -1
- package/dist/types/hive-stream.d.ts +85 -14
- package/dist/types/rates.d.ts +47 -0
- package/dist/types/rates.js +29 -0
- package/dist/types/rates.js.map +1 -0
- package/dist/utils.d.ts +318 -11
- package/dist/utils.js +804 -115
- package/dist/utils.js.map +1 -1
- package/examples/contracts/README.md +8 -0
- package/examples/contracts/exchange.ts +38 -0
- package/examples/contracts/poll.ts +21 -0
- package/examples/contracts/rps.ts +19 -0
- package/examples/contracts/tipjar.ts +19 -0
- package/package.json +20 -19
- package/tests/actions.spec.ts +7 -7
- package/tests/adapters/actions-persistence.spec.ts +4 -4
- package/tests/adapters/sqlite.adapter.spec.ts +2 -2
- package/tests/contracts/coinflip.contract.spec.ts +26 -154
- package/tests/contracts/dice.contract.spec.ts +24 -140
- package/tests/contracts/exchange.contract.spec.ts +84 -0
- package/tests/contracts/lotto.contract.spec.ts +30 -295
- package/tests/contracts/token.contract.spec.ts +72 -316
- package/tests/exchanges/coingecko.exchange.spec.ts +169 -0
- package/tests/exchanges/exchange.base.spec.ts +246 -0
- package/tests/helpers/mock-fetch.ts +165 -0
- package/tests/hive-chain-features.spec.ts +238 -0
- package/tests/hive-rates.spec.ts +443 -0
- package/tests/integration/hive-rates.integration.spec.ts +35 -0
- package/tests/streamer-actions.spec.ts +29 -18
- package/tests/streamer.spec.ts +142 -49
- package/tests/types/rates.spec.ts +216 -0
- package/tests/utils.spec.ts +27 -6
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { sleep } from '@hiveio/dhive/lib/utils';
|
|
2
|
-
import {
|
|
2
|
+
import { createDiceContract } from './../../src/contracts/dice.contract';
|
|
3
3
|
import { Streamer } from '../../src/streamer';
|
|
4
4
|
import { createMockAdapter } from '../helpers/mock-adapter';
|
|
5
|
-
import BigNumber from 'bignumber.js';
|
|
6
5
|
|
|
7
6
|
describe('Dice Contract', () => {
|
|
8
7
|
let sut: Streamer;
|
|
9
|
-
let contract:
|
|
8
|
+
let contract: ReturnType<typeof createDiceContract>;
|
|
10
9
|
|
|
11
10
|
beforeEach(async () => {
|
|
12
11
|
sut = new Streamer();
|
|
13
12
|
await sut.registerAdapter(createMockAdapter());
|
|
14
|
-
|
|
15
|
-
contract =
|
|
13
|
+
|
|
14
|
+
contract = createDiceContract({ name: 'testdice' });
|
|
16
15
|
|
|
17
16
|
// @ts-ignore
|
|
18
17
|
sut.api = jest.fn();
|
|
@@ -26,8 +25,8 @@ describe('Dice Contract', () => {
|
|
|
26
25
|
jest.restoreAllMocks();
|
|
27
26
|
});
|
|
28
27
|
|
|
29
|
-
test('Registers the dice contract', () => {
|
|
30
|
-
sut.registerContract(
|
|
28
|
+
test('Registers the dice contract', async () => {
|
|
29
|
+
await sut.registerContract(contract);
|
|
31
30
|
|
|
32
31
|
const findContract = sut['contracts'].find(c => c.name === 'testdice');
|
|
33
32
|
|
|
@@ -35,21 +34,16 @@ describe('Dice Contract', () => {
|
|
|
35
34
|
});
|
|
36
35
|
|
|
37
36
|
test('User wins a roll', async () => {
|
|
38
|
-
sut.registerContract(
|
|
39
|
-
|
|
40
|
-
contract['_instance'] = sut;
|
|
37
|
+
await sut.registerContract(contract);
|
|
41
38
|
|
|
42
|
-
jest.spyOn(
|
|
43
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
44
|
-
|
|
45
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
39
|
+
jest.spyOn(sut, 'getTransaction').mockResolvedValue({ test: 123 } as any);
|
|
46
40
|
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
47
41
|
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
42
|
+
jest.spyOn(sut['client'].database, 'getAccounts').mockResolvedValue([{ balance: '2000.000 HIVE' }] as any);
|
|
48
43
|
|
|
49
44
|
const memo = JSON.stringify({
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
name: 'testdice',
|
|
45
|
+
hive_stream: {
|
|
46
|
+
contract: 'testdice',
|
|
53
47
|
action: 'roll',
|
|
54
48
|
payload: {
|
|
55
49
|
roll: 69
|
|
@@ -57,147 +51,37 @@ describe('Dice Contract', () => {
|
|
|
57
51
|
}
|
|
58
52
|
});
|
|
59
53
|
|
|
60
|
-
sut.processOperation(['transfer', { from: 'testuser', amount: '9.000 HIVE', memo }], 778782, 'dfjfsdfsdfsd34hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
54
|
+
await sut.processOperation(['transfer', { from: 'testuser', amount: '9.000 HIVE', memo }], 778782, 'dfjfsdfsdfsd34hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
61
55
|
|
|
62
56
|
await sleep(100);
|
|
63
57
|
|
|
64
|
-
expect(
|
|
65
|
-
expect(
|
|
66
|
-
expect(contract['_instance'].transferHiveTokens).toBeCalledWith('beggars', 'testuser', '12.391', 'HIVE', 'You won 12.391 HIVE. Roll: 54, Your guess: 69');
|
|
58
|
+
expect(sut.getTransaction).toHaveBeenCalledWith(778782, 'fhkjsdhfkjsdf');
|
|
59
|
+
expect(sut.transferHiveTokens).toHaveBeenCalledWith('beggars', 'testuser', '12.391', 'HIVE', 'You won 12.391 HIVE. Roll: 54, Your guess: 69');
|
|
67
60
|
});
|
|
68
61
|
|
|
69
62
|
test('User loses a roll', async () => {
|
|
70
|
-
sut.registerContract(
|
|
71
|
-
|
|
72
|
-
contract['_instance'] = sut;
|
|
63
|
+
await sut.registerContract(contract);
|
|
73
64
|
|
|
74
|
-
jest.spyOn(
|
|
75
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
76
|
-
|
|
77
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
65
|
+
jest.spyOn(sut, 'getTransaction').mockResolvedValue({ test: 123 } as any);
|
|
78
66
|
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
79
67
|
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
68
|
+
jest.spyOn(sut['client'].database, 'getAccounts').mockResolvedValue([{ balance: '2000.000 HIVE' }] as any);
|
|
80
69
|
|
|
81
70
|
const memo = JSON.stringify({
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
name: 'testdice',
|
|
71
|
+
hive_stream: {
|
|
72
|
+
contract: 'testdice',
|
|
85
73
|
action: 'roll',
|
|
86
74
|
payload: {
|
|
87
|
-
roll:
|
|
75
|
+
roll: 10
|
|
88
76
|
}
|
|
89
77
|
}
|
|
90
78
|
});
|
|
91
79
|
|
|
92
|
-
sut.processOperation(['transfer', { from: 'testuser', amount: '9.000 HIVE', memo }], 778782, '
|
|
80
|
+
await sut.processOperation(['transfer', { from: 'testuser', amount: '9.000 HIVE', memo }], 778782, 'dfjfsdfsdfsd34hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
93
81
|
|
|
94
82
|
await sleep(100);
|
|
95
83
|
|
|
96
|
-
expect(
|
|
97
|
-
expect(sut.
|
|
98
|
-
expect(sut.transferHiveTokens).toBeCalledWith('beggars', 'testuser', '0.001', 'HIVE', 'You lost 9.000 HIVE. Roll: 81, Your guess: 69');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
test('User sent an invalid amount, refund them', async () => {
|
|
102
|
-
sut.registerContract('testdice', contract);
|
|
103
|
-
|
|
104
|
-
contract['_instance'] = sut;
|
|
105
|
-
|
|
106
|
-
jest.spyOn(contract as any, 'roll');
|
|
107
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
108
|
-
|
|
109
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
110
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
111
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
112
|
-
|
|
113
|
-
const memo = JSON.stringify({
|
|
114
|
-
hivePayload: {
|
|
115
|
-
id: 'hivestream',
|
|
116
|
-
name: 'testdice',
|
|
117
|
-
action: 'roll',
|
|
118
|
-
payload: {
|
|
119
|
-
roll: 69
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
sut.processOperation(['transfer', { from: 'testuser', amount: '100.000 HIVE', memo }], 778782, 'dfjfsdfsdfs4hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
125
|
-
|
|
126
|
-
await sleep(100);
|
|
127
|
-
|
|
128
|
-
expect(contract['roll']).toBeCalled();
|
|
129
|
-
expect(sut.getTransaction).toBeCalledWith(778782, 'fhkjsdhfkjsdf');
|
|
130
|
-
expect(sut.transferHiveTokens).toBeCalledWith('beggars', 'testuser', '100.000', 'HIVE', '[Refund] You sent an invalid bet amount.');
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test('User sent an unsupported currency, refund them', async () => {
|
|
134
|
-
sut.registerContract('testdice', contract);
|
|
135
|
-
|
|
136
|
-
contract['_instance'] = sut;
|
|
137
|
-
|
|
138
|
-
jest.spyOn(contract as any, 'roll');
|
|
139
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
140
|
-
|
|
141
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
142
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
143
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
144
|
-
|
|
145
|
-
const memo = JSON.stringify({
|
|
146
|
-
hivePayload: {
|
|
147
|
-
id: 'hivestream',
|
|
148
|
-
name: 'testdice',
|
|
149
|
-
action: 'roll',
|
|
150
|
-
payload: {
|
|
151
|
-
roll: 69
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
sut.processOperation(['transfer', { from: 'testuser', amount: '10.000 HBD', memo }], 778782, 'dfjfsdfsdfs4hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
157
|
-
|
|
158
|
-
await sleep(100);
|
|
159
|
-
|
|
160
|
-
expect(contract['roll']).toBeCalled();
|
|
161
|
-
expect(sut.getTransaction).toBeCalledWith(778782, 'fhkjsdhfkjsdf');
|
|
162
|
-
expect(sut.transferHiveTokens).toBeCalledWith('beggars', 'testuser', '10.000', 'HBD', '[Refund] Invalid bet params.');
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
test('Queue processes multiple concurrent rolls', async () => {
|
|
166
|
-
sut.registerContract('testdice', contract);
|
|
167
|
-
|
|
168
|
-
contract['_instance'] = sut;
|
|
169
|
-
|
|
170
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
171
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
172
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
173
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
174
|
-
|
|
175
|
-
const memo1 = JSON.stringify({
|
|
176
|
-
hivePayload: {
|
|
177
|
-
id: 'hivestream',
|
|
178
|
-
name: 'testdice',
|
|
179
|
-
action: 'roll',
|
|
180
|
-
payload: { roll: 50 }
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
const memo2 = JSON.stringify({
|
|
185
|
-
hivePayload: {
|
|
186
|
-
id: 'hivestream',
|
|
187
|
-
name: 'testdice',
|
|
188
|
-
action: 'roll',
|
|
189
|
-
payload: { roll: 75 }
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// Process multiple bets concurrently
|
|
194
|
-
const bet1Promise = sut.processOperation(['transfer', { from: 'user1', amount: '5.000 HIVE', memo: memo1 }], 778782, 'block1', 'prevblock1', 'trx1', '2019-06-23' as any);
|
|
195
|
-
const bet2Promise = sut.processOperation(['transfer', { from: 'user2', amount: '5.000 HIVE', memo: memo2 }], 778783, 'block2', 'prevblock2', 'trx2', '2019-06-23' as any);
|
|
196
|
-
|
|
197
|
-
await Promise.all([bet1Promise, bet2Promise]);
|
|
198
|
-
await sleep(200); // Allow queue processing to complete
|
|
199
|
-
|
|
200
|
-
// Both transfers should have been processed
|
|
201
|
-
expect(sut.transferHiveTokens).toHaveBeenCalledTimes(2);
|
|
84
|
+
expect(sut.getTransaction).toHaveBeenCalledWith(778782, 'fhkjsdhfkjsdf');
|
|
85
|
+
expect(sut.transferHiveTokens).toHaveBeenCalledWith('beggars', 'testuser', '0.001', 'HIVE', 'You lost 9.000 HIVE. Roll: 54, Your guess: 10');
|
|
202
86
|
});
|
|
203
|
-
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Streamer } from '../../src/streamer';
|
|
2
|
+
import { SqliteAdapter } from '../../src/adapters/sqlite.adapter';
|
|
3
|
+
import { createExchangeContract } from '../../src/contracts/exchange.contract';
|
|
4
|
+
|
|
5
|
+
describe('Exchange Contract', () => {
|
|
6
|
+
let streamer: Streamer;
|
|
7
|
+
let adapter: SqliteAdapter;
|
|
8
|
+
let contract: ReturnType<typeof createExchangeContract>;
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
streamer = new Streamer({
|
|
12
|
+
JSON_ID: 'hivestream',
|
|
13
|
+
PAYLOAD_IDENTIFIER: 'hive_stream'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
adapter = new SqliteAdapter(':memory:');
|
|
17
|
+
await streamer.registerAdapter(adapter);
|
|
18
|
+
|
|
19
|
+
contract = createExchangeContract({ name: 'exchange' });
|
|
20
|
+
await streamer.registerContract(contract);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(async () => {
|
|
24
|
+
await streamer.stop();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const baseContext = (trigger: 'custom_json' | 'transfer' | 'time', sender: string) => ({
|
|
28
|
+
trigger,
|
|
29
|
+
streamer,
|
|
30
|
+
adapter,
|
|
31
|
+
config: streamer['config'],
|
|
32
|
+
block: { number: 100, id: 'block', previousId: 'prev', time: new Date() },
|
|
33
|
+
transaction: { id: `trx-${trigger}-${sender}` },
|
|
34
|
+
sender,
|
|
35
|
+
customJson: trigger === 'custom_json' ? { id: 'hivestream', json: {}, isSignedWithActiveKey: true } : undefined,
|
|
36
|
+
transfer: trigger === 'transfer' ? { from: sender, to: 'exchange', rawAmount: '', amount: '', asset: '', memo: '' } : undefined
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('Deposits, places orders, and matches', async () => {
|
|
40
|
+
await contract.actions.createPair.handler({ base: 'HIVE', quote: 'HBD' }, baseContext('custom_json', 'alice'));
|
|
41
|
+
|
|
42
|
+
const aliceDepositContext = baseContext('transfer', 'alice');
|
|
43
|
+
aliceDepositContext.transfer.rawAmount = '100.000 HBD';
|
|
44
|
+
aliceDepositContext.transfer.amount = '100.000';
|
|
45
|
+
aliceDepositContext.transfer.asset = 'HBD';
|
|
46
|
+
await contract.actions.deposit.handler({}, aliceDepositContext);
|
|
47
|
+
|
|
48
|
+
const bobDepositContext = baseContext('transfer', 'bob');
|
|
49
|
+
bobDepositContext.transfer.rawAmount = '10.000 HIVE';
|
|
50
|
+
bobDepositContext.transfer.amount = '10.000';
|
|
51
|
+
bobDepositContext.transfer.asset = 'HIVE';
|
|
52
|
+
await contract.actions.deposit.handler({}, bobDepositContext);
|
|
53
|
+
|
|
54
|
+
await contract.actions.placeOrder.handler({
|
|
55
|
+
side: 'buy',
|
|
56
|
+
base: 'HIVE',
|
|
57
|
+
quote: 'HBD',
|
|
58
|
+
price: '2',
|
|
59
|
+
amount: '5'
|
|
60
|
+
}, baseContext('custom_json', 'alice'));
|
|
61
|
+
|
|
62
|
+
await contract.actions.placeOrder.handler({
|
|
63
|
+
side: 'sell',
|
|
64
|
+
base: 'HIVE',
|
|
65
|
+
quote: 'HBD',
|
|
66
|
+
price: '2',
|
|
67
|
+
amount: '5'
|
|
68
|
+
}, baseContext('custom_json', 'bob'));
|
|
69
|
+
|
|
70
|
+
await contract.actions.matchOrders.handler({ base: 'HIVE', quote: 'HBD', limit: 10, snapshot: true, depth: 20 }, baseContext('time', 'system'));
|
|
71
|
+
|
|
72
|
+
const aliceHive = await adapter.query('SELECT available, locked FROM exchange_balances WHERE account = ? AND asset = ?', ['alice', 'HIVE']);
|
|
73
|
+
const bobHbd = await adapter.query('SELECT available, locked FROM exchange_balances WHERE account = ? AND asset = ?', ['bob', 'HBD']);
|
|
74
|
+
|
|
75
|
+
expect(aliceHive[0].available).toBe('4.995');
|
|
76
|
+
expect(bobHbd[0].available).toBe('9.980');
|
|
77
|
+
|
|
78
|
+
const snapshots = await adapter.query(
|
|
79
|
+
'SELECT bids, asks FROM exchange_orderbook_snapshots WHERE base_asset = ? AND quote_asset = ?',
|
|
80
|
+
['HIVE', 'HBD']
|
|
81
|
+
);
|
|
82
|
+
expect(snapshots.length).toBeGreaterThan(0);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -1,324 +1,59 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { TimeAction } from './../../src/actions';
|
|
4
|
-
import { LottoContract } from './../../src/contracts/lotto.contract';
|
|
1
|
+
import { createLottoContract } from './../../src/contracts/lotto.contract';
|
|
5
2
|
import { Streamer } from '../../src/streamer';
|
|
3
|
+
import { createMockAdapter } from '../helpers/mock-adapter';
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
|
8
6
|
|
|
9
7
|
describe('Lotto Contract', () => {
|
|
10
8
|
let sut: Streamer;
|
|
11
|
-
let contract:
|
|
9
|
+
let contract: ReturnType<typeof createLottoContract>;
|
|
10
|
+
let adapter: any;
|
|
12
11
|
|
|
13
12
|
beforeEach(async () => {
|
|
14
|
-
sut = new Streamer(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// @ts-ignore
|
|
18
|
-
sut.adapter = {
|
|
19
|
-
db: jest.fn(),
|
|
20
|
-
create: jest.fn(),
|
|
21
|
-
destroy: jest.fn(),
|
|
22
|
-
loadActions: jest.fn(),
|
|
23
|
-
loadState: jest.fn(),
|
|
24
|
-
saveState: jest.fn(),
|
|
25
|
-
processBlock: jest.fn(),
|
|
26
|
-
processOperation: jest.fn(),
|
|
27
|
-
processTransfer: jest.fn(),
|
|
28
|
-
processCustomJson: jest.fn(),
|
|
29
|
-
find: jest.fn(),
|
|
30
|
-
findOne: jest.fn(),
|
|
31
|
-
insert: jest.fn(),
|
|
32
|
-
replace: jest.fn()
|
|
33
|
-
};
|
|
13
|
+
sut = new Streamer();
|
|
14
|
+
adapter = createMockAdapter();
|
|
15
|
+
await sut.registerAdapter(adapter);
|
|
34
16
|
|
|
35
|
-
|
|
17
|
+
contract = createLottoContract({ name: 'testlotto' });
|
|
36
18
|
|
|
37
|
-
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
sut.api = jest.fn();
|
|
38
21
|
});
|
|
39
22
|
|
|
40
23
|
afterEach(async () => {
|
|
41
24
|
await sut.stop();
|
|
42
25
|
});
|
|
43
26
|
|
|
44
|
-
test('Registers the lotto contract', () => {
|
|
45
|
-
sut.registerContract(
|
|
27
|
+
test('Registers the lotto contract', async () => {
|
|
28
|
+
await sut.registerContract(contract);
|
|
46
29
|
|
|
47
30
|
const findContract = sut['contracts'].find(c => c.name === 'testlotto');
|
|
48
|
-
|
|
49
31
|
expect(findContract).not.toBeUndefined();
|
|
50
32
|
});
|
|
51
33
|
|
|
52
|
-
test('
|
|
53
|
-
|
|
54
|
-
sut.registerContract('testlotto', contract as any);
|
|
55
|
-
|
|
56
|
-
contract['_instance'] = sut;
|
|
57
|
-
|
|
58
|
-
const mockEntry = { startDate: new Date(), type: 'hourly', status: 'active', entries: [] };
|
|
59
|
-
|
|
60
|
-
jest.spyOn(sut['adapter'], 'find').mockResolvedValue(mockEntry);
|
|
61
|
-
|
|
62
|
-
jest.spyOn(contract, 'buy');
|
|
63
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(2000);
|
|
64
|
-
|
|
65
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
66
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
67
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
68
|
-
jest.spyOn(sut, 'transferHiveTokensMultiple').mockResolvedValue(true as any);
|
|
69
|
-
|
|
70
|
-
const memo = JSON.stringify({
|
|
71
|
-
hivePayload: {
|
|
72
|
-
id: 'hivestream',
|
|
73
|
-
name: 'testlotto',
|
|
74
|
-
action: 'buy',
|
|
75
|
-
payload: {
|
|
76
|
-
type: 'hourly'
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
sut.processOperation(['transfer', { from: 'testuser', amount: '10.000 HIVE', memo }], 778782, 'dfjfsdfsdfsd34hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
82
|
-
|
|
83
|
-
await sleep(100);
|
|
84
|
-
|
|
85
|
-
expect(contract.buy).toBeCalled();
|
|
86
|
-
} catch (e) {
|
|
87
|
-
throw e;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('User enters the lotto, but they have hit the entry limit', async () => {
|
|
92
|
-
try {
|
|
93
|
-
sut.registerContract('testlotto', contract as any);
|
|
34
|
+
test('Buys a lotto ticket and inserts a draw entry', async () => {
|
|
35
|
+
await sut.registerContract(contract);
|
|
94
36
|
|
|
95
|
-
|
|
37
|
+
jest.spyOn(sut, 'getTransaction').mockResolvedValue({ test: 123 } as any);
|
|
38
|
+
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
96
39
|
|
|
97
|
-
|
|
40
|
+
const insertSpy = jest.spyOn(adapter, 'insert').mockResolvedValue(true as any);
|
|
41
|
+
jest.spyOn(adapter, 'find').mockResolvedValue([] as any);
|
|
98
42
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const mockData = { startDate: new Date(), type: 'hourly', status: 'active', entries };
|
|
108
|
-
jest.spyOn(sut['adapter'], 'find').mockResolvedValue(mockData);
|
|
109
|
-
|
|
110
|
-
jest.spyOn(contract, 'buy');
|
|
111
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(2000);
|
|
112
|
-
|
|
113
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
114
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
115
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
116
|
-
jest.spyOn(sut, 'transferHiveTokensMultiple').mockResolvedValue(true as any);
|
|
117
|
-
jest.spyOn(contract, 'getPreviousUserTicketsForCurrentDrawType').mockResolvedValue(3);
|
|
118
|
-
|
|
119
|
-
const memo = JSON.stringify({
|
|
120
|
-
hivePayload: {
|
|
121
|
-
id: 'hivestream',
|
|
122
|
-
name: 'testlotto',
|
|
123
|
-
action: 'buy',
|
|
124
|
-
payload: {
|
|
125
|
-
type: 'hourly'
|
|
126
|
-
}
|
|
43
|
+
const memo = JSON.stringify({
|
|
44
|
+
hive_stream: {
|
|
45
|
+
contract: 'testlotto',
|
|
46
|
+
action: 'buy',
|
|
47
|
+
payload: {
|
|
48
|
+
type: 'hourly'
|
|
127
49
|
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
sut.processOperation(['transfer', { from: 'beggars', amount: '10.000 HIVE', memo }], 778782, 'dfjfsdfsdfsd34hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
131
|
-
|
|
132
|
-
await sleep(100);
|
|
133
|
-
|
|
134
|
-
expect(sut.transferHiveTokens).toBeCalledWith('beggars', 'beggars', '10.000', 'HIVE', '[Refund] You have exceeded the allowed number of entries');
|
|
135
|
-
} catch (e) {
|
|
136
|
-
throw e;
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test('Draw the hourly lottery', async () => {
|
|
141
|
-
try {
|
|
142
|
-
sut.registerContract('testlotto', contract as any);
|
|
143
|
-
|
|
144
|
-
contract['_instance'] = sut;
|
|
145
|
-
|
|
146
|
-
const entries = [];
|
|
147
|
-
|
|
148
|
-
for (const entrant of fiftyValidEntrants) {
|
|
149
|
-
// @ts-ignore
|
|
150
|
-
entries.push({
|
|
151
|
-
account: entrant.from,
|
|
152
|
-
date: new Date()
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const mockInsertedData = { startDate: new Date(), type: 'hourly', status: 'active', entries };
|
|
157
|
-
jest.spyOn(sut['adapter'], 'find').mockResolvedValue(mockInsertedData);
|
|
158
|
-
|
|
159
|
-
jest.spyOn(contract, 'buy');
|
|
160
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(2000);
|
|
161
|
-
|
|
162
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
163
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
164
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
165
|
-
jest.spyOn(sut, 'transferHiveTokensMultiple').mockResolvedValue(true as any);
|
|
166
|
-
|
|
167
|
-
const drawn = await contract.drawHourlyLottery();
|
|
168
|
-
|
|
169
|
-
if (drawn) {
|
|
170
|
-
expect(drawn).toHaveLength(3);
|
|
171
|
-
expect(sut.transferHiveTokensMultiple).toBeCalledTimes(2);
|
|
172
|
-
expect(sut.transferHiveTokensMultiple).toBeCalledWith('beggars', expect.any(Array), '164.667', 'HIVE', expect.stringContaining('Congratulations you won the hourly lottery. You won 164.667 HIVE'));
|
|
173
|
-
expect(sut.transferHiveTokensMultiple).toBeCalledWith(expect.any(String), expect.any(Array), '0.001', 'HIVE', expect.stringContaining('Sorry, you didn\'t win the hourly draw. Winners:'));
|
|
174
|
-
}
|
|
175
|
-
} catch (e) {
|
|
176
|
-
throw e;
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test('Draw the hourly lottery, but not enough entrants, so we refund', async () => {
|
|
181
|
-
try {
|
|
182
|
-
sut.registerContract('testlotto', contract as any);
|
|
183
|
-
|
|
184
|
-
contract['_instance'] = sut;
|
|
185
|
-
|
|
186
|
-
const entries = [];
|
|
187
|
-
const reducedEntries = fiftyValidEntrants.slice(0, 2);
|
|
188
|
-
|
|
189
|
-
for (const entrant of reducedEntries) {
|
|
190
|
-
// @ts-ignore
|
|
191
|
-
entries.push({
|
|
192
|
-
account: entrant.from,
|
|
193
|
-
date: new Date()
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const mockResponse = [{ startDate: new Date(), type: 'hourly', status: 'active', entries }];
|
|
198
|
-
jest.spyOn(sut['adapter'], 'find').mockResolvedValue(mockResponse);
|
|
199
|
-
|
|
200
|
-
jest.spyOn(contract, 'buy');
|
|
201
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(2000);
|
|
202
|
-
|
|
203
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
204
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
205
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
206
|
-
jest.spyOn(sut, 'transferHiveTokensMultiple').mockResolvedValue(true as any);
|
|
207
|
-
|
|
208
|
-
const drawn = await contract.drawHourlyLottery();
|
|
209
|
-
|
|
210
|
-
expect(sut.transferHiveTokensMultiple).toBeCalledTimes(1);
|
|
211
|
-
} catch (e) {
|
|
212
|
-
throw e;
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
test('Draw the hourly lottery, balance cannot afford to pay out winnings', async () => {
|
|
217
|
-
try {
|
|
218
|
-
sut.registerContract('testlotto', contract as any);
|
|
219
|
-
|
|
220
|
-
contract['_instance'] = sut;
|
|
221
|
-
|
|
222
|
-
const entries = [];
|
|
223
|
-
|
|
224
|
-
for (const entrant of fiftyValidEntrants) {
|
|
225
|
-
// @ts-ignore
|
|
226
|
-
entries.push({
|
|
227
|
-
account: entrant.from,
|
|
228
|
-
date: new Date()
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const mockData = [{ startDate: new Date(), type: 'hourly', status: 'active', entries }];
|
|
233
|
-
jest.spyOn(sut['adapter'], 'find').mockResolvedValue(mockData);
|
|
234
|
-
|
|
235
|
-
jest.spyOn(contract, 'buy');
|
|
236
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(10);
|
|
237
|
-
|
|
238
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
239
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
240
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
241
|
-
jest.spyOn(sut, 'transferHiveTokensMultiple').mockResolvedValue(true as any);
|
|
242
|
-
|
|
243
|
-
expect(contract.drawHourlyLottery()).rejects.toEqual(new Error('Balance is less than amount to pay out'));
|
|
244
|
-
} catch (e) {
|
|
245
|
-
throw e;
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
test('Draw the daily lottery', async () => {
|
|
250
|
-
try {
|
|
251
|
-
sut.registerContract('testlotto', contract as any);
|
|
252
|
-
|
|
253
|
-
contract['_instance'] = sut;
|
|
254
|
-
|
|
255
|
-
const entries = [];
|
|
256
|
-
const entrants = [...fiftyValidEntrants, ...fiftyValidEntrants];
|
|
257
|
-
|
|
258
|
-
for (const entrant of entrants) {
|
|
259
|
-
// @ts-ignore
|
|
260
|
-
entries.push({
|
|
261
|
-
account: entrant.from,
|
|
262
|
-
date: new Date()
|
|
263
|
-
});
|
|
264
50
|
}
|
|
51
|
+
});
|
|
265
52
|
|
|
266
|
-
|
|
267
|
-
jest.spyOn(sut['adapter'], 'find').mockResolvedValue(mockData);
|
|
268
|
-
|
|
269
|
-
jest.spyOn(contract, 'buy');
|
|
270
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(2000);
|
|
271
|
-
|
|
272
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
273
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
274
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
275
|
-
jest.spyOn(sut, 'transferHiveTokensMultiple').mockResolvedValue(true as any);
|
|
276
|
-
|
|
277
|
-
const drawn = await contract.drawDailyLottery();
|
|
53
|
+
await sut.processOperation(['transfer', { from: 'testuser', amount: '10.000 HIVE', memo }], 778782, 'blockid', 'prev', 'trxid', '2019-06-23' as any);
|
|
278
54
|
|
|
279
|
-
|
|
280
|
-
expect(sut.transferHiveTokensMultiple).toBeCalledWith('beggars', expect.any(Array), '98.800', 'HIVE', 'Congratulations you won the daily lottery. You won 98.800 HIVE');
|
|
281
|
-
} catch (e) {
|
|
282
|
-
throw e;
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test('User attempts to enter lotto with invalid currency, refund them', async () => {
|
|
287
|
-
try {
|
|
288
|
-
sut.registerContract('testlotto', contract as any);
|
|
289
|
-
|
|
290
|
-
contract['_instance'] = sut;
|
|
55
|
+
await wait(50);
|
|
291
56
|
|
|
292
|
-
|
|
293
|
-
jest.spyOn(sut['adapter'], 'find').mockResolvedValue(mockData);
|
|
294
|
-
|
|
295
|
-
jest.spyOn(contract, 'buy');
|
|
296
|
-
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(2000);
|
|
297
|
-
|
|
298
|
-
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
299
|
-
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
300
|
-
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
301
|
-
jest.spyOn(sut, 'transferHiveTokensMultiple').mockResolvedValue(true as any);
|
|
302
|
-
|
|
303
|
-
const memo = JSON.stringify({
|
|
304
|
-
hivePayload: {
|
|
305
|
-
id: 'hivestream',
|
|
306
|
-
name: 'testlotto',
|
|
307
|
-
action: 'buy',
|
|
308
|
-
payload: {
|
|
309
|
-
type: 'hourly'
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
sut.processOperation(['transfer', { from: 'testuser', amount: '10.000 HBD', memo }], 778782, 'dfjfsdfsdfsd34hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
315
|
-
|
|
316
|
-
await sleep(100);
|
|
317
|
-
|
|
318
|
-
expect(sut.transferHiveTokens).toBeCalledWith('beggars', 'testuser', '10.000', 'HBD', '[Refund] You sent an invalid currency.');
|
|
319
|
-
} catch (e) {
|
|
320
|
-
throw e;
|
|
321
|
-
}
|
|
57
|
+
expect(insertSpy).toHaveBeenCalled();
|
|
322
58
|
});
|
|
323
|
-
|
|
324
|
-
});
|
|
59
|
+
});
|