@human-protocol/sdk 1.0.2 → 1.0.25
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 +4 -4
- package/src/job.ts +140 -53
- package/test/job.test.ts +109 -8
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.0.
|
|
4
|
+
"version": "1.0.25",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
7
7
|
"dist",
|
|
@@ -38,7 +38,7 @@
|
|
|
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",
|
|
@@ -47,6 +47,6 @@
|
|
|
47
47
|
"winston": "^3.8.2"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@human-protocol/core": "^1.0.
|
|
50
|
+
"@human-protocol/core": "^1.0.12"
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|
package/src/job.ts
CHANGED
|
@@ -315,27 +315,32 @@ export class Job {
|
|
|
315
315
|
|
|
316
316
|
this._logger.info('Launching escrow...');
|
|
317
317
|
|
|
318
|
-
|
|
319
|
-
this.
|
|
320
|
-
(
|
|
321
|
-
|
|
322
|
-
|
|
318
|
+
try {
|
|
319
|
+
const txReceipt = await this.contractData?.factory?.createEscrow(
|
|
320
|
+
this.providerData?.trustedHandlers?.map(
|
|
321
|
+
(trustedHandler) => trustedHandler.address
|
|
322
|
+
) || []
|
|
323
|
+
);
|
|
323
324
|
|
|
324
|
-
|
|
325
|
+
const txResponse = await txReceipt?.wait();
|
|
325
326
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
327
|
+
const event = txResponse?.events?.find(
|
|
328
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
329
|
+
(event: any) => event.event === 'Launched'
|
|
330
|
+
);
|
|
330
331
|
|
|
331
|
-
|
|
332
|
-
|
|
332
|
+
const escrowAddr = event?.args?.[1];
|
|
333
|
+
this._logger.info(`Escrow is deployed at ${escrowAddr}.`);
|
|
333
334
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
+
}
|
|
339
344
|
|
|
340
345
|
return (
|
|
341
346
|
(await this.status()) == EscrowStatus.Launched &&
|
|
@@ -679,9 +684,10 @@ export class Job {
|
|
|
679
684
|
* **Stake HMTokens**
|
|
680
685
|
*
|
|
681
686
|
* @param {number} amount - Amount to stake
|
|
687
|
+
* @param {string | undefined} from - Address to stake
|
|
682
688
|
* @returns {Promise<boolean>} - True if the token is staked
|
|
683
689
|
*/
|
|
684
|
-
async stake(amount: number) {
|
|
690
|
+
async stake(amount: number, from?: string) {
|
|
685
691
|
if (!this.contractData?.staking) {
|
|
686
692
|
this._logError(ErrorStakingMissing);
|
|
687
693
|
return false;
|
|
@@ -691,63 +697,104 @@ export class Job {
|
|
|
691
697
|
return false;
|
|
692
698
|
}
|
|
693
699
|
|
|
694
|
-
const
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
700
|
+
const operator = this._findOperator(from);
|
|
701
|
+
|
|
702
|
+
if (!operator) {
|
|
703
|
+
this._logError(new Error('Unknown wallet'));
|
|
704
|
+
return false;
|
|
705
|
+
}
|
|
698
706
|
|
|
699
|
-
|
|
707
|
+
try {
|
|
708
|
+
const approved = await this.contractData.hmToken
|
|
709
|
+
.connect(operator)
|
|
710
|
+
.approve(this.contractData.staking.address, toFullDigit(amount));
|
|
711
|
+
|
|
712
|
+
if (!approved) {
|
|
713
|
+
throw new Error('Not approved');
|
|
714
|
+
}
|
|
715
|
+
} catch {
|
|
700
716
|
this._logError(new Error('Error approving HMTokens for staking'));
|
|
701
717
|
return false;
|
|
702
718
|
}
|
|
703
719
|
|
|
704
|
-
|
|
705
|
-
this.contractData.staking
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
720
|
+
try {
|
|
721
|
+
await this.contractData.staking
|
|
722
|
+
.connect(operator)
|
|
723
|
+
.stake(toFullDigit(amount));
|
|
724
|
+
} catch {
|
|
725
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
726
|
+
return false;
|
|
727
|
+
}
|
|
728
|
+
return true;
|
|
709
729
|
}
|
|
710
730
|
|
|
711
731
|
/**
|
|
712
732
|
* **Unstake HMTokens**
|
|
713
733
|
*
|
|
714
734
|
* @param {number} amount - Amount to unstake
|
|
735
|
+
* @param {string | undefined} from - Address to unstake
|
|
715
736
|
* @returns {Promise<boolean>} - True if the token is unstaked
|
|
716
737
|
*/
|
|
717
|
-
async unstake(amount: number) {
|
|
738
|
+
async unstake(amount: number, from?: string) {
|
|
718
739
|
if (!this.contractData?.staking) {
|
|
719
740
|
this._logError(ErrorStakingMissing);
|
|
720
741
|
return false;
|
|
721
742
|
}
|
|
722
743
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
744
|
+
const operator = this._findOperator(from);
|
|
745
|
+
|
|
746
|
+
if (!operator) {
|
|
747
|
+
this._logError(new Error('Unknown wallet'));
|
|
748
|
+
return false;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
try {
|
|
752
|
+
await this.contractData.staking
|
|
753
|
+
.connect(operator)
|
|
754
|
+
.unstake(toFullDigit(amount));
|
|
755
|
+
} catch {
|
|
756
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
return true;
|
|
728
760
|
}
|
|
729
761
|
|
|
730
762
|
/**
|
|
731
763
|
* **Withdraw unstaked HMTokens**
|
|
732
764
|
*
|
|
765
|
+
* @param {string | undefined} from - Address to withdraw
|
|
733
766
|
* @returns {Promise<boolean>} - True if the token is withdrawn
|
|
734
767
|
*/
|
|
735
|
-
async withdraw() {
|
|
768
|
+
async withdraw(from?: string) {
|
|
736
769
|
if (!this.contractData?.staking) {
|
|
737
770
|
this._logError(ErrorStakingMissing);
|
|
738
771
|
return false;
|
|
739
772
|
}
|
|
740
773
|
|
|
741
|
-
|
|
774
|
+
const operator = this._findOperator(from);
|
|
775
|
+
|
|
776
|
+
if (!operator) {
|
|
777
|
+
this._logError(new Error('Unknown wallet'));
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
try {
|
|
782
|
+
await this.contractData.staking.connect(operator).withdraw();
|
|
783
|
+
} catch {
|
|
784
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
785
|
+
return false;
|
|
786
|
+
}
|
|
787
|
+
return true;
|
|
742
788
|
}
|
|
743
789
|
|
|
744
790
|
/**
|
|
745
791
|
* **Allocate HMTokens staked to the job**
|
|
746
792
|
*
|
|
747
|
-
* @param amount - Amount to allocate
|
|
793
|
+
* @param {number} amount - Amount to allocate
|
|
794
|
+
* @param {string | undefined} - Address to allocate with
|
|
748
795
|
* @returns {Promise<boolean>} - True if the token is allocated
|
|
749
796
|
*/
|
|
750
|
-
async allocate(amount: number) {
|
|
797
|
+
async allocate(amount: number, from?: string) {
|
|
751
798
|
if (!this.contractData?.staking) {
|
|
752
799
|
this._logError(ErrorStakingMissing);
|
|
753
800
|
return false;
|
|
@@ -758,20 +805,31 @@ export class Job {
|
|
|
758
805
|
return false;
|
|
759
806
|
}
|
|
760
807
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
this.
|
|
765
|
-
|
|
766
|
-
|
|
808
|
+
const operator = this._findOperator(from);
|
|
809
|
+
|
|
810
|
+
if (!operator) {
|
|
811
|
+
this._logError(new Error('Unknown wallet'));
|
|
812
|
+
return false;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
try {
|
|
816
|
+
await this.contractData.staking
|
|
817
|
+
.connect(operator)
|
|
818
|
+
.allocate(this.contractData.escrowAddr, toFullDigit(amount));
|
|
819
|
+
} catch {
|
|
820
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
821
|
+
return false;
|
|
822
|
+
}
|
|
823
|
+
return true;
|
|
767
824
|
}
|
|
768
825
|
|
|
769
826
|
/**
|
|
770
827
|
* **Unallocate HMTokens from the job**
|
|
771
828
|
*
|
|
829
|
+
* @param {string | undefined} - Address to close allocation with
|
|
772
830
|
* @returns {Promise<boolean>} - True if the token is unallocated.
|
|
773
831
|
*/
|
|
774
|
-
async closeAllocation() {
|
|
832
|
+
async closeAllocation(from?: string) {
|
|
775
833
|
if (!this.contractData?.staking) {
|
|
776
834
|
this._logError(ErrorStakingMissing);
|
|
777
835
|
return false;
|
|
@@ -782,11 +840,22 @@ export class Job {
|
|
|
782
840
|
return false;
|
|
783
841
|
}
|
|
784
842
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
this.
|
|
789
|
-
|
|
843
|
+
const operator = this._findOperator(from);
|
|
844
|
+
|
|
845
|
+
if (!operator) {
|
|
846
|
+
this._logError(new Error('Unknown wallet'));
|
|
847
|
+
return false;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
try {
|
|
851
|
+
await this.contractData.staking
|
|
852
|
+
.connect(operator)
|
|
853
|
+
.closeAllocation(this.contractData.escrowAddr);
|
|
854
|
+
} catch {
|
|
855
|
+
this._logError(new Error(`Error executing transaction from ${from}`));
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
return true;
|
|
790
859
|
}
|
|
791
860
|
|
|
792
861
|
/**
|
|
@@ -959,8 +1028,10 @@ export class Job {
|
|
|
959
1028
|
await contract.connect(trustedHandler).functions[functionName](...args);
|
|
960
1029
|
return true;
|
|
961
1030
|
} catch (err) {
|
|
962
|
-
|
|
963
|
-
|
|
1031
|
+
this._logError(
|
|
1032
|
+
new Error(
|
|
1033
|
+
'Error executing the transaction from all of the trusted handlers. Stop continue executing...'
|
|
1034
|
+
)
|
|
964
1035
|
);
|
|
965
1036
|
}
|
|
966
1037
|
}
|
|
@@ -969,9 +1040,25 @@ export class Job {
|
|
|
969
1040
|
|
|
970
1041
|
/**
|
|
971
1042
|
* **Error log**
|
|
1043
|
+
*
|
|
972
1044
|
* @param {Error} error - Occured error
|
|
973
1045
|
*/
|
|
974
|
-
private
|
|
1046
|
+
private _logError(error: Error) {
|
|
975
1047
|
this._logger.error(error.message);
|
|
976
1048
|
}
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* **Find operator to execute tx**
|
|
1052
|
+
*
|
|
1053
|
+
* @param {string} addr - Address of the operator
|
|
1054
|
+
* @returns {ethers.Wallet | undefined} - Operator wallet
|
|
1055
|
+
*/
|
|
1056
|
+
private _findOperator(addr?: string): ethers.Wallet | undefined {
|
|
1057
|
+
return addr
|
|
1058
|
+
? [
|
|
1059
|
+
this.providerData?.gasPayer,
|
|
1060
|
+
...(this.providerData?.trustedHandlers || []),
|
|
1061
|
+
].find((account?: ethers.Wallet) => account?.address === addr)
|
|
1062
|
+
: this.providerData?.gasPayer;
|
|
1063
|
+
}
|
|
977
1064
|
}
|
package/test/job.test.ts
CHANGED
|
@@ -32,7 +32,6 @@ jest.mock('../src/storage', () => ({
|
|
|
32
32
|
|
|
33
33
|
const setupJob = async (job: Job) => {
|
|
34
34
|
await job.initialize();
|
|
35
|
-
await job.stake(1);
|
|
36
35
|
await job.launch();
|
|
37
36
|
await job.setup();
|
|
38
37
|
};
|
|
@@ -64,10 +63,9 @@ describe('Test Job', () => {
|
|
|
64
63
|
});
|
|
65
64
|
|
|
66
65
|
it('Should be able to launch the job after staking', async () => {
|
|
67
|
-
|
|
66
|
+
expect(await job.initialize()).toBe(true);
|
|
68
67
|
expect(await job.launch()).toBe(false);
|
|
69
68
|
|
|
70
|
-
await job.initialize();
|
|
71
69
|
await job.stake(1);
|
|
72
70
|
|
|
73
71
|
expect(await job.launch()).toBe(true);
|
|
@@ -79,8 +77,6 @@ describe('Test Job', () => {
|
|
|
79
77
|
expect(await job.setup()).toBe(false);
|
|
80
78
|
|
|
81
79
|
await job.initialize();
|
|
82
|
-
await job.stake(1);
|
|
83
|
-
|
|
84
80
|
await job.launch();
|
|
85
81
|
|
|
86
82
|
expect(await job.setup()).toBe(true);
|
|
@@ -88,8 +84,6 @@ describe('Test Job', () => {
|
|
|
88
84
|
|
|
89
85
|
it('Should be able to add trusted handlers', async () => {
|
|
90
86
|
await job.initialize();
|
|
91
|
-
await job.stake(1);
|
|
92
|
-
|
|
93
87
|
await job.launch();
|
|
94
88
|
|
|
95
89
|
expect(await job.isTrustedHandler(DEFAULT_GAS_PAYER_ADDR)).toBe(true);
|
|
@@ -371,6 +365,81 @@ describe('Test Job', () => {
|
|
|
371
365
|
|
|
372
366
|
expect(await job.cancel()).toBe(false);
|
|
373
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
|
+
});
|
|
374
443
|
});
|
|
375
444
|
|
|
376
445
|
describe('Access existing job from trusted handler', () => {
|
|
@@ -387,7 +456,10 @@ describe('Test Job', () => {
|
|
|
387
456
|
logLevel: 'error',
|
|
388
457
|
});
|
|
389
458
|
|
|
390
|
-
await
|
|
459
|
+
await originalJob.initialize();
|
|
460
|
+
await originalJob.launch();
|
|
461
|
+
await originalJob.stake(1);
|
|
462
|
+
await originalJob.setup();
|
|
391
463
|
|
|
392
464
|
job = new Job({
|
|
393
465
|
gasPayer: NOT_TRUSTED_OPERATOR_PRIVKEY,
|
|
@@ -712,5 +784,34 @@ describe('Test Job', () => {
|
|
|
712
784
|
|
|
713
785
|
expect(await job.cancel()).toBe(false);
|
|
714
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
|
+
});
|
|
715
816
|
});
|
|
716
817
|
});
|