Skip to content

Instantly share code, notes, and snippets.

@bonedaddy
Created February 8, 2021 21:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bonedaddy/2cb00701c84fdda3fa467a96a10ab6eb to your computer and use it in GitHub Desktop.
Save bonedaddy/2cb00701c84fdda3fa467a96a10ab6eb to your computer and use it in GitHub Desktop.
package multicall
import (
"context"
"math/big"
bindings "github.com/bonedaddy/<redacted>/bindings/multicall"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
// Multicall exposes utility functions around the multicall contract
type Multicall struct {
backend bind.ContractBackend
binding *bindings.Multicall
ctx context.Context
cancel context.CancelFunc
}
// New initializes the multicall contract wrapper package
func New(ctx context.Context, addr string, backend bind.ContractBackend) (*Multicall, error) {
ctx, cancel := context.WithCancel(ctx)
binding, err := bindings.NewMulticall(common.HexToAddress(addr), backend)
if err != nil {
cancel()
return nil, err
}
return &Multicall{
backend: backend,
binding: binding,
ctx: ctx,
cancel: cancel,
}, nil
}
// GetDenormalizedWeights returns the denormalized weights of all given tokens
func (m *Multicall) GetDenormalizedWeights(
block uint64,
pool string,
tokens []string,
) ([]common.Address, []*big.Int, error) {
poolAddr := common.HexToAddress(pool)
var tokenAddrs = make([]common.Address, len(tokens))
for i, tok := range tokens {
tokenAddrs[i] = common.HexToAddress(tok)
}
return m.binding.GetDenormalizedWeights(
&bind.CallOpts{
Context: m.ctx,
BlockNumber: new(big.Int).SetUint64(block),
},
poolAddr,
tokenAddrs,
)
}
// GetBalances returns the balances of various tokens
func (m *Multicall) GetBalances(
block uint64,
pool string,
tokens []string,
) ([]common.Address, []*big.Int, error) {
poolAddr := common.HexToAddress(pool)
var tokenAddrs = make([]common.Address, len(tokens))
for i, tok := range tokens {
tokenAddrs[i] = common.HexToAddress(tok)
}
return m.binding.GetBalances(
&bind.CallOpts{
Context: m.ctx,
BlockNumber: new(big.Int).SetUint64(block),
},
poolAddr,
tokenAddrs,
)
}
// GetUsedBalances returns the used balances of various tokens
func (m *Multicall) GetUsedBalances(
block uint64,
pool string,
tokens []string,
) ([]common.Address, []*big.Int, error) {
poolAddr := common.HexToAddress(pool)
var tokenAddrs = make([]common.Address, len(tokens))
for i, tok := range tokens {
tokenAddrs[i] = common.HexToAddress(tok)
}
return m.binding.GetUsedBalances(
&bind.CallOpts{
Context: m.ctx,
BlockNumber: new(big.Int).SetUint64(block),
},
poolAddr,
tokenAddrs,
)
}
// GetSpotPrices returns the spot prices of various in/out pairs
func (m *Multicall) GetSpotPrices(
block uint64,
pool string,
tokensIn []string,
tokensOut []string,
) ([]common.Address, []common.Address, []*big.Int, error) {
poolAddr := common.HexToAddress(pool)
var (
tokenInAddrs = make([]common.Address, len(tokensIn))
tokenOutAddrs = make([]common.Address, len(tokensOut))
)
for i, tok := range tokensIn {
tokenInAddrs[i] = common.HexToAddress(tok)
}
for i, tok := range tokensOut {
tokenOutAddrs[i] = common.HexToAddress(tok)
}
return m.binding.GetSpotPrices(
&bind.CallOpts{
Context: m.ctx,
BlockNumber: new(big.Int).SetUint64(block),
},
poolAddr,
tokenInAddrs,
tokenOutAddrs,
)
}
// GetTotalSupplies returns the total supplies of various tokens
func (m *Multicall) GetTotalSupplies(
block uint64,
tokens []string,
) ([]common.Address, []*big.Int, error) {
var tokenAddrs = make([]common.Address, len(tokens))
for i, tok := range tokens {
tokenAddrs[i] = common.HexToAddress(tok)
}
return m.binding.GetTotalSupplies(
&bind.CallOpts{
Context: m.ctx,
BlockNumber: new(big.Int).SetUint64(block),
},
tokenAddrs,
)
}
// Close terminates the context
func (m *Multicall) Close() {
m.cancel()
}
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package multicall
import (
"math/big"
"strings"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// Reference imports to suppress errors if they are not otherwise used.
var (
_ = big.NewInt
_ = strings.NewReader
_ = ethereum.NotFound
_ = bind.Bind
_ = common.Big1
_ = types.BloomLookup
_ = event.NewSubscription
)
// MulticallABI is the input ABI used to generate the binding from.
const MulticallABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"poolAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getBalances\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"poolAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getDenormalizedWeights\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"poolAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"inTokens\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"outTokens\",\"type\":\"address[]\"}],\"name\":\"getSpotPrices\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getTotalSupplies\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"poolAddress\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getUsedBalances\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]"
// MulticallBin is the compiled bytecode used for deploying new contracts.
var MulticallBin = "0x608060405234801561001057600080fd5b50610b3c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80632dd43d891461005c5780636a385ae91461019657806395d7710e14610247578063db16d8ac146102f8578063f7a6b6b6146103a9575b600080fd5b6100fd6004803603602081101561007257600080fd5b810190602081018135600160201b81111561008c57600080fd5b82018360208201111561009e57600080fd5b803590602001918460208302840111600160201b831117156100bf57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506105ba945050505050565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015610141578181015183820152602001610129565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610180578181015183820152602001610168565b5050505090500194505050505060405180910390f35b6100fd600480360360408110156101ac57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156101d657600080fd5b8201836020820111156101e857600080fd5b803590602001918460208302840111600160201b8311171561020957600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506106b1945050505050565b6100fd6004803603604081101561025d57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561028757600080fd5b82018360208201111561029957600080fd5b803590602001918460208302840111600160201b831117156102ba57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506107be945050505050565b6100fd6004803603604081101561030e57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561033857600080fd5b82018360208201111561034a57600080fd5b803590602001918460208302840111600160201b8311171561036b57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506108c1945050505050565b6104dc600480360360608110156103bf57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156103e957600080fd5b8201836020820111156103fb57600080fd5b803590602001918460208302840111600160201b8311171561041c57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561046b57600080fd5b82018360208201111561047d57600080fd5b803590602001918460208302840111600160201b8311171561049e57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506109c4945050505050565b60405180806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b8381101561052457818101518382015260200161050c565b50505050905001848103835286818151815260200191508051906020019060200280838360005b8381101561056357818101518382015260200161054b565b50505050905001848103825285818151815260200191508051906020019060200280838360005b838110156105a257818101518382015260200161058a565b50505050905001965050505050505060405180910390f35b6060806060835167ffffffffffffffff811180156105d757600080fd5b50604051908082528060200260200182016040528015610601578160200160208202803683370190505b50905060005b84518110156106a95784818151811061061c57fe5b60200260200101516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561065c57600080fd5b505afa158015610670573d6000803e3d6000fd5b505050506040513d602081101561068657600080fd5b5051825183908390811061069657fe5b6020908102919091010152600101610607565b509293915050565b6060806060835167ffffffffffffffff811180156106ce57600080fd5b506040519080825280602002602001820160405280156106f8578160200160208202803683370190505b50905060005b84518110156107b457856001600160a01b031663f8b2cb4f86838151811061072257fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561076757600080fd5b505afa15801561077b573d6000803e3d6000fd5b505050506040513d602081101561079157600080fd5b505182518390839081106107a157fe5b60209081029190910101526001016106fe565b5092949293505050565b6060806060835167ffffffffffffffff811180156107db57600080fd5b50604051908082528060200260200182016040528015610805578160200160208202803683370190505b50905060005b84518110156107b457856001600160a01b0316634aa4e0b586838151811061082f57fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561087457600080fd5b505afa158015610888573d6000803e3d6000fd5b505050506040513d602081101561089e57600080fd5b505182518390839081106108ae57fe5b602090810291909101015260010161080b565b6060806060835167ffffffffffffffff811180156108de57600080fd5b50604051908082528060200260200182016040528015610908578160200160208202803683370190505b50905060005b84518110156107b457856001600160a01b031663948d8ce686838151811061093257fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561097757600080fd5b505afa15801561098b573d6000803e3d6000fd5b505050506040513d60208110156109a157600080fd5b505182518390839081106109b157fe5b602090810291909101015260010161090e565b606080606083518551146109d757600080fd5b6060855167ffffffffffffffff811180156109f157600080fd5b50604051908082528060200260200182016040528015610a1b578160200160208202803683370190505b50905060005b8651811015610afb57876001600160a01b03166315e84af9888381518110610a4557fe5b6020026020010151888481518110610a5957fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b03168152602001826001600160a01b031681526020019250505060206040518083038186803b158015610aae57600080fd5b505afa158015610ac2573d6000803e3d6000fd5b505050506040513d6020811015610ad857600080fd5b50518251839083908110610ae857fe5b6020908102919091010152600101610a21565b50949693955050505056fea264697066735822122044470bd2564b5e5b98cf0a195bf1b5960c678d1fb0cc4d8bd8cd0424a29be5a064736f6c63430007040033"
// DeployMulticall deploys a new Ethereum contract, binding an instance of Multicall to it.
func DeployMulticall(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Multicall, error) {
parsed, err := abi.JSON(strings.NewReader(MulticallABI))
if err != nil {
return common.Address{}, nil, nil, err
}
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(MulticallBin), backend)
if err != nil {
return common.Address{}, nil, nil, err
}
return address, tx, &Multicall{MulticallCaller: MulticallCaller{contract: contract}, MulticallTransactor: MulticallTransactor{contract: contract}, MulticallFilterer: MulticallFilterer{contract: contract}}, nil
}
// Multicall is an auto generated Go binding around an Ethereum contract.
type Multicall struct {
MulticallCaller // Read-only binding to the contract
MulticallTransactor // Write-only binding to the contract
MulticallFilterer // Log filterer for contract events
}
// MulticallCaller is an auto generated read-only Go binding around an Ethereum contract.
type MulticallCaller struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// MulticallTransactor is an auto generated write-only Go binding around an Ethereum contract.
type MulticallTransactor struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// MulticallFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
type MulticallFilterer struct {
contract *bind.BoundContract // Generic contract wrapper for the low level calls
}
// MulticallSession is an auto generated Go binding around an Ethereum contract,
// with pre-set call and transact options.
type MulticallSession struct {
Contract *Multicall // Generic contract binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// MulticallCallerSession is an auto generated read-only Go binding around an Ethereum contract,
// with pre-set call options.
type MulticallCallerSession struct {
Contract *MulticallCaller // Generic contract caller binding to set the session for
CallOpts bind.CallOpts // Call options to use throughout this session
}
// MulticallTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
// with pre-set transact options.
type MulticallTransactorSession struct {
Contract *MulticallTransactor // Generic contract transactor binding to set the session for
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
}
// MulticallRaw is an auto generated low-level Go binding around an Ethereum contract.
type MulticallRaw struct {
Contract *Multicall // Generic contract binding to access the raw methods on
}
// MulticallCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
type MulticallCallerRaw struct {
Contract *MulticallCaller // Generic read-only contract binding to access the raw methods on
}
// MulticallTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
type MulticallTransactorRaw struct {
Contract *MulticallTransactor // Generic write-only contract binding to access the raw methods on
}
// NewMulticall creates a new instance of Multicall, bound to a specific deployed contract.
func NewMulticall(address common.Address, backend bind.ContractBackend) (*Multicall, error) {
contract, err := bindMulticall(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &Multicall{MulticallCaller: MulticallCaller{contract: contract}, MulticallTransactor: MulticallTransactor{contract: contract}, MulticallFilterer: MulticallFilterer{contract: contract}}, nil
}
// NewMulticallCaller creates a new read-only instance of Multicall, bound to a specific deployed contract.
func NewMulticallCaller(address common.Address, caller bind.ContractCaller) (*MulticallCaller, error) {
contract, err := bindMulticall(address, caller, nil, nil)
if err != nil {
return nil, err
}
return &MulticallCaller{contract: contract}, nil
}
// NewMulticallTransactor creates a new write-only instance of Multicall, bound to a specific deployed contract.
func NewMulticallTransactor(address common.Address, transactor bind.ContractTransactor) (*MulticallTransactor, error) {
contract, err := bindMulticall(address, nil, transactor, nil)
if err != nil {
return nil, err
}
return &MulticallTransactor{contract: contract}, nil
}
// NewMulticallFilterer creates a new log filterer instance of Multicall, bound to a specific deployed contract.
func NewMulticallFilterer(address common.Address, filterer bind.ContractFilterer) (*MulticallFilterer, error) {
contract, err := bindMulticall(address, nil, nil, filterer)
if err != nil {
return nil, err
}
return &MulticallFilterer{contract: contract}, nil
}
// bindMulticall binds a generic wrapper to an already deployed contract.
func bindMulticall(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
parsed, err := abi.JSON(strings.NewReader(MulticallABI))
if err != nil {
return nil, err
}
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Multicall *MulticallRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _Multicall.Contract.MulticallCaller.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Multicall *MulticallRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _Multicall.Contract.MulticallTransactor.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_Multicall *MulticallRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _Multicall.Contract.MulticallTransactor.contract.Transact(opts, method, params...)
}
// Call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
func (_Multicall *MulticallCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
return _Multicall.Contract.contract.Call(opts, result, method, params...)
}
// Transfer initiates a plain transaction to move funds to the contract, calling
// its default method if one is available.
func (_Multicall *MulticallTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
return _Multicall.Contract.contract.Transfer(opts)
}
// Transact invokes the (paid) contract method with params as input values.
func (_Multicall *MulticallTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
return _Multicall.Contract.contract.Transact(opts, method, params...)
}
// GetBalances is a free data retrieval call binding the contract method 0x6a385ae9.
//
// Solidity: function getBalances(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallCaller) GetBalances(opts *bind.CallOpts, poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
var out []interface{}
err := _Multicall.contract.Call(opts, &out, "getBalances", poolAddress, tokens)
if err != nil {
return *new([]common.Address), *new([]*big.Int), err
}
out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
out1 := *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int)
return out0, out1, err
}
// GetBalances is a free data retrieval call binding the contract method 0x6a385ae9.
//
// Solidity: function getBalances(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallSession) GetBalances(poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
return _Multicall.Contract.GetBalances(&_Multicall.CallOpts, poolAddress, tokens)
}
// GetBalances is a free data retrieval call binding the contract method 0x6a385ae9.
//
// Solidity: function getBalances(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallCallerSession) GetBalances(poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
return _Multicall.Contract.GetBalances(&_Multicall.CallOpts, poolAddress, tokens)
}
// GetDenormalizedWeights is a free data retrieval call binding the contract method 0xdb16d8ac.
//
// Solidity: function getDenormalizedWeights(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallCaller) GetDenormalizedWeights(opts *bind.CallOpts, poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
var out []interface{}
err := _Multicall.contract.Call(opts, &out, "getDenormalizedWeights", poolAddress, tokens)
if err != nil {
return *new([]common.Address), *new([]*big.Int), err
}
out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
out1 := *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int)
return out0, out1, err
}
// GetDenormalizedWeights is a free data retrieval call binding the contract method 0xdb16d8ac.
//
// Solidity: function getDenormalizedWeights(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallSession) GetDenormalizedWeights(poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
return _Multicall.Contract.GetDenormalizedWeights(&_Multicall.CallOpts, poolAddress, tokens)
}
// GetDenormalizedWeights is a free data retrieval call binding the contract method 0xdb16d8ac.
//
// Solidity: function getDenormalizedWeights(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallCallerSession) GetDenormalizedWeights(poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
return _Multicall.Contract.GetDenormalizedWeights(&_Multicall.CallOpts, poolAddress, tokens)
}
// GetSpotPrices is a free data retrieval call binding the contract method 0xf7a6b6b6.
//
// Solidity: function getSpotPrices(address poolAddress, address[] inTokens, address[] outTokens) view returns(address[], address[], uint256[])
func (_Multicall *MulticallCaller) GetSpotPrices(opts *bind.CallOpts, poolAddress common.Address, inTokens []common.Address, outTokens []common.Address) ([]common.Address, []common.Address, []*big.Int, error) {
var out []interface{}
err := _Multicall.contract.Call(opts, &out, "getSpotPrices", poolAddress, inTokens, outTokens)
if err != nil {
return *new([]common.Address), *new([]common.Address), *new([]*big.Int), err
}
out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
out1 := *abi.ConvertType(out[1], new([]common.Address)).(*[]common.Address)
out2 := *abi.ConvertType(out[2], new([]*big.Int)).(*[]*big.Int)
return out0, out1, out2, err
}
// GetSpotPrices is a free data retrieval call binding the contract method 0xf7a6b6b6.
//
// Solidity: function getSpotPrices(address poolAddress, address[] inTokens, address[] outTokens) view returns(address[], address[], uint256[])
func (_Multicall *MulticallSession) GetSpotPrices(poolAddress common.Address, inTokens []common.Address, outTokens []common.Address) ([]common.Address, []common.Address, []*big.Int, error) {
return _Multicall.Contract.GetSpotPrices(&_Multicall.CallOpts, poolAddress, inTokens, outTokens)
}
// GetSpotPrices is a free data retrieval call binding the contract method 0xf7a6b6b6.
//
// Solidity: function getSpotPrices(address poolAddress, address[] inTokens, address[] outTokens) view returns(address[], address[], uint256[])
func (_Multicall *MulticallCallerSession) GetSpotPrices(poolAddress common.Address, inTokens []common.Address, outTokens []common.Address) ([]common.Address, []common.Address, []*big.Int, error) {
return _Multicall.Contract.GetSpotPrices(&_Multicall.CallOpts, poolAddress, inTokens, outTokens)
}
// GetTotalSupplies is a free data retrieval call binding the contract method 0x2dd43d89.
//
// Solidity: function getTotalSupplies(address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallCaller) GetTotalSupplies(opts *bind.CallOpts, tokens []common.Address) ([]common.Address, []*big.Int, error) {
var out []interface{}
err := _Multicall.contract.Call(opts, &out, "getTotalSupplies", tokens)
if err != nil {
return *new([]common.Address), *new([]*big.Int), err
}
out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
out1 := *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int)
return out0, out1, err
}
// GetTotalSupplies is a free data retrieval call binding the contract method 0x2dd43d89.
//
// Solidity: function getTotalSupplies(address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallSession) GetTotalSupplies(tokens []common.Address) ([]common.Address, []*big.Int, error) {
return _Multicall.Contract.GetTotalSupplies(&_Multicall.CallOpts, tokens)
}
// GetTotalSupplies is a free data retrieval call binding the contract method 0x2dd43d89.
//
// Solidity: function getTotalSupplies(address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallCallerSession) GetTotalSupplies(tokens []common.Address) ([]common.Address, []*big.Int, error) {
return _Multicall.Contract.GetTotalSupplies(&_Multicall.CallOpts, tokens)
}
// GetUsedBalances is a free data retrieval call binding the contract method 0x95d7710e.
//
// Solidity: function getUsedBalances(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallCaller) GetUsedBalances(opts *bind.CallOpts, poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
var out []interface{}
err := _Multicall.contract.Call(opts, &out, "getUsedBalances", poolAddress, tokens)
if err != nil {
return *new([]common.Address), *new([]*big.Int), err
}
out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
out1 := *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int)
return out0, out1, err
}
// GetUsedBalances is a free data retrieval call binding the contract method 0x95d7710e.
//
// Solidity: function getUsedBalances(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallSession) GetUsedBalances(poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
return _Multicall.Contract.GetUsedBalances(&_Multicall.CallOpts, poolAddress, tokens)
}
// GetUsedBalances is a free data retrieval call binding the contract method 0x95d7710e.
//
// Solidity: function getUsedBalances(address poolAddress, address[] tokens) view returns(address[], uint256[])
func (_Multicall *MulticallCallerSession) GetUsedBalances(poolAddress common.Address, tokens []common.Address) ([]common.Address, []*big.Int, error) {
return _Multicall.Contract.GetUsedBalances(&_Multicall.CallOpts, poolAddress, tokens)
}
package multicall
import (
"context"
"os"
"testing"
"github.com/bonedaddy/bdsm/testenv"
"github.com/bonedaddy/<redacted>/bindings/logswap"
"github.com/bonedaddy/<redacted>/bindings/multicall"
"github.com/bonedaddy/go-indexed/bclient"
"github.com/stretchr/testify/require"
)
var (
infuraAPIKey = os.Getenv("INFURA_API_KEY")
defi5ContractAddress = "0xfa6de2697d59e88ed7fc4dfe5a33dac43565ea41"
multicallContractAddress = "0x3067b1b7bf344027c7439509fbdf344eb25f5991"
defi5Tokens = []string{
"0xc00e94Cb662C3520282E6f5717214004A7f26888",
"0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F",
"0xD533a949740bb3306d119CC777fa900bA034cd52",
"0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
"0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9",
}
)
func TestMulticallReal(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
bc, err := bclient.NewInfuraClient(infuraAPIKey, true)
require.NoError(t, err)
caller, err := New(ctx, multicallContractAddress, bc.EthClient())
require.NoError(t, err)
var defi5TokensReversed []string
for i := len(defi5Tokens) - 1; i >= 0; i-- {
defi5TokensReversed = append(defi5TokensReversed, defi5Tokens[i])
}
// make sure reversal worked
require.NotEqual(t, defi5Tokens, defi5TokensReversed)
t.Run("GetDenormalizedWeights", func(t *testing.T) {
type args struct {
pool string
addrs []string
}
tests := []struct {
name string
args args
wantCount int
}{
{"DEFI5", args{
defi5ContractAddress,
defi5Tokens,
}, 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// get the current block number
block, err := bc.CurrentBlock()
require.NoError(t, err)
addrs, values, err := caller.GetDenormalizedWeights(
block,
tt.args.pool,
tt.args.addrs,
)
require.NoError(t, err)
require.Len(t, values, tt.wantCount)
require.Len(t, addrs, tt.wantCount)
})
}
})
t.Run("GetBalances", func(t *testing.T) {
type args struct {
pool string
addrs []string
}
tests := []struct {
name string
args args
wantCount int
}{
{"DEFI5", args{
defi5ContractAddress,
defi5Tokens,
}, 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// get the current block number
block, err := bc.CurrentBlock()
require.NoError(t, err)
addrs, values, err := caller.GetBalances(
block,
tt.args.pool,
tt.args.addrs,
)
require.NoError(t, err)
require.Len(t, values, tt.wantCount)
require.Len(t, addrs, tt.wantCount)
})
}
})
t.Run("GetUsedBalances", func(t *testing.T) {
type args struct {
pool string
addrs []string
}
tests := []struct {
name string
args args
wantCount int
}{
{"DEFI5", args{
defi5ContractAddress,
defi5Tokens,
}, 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// get the current block number
block, err := bc.CurrentBlock()
require.NoError(t, err)
addrs, values, err := caller.GetUsedBalances(
block,
tt.args.pool,
tt.args.addrs,
)
require.NoError(t, err)
require.Len(t, values, tt.wantCount)
require.Len(t, addrs, tt.wantCount)
})
}
})
t.Run("GetSpotPrices", func(t *testing.T) {
type args struct {
pool string
addrs []string
}
tests := []struct {
name string
args args
wantCount int
}{
{"DEFI5", args{
defi5ContractAddress,
defi5Tokens,
}, 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// get the current block number
block, err := bc.CurrentBlock()
require.NoError(t, err)
addrsIn, addrsOut, values, err := caller.GetSpotPrices(
block,
tt.args.pool,
tt.args.addrs, // in
defi5TokensReversed, // out
)
require.NoError(t, err)
require.Len(t, values, tt.wantCount)
require.Len(t, addrsIn, tt.wantCount)
require.Len(t, addrsOut, tt.wantCount)
})
}
})
t.Run("GetTotalSupplies", func(t *testing.T) {
type args struct {
addrs []string
}
tests := []struct {
name string
args args
wantCount int
}{
{"DEFI5", args{
defi5Tokens,
}, 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// get the current block number
block, err := bc.CurrentBlock()
require.NoError(t, err)
addrs, values, err := caller.GetTotalSupplies(
block,
tt.args.addrs,
)
require.NoError(t, err)
require.Len(t, values, tt.wantCount)
require.Len(t, addrs, tt.wantCount)
})
}
})
caller.Close()
}
pragma solidity >=0.7.0 <0.8.0;
/**
* @notice this interface is taken from indexed-core commit hash dae7f231d0f58bfc0993f6c01199cd6b74b01895
*/
interface IndexPoolI {
function getDenormalizedWeight(address token) external view returns (uint256);
function getBalance(address token) external view returns (uint256);
function getUsedBalance(address token) external view returns (uint256);
function getSpotPrice(address tokenIn, address tokenOut) external view returns (uint256);
}
interface ERC20I {
function totalSupply() external view returns (uint256);
}
/**
* @notice SimpleMultiCall is a multicall-like contract for reading IndexPool information
* @notice it is intended to minimize the need for manual abi encoding/decoding
* @notice and leverage Golang's abigen to do the heavy lifting
*/
contract SimpleMultiCall {
// index pool methods
function getDenormalizedWeights(
address poolAddress,
address[] memory tokens
)
public
view
returns (address[] memory, uint256[] memory)
{
uint256[] memory weights = new uint256[](tokens.length);
for (uint256 i = 0; i < tokens.length; i++) {
weights[i] = IndexPoolI(poolAddress).getDenormalizedWeight(tokens[i]);
}
return (tokens, weights);
}
function getBalances(
address poolAddress,
address[] memory tokens
)
public
view
returns (address[] memory, uint256[] memory)
{
uint256[] memory balances = new uint256[](tokens.length);
for (uint256 i = 0; i < tokens.length; i++) {
balances[i] = IndexPoolI(poolAddress).getBalance(tokens[i]);
}
return (tokens, balances);
}
function getUsedBalances(
address poolAddress,
address[] memory tokens
)
public
view
returns (address[] memory, uint256[] memory)
{
uint256[] memory balances = new uint256[](tokens.length);
for (uint256 i = 0; i < tokens.length; i++) {
balances[i] = IndexPoolI(poolAddress).getUsedBalance(tokens[i]);
}
return (tokens, balances);
}
function getSpotPrices(
address poolAddress,
address[] memory inTokens,
address[] memory outTokens
)
public
view
returns (address[] memory, address[] memory, uint256[] memory)
{
require(inTokens.length == outTokens.length);
uint256[] memory prices = new uint256[](inTokens.length);
for (uint256 i = 0; i < inTokens.length; i++) {
prices[i] = IndexPoolI(poolAddress).getSpotPrice(inTokens[i], outTokens[i]);
}
return (inTokens, outTokens, prices);
}
// erc20 methods
function getTotalSupplies(
address[] memory tokens
)
public
view
returns (address[] memory, uint256[] memory)
{
uint256[] memory supplies = new uint256[](tokens.length);
for (uint256 i = 0; i < tokens.length; i++) {
supplies[i] = ERC20I(tokens[i]).totalSupply();
}
return (tokens, supplies);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment