Basic payouts to delegators when the pool is empty and they receive 100% of the reward.
This commit is contained in:
@@ -420,4 +420,7 @@ contract Staking is
|
|||||||
{
|
{
|
||||||
rewardVault = IRewardVault(_rewardVault);
|
rewardVault = IRewardVault(_rewardVault);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///// CAN RECEIVE FUNDS /////
|
||||||
|
function () external payable {}
|
||||||
}
|
}
|
||||||
|
@@ -174,16 +174,27 @@ contract MixinStake is
|
|||||||
// update delegator's share of reward pool
|
// update delegator's share of reward pool
|
||||||
// note that this uses the snapshot parameters
|
// note that this uses the snapshot parameters
|
||||||
uint256 poolBalance = rewardVault.balanceOf(poolId);
|
uint256 poolBalance = rewardVault.balanceOf(poolId);
|
||||||
/*uint256 buyIn = _computeBuyInDenominatedInShadowAsset(
|
uint256 buyIn = _computeBuyInDenominatedInShadowAsset(
|
||||||
amount,
|
amount,
|
||||||
_delegatedStakeByPoolId,
|
_delegatedStakeByPoolId,
|
||||||
shadowRewardsByPoolId[poolId],
|
shadowRewardsByPoolId[poolId],
|
||||||
poolBalance
|
poolBalance
|
||||||
);*/
|
);
|
||||||
//shadowRewardsInPoolByOwner[owner][poolId] = _safeAdd(shadowRewardsInPoolByOwner[owner][poolId], buyIn);
|
if (buyIn > 0) {
|
||||||
//shadowRewardsByPoolId[poolId] = _safeAdd(shadowRewardsByPoolId[poolId], buyIn);
|
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?
|
// question - should we then return the amount withdrawn?
|
||||||
function _undelegateStake(address payable owner, bytes32 poolId, uint256 amount)
|
function _undelegateStake(address payable owner, bytes32 poolId, uint256 amount)
|
||||||
private
|
private
|
||||||
@@ -203,6 +214,7 @@ contract MixinStake is
|
|||||||
delegatedStakeByPoolId[poolId] = _safeSub(_delegatedStakeByPoolId, amount);
|
delegatedStakeByPoolId[poolId] = _safeSub(_delegatedStakeByPoolId, amount);
|
||||||
|
|
||||||
// get payout
|
// get payout
|
||||||
|
// TODO -- not full balance, just balance that belongs to delegators.
|
||||||
uint256 poolBalance = rewardVault.balanceOf(poolId);
|
uint256 poolBalance = rewardVault.balanceOf(poolId);
|
||||||
uint256 payoutInRealAsset;
|
uint256 payoutInRealAsset;
|
||||||
uint256 payoutInShadowAsset;
|
uint256 payoutInShadowAsset;
|
||||||
@@ -216,8 +228,17 @@ contract MixinStake is
|
|||||||
shadowRewardsByPoolId[poolId],
|
shadowRewardsByPoolId[poolId],
|
||||||
poolBalance
|
poolBalance
|
||||||
);
|
);
|
||||||
|
emit K(
|
||||||
|
amount,
|
||||||
|
_delegatedStakeByPoolId,
|
||||||
|
payoutInShadowAsset,
|
||||||
|
shadowRewardsByPoolId[poolId],
|
||||||
|
poolBalance,
|
||||||
|
payoutInRealAsset
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// partial payout
|
// partial payout
|
||||||
|
revert('no partial');
|
||||||
(payoutInRealAsset, payoutInShadowAsset) = _computePartialPayout(
|
(payoutInRealAsset, payoutInShadowAsset) = _computePartialPayout(
|
||||||
amount,
|
amount,
|
||||||
_delegatedStakeByOwner,
|
_delegatedStakeByOwner,
|
||||||
@@ -231,8 +252,10 @@ contract MixinStake is
|
|||||||
shadowRewardsByPoolId[poolId] = _safeSub(shadowRewardsByPoolId[poolId], payoutInShadowAsset);
|
shadowRewardsByPoolId[poolId] = _safeSub(shadowRewardsByPoolId[poolId], payoutInShadowAsset);
|
||||||
|
|
||||||
// withdraw payout for delegator
|
// withdraw payout for delegator
|
||||||
rewardVault.withdrawFor(poolId, payoutInRealAsset);
|
if (payoutInRealAsset > 0) {
|
||||||
owner.transfer(payoutInRealAsset);
|
rewardVault.withdrawFor(poolId, payoutInRealAsset);
|
||||||
|
owner.transfer(payoutInRealAsset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Epoch | lockedAt | total | pending | deactivated | timelock() | withdraw() | available()
|
// Epoch | lockedAt | total | pending | deactivated | timelock() | withdraw() | available()
|
||||||
|
@@ -31,6 +31,7 @@ contract LibRewards is SafeMath {
|
|||||||
uint256 totalAmountOfRealAsset
|
uint256 totalAmountOfRealAsset
|
||||||
)
|
)
|
||||||
internal
|
internal
|
||||||
|
pure
|
||||||
returns (uint256)
|
returns (uint256)
|
||||||
{
|
{
|
||||||
return _safeSub(
|
return _safeSub(
|
||||||
@@ -54,6 +55,7 @@ contract LibRewards is SafeMath {
|
|||||||
uint256 totalAmountOfRealAsset
|
uint256 totalAmountOfRealAsset
|
||||||
)
|
)
|
||||||
internal
|
internal
|
||||||
|
pure
|
||||||
returns (
|
returns (
|
||||||
uint256 payoutInRealAsset,
|
uint256 payoutInRealAsset,
|
||||||
uint256 payoutInShadowAsset
|
uint256 payoutInShadowAsset
|
||||||
@@ -77,6 +79,7 @@ contract LibRewards is SafeMath {
|
|||||||
uint256 totalAmountOfRealAsset
|
uint256 totalAmountOfRealAsset
|
||||||
)
|
)
|
||||||
internal
|
internal
|
||||||
|
pure
|
||||||
returns (uint256)
|
returns (uint256)
|
||||||
{
|
{
|
||||||
if (totalAmountDelegated == 0) {
|
if (totalAmountDelegated == 0) {
|
||||||
|
@@ -1090,7 +1090,42 @@ describe('Staking Core', () => {
|
|||||||
///// 8 CHECK PROFITS VIA STAKING CONTRACT /////
|
///// 8 CHECK PROFITS VIA STAKING CONTRACT /////
|
||||||
///// 9 WITHDRAW 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 /////
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -122,12 +122,10 @@ export class StakingWrapper {
|
|||||||
to: this.getStakingProxyContract().address,
|
to: this.getStakingProxyContract().address,
|
||||||
data: calldata,
|
data: calldata,
|
||||||
gas: 3000000,
|
gas: 3000000,
|
||||||
|
gasPrice: 0,
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
const txHash = await this._web3Wrapper.sendTransactionAsync(txData);
|
const txHash = await this._web3Wrapper.sendTransactionAsync(txData);
|
||||||
if (includeLogs) {
|
|
||||||
|
|
||||||
}
|
|
||||||
const txReceipt = await (includeLogs ? this._logDecoder.getTxWithDecodedLogsAsync(txHash) : this._web3Wrapper.awaitTransactionSuccessAsync(txHash));
|
const txReceipt = await (includeLogs ? this._logDecoder.getTxWithDecodedLogsAsync(txHash) : this._web3Wrapper.awaitTransactionSuccessAsync(txHash));
|
||||||
return txReceipt;
|
return txReceipt;
|
||||||
}
|
}
|
||||||
@@ -141,6 +139,10 @@ export class StakingWrapper {
|
|||||||
const returnValue = await this._web3Wrapper.callAsync(txData);
|
const returnValue = await this._web3Wrapper.callAsync(txData);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
public async getEthBalanceAsync(owner: string): Promise<BigNumber> {
|
||||||
|
const balance = this._web3Wrapper.getBalanceInWeiAsync(owner);
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
///// STAKE /////
|
///// STAKE /////
|
||||||
public async depositAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
public async depositAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const calldata = this.getStakingContract().deposit.getABIEncodedTransactionData(amount);
|
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> {
|
public async depositAndDelegateAsync(owner: string, poolId: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const calldata = this.getStakingContract().depositAndDelegate.getABIEncodedTransactionData(poolId, amount);
|
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;
|
return txReceipt;
|
||||||
}
|
}
|
||||||
public async activateStakeAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
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> {
|
public async deactivateAndTimelockDelegatedStakeAsync(owner: string, poolId: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const calldata = this.getStakingContract().deactivateAndTimelockDelegatedStake.getABIEncodedTransactionData(poolId, amount);
|
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;
|
return txReceipt;
|
||||||
}
|
}
|
||||||
public async withdrawAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
public async withdrawAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
Reference in New Issue
Block a user