Skip to content

Commit 20278c6

Browse files
committed
Add resolveAndReleaseStake method
1 parent bbc9835 commit 20278c6

File tree

2 files changed

+112
-1
lines changed

2 files changed

+112
-1
lines changed

contracts/NumeraiErasureV1.sol

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ contract NumeraiErasureV1 is Initializable, Pausable {
4747
uint256 amountReleased
4848
);
4949

50+
event ResolveAndReleaseStake(
51+
address indexed agreement,
52+
address indexed staker,
53+
uint256 oldStakeAmount,
54+
uint256 amountReleased,
55+
int256 amountStakeChanged
56+
);
57+
5058
// set the address of the NMR token as a constant (stored in runtime code)
5159
address private constant _TOKEN = address(
5260
0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671
@@ -170,10 +178,33 @@ contract NumeraiErasureV1 is Initializable, Pausable {
170178
function releaseStake(
171179
address agreement, address staker, uint256 currentStake, uint256 amountToRelease
172180
) public onlyManagerOrOwner whenNotPaused {
173-
require(amountToRelease > 0, "Cannot punish zero NMR");
181+
require(amountToRelease > 0, "Cannot release zero NMR");
174182

175183
IErasureStake(agreement).releaseStake(currentStake, amountToRelease);
176184

177185
emit ReleaseStake(agreement, staker, currentStake, amountToRelease);
178186
}
187+
188+
/// @notice Internal function to resolve and then release an Erasure agreement stake
189+
/// @param agreement The address of the agreement contract. Must conform to IErasureStake interface
190+
/// @param staker The address of the staker
191+
/// @param currentStake The amount of NMR in wei already staked on the agreement
192+
/// @param amountToRelease The amount of NMR in wei to release back to the staker
193+
/// @param amountToChangeStake The amount of NMR to change the stake with. If negative, then call `punish`, else call `reward`. This is called before `releaseStake`
194+
function resolveAndReleaseStake(
195+
address agreement, address staker, uint256 currentStake, uint256 amountToRelease, int256 amountToChangeStake
196+
) public onlyManagerOrOwner whenNotPaused {
197+
uint256 newStake;
198+
if(amountToChangeStake > 0) {
199+
reward(agreement, staker, currentStake, uint256(amountToChangeStake));
200+
newStake = currentStake.add(uint256(amountToChangeStake));
201+
} else {
202+
punish(agreement, staker, currentStake, uint256(-amountToChangeStake), "punish before release");
203+
newStake = currentStake.sub(uint256(-amountToChangeStake));
204+
}
205+
206+
IErasureStake(agreement).releaseStake(newStake, amountToRelease);
207+
208+
emit ResolveAndReleaseStake(agreement, staker, currentStake, amountToRelease, amountToChangeStake);
209+
}
179210
}

test/erasure.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ describe('Test Erasure agreements', async () => {
6969
assert.strictEqual(balance.toString(), utils.parseEther("90").toString(), 'balance is wrong for user');
7070

7171
agreement = deployer.wrapDeployedContract(SimpleGriefing, agreementAddress);
72+
balance = await agreement.getStake(userAddress);
73+
assert.strictEqual(balance.toString(), utils.parseEther("10").toString(), 'balance is wrong for stake');
7274
});
7375

7476
it('should increaseStake', async () => {
@@ -95,6 +97,8 @@ describe('Test Erasure agreements', async () => {
9597

9698
let balance = await mockNMRContract.balanceOf(userAddress);
9799
assert.strictEqual(balance.toString(), utils.parseEther("75").toString(), 'balance is wrong for user');
100+
balance = await agreement.getStake(userAddress);
101+
assert.strictEqual(balance.toString(), utils.parseEther("25").toString(), 'balance is wrong for stake');
98102
});
99103

100104
it('should reward', async () => {
@@ -122,6 +126,8 @@ describe('Test Erasure agreements', async () => {
122126

123127
let balance = await mockNMRContract.balanceOf(userAddress);
124128
assert.strictEqual(balance.toString(), utils.parseEther("75").toString(), 'balance is wrong for user');
129+
balance = await agreement.getStake(userAddress);
130+
assert.strictEqual(balance.toString(), utils.parseEther("35").toString(), 'balance is wrong for stake');
125131
});
126132

127133
it('should punish', async () => {
@@ -149,6 +155,8 @@ describe('Test Erasure agreements', async () => {
149155

150156
let balance = await mockNMRContract.balanceOf(userAddress);
151157
assert.strictEqual(balance.toString(), utils.parseEther("75").toString(), 'balance is wrong for user');
158+
balance = await agreement.getStake(userAddress);
159+
assert.strictEqual(balance.toString(), utils.parseEther("25").toString(), 'balance is wrong for stake');
152160
});
153161

154162
it('should releaseStake partial', async () => {
@@ -176,6 +184,8 @@ describe('Test Erasure agreements', async () => {
176184

177185
let balance = await mockNMRContract.balanceOf(userAddress);
178186
assert.strictEqual(balance.toString(), utils.parseEther("85").toString(), 'balance is wrong for user');
187+
balance = await agreement.getStake(userAddress);
188+
assert.strictEqual(balance.toString(), utils.parseEther("15").toString(), 'balance is wrong for stake');
179189
});
180190

181191
it('should releaseStake full', async () => {
@@ -203,5 +213,75 @@ describe('Test Erasure agreements', async () => {
203213

204214
let balance = await mockNMRContract.balanceOf(userAddress);
205215
assert.strictEqual(balance.toString(), utils.parseEther("100").toString(), 'balance is wrong for user');
216+
balance = await agreement.getStake(userAddress);
217+
assert.strictEqual(balance.toString(), utils.parseEther("0").toString(), 'balance is wrong for stake');
218+
});
219+
220+
it('should resolveAndRelease reward', async () => {
221+
const releaseAmount = utils.parseEther("15");
222+
const amountToChange = utils.parseEther("40");
223+
const oldStakeAmount = utils.parseEther("0");
224+
225+
let txn = await numeraiErasureContract.resolveAndReleaseStake(agreement.contractAddress, userAddress, oldStakeAmount, releaseAmount, amountToChange);
226+
const receipt = await numeraiErasureContract.verboseWaitForTransaction(txn);
227+
const stakeEvent = receipt.events.find(
228+
emittedEvent => emittedEvent.event === "ResolveAndReleaseStake",
229+
"There is no such event"
230+
);
231+
232+
assert.isDefined(stakeEvent);
233+
assert.equal(stakeEvent.args.agreement, agreement.contractAddress);
234+
assert.equal(stakeEvent.args.staker, userAddress);
235+
assert.strictEqual(
236+
stakeEvent.args.amountReleased.toString(),
237+
releaseAmount.toString(),
238+
);
239+
assert.strictEqual(
240+
stakeEvent.args.oldStakeAmount.toString(),
241+
oldStakeAmount.toString(),
242+
);
243+
assert.strictEqual(
244+
stakeEvent.args.amountStakeChanged.toString(),
245+
amountToChange.toString(),
246+
);
247+
248+
let balance = await mockNMRContract.balanceOf(userAddress);
249+
assert.strictEqual(balance.toString(), utils.parseEther("115").toString(), 'balance is wrong for user');
250+
balance = await agreement.getStake(userAddress);
251+
assert.strictEqual(balance.toString(), utils.parseEther("25").toString(), 'balance is wrong for stake');
252+
});
253+
254+
it('should resolveAndRelease punish', async () => {
255+
const releaseAmount = utils.parseEther("5");
256+
const amountToChange = utils.parseEther("-10");
257+
const oldStakeAmount = utils.parseEther("25");
258+
259+
let txn = await numeraiErasureContract.resolveAndReleaseStake(agreement.contractAddress, userAddress, oldStakeAmount, releaseAmount, amountToChange);
260+
const receipt = await numeraiErasureContract.verboseWaitForTransaction(txn);
261+
const stakeEvent = receipt.events.find(
262+
emittedEvent => emittedEvent.event === "ResolveAndReleaseStake",
263+
"There is no such event"
264+
);
265+
266+
assert.isDefined(stakeEvent);
267+
assert.equal(stakeEvent.args.agreement, agreement.contractAddress);
268+
assert.equal(stakeEvent.args.staker, userAddress);
269+
assert.strictEqual(
270+
stakeEvent.args.amountReleased.toString(),
271+
releaseAmount.toString(),
272+
);
273+
assert.strictEqual(
274+
stakeEvent.args.oldStakeAmount.toString(),
275+
oldStakeAmount.toString(),
276+
);
277+
assert.strictEqual(
278+
stakeEvent.args.amountStakeChanged.toString(),
279+
amountToChange.toString(),
280+
);
281+
282+
let balance = await mockNMRContract.balanceOf(userAddress);
283+
assert.strictEqual(balance.toString(), utils.parseEther("120").toString(), 'balance is wrong for user');
284+
balance = await agreement.getStake(userAddress);
285+
assert.strictEqual(balance.toString(), utils.parseEther("10").toString(), 'balance is wrong for stake');
206286
});
207287
});

0 commit comments

Comments
 (0)