diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/constants.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/constants.py index ff063c873b..d705cd49f5 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/constants.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/constants.py @@ -1,5 +1,6 @@ from enum import Enum import os +from web3 import Web3 class ChainId(Enum): @@ -160,6 +161,8 @@ class OperatorCategory(Enum): }, } +DEFAULT_AURORA_GAS_PRICE = Web3.to_wei(0.07, "gwei") + SUBGRAPH_API_KEY_PLACEHOLDER = "[SUBGRAPH_API_KEY]" diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_client.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_client.py index 234e6842eb..d66b42a885 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_client.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/escrow/escrow_client.py @@ -75,7 +75,7 @@ def get_w3_with_priv_key(priv_key: str): from web3.types import TxParams from eth_utils import abi -from human_protocol_sdk.utils import validate_url +from human_protocol_sdk.utils import validate_url, apply_tx_defaults from human_protocol_sdk.decorators import requires_signer LOG = logging.getLogger("human_protocol_sdk.escrow") @@ -278,7 +278,7 @@ def get_w3_with_priv_key(priv_key: str): try: tx_hash = self.factory_contract.functions.createEscrow( token_address, trusted_handlers, job_requester_id - ).transact(tx_options or {}) + ).transact(apply_tx_defaults(self.w3, tx_options)) receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash) event = next( ( @@ -366,7 +366,7 @@ def get_w3_with_priv_key(priv_key: str): escrow_config.manifest, escrow_config.hash, ) - .transact(tx_options or {}) + .transact(apply_tx_defaults(self.w3, tx_options)) ) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: @@ -431,7 +431,7 @@ def get_w3_with_priv_key(priv_key: str): try: tx_hash = token_contract.functions.transfer( escrow_address, amount - ).transact(tx_options or {}) + ).transact(apply_tx_defaults(self.w3, tx_options)) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: handle_error(e, EscrowClientError) @@ -497,7 +497,7 @@ def get_w3_with_priv_key(priv_key: str): tx_hash = ( self._get_escrow_contract(escrow_address) .functions.storeResults(url, hash) - .transact(tx_options or {}) + .transact(apply_tx_defaults(self.w3, tx_options)) ) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: @@ -550,7 +550,7 @@ def get_w3_with_priv_key(priv_key: str): tx_hash = ( self._get_escrow_contract(escrow_address) .functions.complete() - .transact(tx_options or {}) + .transact(apply_tx_defaults(self.w3, tx_options)) ) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: @@ -646,7 +646,7 @@ def get_w3_with_priv_key(priv_key: str): recipients, amounts, final_results_url, final_results_hash, txId ) ) - tx_hash = contract_func.transact(tx_options or {}) + tx_hash = contract_func.transact(apply_tx_defaults(self.w3, tx_options)) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: handle_error(e, EscrowClientError) @@ -874,7 +874,7 @@ def get_w3_with_priv_key(priv_key: str): tx_hash = ( self._get_escrow_contract(escrow_address) .functions.cancel() - .transact(tx_options or {}) + .transact(apply_tx_defaults(self.w3, tx_options)) ) receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/kvstore/kvstore_client.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/kvstore/kvstore_client.py index 54b366cba1..38158e76fe 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/kvstore/kvstore_client.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/kvstore/kvstore_client.py @@ -63,6 +63,7 @@ def get_w3_with_priv_key(priv_key: str): get_kvstore_interface, handle_error, validate_url, + apply_tx_defaults, ) from web3 import Web3 from web3.middleware import ExtraDataToPOAMiddleware @@ -159,7 +160,7 @@ def get_w3_with_priv_key(priv_key: str): try: tx_hash = self.kvstore_contract.functions.set(key, value).transact( - tx_options or {} + apply_tx_defaults(self.w3, tx_options) ) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: @@ -216,7 +217,7 @@ def get_w3_with_priv_key(priv_key: str): try: tx_hash = self.kvstore_contract.functions.setBulk(keys, values).transact( - tx_options or {} + apply_tx_defaults(self.w3, tx_options) ) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: @@ -275,7 +276,7 @@ def get_w3_with_priv_key(priv_key: str): try: tx_hash = self.kvstore_contract.functions.setBulk( [key, key + "_hash"], [url, content_hash] - ).transact(tx_options or {}) + ).transact(apply_tx_defaults(self.w3, tx_options)) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: handle_error(e, KVStoreClientError) diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_client.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_client.py index c9a7f2e53c..136266a257 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_client.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/staking/staking_client.py @@ -69,6 +69,7 @@ def get_w3_with_priv_key(priv_key: str): get_factory_interface, get_staking_interface, handle_error, + apply_tx_defaults, ) LOG = logging.getLogger("human_protocol_sdk.staking") @@ -178,7 +179,7 @@ def get_w3_with_priv_key(priv_key: str): try: tx_hash = self.hmtoken_contract.functions.approve( self.network["staking_address"], amount - ).transact(tx_options or {}) + ).transact(apply_tx_defaults(self.w3, tx_options)) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: handle_error(e, StakingClientError) @@ -230,7 +231,7 @@ def get_w3_with_priv_key(priv_key: str): raise StakingClientError("Amount to stake must be greater than 0") try: tx_hash = self.staking_contract.functions.stake(amount).transact( - tx_options or {} + apply_tx_defaults(self.w3, tx_options) ) self.w3.eth.wait_for_transaction_receipt(tx_hash) except Exception as e: diff --git a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/utils.py b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/utils.py index 34b52f78ed..25db19cbf7 100644 --- a/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/utils.py +++ b/packages/sdk/python/human-protocol-sdk/human_protocol_sdk/utils.py @@ -14,7 +14,12 @@ from web3.types import TxParams from web3.middleware import SignAndSendRawMiddlewareBuilder -from human_protocol_sdk.constants import ARTIFACTS_FOLDER, SUBGRAPH_API_KEY_PLACEHOLDER +from human_protocol_sdk.constants import ( + ARTIFACTS_FOLDER, + SUBGRAPH_API_KEY_PLACEHOLDER, + ChainId, + DEFAULT_AURORA_GAS_PRICE, +) logger = logging.getLogger("human_protocol_sdk.utils") @@ -319,3 +324,22 @@ def validate_json(data: str) -> bool: return True except (ValueError, TypeError): return False + + +def apply_tx_defaults(w3: Web3, tx_options: Optional[TxParams]) -> TxParams: + """Apply network specific default transaction parameters. + + Aurora networks enforce a fixed gas price. We always override any user supplied + gasPrice with DEFAULT_AURORA_GAS_PRICE when on Aurora Testnet. + EIP-1559 fields are removed to avoid conflicts. + + :param w3: Web3 instance (used to read chain id) + :param tx_options: Original transaction options (can be None) + :return: Mutated tx options with enforced defaults + """ + opts: TxParams = dict(tx_options) if tx_options else {} + if w3.eth.chain_id == ChainId.AURORA_TESTNET.value: + opts["gasPrice"] = DEFAULT_AURORA_GAS_PRICE + opts.pop("maxFeePerGas", None) + opts.pop("maxPriorityFeePerGas", None) + return opts diff --git a/packages/sdk/typescript/human-protocol-sdk/src/base.ts b/packages/sdk/typescript/human-protocol-sdk/src/base.ts index a0f3083da7..12bd18e3c2 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/base.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/base.ts @@ -1,5 +1,7 @@ -import { ContractRunner } from 'ethers'; +import { ContractRunner, Overrides } from 'ethers'; import { NetworkData } from './types'; +import { ChainId } from './enums'; +import { DEFAULT_AURORA_GAS_PRICE } from './constants'; /** * ## Introduction @@ -21,4 +23,24 @@ export abstract class BaseEthersClient { this.networkData = networkData; this.runner = runner; } + + /** + * Internal helper to enrich transaction overrides with network specific defaults. + * + * Aurora networks use a fixed gas price. We always override any user provided + * gasPrice with the canonical DEFAULT_AURORA_GAS_PRICE to avoid mismatches + * or tx failures due to an unexpected value. For other networks the user + * supplied fee parameters are left untouched. + */ + protected applyTxDefaults(txOptions: Overrides = {}): Overrides { + if (this.networkData.chainId === ChainId.AURORA_TESTNET) { + return { + ...txOptions, + gasPrice: DEFAULT_AURORA_GAS_PRICE, + maxFeePerGas: undefined, + maxPriorityFeePerGas: undefined, + } as Overrides; + } + return txOptions; + } } diff --git a/packages/sdk/typescript/human-protocol-sdk/src/constants.ts b/packages/sdk/typescript/human-protocol-sdk/src/constants.ts index fb59fc4b06..95610ab7dd 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/constants.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/constants.ts @@ -1,3 +1,4 @@ +import { ethers } from 'ethers'; import { ChainId } from './enums'; import { NetworkData } from './types'; @@ -11,6 +12,8 @@ export const DEFAULT_PORT = 9000; export const DEFAULT_USE_SSL = false; +export const DEFAULT_AURORA_GAS_PRICE = ethers.parseUnits('0.07', 'gwei'); + export enum HttpStatus { OK = 200, CREATED = 201, diff --git a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts index 709a2f42be..42e6cd620f 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts @@ -251,7 +251,7 @@ export class EscrowClient extends BaseEthersClient { tokenAddress, trustedHandlers, jobRequesterId, - txOptions + this.applyTxDefaults(txOptions) ) ).wait(); @@ -380,7 +380,7 @@ export class EscrowClient extends BaseEthersClient { exchangeOracleFee, manifest, manifestHash, - txOptions + this.applyTxDefaults(txOptions) ) ).wait(); @@ -444,7 +444,11 @@ export class EscrowClient extends BaseEthersClient { this.runner ); await ( - await tokenContract.transfer(escrowAddress, amount, txOptions) + await tokenContract.transfer( + escrowAddress, + amount, + this.applyTxDefaults(txOptions) + ) ).wait(); return; @@ -511,7 +515,13 @@ export class EscrowClient extends BaseEthersClient { try { const escrowContract = this.getEscrowContract(escrowAddress); - await (await escrowContract.storeResults(url, hash, txOptions)).wait(); + await ( + await escrowContract.storeResults( + url, + hash, + this.applyTxDefaults(txOptions) + ) + ).wait(); return; } catch (e) { @@ -561,7 +571,9 @@ export class EscrowClient extends BaseEthersClient { try { const escrowContract = this.getEscrowContract(escrowAddress); - await (await escrowContract.complete(txOptions)).wait(); + await ( + await escrowContract.complete(this.applyTxDefaults(txOptions)) + ).wait(); return; } catch (e) { return throwError(e); @@ -638,7 +650,7 @@ export class EscrowClient extends BaseEthersClient { finalResultsHash, txId, forceComplete, - txOptions + this.applyTxDefaults(txOptions) ) ).wait(); } else { @@ -651,7 +663,7 @@ export class EscrowClient extends BaseEthersClient { finalResultsUrl, finalResultsHash, txId, - txOptions + this.applyTxDefaults(txOptions) ) ).wait(); } @@ -704,7 +716,7 @@ export class EscrowClient extends BaseEthersClient { const escrowContract = this.getEscrowContract(escrowAddress); const transactionReceipt = await ( - await escrowContract.cancel(txOptions) + await escrowContract.cancel(this.applyTxDefaults(txOptions)) ).wait(); let amountTransferred: bigint | undefined = undefined; @@ -801,7 +813,10 @@ export class EscrowClient extends BaseEthersClient { const escrowContract = this.getEscrowContract(escrowAddress); await ( - await escrowContract.addTrustedHandlers(trustedHandlers, txOptions) + await escrowContract.addTrustedHandlers( + trustedHandlers, + this.applyTxDefaults(txOptions) + ) ).wait(); return; } catch (e) { @@ -861,7 +876,10 @@ export class EscrowClient extends BaseEthersClient { const escrowContract = this.getEscrowContract(escrowAddress); const transactionReceipt = await ( - await escrowContract.withdraw(tokenAddress, txOptions) + await escrowContract.withdraw( + tokenAddress, + this.applyTxDefaults(txOptions) + ) ).wait(); let amountTransferred: bigint | undefined = undefined; @@ -953,6 +971,7 @@ export class EscrowClient extends BaseEthersClient { forceComplete = false, txOptions: Overrides = {} ): Promise { + txOptions = this.applyTxDefaults(txOptions); await this.ensureCorrectBulkPayoutInput( escrowAddress, recipients, diff --git a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts index 867515c365..ea12cedb3e 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts @@ -175,7 +175,9 @@ export class KVStoreClient extends BaseEthersClient { ): Promise { if (key === '') throw ErrorKVStoreEmptyKey; try { - await (await this.contract.set(key, value, txOptions)).wait(); + await ( + await this.contract.set(key, value, this.applyTxDefaults(txOptions)) + ).wait(); } catch (e) { if (e instanceof Error) throw Error(`Failed to set value: ${e.message}`); } @@ -220,7 +222,13 @@ export class KVStoreClient extends BaseEthersClient { if (keys.includes('')) throw ErrorKVStoreEmptyKey; try { - await (await this.contract.setBulk(keys, values, txOptions)).wait(); + await ( + await this.contract.setBulk( + keys, + values, + this.applyTxDefaults(txOptions) + ) + ).wait(); } catch (e) { if (e instanceof Error) throw Error(`Failed to set bulk values: ${e.message}`); @@ -273,7 +281,7 @@ export class KVStoreClient extends BaseEthersClient { await this.contract.setBulk( [urlKey, hashKey], [url, contentHash], - txOptions + this.applyTxDefaults(txOptions) ) ).wait(); } catch (e) { diff --git a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts index 215624c0e2..cadf10fc17 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/staking.ts @@ -207,7 +207,7 @@ export class StakingClient extends BaseEthersClient { await this.tokenContract.approve( await this.stakingContract.getAddress(), amount, - txOptions + this.applyTxDefaults(txOptions) ) ).wait(); return; @@ -254,7 +254,12 @@ export class StakingClient extends BaseEthersClient { } try { - await (await this.stakingContract.stake(amount, txOptions)).wait(); + await ( + await this.stakingContract.stake( + amount, + this.applyTxDefaults(txOptions) + ) + ).wait(); return; } catch (e) { return throwError(e); @@ -301,7 +306,12 @@ export class StakingClient extends BaseEthersClient { } try { - await (await this.stakingContract.unstake(amount, txOptions)).wait(); + await ( + await this.stakingContract.unstake( + amount, + this.applyTxDefaults(txOptions) + ) + ).wait(); return; } catch (e) { return throwError(e); @@ -335,7 +345,9 @@ export class StakingClient extends BaseEthersClient { @requiresSigner public async withdraw(txOptions: Overrides = {}): Promise { try { - await (await this.stakingContract.withdraw(txOptions)).wait(); + await ( + await this.stakingContract.withdraw(this.applyTxDefaults(txOptions)) + ).wait(); return; } catch (e) { return throwError(e); @@ -402,7 +414,7 @@ export class StakingClient extends BaseEthersClient { staker, escrowAddress, amount, - txOptions + this.applyTxDefaults(txOptions) ) ).wait(); @@ -439,6 +451,7 @@ export class StakingClient extends BaseEthersClient { try { const stakerInfo = await this.stakingContract.stakes(stakerAddress); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const currentBlock = await this.runner.provider!.getBlockNumber(); const tokensWithdrawable =