diff --git a/docs/sdk/typescript/classes/base.BaseEthersClient.md b/docs/sdk/typescript/classes/base.BaseEthersClient.md new file mode 100644 index 0000000000..a5a263a6d8 --- /dev/null +++ b/docs/sdk/typescript/classes/base.BaseEthersClient.md @@ -0,0 +1,103 @@ +[@human-protocol/sdk](../README.md) / [Modules](../modules.md) / [base](../modules/base.md) / BaseEthersClient + +# Class: BaseEthersClient + +[base](../modules/base.md).BaseEthersClient + +## Introduction + +This class is used as a base class for other clients making on-chain calls. + +## Hierarchy + +- **`BaseEthersClient`** + + ↳ [`EscrowClient`](escrow.EscrowClient.md) + + ↳ [`KVStoreClient`](kvstore.KVStoreClient.md) + + ↳ [`StakingClient`](staking.StakingClient.md) + +## Table of contents + +### Constructors + +- [constructor](base.BaseEthersClient.md#constructor) + +### Properties + +- [gasPriceMultiplier](base.BaseEthersClient.md#gaspricemultiplier) +- [networkData](base.BaseEthersClient.md#networkdata) +- [signerOrProvider](base.BaseEthersClient.md#signerorprovider) + +### Methods + +- [gasPriceOptions](base.BaseEthersClient.md#gaspriceoptions) + +## Constructors + +### constructor + +• **new BaseEthersClient**(`signerOrProvider`, `networkData`, `gasPriceMultiplier?`) + +**BaseClient constructor** + +#### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `signerOrProvider` | `Signer` \| `Provider` | The Signer or Provider object to interact with the Ethereum network | +| `networkData` | `NetworkData` | The network information required to connect to the contracts | +| `gasPriceMultiplier?` | `number` | The multiplier to apply to the gas price | + +#### Defined in + +base.ts:24 + +## Properties + +### gasPriceMultiplier + +• `Protected` `Optional` **gasPriceMultiplier**: `number` + +#### Defined in + +base.ts:14 + +___ + +### networkData + +• **networkData**: `NetworkData` + +#### Defined in + +base.ts:15 + +___ + +### signerOrProvider + +• `Protected` **signerOrProvider**: `Signer` \| `Provider` + +#### Defined in + +base.ts:13 + +## Methods + +### gasPriceOptions + +▸ `Protected` **gasPriceOptions**(): `Promise`<`Partial`<`Overrides`\>\> + +Adjust the gas price, and return as an option to be passed to a transaction + +#### Returns + +`Promise`<`Partial`<`Overrides`\>\> + +Returns the gas price options + +#### Defined in + +base.ts:39 diff --git a/docs/sdk/typescript/classes/encryption.Encryption.md b/docs/sdk/typescript/classes/encryption.Encryption.md index 56dc23886a..694997c307 100644 --- a/docs/sdk/typescript/classes/encryption.Encryption.md +++ b/docs/sdk/typescript/classes/encryption.Encryption.md @@ -77,7 +77,7 @@ Constructor for the Encryption class. #### Defined in -[encryption.ts:53](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L53) +[encryption.ts:53](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L53) ## Properties @@ -87,7 +87,7 @@ Constructor for the Encryption class. #### Defined in -[encryption.ts:46](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L46) +[encryption.ts:46](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L46) ## Methods @@ -136,7 +136,7 @@ const resultMessage = await encription.decrypt('message'); #### Defined in -[encryption.ts:180](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L180) +[encryption.ts:180](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L180) ___ @@ -172,7 +172,7 @@ const resultMessage = await encription.sign('message'); #### Defined in -[encryption.ts:217](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L217) +[encryption.ts:217](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L217) ___ @@ -234,7 +234,7 @@ const resultMessage = await encription.signAndEncrypt('message', publicKeys); #### Defined in -[encryption.ts:129](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L129) +[encryption.ts:129](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L129) ___ @@ -259,4 +259,4 @@ Builds an Encryption instance by decrypting the private key from an encrypted pr #### Defined in -[encryption.ts:64](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L64) +[encryption.ts:64](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L64) diff --git a/docs/sdk/typescript/classes/encryption.EncryptionUtils.md b/docs/sdk/typescript/classes/encryption.EncryptionUtils.md index 461343dd90..4ad2b4d263 100644 --- a/docs/sdk/typescript/classes/encryption.EncryptionUtils.md +++ b/docs/sdk/typescript/classes/encryption.EncryptionUtils.md @@ -103,7 +103,7 @@ const result = await EncriptionUtils.encrypt('message', publicKeys); #### Defined in -[encryption.ts:422](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L422) +[encryption.ts:422](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L422) ___ @@ -152,7 +152,7 @@ const result = await EncriptionUtils.generateKeyPair(name, email, passphrase); #### Defined in -[encryption.ts:360](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L360) +[encryption.ts:360](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L360) ___ @@ -184,7 +184,7 @@ const signedData = await EncriptionUtils.getSignedData('message'); #### Defined in -[encryption.ts:317](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L317) +[encryption.ts:317](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L317) ___ @@ -229,4 +229,4 @@ const result = await EncriptionUtils.verify('message', publicKey); #### Defined in -[encryption.ts:284](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L284) +[encryption.ts:284](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L284) diff --git a/docs/sdk/typescript/classes/escrow.EscrowClient.md b/docs/sdk/typescript/classes/escrow.EscrowClient.md index 4a6ae3ab03..2eb37dd1bc 100644 --- a/docs/sdk/typescript/classes/escrow.EscrowClient.md +++ b/docs/sdk/typescript/classes/escrow.EscrowClient.md @@ -72,6 +72,12 @@ const provider = new providers.JsonRpcProvider(rpcUrl); const escrowClient = await EscrowClient.build(provider); ``` +## Hierarchy + +- [`BaseEthersClient`](base.BaseEthersClient.md) + + ↳ **`EscrowClient`** + ## Table of contents ### Constructors @@ -80,9 +86,9 @@ const escrowClient = await EscrowClient.build(provider); ### Properties -- [escrowContract](escrow.EscrowClient.md#escrowcontract) - [escrowFactoryContract](escrow.EscrowClient.md#escrowfactorycontract) -- [network](escrow.EscrowClient.md#network) +- [gasPriceMultiplier](escrow.EscrowClient.md#gaspricemultiplier) +- [networkData](escrow.EscrowClient.md#networkdata) - [signerOrProvider](escrow.EscrowClient.md#signerorprovider) ### Methods @@ -95,7 +101,9 @@ const escrowClient = await EscrowClient.build(provider); - [createAndSetupEscrow](escrow.EscrowClient.md#createandsetupescrow) - [createEscrow](escrow.EscrowClient.md#createescrow) - [fund](escrow.EscrowClient.md#fund) +- [gasPriceOptions](escrow.EscrowClient.md#gaspriceoptions) - [getBalance](escrow.EscrowClient.md#getbalance) +- [getEscrowContract](escrow.EscrowClient.md#getescrowcontract) - [getExchangeOracleAddress](escrow.EscrowClient.md#getexchangeoracleaddress) - [getFactoryAddress](escrow.EscrowClient.md#getfactoryaddress) - [getIntermediateResultsUrl](escrow.EscrowClient.md#getintermediateresultsurl) @@ -115,7 +123,7 @@ const escrowClient = await EscrowClient.build(provider); ### constructor -• **new EscrowClient**(`signerOrProvider`, `network`) +• **new EscrowClient**(`signerOrProvider`, `networkData`, `gasPriceMultiplier?`) **EscrowClient constructor** @@ -124,51 +132,68 @@ const escrowClient = await EscrowClient.build(provider); | Name | Type | Description | | :------ | :------ | :------ | | `signerOrProvider` | `Signer` \| `Provider` | The Signer or Provider object to interact with the Ethereum network | -| `network` | `NetworkData` | The network information required to connect to the Escrow contract | +| `networkData` | `NetworkData` | - | +| `gasPriceMultiplier?` | `number` | The multiplier to apply to the gas price | + +#### Overrides + +[BaseEthersClient](base.BaseEthersClient.md).[constructor](base.BaseEthersClient.md#constructor) #### Defined in -[escrow.ts:131](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L131) +[escrow.ts:130](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L130) ## Properties -### escrowContract +### escrowFactoryContract -• `Private` `Optional` **escrowContract**: `Escrow` +• `Private` **escrowFactoryContract**: `EscrowFactory` #### Defined in -[escrow.ts:121](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L121) +[escrow.ts:121](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L121) ___ -### escrowFactoryContract +### gasPriceMultiplier -• `Private` **escrowFactoryContract**: `EscrowFactory` +• `Protected` `Optional` **gasPriceMultiplier**: `number` + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[gasPriceMultiplier](base.BaseEthersClient.md#gaspricemultiplier) #### Defined in -[escrow.ts:120](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L120) +base.ts:14 ___ -### network +### networkData + +• **networkData**: `NetworkData` -• **network**: `NetworkData` +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[networkData](base.BaseEthersClient.md#networkdata) #### Defined in -[escrow.ts:123](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L123) +base.ts:15 ___ ### signerOrProvider -• `Private` **signerOrProvider**: `Signer` \| `Provider` +• `Protected` **signerOrProvider**: `Signer` \| `Provider` + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[signerOrProvider](base.BaseEthersClient.md#signerorprovider) #### Defined in -[escrow.ts:122](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L122) +base.ts:13 ## Methods @@ -210,7 +235,7 @@ await escrowClient.abort('0x62dD51230A30401C455c8398d06F85e4EaB6309f'); #### Defined in -[escrow.ts:810](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L810) +[escrow.ts:835](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L835) ___ @@ -254,7 +279,7 @@ await escrowClient.addTrustedHandlers('0x62dD51230A30401C455c8398d06F85e4EaB6309 #### Defined in -[escrow.ts:859](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L859) +[escrow.ts:884](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L884) ___ @@ -305,7 +330,7 @@ await escrowClient.bulkPayOut('0x62dD51230A30401C455c8398d06F85e4EaB6309f', reci #### Defined in -[escrow.ts:631](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L631) +[escrow.ts:655](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L655) ___ @@ -347,7 +372,7 @@ await escrowClient.cancel('0x62dD51230A30401C455c8398d06F85e4EaB6309f'); #### Defined in -[escrow.ts:732](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L732) +[escrow.ts:757](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L757) ___ @@ -389,7 +414,7 @@ await escrowClient.complete('0x62dD51230A30401C455c8398d06F85e4EaB6309f'); #### Defined in -[escrow.ts:575](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L575) +[escrow.ts:599](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L599) ___ @@ -447,7 +472,7 @@ const escrowAddress = await escrowClient.createAndSetupEscrow(tokenAddress, trus #### Defined in -[escrow.ts:402](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L402) +[escrow.ts:427](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L427) ___ @@ -494,7 +519,7 @@ const escrowAddress = await escrowClient.createEscrow(tokenAddress, trustedHandl #### Defined in -[escrow.ts:201](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L201) +[escrow.ts:222](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L222) ___ @@ -536,7 +561,29 @@ await escrowClient.fund('0x62dD51230A30401C455c8398d06F85e4EaB6309f', amount); #### Defined in -[escrow.ts:449](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L449) +[escrow.ts:474](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L474) + +___ + +### gasPriceOptions + +▸ `Protected` **gasPriceOptions**(): `Promise`<`Partial`<`Overrides`\>\> + +Adjust the gas price, and return as an option to be passed to a transaction + +#### Returns + +`Promise`<`Partial`<`Overrides`\>\> + +Returns the gas price options + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[gasPriceOptions](base.BaseEthersClient.md#gaspriceoptions) + +#### Defined in + +base.ts:39 ___ @@ -574,7 +621,29 @@ const balance = await escrowClient.getBalance('0x62dD51230A30401C455c8398d06F85e #### Defined in -[escrow.ts:913](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L913) +[escrow.ts:938](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L938) + +___ + +### getEscrowContract + +▸ `Private` **getEscrowContract**(`escrowAddress`): `Escrow` + +Connects to the escrow contract + +#### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `escrowAddress` | `string` | Escrow address to connect to | + +#### Returns + +`Escrow` + +#### Defined in + +[escrow.ts:183](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L183) ___ @@ -612,7 +681,7 @@ const oracleAddress = await escrowClient.getExchangeOracleAddress('0x62dD51230A3 #### Defined in -[escrow.ts:1313](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1313) +[escrow.ts:1318](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1318) ___ @@ -650,7 +719,7 @@ const factoryAddress = await escrowClient.getFactoryAddress('0x62dD51230A30401C4 #### Defined in -[escrow.ts:1353](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1353) +[escrow.ts:1356](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1356) ___ @@ -688,7 +757,7 @@ const intemediateResultsUrl = await escrowClient.getIntermediateResultsUrl('0x62 #### Defined in -[escrow.ts:1073](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1073) +[escrow.ts:1090](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1090) ___ @@ -726,7 +795,7 @@ const jobLauncherAddress = await escrowClient.getJobLauncherAddress('0x62dD51230 #### Defined in -[escrow.ts:1233](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1233) +[escrow.ts:1242](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1242) ___ @@ -764,7 +833,7 @@ const manifestHash = await escrowClient.getManifestHash('0x62dD51230A30401C455c8 #### Defined in -[escrow.ts:953](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L953) +[escrow.ts:976](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L976) ___ @@ -802,7 +871,7 @@ const manifestUrl = await escrowClient.getManifestUrl('0x62dD51230A30401C455c839 #### Defined in -[escrow.ts:993](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L993) +[escrow.ts:1014](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1014) ___ @@ -840,7 +909,7 @@ const oracleAddress = await escrowClient.getRecordingOracleAddress('0x62dD51230A #### Defined in -[escrow.ts:1193](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1193) +[escrow.ts:1204](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1204) ___ @@ -878,7 +947,7 @@ const oracleAddress = await escrowClient.getReputationOracleAddress('0x62dD51230 #### Defined in -[escrow.ts:1273](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1273) +[escrow.ts:1280](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1280) ___ @@ -916,7 +985,7 @@ const resultsUrl = await escrowClient.getResultsUrl('0x62dD51230A30401C455c8398d #### Defined in -[escrow.ts:1033](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1033) +[escrow.ts:1052](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1052) ___ @@ -954,7 +1023,7 @@ const status = await escrowClient.getStatus('0x62dD51230A30401C455c8398d06F85e4E #### Defined in -[escrow.ts:1153](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1153) +[escrow.ts:1166](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1166) ___ @@ -992,7 +1061,7 @@ const tokenAddress = await escrowClient.getTokenAddress('0x62dD51230A30401C455c8 #### Defined in -[escrow.ts:1113](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1113) +[escrow.ts:1128](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1128) ___ @@ -1046,7 +1115,7 @@ await escrowClient.setup(escrowAddress, escrowConfig); #### Defined in -[escrow.ts:277](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L277) +[escrow.ts:301](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L301) ___ @@ -1090,13 +1159,13 @@ await storeResults.storeResults('0x62dD51230A30401C455c8398d06F85e4EaB6309f', 'h #### Defined in -[escrow.ts:511](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L511) +[escrow.ts:535](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L535) ___ ### build -▸ `Static` **build**(`signerOrProvider`): `Promise`<[`EscrowClient`](escrow.EscrowClient.md)\> +▸ `Static` **build**(`signerOrProvider`, `gasPriceMultiplier?`): `Promise`<[`EscrowClient`](escrow.EscrowClient.md)\> Creates an instance of EscrowClient from a Signer or Provider. @@ -1105,6 +1174,7 @@ Creates an instance of EscrowClient from a Signer or Provider. | Name | Type | Description | | :------ | :------ | :------ | | `signerOrProvider` | `Signer` \| `Provider` | The Signer or Provider object to interact with the Ethereum network | +| `gasPriceMultiplier?` | `number` | The multiplier to apply to the gas price | #### Returns @@ -1122,4 +1192,4 @@ Thrown if the network's chainId is not supported #### Defined in -[escrow.ts:148](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L148) +[escrow.ts:153](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L153) diff --git a/docs/sdk/typescript/classes/escrow.EscrowUtils.md b/docs/sdk/typescript/classes/escrow.EscrowUtils.md index a4dca3d213..b9ab9ec95a 100644 --- a/docs/sdk/typescript/classes/escrow.EscrowUtils.md +++ b/docs/sdk/typescript/classes/escrow.EscrowUtils.md @@ -134,7 +134,7 @@ const escrowData = new EscrowUtils.getEscrow(ChainId.POLYGON_MUMBAI, "0x12345678 #### Defined in -[escrow.ts:1640](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1640) +[escrow.ts:1641](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1641) ___ @@ -247,4 +247,4 @@ const escrowDatas = await EscrowUtils.getEscrows(filters); #### Defined in -[escrow.ts:1503](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1503) +[escrow.ts:1504](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1504) diff --git a/docs/sdk/typescript/classes/kvstore.KVStoreClient.md b/docs/sdk/typescript/classes/kvstore.KVStoreClient.md index cfa70b1e68..f84ffbfa38 100644 --- a/docs/sdk/typescript/classes/kvstore.KVStoreClient.md +++ b/docs/sdk/typescript/classes/kvstore.KVStoreClient.md @@ -72,6 +72,12 @@ const provider = new providers.JsonRpcProvider(rpcUrl); const kvstoreClient = await KVStoreClient.build(signer); ``` +## Hierarchy + +- [`BaseEthersClient`](base.BaseEthersClient.md) + + ↳ **`KVStoreClient`** + ## Table of contents ### Constructors @@ -81,10 +87,13 @@ const kvstoreClient = await KVStoreClient.build(signer); ### Properties - [contract](kvstore.KVStoreClient.md#contract) +- [gasPriceMultiplier](kvstore.KVStoreClient.md#gaspricemultiplier) +- [networkData](kvstore.KVStoreClient.md#networkdata) - [signerOrProvider](kvstore.KVStoreClient.md#signerorprovider) ### Methods +- [gasPriceOptions](kvstore.KVStoreClient.md#gaspriceoptions) - [get](kvstore.KVStoreClient.md#get) - [getURL](kvstore.KVStoreClient.md#geturl) - [set](kvstore.KVStoreClient.md#set) @@ -96,7 +105,7 @@ const kvstoreClient = await KVStoreClient.build(signer); ### constructor -• **new KVStoreClient**(`signerOrProvider`, `network`) +• **new KVStoreClient**(`signerOrProvider`, `networkData`, `gasPriceMultiplier?`) **KVStoreClient constructor** @@ -105,11 +114,16 @@ const kvstoreClient = await KVStoreClient.build(signer); | Name | Type | Description | | :------ | :------ | :------ | | `signerOrProvider` | `Signer` \| `Provider` | The Signer or Provider object to interact with the Ethereum network | -| `network` | `NetworkData` | The network information required to connect to the KVStore contract | +| `networkData` | `NetworkData` | - | +| `gasPriceMultiplier?` | `number` | The multiplier to apply to the gas price | + +#### Overrides + +[BaseEthersClient](base.BaseEthersClient.md).[constructor](base.BaseEthersClient.md#constructor) #### Defined in -[kvstore.ts:103](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L103) +[kvstore.ts:104](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L104) ## Properties @@ -119,20 +133,74 @@ const kvstoreClient = await KVStoreClient.build(signer); #### Defined in -[kvstore.ts:94](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L94) +[kvstore.ts:95](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L95) + +___ + +### gasPriceMultiplier + +• `Protected` `Optional` **gasPriceMultiplier**: `number` + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[gasPriceMultiplier](base.BaseEthersClient.md#gaspricemultiplier) + +#### Defined in + +base.ts:14 + +___ + +### networkData + +• **networkData**: `NetworkData` + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[networkData](base.BaseEthersClient.md#networkdata) + +#### Defined in + +base.ts:15 ___ ### signerOrProvider -• `Private` **signerOrProvider**: `Signer` \| `Provider` +• `Protected` **signerOrProvider**: `Signer` \| `Provider` + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[signerOrProvider](base.BaseEthersClient.md#signerorprovider) #### Defined in -[kvstore.ts:95](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L95) +base.ts:13 ## Methods +### gasPriceOptions + +▸ `Protected` **gasPriceOptions**(): `Promise`<`Partial`<`Overrides`\>\> + +Adjust the gas price, and return as an option to be passed to a transaction + +#### Returns + +`Promise`<`Partial`<`Overrides`\>\> + +Returns the gas price options + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[gasPriceOptions](base.BaseEthersClient.md#gaspriceoptions) + +#### Defined in + +base.ts:39 + +___ + ### get ▸ **get**(`address`, `key`): `Promise`<`string`\> @@ -170,7 +238,7 @@ const value = await kvstoreClient.get('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb9226 #### Defined in -[kvstore.ts:295](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L295) +[kvstore.ts:311](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L311) ___ @@ -182,10 +250,10 @@ This function returns the URL value for the given entity. #### Parameters -| Name | Type | Description | -| :------ | :------ | :------ | -| `address` | `string` | Address from which to get the URL value. | -| `urlKey?` | `string` | Configurable URL key. `url` by default. | +| Name | Type | Default value | Description | +| :------ | :------ | :------ | :------ | +| `address` | `string` | `undefined` | Address from which to get the URL value. | +| `urlKey` | `string` | `'url'` | Configurable URL key. `url` by default. | #### Returns @@ -213,7 +281,7 @@ const linkedinUrl = await kvstoreClient.getURL( #### Defined in -[kvstore.ts:334](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L334) +[kvstore.ts:350](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L350) ___ @@ -256,7 +324,7 @@ await kvstoreClient.set('Role', 'RecordingOracle'); #### Defined in -[kvstore.ts:168](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L168) +[kvstore.ts:179](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L179) ___ @@ -301,7 +369,7 @@ await kvstoreClient.set(keys, values); #### Defined in -[kvstore.ts:207](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L207) +[kvstore.ts:220](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L220) ___ @@ -313,10 +381,10 @@ This function sets a URL value for the address that submits the transaction. #### Parameters -| Name | Type | Description | -| :------ | :------ | :------ | -| `url` | `string` | URL to set | -| `urlKey?` | `string` | Configurable URL key. `url` by default. | +| Name | Type | Default value | Description | +| :------ | :------ | :------ | :------ | +| `url` | `string` | `undefined` | URL to set | +| `urlKey` | `string` | `'url'` | Configurable URL key. `url` by default. | #### Returns @@ -343,13 +411,13 @@ await kvstoreClient.setURL('linkedin.com/example', 'linkedinUrl); #### Defined in -[kvstore.ts:246](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L246) +[kvstore.ts:261](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L261) ___ ### build -▸ `Static` **build**(`signerOrProvider`): `Promise`<[`KVStoreClient`](kvstore.KVStoreClient.md)\> +▸ `Static` **build**(`signerOrProvider`, `gasPriceMultiplier?`): `Promise`<[`KVStoreClient`](kvstore.KVStoreClient.md)\> Creates an instance of KVStoreClient from a Signer or Provider. @@ -358,6 +426,7 @@ Creates an instance of KVStoreClient from a Signer or Provider. | Name | Type | Description | | :------ | :------ | :------ | | `signerOrProvider` | `Signer` \| `Provider` | The Signer or Provider object to interact with the Ethereum network | +| `gasPriceMultiplier?` | `number` | The multiplier to apply to the gas price | #### Returns @@ -375,4 +444,4 @@ Creates an instance of KVStoreClient from a Signer or Provider. #### Defined in -[kvstore.ts:119](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L119) +[kvstore.ts:127](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L127) diff --git a/docs/sdk/typescript/classes/staking.StakingClient.md b/docs/sdk/typescript/classes/staking.StakingClient.md index b272e2d064..6565bfdcb6 100644 --- a/docs/sdk/typescript/classes/staking.StakingClient.md +++ b/docs/sdk/typescript/classes/staking.StakingClient.md @@ -72,6 +72,12 @@ const provider = new providers.JsonRpcProvider(rpcUrl); const stakingClient = await StakingClient.build(provider); ``` +## Hierarchy + +- [`BaseEthersClient`](base.BaseEthersClient.md) + + ↳ **`StakingClient`** + ## Table of contents ### Constructors @@ -81,7 +87,9 @@ const stakingClient = await StakingClient.build(provider); ### Properties - [escrowFactoryContract](staking.StakingClient.md#escrowfactorycontract) -- [network](staking.StakingClient.md#network) +- [gasPriceMultiplier](staking.StakingClient.md#gaspricemultiplier) +- [networkData](staking.StakingClient.md#networkdata) +- [rewardPoolContract](staking.StakingClient.md#rewardpoolcontract) - [signerOrProvider](staking.StakingClient.md#signerorprovider) - [stakingContract](staking.StakingClient.md#stakingcontract) - [tokenContract](staking.StakingClient.md#tokencontract) @@ -90,8 +98,10 @@ const stakingClient = await StakingClient.build(provider); - [allocate](staking.StakingClient.md#allocate) - [approveStake](staking.StakingClient.md#approvestake) +- [checkValidEscrow](staking.StakingClient.md#checkvalidescrow) - [closeAllocation](staking.StakingClient.md#closeallocation) -- [distributeRewards](staking.StakingClient.md#distributerewards) +- [distributeReward](staking.StakingClient.md#distributereward) +- [gasPriceOptions](staking.StakingClient.md#gaspriceoptions) - [getAllocation](staking.StakingClient.md#getallocation) - [getLeader](staking.StakingClient.md#getleader) - [getLeaders](staking.StakingClient.md#getleaders) @@ -106,7 +116,7 @@ const stakingClient = await StakingClient.build(provider); ### constructor -• **new StakingClient**(`signerOrProvider`, `network`) +• **new StakingClient**(`signerOrProvider`, `networkData`, `gasPriceMultiplier?`) **StakingClient constructor** @@ -115,11 +125,16 @@ const stakingClient = await StakingClient.build(provider); | Name | Type | Description | | :------ | :------ | :------ | | `signerOrProvider` | `Signer` \| `Provider` | The Signer or Provider object to interact with the Ethereum network | -| `network` | `NetworkData` | The network information required to connect to the Staking contract | +| `networkData` | `NetworkData` | - | +| `gasPriceMultiplier?` | `number` | The multiplier to apply to the gas price | + +#### Overrides + +[BaseEthersClient](base.BaseEthersClient.md).[constructor](base.BaseEthersClient.md#constructor) #### Defined in -[staking.ts:118](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L118) +[staking.ts:119](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L119) ## Properties @@ -129,27 +144,59 @@ const stakingClient = await StakingClient.build(provider); #### Defined in -[staking.ts:110](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L110) +[staking.ts:109](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L109) + +___ + +### gasPriceMultiplier + +• `Protected` `Optional` **gasPriceMultiplier**: `number` + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[gasPriceMultiplier](base.BaseEthersClient.md#gaspricemultiplier) + +#### Defined in + +base.ts:14 ___ -### network +### networkData -• **network**: `NetworkData` +• **networkData**: `NetworkData` + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[networkData](base.BaseEthersClient.md#networkdata) + +#### Defined in + +base.ts:15 + +___ + +### rewardPoolContract + +• **rewardPoolContract**: `RewardPool` #### Defined in -[staking.ts:107](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L107) +[staking.ts:110](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L110) ___ ### signerOrProvider -• **signerOrProvider**: `Signer` \| `Provider` +• `Protected` **signerOrProvider**: `Signer` \| `Provider` + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[signerOrProvider](base.BaseEthersClient.md#signerorprovider) #### Defined in -[staking.ts:106](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L106) +base.ts:13 ___ @@ -159,7 +206,7 @@ ___ #### Defined in -[staking.ts:109](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L109) +[staking.ts:108](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L108) ___ @@ -169,7 +216,7 @@ ___ #### Defined in -[staking.ts:108](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L108) +[staking.ts:107](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L107) ## Methods @@ -213,7 +260,7 @@ await stakingClient.allocate('0x62dD51230A30401C455c8398d06F85e4EaB6309f', amoun #### Defined in -[staking.ts:428](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L428) +[staking.ts:461](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L461) ___ @@ -254,7 +301,29 @@ await stakingClient.approveStake(amount); #### Defined in -[staking.ts:193](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L193) +[staking.ts:222](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L222) + +___ + +### checkValidEscrow + +▸ `Private` **checkValidEscrow**(`escrowAddress`): `Promise`<`void`\> + +Check if escrow exists + +#### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `escrowAddress` | `string` | Escrow address to check against | + +#### Returns + +`Promise`<`void`\> + +#### Defined in + +[staking.ts:187](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L187) ___ @@ -297,13 +366,13 @@ await stakingClient.closeAllocation('0x62dD51230A30401C455c8398d06F85e4EaB6309f' #### Defined in -[staking.ts:483](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L483) +[staking.ts:512](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L512) ___ -### distributeRewards +### distributeReward -▸ **distributeRewards**(`escrowAddress`): `Promise`<`void`\> +▸ **distributeReward**(`escrowAddress`): `Promise`<`void`\> This function drops the allocation from a specific escrow. @@ -334,12 +403,34 @@ const provider = new providers.JsonRpcProvider(rpcUrl); const signer = new Wallet(privateKey, provider); const stakingClient = await StakingClient.build(signer); -await stakingClient.distributeRewards('0x62dD51230A30401C455c8398d06F85e4EaB6309f'); +await stakingClient.distributeReward('0x62dD51230A30401C455c8398d06F85e4EaB6309f'); ``` #### Defined in -[staking.ts:526](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L526) +[staking.ts:551](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L551) + +___ + +### gasPriceOptions + +▸ `Protected` **gasPriceOptions**(): `Promise`<`Partial`<`Overrides`\>\> + +Adjust the gas price, and return as an option to be passed to a transaction + +#### Returns + +`Promise`<`Partial`<`Overrides`\>\> + +Returns the gas price options + +#### Inherited from + +[BaseEthersClient](base.BaseEthersClient.md).[gasPriceOptions](base.BaseEthersClient.md#gaspriceoptions) + +#### Defined in + +base.ts:39 ___ @@ -377,7 +468,7 @@ const allocationInfo = await stakingClient.getAllocation('0x62dD51230A30401C455c #### Defined in -[staking.ts:643](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L643) +[staking.ts:659](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L659) ___ @@ -415,7 +506,7 @@ const leaders = await stakingClient.getLeaders(); #### Defined in -[staking.ts:569](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L569) +[staking.ts:585](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L585) ___ @@ -453,7 +544,7 @@ const leader = await stakingClient.getLeader('0x62dD51230A30401C455c8398d06F85e4 #### Defined in -[staking.ts:608](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L608) +[staking.ts:624](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L624) ___ @@ -491,7 +582,7 @@ const rewards = await stakingClient.getRewards('0x62dD51230A30401C455c8398d06F85 #### Defined in -[staking.ts:681](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L681) +[staking.ts:691](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L691) ___ @@ -535,7 +626,7 @@ await stakingClient.slash('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', '0xf39Fd #### Defined in -[staking.ts:361](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L361) +[staking.ts:398](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L398) ___ @@ -579,7 +670,7 @@ await stakingClient.approveStake(amount); #### Defined in -[staking.ts:238](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L238) +[staking.ts:269](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L269) ___ @@ -622,7 +713,7 @@ await stakingClient.unstake(amount); #### Defined in -[staking.ts:282](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L282) +[staking.ts:315](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L315) ___ @@ -658,13 +749,13 @@ await stakingClient.withdraw(); #### Defined in -[staking.ts:324](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L324) +[staking.ts:359](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L359) ___ ### build -▸ `Static` **build**(`signerOrProvider`): `Promise`<[`StakingClient`](staking.StakingClient.md)\> +▸ `Static` **build**(`signerOrProvider`, `gasPriceMultiplier?`): `Promise`<[`StakingClient`](staking.StakingClient.md)\> Creates an instance of StakingClient from a Signer or Provider. @@ -673,6 +764,7 @@ Creates an instance of StakingClient from a Signer or Provider. | Name | Type | Description | | :------ | :------ | :------ | | `signerOrProvider` | `Signer` \| `Provider` | The Signer or Provider object to interact with the Ethereum network | +| `gasPriceMultiplier?` | `number` | The multiplier to apply to the gas price | #### Returns @@ -690,4 +782,4 @@ Creates an instance of StakingClient from a Signer or Provider. #### Defined in -[staking.ts:146](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L146) +[staking.ts:157](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L157) diff --git a/docs/sdk/typescript/classes/statistics.StatisticsClient.md b/docs/sdk/typescript/classes/statistics.StatisticsClient.md index 579618e478..9af53257dc 100644 --- a/docs/sdk/typescript/classes/statistics.StatisticsClient.md +++ b/docs/sdk/typescript/classes/statistics.StatisticsClient.md @@ -48,7 +48,7 @@ const statisticsClient = new StatisticsClient(NETWORKS[ChainId.POLYGON_MUMBAI]); ### Properties -- [network](statistics.StatisticsClient.md#network) +- [networkData](statistics.StatisticsClient.md#networkdata) ### Methods @@ -61,7 +61,7 @@ const statisticsClient = new StatisticsClient(NETWORKS[ChainId.POLYGON_MUMBAI]); ### constructor -• **new StatisticsClient**(`network`) +• **new StatisticsClient**(`networkData`) **StatisticsClient constructor** @@ -69,21 +69,21 @@ const statisticsClient = new StatisticsClient(NETWORKS[ChainId.POLYGON_MUMBAI]); | Name | Type | Description | | :------ | :------ | :------ | -| `network` | `NetworkData` | The network information required to connect to the Statistics contract | +| `networkData` | `NetworkData` | The network information required to connect to the Statistics contract | #### Defined in -[statistics.ts:68](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L68) +[statistics.ts:68](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L68) ## Properties -### network +### networkData -• **network**: `NetworkData` +• **networkData**: `NetworkData` #### Defined in -[statistics.ts:61](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L61) +[statistics.ts:61](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L61) ## Methods @@ -147,7 +147,7 @@ const escrowStatisticsApril = await statisticsClient.getEscrowStatistics({ #### Defined in -[statistics.ts:121](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L121) +[statistics.ts:121](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L121) ___ @@ -243,7 +243,7 @@ console.log('HMT statistics from 5/8 - 6/8:', { #### Defined in -[statistics.ts:395](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L395) +[statistics.ts:395](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L395) ___ @@ -325,7 +325,7 @@ console.log( #### Defined in -[statistics.ts:285](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L285) +[statistics.ts:285](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L285) ___ @@ -384,4 +384,4 @@ const workerStatisticsApril = await statisticsClient.getWorkerStatistics({ #### Defined in -[statistics.ts:196](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L196) +[statistics.ts:196](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L196) diff --git a/docs/sdk/typescript/classes/storage.StorageClient.md b/docs/sdk/typescript/classes/storage.StorageClient.md index a30af2ff1a..284e85428f 100644 --- a/docs/sdk/typescript/classes/storage.StorageClient.md +++ b/docs/sdk/typescript/classes/storage.StorageClient.md @@ -87,7 +87,7 @@ const storageClient = new StorageClient(params, credentials); #### Defined in -[storage.ts:73](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L73) +[storage.ts:73](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L73) ## Properties @@ -97,7 +97,7 @@ const storageClient = new StorageClient(params, credentials); #### Defined in -[storage.ts:64](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L64) +[storage.ts:64](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L64) ___ @@ -107,7 +107,7 @@ ___ #### Defined in -[storage.ts:65](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L65) +[storage.ts:65](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L65) ## Methods @@ -151,7 +151,7 @@ const exists = await storageClient.bucketExists('bucket-name'); #### Defined in -[storage.ts:265](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L265) +[storage.ts:265](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L265) ___ @@ -194,7 +194,7 @@ const files = await storageClient.downloadFiles(keys, 'bucket-name'); #### Defined in -[storage.ts:113](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L113) +[storage.ts:113](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L113) ___ @@ -238,7 +238,7 @@ const fileNames = await storageClient.listObjects('bucket-name'); #### Defined in -[storage.ts:296](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L296) +[storage.ts:296](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L296) ___ @@ -286,7 +286,7 @@ const uploadedFiles = await storageClient.uploadFiles(files, 'bucket-name'); #### Defined in -[storage.ts:201](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L201) +[storage.ts:201](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L201) ___ @@ -318,4 +318,4 @@ const file = await storageClient.downloadFileFromUrl('http://localhost/file.json #### Defined in -[storage.ts:148](https://github.com/humanprotocol/human-protocol/blob/930bec07/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L148) +[storage.ts:148](https://github.com/humanprotocol/human-protocol/blob/b4448a8b/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L148) diff --git a/docs/sdk/typescript/modules.md b/docs/sdk/typescript/modules.md index dab3e21066..1307c92503 100644 --- a/docs/sdk/typescript/modules.md +++ b/docs/sdk/typescript/modules.md @@ -6,6 +6,7 @@ ### Modules +- [base](modules/base.md) - [encryption](modules/encryption.md) - [escrow](modules/escrow.md) - [kvstore](modules/kvstore.md) diff --git a/docs/sdk/typescript/modules/base.md b/docs/sdk/typescript/modules/base.md new file mode 100644 index 0000000000..b5c39bcd06 --- /dev/null +++ b/docs/sdk/typescript/modules/base.md @@ -0,0 +1,9 @@ +[@human-protocol/sdk](../README.md) / [Modules](../modules.md) / base + +# Module: base + +## Table of contents + +### Classes + +- [BaseEthersClient](../classes/base.BaseEthersClient.md) diff --git a/packages/sdk/typescript/human-protocol-sdk/package.json b/packages/sdk/typescript/human-protocol-sdk/package.json index cfa2f9adc1..0c363f137b 100644 --- a/packages/sdk/typescript/human-protocol-sdk/package.json +++ b/packages/sdk/typescript/human-protocol-sdk/package.json @@ -59,6 +59,7 @@ }, "typedocOptions": { "entryPoints": [ + "./src/base.ts", "./src/encryption.ts", "./src/escrow.ts", "./src/kvstore.ts", diff --git a/packages/sdk/typescript/human-protocol-sdk/src/base.ts b/packages/sdk/typescript/human-protocol-sdk/src/base.ts new file mode 100644 index 0000000000..f66bfd59cd --- /dev/null +++ b/packages/sdk/typescript/human-protocol-sdk/src/base.ts @@ -0,0 +1,49 @@ +import { Provider } from '@ethersproject/abstract-provider'; +import { Signer, ethers } from 'ethers'; +import { NetworkData } from './types'; +import { gasPriceAdjusted } from './utils'; + +/** + * ## Introduction + * + * This class is used as a base class for other clients making on-chain calls. + * + */ +export abstract class BaseEthersClient { + protected signerOrProvider: Signer | Provider; + protected gasPriceMultiplier?: number; + public networkData: NetworkData; + + /** + * **BaseClient constructor** + * + * @param {Signer | Provider} signerOrProvider The Signer or Provider object to interact with the Ethereum network + * @param {NetworkData} networkData The network information required to connect to the contracts + * @param {number | undefined} gasPriceMultiplier The multiplier to apply to the gas price + */ + constructor( + signerOrProvider: Signer | Provider, + networkData: NetworkData, + gasPriceMultiplier?: number + ) { + this.networkData = networkData; + this.signerOrProvider = signerOrProvider; + this.gasPriceMultiplier = gasPriceMultiplier; + } + + /** + * Adjust the gas price, and return as an option to be passed to a transaction + * + * @returns {Promise<{ gasPrice: BigNumber }>} Returns the gas price options + */ + protected async gasPriceOptions(): Promise> { + return this.gasPriceMultiplier + ? { + gasPrice: await gasPriceAdjusted( + this.signerOrProvider, + this.gasPriceMultiplier + ), + } + : {}; + } +} diff --git a/packages/sdk/typescript/human-protocol-sdk/src/error.ts b/packages/sdk/typescript/human-protocol-sdk/src/error.ts index b433dddd58..3416812eaf 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/error.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/error.ts @@ -334,3 +334,8 @@ export class InvalidEthereumAddressError extends Error { * @constant {Error} - The Hash does not match */ export const ErrorInvalidHash = new Error('Invalid hash'); + +/** + * @constant {Error} - The Hash does not match + */ +export const ErrorMissingGasPrice = new Error('Missing gas price'); diff --git a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts index 56032f52a2..479733d6e6 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts @@ -11,6 +11,7 @@ import { } from '@human-protocol/core/typechain-types'; import { BigNumber, ContractReceipt, Signer, ethers } from 'ethers'; import gqlFetch from 'graphql-request'; +import { BaseEthersClient } from './base'; import { DEFAULT_TX_ID, NETWORKS } from './constants'; import { requiresSigner } from './decorators'; import { ChainId } from './enums'; @@ -116,36 +117,43 @@ import { * const escrowClient = await EscrowClient.build(provider); * ``` */ -export class EscrowClient { +export class EscrowClient extends BaseEthersClient { private escrowFactoryContract: EscrowFactory; - private escrowContract?: Escrow; - private signerOrProvider: Signer | Provider; - public network: NetworkData; /** * **EscrowClient constructor** * * @param {Signer | Provider} signerOrProvider The Signer or Provider object to interact with the Ethereum network * @param {NetworkData} network The network information required to connect to the Escrow contract + * @param {number | undefined} gasPriceMultiplier The multiplier to apply to the gas price */ - constructor(signerOrProvider: Signer | Provider, network: NetworkData) { + constructor( + signerOrProvider: Signer | Provider, + networkData: NetworkData, + gasPriceMultiplier?: number + ) { + super(signerOrProvider, networkData, gasPriceMultiplier); + this.escrowFactoryContract = EscrowFactory__factory.connect( - network.factoryAddress, + networkData.factoryAddress, signerOrProvider ); - this.network = network; - this.signerOrProvider = signerOrProvider; } /** * Creates an instance of EscrowClient from a Signer or Provider. * * @param {Signer | Provider} signerOrProvider The Signer or Provider object to interact with the Ethereum network + * @param {number | undefined} gasPriceMultiplier The multiplier to apply to the gas price + * * @returns {Promise} An instance of EscrowClient * @throws {ErrorProviderDoesNotExist} Thrown if the provider does not exist for the provided Signer * @throws {ErrorUnsupportedChainID} Thrown if the network's chainId is not supported */ - public static async build(signerOrProvider: Signer | Provider) { + public static async build( + signerOrProvider: Signer | Provider, + gasPriceMultiplier?: number + ) { let network: Network; if (Signer.isSigner(signerOrProvider)) { if (!signerOrProvider.provider) { @@ -164,7 +172,20 @@ export class EscrowClient { throw ErrorUnsupportedChainID; } - return new EscrowClient(signerOrProvider, networkData); + return new EscrowClient(signerOrProvider, networkData, gasPriceMultiplier); + } + + /** + * Connects to the escrow contract + * + * @param escrowAddress Escrow address to connect to + */ + private getEscrowContract(escrowAddress: string): Escrow { + try { + return Escrow__factory.connect(escrowAddress, this.signerOrProvider); + } catch (e) { + return throwError(e); + } } /** @@ -218,7 +239,10 @@ export class EscrowClient { await this.escrowFactoryContract.createEscrow( tokenAddress, trustedHandlers, - jobRequesterId + jobRequesterId, + { + ...(await this.gasPriceOptions()), + } ) ).wait(); @@ -336,11 +360,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - await this.escrowContract.setup( + const escrowContract = this.getEscrowContract(escrowAddress); + + await escrowContract.setup( reputationOracle, recordingOracle, exchangeOracle, @@ -348,7 +370,10 @@ export class EscrowClient { recordingOracleFee, exchangeOracleFee, manifestUrl, - manifestHash + manifestHash, + { + ...(await this.gasPriceOptions()), + } ); return; @@ -460,19 +485,18 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); + const escrowContract = this.getEscrowContract(escrowAddress); - const tokenAddress = await this.escrowContract.token(); + const tokenAddress = await escrowContract.token(); const tokenContract: HMToken = HMToken__factory.connect( tokenAddress, this.signerOrProvider ); - await tokenContract.transfer(escrowAddress, amount); + await tokenContract.transfer(escrowAddress, amount, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { @@ -534,11 +558,11 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - await this.escrowContract.storeResults(url, hash); + const escrowContract = this.getEscrowContract(escrowAddress); + + await escrowContract.storeResults(url, hash, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { @@ -582,11 +606,11 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - await this.escrowContract.complete(); + const escrowContract = this.getEscrowContract(escrowAddress); + + await escrowContract.complete({ + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -685,17 +709,18 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); + const escrowContract = this.getEscrowContract(escrowAddress); - await this.escrowContract.bulkPayOut( + await escrowContract.bulkPayOut( recipients, amounts, finalResultsUrl, finalResultsHash, - DEFAULT_TX_ID + DEFAULT_TX_ID, + + { + ...(await this.gasPriceOptions()), + } ); return; } catch (e) { @@ -739,15 +764,15 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - const tx = await this.escrowContract.cancel(); + const escrowContract = this.getEscrowContract(escrowAddress); + + const tx = await escrowContract.cancel({ + ...(await this.gasPriceOptions()), + }); const transactionReceipt = await tx.wait(); let amountTransferred: BigNumber | undefined = undefined; - const tokenAddress = await this.escrowContract.token(); + const tokenAddress = await escrowContract.token(); const tokenContract: HMToken = HMToken__factory.connect( tokenAddress, @@ -817,11 +842,11 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - await this.escrowContract.abort(); + const escrowContract = this.getEscrowContract(escrowAddress); + + await escrowContract.abort({ + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -879,11 +904,11 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - await this.escrowContract.addTrustedHandlers(trustedHandlers); + const escrowContract = this.getEscrowContract(escrowAddress); + + await escrowContract.addTrustedHandlers(trustedHandlers, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -920,11 +945,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.getBalance(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.getBalance(); } catch (e) { return throwError(e); } @@ -960,11 +983,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.manifestHash(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.manifestHash(); } catch (e) { return throwError(e); } @@ -1000,11 +1021,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.manifestUrl(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.manifestUrl(); } catch (e) { return throwError(e); } @@ -1040,11 +1059,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.finalResultsUrl(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.finalResultsUrl(); } catch (e) { return throwError(e); } @@ -1080,11 +1097,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.intermediateResultsUrl(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.intermediateResultsUrl(); } catch (e: any) { return throwError(e); } @@ -1120,11 +1135,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.token(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.token(); } catch (e) { return throwError(e); } @@ -1160,11 +1173,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.status(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.status(); } catch (e) { return throwError(e); } @@ -1200,11 +1211,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.recordingOracle(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.recordingOracle(); } catch (e: any) { return throwError(e); } @@ -1240,11 +1249,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.launcher(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.launcher(); } catch (e: any) { return throwError(e); } @@ -1280,11 +1287,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.reputationOracle(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.reputationOracle(); } catch (e: any) { return throwError(e); } @@ -1320,11 +1325,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.exchangeOracle(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.exchangeOracle(); } catch (e: any) { return throwError(e); } @@ -1360,11 +1363,9 @@ export class EscrowClient { } try { - this.escrowContract = Escrow__factory.connect( - escrowAddress, - this.signerOrProvider - ); - return this.escrowContract.escrowFactory(); + const escrowContract = this.getEscrowContract(escrowAddress); + + return escrowContract.escrowFactory(); } catch (e: any) { return throwError(e); } diff --git a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts index 5c4a884d77..486264e3d8 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts @@ -5,6 +5,7 @@ import { KVStore__factory, } from '@human-protocol/core/typechain-types'; import { Signer, ethers } from 'ethers'; +import { BaseEthersClient } from './base'; import { NETWORKS } from './constants'; import { requiresSigner } from './decorators'; import { ChainId } from './enums'; @@ -90,33 +91,43 @@ import { isValidUrl } from './utils'; * const kvstoreClient = await KVStoreClient.build(signer); * ``` */ -export class KVStoreClient { +export class KVStoreClient extends BaseEthersClient { private contract: KVStore; - private signerOrProvider: Signer | Provider; /** * **KVStoreClient constructor** * * @param {Signer | Provider} signerOrProvider - The Signer or Provider object to interact with the Ethereum network * @param {NetworkData} network - The network information required to connect to the KVStore contract + * @param {number | undefined} gasPriceMultiplier - The multiplier to apply to the gas price */ - constructor(signerOrProvider: Signer | Provider, network: NetworkData) { + constructor( + signerOrProvider: Signer | Provider, + networkData: NetworkData, + gasPriceMultiplier?: number + ) { + super(signerOrProvider, networkData, gasPriceMultiplier); + this.contract = KVStore__factory.connect( - network.kvstoreAddress, + networkData.kvstoreAddress, signerOrProvider ); - this.signerOrProvider = signerOrProvider; } /** * Creates an instance of KVStoreClient from a Signer or Provider. * * @param {Signer | Provider} signerOrProvider - The Signer or Provider object to interact with the Ethereum network + * @param {number | undefined} gasPriceMultiplier - The multiplier to apply to the gas price + * * @returns {Promise} - An instance of KVStoreClient * @throws {ErrorProviderDoesNotExist} - Thrown if the provider does not exist for the provided Signer * @throws {ErrorUnsupportedChainID} - Thrown if the network's chainId is not supported */ - public static async build(signerOrProvider: Signer | Provider) { + public static async build( + signerOrProvider: Signer | Provider, + gasPriceMultiplier?: number + ) { let network: Network; if (Signer.isSigner(signerOrProvider)) { if (!signerOrProvider.provider) { @@ -135,7 +146,7 @@ export class KVStoreClient { throw ErrorUnsupportedChainID; } - return new KVStoreClient(signerOrProvider, networkData); + return new KVStoreClient(signerOrProvider, networkData, gasPriceMultiplier); } /** @@ -169,7 +180,9 @@ export class KVStoreClient { if (!Signer.isSigner(this.signerOrProvider)) throw ErrorSigner; if (key === '') throw ErrorKVStoreEmptyKey; try { - await this.contract?.set(key, value); + await this.contract?.set(key, value, { + ...(await this.gasPriceOptions()), + }); } catch (e) { if (e instanceof Error) throw Error(`Failed to set value: ${e.message}`); } @@ -210,7 +223,9 @@ export class KVStoreClient { if (keys.includes('')) throw ErrorKVStoreEmptyKey; try { - await this.contract?.setBulk(keys, values); + await this.contract?.setBulk(keys, values, { + ...(await this.gasPriceOptions()), + }); } catch (e) { if (e instanceof Error) throw Error(`Failed to set bulk values: ${e.message}`); @@ -260,7 +275,9 @@ export class KVStoreClient { const hashKey = urlKey + 'Hash'; try { - await this.contract.setBulk([urlKey, hashKey], [url, contentHash]); + await this.contract.setBulk([urlKey, hashKey], [url, contentHash], { + ...(await this.gasPriceOptions()), + }); } catch (e) { if (e instanceof Error) throw Error(`Failed to set URL and hash: ${e.message}`); diff --git a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts index ca01a516c1..849d9b2ba0 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts @@ -13,6 +13,7 @@ import { } from '@human-protocol/core/typechain-types'; import { BigNumber, Signer, ethers } from 'ethers'; import gqlFetch from 'graphql-request'; +import { BaseEthersClient } from './base'; import { NETWORKS } from './constants'; import { requiresSigner } from './decorators'; import { ChainId } from './enums'; @@ -102,48 +103,61 @@ import { GET_LEADER_QUERY, GET_LEADERS_QUERY } from './graphql/queries/staking'; * const stakingClient = await StakingClient.build(provider); * ``` */ -export class StakingClient { - public signerOrProvider: Signer | Provider; - public network: NetworkData; +export class StakingClient extends BaseEthersClient { public tokenContract: HMToken; public stakingContract: Staking; public escrowFactoryContract: EscrowFactory; + public rewardPoolContract: RewardPool; /** * **StakingClient constructor** * * @param {Signer | Provider} signerOrProvider - The Signer or Provider object to interact with the Ethereum network * @param {NetworkData} network - The network information required to connect to the Staking contract + * @param {number | undefined} gasPriceMultiplier - The multiplier to apply to the gas price */ - constructor(signerOrProvider: Signer | Provider, network: NetworkData) { + constructor( + signerOrProvider: Signer | Provider, + networkData: NetworkData, + gasPriceMultiplier?: number + ) { + super(signerOrProvider, networkData, gasPriceMultiplier); + this.stakingContract = Staking__factory.connect( - network.stakingAddress, + networkData.stakingAddress, signerOrProvider ); this.escrowFactoryContract = EscrowFactory__factory.connect( - network.factoryAddress, + networkData.factoryAddress, signerOrProvider ); this.tokenContract = HMToken__factory.connect( - network.hmtAddress, + networkData.hmtAddress, signerOrProvider ); - this.signerOrProvider = signerOrProvider; - this.network = network; + this.rewardPoolContract = RewardPool__factory.connect( + networkData.rewardPoolAddress, + this.signerOrProvider + ); } /** * Creates an instance of StakingClient from a Signer or Provider. * * @param {Signer | Provider} signerOrProvider - The Signer or Provider object to interact with the Ethereum network + * @param {number | undefined} gasPriceMultiplier - The multiplier to apply to the gas price + * * @returns {Promise} - An instance of StakingClient * @throws {ErrorProviderDoesNotExist} - Thrown if the provider does not exist for the provided Signer * @throws {ErrorUnsupportedChainID} - Thrown if the network's chainId is not supported */ - public static async build(signerOrProvider: Signer | Provider) { + public static async build( + signerOrProvider: Signer | Provider, + gasPriceMultiplier?: number + ) { let network: Network; if (Signer.isSigner(signerOrProvider)) { if (!signerOrProvider.provider) { @@ -162,7 +176,22 @@ export class StakingClient { throw ErrorUnsupportedChainID; } - return new StakingClient(signerOrProvider, networkData); + return new StakingClient(signerOrProvider, networkData, gasPriceMultiplier); + } + + /** + * Check if escrow exists + * + * @param escrowAddress Escrow address to check against + */ + private async checkValidEscrow(escrowAddress: string) { + if (!ethers.utils.isAddress(escrowAddress)) { + throw ErrorInvalidEscrowAddressProvided; + } + + if (!(await this.escrowFactoryContract.hasEscrow(escrowAddress))) { + throw ErrorEscrowAddressIsNotProvidedByFactory; + } } /** @@ -200,7 +229,9 @@ export class StakingClient { } try { - await this.tokenContract.approve(this.stakingContract.address, amount); + await this.tokenContract.approve(this.stakingContract.address, amount, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -245,7 +276,9 @@ export class StakingClient { } try { - await this.stakingContract.stake(amount); + await this.stakingContract.stake(amount, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -289,7 +322,9 @@ export class StakingClient { } try { - await this.stakingContract.unstake(amount); + await this.stakingContract.unstake(amount, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -323,7 +358,9 @@ export class StakingClient { @requiresSigner public async withdraw(): Promise { try { - await this.stakingContract.withdraw(); + await this.stakingContract.withdraw({ + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -380,16 +417,12 @@ export class StakingClient { throw ErrorInvalidStakerAddressProvided; } - if (!ethers.utils.isAddress(escrowAddress)) { - throw ErrorInvalidEscrowAddressProvided; - } - - if (!(await this.escrowFactoryContract.hasEscrow(escrowAddress))) { - throw ErrorEscrowAddressIsNotProvidedByFactory; - } + await this.checkValidEscrow(escrowAddress); try { - await this.stakingContract.slash(slasher, staker, escrowAddress, amount); + await this.stakingContract.slash(slasher, staker, escrowAddress, amount, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { @@ -437,16 +470,12 @@ export class StakingClient { throw ErrorInvalidStakingValueSign; } - if (!ethers.utils.isAddress(escrowAddress)) { - throw ErrorInvalidEscrowAddressProvided; - } - - if (!(await this.escrowFactoryContract.hasEscrow(escrowAddress))) { - throw ErrorEscrowAddressIsNotProvidedByFactory; - } + await this.checkValidEscrow(escrowAddress); try { - await this.stakingContract.allocate(escrowAddress, amount); + await this.stakingContract.allocate(escrowAddress, amount, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -481,16 +510,12 @@ export class StakingClient { */ @requiresSigner public async closeAllocation(escrowAddress: string): Promise { - if (!ethers.utils.isAddress(escrowAddress)) { - throw ErrorInvalidEscrowAddressProvided; - } - - if (!(await this.escrowFactoryContract.hasEscrow(escrowAddress))) { - throw ErrorEscrowAddressIsNotProvidedByFactory; - } + await this.checkValidEscrow(escrowAddress); try { - await this.stakingContract.closeAllocation(escrowAddress); + await this.stakingContract.closeAllocation(escrowAddress, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -519,26 +544,17 @@ export class StakingClient { * const signer = new Wallet(privateKey, provider); * const stakingClient = await StakingClient.build(signer); * - * await stakingClient.distributeRewards('0x62dD51230A30401C455c8398d06F85e4EaB6309f'); + * await stakingClient.distributeReward('0x62dD51230A30401C455c8398d06F85e4EaB6309f'); * ``` */ @requiresSigner - public async distributeRewards(escrowAddress: string): Promise { - if (!ethers.utils.isAddress(escrowAddress)) { - throw ErrorInvalidEscrowAddressProvided; - } - - if (!(await this.escrowFactoryContract.hasEscrow(escrowAddress))) { - throw ErrorEscrowAddressIsNotProvidedByFactory; - } + public async distributeReward(escrowAddress: string): Promise { + await this.checkValidEscrow(escrowAddress); try { - const rewardPoolContract: RewardPool = RewardPool__factory.connect( - await this.stakingContract.rewardPool(), - this.signerOrProvider - ); - - await rewardPoolContract.distributeReward(escrowAddress); + this.rewardPoolContract.distributeReward(escrowAddress, { + ...(await this.gasPriceOptions()), + }); return; } catch (e) { return throwError(e); @@ -574,7 +590,7 @@ export class StakingClient { try { const { leader } = await gqlFetch<{ leader: ILeader; - }>(this.network.subgraphUrl, GET_LEADER_QUERY, { + }>(this.networkData.subgraphUrl, GET_LEADER_QUERY, { address: address.toLowerCase(), }); @@ -609,7 +625,7 @@ export class StakingClient { try { const { leaders } = await gqlFetch<{ leaders: ILeader[]; - }>(this.network.subgraphUrl, GET_LEADERS_QUERY(filter), { + }>(this.networkData.subgraphUrl, GET_LEADERS_QUERY(filter), { role: filter.role, }); @@ -641,13 +657,7 @@ export class StakingClient { * ``` */ public async getAllocation(escrowAddress: string): Promise { - if (!ethers.utils.isAddress(escrowAddress)) { - throw ErrorInvalidEscrowAddressProvided; - } - - if (!(await this.escrowFactoryContract.hasEscrow(escrowAddress))) { - throw ErrorEscrowAddressIsNotProvidedByFactory; - } + await this.checkValidEscrow(escrowAddress); try { const result = await this.stakingContract.getAllocation(escrowAddress); @@ -686,7 +696,7 @@ export class StakingClient { try { const { rewardAddedEvents } = await gqlFetch<{ rewardAddedEvents: RewardAddedEventData[]; - }>(this.network.subgraphUrl, GET_REWARD_ADDED_EVENTS_QUERY, { + }>(this.networkData.subgraphUrl, GET_REWARD_ADDED_EVENTS_QUERY, { slasherAddress: slasherAddress.toLowerCase(), }); diff --git a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts index 23555e841d..ce9fc01240 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts @@ -58,15 +58,15 @@ import { throwError } from './utils'; * ``` */ export class StatisticsClient { - public network: NetworkData; + public networkData: NetworkData; /** * **StatisticsClient constructor** * - * @param {NetworkData} network - The network information required to connect to the Statistics contract + * @param {NetworkData} networkData - The network information required to connect to the Statistics contract */ - constructor(network: NetworkData) { - this.network = network; + constructor(networkData: NetworkData) { + this.networkData = networkData; } /** @@ -124,11 +124,11 @@ export class StatisticsClient { try { const { escrowStatistics } = await gqlFetch<{ escrowStatistics: EscrowStatisticsData; - }>(this.network.subgraphUrl, GET_ESCROW_STATISTICS_QUERY); + }>(this.networkData.subgraphUrl, GET_ESCROW_STATISTICS_QUERY); const { eventDayDatas } = await gqlFetch<{ eventDayDatas: EventDayData[]; - }>(this.network.subgraphUrl, GET_EVENT_DAY_DATA_QUERY(params), { + }>(this.networkData.subgraphUrl, GET_EVENT_DAY_DATA_QUERY(params), { from: params.from ? params.from.getTime() / 1000 : undefined, to: params.to ? params.to.getTime() / 1000 : undefined, }); @@ -199,7 +199,7 @@ export class StatisticsClient { try { const { eventDayDatas } = await gqlFetch<{ eventDayDatas: EventDayData[]; - }>(this.network.subgraphUrl, GET_EVENT_DAY_DATA_QUERY(params), { + }>(this.networkData.subgraphUrl, GET_EVENT_DAY_DATA_QUERY(params), { from: params.from ? params.from.getTime() / 1000 : undefined, to: params.to ? params.to.getTime() / 1000 : undefined, }); @@ -288,7 +288,7 @@ export class StatisticsClient { try { const { eventDayDatas } = await gqlFetch<{ eventDayDatas: EventDayData[]; - }>(this.network.subgraphUrl, GET_EVENT_DAY_DATA_QUERY(params), { + }>(this.networkData.subgraphUrl, GET_EVENT_DAY_DATA_QUERY(params), { from: params.from ? params.from.getTime() / 1000 : undefined, to: params.to ? params.to.getTime() / 1000 : undefined, }); @@ -398,15 +398,15 @@ export class StatisticsClient { try { const { hmtokenStatistics } = await gqlFetch<{ hmtokenStatistics: HMTStatisticsData; - }>(this.network.subgraphUrl, GET_HMTOKEN_STATISTICS_QUERY); + }>(this.networkData.subgraphUrl, GET_HMTOKEN_STATISTICS_QUERY); const { holders } = await gqlFetch<{ holders: HMTHolderData[]; - }>(this.network.subgraphUrl, GET_HOLDERS_QUERY); + }>(this.networkData.subgraphUrl, GET_HOLDERS_QUERY); const { eventDayDatas } = await gqlFetch<{ eventDayDatas: EventDayData[]; - }>(this.network.subgraphUrl, GET_EVENT_DAY_DATA_QUERY(params), { + }>(this.networkData.subgraphUrl, GET_EVENT_DAY_DATA_QUERY(params), { from: params.from ? params.from.getTime() / 1000 : undefined, to: params.to ? params.to.getTime() / 1000 : undefined, }); diff --git a/packages/sdk/typescript/human-protocol-sdk/src/utils.ts b/packages/sdk/typescript/human-protocol-sdk/src/utils.ts index 977a55e41a..680bdc03d2 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/utils.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/utils.ts @@ -1,8 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { ethers } from 'ethers'; +import { Provider } from '@ethersproject/abstract-provider'; +import { BigNumber, Signer, ethers } from 'ethers'; import { ContractExecutionError, + ErrorMissingGasPrice, EthereumError, InvalidArgumentError, NonceExpired, @@ -71,3 +73,29 @@ export const isValidUrl = (url: string) => { return false; } }; + +/** + * Increase/Decrease gas price + * + * @returns {Promise} Returns the adjusted gas price + */ +export const gasPriceAdjusted = async ( + signerOrProvider: Signer | Provider, + gasPriceMultiplier: number +): Promise => { + let gasPrice; + + if (Signer.isSigner(signerOrProvider)) { + gasPrice = (await signerOrProvider.provider?.getFeeData())?.gasPrice; + } else { + gasPrice = (await signerOrProvider.getFeeData()).gasPrice; + } + + if (!gasPrice) { + throw ErrorMissingGasPrice; + } + + return gasPrice + .mul(ethers.utils.parseEther(gasPriceMultiplier.toString())) + .div(ethers.utils.parseEther('1')); +}; diff --git a/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts index 079e571bcc..258e16e2a3 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/escrow.test.ts @@ -23,6 +23,7 @@ import { ErrorInvalidTokenAddress, ErrorInvalidUrl, ErrorListOfHandlersCannotBeEmpty, + ErrorMissingGasPrice, ErrorProviderDoesNotExist, ErrorRecipientAndAmountsMustBeSameLength, ErrorRecipientCannotBeEmptyArray, @@ -223,7 +224,8 @@ describe('EscrowClient', () => { expect(createEscrowSpy).toHaveBeenCalledWith( tokenAddress, trustedHandlers, - jobRequesterId + jobRequesterId, + {} ); expect(result).toBe(expectedEscrowAddress); }); @@ -243,7 +245,7 @@ describe('EscrowClient', () => { expect( escrowClient.escrowFactoryContract.createEscrow - ).toHaveBeenCalledWith(tokenAddress, trustedHandlers, jobRequesterId); + ).toHaveBeenCalledWith(tokenAddress, trustedHandlers, jobRequesterId, {}); }); }); @@ -493,7 +495,8 @@ describe('EscrowClient', () => { BigNumber.from(10), BigNumber.from(10), VALID_URL, - FAKE_HASH + FAKE_HASH, + {} ); }); @@ -524,7 +527,8 @@ describe('EscrowClient', () => { BigNumber.from(10), BigNumber.from(10), VALID_URL, - FAKE_HASH + FAKE_HASH, + {} ); }); }); @@ -571,7 +575,8 @@ describe('EscrowClient', () => { BigNumber.from(10), BigNumber.from(10), VALID_URL, - FAKE_HASH + FAKE_HASH, + {} ); }); @@ -602,7 +607,8 @@ describe('EscrowClient', () => { BigNumber.from(10), BigNumber.from(10), VALID_URL, - FAKE_HASH + FAKE_HASH, + {} ); }); }); @@ -652,7 +658,8 @@ describe('EscrowClient', () => { expect(escrowClient.escrowContract.token).toHaveBeenCalledWith(); expect(escrowClient.tokenContract.transfer).toHaveBeenCalledWith( escrowAddress, - amount + amount, + {} ); }); @@ -741,7 +748,8 @@ describe('EscrowClient', () => { expect(escrowClient.escrowContract.storeResults).toHaveBeenCalledWith( url, - hash + hash, + {} ); }); @@ -761,7 +769,8 @@ describe('EscrowClient', () => { expect(escrowClient.escrowContract.storeResults).toHaveBeenCalledWith( url, - hash + hash, + {} ); }); }); @@ -792,7 +801,7 @@ describe('EscrowClient', () => { await escrowClient.complete(escrowAddress); - expect(escrowClient.escrowContract.complete).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.complete).toHaveBeenCalledWith({}); }); test('should throw an error if the complete fails', async () => { @@ -803,7 +812,7 @@ describe('EscrowClient', () => { await expect(escrowClient.complete(escrowAddress)).rejects.toThrow(); - expect(escrowClient.escrowContract.complete).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.complete).toHaveBeenCalledWith({}); }); }); @@ -1040,7 +1049,8 @@ describe('EscrowClient', () => { amounts, finalResultsUrl, finalResultsHash, - DEFAULT_TX_ID + DEFAULT_TX_ID, + {} ); }); @@ -1052,7 +1062,7 @@ describe('EscrowClient', () => { await expect(escrowClient.abort(escrowAddress)).rejects.toThrow(); - expect(escrowClient.escrowContract.abort).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.abort).toHaveBeenCalledWith({}); }); }); @@ -1116,7 +1126,7 @@ describe('EscrowClient', () => { amountRefunded, txHash: FAKE_HASH, }); - expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith({}); }); test('should throw an error if the cancel fails', async () => { @@ -1127,7 +1137,7 @@ describe('EscrowClient', () => { await expect(escrowClient.cancel(escrowAddress)).rejects.toThrow(); - expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith({}); }); test('should throw an error if the wait fails', async () => { @@ -1138,7 +1148,7 @@ describe('EscrowClient', () => { await expect(escrowClient.cancel(escrowAddress)).rejects.toThrow(); - expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith({}); }); test('should throw an error if transfer event not found in transaction logs', async () => { @@ -1172,7 +1182,7 @@ describe('EscrowClient', () => { await expect(escrowClient.cancel(escrowAddress)).rejects.toThrow(); - expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith({}); }); }); @@ -1202,7 +1212,7 @@ describe('EscrowClient', () => { await escrowClient.abort(escrowAddress); - expect(escrowClient.escrowContract.abort).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.abort).toHaveBeenCalledWith({}); }); test('should throw an error if abort fails', async () => { @@ -1213,7 +1223,7 @@ describe('EscrowClient', () => { await expect(escrowClient.abort(escrowAddress)).rejects.toThrow(); - expect(escrowClient.escrowContract.abort).toHaveBeenCalledWith(); + expect(escrowClient.escrowContract.abort).toHaveBeenCalledWith({}); }); }); @@ -1270,7 +1280,7 @@ describe('EscrowClient', () => { expect( escrowClient.escrowContract.addTrustedHandlers - ).toHaveBeenCalledWith(trustedHandlers); + ).toHaveBeenCalledWith(trustedHandlers, {}); }); test('should throw an error if addTrustedHandlers fails', async () => { @@ -1288,7 +1298,7 @@ describe('EscrowClient', () => { expect( escrowClient.escrowContract.addTrustedHandlers - ).toHaveBeenCalledWith(trustedHandlers); + ).toHaveBeenCalledWith(trustedHandlers, {}); }); }); @@ -2131,3 +2141,1463 @@ describe('EscrowUtils', () => { }); }); }); + +describe('EscrowClient with higher gas price', () => { + const gasPriceMultiplier = 1.5; + const defaultGasPrice = BigNumber.from(10); + const expectedGasPrice = BigNumber.from(15); + + const provider = new ethers.providers.JsonRpcProvider(); + let escrowClient: any, + mockProvider: any, + mockSigner: any, + mockEscrowContract: any, + mockEscrowFactoryContract: any, + mockTokenContract: any, + mockTx: any; + + beforeEach(async () => { + mockProvider = { + ...provider, + getNetwork: vi.fn().mockReturnValue({ chainId: ChainId.LOCALHOST }), + getFeeData: vi.fn().mockResolvedValue({ gasPrice: defaultGasPrice }), + }; + mockSigner = { + ...provider.getSigner(), + provider: { + ...mockProvider, + }, + getAddress: vi.fn().mockReturnValue(ethers.constants.AddressZero), + }; + + mockEscrowContract = { + createEscrow: vi.fn(), + setup: vi.fn(), + createAndSetupEscrow: vi.fn(), + fund: vi.fn(), + storeResults: vi.fn(), + complete: vi.fn(), + bulkPayOut: vi.fn(), + cancel: vi.fn(), + abort: vi.fn(), + addTrustedHandlers: vi.fn(), + getBalance: vi.fn(), + manifestHash: vi.fn(), + manifestUrl: vi.fn(), + finalResultsUrl: vi.fn(), + token: vi.fn(), + status: vi.fn(), + getEscrow: vi.fn(), + getEscrows: vi.fn(), + address: ethers.constants.AddressZero, + canceler: vi.fn(), + recordingOracle: vi.fn(), + reputationOracle: vi.fn(), + exchangeOracle: vi.fn(), + intermediateResultsUrl: vi.fn(), + launcher: vi.fn(), + escrowFactory: vi.fn(), + }; + + mockEscrowFactoryContract = { + createEscrow: vi.fn(), + hasEscrow: vi.fn(), + lastEscrow: vi.fn(), + }; + + mockTokenContract = { + allowance: vi.fn(), + approve: vi.fn(), + transfer: vi.fn(), + }; + + mockTx = { + wait: vi.fn(), + }; + + // Mock EscrowFactory__factory.connect to return the mock EscrowFactory + vi.spyOn(EscrowFactory__factory, 'connect').mockReturnValue( + mockEscrowFactoryContract + ); + + // Mock Escrow__factory.connect to return the mock Escrow + vi.spyOn(Escrow__factory, 'connect').mockReturnValue(mockEscrowContract); + + // Mock HMToken__factory.connect to return the mock HMToken + vi.spyOn(HMToken__factory, 'connect').mockReturnValue(mockTokenContract); + + escrowClient = await EscrowClient.build(mockSigner, gasPriceMultiplier); + escrowClient.escrowContract = mockEscrowContract; + escrowClient.tokenContract = mockTokenContract; + escrowClient.escrowFactoryContract = mockEscrowFactoryContract; + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('build', () => { + test('should create a new instance of EscrowClient with a Signer', async () => { + const escrowClient = await EscrowClient.build( + mockSigner, + gasPriceMultiplier + ); + + expect(escrowClient).toBeInstanceOf(EscrowClient); + }); + + test('should create a new instance of EscrowClient with a Provider', async () => { + const provider = ethers.getDefaultProvider(); + + const escrowClient = await EscrowClient.build( + provider, + gasPriceMultiplier + ); + + expect(escrowClient).toBeInstanceOf(EscrowClient); + }); + + test('should throw an error if Signer provider does not exist', async () => { + const signer = new ethers.Wallet(DEFAULT_GAS_PAYER_PRIVKEY); + + await expect( + EscrowClient.build(signer, gasPriceMultiplier) + ).rejects.toThrow(ErrorProviderDoesNotExist); + }); + + test('should throw an error if the chain ID is unsupported', async () => { + const provider = ethers.getDefaultProvider(); + + vi.spyOn(provider, 'getNetwork').mockResolvedValue({ + chainId: 1337, + } as any); + + await expect( + EscrowClient.build(provider, gasPriceMultiplier) + ).rejects.toThrow(ErrorUnsupportedChainID); + }); + }); + + describe('createEscrow', () => { + test('should throw an error if tokenAddress is an invalid address', async () => { + const invalidAddress = FAKE_ADDRESS; + + await expect( + escrowClient.createEscrow(invalidAddress, [ + ethers.constants.AddressZero, + ]) + ).rejects.toThrow(ErrorInvalidTokenAddress); + }); + + test('should throw an error if trustedHandlers contains an invalid address', async () => { + await expect( + escrowClient.createEscrow(ethers.constants.AddressZero, [FAKE_ADDRESS]) + ).rejects.toThrow(new InvalidEthereumAddressError(FAKE_ADDRESS)); + }); + + test('should create an escrow and return its address', async () => { + const tokenAddress = ethers.constants.AddressZero; + const trustedHandlers = [ethers.constants.AddressZero]; + const jobRequesterId = 'job-requester'; + const expectedEscrowAddress = ethers.constants.AddressZero; + + // Create a spy object for the createEscrow method + const createEscrowSpy = vi + .spyOn(escrowClient.escrowFactoryContract, 'createEscrow') + .mockImplementation(() => ({ + wait: async () => ({ + events: [ + { + topics: [ethers.utils.id('LaunchedV2(address,address,string)')], + args: { + escrow: expectedEscrowAddress, + }, + }, + ], + }), + })); + + const result = await escrowClient.createEscrow( + tokenAddress, + trustedHandlers, + jobRequesterId + ); + + expect(createEscrowSpy).toHaveBeenCalledWith( + tokenAddress, + trustedHandlers, + jobRequesterId, + { + gasPrice: expectedGasPrice, + } + ); + expect(result).toBe(expectedEscrowAddress); + }); + + test('should throw an error if the create an escrow fails', async () => { + const tokenAddress = ethers.constants.AddressZero; + const trustedHandlers = [ethers.constants.AddressZero]; + const jobRequesterId = 'job-requester'; + + escrowClient.escrowFactoryContract.createEscrow.mockRejectedValueOnce( + new Error() + ); + + await expect( + escrowClient.createEscrow(tokenAddress, trustedHandlers, jobRequesterId) + ).rejects.toThrow(); + + expect( + escrowClient.escrowFactoryContract.createEscrow + ).toHaveBeenCalledWith(tokenAddress, trustedHandlers, jobRequesterId, { + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const tokenAddress = ethers.constants.AddressZero; + const trustedHandlers = [ethers.constants.AddressZero]; + const jobRequesterId = 'job-requester'; + + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + escrowClient.createEscrow(tokenAddress, trustedHandlers, jobRequesterId) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); + + describe('setup', () => { + test('should throw an error if recordingOracle is an invalid address', async () => { + const escrowConfig = { + recordingOracle: FAKE_ADDRESS, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + hash: FAKE_HASH, + }; + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorInvalidRecordingOracleAddressProvided); + }); + + test('should throw an error if reputationOracle is an invalid address', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: FAKE_ADDRESS, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + hash: FAKE_HASH, + }; + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorInvalidReputationOracleAddressProvided); + }); + + test('should throw an error if exchangeOracle is an invalid address', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: FAKE_ADDRESS, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + hash: FAKE_HASH, + }; + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorInvalidExchangeOracleAddressProvided); + }); + + test('should throw an error if escrowAddress is an invalid address', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + hash: FAKE_HASH, + }; + + await expect( + escrowClient.setup(FAKE_ADDRESS, escrowConfig) + ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); + }); + + test('should throw an error if hasEscrow returns false', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + manifestHash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(false); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorEscrowAddressIsNotProvidedByFactory); + }); + + test('should throw an error if 0 <= recordingOracleFee', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(0), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + hash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorAmountMustBeGreaterThanZero); + }); + + test('should throw an error if 0 <= reputationOracleFee', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(0), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + hash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorAmountMustBeGreaterThanZero); + }); + + test('should throw an error if 0 <= exchangeOracleFee', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(0), + manifestUrl: VALID_URL, + hash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorAmountMustBeGreaterThanZero); + }); + + test('should throw an error if total fee is greater than 100', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(40), + reputationOracleFee: BigNumber.from(40), + exchangeOracleFee: BigNumber.from(40), + manifestUrl: VALID_URL, + hash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorTotalFeeMustBeLessThanHundred); + }); + + test('should throw an error if manifestUrl is an empty string', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: '', + hash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorUrlIsEmptyString); + }); + + test('should throw an error if manifestUrl is an invalid url', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: FAKE_URL, + hash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorInvalidUrl); + }); + + test('should throw an error if hash is an empty string', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + hash: '', + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(ErrorHashIsEmptyString); + }); + + test('should successfully setup escrow', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + manifestHash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.setup.mockReturnValue(true); + + await escrowClient.setup(ethers.constants.AddressZero, escrowConfig); + + expect(escrowClient.escrowContract.setup).toHaveBeenCalledWith( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + BigNumber.from(10), + BigNumber.from(10), + BigNumber.from(10), + VALID_URL, + FAKE_HASH, + { + gasPrice: expectedGasPrice, + } + ); + }); + + test('should throw an error if setup escrow fails', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + manifestHash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.setup.mockRejectedValueOnce(new Error()); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(); + + expect(escrowClient.escrowContract.setup).toHaveBeenCalledWith( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + BigNumber.from(10), + BigNumber.from(10), + BigNumber.from(10), + VALID_URL, + FAKE_HASH, + { + gasPrice: expectedGasPrice, + } + ); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + manifestHash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); + + describe('createAndSetupEscrow', () => { + test('should successfully create and setup escrow', async () => { + const escrowAddress = ethers.constants.AddressZero; + const tokenAddress = ethers.constants.AddressZero; + const trustedHandlers = [ethers.constants.AddressZero]; + const jobRequesterId = 'job-requester'; + + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + manifestHash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.createEscrow = vi.fn().mockReturnValue(escrowAddress); + escrowClient.escrowContract.setup.mockReturnValue(true); + + await escrowClient.createAndSetupEscrow( + tokenAddress, + trustedHandlers, + jobRequesterId, + escrowConfig + ); + + expect(escrowClient.createEscrow).toHaveBeenCalledWith( + tokenAddress, + trustedHandlers, + jobRequesterId + ); + expect(escrowClient.escrowContract.setup).toHaveBeenCalledWith( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + BigNumber.from(10), + BigNumber.from(10), + BigNumber.from(10), + VALID_URL, + FAKE_HASH, + { + gasPrice: expectedGasPrice, + } + ); + }); + + test('should throw an error if setup escrow fails', async () => { + const escrowConfig = { + recordingOracle: ethers.constants.AddressZero, + reputationOracle: ethers.constants.AddressZero, + exchangeOracle: ethers.constants.AddressZero, + recordingOracleFee: BigNumber.from(10), + reputationOracleFee: BigNumber.from(10), + exchangeOracleFee: BigNumber.from(10), + manifestUrl: VALID_URL, + manifestHash: FAKE_HASH, + }; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.setup.mockRejectedValueOnce(new Error()); + + await expect( + escrowClient.setup(ethers.constants.AddressZero, escrowConfig) + ).rejects.toThrow(); + + expect(escrowClient.escrowContract.setup).toHaveBeenCalledWith( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + BigNumber.from(10), + BigNumber.from(10), + BigNumber.from(10), + VALID_URL, + FAKE_HASH, + { + gasPrice: expectedGasPrice, + } + ); + }); + }); + + describe('fund', () => { + test('should throw an error if escrowAddress is an invalid address', async () => { + const invalidAddress = FAKE_ADDRESS; + const amount = BigNumber.from(10); + + await expect(escrowClient.fund(invalidAddress, amount)).rejects.toThrow( + ErrorInvalidEscrowAddressProvided + ); + }); + + test('should throw an error if hasEscrow returns false', async () => { + const escrowAddress = ethers.constants.AddressZero; + const amount = BigNumber.from(10); + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(false); + + await expect(escrowClient.fund(escrowAddress, amount)).rejects.toThrow( + ErrorEscrowAddressIsNotProvidedByFactory + ); + }); + + test('should throw an error if 0 <= amount', async () => { + const escrowAddress = ethers.constants.AddressZero; + const invalidAmount = BigNumber.from(0); + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.fund(escrowAddress, invalidAmount) + ).rejects.toThrow(ErrorAmountMustBeGreaterThanZero); + }); + + test('should successfully fund escrow', async () => { + const tokenAddress = ethers.constants.AddressZero; + const escrowAddress = ethers.constants.AddressZero; + const amount = BigNumber.from(10); + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.token.mockReturnValue(tokenAddress); + + await escrowClient.fund(escrowAddress, amount); + + expect(escrowClient.escrowContract.token).toHaveBeenCalledWith(); + expect(escrowClient.tokenContract.transfer).toHaveBeenCalledWith( + escrowAddress, + amount, + { + gasPrice: expectedGasPrice, + } + ); + }); + + test('should throw an error if setup escrow fails', async () => { + const tokenAddress = ethers.constants.AddressZero; + const escrowAddress = ethers.constants.AddressZero; + const amount = BigNumber.from(10); + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.token.mockReturnValue(tokenAddress); + escrowClient.tokenContract.transfer.mockRejectedValueOnce(new Error()); + + await expect(escrowClient.fund(escrowAddress, amount)).rejects.toThrow(); + + expect(escrowClient.escrowContract.token).toHaveBeenCalledWith(); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const tokenAddress = ethers.constants.AddressZero; + const escrowAddress = ethers.constants.AddressZero; + const amount = BigNumber.from(10); + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.token.mockReturnValue(tokenAddress); + + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect(escrowClient.fund(escrowAddress, amount)).rejects.toThrow( + new EthereumError(ErrorMissingGasPrice.message) + ); + + expect(escrowClient.escrowContract.token).toHaveBeenCalledWith(); + }); + }); + + describe('storeResults', () => { + test('should throw an error if escrowAddress is an invalid address', async () => { + const invalidAddress = FAKE_ADDRESS; + const url = VALID_URL; + const hash = FAKE_HASH; + + await expect( + escrowClient.storeResults(invalidAddress, url, hash) + ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); + }); + + test('should throw an error if hasEscrow returns false', async () => { + const escrowAddress = ethers.constants.AddressZero; + const url = VALID_URL; + const hash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(false); + + await expect( + escrowClient.storeResults(escrowAddress, url, hash) + ).rejects.toThrow(ErrorEscrowAddressIsNotProvidedByFactory); + }); + + test('should throw an error if url is an empty string', async () => { + const escrowAddress = ethers.constants.AddressZero; + const url = ''; + const hash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.storeResults(escrowAddress, url, hash) + ).rejects.toThrow(ErrorUrlIsEmptyString); + }); + + test('should throw an error if results url is invalid url', async () => { + const escrowAddress = ethers.constants.AddressZero; + const url = FAKE_URL; + const hash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.storeResults(escrowAddress, url, hash) + ).rejects.toThrow(ErrorInvalidUrl); + }); + + test('should throw an error if hash is an empty string', async () => { + const escrowAddress = ethers.constants.AddressZero; + const url = VALID_URL; + const hash = ''; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.storeResults(escrowAddress, url, hash) + ).rejects.toThrow(ErrorHashIsEmptyString); + }); + + test('should successfully store results', async () => { + const escrowAddress = ethers.constants.AddressZero; + const url = VALID_URL; + const hash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await escrowClient.storeResults(escrowAddress, url, hash); + + expect(escrowClient.escrowContract.storeResults).toHaveBeenCalledWith( + url, + hash, + { + gasPrice: expectedGasPrice, + } + ); + }); + + test('should throw an error if the store results fails', async () => { + const escrowAddress = ethers.constants.AddressZero; + const url = VALID_URL; + const hash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.storeResults.mockRejectedValueOnce( + new Error() + ); + + await expect( + escrowClient.storeResults(escrowAddress, url, hash) + ).rejects.toThrow(); + + expect(escrowClient.escrowContract.storeResults).toHaveBeenCalledWith( + url, + hash, + { + gasPrice: expectedGasPrice, + } + ); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const escrowAddress = ethers.constants.AddressZero; + const url = VALID_URL; + const hash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + escrowClient.storeResults(escrowAddress, url, hash) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); + + describe('complete', () => { + test('should throw an error if escrowAddress is an invalid address', async () => { + const invalidAddress = FAKE_ADDRESS; + + await expect(escrowClient.complete(invalidAddress)).rejects.toThrow( + ErrorInvalidEscrowAddressProvided + ); + }); + + test('should throw an error if hasEscrow returns false', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(false); + + await expect(escrowClient.complete(escrowAddress)).rejects.toThrow( + ErrorEscrowAddressIsNotProvidedByFactory + ); + }); + + test('should successfully complete escrow', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await escrowClient.complete(escrowAddress); + + expect(escrowClient.escrowContract.complete).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if the complete fails', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.complete.mockRejectedValueOnce(new Error()); + + await expect(escrowClient.complete(escrowAddress)).rejects.toThrow(); + + expect(escrowClient.escrowContract.complete).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect(escrowClient.complete(escrowAddress)).rejects.toThrow( + new EthereumError(ErrorMissingGasPrice.message) + ); + }); + }); + + describe('bulkPayOut', () => { + test('should throw an error if escrowAddress is an invalid address', async () => { + const invalidAddress = FAKE_ADDRESS; + const recipients = [ethers.constants.AddressZero]; + const amounts = [BigNumber.from(100)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + await expect( + escrowClient.bulkPayOut( + invalidAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); + }); + + test('should throw an error if hasEscrow returns false', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ethers.constants.AddressZero]; + const amounts = [BigNumber.from(100)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(false); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorEscrowAddressIsNotProvidedByFactory); + }); + + test('should throw an error if recipients length is equal to 0', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients: string[] = []; + const amounts = [BigNumber.from(100)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorRecipientCannotBeEmptyArray); + }); + + test('should throw an error if amounts length is equal to 0', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ethers.constants.AddressZero]; + const amounts: number[] = []; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorAmountsCannotBeEmptyArray); + }); + + test('should throw an error if recipients and amounts do not have the same length', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ethers.constants.AddressZero]; + const amounts = [ + BigNumber.from(100), + BigNumber.from(100), + BigNumber.from(100), + ]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorRecipientAndAmountsMustBeSameLength); + }); + + test('should throw an error if recipients contains invalid addresses', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [FAKE_ADDRESS]; + const amounts = [BigNumber.from(100)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(new InvalidEthereumAddressError(FAKE_ADDRESS)); + }); + + test('should throw an error if url is an empty string', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ethers.constants.AddressZero]; + const amounts = [BigNumber.from(100)]; + const finalResultsUrl = ''; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorUrlIsEmptyString); + }); + + test('should throw an error if final results url is an invalid url', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ethers.constants.AddressZero]; + const amounts = [BigNumber.from(100)]; + const finalResultsUrl = FAKE_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorInvalidUrl); + }); + + test('should throw an error if hash is an empty string', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ethers.constants.AddressZero]; + const amounts = [BigNumber.from(100)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = ''; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorHashIsEmptyString); + }); + + test('should throw an error if escrow does not have enough balance', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ]; + const amounts = [BigNumber.from(90), BigNumber.from(20)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.getBalance = vi.fn().mockReturnValue(BigNumber.from(50)); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(ErrorEscrowDoesNotHaveEnoughBalance); + }); + + test('should successfully bulkPayOut escrow', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ]; + const amounts = [BigNumber.from(10), BigNumber.from(10)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.getBalance = vi.fn().mockReturnValue(BigNumber.from(100)); + + await escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ); + + expect(escrowClient.escrowContract.bulkPayOut).toHaveBeenCalledWith( + recipients, + amounts, + finalResultsUrl, + finalResultsHash, + DEFAULT_TX_ID, + { + gasPrice: expectedGasPrice, + } + ); + }); + + test('should throw an error if bulkPayOut fails', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ]; + const amounts = [BigNumber.from(10), BigNumber.from(10)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.getBalance = vi.fn().mockReturnValue(BigNumber.from(100)); + escrowClient.escrowContract.bulkPayOut.mockRejectedValueOnce(new Error()); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(); + + expect(escrowClient.escrowContract.bulkPayOut).toHaveBeenCalledWith( + recipients, + amounts, + finalResultsUrl, + finalResultsHash, + DEFAULT_TX_ID, + { + gasPrice: expectedGasPrice, + } + ); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const escrowAddress = ethers.constants.AddressZero; + const recipients = [ + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ]; + const amounts = [BigNumber.from(10), BigNumber.from(10)]; + const finalResultsUrl = VALID_URL; + const finalResultsHash = FAKE_HASH; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.getBalance = vi.fn().mockReturnValue(BigNumber.from(100)); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + escrowClient.bulkPayOut( + escrowAddress, + recipients, + amounts, + finalResultsUrl, + finalResultsHash + ) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); + + describe('cancel', () => { + test('should throw an error if escrowAddress is an invalid address', async () => { + const invalidAddress = FAKE_ADDRESS; + + await expect(escrowClient.cancel(invalidAddress)).rejects.toThrow( + ErrorInvalidEscrowAddressProvided + ); + }); + + test('should throw an error if hasEscrow returns false', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(false); + + await expect(escrowClient.cancel(escrowAddress)).rejects.toThrow( + ErrorEscrowAddressIsNotProvidedByFactory + ); + }); + + test('should successfully cancel escrow', async () => { + const escrowAddress = ethers.constants.AddressZero; + const amountRefunded = BigNumber.from(1); + + escrowClient.escrowContract.token.mockResolvedValueOnce( + ethers.constants.AddressZero + ); + + const log = { + address: ethers.constants.AddressZero, + name: 'Transfer', + args: [ + ethers.constants.AddressZero, + ethers.constants.AddressZero, + amountRefunded, + ], + }; + mockTx.wait.mockResolvedValueOnce({ + transactionHash: FAKE_HASH, + logs: [log], + }); + + const mockHMTokenFactoryContract = { + interface: { + parseLog: vi.fn().mockReturnValueOnce(log), + }, + }; + + vi.spyOn(HMToken__factory, 'connect').mockReturnValue( + mockHMTokenFactoryContract as any + ); + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.cancel.mockResolvedValueOnce(mockTx); + + const result = await escrowClient.cancel(escrowAddress); + + expect(result).toStrictEqual({ + amountRefunded, + txHash: FAKE_HASH, + }); + expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if the cancel fails', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.cancel.mockRejectedValueOnce(new Error()); + + await expect(escrowClient.cancel(escrowAddress)).rejects.toThrow(); + + expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if the wait fails', async () => { + const escrowAddress = ethers.constants.AddressZero; + mockTx.wait.mockRejectedValueOnce(new Error()); + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.cancel.mockResolvedValueOnce(mockTx); + + await expect(escrowClient.cancel(escrowAddress)).rejects.toThrow(); + + expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if transfer event not found in transaction logs', async () => { + const escrowAddress = ethers.constants.AddressZero; + mockTx.wait.mockResolvedValueOnce({ + transactionHash: FAKE_HASH, + logs: [ + { + address: ethers.constants.AddressZero, + name: 'NotTransfer', + args: [ + ethers.constants.AddressZero, + ethers.constants.AddressZero, + undefined, + ], + }, + ], + }); + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.cancel.mockResolvedValueOnce(mockTx); + + const mockHMTokenFactoryContract = { + interface: { + parseLog: vi.fn(), + }, + }; + + vi.spyOn(HMToken__factory, 'connect').mockReturnValue( + mockHMTokenFactoryContract as any + ); + + await expect(escrowClient.cancel(escrowAddress)).rejects.toThrow(); + + expect(escrowClient.escrowContract.cancel).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect(escrowClient.cancel(escrowAddress)).rejects.toThrow( + new EthereumError(ErrorMissingGasPrice.message) + ); + }); + }); + + describe('abort', () => { + test('should throw an error if escrowAddress is an invalid address', async () => { + const invalidAddress = FAKE_ADDRESS; + + await expect(escrowClient.abort(invalidAddress)).rejects.toThrow( + ErrorInvalidEscrowAddressProvided + ); + }); + + test('should throw an error if hasEscrow returns false', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(false); + + await expect(escrowClient.abort(escrowAddress)).rejects.toThrow( + ErrorEscrowAddressIsNotProvidedByFactory + ); + }); + + test('should successfully abort escrow', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await escrowClient.abort(escrowAddress); + + expect(escrowClient.escrowContract.abort).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if abort fails', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.abort.mockRejectedValueOnce(new Error()); + + await expect(escrowClient.abort(escrowAddress)).rejects.toThrow(); + + expect(escrowClient.escrowContract.abort).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const escrowAddress = ethers.constants.AddressZero; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect(escrowClient.abort(escrowAddress)).rejects.toThrow( + new EthereumError(ErrorMissingGasPrice.message) + ); + }); + }); + + describe('addTrustedHandlers', () => { + test('should throw an error if escrowAddress is an invalid address', async () => { + const escrowAddress = FAKE_ADDRESS; + const trustedHandlers = [ethers.constants.AddressZero]; + + await expect( + escrowClient.addTrustedHandlers(escrowAddress, trustedHandlers) + ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); + }); + + test('should throw an error if hasEscrow returns false', async () => { + const escrowAddress = ethers.constants.AddressZero; + const trustedHandlers = [ethers.constants.AddressZero]; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(false); + + await expect( + escrowClient.addTrustedHandlers(escrowAddress, trustedHandlers) + ).rejects.toThrow(ErrorEscrowAddressIsNotProvidedByFactory); + }); + + test('should throw an error if trusted handlers length is equal to 0', async () => { + const escrowAddress = ethers.constants.AddressZero; + const trustedHandlers: string[] = []; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.addTrustedHandlers(escrowAddress, trustedHandlers) + ).rejects.toThrow(ErrorListOfHandlersCannotBeEmpty); + }); + + test('should throw an error if trusted handlers contains invalid addresses', async () => { + const escrowAddress = ethers.constants.AddressZero; + const trustedHandlers = [FAKE_ADDRESS]; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await expect( + escrowClient.addTrustedHandlers(escrowAddress, trustedHandlers) + ).rejects.toThrow(new InvalidEthereumAddressError(FAKE_ADDRESS)); + }); + + test('should successfully addTrustedHandlers', async () => { + const escrowAddress = ethers.constants.AddressZero; + const trustedHandlers = [ethers.constants.AddressZero]; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + + await escrowClient.addTrustedHandlers(escrowAddress, trustedHandlers); + + expect( + escrowClient.escrowContract.addTrustedHandlers + ).toHaveBeenCalledWith(trustedHandlers, { + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if addTrustedHandlers fails', async () => { + const escrowAddress = ethers.constants.AddressZero; + const trustedHandlers = [ethers.constants.AddressZero]; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + escrowClient.escrowContract.addTrustedHandlers.mockRejectedValueOnce( + new Error() + ); + + await expect( + escrowClient.addTrustedHandlers(escrowAddress, trustedHandlers) + ).rejects.toThrow(); + + expect( + escrowClient.escrowContract.addTrustedHandlers + ).toHaveBeenCalledWith(trustedHandlers, { + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + const escrowAddress = ethers.constants.AddressZero; + const trustedHandlers = [ethers.constants.AddressZero]; + + escrowClient.escrowFactoryContract.hasEscrow.mockReturnValue(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + escrowClient.addTrustedHandlers(escrowAddress, trustedHandlers) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); +}); diff --git a/packages/sdk/typescript/human-protocol-sdk/test/kvstore.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/kvstore.test.ts index 6050267d35..4105f2f6c7 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/kvstore.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/kvstore.test.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { ethers } from 'ethers'; +import { BigNumber, ethers } from 'ethers'; import { beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; import { NETWORKS } from '../src/constants'; import { ChainId } from '../src/enums'; @@ -105,8 +105,12 @@ describe('KVStoreClient', () => { test('should set the key-value pair if both key and value are provided', async () => { mockKVStoreContract.set.mockResolvedValue(null); - expect(kvStoreClient.set('key1', 'value1')).resolves.toBeUndefined(); - expect(mockKVStoreContract.set).toHaveBeenCalledWith('key1', 'value1'); + expect(await kvStoreClient.set('key1', 'value1')).toBeUndefined(); + expect(mockKVStoreContract.set).toHaveBeenCalledWith( + 'key1', + 'value1', + {} + ); }); test('should throw an error when attempting to set a value without signer', async () => { @@ -126,7 +130,11 @@ describe('KVStoreClient', () => { Error('Failed to set value: could not detect network') ); - expect(mockKVStoreContract.set).toHaveBeenCalledWith('key1', 'value1'); + expect(mockKVStoreContract.set).toHaveBeenCalledWith( + 'key1', + 'value1', + {} + ); }); }); @@ -141,7 +149,8 @@ describe('KVStoreClient', () => { [ 'https://example.com', ethers.utils.keccak256(ethers.utils.toUtf8Bytes('example')), - ] + ], + {} ); }); @@ -157,7 +166,8 @@ describe('KVStoreClient', () => { [ 'https://example.com', ethers.utils.keccak256(ethers.utils.toUtf8Bytes('example')), - ] + ], + {} ); }); @@ -189,7 +199,8 @@ describe('KVStoreClient', () => { [ 'https://example.com', ethers.utils.keccak256(ethers.utils.toUtf8Bytes('example')), - ] + ], + {} ); }); }); @@ -217,11 +228,12 @@ describe('KVStoreClient', () => { test('should set the key-value pairs if both keys and values arrays are provided correctly', async () => { mockKVStoreContract.setBulk.mockResolvedValue(null); expect( - kvStoreClient.setBulk(['key1', 'key2'], ['value1', 'value2']) - ).resolves.resolves.toBeUndefined(); + await kvStoreClient.setBulk(['key1', 'key2'], ['value1', 'value2']) + ).toBeUndefined(); expect(mockKVStoreContract.setBulk).toHaveBeenCalledWith( ['key1', 'key2'], - ['value1', 'value2'] + ['value1', 'value2'], + {} ); }); @@ -244,7 +256,8 @@ describe('KVStoreClient', () => { ); expect(mockKVStoreContract.setBulk).toHaveBeenCalledWith( ['key1', 'key2'], - ['value1', 'value2'] + ['value1', 'value2'], + {} ); }); }); @@ -415,3 +428,277 @@ describe('KVStoreClient', () => { }); }); }); + +describe('KVStoreClient with lower gas price', () => { + const gasPriceMultiplier = 0.5; + const defaultGasPrice = BigNumber.from(10); + const expectedGasPrice = BigNumber.from(5); + + let mockProvider: any, + mockSigner: any, + network: NetworkData | undefined, + kvStoreClient: any, + mockKVStoreContract: any; + + beforeAll(async () => { + const provider = new ethers.providers.JsonRpcProvider(); + mockProvider = { + ...provider, + getNetwork: vi.fn().mockReturnValue({ chainId: ChainId.LOCALHOST }), + getFeeData: vi.fn().mockResolvedValue({ gasPrice: defaultGasPrice }), + }; + mockSigner = { + ...provider.getSigner(), + provider: { + ...mockProvider, + }, + getAddress: vi.fn().mockReturnValue(ethers.constants.AddressZero), + }; + network = NETWORKS[ChainId.LOCALHOST]; + }); + + beforeEach(async () => { + kvStoreClient = await KVStoreClient.build(mockSigner, gasPriceMultiplier); + mockKVStoreContract = { + ...kvStoreClient.contract, + set: vi.fn(), + setBulk: vi.fn(), + get: vi.fn(), + address: network?.kvstoreAddress, + }; + kvStoreClient.contract = mockKVStoreContract; + }); + + describe('build', () => { + test('should create a new instance of KVStoreClient with a Signer', async () => { + const kvStoreClient = await KVStoreClient.build( + mockSigner, + gasPriceMultiplier + ); + + expect(kvStoreClient).toBeInstanceOf(KVStoreClient); + }); + + test('should create a new instance of KVStoreClient with a Provider', async () => { + const provider = ethers.getDefaultProvider(); + + const kvStoreClient = await KVStoreClient.build( + provider, + gasPriceMultiplier + ); + + expect(kvStoreClient).toBeInstanceOf(KVStoreClient); + }); + + test('should throw an error if Signer provider does not exist', async () => { + const signer = new ethers.Wallet(DEFAULT_GAS_PAYER_PRIVKEY); + + await expect( + KVStoreClient.build(signer, gasPriceMultiplier) + ).rejects.toThrow(ErrorProviderDoesNotExist); + }); + + test('should throw an error if the chain ID is unsupported', async () => { + const provider = ethers.getDefaultProvider(); + + vi.spyOn(provider, 'getNetwork').mockResolvedValue({ + chainId: 1337, + } as any); + + await expect( + KVStoreClient.build(provider, gasPriceMultiplier) + ).rejects.toThrow(ErrorUnsupportedChainID); + }); + }); + + describe('set', () => { + test('should throw an error if key is empty', async () => { + const setSpy = vi.spyOn(kvStoreClient, 'set'); + await expect(kvStoreClient.set('', 'test')).rejects.toThrow( + ErrorKVStoreEmptyKey + ); + expect(setSpy).toHaveBeenCalledWith('', 'test'); + }); + + test('should set the key-value pair if both key and value are provided', async () => { + mockKVStoreContract.set.mockResolvedValue(null); + expect(await kvStoreClient.set('key1', 'value1')).toBeUndefined(); + expect(mockKVStoreContract.set).toHaveBeenCalledWith('key1', 'value1', { + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error when attempting to set a value without signer', async () => { + kvStoreClient = await KVStoreClient.build(mockProvider); + + await expect(kvStoreClient.set('key1', 'value1')).rejects.toThrow( + ErrorSigner + ); + }); + + test('should throw an error when a network error occurs', async () => { + mockKVStoreContract.set.mockRejectedValue( + new Error('could not detect network') + ); + + await expect(kvStoreClient.set('key1', 'value1')).rejects.toThrow( + Error('Failed to set value: could not detect network') + ); + + expect(mockKVStoreContract.set).toHaveBeenCalledWith('key1', 'value1', { + gasPrice: expectedGasPrice, + }); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockKVStoreContract.set.mockResolvedValue(null); + mockProvider.getFeeData.mockResolvedValueOnce({ gasPrice: null }); + + await expect(kvStoreClient.set('key1', 'value1')).rejects.toThrow( + Error('Failed to set value: Missing gas price') + ); + }); + }); + + describe('setURL', () => { + test('should set the URL and hash', async () => { + mockKVStoreContract.set.mockResolvedValue(null); + + expect(await kvStoreClient.setURL('https://example.com')).toBeUndefined(); + + expect(mockKVStoreContract.setBulk).toHaveBeenCalledWith( + ['url', 'urlHash'], + [ + 'https://example.com', + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('example')), + ], + { gasPrice: expectedGasPrice } + ); + }); + + test('should set the URL and hash for the given URL key', async () => { + mockKVStoreContract.set.mockResolvedValue(null); + + expect( + await kvStoreClient.setURL('https://example.com', 'linkedinUrl') + ).toBeUndefined(); + + expect(mockKVStoreContract.setBulk).toHaveBeenCalledWith( + ['linkedinUrl', 'linkedinUrlHash'], + [ + 'https://example.com', + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('example')), + ], + { gasPrice: expectedGasPrice } + ); + }); + + test('should throw an error when attempting to set the URL without signer', async () => { + kvStoreClient = await KVStoreClient.build(mockProvider); + + await expect(kvStoreClient.setURL('example.com')).rejects.toThrow( + ErrorSigner + ); + }); + + test('should throw an error when attempting to set invalid URL', async () => { + await expect(kvStoreClient.setURL('invalid_url')).rejects.toThrow( + ErrorInvalidUrl + ); + }); + + test('should throw an error when a network error occurs', async () => { + mockKVStoreContract.setBulk.mockRejectedValue( + new Error('could not detect network') + ); + + await expect(kvStoreClient.setURL('https://example.com')).rejects.toThrow( + Error('Failed to set URL and hash: could not detect network') + ); + + expect(mockKVStoreContract.setBulk).toHaveBeenCalledWith( + ['url', 'urlHash'], + [ + 'https://example.com', + ethers.utils.keccak256(ethers.utils.toUtf8Bytes('example')), + ], + { gasPrice: expectedGasPrice } + ); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockKVStoreContract.setBulk.mockResolvedValue(null); + mockProvider.getFeeData.mockResolvedValueOnce({ gasPrice: null }); + + await expect(kvStoreClient.setURL('https://example.com')).rejects.toThrow( + Error('Failed to set URL and hash: Missing gas price') + ); + }); + }); + + describe('setBulk', () => { + test('should throw an error if keys and values arrays are not of the same length', async () => { + const setBulkSpy = vi.spyOn(kvStoreClient, 'setBulk'); + await expect( + kvStoreClient.setBulk(['key1', 'key2'], ['value1']) + ).rejects.toThrow(ErrorKVStoreArrayLength); + expect(setBulkSpy).toHaveBeenCalledWith(['key1', 'key2'], ['value1']); + }); + + test('should throw an error if any of the keys is empty', async () => { + const setBulkSpy = vi.spyOn(kvStoreClient, 'setBulk'); + await expect( + kvStoreClient.setBulk(['key1', ''], ['value1', 'value2']) + ).rejects.toThrow(ErrorKVStoreEmptyKey); + expect(setBulkSpy).toHaveBeenCalledWith( + ['key1', ''], + ['value1', 'value2'] + ); + }); + + test('should set the key-value pairs if both keys and values arrays are provided correctly', async () => { + mockKVStoreContract.setBulk.mockResolvedValue(null); + expect( + await kvStoreClient.setBulk(['key1', 'key2'], ['value1', 'value2']) + ).toBeUndefined(); + expect(mockKVStoreContract.setBulk).toHaveBeenCalledWith( + ['key1', 'key2'], + ['value1', 'value2'], + { gasPrice: expectedGasPrice } + ); + }); + + test('should throw an error when attempting to set values without signer', async () => { + kvStoreClient = await KVStoreClient.build(mockProvider); + + await expect( + kvStoreClient.setBulk(['key1', 'key2'], ['value1', 'value2']) + ).rejects.toThrow(ErrorSigner); + }); + + test('should throw an error if a network error occurs', async () => { + mockKVStoreContract.setBulk.mockRejectedValue( + new Error('could not detect network') + ); + await expect( + kvStoreClient.setBulk(['key1', 'key2'], ['value1', 'value2']) + ).rejects.toThrow( + new Error('Failed to set bulk values: could not detect network') + ); + expect(mockKVStoreContract.setBulk).toHaveBeenCalledWith( + ['key1', 'key2'], + ['value1', 'value2'], + { gasPrice: expectedGasPrice } + ); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockKVStoreContract.setBulk.mockResolvedValue(null); + mockProvider.getFeeData.mockResolvedValueOnce({ gasPrice: null }); + + await expect( + kvStoreClient.setBulk(['key1', 'key2'], ['value1', 'value2']) + ).rejects.toThrow(Error('Failed to set bulk values: Missing gas price')); + }); + }); +}); diff --git a/packages/sdk/typescript/human-protocol-sdk/test/staking.test.ts b/packages/sdk/typescript/human-protocol-sdk/test/staking.test.ts index a578239605..15cbc7e643 100644 --- a/packages/sdk/typescript/human-protocol-sdk/test/staking.test.ts +++ b/packages/sdk/typescript/human-protocol-sdk/test/staking.test.ts @@ -9,8 +9,10 @@ import { ErrorInvalidStakerAddressProvided, ErrorInvalidStakingValueSign, ErrorInvalidStakingValueType, + ErrorMissingGasPrice, ErrorProviderDoesNotExist, ErrorUnsupportedChainID, + EthereumError, } from '../src/error'; import { IAllocation, IReward, ILeader } from '../src/interfaces'; import { StakingClient } from '../src/staking'; @@ -42,7 +44,8 @@ describe('StakingClient', () => { mockSigner: any, mockStakingContract: any, mockEscrowFactoryContract: any, - mockTokenContract: any; + mockTokenContract: any, + mockRewardPoolContract: any; beforeEach(async () => { mockProvider = { @@ -64,12 +67,11 @@ describe('StakingClient', () => { slash: vi.fn(), allocate: vi.fn(), closeAllocation: vi.fn(), - distributeRewards: vi.fn(), + distributeReward: vi.fn(), getRewards: vi.fn(), getStaker: vi.fn(), getListOfStakers: vi.fn(), getAllocation: vi.fn(), - rewardPool: vi.fn().mockResolvedValueOnce(ethers.constants.AddressZero), address: ethers.constants.AddressZero, }; @@ -82,10 +84,15 @@ describe('StakingClient', () => { approve: vi.fn(), }; + mockRewardPoolContract = { + distributeReward: vi.fn(), + }; + stakingClient = await StakingClient.build(mockSigner); stakingClient.stakingContract = mockStakingContract; stakingClient.tokenContract = mockTokenContract; stakingClient.escrowFactoryContract = mockEscrowFactoryContract; + stakingClient.rewardPoolContract = mockRewardPoolContract; }); afterEach(() => { @@ -155,10 +162,11 @@ describe('StakingClient', () => { confirmations: FAKE_TRANSACTION_CONFIRMATIONS, }); - await expect(stakingClient.approveStake(amount)).resolves.toBeUndefined(); + await expect(await stakingClient.approveStake(amount)).toBeUndefined(); expect(mockTokenContract.approve).toBeCalledWith( ethers.constants.AddressZero, - amount + amount, + {} ); expect(mockTokenContract.approve).toHaveBeenCalledTimes(1); }); @@ -171,7 +179,8 @@ describe('StakingClient', () => { await expect(stakingClient.approveStake(amount)).rejects.toThrow(); expect(mockTokenContract.approve).toBeCalledWith( ethers.constants.AddressZero, - amount + amount, + {} ); expect(mockTokenContract.approve).toHaveBeenCalledTimes(1); }); @@ -200,7 +209,7 @@ describe('StakingClient', () => { await stakingClient.stake(amount); - expect(mockStakingContract.stake).toHaveBeenCalledWith(amount); + expect(mockStakingContract.stake).toHaveBeenCalledWith(amount, {}); expect(mockStakingContract.stake).toHaveBeenCalledTimes(1); }); @@ -210,7 +219,7 @@ describe('StakingClient', () => { mockStakingContract.stake.mockRejectedValueOnce(new Error()); await expect(stakingClient.stake(amount)).rejects.toThrow(); - expect(mockStakingContract.stake).toHaveBeenCalledWith(amount); + expect(mockStakingContract.stake).toHaveBeenCalledWith(amount, {}); expect(mockStakingContract.stake).toHaveBeenCalledTimes(1); }); }); @@ -236,7 +245,7 @@ describe('StakingClient', () => { test('should call the unstake function on the staking contract with the given amount', async () => { await stakingClient.unstake(amount); - expect(mockStakingContract.unstake).toHaveBeenCalledWith(amount); + expect(mockStakingContract.unstake).toHaveBeenCalledWith(amount, {}); expect(mockStakingContract.unstake).toHaveBeenCalledTimes(1); }); @@ -244,7 +253,7 @@ describe('StakingClient', () => { mockStakingContract.unstake.mockRejectedValueOnce(new Error()); await expect(stakingClient.unstake(amount)).rejects.toThrow(); - expect(mockStakingContract.unstake).toHaveBeenCalledWith(amount); + expect(mockStakingContract.unstake).toHaveBeenCalledWith(amount, {}); expect(mockStakingContract.unstake).toHaveBeenCalledTimes(1); }); }); @@ -255,6 +264,7 @@ describe('StakingClient', () => { await stakingClient.withdraw(); + expect(mockStakingContract.withdraw).toHaveBeenCalledWith({}); expect(mockStakingContract.withdraw).toHaveBeenCalledTimes(1); }); @@ -262,6 +272,7 @@ describe('StakingClient', () => { mockStakingContract.withdraw.mockRejectedValueOnce(new Error()); await expect(stakingClient.withdraw()).rejects.toThrow(); + expect(mockStakingContract.withdraw).toHaveBeenCalledWith({}); expect(mockStakingContract.withdraw).toHaveBeenCalledTimes(1); }); }); @@ -362,7 +373,8 @@ describe('StakingClient', () => { ethers.constants.AddressZero, ethers.constants.AddressZero, ethers.constants.AddressZero, - amount + amount, + {} ); expect(mockStakingContract.slash).toHaveBeenCalledTimes(1); }); @@ -382,7 +394,8 @@ describe('StakingClient', () => { ethers.constants.AddressZero, ethers.constants.AddressZero, ethers.constants.AddressZero, - amount + amount, + {} ); expect(mockStakingContract.slash).toHaveBeenCalledTimes(1); }); @@ -429,7 +442,8 @@ describe('StakingClient', () => { expect(mockStakingContract.allocate).toHaveBeenCalledWith( ethers.constants.AddressZero, - amount + amount, + {} ); expect(mockStakingContract.allocate).toHaveBeenCalledTimes(1); }); @@ -443,7 +457,8 @@ describe('StakingClient', () => { ).rejects.toThrow(); expect(mockStakingContract.allocate).toHaveBeenCalledWith( ethers.constants.AddressZero, - amount + amount, + {} ); expect(mockStakingContract.allocate).toHaveBeenCalledTimes(1); }); @@ -477,7 +492,8 @@ describe('StakingClient', () => { ).rejects.toThrow(); expect(mockStakingContract.closeAllocation).toHaveBeenCalledWith( - ethers.constants.AddressZero + ethers.constants.AddressZero, + {} ); expect(mockStakingContract.closeAllocation).toHaveBeenCalledTimes(1); }); @@ -489,42 +505,43 @@ describe('StakingClient', () => { await stakingClient.closeAllocation(ethers.constants.AddressZero); expect(mockStakingContract.closeAllocation).toHaveBeenCalledWith( - ethers.constants.AddressZero + ethers.constants.AddressZero, + {} ); expect(mockStakingContract.closeAllocation).toHaveBeenCalledTimes(1); }); }); - describe('distributeRewards', () => { + describe('distributeReward', () => { const invalidAddress = 'InvalidAddress'; test('should throw an error if an invalid escrow address is provided', async () => { await expect( - stakingClient.distributeRewards(invalidAddress) + stakingClient.distributeReward(invalidAddress) ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); - expect(mockStakingContract.distributeRewards).toHaveBeenCalledTimes(0); + expect(mockRewardPoolContract.distributeReward).toHaveBeenCalledTimes(0); }); test('throws an error if escrow address is not provided by the factory', async () => { mockEscrowFactoryContract.hasEscrow.mockRejectedValueOnce(new Error()); await expect( - stakingClient.distributeRewards(ethers.constants.AddressZero) + stakingClient.distributeReward(ethers.constants.AddressZero) ).rejects.toThrow(); - expect(mockStakingContract.distributeRewards).toHaveBeenCalledTimes(0); + expect(mockRewardPoolContract.distributeReward).toHaveBeenCalledTimes(0); }); test('should call distributeReward on the reward pool contract', async () => { mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); - vi.spyOn(stakingClient, 'distributeRewards').mockImplementation(() => - Promise.resolve(undefined) - ); + mockRewardPoolContract.distributeReward.mockResolvedValueOnce(); - const results = await stakingClient.distributeRewards( - ethers.constants.AddressZero - ); + await stakingClient.distributeReward(ethers.constants.AddressZero); - expect(results).toBeUndefined(); + expect(mockRewardPoolContract.distributeReward).toHaveBeenCalledWith( + ethers.constants.AddressZero, + {} + ); + expect(mockRewardPoolContract.distributeReward).toHaveBeenCalledTimes(1); }); }); @@ -700,3 +717,612 @@ describe('StakingClient', () => { }); }); }); + +describe('StakingClient with higher gas price', () => { + const gasPriceMultiplier = 2; + const defaultGasPrice = BigNumber.from(10); + const expectedGasPrice = BigNumber.from(20); + + const provider = new ethers.providers.JsonRpcProvider(); + let stakingClient: any, + mockProvider: any, + mockSigner: any, + mockStakingContract: any, + mockEscrowFactoryContract: any, + mockTokenContract: any, + mockRewardPoolContract: any; + + beforeEach(async () => { + mockProvider = { + ...provider, + getNetwork: vi.fn().mockReturnValue({ chainId: ChainId.MAINNET }), + getFeeData: vi.fn().mockResolvedValue({ gasPrice: defaultGasPrice }), + }; + mockSigner = { + ...provider.getSigner(), + provider: { + ...mockProvider, + }, + getAddress: vi.fn().mockReturnValue(ethers.constants.AddressZero), + }; + + mockStakingContract = { + stake: vi.fn(), + unstake: vi.fn(), + withdraw: vi.fn(), + slash: vi.fn(), + allocate: vi.fn(), + closeAllocation: vi.fn(), + distributeReward: vi.fn(), + getRewards: vi.fn(), + getStaker: vi.fn(), + getListOfStakers: vi.fn(), + getAllocation: vi.fn(), + address: ethers.constants.AddressZero, + }; + + mockEscrowFactoryContract = { + hasEscrow: vi.fn(), + }; + + mockTokenContract = { + allowance: vi.fn(), + approve: vi.fn(), + }; + + mockRewardPoolContract = { + distributeReward: vi.fn(), + }; + + stakingClient = await StakingClient.build(mockSigner, gasPriceMultiplier); + stakingClient.stakingContract = mockStakingContract; + stakingClient.tokenContract = mockTokenContract; + stakingClient.escrowFactoryContract = mockEscrowFactoryContract; + stakingClient.rewardPoolContract = mockRewardPoolContract; + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('build', () => { + test('should create a new instance of StakingClient with a Signer', async () => { + const stakingClient = await StakingClient.build( + mockSigner as Signer, + gasPriceMultiplier + ); + + expect(stakingClient).toBeInstanceOf(StakingClient); + }); + + test('should create a new instance of StakingClient with a Provider', async () => { + const provider = ethers.getDefaultProvider(); + + const stakingClient = await StakingClient.build( + provider, + gasPriceMultiplier + ); + + expect(stakingClient).toBeInstanceOf(StakingClient); + }); + + test('should throw an error if Signer provider does not exist', async () => { + const signer = new ethers.Wallet(DEFAULT_GAS_PAYER_PRIVKEY); + + await expect( + StakingClient.build(signer, gasPriceMultiplier) + ).rejects.toThrow(ErrorProviderDoesNotExist); + }); + + test('should throw an error if the chain ID is unsupported', async () => { + const provider = ethers.getDefaultProvider(); + + vi.spyOn(provider, 'getNetwork').mockResolvedValue({ + chainId: 1337, + } as any); + + await expect( + StakingClient.build(provider, gasPriceMultiplier) + ).rejects.toThrow(ErrorUnsupportedChainID); + }); + }); + + describe('approveStake', () => { + const amount = BigNumber.from(FAKE_AMOUNT); + const negativeAmount = BigNumber.from(FAKE_NEGATIVE_AMOUNT); + + test('should throw an error if the amount is not a BigNumber', async () => { + await expect(stakingClient.approveStake('foo')).rejects.toThrow( + ErrorInvalidStakingValueType + ); + expect(mockTokenContract.approve).toHaveBeenCalledTimes(0); + }); + + test('should throw an error if the amount is negative', async () => { + await expect(stakingClient.approveStake(negativeAmount)).rejects.toThrow( + ErrorInvalidStakingValueSign + ); + expect(mockTokenContract.approve).toHaveBeenCalledTimes(0); + }); + + test('should not fail and return void if the allowance is sufficient and the approval is successful', async () => { + stakingClient.isAllowance = vi.fn().mockResolvedValue(true); + + mockTokenContract.approve = vi.fn().mockResolvedValue({ + hash: FAKE_TRANSACTION_HASH, + blockNumber: FAKE_BLOCK_NUMBER, + confirmations: FAKE_TRANSACTION_CONFIRMATIONS, + }); + + await expect(await stakingClient.approveStake(amount)).toBeUndefined(); + expect(mockTokenContract.approve).toBeCalledWith( + ethers.constants.AddressZero, + amount, + { gasPrice: expectedGasPrice } + ); + expect(mockTokenContract.approve).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if the approval fails', async () => { + stakingClient.isAllowance = vi.fn().mockResolvedValue(true); + + mockTokenContract.approve = vi.fn().mockRejectedValue(new Error()); + + await expect(stakingClient.approveStake(amount)).rejects.toThrow(); + expect(mockTokenContract.approve).toBeCalledWith( + ethers.constants.AddressZero, + amount, + { gasPrice: expectedGasPrice } + ); + expect(mockTokenContract.approve).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + stakingClient.isAllowance = vi.fn().mockResolvedValue(true); + + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect(stakingClient.approveStake(amount)).rejects.toThrow( + new EthereumError(ErrorMissingGasPrice.message) + ); + }); + }); + + describe('stake', () => { + const amount = BigNumber.from(FAKE_AMOUNT); + const negativeAmount = BigNumber.from(FAKE_NEGATIVE_AMOUNT); + + test('should throw an error if amount is not a BigNumber', async () => { + await expect(stakingClient.stake('foo')).rejects.toThrow( + ErrorInvalidStakingValueType + ); + expect(mockStakingContract.stake).toHaveBeenCalledTimes(0); + }); + + test('should throw an error if amount is negative', async () => { + await expect(stakingClient.stake(negativeAmount)).rejects.toThrow( + ErrorInvalidStakingValueSign + ); + expect(mockStakingContract.stake).toHaveBeenCalledTimes(0); + }); + + test('should call the stake function on the staking contract with the given amount', async () => { + mockTokenContract.allowance.mockResolvedValueOnce(amount); + + await stakingClient.stake(amount); + + expect(mockStakingContract.stake).toHaveBeenCalledWith(amount, { + gasPrice: expectedGasPrice, + }); + expect(mockStakingContract.stake).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if the stake function on the staking contract fails', async () => { + mockTokenContract.allowance.mockResolvedValueOnce(amount); + + mockStakingContract.stake.mockRejectedValueOnce(new Error()); + + await expect(stakingClient.stake(amount)).rejects.toThrow(); + expect(mockStakingContract.stake).toHaveBeenCalledWith(amount, { + gasPrice: expectedGasPrice, + }); + expect(mockStakingContract.stake).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockTokenContract.allowance.mockResolvedValueOnce(amount); + + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect(stakingClient.stake(amount)).rejects.toThrow( + new EthereumError(ErrorMissingGasPrice.message) + ); + }); + }); + + describe('unstake', () => { + const amount = BigNumber.from(FAKE_AMOUNT); + const negativeAmount = BigNumber.from(FAKE_NEGATIVE_AMOUNT); + + test('should throw an error if amount is not a BigNumber', async () => { + await expect(stakingClient.unstake('foo')).rejects.toThrow( + ErrorInvalidStakingValueType + ); + expect(mockStakingContract.unstake).toHaveBeenCalledTimes(0); + }); + + test('should throw an error if amount is negative', async () => { + await expect(stakingClient.unstake(negativeAmount)).rejects.toThrow( + ErrorInvalidStakingValueSign + ); + expect(mockStakingContract.unstake).toHaveBeenCalledTimes(0); + }); + + test('should call the unstake function on the staking contract with the given amount', async () => { + await stakingClient.unstake(amount); + + expect(mockStakingContract.unstake).toHaveBeenCalledWith(amount, { + gasPrice: expectedGasPrice, + }); + expect(mockStakingContract.unstake).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if the unstake function on the staking contract fails', async () => { + mockStakingContract.unstake.mockRejectedValueOnce(new Error()); + + await expect(stakingClient.unstake(amount)).rejects.toThrow(); + expect(mockStakingContract.unstake).toHaveBeenCalledWith(amount, { + gasPrice: expectedGasPrice, + }); + expect(mockStakingContract.unstake).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect(stakingClient.unstake(amount)).rejects.toThrow( + new EthereumError(ErrorMissingGasPrice.message) + ); + }); + }); + + describe('withdraw', () => { + test('should call the withdraw method with the correct parameters', async () => { + mockStakingContract.withdraw.mockResolvedValueOnce(); + + await stakingClient.withdraw(); + + expect(mockStakingContract.withdraw).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + expect(mockStakingContract.withdraw).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if the withdraw method of the staking contract fails', async () => { + mockStakingContract.withdraw.mockRejectedValueOnce(new Error()); + + await expect(stakingClient.withdraw()).rejects.toThrow(); + expect(mockStakingContract.withdraw).toHaveBeenCalledWith({ + gasPrice: expectedGasPrice, + }); + expect(mockStakingContract.withdraw).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect(stakingClient.withdraw()).rejects.toThrow( + new EthereumError(ErrorMissingGasPrice.message) + ); + }); + }); + + describe('slash', () => { + const amount = BigNumber.from(FAKE_AMOUNT); + const negativeAmount = BigNumber.from(FAKE_NEGATIVE_AMOUNT); + const invalidAddress = 'InvalidAddress'; + + test('throws an error if amount is not a BigNumber', async () => { + await expect( + stakingClient.slash( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + 'foo' + ) + ).rejects.toThrow(ErrorInvalidStakingValueType); + expect(mockStakingContract.slash).toHaveBeenCalledTimes(0); + }); + + test('throws an error if amount is negative', async () => { + await expect( + stakingClient.slash( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + negativeAmount + ) + ).rejects.toThrow(ErrorInvalidStakingValueSign); + expect(mockStakingContract.slash).toHaveBeenCalledTimes(0); + }); + + test('throws an error if slasher address is invalid', async () => { + await expect( + stakingClient.slash( + invalidAddress, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + amount + ) + ).rejects.toThrow(ErrorInvalidSlasherAddressProvided); + expect(mockStakingContract.slash).toHaveBeenCalledTimes(0); + }); + + test('throws an error if staker address is invalid', async () => { + await expect( + stakingClient.slash( + ethers.constants.AddressZero, + invalidAddress, + ethers.constants.AddressZero, + amount + ) + ).rejects.toThrow(ErrorInvalidStakerAddressProvided); + expect(mockStakingContract.slash).toHaveBeenCalledTimes(0); + }); + + test('throws an error if escrow address is invalid', async () => { + await expect( + stakingClient.slash( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + invalidAddress, + amount + ) + ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); + expect(mockStakingContract.slash).toHaveBeenCalledTimes(0); + }); + + test('throws an error if escrow address is not provided by the factory', async () => { + mockEscrowFactoryContract.hasEscrow.mockRejectedValueOnce(new Error()); + + await expect( + stakingClient.slash( + invalidAddress, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + amount + ) + ).rejects.toThrow(ErrorInvalidSlasherAddressProvided); + expect(mockStakingContract.slash).toHaveBeenCalledTimes(0); + }); + + test('throws an error if slashing fails', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockStakingContract.slash.mockRejectedValueOnce(new Error()); + + await expect( + stakingClient.slash( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + amount + ) + ).rejects.toThrow(); + + expect(mockStakingContract.slash).toHaveBeenCalledWith( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + amount, + { gasPrice: expectedGasPrice } + ); + expect(mockStakingContract.slash).toHaveBeenCalledTimes(1); + }); + + test('calls the staking contract to slash the given amount', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockStakingContract.slash.mockResolvedValueOnce(); + + await stakingClient.slash( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + amount + ); + + expect(mockStakingContract.slash).toHaveBeenCalledWith( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + amount, + { gasPrice: expectedGasPrice } + ); + expect(mockStakingContract.slash).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + stakingClient.slash( + ethers.constants.AddressZero, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + amount + ) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); + + describe('allocate', () => { + const amount = BigNumber.from(FAKE_AMOUNT); + const negativeAmount = BigNumber.from(FAKE_NEGATIVE_AMOUNT); + const invalidAddress = 'InvalidAddress'; + + test('throws an error if escrow address is invalid', async () => { + await expect( + stakingClient.allocate(invalidAddress, amount) + ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); + expect(mockStakingContract.allocate).toHaveBeenCalledTimes(0); + }); + + test('throws an error if amount is not a BigNumber', async () => { + await expect( + stakingClient.allocate(ethers.constants.AddressZero, 'foo') + ).rejects.toThrow(ErrorInvalidStakingValueType); + expect(mockStakingContract.allocate).toHaveBeenCalledTimes(0); + }); + + test('throws an error if amount is negative', async () => { + await expect( + stakingClient.allocate(ethers.constants.AddressZero, negativeAmount) + ).rejects.toThrow(ErrorInvalidStakingValueSign); + expect(mockStakingContract.allocate).toHaveBeenCalledTimes(0); + }); + + test('throws an error if escrow address is not provided by the factory', async () => { + mockEscrowFactoryContract.hasEscrow.mockRejectedValueOnce(new Error()); + + await expect( + stakingClient.allocate(ethers.constants.AddressZero, amount) + ).rejects.toThrow(); + expect(mockStakingContract.allocate).toHaveBeenCalledTimes(0); + }); + + test('should call the allocate method with the correct parameters', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + await stakingClient.allocate(ethers.constants.AddressZero, amount); + + expect(mockStakingContract.allocate).toHaveBeenCalledWith( + ethers.constants.AddressZero, + amount, + { gasPrice: expectedGasPrice } + ); + expect(mockStakingContract.allocate).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if the allocate method fails', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockStakingContract.allocate.mockRejectedValueOnce(new Error()); + + await expect( + stakingClient.allocate(ethers.constants.AddressZero, amount) + ).rejects.toThrow(); + expect(mockStakingContract.allocate).toHaveBeenCalledWith( + ethers.constants.AddressZero, + amount, + { gasPrice: expectedGasPrice } + ); + expect(mockStakingContract.allocate).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + stakingClient.allocate(ethers.constants.AddressZero, amount) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); + + describe('closeAllocation', () => { + const invalidAddress = 'InvalidAddress'; + + test('should throws an error if escrow address is invalid', async () => { + await expect( + stakingClient.closeAllocation(invalidAddress) + ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); + expect(mockStakingContract.closeAllocation).toHaveBeenCalledTimes(0); + }); + + test('throws an error if escrow address is not provided by the factory', async () => { + mockEscrowFactoryContract.hasEscrow.mockRejectedValueOnce(new Error()); + + await expect( + stakingClient.closeAllocation(ethers.constants.AddressZero) + ).rejects.toThrow(); + expect(mockStakingContract.closeAllocation).toHaveBeenCalledTimes(0); + }); + + test('should throw an error when stakingContract.closeAllocation throws an error', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockStakingContract.closeAllocation.mockRejectedValueOnce(new Error()); + + await expect( + stakingClient.closeAllocation(ethers.constants.AddressZero) + ).rejects.toThrow(); + + expect(mockStakingContract.closeAllocation).toHaveBeenCalledWith( + ethers.constants.AddressZero, + { gasPrice: expectedGasPrice } + ); + expect(mockStakingContract.closeAllocation).toHaveBeenCalledTimes(1); + }); + + test('should call the closeAllocation method with the correct parameters', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockStakingContract.closeAllocation.mockResolvedValueOnce(); + + await stakingClient.closeAllocation(ethers.constants.AddressZero); + + expect(mockStakingContract.closeAllocation).toHaveBeenCalledWith( + ethers.constants.AddressZero, + { gasPrice: expectedGasPrice } + ); + expect(mockStakingContract.closeAllocation).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + stakingClient.closeAllocation(ethers.constants.AddressZero) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); + + describe('distributeReward', () => { + const invalidAddress = 'InvalidAddress'; + + test('should throw an error if an invalid escrow address is provided', async () => { + await expect( + stakingClient.distributeReward(invalidAddress) + ).rejects.toThrow(ErrorInvalidEscrowAddressProvided); + expect(mockRewardPoolContract.distributeReward).toHaveBeenCalledTimes(0); + }); + + test('throws an error if escrow address is not provided by the factory', async () => { + mockEscrowFactoryContract.hasEscrow.mockRejectedValueOnce(new Error()); + + await expect( + stakingClient.distributeReward(ethers.constants.AddressZero) + ).rejects.toThrow(); + expect(mockRewardPoolContract.distributeReward).toHaveBeenCalledTimes(0); + }); + + test('should call distributeReward on the reward pool contract', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockRewardPoolContract.distributeReward.mockResolvedValueOnce(); + + await stakingClient.distributeReward(ethers.constants.AddressZero); + + expect(mockRewardPoolContract.distributeReward).toHaveBeenCalledWith( + ethers.constants.AddressZero, + { gasPrice: expectedGasPrice } + ); + expect(mockRewardPoolContract.distributeReward).toHaveBeenCalledTimes(1); + }); + + test('should throw an error if gas price data is missing from provider/signer', async () => { + mockEscrowFactoryContract.hasEscrow.mockResolvedValueOnce(true); + mockProvider.getFeeData.mockResolvedValueOnce({}); + + await expect( + stakingClient.distributeReward(ethers.constants.AddressZero) + ).rejects.toThrow(new EthereumError(ErrorMissingGasPrice.message)); + }); + }); +});