hive-stream 2.0.5 → 3.0.0
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/.claude/settings.local.json +12 -0
- package/.env.example +2 -2
- package/.travis.yml +11 -11
- package/CHANGELOG.md +166 -0
- package/CLAUDE.md +75 -0
- package/LICENSE +21 -21
- package/README.md +338 -238
- package/dist/actions.d.ts +41 -10
- package/dist/actions.js +126 -23
- package/dist/actions.js.map +1 -1
- package/dist/adapters/base.adapter.d.ts +25 -25
- package/dist/adapters/base.adapter.js +63 -49
- package/dist/adapters/base.adapter.js.map +1 -1
- package/dist/adapters/mongodb.adapter.d.ts +50 -37
- package/dist/adapters/mongodb.adapter.js +363 -158
- package/dist/adapters/mongodb.adapter.js.map +1 -1
- package/dist/adapters/postgresql.adapter.d.ts +49 -0
- package/dist/adapters/postgresql.adapter.js +507 -0
- package/dist/adapters/postgresql.adapter.js.map +1 -0
- package/dist/adapters/sqlite.adapter.d.ts +40 -41
- package/dist/adapters/sqlite.adapter.js +470 -397
- package/dist/adapters/sqlite.adapter.js.map +1 -1
- package/dist/api.d.ts +6 -6
- package/dist/api.js +95 -55
- package/dist/api.js.map +1 -1
- package/dist/config.d.ts +16 -16
- package/dist/config.js +18 -18
- package/dist/config.js.map +1 -1
- package/dist/contracts/coinflip.contract.d.ts +27 -14
- package/dist/contracts/coinflip.contract.js +253 -94
- package/dist/contracts/coinflip.contract.js.map +1 -1
- package/dist/contracts/dice.contract.d.ts +37 -29
- package/dist/contracts/dice.contract.js +282 -155
- package/dist/contracts/dice.contract.js.map +1 -1
- package/dist/contracts/lotto.contract.d.ts +20 -20
- package/dist/contracts/lotto.contract.js +246 -246
- package/dist/contracts/nft.contract.d.ts +24 -0
- package/dist/contracts/nft.contract.js +533 -0
- package/dist/contracts/nft.contract.js.map +1 -0
- package/dist/contracts/token.contract.d.ts +18 -0
- package/dist/contracts/token.contract.js +263 -0
- package/dist/contracts/token.contract.js.map +1 -0
- package/dist/exchanges/bittrex.d.ts +6 -6
- package/dist/exchanges/bittrex.js +34 -34
- package/dist/exchanges/coingecko.d.ts +5 -0
- package/dist/exchanges/coingecko.js +40 -0
- package/dist/exchanges/coingecko.js.map +1 -0
- package/dist/exchanges/exchange.d.ts +9 -9
- package/dist/exchanges/exchange.js +26 -26
- package/dist/hive-rates.d.ts +9 -9
- package/dist/hive-rates.js +121 -75
- package/dist/hive-rates.js.map +1 -1
- package/dist/index.d.ts +12 -11
- package/dist/index.js +33 -32
- package/dist/index.js.map +1 -1
- package/dist/streamer.d.ts +140 -93
- package/dist/streamer.js +793 -545
- package/dist/streamer.js.map +1 -1
- package/dist/test.d.ts +1 -1
- package/dist/test.js +25 -25
- package/dist/test.js.map +1 -1
- package/dist/types/hive-stream.d.ts +35 -6
- package/dist/types/hive-stream.js +2 -2
- package/dist/utils.d.ts +27 -27
- package/dist/utils.js +271 -261
- package/dist/utils.js.map +1 -1
- package/ecosystem.config.js +17 -17
- package/jest.config.js +8 -8
- package/package.json +53 -48
- package/test-contract-block.md +18 -18
- package/tests/actions.spec.ts +252 -0
- package/tests/adapters/actions-persistence.spec.ts +144 -0
- package/tests/adapters/postgresql.adapter.spec.ts +127 -0
- package/tests/adapters/sqlite.adapter.spec.ts +180 -42
- package/tests/contracts/coinflip.contract.spec.ts +221 -131
- package/tests/contracts/dice.contract.spec.ts +202 -159
- package/tests/contracts/entrants.json +728 -728
- package/tests/contracts/lotto.contract.spec.ts +323 -323
- package/tests/contracts/nft.contract.spec.ts +948 -0
- package/tests/contracts/token.contract.spec.ts +334 -0
- package/tests/helpers/mock-adapter.ts +214 -0
- package/tests/setup.ts +29 -18
- package/tests/streamer-actions.spec.ts +263 -0
- package/tests/streamer.spec.ts +248 -151
- package/tests/utils.spec.ts +91 -94
- package/tsconfig.build.json +3 -22
- package/tslint.json +20 -20
- package/wallaby.js +26 -26
- package/.env +0 -3
|
@@ -1,132 +1,222 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
sut
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
jest.spyOn(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
jest.spyOn(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
1
|
+
import { CoinflipContract } from '../../src/contracts/coinflip.contract';
|
|
2
|
+
import { sleep } from '@hiveio/dhive/lib/utils';
|
|
3
|
+
import { Streamer } from '../../src/streamer';
|
|
4
|
+
import { createMockAdapter } from '../helpers/mock-adapter';
|
|
5
|
+
import BigNumber from 'bignumber.js';
|
|
6
|
+
|
|
7
|
+
// Mock uuid module at the top level
|
|
8
|
+
jest.mock('uuid', () => ({
|
|
9
|
+
v4: jest.fn()
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
13
|
+
|
|
14
|
+
describe('Coinflip Contract', () => {
|
|
15
|
+
let sut: Streamer;
|
|
16
|
+
let contract: CoinflipContract;
|
|
17
|
+
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
sut = new Streamer();
|
|
20
|
+
await sut.registerAdapter(createMockAdapter());
|
|
21
|
+
|
|
22
|
+
contract = new CoinflipContract();
|
|
23
|
+
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
sut.api = jest.fn();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(async () => {
|
|
29
|
+
await sut.stop();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
jest.restoreAllMocks();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
afterAll(() => {
|
|
37
|
+
jest.resetAllMocks();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('Registers the contract', () => {
|
|
41
|
+
sut.registerContract('coinflip', contract);
|
|
42
|
+
|
|
43
|
+
const findContract = sut['contracts'].find(c => c.name === 'coinflip');
|
|
44
|
+
|
|
45
|
+
expect(findContract).not.toBeUndefined();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('User wins a flip', async () => {
|
|
49
|
+
sut.registerContract('coinflip', contract);
|
|
50
|
+
|
|
51
|
+
contract['_instance'] = sut;
|
|
52
|
+
|
|
53
|
+
jest.spyOn(contract as any, 'flip');
|
|
54
|
+
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
55
|
+
|
|
56
|
+
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
57
|
+
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
58
|
+
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
59
|
+
|
|
60
|
+
const memo = JSON.stringify({
|
|
61
|
+
hivePayload: {
|
|
62
|
+
id: 'hivestream',
|
|
63
|
+
name: 'coinflip',
|
|
64
|
+
action: 'flip',
|
|
65
|
+
payload: {
|
|
66
|
+
guess: 'heads',
|
|
67
|
+
seed: 'hj879879g7686876'
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
(uuidv4 as jest.Mock).mockReturnValue('j93jgsjghjdhgjfhgkfdhgkj34872394723');
|
|
73
|
+
|
|
74
|
+
sut.processOperation(['transfer', { from: 'testuser', amount: '9.000 HIVE', memo }], 778782, 'dfjfsdfsdfs4hfkj88787', 'fkjs7878dkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
75
|
+
|
|
76
|
+
await sleep(100);
|
|
77
|
+
|
|
78
|
+
expect(contract['flip']).toBeCalled();
|
|
79
|
+
expect(contract['_instance'].getTransaction).toBeCalledWith(778782, 'fhkjsdhfkjsdf');
|
|
80
|
+
expect(contract['_instance'].transferHiveTokens).toBeCalledWith('beggars', 'testuser', '18.000', 'HIVE', '[Winner] | Guess: heads | Server Roll: heads | Previous block id: fkjs7878dkfj | BlockID: dfjfsdfsdfs4hfkj88787 | Trx ID: fhkjsdhfkjsdf | Server Seed: j93jgsjghjdhgjfhgkfdhgkj34872394723');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('User loses a flip', async () => {
|
|
84
|
+
sut.registerContract('coinflip', contract);
|
|
85
|
+
|
|
86
|
+
contract['_instance'] = sut;
|
|
87
|
+
|
|
88
|
+
jest.spyOn(contract as any, 'flip');
|
|
89
|
+
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
90
|
+
|
|
91
|
+
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
92
|
+
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
93
|
+
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
94
|
+
|
|
95
|
+
const memo = JSON.stringify({
|
|
96
|
+
hivePayload: {
|
|
97
|
+
id: 'hivestream',
|
|
98
|
+
name: 'coinflip',
|
|
99
|
+
action: 'flip',
|
|
100
|
+
payload: {
|
|
101
|
+
guess: 'heads',
|
|
102
|
+
seed: 'tulips'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
(uuidv4 as jest.Mock).mockReturnValue('j93jgsjghjdhgjfhgkfdhgkj34872394723');
|
|
108
|
+
|
|
109
|
+
sut.processOperation(['transfer', { from: 'testuser', amount: '9.000 HIVE', memo }], 778782, 'dfjfsdfsdfs4hfkj88787', 'fkjs7878dkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
110
|
+
|
|
111
|
+
await sleep(100);
|
|
112
|
+
|
|
113
|
+
expect(contract['flip']).toBeCalled();
|
|
114
|
+
expect(contract['_instance'].getTransaction).toBeCalledWith(778782, 'fhkjsdhfkjsdf');
|
|
115
|
+
expect(contract['_instance'].transferHiveTokens).toBeCalledWith('beggars', 'testuser', '0.001', 'HIVE', '[Lost] | Guess: heads | Server Roll: tails | Previous block id: fkjs7878dkfj | BlockID: dfjfsdfsdfs4hfkj88787 | Trx ID: fhkjsdhfkjsdf | Server Seed: j93jgsjghjdhgjfhgkfdhgkj34872394723');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('User sent an unsupported currency, refund them', async () => {
|
|
119
|
+
sut.registerContract('coinflip', contract);
|
|
120
|
+
|
|
121
|
+
contract['_instance'] = sut;
|
|
122
|
+
|
|
123
|
+
jest.spyOn(contract as any, 'flip');
|
|
124
|
+
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
125
|
+
|
|
126
|
+
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
127
|
+
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
128
|
+
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
129
|
+
|
|
130
|
+
const memo = JSON.stringify({
|
|
131
|
+
hivePayload: {
|
|
132
|
+
id: 'hivestream',
|
|
133
|
+
name: 'coinflip',
|
|
134
|
+
action: 'flip',
|
|
135
|
+
payload: {
|
|
136
|
+
guess: 'heads'
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
sut.processOperation(['transfer', { from: 'testuser', amount: '10.000 HBD', memo }], 778782, 'dfjfsdfsdfs4hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
142
|
+
|
|
143
|
+
await sleep(100);
|
|
144
|
+
|
|
145
|
+
expect(contract['flip']).toBeCalled();
|
|
146
|
+
expect(sut.getTransaction).toBeCalledWith(778782, 'fhkjsdhfkjsdf');
|
|
147
|
+
expect(sut.transferHiveTokens).toBeCalledWith('beggars', 'testuser', '10.000', 'HBD', '[Refund] You sent an invalid currency.');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('Server cannot afford payout, refund user', async () => {
|
|
151
|
+
sut.registerContract('coinflip', contract);
|
|
152
|
+
|
|
153
|
+
contract['_instance'] = sut;
|
|
154
|
+
|
|
155
|
+
jest.spyOn(contract as any, 'flip');
|
|
156
|
+
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(10)); // Low balance
|
|
157
|
+
|
|
158
|
+
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
159
|
+
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
160
|
+
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
161
|
+
|
|
162
|
+
const memo = JSON.stringify({
|
|
163
|
+
hivePayload: {
|
|
164
|
+
id: 'hivestream',
|
|
165
|
+
name: 'coinflip',
|
|
166
|
+
action: 'flip',
|
|
167
|
+
payload: {
|
|
168
|
+
guess: 'heads'
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
sut.processOperation(['transfer', { from: 'testuser', amount: '15.000 HIVE', memo }], 778782, 'dfjfsdfsdfs4hfkj88787', 'fkjsdkfj', 'fhkjsdhfkjsdf', '2019-06-23' as any);
|
|
174
|
+
|
|
175
|
+
await sleep(100);
|
|
176
|
+
|
|
177
|
+
expect(contract['flip']).toBeCalled();
|
|
178
|
+
expect(sut.getTransaction).toBeCalledWith(778782, 'fhkjsdhfkjsdf');
|
|
179
|
+
expect(sut.transferHiveTokens).toBeCalledWith('beggars', 'testuser', '15.000', 'HIVE', '[Refund] The server cannot afford this bet payout.');
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('Queue processes multiple concurrent bets', async () => {
|
|
183
|
+
sut.registerContract('coinflip', contract);
|
|
184
|
+
|
|
185
|
+
contract['_instance'] = sut;
|
|
186
|
+
|
|
187
|
+
jest.spyOn(contract as any, 'getBalance').mockResolvedValue(new BigNumber(2000));
|
|
188
|
+
jest.spyOn(sut, 'getTransaction').mockResolvedValue({test: 123} as any);
|
|
189
|
+
jest.spyOn(sut, 'verifyTransfer').mockResolvedValue(true as any);
|
|
190
|
+
jest.spyOn(sut, 'transferHiveTokens').mockResolvedValue(true as any);
|
|
191
|
+
|
|
192
|
+
const memo1 = JSON.stringify({
|
|
193
|
+
hivePayload: {
|
|
194
|
+
id: 'hivestream',
|
|
195
|
+
name: 'coinflip',
|
|
196
|
+
action: 'flip',
|
|
197
|
+
payload: { guess: 'heads', seed: 'seed1' }
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const memo2 = JSON.stringify({
|
|
202
|
+
hivePayload: {
|
|
203
|
+
id: 'hivestream',
|
|
204
|
+
name: 'coinflip',
|
|
205
|
+
action: 'flip',
|
|
206
|
+
payload: { guess: 'heads', seed: 'seed2' }
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
(uuidv4 as jest.Mock).mockReturnValue('test-server-seed');
|
|
211
|
+
|
|
212
|
+
// Process multiple bets concurrently
|
|
213
|
+
const bet1Promise = sut.processOperation(['transfer', { from: 'user1', amount: '5.000 HIVE', memo: memo1 }], 778782, 'block1', 'prevblock1', 'trx1', '2019-06-23' as any);
|
|
214
|
+
const bet2Promise = sut.processOperation(['transfer', { from: 'user2', amount: '5.000 HIVE', memo: memo2 }], 778783, 'block2', 'prevblock2', 'trx2', '2019-06-23' as any);
|
|
215
|
+
|
|
216
|
+
await Promise.all([bet1Promise, bet2Promise]);
|
|
217
|
+
await sleep(200); // Allow queue processing to complete
|
|
218
|
+
|
|
219
|
+
// Both transfers should have been processed
|
|
220
|
+
expect(sut.transferHiveTokens).toHaveBeenCalledTimes(2);
|
|
221
|
+
});
|
|
132
222
|
});
|