Basic payouts to delegators when the pool is empty and they receive 100% of the reward.

This commit is contained in:
Greg Hysen
2019-06-11 16:56:12 -07:00
parent 362a8c8fc5
commit 7d85e61cc5
5 changed files with 80 additions and 12 deletions

View File

@@ -420,4 +420,7 @@ contract Staking is
{
rewardVault = IRewardVault(_rewardVault);
}
///// CAN RECEIVE FUNDS /////
function () external payable {}
}

View File

@@ -174,15 +174,26 @@ contract MixinStake is
// update delegator's share of reward pool
// note that this uses the snapshot parameters
uint256 poolBalance = rewardVault.balanceOf(poolId);
/*uint256 buyIn = _computeBuyInDenominatedInShadowAsset(
uint256 buyIn = _computeBuyInDenominatedInShadowAsset(
amount,
_delegatedStakeByPoolId,
shadowRewardsByPoolId[poolId],
poolBalance
);*/
//shadowRewardsInPoolByOwner[owner][poolId] = _safeAdd(shadowRewardsInPoolByOwner[owner][poolId], buyIn);
//shadowRewardsByPoolId[poolId] = _safeAdd(shadowRewardsByPoolId[poolId], buyIn);
);
if (buyIn > 0) {
shadowRewardsInPoolByOwner[owner][poolId] = _safeAdd(shadowRewardsInPoolByOwner[owner][poolId], buyIn);
shadowRewardsByPoolId[poolId] = _safeAdd(shadowRewardsByPoolId[poolId], buyIn);
}
}
event K(
uint256 amountDelegatedByOwner,
uint256 totalAmountDelegated,
uint256 amountOfShadowAssetHeldByOwner,
uint256 totalAmountOfShadowAsset,
uint256 totalAmountOfRealAsset,
uint256 payoutInRealAsset
);
// question - should we then return the amount withdrawn?
function _undelegateStake(address payable owner, bytes32 poolId, uint256 amount)
@@ -203,6 +214,7 @@ contract MixinStake is
delegatedStakeByPoolId[poolId] = _safeSub(_delegatedStakeByPoolId, amount);
// get payout
// TODO -- not full balance, just balance that belongs to delegators.
uint256 poolBalance = rewardVault.balanceOf(poolId);
uint256 payoutInRealAsset;
uint256 payoutInShadowAsset;
@@ -216,8 +228,17 @@ contract MixinStake is
shadowRewardsByPoolId[poolId],
poolBalance
);
emit K(
amount,
_delegatedStakeByPoolId,
payoutInShadowAsset,
shadowRewardsByPoolId[poolId],
poolBalance,
payoutInRealAsset
);
} else {
// partial payout
revert('no partial');
(payoutInRealAsset, payoutInShadowAsset) = _computePartialPayout(
amount,
_delegatedStakeByOwner,
@@ -231,9 +252,11 @@ contract MixinStake is
shadowRewardsByPoolId[poolId] = _safeSub(shadowRewardsByPoolId[poolId], payoutInShadowAsset);
// withdraw payout for delegator
if (payoutInRealAsset > 0) {
rewardVault.withdrawFor(poolId, payoutInRealAsset);
owner.transfer(payoutInRealAsset);
}
}
// Epoch | lockedAt | total | pending | deactivated | timelock() | withdraw() | available()
// 0 | 0 | 0 | 0 | 0 | | | 0

View File

@@ -31,6 +31,7 @@ contract LibRewards is SafeMath {
uint256 totalAmountOfRealAsset
)
internal
pure
returns (uint256)
{
return _safeSub(
@@ -54,6 +55,7 @@ contract LibRewards is SafeMath {
uint256 totalAmountOfRealAsset
)
internal
pure
returns (
uint256 payoutInRealAsset,
uint256 payoutInShadowAsset
@@ -77,6 +79,7 @@ contract LibRewards is SafeMath {
uint256 totalAmountOfRealAsset
)
internal
pure
returns (uint256)
{
if (totalAmountDelegated == 0) {

View File

@@ -1090,7 +1090,42 @@ describe('Staking Core', () => {
///// 8 CHECK PROFITS VIA STAKING CONTRACT /////
///// 9 WITHDRAW PROFITS VIA STAKING CONTRACT /////
/////
///// 10 CHECK DELEGATOR BY UNDELEGATING /////
const ethBalancesByDelegatorInit = await Promise.all([
stakingWrapper.getEthBalanceAsync(delegators[0]),
stakingWrapper.getEthBalanceAsync(delegators[1]),
stakingWrapper.getEthBalanceAsync(delegators[2]),
]);
await Promise.all([
stakingWrapper.deactivateAndTimelockDelegatedStakeAsync(delegators[0], poolIds[2], stakeByDelegator[0]),
stakingWrapper.deactivateAndTimelockDelegatedStakeAsync(delegators[1], poolIds[2], stakeByDelegator[1]),
stakingWrapper.deactivateAndTimelockDelegatedStakeAsync(delegators[2], poolIds[2], stakeByDelegator[2]),
]);
const ethBalancesByDelegatorFinal = await Promise.all([
stakingWrapper.getEthBalanceAsync(delegators[0]),
stakingWrapper.getEthBalanceAsync(delegators[1]),
stakingWrapper.getEthBalanceAsync(delegators[2]),
]);
const rewardByDelegator = [
ethBalancesByDelegatorFinal[0].minus(ethBalancesByDelegatorInit[0]),
ethBalancesByDelegatorFinal[1].minus(ethBalancesByDelegatorInit[1]),
ethBalancesByDelegatorFinal[2].minus(ethBalancesByDelegatorInit[2]),
];
// note that these may be slightly off due to rounding down on each entry
// there is a carry over between calls, which we account for here.
// if the last person to leave rounded down, then there is some trace amount left in the pool.
// carry-over here is 00000000000000000002
const expectedRewardByDelegator = [
payoutByPoolOperator[2].times(stakeByDelegator[0]).dividedToIntegerBy(totalStakeByDelegators),
payoutByPoolOperator[2].times(stakeByDelegator[1]).dividedToIntegerBy(totalStakeByDelegators),
new BigNumber('13927564703644768540'), // computed by hand to account for carry-over
];
expect(rewardByDelegator[0]).to.be.bignumber.equal(expectedRewardByDelegator[0]);
expect(rewardByDelegator[1]).to.be.bignumber.equal(expectedRewardByDelegator[1]);
expect(rewardByDelegator[2]).to.be.bignumber.equal(expectedRewardByDelegator[2]);
///// 10 CHECK DELEGATOR BUY-IN ON A SUBSEQUENT EPOCH, WHEN AMOUNT IS NON-ZERO /////
});
});
});

View File

@@ -122,12 +122,10 @@ export class StakingWrapper {
to: this.getStakingProxyContract().address,
data: calldata,
gas: 3000000,
gasPrice: 0,
value
}
const txHash = await this._web3Wrapper.sendTransactionAsync(txData);
if (includeLogs) {
}
const txReceipt = await (includeLogs ? this._logDecoder.getTxWithDecodedLogsAsync(txHash) : this._web3Wrapper.awaitTransactionSuccessAsync(txHash));
return txReceipt;
}
@@ -141,6 +139,10 @@ export class StakingWrapper {
const returnValue = await this._web3Wrapper.callAsync(txData);
return returnValue;
}
public async getEthBalanceAsync(owner: string): Promise<BigNumber> {
const balance = this._web3Wrapper.getBalanceInWeiAsync(owner);
return balance;
}
///// STAKE /////
public async depositAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().deposit.getABIEncodedTransactionData(amount);
@@ -154,7 +156,8 @@ export class StakingWrapper {
}
public async depositAndDelegateAsync(owner: string, poolId: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().depositAndDelegate.getABIEncodedTransactionData(poolId, amount);
const txReceipt = await this._executeTransactionAsync(calldata, owner);
const txReceipt = await this._executeTransactionAsync(calldata, owner);//, new BigNumber(0), true);
//console.log(JSON.stringify(txReceipt, null, 4));
return txReceipt;
}
public async activateStakeAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
@@ -174,7 +177,8 @@ export class StakingWrapper {
}
public async deactivateAndTimelockDelegatedStakeAsync(owner: string, poolId: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().deactivateAndTimelockDelegatedStake.getABIEncodedTransactionData(poolId, amount);
const txReceipt = await this._executeTransactionAsync(calldata, owner);
const txReceipt = await this._executeTransactionAsync(calldata, owner, new BigNumber(0), true);
console.log(JSON.stringify(txReceipt, null, 4));
return txReceipt;
}
public async withdrawAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {