@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.
Files changed (3) hide show
  1. package/package.json +4 -4
  2. package/src/job.ts +140 -53
  3. 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.2",
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.11",
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.11"
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
- const txReceipt = await this.contractData?.factory?.createEscrow(
319
- this.providerData?.trustedHandlers?.map(
320
- (trustedHandler) => trustedHandler.address
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
- const txResponse = await txReceipt?.wait();
325
+ const txResponse = await txReceipt?.wait();
325
326
 
326
- const event = txResponse?.events?.find(
327
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
328
- (event: any) => event.event === 'Launched'
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
- const escrowAddr = event?.args?.[1];
332
- this._logger.info(`Escrow is deployed at ${escrowAddr}.`);
332
+ const escrowAddr = event?.args?.[1];
333
+ this._logger.info(`Escrow is deployed at ${escrowAddr}.`);
333
334
 
334
- this.contractData.escrowAddr = escrowAddr;
335
- this.contractData.escrow = await getEscrow(
336
- escrowAddr,
337
- this.providerData?.gasPayer
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 approved = await this.contractData.hmToken.approve(
695
- this.contractData.staking.address,
696
- toFullDigit(amount)
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
- if (!approved) {
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
- return await this._raffleExecute(
705
- this.contractData.staking,
706
- 'stake',
707
- toFullDigit(amount)
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
- return await this._raffleExecute(
724
- this.contractData.staking,
725
- 'unstake',
726
- toFullDigit(amount)
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
- return await this._raffleExecute(this.contractData.staking, 'withdraw');
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
- return await this._raffleExecute(
762
- this.contractData.staking,
763
- 'allocate',
764
- this.contractData.escrowAddr,
765
- toFullDigit(amount)
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
- return await this._raffleExecute(
786
- this.contractData.staking,
787
- 'closeAllocation',
788
- this.contractData.escrowAddr
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
- new Error(
963
- 'Error executing the transaction from all of the trusted handlers. Stop continue executing...'
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 async _logError(error: Error) {
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
- // Fail to launch the job before initialization
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 setupJob(originalJob);
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
  });