tip: 271
title: Vote for SR in Smart Contract
author: yanghang8612<[email protected]>
status: Final
type: Standards Track
category: VM
created: 2021-06-01
To provide vote related operations in TVM.
VoteWitness
& WithdrawReward
operations in system contract are introduced, smart contract can vote for witness and get reward from the system.
Common user can vote for activated witness to share the block reward. However, non-privatekey accounts, like smart contracts, can not get benefit from this incentive mechanism.
Meanwhile, after TIP-157 activating on the mainnet, smart contracts can freeze their balance to get resources include tron power. But this part of resources can not be used because there is no vote related instructions in TVM.
So this TIP aims to implement the incentive voting functionalities for smart contracts. On one hand, smart contracts will take fully advantage of their balance. For example, voting witness, keeping the network safe, sharing the block reward. On the other hand, developer could write some special voting contracts to provide a new way to vote witness for common user which is different from system voting contract. These voting contracts may be more complex to system voting contract and provide more attractive and unique voting feature.
The VOTE
takes 4 operands pop up from stack:
tronPowerArrayLength
: witness address array offset.
tronPowerArrayOffset
: witness address array size.
witnessAddressArrayLength
: tron power number array offset.
witnessAddressArrayOffset
: tron power number array size.
TVM will get witness array from memory by using witnessOffset
and witnessSize
.
TVM will get tron power array from memory by using tronPowerOffset
and tronPowerSize
.
Execute vote function and push 0 to stack if fail, push 1 otherwize.
The WITHDRAWREWARD
takes no operand pop up from stack.
Execute withdraw function and push actually withdrawed reward amout to stack.
The RewardBalance
takes no operand pop up from stack.
Execute query reward function and push reward amount which can be withdrawed to stack.
The IsSrCandidate
takes 1 operand pop up from stack:
targetAddress
: target account address.
Push 0 if target address is not a witness, otherwise push 1.
The VoteCount
takes 2 operand pop up from stack:
voteAddress
: vote account address.
targetAddress
: target account address.
Execute query vote count function and push vote count to stack.
The UsedVoteCount
takes 1 operand pop up from stack:
voteAddress
: vote account address.
Execute query total used vote count function.
The ReceviedVoteCount
takes 1 operand pop up from stack:
receivedAddress
: witness address.
Excute query witness total received vote count.
The TotalVoteCount
takes 1 operand pop up from stack:
voteAddress
: vote account address.
Execute query total vote count function.
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.5.18 || ^0.6.13 || ^0.7.7 || ^0.8.6;
contract TestVote {
/**
* @dev Contract can accept value while creating.
*/
constructor() public payable {}
/**
* Due to the introduction of Stake2.0, we have removed the Stake1.0 related example codes.
* Please add the appropriate staking codes here according to the version of the staking mechanism.
*/
// Staking related code here
/**
* @dev Vote witness in `srList` array and every witness will get correspond
* tron power in `tpList` array.
*
* Below situations can cause `revert` exception:
* 1. `srList` array length and `tpList` array length are different.
* 2. Array length are greater than MAX_VOTE_NUMBER (30).
* 3. There are normal account address in `srList` array.
* 4. There are negative value in 'tpList' array.
* 5. Total needed tron power is greater than current owned tron power of contract.
*/
function voteWitness(address[] calldata srList, uint[] calldata tpList) external {
vote(srList, tpList);
}
/**
* @dev Withdraw all allowance and reward to contract balance.
* @return Actually withdrawn balance of allowance and reward.
*
* Below situations can cause `revert` exception:
* 1. Contract address is in witness list of genesis block.
* 2. Sum of contract balance and reward overflow long (8 bytes).
*
* Caution:
* 1. Current cycle reward can not be withdrawed.
*/
function withdrawReward() external returns(uint) {
return withdrawreward();
}
/**
* @dev Query all allowance and reward of contract account.
* @return Sum of allowance and reward of contradct account.
*
* caution:
* 1. Current cycle reward is excluded
*/
function queryRewardBalance() external view returns(uint) {
return rewardBalance();
}
/**
* @dev Judge whether the address is a candidate address.
* @return If the address is a candidate address, return `true`, otherwise return `false`.
*/
function isWitness(address sr) external view returns(bool) {
return isSrCandidate(sr);
}
/**
* @dev Query vote count of `from` account voting for `to` account.
* @return Corresponding vote count (tron-power, 1 trx = 1 tron-power).
*/
function queryVoteCount(address from, address to) external view returns(uint) {
return voteCount(from, to);
}
/**
* @dev Query total vote count of `owner` (Also can be called tron-power owned by contract).
* @return Total vote count of `owner` account (tron-power, 1 trx = 1 tron-power).
*/
function queryTotalVoteCount(address owner) external view returns(uint) {
return totalVoteCount(owner);
}
/**
* @dev Query `owner` recevied vote count.
* @return Received vote count of `owner` account (tron-power, 1 trx = 1 tron-power).
*/
function queryReceivedVoteCount(address owner) external view returns(uint) {
return receivedVoteCount(owner);
}
/**
* @dev Query `owner` used vote count.
* @return Used vote count of `owner` account (tron-power, 1 trx = 1 tron-power).
*/
function queryUsedVoteCount(address owner) external view returns(uint) {
return usedVoteCount(owner);
}
/**
* @dev Execute self destruct and transfer all balance and asset of contract to target address.
*
* Below situations can cause `revert` exception:
* 1. There are still delegated frozen balance for other account address.
*
* Caution
* 1. The operation will auto clear votes and withdraw all allowance and reward to contract balance.
*/
function killme(address payable target) external {
selfdestruct(target);
}
}
For vote(address[], uint[])
, if array length in memory does not match the parameter length, a ByteExecutionexception
will throw.
For vote(address[], uint[])
, if address
array length and uint
array length is different, a revert
exception will throw.
For withdrawreward()
, withdraw all rewards to contract balance.
Both vote(address[], uint[])
and withdrawreward()
will change the state of storage, so they can not be executed in static
context (a static
context can only be created by staticcall
now). Otherwise, a StaticCallModificationexception
will throw.
See author`s blog for more details of the algorithm at Read the docs
VOTEWITNESS
: tier.ExtTier
WITHDRAWREWARD
: tier.ExtTier
VOTEWITNESS
: 30000 energy
WITHDRAWREWARD
: 20000 energy
RewardBalance
: 500 energy
IsSrCandidate
: 20 energy
VoteCount
: 500 energy
UsedVoteCount
: 20 energy
ReceivedVoteCount
: 20 energy
TotalVoteCount
: 20 energy
If contract still has votes and unwithdrawed reward, selfdestruct will auto clear votes and withdraw allowance and reward to contract balance. There may be some rewards of current cycle that can never be withdrawed.