Nethereum.Playground icon indicating copy to clipboard operation
Nethereum.Playground copied to clipboard

Example: Multicall

Open juanfranblanco opened this issue 3 years ago • 2 comments

using System;
using System.Numerics;
using System.Threading.Tasks;
using Nethereum.Web3;
using Nethereum.ABI.FunctionEncoding.Attributes;
using Nethereum.Contracts;
using System.Collections.Generic;
using Nethereum.Hex.HexConvertors.Extensions;


public class Program
{
    //Example of using multicall https://github.com/makerdao/multicall/blob/master/src/Multicall.sol
    //calling contract deployed at https://etherscan.io/address/0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441#code

    [Function("balanceOf", "uint256")]
    public class BalanceOfFunction : FunctionMessage
    {
        [Parameter("address", "_owner", 1)] public string Owner { get; set; }
    }


    public partial class Call : CallBase { }

    public class CallBase
    {
        [Parameter("address", "target", 1)]
        public virtual string Target { get; set; }
        [Parameter("bytes", "callData", 2)]
        public virtual byte[] CallData { get; set; }
    }

    public partial class AggregateFunction : AggregateFunctionBase { }

    [Function("aggregate", typeof(AggregateOutputDTO))]
    public class AggregateFunctionBase : FunctionMessage
    {
        [Parameter("tuple[]", "calls", 1)]
        public virtual List<Call> Calls { get; set; }
    }

    public partial class AggregateOutputDTO : AggregateOutputDTOBase { }

    [FunctionOutput]
    public class AggregateOutputDTOBase : IFunctionOutputDTO
    {
        [Parameter("uint256", "blockNumber", 1)]
        public virtual BigInteger BlockNumber { get; set; }
        [Parameter("bytes[]", "returnData", 2)]
        public virtual List<byte[]> ReturnData { get; set; }
    }


    [FunctionOutput]
    public class BalanceOfOutputDTO : IFunctionOutputDTO
    {
        [Parameter("uint256", "balance", 1)]
        public BigInteger Balance { get; set; }
    }


    //async Task Main to enable async methods

    private static async Task Main(string[] args)
    {
        //Connecting to Ethereum mainnet using Infura
        var web3 = new Web3("https://mainnet.infura.io/v3/7238211010344719ad14a89db874158c");

        //Setting the owner https://etherscan.io/tokenholdings?a=0x8ee7d9235e01e6b42345120b5d270bdb763624c7
        var balanceOfMessage1 = new BalanceOfFunction() { Owner = "0x8ee7d9235e01e6b42345120b5d270bdb763624c7" };
        var call1 = new Call();
        call1.CallData = balanceOfMessage1.GetCallData();
        call1.Target = "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2";

        var balanceOfMessage2 = new BalanceOfFunction() { Owner = "0x8ee7d9235e01e6b42345120b5d270bdb763624c7" };
        var call2 = new Call();
        call2.CallData = balanceOfMessage2.GetCallData();
        call2.Target = "0xc12d1c73ee7dc3615ba4e37e4abfdbddfa38907e";


        var aggregateFunction = new AggregateFunction();
        aggregateFunction.Calls = new List<Call>();
        aggregateFunction.Calls.Add(call1);
        aggregateFunction.Calls.Add(call2);
        //Creating a new query handler
        var queryHandler = web3.Eth.GetContractQueryHandler<AggregateFunction>();

        var returnCalls = await queryHandler
            .QueryDeserializingToObjectAsync<AggregateOutputDTO>(aggregateFunction, "0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441")
            .ConfigureAwait(false);

        var balance1 = new BalanceOfOutputDTO().DecodeOutput(returnCalls.ReturnData[0].ToHex());
        Console.WriteLine(Web3.Convert.FromWei(balance1.Balance));

        var balance2 = new BalanceOfOutputDTO().DecodeOutput(returnCalls.ReturnData[1].ToHex());
        Console.WriteLine(Web3.Convert.FromWei(balance2.Balance, 8));
    }
}

juanfranblanco avatar Jun 09 '21 05:06 juanfranblanco

thanks for share

Eternity714 avatar Sep 14 '22 02:09 Eternity714

@Eternity714 Multicall is part of Nethereum now, hence this example is not in the playground, but another.

juanfranblanco avatar Sep 15 '22 04:09 juanfranblanco