Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check bonded ETH for operators #48

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 257 additions & 3 deletions inspector/scripts/inspect-operators.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const truffleContract = require("@truffle/contract")
const clc = require("cli-color")

const contractHelper = require("./lib/contract-helper")

const KeepTokenJson = require("@keep-network/keep-core/artifacts/KeepToken.json")
const TokenStakingJson = require("@keep-network/keep-core/artifacts/TokenStaking.json")
const KeepBondingJson = require("@keep-network/keep-ecdsa/artifacts/KeepBonding.json")
Expand Down Expand Up @@ -41,6 +43,11 @@ module.exports = async function () {
const keepBonding = await KeepBonding.deployed()
const tbtcSystem = await TBTCSystem.deployed()

const deploymentBlock = await contractHelper.getDeploymentBlockNumber(
KeepBondingJson,
web3,
)

console.log(clc.yellow(`*** Contract Addresses ***`))
console.log(`KeepToken: ${keepToken.address}`)
console.log(`TokenStaking: ${tokenStaking.address}`)
Expand Down Expand Up @@ -102,9 +109,229 @@ module.exports = async function () {
)
console.log(``)

getDepositedAmount = async function () {
bondSeizedEventSignature = web3.utils.sha3(
"BondSeized(address,uint256,address,uint256)",
)

const operatorsDepositedAmount = {}
const totalDepositedAmount = web3.utils.toBN(0)

const events = await keepBonding.getPastEvents("UnbondedValueDeposited", {
fromBlock: deploymentBlock,
})

eventsLoop: for (let i = 0; i < events.length; i++) {
const event = events[i]

const operator = event.args.operator.toLowerCase()
const amount = web3.utils.toBN(event.args.amount || 0)

// Part of seized bond amount is being returned by tBTC as a unbonded
// value deposit. We want to check if the deposited value came from
// a returned seized amount and if so don't include it in the
// deposited amount.
const transaction = await web3.eth.getTransactionReceipt(
event.transactionHash,
)

for (let i = 0; i < transaction.logs.length; i++) {
const log = transaction.logs[i]

if (log.topics[0] === bondSeizedEventSignature) {
continue eventsLoop
}
}

if (operatorsDepositedAmount[operator] === undefined) {
operatorsDepositedAmount[operator] = amount
} else {
operatorsDepositedAmount[operator].iadd(amount)
}

totalDepositedAmount.iadd(amount)
}

return {
forOperators: operatorsDepositedAmount,
total: totalDepositedAmount,
}
}

getWithdrawnAmount = async function (eventName) {
const operatorsWithdrawnAmount = {}
const totalWithdrawnAmount = web3.utils.toBN(0)

const events = await keepBonding.getPastEvents("UnbondedValueWithdrawn", {
fromBlock: deploymentBlock,
})

for (let i = 0; i < events.length; i++) {
const event = events[i]

const operator = event.args.operator.toLowerCase()
const amount = web3.utils.toBN(event.args.amount || 0)

if (operatorsWithdrawnAmount[operator] === undefined) {
operatorsWithdrawnAmount[operator] = amount
} else {
operatorsWithdrawnAmount[operator].iadd(amount)
}

totalWithdrawnAmount.iadd(amount)
}

return {
forOperators: operatorsWithdrawnAmount,
total: totalWithdrawnAmount,
}
}

getBondedAmount = async function () {
const operatorsBondedAmount = {}
const totalBondedAmount = web3.utils.toBN(0)

const events = await keepBonding.getPastEvents("BondCreated", {
fromBlock: deploymentBlock,
})

for (let i = 0; i < events.length; i++) {
const event = events[i]

const operator = event.args.operator.toLowerCase()
const bondAmount = web3.utils.toBN(event.args.amount || 0)
const bondReferenceID = event.args.referenceID

// Check if the bond has been released. If so don't include the bond in
// the result and skip to a next event.
const releasedEvents = await keepBonding.getPastEvents("BondReleased", {
fromBlock: deploymentBlock,
filter: {
operator: operator,
referenceID: bondReferenceID.toString(),
},
})
if (releasedEvents.length > 0) {
continue
}

// Check if the bond has been seized. If so subtract the seized amount from
// the bonded amount.
const seizedEvents = await keepBonding.getPastEvents("BondSeized", {
fromBlock: deploymentBlock,
filter: {
operator: operator,
referenceID: bondReferenceID.toString(),
},
})

for (let i = 0; i < seizedEvents.length; i++) {
const seizedEvent = seizedEvents[i]
const seizedAmount = seizedEvent.args.amount
bondAmount.isub(seizedAmount)
}

if (operatorsBondedAmount[operator] === undefined) {
operatorsBondedAmount[operator] = bondAmount
} else {
operatorsBondedAmount[operator].iadd(bondAmount)
}

totalBondedAmount.iadd(bondAmount)
}

return { forOperators: operatorsBondedAmount, total: totalBondedAmount }
}

getSeizedAmount = async function () {
depositedEventSignature = web3.utils.sha3(
"UnbondedValueDeposited(address,address,uint256)",
)

const operatorsSeizedAmount = {}
const totalSeizedAmount = web3.utils.toBN(0)

const events = await keepBonding.getPastEvents("BondSeized", {
fromBlock: deploymentBlock,
})

eventsLoop: for (let i = 0; i < events.length; i++) {
const event = events[i]
const operator = event.args.operator.toLowerCase()
const grossSeizedAmount = web3.utils.toBN(event.args.amount || 0)

// Part of seized bond amount is being returned by tBTC as a unbonded
// value deposit. We want to find the value that got returned so we can
// find actual seized amount (net seized amount).
const transaction = await web3.eth.getTransactionReceipt(
event.transactionHash,
)

// Check other events emitted in the same transaction that bond has been
// seized.
for (let i = 0; i < transaction.logs.length; i++) {
const log = transaction.logs[i]

encodedOperator = web3.eth.abi.encodeParameter("address", operator)

if (
log.topics[0] === depositedEventSignature &&
log.topics[1] === encodedOperator
) {
const returnedAmount = web3.utils.toBN(log.data)

const netSeizedAmount = grossSeizedAmount.sub(returnedAmount)

if (operatorsSeizedAmount[operator] === undefined) {
operatorsSeizedAmount[operator] = netSeizedAmount
} else {
operatorsSeizedAmount[operator].iadd(netSeizedAmount)
}

totalSeizedAmount.iadd(netSeizedAmount)
}
}
}

return { forOperators: operatorsSeizedAmount, total: totalSeizedAmount }
}

// Operators' Deposited Amount
const depositedAmounts = await getDepositedAmount()

// Operators' Withdrawn Amount
const withdrawnAmounts = await getWithdrawnAmount()

// Operators' Currently Bonded Amount
const bondedAmounts = await getBondedAmount()

// Operators' Seized Bonds Amount
const bondsSeizedAmounts = await getSeizedAmount()

// Total Values
console.log(
`Total Deposited Amount ETH: ` +
`${web3.utils.fromWei(depositedAmounts.total).toString()}`,
)

console.log(
`Total Withdrawn Amount ETH: ` +
`${web3.utils.fromWei(withdrawnAmounts.total).toString()}`,
)

console.log(
`Total Currently Bonded Amount ETH: ` +
`${web3.utils.fromWei(bondedAmounts.total).toString()}`,
)

console.log(
`Total Seized Bonds ETH: ` +
`${web3.utils.fromWei(bondsSeizedAmounts.total).toString()}`,
)

const ecdsaSummary = []
for (let i = 0; i < ecdsaOperators.length; i++) {
const operator = ecdsaOperators[i]
const operator = ecdsaOperators[i].toLowerCase()

const eligibleStake = await tokenStaking.eligibleStake(
operator,
Expand All @@ -118,6 +345,26 @@ module.exports = async function () {
const unbondedValue = await keepBonding.unbondedValue(operator)
const unbondedValueEth = web3.utils.fromWei(unbondedValue)

const depositedAmount = web3.utils.toBN(
depositedAmounts.forOperators[operator] || 0,
)
const depositedAmountEth = web3.utils.fromWei(depositedAmount)

const withdrawnAmount = web3.utils.toBN(
withdrawnAmounts.forOperators[operator] || 0,
)
const withdrawnAmountEth = web3.utils.fromWei(withdrawnAmount)

const bondedAmount = web3.utils.toBN(
bondedAmounts.forOperators[operator] || 0,
)
const bondedAmountEth = web3.utils.fromWei(bondedAmount)

const bondsSeizedAmount = web3.utils.toBN(
bondsSeizedAmounts.forOperators[operator] || 0,
)
const bondsSeizedAmountEth = web3.utils.fromWei(bondsSeizedAmount)

const isRegisteredInTbtcPool = await bondedEcdsaKeepFactory.isOperatorRegistered(
operator,
tbtcSystem.address,
Expand All @@ -137,18 +384,25 @@ module.exports = async function () {
address: operator,
eligibleStakeKeep: eligibleStakeKeep.toString(),
operatorBalanceEth: operatorBalanceEth.toString(),
depositedAmountEth: depositedAmountEth.toString(),
withdrawnAmountEth: withdrawnAmountEth.toString(),
unbondedValueEth: unbondedValueEth.toString(),
bondsAmountEth: bondedAmountEth.toString(),
seizedAmountEth: bondsSeizedAmountEth.toString(),
isRegisteredInTbtcPool: isRegisteredInTbtcPool,
isUpToDateInTbtcPool: isUpToDateInTbtcPool,
})
}

console.log(clc.yellow(`*** ECDSA Operators ***`))

if (process.env.OUTPUT_MODE === "text") {
ecdsaSummary.forEach((s) =>
console.log(
`${s.address} ${s.eligibleStakeKeep} ${s.operatorBalanceEth} ` +
`${s.unbondedValueEth} ${s.isRegisteredInTbtcPool} ${s.isUpToDateInTbtcPool}`,
`${s.depositedAmountEth} ${s.withdrawnAmountEth} ${s.unbondedValueEth} ` +
`${s.bondsAmountEth} ${s.seizedAmountEth} ${s.isRegisteredInTbtcPool} ` +
`${s.isUpToDateInTbtcPool}`,
),
)
} else {
Expand All @@ -159,7 +413,7 @@ module.exports = async function () {

process.exit(0)
} catch (error) {
console.log(`ERROR: ${error}`)
console.trace(error)
process.exit(1)
}
}