From 9d46d7f64bd3531e61ba677be55eee9f887c74dd Mon Sep 17 00:00:00 2001 From: Vadym Mozharivsky Date: Thu, 7 Nov 2024 16:36:15 +0200 Subject: [PATCH 1/3] eth multicall --- ethereum.js | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 65 insertions(+) diff --git a/ethereum.js b/ethereum.js index ab0adbc..e912a1d 100644 --- a/ethereum.js +++ b/ethereum.js @@ -1,5 +1,6 @@ const { Web3 } = require('web3'); const BigNumber = require('bignumber.js'); +const {Multicall} = require('ethereum-multicall'); const ABI_CONTRACT_ACCOUNTING = [{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"InvalidParam","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"InvalidValue","type":"error"},{"inputs":[{"internalType":"string","name":"field","type":"string"}],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"ActivateRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"AddWithdrawRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Autocompound","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"","type":"int256"}],"name":"ChangeExpectValidatorsToStop","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"ClaimPoolFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"ClaimWithdrawRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"DepositPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"FeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldGovernor","type":"address"},{"indexed":false,"internalType":"address","name":"newGovernor","type":"address"}],"name":"GovernorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"InterchangeDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"InterchangeWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"superAdmin","type":"address"}],"name":"SetSuperAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rewarderBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Update","type":"event"},{"inputs":[],"name":"BEACON_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"value","type":"address"}],"name":"setSuperAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"superAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolFee","type":"uint256"},{"internalType":"address","name":"rewardsTreasury","type":"address"},{"internalType":"address","name":"withdrawTreasury","type":"address"},{"internalType":"address","name":"accountingGovernor","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"depositToPendingValue","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"interchangedAmount","type":"uint256"},{"internalType":"uint256","name":"activatedSlots","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingDepositedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"autocompoundBalanceOf","outputs":[{"internalType":"uint256","name":"autocompoundBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"depositedBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"pendingDepositedBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"pendingBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawPending","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"withdrawFromPendingAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimPoolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getPoolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"update","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"feeValue","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"autocompound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingRestakedRewards","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"pendingRestakedRewardOf","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"restakedRewardOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawRequestQueueParams","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"withdrawRequest","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimWithdrawRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"readyforAutocompoundRewardsAmount","outputs":[{"internalType":"uint256","name":"unclaimedReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"closeValidatorsStat","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeAmount","type":"uint256"}],"name":"setMinRestakeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"activatedValidatorNum","type":"uint256"}],"name":"activateValidators","outputs":[],"stateMutability":"nonpayable","type":"function"}]; let ADDRESS_CONTRACT_ACCOUNTING = '0x7a7f0b3c23C23a31cFcb0c44709be70d4D545c6e'; @@ -10,6 +11,8 @@ let ADDRESS_CONTRACT_POOL = '0xD523794C879D9eC028960a231F866758e405bE34'; let ADDRESS_CONTRACT_WITHDRAW_TREASURY = '0x19449f0f696703Aa3b1485DfA2d855F33659397a'; let RPC_URL = 'https://mainnet.infura.io/v3/f583d4f04d384b9e8c59a7ff1c9f68f1'; +let MULTICALL_CONTRACT_ADDRESS = '0xca11bde05977b3631167028862be2a173976ca11' + let web3 = new Web3(RPC_URL); let contract_accounting = new web3.eth.Contract(ABI_CONTRACT_ACCOUNTING, ADDRESS_CONTRACT_ACCOUNTING); let contract_pool = new web3.eth.Contract(ABI_CONTRACT_POOL, ADDRESS_CONTRACT_POOL); @@ -238,6 +241,65 @@ async function closeValidatorsStat() { } } +// aggregatedBalances method returns object with aggregated balances using multicall contract +async function aggregatedBalances() { + const methods = [ + 'balance', + 'pendingBalance', + 'pendingDepositedBalance', + 'pendingRestakedRewards', + 'readyforAutocompoundRewardsAmount' + ] + const multicall = new Multicall({ + multicallCustomContractAddress: MULTICALL_CONTRACT_ADDRESS, + web3Instance: web3, + tryAggregate: true + }); + let contractCallContext = [] + methods.forEach((method) => contractCallContext.push({ + reference: method, + contractAddress: ADDRESS_CONTRACT_ACCOUNTING, + abi: ABI_CONTRACT_ACCOUNTING, + calls: [{reference: method, methodName: method}] + + })); + const results = await multicall.call(contractCallContext); + let aggResult = {} + for (const [key, value] of Object.entries(results.results)) { + aggResult[key] = web3.utils.fromWei(value.callsReturnContext[0].returnValues[0].hex, 'ether') + } + return aggResult; +} + +// aggregatedUserBalances method returns object with aggregated user balances using multicall contract +async function aggregatedUserBalances(address) { + const methods = [ + 'pendingBalanceOf', + 'pendingDepositedBalanceOf', + 'pendingRestakedRewardOf', + 'autocompoundBalanceOf', + ] + const multicall = new Multicall({ + multicallCustomContractAddress: MULTICALL_CONTRACT_ADDRESS, + web3Instance: web3, + tryAggregate: true + }); + let contractCallContext = [] + methods.forEach((method) => contractCallContext.push({ + reference: method, + contractAddress: ADDRESS_CONTRACT_ACCOUNTING, + abi: ABI_CONTRACT_ACCOUNTING, + calls: [{reference: method, methodName: method, methodParameters: [address]}] + + })); + const results = await multicall.call(contractCallContext); + let aggResult = {} + for (const [key, value] of Object.entries(results.results)) { + aggResult[key] = web3.utils.fromWei(value.callsReturnContext[0].returnValues[0].hex, 'ether') + } + return aggResult; +} + // ===POOL=== /** Stake funds into pool. * @param {string} address - Sender address. @@ -487,6 +549,8 @@ module.exports = { withdrawRequest, claimWithdrawRequest, closeValidatorsStat, + aggregatedBalances, + aggregatedUserBalances, // pool stake, diff --git a/package.json b/package.json index 1ca4f4a..f5b5582 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "bignumber.js": "^9.1.2", "bip39": "^3.1.0", "bs58": "^5.0.0", + "ethereum-multicall": "^2.26.0", "web3": "^4.14.0" } } From 1834bf3ce9cad6e6bbcd7795850e721309c3d253 Mon Sep 17 00:00:00 2001 From: Vadym Mozharivsky Date: Tue, 12 Nov 2024 12:56:31 +0200 Subject: [PATCH 2/3] rename methods --- ethereum.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ethereum.js b/ethereum.js index fef942d..4d09000 100644 --- a/ethereum.js +++ b/ethereum.js @@ -241,8 +241,8 @@ async function closeValidatorsStat() { } } -// aggregatedBalances method returns object with aggregated balances using multicall contract -async function aggregatedBalances() { +// poolBalances method returns object with aggregated balances using multicall contract +async function poolBalances() { const methods = [ 'balance', 'pendingBalance', @@ -271,8 +271,8 @@ async function aggregatedBalances() { return aggResult; } -// aggregatedUserBalances method returns object with aggregated user balances using multicall contract -async function aggregatedUserBalances(address) { +// userBalances method returns object with aggregated user balances using multicall contract +async function userBalances(address) { const methods = [ 'pendingBalanceOf', 'pendingDepositedBalanceOf', From d1e63b065c1acaf3d3188b497fef28189061bf3b Mon Sep 17 00:00:00 2001 From: Messer4 Date: Fri, 15 Nov 2024 14:54:19 +0200 Subject: [PATCH 3/3] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4cd6d74..6e7e0a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@everstake/wallet-sdk", - "version": "0.3.67", + "version": "0.3.68", "description": "Everstake Wallet SDK for Javascript", "main": "index.js", "publishConfig": {