@human-protocol/sdk 1.1.0 → 1.1.2
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/package.json +3 -6
- package/src/error.ts +5 -0
- package/src/job.ts +268 -22
- package/src/storage.ts +4 -3
- package/src/types.ts +13 -0
- package/src/utils.ts +70 -3
- package/test/job.test.ts +132 -68
- package/test/utils/constants.ts +3 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@human-protocol/sdk",
|
|
3
3
|
"description": "Human Protocol SDK",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.2",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
7
7
|
"dist",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"clean": "rm -rf ./dist",
|
|
15
15
|
"build": "npm run clean && tsc",
|
|
16
16
|
"prepublish": "npm run build",
|
|
17
|
-
"test": "
|
|
17
|
+
"test": "concurrently -k -s first -g --hide 0 \"yarn workspace @human-protocol/core local\" \"sleep 10 && jest --runInBand\"",
|
|
18
18
|
"lint": "eslint .",
|
|
19
19
|
"lint:fix": "eslint . --fix",
|
|
20
20
|
"format": "prettier --write '**/*.{ts,json}'"
|
|
@@ -38,15 +38,12 @@
|
|
|
38
38
|
]
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@human-protocol/core": "^1.0.
|
|
41
|
+
"@human-protocol/core": "^1.0.12",
|
|
42
42
|
"aws-sdk": "^2.1255.0",
|
|
43
43
|
"crypto": "^1.0.1",
|
|
44
44
|
"dotenv": "^16.0.3",
|
|
45
45
|
"ethers": "^5.7.2",
|
|
46
46
|
"secp256k1": "^4.0.3",
|
|
47
47
|
"winston": "^3.8.2"
|
|
48
|
-
},
|
|
49
|
-
"peerDependencies": {
|
|
50
|
-
"@human-protocol/core": "^1.0.9"
|
|
51
48
|
}
|
|
52
49
|
}
|
package/src/error.ts
CHANGED
|
@@ -36,3 +36,8 @@ export const ErrorHMTokenMissing = new Error('HMToken is missing');
|
|
|
36
36
|
export const ErrorStorageAccessDataMissing = new Error(
|
|
37
37
|
'Storage access data is missing'
|
|
38
38
|
);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @constant {Error} - The Staking contract is missing.
|
|
42
|
+
*/
|
|
43
|
+
export const ErrorStakingMissing = new Error('Staking contract is missing');
|
package/src/job.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
getEscrow,
|
|
21
21
|
getEscrowFactory,
|
|
22
22
|
getHmToken,
|
|
23
|
+
getStaking,
|
|
23
24
|
toFullDigit,
|
|
24
25
|
} from './utils';
|
|
25
26
|
import {
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
ErrorJobNotLaunched,
|
|
30
31
|
ErrorManifestMissing,
|
|
31
32
|
ErrorReputationOracleMissing,
|
|
33
|
+
ErrorStakingMissing,
|
|
32
34
|
ErrorStorageAccessDataMissing,
|
|
33
35
|
} from './error';
|
|
34
36
|
import { createLogger } from './logger';
|
|
@@ -94,6 +96,7 @@ export class Job {
|
|
|
94
96
|
storageEndpoint,
|
|
95
97
|
storagePublicBucket,
|
|
96
98
|
storageBucket,
|
|
99
|
+
stakingAddr,
|
|
97
100
|
logLevel = 'info',
|
|
98
101
|
}: JobArguments) {
|
|
99
102
|
const provider = network
|
|
@@ -101,7 +104,7 @@ export class Job {
|
|
|
101
104
|
alchemy: alchemyKey,
|
|
102
105
|
infura: infuraKey,
|
|
103
106
|
})
|
|
104
|
-
: new ethers.providers.JsonRpcProvider();
|
|
107
|
+
: new ethers.providers.JsonRpcProvider('http://127.0.0.1:8545');
|
|
105
108
|
|
|
106
109
|
this.providerData = {
|
|
107
110
|
provider,
|
|
@@ -134,6 +137,7 @@ export class Job {
|
|
|
134
137
|
hmTokenAddr,
|
|
135
138
|
escrowAddr,
|
|
136
139
|
factoryAddr,
|
|
140
|
+
stakingAddr,
|
|
137
141
|
};
|
|
138
142
|
|
|
139
143
|
this.manifestData = { manifest };
|
|
@@ -174,9 +178,20 @@ export class Job {
|
|
|
174
178
|
return false;
|
|
175
179
|
}
|
|
176
180
|
|
|
181
|
+
if (!this.contractData.stakingAddr) {
|
|
182
|
+
this._logError(new Error('Staking contract is missing'));
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this._logger.info('Getting staking...');
|
|
187
|
+
this.contractData.staking = await getStaking(
|
|
188
|
+
this.contractData.stakingAddr,
|
|
189
|
+
this.providerData?.gasPayer
|
|
190
|
+
);
|
|
191
|
+
|
|
177
192
|
this._logger.info('Deploying escrow factory...');
|
|
178
193
|
this.contractData.factory = await deployEscrowFactory(
|
|
179
|
-
this.contractData.
|
|
194
|
+
this.contractData.stakingAddr,
|
|
180
195
|
this.providerData?.gasPayer
|
|
181
196
|
);
|
|
182
197
|
this.contractData.factoryAddr = this.contractData.factory.address;
|
|
@@ -197,6 +212,31 @@ export class Job {
|
|
|
197
212
|
this.providerData?.gasPayer
|
|
198
213
|
);
|
|
199
214
|
|
|
215
|
+
this._logger.info('Checking if staking is configured...');
|
|
216
|
+
const stakingAddr = await this.contractData.factory.staking();
|
|
217
|
+
if (!stakingAddr) {
|
|
218
|
+
this._logError(new Error('Factory is not configured with staking'));
|
|
219
|
+
this.contractData.factory = undefined;
|
|
220
|
+
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
this._logger.info('Getting staking...');
|
|
224
|
+
this.contractData.staking = await getStaking(
|
|
225
|
+
stakingAddr,
|
|
226
|
+
this.providerData?.gasPayer
|
|
227
|
+
);
|
|
228
|
+
this.contractData.stakingAddr = stakingAddr;
|
|
229
|
+
|
|
230
|
+
this._logger.info('Checking if reward pool is configured...');
|
|
231
|
+
const rewardPoolAddr = await this.contractData.staking.rewardPool();
|
|
232
|
+
if (!rewardPoolAddr) {
|
|
233
|
+
this._logError(new Error('Staking is not configured with reward pool'));
|
|
234
|
+
this.contractData.staking = undefined;
|
|
235
|
+
this.contractData.factory = undefined;
|
|
236
|
+
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
|
|
200
240
|
this._logger.info('Checking if escrow exists in the factory...');
|
|
201
241
|
const hasEscrow = await this.contractData?.factory.hasEscrow(
|
|
202
242
|
this.contractData?.escrowAddr
|
|
@@ -274,26 +314,33 @@ export class Job {
|
|
|
274
314
|
|
|
275
315
|
this._logger.info('Launching escrow...');
|
|
276
316
|
|
|
277
|
-
|
|
278
|
-
this.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
317
|
+
try {
|
|
318
|
+
const txReceipt = await this.contractData?.factory?.createEscrow(
|
|
319
|
+
this.contractData.hmTokenAddr,
|
|
320
|
+
this.providerData?.trustedHandlers?.map(
|
|
321
|
+
(trustedHandler) => trustedHandler.address
|
|
322
|
+
) || []
|
|
323
|
+
);
|
|
282
324
|
|
|
283
|
-
|
|
325
|
+
const txResponse = await txReceipt?.wait();
|
|
284
326
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
327
|
+
const event = txResponse?.events?.find(
|
|
328
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
329
|
+
(event: any) => event.event === 'Launched'
|
|
330
|
+
);
|
|
288
331
|
|
|
289
|
-
|
|
290
|
-
|
|
332
|
+
const escrowAddr = event?.args?.[1];
|
|
333
|
+
this._logger.info(`Escrow is deployed at ${escrowAddr}.`);
|
|
291
334
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
335
|
+
this.contractData.escrowAddr = escrowAddr;
|
|
336
|
+
this.contractData.escrow = await getEscrow(
|
|
337
|
+
escrowAddr,
|
|
338
|
+
this.providerData?.gasPayer
|
|
339
|
+
);
|
|
340
|
+
} catch {
|
|
341
|
+
this._logError(new Error('Error creating escrow...'));
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
297
344
|
|
|
298
345
|
return (
|
|
299
346
|
(await this.status()) == EscrowStatus.Launched &&
|
|
@@ -338,6 +385,8 @@ export class Job {
|
|
|
338
385
|
this.manifestData?.manifest?.reputation_oracle_addr || '';
|
|
339
386
|
const recordingOracleAddr =
|
|
340
387
|
this.manifestData?.manifest?.recording_oracle_addr || '';
|
|
388
|
+
const requestedSolutions =
|
|
389
|
+
this.manifestData?.manifest?.job_total_tasks || 0;
|
|
341
390
|
|
|
342
391
|
this._logger.info(
|
|
343
392
|
`Transferring ${this.amount} HMT to ${this.contractData.escrow.address}...`
|
|
@@ -391,7 +440,8 @@ export class Job {
|
|
|
391
440
|
reputationOracleStake,
|
|
392
441
|
recordingOracleStake,
|
|
393
442
|
this.manifestData?.manifestlink?.url,
|
|
394
|
-
this.manifestData?.manifestlink?.hash
|
|
443
|
+
this.manifestData?.manifestlink?.hash,
|
|
444
|
+
requestedSolutions
|
|
395
445
|
);
|
|
396
446
|
|
|
397
447
|
if (!contractSetup) {
|
|
@@ -633,6 +683,184 @@ export class Job {
|
|
|
633
683
|
return (await this.status()) === EscrowStatus.Complete;
|
|
634
684
|
}
|
|
635
685
|
|
|
686
|
+
/**
|
|
687
|
+
* **Stake HMTokens**
|
|
688
|
+
*
|
|
689
|
+
* @param {number} amount - Amount to stake
|
|
690
|
+
* @param {string | undefined} from - Address to stake
|
|
691
|
+
* @returns {Promise<boolean>} - True if the token is staked
|
|
692
|
+
*/
|
|
693
|
+
async stake(amount: number, from?: string) {
|
|
694
|
+
if (!this.contractData?.staking) {
|
|
695
|
+
this._logError(ErrorStakingMissing);
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
if (!this.contractData.hmToken) {
|
|
699
|
+
this._logError(ErrorHMTokenMissing);
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const operator = this._findOperator(from);
|
|
704
|
+
|
|
705
|
+
if (!operator) {
|
|
706
|
+
this._logError(new Error('Unknown wallet'));
|
|
707
|
+
return false;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
try {
|
|
711
|
+
const approved = await this.contractData.hmToken
|
|
712
|
+
.connect(operator)
|
|
713
|
+
.approve(this.contractData.staking.address, toFullDigit(amount));
|
|
714
|
+
|
|
715
|
+
if (!approved) {
|
|
716
|
+
throw new Error('Not approved');
|
|
717
|
+
}
|
|
718
|
+
} catch {
|
|
719
|
+
this._logError(new Error('Error approving HMTokens for staking'));
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
try {
|
|
724
|
+
await this.contractData.staking
|
|
725
|
+
.connect(operator)
|
|
726
|
+
.stake(toFullDigit(amount));
|
|
727
|
+
} catch {
|
|
728
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
return true;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* **Unstake HMTokens**
|
|
736
|
+
*
|
|
737
|
+
* @param {number} amount - Amount to unstake
|
|
738
|
+
* @param {string | undefined} from - Address to unstake
|
|
739
|
+
* @returns {Promise<boolean>} - True if the token is unstaked
|
|
740
|
+
*/
|
|
741
|
+
async unstake(amount: number, from?: string) {
|
|
742
|
+
if (!this.contractData?.staking) {
|
|
743
|
+
this._logError(ErrorStakingMissing);
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const operator = this._findOperator(from);
|
|
748
|
+
|
|
749
|
+
if (!operator) {
|
|
750
|
+
this._logError(new Error('Unknown wallet'));
|
|
751
|
+
return false;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
try {
|
|
755
|
+
await this.contractData.staking
|
|
756
|
+
.connect(operator)
|
|
757
|
+
.unstake(toFullDigit(amount));
|
|
758
|
+
} catch {
|
|
759
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
return true;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* **Withdraw unstaked HMTokens**
|
|
767
|
+
*
|
|
768
|
+
* @param {string | undefined} from - Address to withdraw
|
|
769
|
+
* @returns {Promise<boolean>} - True if the token is withdrawn
|
|
770
|
+
*/
|
|
771
|
+
async withdraw(from?: string) {
|
|
772
|
+
if (!this.contractData?.staking) {
|
|
773
|
+
this._logError(ErrorStakingMissing);
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const operator = this._findOperator(from);
|
|
778
|
+
|
|
779
|
+
if (!operator) {
|
|
780
|
+
this._logError(new Error('Unknown wallet'));
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
try {
|
|
785
|
+
await this.contractData.staking.connect(operator).withdraw();
|
|
786
|
+
} catch {
|
|
787
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
return true;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* **Allocate HMTokens staked to the job**
|
|
795
|
+
*
|
|
796
|
+
* @param {number} amount - Amount to allocate
|
|
797
|
+
* @param {string | undefined} - Address to allocate with
|
|
798
|
+
* @returns {Promise<boolean>} - True if the token is allocated
|
|
799
|
+
*/
|
|
800
|
+
async allocate(amount: number, from?: string) {
|
|
801
|
+
if (!this.contractData?.staking) {
|
|
802
|
+
this._logError(ErrorStakingMissing);
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (!this.contractData.escrowAddr) {
|
|
807
|
+
this._logError(ErrorJobNotLaunched);
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
const operator = this._findOperator(from);
|
|
812
|
+
|
|
813
|
+
if (!operator) {
|
|
814
|
+
this._logError(new Error('Unknown wallet'));
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
try {
|
|
819
|
+
await this.contractData.staking
|
|
820
|
+
.connect(operator)
|
|
821
|
+
.allocate(this.contractData.escrowAddr, toFullDigit(amount));
|
|
822
|
+
} catch {
|
|
823
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
return true;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* **Unallocate HMTokens from the job**
|
|
831
|
+
*
|
|
832
|
+
* @param {string | undefined} - Address to close allocation with
|
|
833
|
+
* @returns {Promise<boolean>} - True if the token is unallocated.
|
|
834
|
+
*/
|
|
835
|
+
async closeAllocation(from?: string) {
|
|
836
|
+
if (!this.contractData?.staking) {
|
|
837
|
+
this._logError(ErrorStakingMissing);
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if (!this.contractData.escrowAddr) {
|
|
842
|
+
this._logError(ErrorJobNotLaunched);
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const operator = this._findOperator(from);
|
|
847
|
+
|
|
848
|
+
if (!operator) {
|
|
849
|
+
this._logError(new Error('Unknown wallet'));
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
try {
|
|
854
|
+
await this.contractData.staking
|
|
855
|
+
.connect(operator)
|
|
856
|
+
.closeAllocation(this.contractData.escrowAddr);
|
|
857
|
+
} catch {
|
|
858
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
return true;
|
|
862
|
+
}
|
|
863
|
+
|
|
636
864
|
/**
|
|
637
865
|
* **Get current status of the escrow**
|
|
638
866
|
*
|
|
@@ -803,8 +1031,10 @@ export class Job {
|
|
|
803
1031
|
await contract.connect(trustedHandler).functions[functionName](...args);
|
|
804
1032
|
return true;
|
|
805
1033
|
} catch (err) {
|
|
806
|
-
|
|
807
|
-
|
|
1034
|
+
this._logError(
|
|
1035
|
+
new Error(
|
|
1036
|
+
'Error executing the transaction from all of the trusted handlers. Stop continue executing...'
|
|
1037
|
+
)
|
|
808
1038
|
);
|
|
809
1039
|
}
|
|
810
1040
|
}
|
|
@@ -813,9 +1043,25 @@ export class Job {
|
|
|
813
1043
|
|
|
814
1044
|
/**
|
|
815
1045
|
* **Error log**
|
|
1046
|
+
*
|
|
816
1047
|
* @param {Error} error - Occured error
|
|
817
1048
|
*/
|
|
818
|
-
private
|
|
1049
|
+
private _logError(error: Error) {
|
|
819
1050
|
this._logger.error(error.message);
|
|
820
1051
|
}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* **Find operator to execute tx**
|
|
1055
|
+
*
|
|
1056
|
+
* @param {string} addr - Address of the operator
|
|
1057
|
+
* @returns {ethers.Wallet | undefined} - Operator wallet
|
|
1058
|
+
*/
|
|
1059
|
+
private _findOperator(addr?: string): ethers.Wallet | undefined {
|
|
1060
|
+
return addr
|
|
1061
|
+
? [
|
|
1062
|
+
this.providerData?.gasPayer,
|
|
1063
|
+
...(this.providerData?.trustedHandlers || []),
|
|
1064
|
+
].find((account?: ethers.Wallet) => account?.address === addr)
|
|
1065
|
+
: this.providerData?.gasPayer;
|
|
1066
|
+
}
|
|
821
1067
|
}
|
package/src/storage.ts
CHANGED
|
@@ -76,7 +76,7 @@ export const getKeyFromURL = (url: string): string => {
|
|
|
76
76
|
* @param {StorageAccessData} storageAccessData - Cloud storage access data
|
|
77
77
|
* @param {string} key - Key of result object
|
|
78
78
|
* @param {string} privateKey - Private key to decode encrypted content
|
|
79
|
-
* @param {
|
|
79
|
+
* @param {boolean} isPublic - Whether the objest is using public bucket, or private bucket
|
|
80
80
|
* @returns {Promise<Result>} - Downloaded result
|
|
81
81
|
*/
|
|
82
82
|
export const download = async (
|
|
@@ -104,14 +104,15 @@ export const download = async (
|
|
|
104
104
|
* @param {StorageAccessData} storageAccessData - Cloud storage access data
|
|
105
105
|
* @param {Result} result - Result to upload
|
|
106
106
|
* @param {string} publicKey - Public key to encrypt data if necessary
|
|
107
|
-
* @param {
|
|
108
|
-
* @param {
|
|
107
|
+
* @param {boolean} _encrypt - Whether to encrypt the result, or not
|
|
108
|
+
* @param {boolean} isPublic - Whether to use public bucket, or private bucket
|
|
109
109
|
* @returns {Promise<UploadResult>} - Uploaded result with key/hash
|
|
110
110
|
*/
|
|
111
111
|
export const upload = async (
|
|
112
112
|
storageAccessData: StorageAccessData,
|
|
113
113
|
result: Result,
|
|
114
114
|
publicKey: string,
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
115
116
|
encrypt = true,
|
|
116
117
|
isPublic = false
|
|
117
118
|
): Promise<UploadResult> => {
|
package/src/types.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
Escrow,
|
|
3
3
|
EscrowFactory,
|
|
4
4
|
HMToken,
|
|
5
|
+
Staking,
|
|
5
6
|
} from '@human-protocol/core/typechain-types';
|
|
6
7
|
import { ethers } from 'ethers';
|
|
7
8
|
|
|
@@ -567,6 +568,14 @@ export type ContractData = {
|
|
|
567
568
|
* HMToken contract instance
|
|
568
569
|
*/
|
|
569
570
|
hmToken?: HMToken;
|
|
571
|
+
/**
|
|
572
|
+
* Staking contract address
|
|
573
|
+
*/
|
|
574
|
+
stakingAddr?: string;
|
|
575
|
+
/**
|
|
576
|
+
* Staking contract instance
|
|
577
|
+
*/
|
|
578
|
+
staking?: Staking;
|
|
570
579
|
};
|
|
571
580
|
|
|
572
581
|
/**
|
|
@@ -627,6 +636,10 @@ export type JobArguments = {
|
|
|
627
636
|
/**
|
|
628
637
|
* Factory contract address
|
|
629
638
|
*/
|
|
639
|
+
stakingAddr?: string;
|
|
640
|
+
/**
|
|
641
|
+
* Staking contract address
|
|
642
|
+
*/
|
|
630
643
|
factoryAddr?: string;
|
|
631
644
|
/**
|
|
632
645
|
* Escrow contract address
|
package/src/utils.ts
CHANGED
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
EscrowFactory__factory,
|
|
8
8
|
HMToken,
|
|
9
9
|
HMToken__factory,
|
|
10
|
+
Staking,
|
|
11
|
+
Staking__factory,
|
|
12
|
+
RewardPool,
|
|
13
|
+
RewardPool__factory,
|
|
10
14
|
} from '@human-protocol/core/typechain-types';
|
|
11
15
|
|
|
12
16
|
/**
|
|
@@ -30,17 +34,18 @@ export const getHmToken = async (
|
|
|
30
34
|
/**
|
|
31
35
|
* **Deploy EscrowFactory contract**
|
|
32
36
|
*
|
|
33
|
-
* @param {string}
|
|
37
|
+
* @param {string} stakingAddr Staking address
|
|
34
38
|
* @param {ethers.Signer | undefined} signer Deployer signer
|
|
35
39
|
* @returns {Promise<EscrowFactory>} Deployed contract instance
|
|
36
40
|
*/
|
|
37
41
|
export const deployEscrowFactory = async (
|
|
38
|
-
|
|
42
|
+
stakingAddr: string,
|
|
39
43
|
signer?: ethers.Signer
|
|
40
44
|
): Promise<EscrowFactory> => {
|
|
41
45
|
const factory = new EscrowFactory__factory(signer);
|
|
42
46
|
|
|
43
|
-
const contract = await factory.deploy(
|
|
47
|
+
const contract = await factory.deploy();
|
|
48
|
+
await contract.initialize(stakingAddr);
|
|
44
49
|
|
|
45
50
|
return contract;
|
|
46
51
|
};
|
|
@@ -81,6 +86,68 @@ export const getEscrow = async (
|
|
|
81
86
|
return contract;
|
|
82
87
|
};
|
|
83
88
|
|
|
89
|
+
/**
|
|
90
|
+
* **Deploy Staking contract**
|
|
91
|
+
*
|
|
92
|
+
* @param {string} hmTokenAddr HMToken address
|
|
93
|
+
* @param {number} minimumStake Minimum amount to stake
|
|
94
|
+
* @param {number} lockPeriod Lock period after unstake
|
|
95
|
+
* @param {ethers.Signer | undefined} signer Deployer signer
|
|
96
|
+
* @returns {Promise<Staking>} Deployed contract instance
|
|
97
|
+
*/
|
|
98
|
+
export const deployStaking = async (
|
|
99
|
+
hmTokenAddr: string,
|
|
100
|
+
minimumStake: number,
|
|
101
|
+
lockPeriod: number,
|
|
102
|
+
signer?: ethers.Signer
|
|
103
|
+
): Promise<Staking> => {
|
|
104
|
+
const staking = new Staking__factory(signer);
|
|
105
|
+
const contract = await staking.deploy();
|
|
106
|
+
await contract.initialize(hmTokenAddr, minimumStake, lockPeriod);
|
|
107
|
+
|
|
108
|
+
return contract;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* **Get Staking contract instance at given address**
|
|
113
|
+
*
|
|
114
|
+
* @param {string} stakingAddr Staking contract address
|
|
115
|
+
* @param {ethers.Signer | undefined} signer Deployer signer
|
|
116
|
+
* @returns {Promise<Staking>} Attached contract instance
|
|
117
|
+
*/
|
|
118
|
+
export const getStaking = async (
|
|
119
|
+
stakingAddr: string,
|
|
120
|
+
signer?: ethers.Signer
|
|
121
|
+
): Promise<Staking> => {
|
|
122
|
+
const factory = new Staking__factory(signer);
|
|
123
|
+
|
|
124
|
+
const contract = await factory.attach(stakingAddr);
|
|
125
|
+
|
|
126
|
+
return contract;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* **Deploy RewardPool contract**
|
|
131
|
+
*
|
|
132
|
+
* @param {string} hmTokenAddr HMToken address
|
|
133
|
+
* @param {string} stakingAddr Staking address
|
|
134
|
+
* @param {number} fee Reward fee of the protocol
|
|
135
|
+
* @param {ethers.Signer | undefined} signer Deployer signer
|
|
136
|
+
* @returns {Promise<Staking>} Deployed contract instance
|
|
137
|
+
*/
|
|
138
|
+
export const deployRewardPool = async (
|
|
139
|
+
hmTokenAddr: string,
|
|
140
|
+
stakingAddr: string,
|
|
141
|
+
fee: number,
|
|
142
|
+
signer?: ethers.Signer
|
|
143
|
+
): Promise<RewardPool> => {
|
|
144
|
+
const rewardPool = new RewardPool__factory(signer);
|
|
145
|
+
const contract = await rewardPool.deploy();
|
|
146
|
+
await contract.initialize(hmTokenAddr, stakingAddr, fee);
|
|
147
|
+
|
|
148
|
+
return contract;
|
|
149
|
+
};
|
|
150
|
+
|
|
84
151
|
/**
|
|
85
152
|
* **Get specific amount representation in given decimals**
|
|
86
153
|
*
|
package/test/job.test.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
DEFAULT_GAS_PAYER_ADDR,
|
|
7
7
|
DEFAULT_GAS_PAYER_PRIVKEY,
|
|
8
8
|
DEFAULT_HMTOKEN_ADDR,
|
|
9
|
+
DEFAULT_STAKING_ADDR,
|
|
9
10
|
NOT_TRUSTED_OPERATOR_PRIVKEY,
|
|
10
11
|
REPUTATION_ORACLE_PRIVKEY,
|
|
11
12
|
TRUSTED_OPERATOR1_ADDR,
|
|
@@ -29,6 +30,12 @@ jest.mock('../src/storage', () => ({
|
|
|
29
30
|
getPublicURL: jest.fn().mockResolvedValue('public-url'),
|
|
30
31
|
}));
|
|
31
32
|
|
|
33
|
+
const setupJob = async (job: Job) => {
|
|
34
|
+
await job.initialize();
|
|
35
|
+
await job.launch();
|
|
36
|
+
await job.setup();
|
|
37
|
+
};
|
|
38
|
+
|
|
32
39
|
describe('Test Job', () => {
|
|
33
40
|
describe('New job', () => {
|
|
34
41
|
let job: Job;
|
|
@@ -39,6 +46,7 @@ describe('Test Job', () => {
|
|
|
39
46
|
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
40
47
|
manifest: manifest,
|
|
41
48
|
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
49
|
+
stakingAddr: DEFAULT_STAKING_ADDR,
|
|
42
50
|
logLevel: 'debug',
|
|
43
51
|
});
|
|
44
52
|
});
|
|
@@ -54,11 +62,11 @@ describe('Test Job', () => {
|
|
|
54
62
|
expect(await job.contractData?.factory?.address).not.toBeNull();
|
|
55
63
|
});
|
|
56
64
|
|
|
57
|
-
it('Should be able to launch the job', async () => {
|
|
58
|
-
|
|
65
|
+
it('Should be able to launch the job after staking', async () => {
|
|
66
|
+
expect(await job.initialize()).toBe(true);
|
|
59
67
|
expect(await job.launch()).toBe(false);
|
|
60
68
|
|
|
61
|
-
await job.
|
|
69
|
+
await job.stake(1);
|
|
62
70
|
|
|
63
71
|
expect(await job.launch()).toBe(true);
|
|
64
72
|
expect(await job.status()).toBe(EscrowStatus.Launched);
|
|
@@ -92,9 +100,7 @@ describe('Test Job', () => {
|
|
|
92
100
|
});
|
|
93
101
|
|
|
94
102
|
it('Should be able to bulk payout workers', async () => {
|
|
95
|
-
await job
|
|
96
|
-
await job.launch();
|
|
97
|
-
await job.setup();
|
|
103
|
+
await setupJob(job);
|
|
98
104
|
|
|
99
105
|
expect(
|
|
100
106
|
await job.bulkPayout(
|
|
@@ -148,9 +154,7 @@ describe('Test Job', () => {
|
|
|
148
154
|
});
|
|
149
155
|
|
|
150
156
|
it('Should encrypt result, when bulk paying out workers', async () => {
|
|
151
|
-
await job
|
|
152
|
-
await job.launch();
|
|
153
|
-
await job.setup();
|
|
157
|
+
await setupJob(job);
|
|
154
158
|
|
|
155
159
|
jest.clearAllMocks();
|
|
156
160
|
const finalResults = { results: 0 };
|
|
@@ -176,9 +180,7 @@ describe('Test Job', () => {
|
|
|
176
180
|
});
|
|
177
181
|
|
|
178
182
|
it('Should not encrypt result, when bulk paying out workers', async () => {
|
|
179
|
-
await job
|
|
180
|
-
await job.launch();
|
|
181
|
-
await job.setup();
|
|
183
|
+
await setupJob(job);
|
|
182
184
|
|
|
183
185
|
jest.clearAllMocks();
|
|
184
186
|
const finalResults = { results: 0 };
|
|
@@ -204,9 +206,7 @@ describe('Test Job', () => {
|
|
|
204
206
|
});
|
|
205
207
|
|
|
206
208
|
it('Should store result in private storage, when bulk paying out workers', async () => {
|
|
207
|
-
await job
|
|
208
|
-
await job.launch();
|
|
209
|
-
await job.setup();
|
|
209
|
+
await setupJob(job);
|
|
210
210
|
|
|
211
211
|
jest.clearAllMocks();
|
|
212
212
|
const finalResults = { results: 0 };
|
|
@@ -233,9 +233,7 @@ describe('Test Job', () => {
|
|
|
233
233
|
});
|
|
234
234
|
|
|
235
235
|
it('Should store result in public storage, when bulk paying out workers', async () => {
|
|
236
|
-
await job
|
|
237
|
-
await job.launch();
|
|
238
|
-
await job.setup();
|
|
236
|
+
await setupJob(job);
|
|
239
237
|
|
|
240
238
|
jest.clearAllMocks();
|
|
241
239
|
const finalResults = { results: 0 };
|
|
@@ -263,9 +261,7 @@ describe('Test Job', () => {
|
|
|
263
261
|
});
|
|
264
262
|
|
|
265
263
|
it('Should return final result', async () => {
|
|
266
|
-
await job
|
|
267
|
-
await job.launch();
|
|
268
|
-
await job.setup();
|
|
264
|
+
await setupJob(job);
|
|
269
265
|
|
|
270
266
|
const finalResults = { results: 0 };
|
|
271
267
|
await job.bulkPayout(
|
|
@@ -285,17 +281,13 @@ describe('Test Job', () => {
|
|
|
285
281
|
});
|
|
286
282
|
|
|
287
283
|
it('Should be able to abort the job', async () => {
|
|
288
|
-
await job
|
|
289
|
-
await job.launch();
|
|
290
|
-
await job.setup();
|
|
284
|
+
await setupJob(job);
|
|
291
285
|
|
|
292
286
|
expect(await job.abort()).toBe(true);
|
|
293
287
|
});
|
|
294
288
|
|
|
295
289
|
it('Should be able to abort partially paid job', async () => {
|
|
296
|
-
await job
|
|
297
|
-
await job.launch();
|
|
298
|
-
await job.setup();
|
|
290
|
+
await setupJob(job);
|
|
299
291
|
|
|
300
292
|
const finalResults = { results: 0 };
|
|
301
293
|
await job.bulkPayout(
|
|
@@ -313,9 +305,7 @@ describe('Test Job', () => {
|
|
|
313
305
|
});
|
|
314
306
|
|
|
315
307
|
it('Should not be able to abort fully paid job', async () => {
|
|
316
|
-
await job
|
|
317
|
-
await job.launch();
|
|
318
|
-
await job.setup();
|
|
308
|
+
await setupJob(job);
|
|
319
309
|
|
|
320
310
|
const finalResults = { results: 0 };
|
|
321
311
|
await job.bulkPayout(
|
|
@@ -333,18 +323,14 @@ describe('Test Job', () => {
|
|
|
333
323
|
});
|
|
334
324
|
|
|
335
325
|
it('Should be able to cancel the job', async () => {
|
|
336
|
-
await job
|
|
337
|
-
await job.launch();
|
|
338
|
-
await job.setup();
|
|
326
|
+
await setupJob(job);
|
|
339
327
|
|
|
340
328
|
expect(await job.cancel()).toBe(true);
|
|
341
329
|
expect((await job.balance())?.toString()).toBe(toFullDigit(0).toString());
|
|
342
330
|
});
|
|
343
331
|
|
|
344
332
|
it('Should be able to cancel partially paid job', async () => {
|
|
345
|
-
await job
|
|
346
|
-
await job.launch();
|
|
347
|
-
await job.setup();
|
|
333
|
+
await setupJob(job);
|
|
348
334
|
|
|
349
335
|
const finalResults = { results: 0 };
|
|
350
336
|
await job.bulkPayout(
|
|
@@ -363,9 +349,7 @@ describe('Test Job', () => {
|
|
|
363
349
|
});
|
|
364
350
|
|
|
365
351
|
it('Should not be able to cancel paid job', async () => {
|
|
366
|
-
await job
|
|
367
|
-
await job.launch();
|
|
368
|
-
await job.setup();
|
|
352
|
+
await setupJob(job);
|
|
369
353
|
|
|
370
354
|
const finalResults = { results: 0 };
|
|
371
355
|
await job.bulkPayout(
|
|
@@ -381,6 +365,81 @@ describe('Test Job', () => {
|
|
|
381
365
|
|
|
382
366
|
expect(await job.cancel()).toBe(false);
|
|
383
367
|
});
|
|
368
|
+
|
|
369
|
+
it('Should be able to allocate token to the job', async () => {
|
|
370
|
+
await job.initialize();
|
|
371
|
+
|
|
372
|
+
expect(await job.launch()).toBe(true);
|
|
373
|
+
expect(await job.status()).toBe(EscrowStatus.Launched);
|
|
374
|
+
|
|
375
|
+
expect(await job.allocate(1)).toBe(true);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('Should be able to launch another job after allocating portion of the stake', async () => {
|
|
379
|
+
await job.initialize();
|
|
380
|
+
await job.stake(2);
|
|
381
|
+
|
|
382
|
+
expect(await job.launch()).toBe(true);
|
|
383
|
+
expect(await job.status()).toBe(EscrowStatus.Launched);
|
|
384
|
+
|
|
385
|
+
expect(await job.allocate(1)).toBe(true);
|
|
386
|
+
|
|
387
|
+
const newJob = new Job({
|
|
388
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
389
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
390
|
+
manifest: manifest,
|
|
391
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
392
|
+
stakingAddr: DEFAULT_STAKING_ADDR,
|
|
393
|
+
logLevel: 'error',
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
await newJob.initialize();
|
|
397
|
+
expect(await newJob.launch()).toBe(true);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('Should not be able to launch another job after allocating all of the stake', async () => {
|
|
401
|
+
await job.initialize();
|
|
402
|
+
|
|
403
|
+
expect(await job.launch()).toBe(true);
|
|
404
|
+
expect(await job.status()).toBe(EscrowStatus.Launched);
|
|
405
|
+
|
|
406
|
+
expect(await job.allocate(1)).toBe(true);
|
|
407
|
+
|
|
408
|
+
const newJob = new Job({
|
|
409
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
410
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
411
|
+
manifest: manifest,
|
|
412
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
413
|
+
stakingAddr: DEFAULT_STAKING_ADDR,
|
|
414
|
+
logLevel: 'error',
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
await newJob.initialize();
|
|
418
|
+
expect(await newJob.launch()).toBe(false);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('Should be able to launch another job after staking more tokens', async () => {
|
|
422
|
+
await job.initialize();
|
|
423
|
+
await job.stake(1);
|
|
424
|
+
|
|
425
|
+
expect(await job.launch()).toBe(true);
|
|
426
|
+
expect(await job.status()).toBe(EscrowStatus.Launched);
|
|
427
|
+
|
|
428
|
+
expect(await job.allocate(1)).toBe(true);
|
|
429
|
+
|
|
430
|
+
const newJob = new Job({
|
|
431
|
+
gasPayer: DEFAULT_GAS_PAYER_PRIVKEY,
|
|
432
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
433
|
+
manifest: manifest,
|
|
434
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
435
|
+
stakingAddr: DEFAULT_STAKING_ADDR,
|
|
436
|
+
logLevel: 'error',
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
await newJob.initialize();
|
|
440
|
+
await newJob.stake(1);
|
|
441
|
+
expect(await newJob.launch()).toBe(true);
|
|
442
|
+
});
|
|
384
443
|
});
|
|
385
444
|
|
|
386
445
|
describe('Access existing job from trusted handler', () => {
|
|
@@ -392,12 +451,14 @@ describe('Test Job', () => {
|
|
|
392
451
|
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
393
452
|
manifest: manifest,
|
|
394
453
|
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
454
|
+
stakingAddr: DEFAULT_STAKING_ADDR,
|
|
395
455
|
trustedHandlers: [TRUSTED_OPERATOR1_PRIVKEY],
|
|
396
456
|
logLevel: 'error',
|
|
397
457
|
});
|
|
398
458
|
|
|
399
459
|
await originalJob.initialize();
|
|
400
460
|
await originalJob.launch();
|
|
461
|
+
await originalJob.stake(1);
|
|
401
462
|
await originalJob.setup();
|
|
402
463
|
|
|
403
464
|
job = new Job({
|
|
@@ -407,7 +468,7 @@ describe('Test Job', () => {
|
|
|
407
468
|
escrowAddr: originalJob.contractData?.escrowAddr,
|
|
408
469
|
factoryAddr: originalJob.contractData?.factoryAddr,
|
|
409
470
|
trustedHandlers: [TRUSTED_OPERATOR1_PRIVKEY],
|
|
410
|
-
logLevel: '
|
|
471
|
+
logLevel: 'error',
|
|
411
472
|
});
|
|
412
473
|
});
|
|
413
474
|
|
|
@@ -416,8 +477,7 @@ describe('Test Job', () => {
|
|
|
416
477
|
});
|
|
417
478
|
|
|
418
479
|
it('Should be able to initializes the job by accessing existing escrow', async () => {
|
|
419
|
-
|
|
420
|
-
expect(initialized).toBe(true);
|
|
480
|
+
expect(await job.initialize()).toBe(true);
|
|
421
481
|
|
|
422
482
|
expect(await job.manifestData?.manifestlink?.url).toBe('uploaded-key');
|
|
423
483
|
expect(await job.manifestData?.manifestlink?.hash).toBe('uploaded-hash');
|
|
@@ -430,7 +490,7 @@ describe('Test Job', () => {
|
|
|
430
490
|
expect(await job.status()).toBe(EscrowStatus.Pending);
|
|
431
491
|
});
|
|
432
492
|
|
|
433
|
-
it('Should be able to setup the job again', async () => {
|
|
493
|
+
it('Should not be able to setup the job again', async () => {
|
|
434
494
|
await job.initialize();
|
|
435
495
|
|
|
436
496
|
expect(await job.setup()).toBe(false);
|
|
@@ -444,7 +504,6 @@ describe('Test Job', () => {
|
|
|
444
504
|
|
|
445
505
|
it('Should be able to add trusted handlers', async () => {
|
|
446
506
|
await job.initialize();
|
|
447
|
-
await job.launch();
|
|
448
507
|
|
|
449
508
|
expect(await job.isTrustedHandler(DEFAULT_GAS_PAYER_ADDR)).toBe(true);
|
|
450
509
|
|
|
@@ -461,8 +520,6 @@ describe('Test Job', () => {
|
|
|
461
520
|
|
|
462
521
|
it('Should be able to bulk payout workers', async () => {
|
|
463
522
|
await job.initialize();
|
|
464
|
-
await job.launch();
|
|
465
|
-
await job.setup();
|
|
466
523
|
|
|
467
524
|
expect(
|
|
468
525
|
await job.bulkPayout(
|
|
@@ -517,8 +574,6 @@ describe('Test Job', () => {
|
|
|
517
574
|
|
|
518
575
|
it('Should encrypt result, when bulk paying out workers', async () => {
|
|
519
576
|
await job.initialize();
|
|
520
|
-
await job.launch();
|
|
521
|
-
await job.setup();
|
|
522
577
|
|
|
523
578
|
jest.clearAllMocks();
|
|
524
579
|
const finalResults = { results: 0 };
|
|
@@ -545,8 +600,6 @@ describe('Test Job', () => {
|
|
|
545
600
|
|
|
546
601
|
it('Should not encrypt result, when bulk paying out workers', async () => {
|
|
547
602
|
await job.initialize();
|
|
548
|
-
await job.launch();
|
|
549
|
-
await job.setup();
|
|
550
603
|
|
|
551
604
|
jest.clearAllMocks();
|
|
552
605
|
const finalResults = { results: 0 };
|
|
@@ -573,8 +626,6 @@ describe('Test Job', () => {
|
|
|
573
626
|
|
|
574
627
|
it('Should store result in private storage, when bulk paying out workers', async () => {
|
|
575
628
|
await job.initialize();
|
|
576
|
-
await job.launch();
|
|
577
|
-
await job.setup();
|
|
578
629
|
|
|
579
630
|
jest.clearAllMocks();
|
|
580
631
|
const finalResults = { results: 0 };
|
|
@@ -602,8 +653,6 @@ describe('Test Job', () => {
|
|
|
602
653
|
|
|
603
654
|
it('Should store result in public storage, when bulk paying out workers', async () => {
|
|
604
655
|
await job.initialize();
|
|
605
|
-
await job.launch();
|
|
606
|
-
await job.setup();
|
|
607
656
|
|
|
608
657
|
jest.clearAllMocks();
|
|
609
658
|
const finalResults = { results: 0 };
|
|
@@ -632,8 +681,6 @@ describe('Test Job', () => {
|
|
|
632
681
|
|
|
633
682
|
it('Should return final result', async () => {
|
|
634
683
|
await job.initialize();
|
|
635
|
-
await job.launch();
|
|
636
|
-
await job.setup();
|
|
637
684
|
|
|
638
685
|
const finalResults = { results: 0 };
|
|
639
686
|
await job.bulkPayout(
|
|
@@ -654,16 +701,12 @@ describe('Test Job', () => {
|
|
|
654
701
|
|
|
655
702
|
it('Should be able to abort the job', async () => {
|
|
656
703
|
await job.initialize();
|
|
657
|
-
await job.launch();
|
|
658
|
-
await job.setup();
|
|
659
704
|
|
|
660
705
|
expect(await job.abort()).toBe(true);
|
|
661
706
|
});
|
|
662
707
|
|
|
663
708
|
it('Should be able to abort partially paid job', async () => {
|
|
664
709
|
await job.initialize();
|
|
665
|
-
await job.launch();
|
|
666
|
-
await job.setup();
|
|
667
710
|
|
|
668
711
|
const finalResults = { results: 0 };
|
|
669
712
|
await job.bulkPayout(
|
|
@@ -682,8 +725,6 @@ describe('Test Job', () => {
|
|
|
682
725
|
|
|
683
726
|
it('Should not be able to abort fully paid job', async () => {
|
|
684
727
|
await job.initialize();
|
|
685
|
-
await job.launch();
|
|
686
|
-
await job.setup();
|
|
687
728
|
|
|
688
729
|
const finalResults = { results: 0 };
|
|
689
730
|
await job.bulkPayout(
|
|
@@ -702,8 +743,6 @@ describe('Test Job', () => {
|
|
|
702
743
|
|
|
703
744
|
it('Should be able to cancel the job', async () => {
|
|
704
745
|
await job.initialize();
|
|
705
|
-
await job.launch();
|
|
706
|
-
await job.setup();
|
|
707
746
|
|
|
708
747
|
expect(await job.cancel()).toBe(true);
|
|
709
748
|
expect((await job.balance())?.toString()).toBe(toFullDigit(0).toString());
|
|
@@ -711,8 +750,6 @@ describe('Test Job', () => {
|
|
|
711
750
|
|
|
712
751
|
it('Should be able to cancel partially paid job', async () => {
|
|
713
752
|
await job.initialize();
|
|
714
|
-
await job.launch();
|
|
715
|
-
await job.setup();
|
|
716
753
|
|
|
717
754
|
const finalResults = { results: 0 };
|
|
718
755
|
await job.bulkPayout(
|
|
@@ -732,8 +769,6 @@ describe('Test Job', () => {
|
|
|
732
769
|
|
|
733
770
|
it('Should not be able to cancel paid job', async () => {
|
|
734
771
|
await job.initialize();
|
|
735
|
-
await job.launch();
|
|
736
|
-
await job.setup();
|
|
737
772
|
|
|
738
773
|
const finalResults = { results: 0 };
|
|
739
774
|
await job.bulkPayout(
|
|
@@ -749,5 +784,34 @@ describe('Test Job', () => {
|
|
|
749
784
|
|
|
750
785
|
expect(await job.cancel()).toBe(false);
|
|
751
786
|
});
|
|
787
|
+
|
|
788
|
+
it('Should not be able to allocate to job without staking', async () => {
|
|
789
|
+
await job.initialize();
|
|
790
|
+
expect(await job.allocate(1, TRUSTED_OPERATOR1_ADDR)).toBe(false);
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
it('Should be able to allocate to job after staking', async () => {
|
|
794
|
+
await job.initialize();
|
|
795
|
+
await job.stake(1, TRUSTED_OPERATOR1_ADDR);
|
|
796
|
+
|
|
797
|
+
expect(await job.allocate(1, TRUSTED_OPERATOR1_ADDR)).toBe(true);
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
it('Should be able to launch another job after staking', async () => {
|
|
801
|
+
await job.initialize();
|
|
802
|
+
await job.stake(1, TRUSTED_OPERATOR1_ADDR);
|
|
803
|
+
|
|
804
|
+
const newJob = new Job({
|
|
805
|
+
gasPayer: TRUSTED_OPERATOR1_PRIVKEY,
|
|
806
|
+
reputationOracle: REPUTATION_ORACLE_PRIVKEY,
|
|
807
|
+
manifest: manifest,
|
|
808
|
+
hmTokenAddr: DEFAULT_HMTOKEN_ADDR,
|
|
809
|
+
stakingAddr: DEFAULT_STAKING_ADDR,
|
|
810
|
+
logLevel: 'error',
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
await newJob.initialize();
|
|
814
|
+
expect(await newJob.launch()).toBe(true);
|
|
815
|
+
});
|
|
752
816
|
});
|
|
753
817
|
});
|
package/test/utils/constants.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export const DEFAULT_HMTOKEN_ADDR =
|
|
2
2
|
'0x5FbDB2315678afecb367f032d93F642f64180aa3';
|
|
3
3
|
|
|
4
|
+
export const DEFAULT_STAKING_ADDR =
|
|
5
|
+
'0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0';
|
|
6
|
+
|
|
4
7
|
export const DEFAULT_GAS_PAYER_ADDR =
|
|
5
8
|
'0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
|
|
6
9
|
export const DEFAULT_GAS_PAYER_PRIVKEY =
|