2

I want to call this method updateRewardsPercentageByTokens() , with web3.py but I fail . please can you help me find a solution

updateRewardsPercentageByTokens code :

   function updateRewardsPercentageByTokens(EchelonReward[] memory newEchlonArray) public onlyOwner {
        if (0 != newEchlonArray.length) {
            delete rewardsPercentageByTokens;
            for (uint index = 0; index < newEchlonArray.length; index++) {
                EchelonReward memory echelon;
                echelon.echelonMaxValue = newEchlonArray[index].echelonMaxValue * 10 ** uint256(decimals());
                echelon.percentage = newEchlonArray[index].percentage;
                rewardsPercentageByTokens[index] = echelon;
            }
        }
    }


struct code :

  struct EchelonReward {
        uint256 echelonMaxValue;
        uint256 percentage;
    }

my code to call the function

from flask_restful import Resource,reqparse
from data import * 
import argparse
class updateRewardsPercentageByTokens(Resource):
    parser = argparse.ArgumentParser()
    parser.add_argument('-a', nargs="+", type=int)
    parser.add_argument('-b', nargs="+", type=int)
    parser.add_argument('-fromA',help="please put the from address")
    parser.add_argument('-gas',type=int,help="please put the amount of gas")

    def get (self): 
        nonce = web3.eth.getTransactionCount(account)
        data = updateRewardsPercentageByTokens.parser.parse_args([])
        fromAddress = data.fromA
        gas = data.gas
        a = data.a
        b = data.b
        c = dict(echelonMaxValue="100000",percentage="2")
        #{'newEchlonArray': ['1', '10000']}
        #{'echelonMaxValue': ['10000'], 'percentage': [1]}
        #{"echelonMaxValue": 1000, "percentage": 1}
        print(c)
        try : 
            print('here')
            print(a)
            print(b)
            print(gas)
            print(fromAddress)
            tx = contract.functions.updateRewardsPercentageByTokens({'newEchlonArray':[500000000000000000000,1]}).transact({

                'chainId': 3,
                'from': fromAddress,
                'gas' : gas,
                'gasPrice' : web3.toWei('100', 'gwei'),
                'nonce': nonce,

            })
            
            #sign the transaction
            signed_tx = web3.eth.account.sign_transaction(tx,wallet_private_key)
            #get the transaction hash 
            tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
            print(web3.toHex(tx_hash))

            #waiting for the trasaction receipt
            receipt = web3.eth.wait_for_transaction_receipt(tx_hash,timeout=3600, poll_latency=0.1)

            #convert the result from dict to json
            tx_dict = dict(receipt)                   
            tx_json = Web3.toJSON(tx_dict) 
           
            #return result sous format json
            return json.loads(tx_json),201
        except Exception as e : 
            print (str(e))
           
            return {'error': str(e)},401

1 Answer 1

3
+50

You are just not giving the inputs in the right format.

I used a simplified version of your contract :

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Example {

    struct EchelonReward {
        uint256 echelonMaxValue;
        uint256 percentage;
    }

    function updateRewardsPercentageByTokens(EchelonReward[] memory newEchlonArray) public {
        // FUNCTION BODY
    }
}

The ABI entry for the updateRewardsPercentageByTokens inputs is the following :

"internalType": "struct Example.EchelonReward[]",
                "name": "newEchlonArray",
                "type": "tuple[]"

Where you can see that the input type is an array of tuple, but in your code you are giving : {'newEchlonArray':[500000000000000000000,1]} which is of type Dict and cannot be unambiguously transformed to an array of tuple.

Simply changing this :

tx = contract.functions.updateRewardsPercentageByTokens({'newEchlonArray':[500000000000000000000,1]}).transact({

                'chainId': 3,
                'from': fromAddress,
                'gas' : gas,
                'gasPrice' : web3.toWei('100', 'gwei'),
                'nonce': nonce,

            })

To use the correct input type :

tx = contract.functions.updateRewardsPercentageByTokens([(500000000000000000000,1)]).transact({

                'chainId': 3,
                'from': fromAddress,
                'gas' : gas,
                'gasPrice' : web3.toWei('100', 'gwei'),
                'nonce': nonce,

            })

Should solve your problem.

If that's useful, here's the code I used to test your contract :

from web3 import Web3
import json

ENDPOINT = "http://localhost:8545"
ABI_PATH = "abi.json";
CONTRACT_ADDRESS = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512";

web3 = Web3(Web3.HTTPProvider(ENDPOINT))
accounts = web3.eth.accounts;

with open(ABI_PATH) as file:
    CONTRACT_ABI = json.load(file);

contract = web3.eth.contract(address=CONTRACT_ADDRESS, abi=CONTRACT_ABI);

// Array of tuples - You can also make an Array of Arrays , the conversion
// has no ambiguity as long as the dimensions are respected.
newEchlonArray = [(0,0), (1, 1)]

contract.functions.updateRewardsPercentageByTokens(newEchlonArray).call();

On a side note, you'd be better off not setting the nonce and gas parameters yourself. Web3.py will take care of it according to your account nonce, and the gas requirements respectively.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.