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

Implement ScorchedEarth Mechanics Using ForceMove Protocol #8

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Require User undo Burn & apply payment on Reward
apbendi committed Jul 23, 2020
commit 6f45ff331dad8a7e6f6132ccfe6d0085874db828
17 changes: 14 additions & 3 deletions chain/contracts/ScorchedEarth.sol
Original file line number Diff line number Diff line change
@@ -126,7 +126,7 @@ contract ScorchedEarth is ForceMoveApp {
require(bytes(_data.suggestion).length == 0,
'ScorchedEarth: React Phase must not have suggestion');
} else {
require(false, 'ScorchedEarth: Invalid phase');
require(false, 'ScorchedEarth: Invalid Phase');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would revert('msg') be a minor improvement to require(false,'msg')?

}
}

@@ -166,9 +166,20 @@ contract ScorchedEarth is ForceMoveApp {
require(didBurnUser && didBurnSuggester && didPayBurner,
'ScorchedEarth: Suggest Phase must burn funds');
} else if (_toData.phase == Phase.React) {

if (_toData.reaction == Reaction.Reward) {
bool didUserPay = ( _toAllocation[0].amount == (_fromAllocation[0].amount.add(_toData.userBurn)) );
bool didPaySuggester = ( _toAllocation[1].amount == (_fromAllocation[1].amount.add(_toData.suggesterBurn).add(_toData.payment)) );
bool didUndoBurner = ( _toAllocation[2].amount == (_fromAllocation[2].amount.sub(_toData.payment).sub(_toData.userBurn).sub(_toData.suggesterBurn)) );

require(didUserPay && didPaySuggester && didUndoBurner,
'ScorchedEarth: Reward Reaction must pay');
} else if (_toData.reaction == Reaction.Burn) {

} else {
require(false, 'ScorchedEarth: Invalid reaction');
}
} else {
require(false, 'ScorchedEarth: Invalid phase');
require(false, 'ScorchedEarth: Invalid Phase');
}
}
}
120 changes: 120 additions & 0 deletions chain/test/scorched-earth-force-move-test.ts
Original file line number Diff line number Diff line change
@@ -572,4 +572,124 @@ describe('ScorchedEarth Force Move Implementation', () => {

expect(isValid).to.be.true;
});

it('should not accept a react phase that does not pay the suggester', async () => {
const initialAllocations = {user: 100, suggester: 100, burner: 0};
const parameters = dataBuilder.parameters;

const fromOutcome = outcomeBuilder.createEncodedOutcome({
user: initialAllocations.user - parameters.payment - parameters.userBurn,
suggester: initialAllocations.suggester - parameters.suggesterBurn,
burner: initialAllocations.burner + parameters.payment + parameters.suggesterBurn + parameters.userBurn,
});

const toOutcome = outcomeBuilder.createEncodedOutcome({
user: initialAllocations.user - parameters.payment,
suggester: initialAllocations.suggester, // WRONG
burner: initialAllocations.burner,
});

const fromData = dataBuilder.createEncodedSEData({
phase: Phase.Suggest,
reaction: Reaction.None,
suggestion: suggestion,
});

const toData = dataBuilder.createEncodedSEData({
phase: Phase.React,
reaction: Reaction.Reward,
suggestion: '',
});

let validationTx = instance.validTransition(
{outcome: fromOutcome, appData: fromData},
{outcome: toOutcome, appData: toData},
4,
2,
);

await expectRevert(
validationTx,
"ScorchedEarth: Reward Reaction must pay",
);
});

it('should not accept a react phase that does not spend user funds', async () => {
const initialAllocations = {user: 100, suggester: 100, burner: 0};
const parameters = dataBuilder.parameters;

const fromOutcome = outcomeBuilder.createEncodedOutcome({
user: initialAllocations.user - parameters.payment - parameters.userBurn,
suggester: initialAllocations.suggester - parameters.suggesterBurn,
burner: initialAllocations.burner + parameters.payment + parameters.suggesterBurn + parameters.userBurn,
});

const toOutcome = outcomeBuilder.createEncodedOutcome({
user: initialAllocations.user, // WRONG
suggester: initialAllocations.suggester + parameters.payment,
burner: initialAllocations.burner,
});

const fromData = dataBuilder.createEncodedSEData({
phase: Phase.Suggest,
reaction: Reaction.None,
suggestion: suggestion,
});

const toData = dataBuilder.createEncodedSEData({
phase: Phase.React,
reaction: Reaction.Reward,
suggestion: '',
});

let validationTx = instance.validTransition(
{outcome: fromOutcome, appData: fromData},
{outcome: toOutcome, appData: toData},
4,
2,
);

await expectRevert(
validationTx,
"ScorchedEarth: Reward Reaction must pay",
);
});

it('should validate a react phase that correctly rewards the suggester', async () => {
const initialAllocations = {user: 100, suggester: 100, burner: 0};
const parameters = dataBuilder.parameters;

const fromOutcome = outcomeBuilder.createEncodedOutcome({
user: initialAllocations.user - parameters.payment - parameters.userBurn,
suggester: initialAllocations.suggester - parameters.suggesterBurn,
burner: initialAllocations.burner + parameters.payment + parameters.suggesterBurn + parameters.userBurn,
});

const toOutcome = outcomeBuilder.createEncodedOutcome({
user: initialAllocations.user - parameters.payment,
suggester: initialAllocations.suggester + parameters.payment,
burner: initialAllocations.burner,
});

const fromData = dataBuilder.createEncodedSEData({
phase: Phase.Suggest,
reaction: Reaction.None,
suggestion: suggestion,
});

const toData = dataBuilder.createEncodedSEData({
phase: Phase.React,
reaction: Reaction.Reward,
suggestion: '',
});

let isValid = await instance.validTransition(
{outcome: fromOutcome, appData: fromData},
{outcome: toOutcome, appData: toData},
4,
2,
);

expect(isValid).to.be.true;
});
});