diff --git a/.pylintrc b/.pylintrc index a7a5b2d52..2a0787c90 100644 --- a/.pylintrc +++ b/.pylintrc @@ -34,6 +34,7 @@ ignore= LICENSE, docker-compose.yml, brownie-config.yaml, + PREDICTOOR-DISPENSE.md, Dockerfile, dfpy_docker, package-lock.json, @@ -65,7 +66,7 @@ persistent=yes # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages. -suggestion-mode=yes +# suggestion-mode=yes # Deprecated in newer versions of pylint # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. diff --git a/df_py/predictoor/calc_rewards.py b/df_py/predictoor/calc_rewards.py index 2e084993b..45c043ef1 100644 --- a/df_py/predictoor/calc_rewards.py +++ b/df_py/predictoor/calc_rewards.py @@ -71,7 +71,7 @@ def calc_predictoor_rewards( def aggregate_predictoor_rewards( - predictoor_rewards: Dict[str, Dict[str, float]] + predictoor_rewards: Dict[str, Dict[str, float]], ) -> Dict[str, float]: # Aggregate total reward per predictor address aggregated_rewards: Dict[str, float] = {} diff --git a/df_py/util/base18.py b/df_py/util/base18.py index bc81a8168..cf2c5956a 100644 --- a/df_py/util/base18.py +++ b/df_py/util/base18.py @@ -2,15 +2,15 @@ @enforce_types -def from_wei(amt_base: int) -> float: - return float(amt_base / 1e18) +def from_wei(amt_base: int, decimals: int = 18) -> float: + return float(amt_base / (10**decimals)) @enforce_types -def to_wei(amt_eth) -> int: - return int(amt_eth * 1e18) +def to_wei(amt_eth, decimals: int = 18) -> int: + return int(amt_eth * (10**decimals)) @enforce_types -def str_with_wei(amt_wei: int) -> str: - return f"{from_wei(amt_wei)} ({amt_wei} wei)" +def str_with_wei(amt_wei: int, decimals: int = 18) -> str: + return f"{from_wei(amt_wei, decimals)} ({amt_wei} wei)" diff --git a/df_py/util/dispense.py b/df_py/util/dispense.py index 407fb168e..4e85c3f6c 100644 --- a/df_py/util/dispense.py +++ b/df_py/util/dispense.py @@ -53,12 +53,14 @@ def dispense( multisigaddr = chain_id_to_multisig_addr(web3.eth.chain_id) df_rewards = ContractBase(web3, "DFRewards", dfrewards_addr) TOK = ContractBase(web3, "OceanToken", token_addr) + token_decimals = TOK.decimals() + logger.info(f" Token decimals: {token_decimals}") logger.info(f" Total amount: {sum(rewards.values())} {TOK.symbol()}") # checksum addresses rewards = {web3.to_checksum_address(k): v for k, v in rewards.items()} to_addrs = list(rewards.keys()) - values = [to_wei(rewards[to_addr]) for to_addr in to_addrs] + values = [to_wei(rewards[to_addr], decimals=token_decimals) for to_addr in to_addrs] N = len(rewards) sts = list(range(N))[::batch_size] # send in batches to avoid gas issues @@ -140,7 +142,8 @@ def approveAmt(amt): @enforce_types def multisig_transfer_tokens(web3, ocean, receiver_address, amount): - amount_wei = to_wei(amount) + token_decimals = ocean.decimals() + amount_wei = to_wei(amount, decimals=token_decimals) transfer_data = ocean.contract.encodeABI( fn_name="transfer", args=[receiver_address, amount_wei] ) diff --git a/df_py/util/test/test_base18.py b/df_py/util/test/test_base18.py index be0cd3791..ba650829c 100644 --- a/df_py/util/test/test_base18.py +++ b/df_py/util/test/test_base18.py @@ -16,3 +16,32 @@ def test_wei(): assert to_wei(0.1234) == 0.1234 * 1e18 and type(to_wei(0.1234)) == int assert str_with_wei(int(12.34 * 1e18)) == "12.34 (12340000000000000000 wei)" + + +def test_wei_with_custom_decimals(): + # Test with 9 decimals (USDC) + assert from_wei(int(1234 * 1e9), decimals=9) == 1234 + assert from_wei(int(12.34 * 1e9), decimals=9) == 12.34 + assert from_wei(int(0.1234 * 1e9), decimals=9) == 0.1234 + + assert ( + to_wei(1234, decimals=9) == 1234 * 1e9 and type(to_wei(1234, decimals=9)) == int + ) + assert ( + to_wei(12.34, decimals=9) == 12.34 * 1e9 + and type(to_wei(12.34, decimals=9)) == int + ) + assert ( + to_wei(0.1234, decimals=9) == 0.1234 * 1e9 + and type(to_wei(0.1234, decimals=9)) == int + ) + + assert str_with_wei(int(12.34 * 1e9), decimals=9) == "12.34 (12340000000 wei)" + + # Test with 6 decimals (USDT) + assert from_wei(int(100 * 1e6), decimals=6) == 100 + assert to_wei(100, decimals=6) == 100 * 1e6 and type(to_wei(100, decimals=6)) == int + + # Test with 8 decimals (WBTC) + assert from_wei(int(50 * 1e8), decimals=8) == 50 + assert to_wei(50, decimals=8) == 50 * 1e8 and type(to_wei(50, decimals=8)) == int diff --git a/df_py/util/test/test_dispense.py b/df_py/util/test/test_dispense.py index 8d9f89a92..3296b67c5 100644 --- a/df_py/util/test/test_dispense.py +++ b/df_py/util/test/test_dispense.py @@ -106,6 +106,42 @@ def test_multisig_transfer_tokens(w3): assert mock.call_count == 1 +@enforce_types +def test_dispense_with_9_decimals(w3): + # Create a token with 9 decimals (like USDC on Sapphire) + token = ContractBase( + w3, + "OceanToken", + constructor_args=["USDC", "USDC", 9, to_wei(100000, decimals=9)], + ) + + df_rewards = ContractBase(w3, "DFRewards", constructor_args=[]) + df_strategy = ContractBase( + w3, "DFStrategyV1", constructor_args=[df_rewards.address] + ) + + rewards_at_chain = {a1.address: 10.5, a2.address: 20.5, a3.address: 30.5} + dispense.dispense( + w3, + rewards_at_chain, + dfrewards_addr=df_rewards.address, + token_addr=token.address, + from_account=accounts[0], + ) + + # a1 claims for itself - should receive rewards with 9 decimals + bal_before = from_wei(token.balanceOf(a1), decimals=9) + df_strategy.claim([token.address], {"from": accounts[1]}) + bal_after = from_wei(token.balanceOf(a1), decimals=9) + assert (bal_after - bal_before) == pytest.approx(10.5) + + # a3 claims + bal_before = from_wei(token.balanceOf(a3), decimals=9) + df_rewards.claimFor(a3, token.address, {"from": accounts[8]}) + bal_after = from_wei(token.balanceOf(a3), decimals=9) + assert (bal_after - bal_before) == pytest.approx(30.5) + + @enforce_types def setup_function(): oceantestutil.fill_accounts_with_OCEAN(accounts)