From aa198f57241abacf5d11ade293e37449028d87f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Tue, 26 Aug 2025 14:37:06 +0200 Subject: [PATCH 1/4] enhance transaction handling by applying specific defaults for Aurora network --- .../typescript/human-protocol-sdk/src/base.ts | 19 ++++++++- .../human-protocol-sdk/src/constants.ts | 3 ++ .../human-protocol-sdk/src/escrow.ts | 39 ++++++++++++++----- .../human-protocol-sdk/src/kvstore.ts | 14 +++++-- .../human-protocol-sdk/src/staking.ts | 23 ++++++++--- 5 files changed, 79 insertions(+), 19 deletions(-) diff --git a/packages/sdk/typescript/human-protocol-sdk/src/base.ts b/packages/sdk/typescript/human-protocol-sdk/src/base.ts index a0f3083da7..cf01b41329 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,19 @@ export abstract class BaseEthersClient { this.networkData = networkData; this.runner = runner; } + + /** + * Internal helper to enrich transaction overrides with network specific defaults + * (e.g. fixed gas price for Aurora networks) while preserving user provided + * fee parameters. + */ + protected applyTxDefaults(txOptions: Overrides = {}): Overrides { + if ( + this.networkData.chainId === ChainId.AURORA_TESTNET && + txOptions.gasPrice === undefined + ) { + return { ...txOptions, gasPrice: DEFAULT_AURORA_GAS_PRICE }; + } + 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 = From 22b78f4ca38eb31799229bd3f7b266ceb11207e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Tue, 2 Sep 2025 13:45:30 +0200 Subject: [PATCH 2/4] implement apply_tx_defaults utility for consistent transaction handling across networks in Python SDK --- .../human_protocol_sdk/constants.py | 3 ++ .../escrow/escrow_client.py | 16 +++++----- .../kvstore/kvstore_client.py | 7 +++-- .../staking/staking_client.py | 5 ++-- .../human_protocol_sdk/utils.py | 29 ++++++++++++++++++- .../typescript/human-protocol-sdk/src/base.ts | 21 +++++++++----- 6 files changed, 59 insertions(+), 22 deletions(-) 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..8be2145e38 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,25 @@ 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 {} + try: + if w3.eth.chain_id == ChainId.AURORA_TESTNET.value: + opts["gasPrice"] = DEFAULT_AURORA_GAS_PRICE + opts.pop("maxFeePerGas", None) + opts.pop("maxPriorityFeePerGas", None) + except Exception: + pass + 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 cf01b41329..12bd18e3c2 100644 --- a/packages/sdk/typescript/human-protocol-sdk/src/base.ts +++ b/packages/sdk/typescript/human-protocol-sdk/src/base.ts @@ -25,16 +25,21 @@ export abstract class BaseEthersClient { } /** - * Internal helper to enrich transaction overrides with network specific defaults - * (e.g. fixed gas price for Aurora networks) while preserving user provided - * fee parameters. + * 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 && - txOptions.gasPrice === undefined - ) { - return { ...txOptions, gasPrice: DEFAULT_AURORA_GAS_PRICE }; + if (this.networkData.chainId === ChainId.AURORA_TESTNET) { + return { + ...txOptions, + gasPrice: DEFAULT_AURORA_GAS_PRICE, + maxFeePerGas: undefined, + maxPriorityFeePerGas: undefined, + } as Overrides; } return txOptions; } From 44d929f83737ad05ed15e049f4cda6450453955f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= Date: Tue, 2 Sep 2025 14:49:16 +0200 Subject: [PATCH 3/4] simplify apply_tx_defaults by removing unnecessary try-except block --- .../python/human-protocol-sdk/example_kvstore_set.py | 0 .../human-protocol-sdk/human_protocol_sdk/utils.py | 11 ++++------- 2 files changed, 4 insertions(+), 7 deletions(-) create mode 100644 packages/sdk/python/human-protocol-sdk/example_kvstore_set.py diff --git a/packages/sdk/python/human-protocol-sdk/example_kvstore_set.py b/packages/sdk/python/human-protocol-sdk/example_kvstore_set.py new file mode 100644 index 0000000000..e69de29bb2 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 8be2145e38..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 @@ -338,11 +338,8 @@ def apply_tx_defaults(w3: Web3, tx_options: Optional[TxParams]) -> TxParams: :return: Mutated tx options with enforced defaults """ opts: TxParams = dict(tx_options) if tx_options else {} - try: - if w3.eth.chain_id == ChainId.AURORA_TESTNET.value: - opts["gasPrice"] = DEFAULT_AURORA_GAS_PRICE - opts.pop("maxFeePerGas", None) - opts.pop("maxPriorityFeePerGas", None) - except Exception: - pass + 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 From b3d630680e272549600c411735cbe2354d0e4e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20L=C3=B3pez?= <50665615+flopez7@users.noreply.github.com> Date: Thu, 4 Sep 2025 11:49:51 +0200 Subject: [PATCH 4/4] Delete packages/sdk/python/human-protocol-sdk/example_kvstore_set.py --- packages/sdk/python/human-protocol-sdk/example_kvstore_set.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 packages/sdk/python/human-protocol-sdk/example_kvstore_set.py diff --git a/packages/sdk/python/human-protocol-sdk/example_kvstore_set.py b/packages/sdk/python/human-protocol-sdk/example_kvstore_set.py deleted file mode 100644 index e69de29bb2..0000000000