Skip to content

Instantly share code, notes, and snippets.

@diminator
Created April 25, 2020 12:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save diminator/e442ebe84a79c2d88eb9e725b299c09c to your computer and use it in GitHub Desktop.
Save diminator/e442ebe84a79c2d88eb9e725b299c09c to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.6.6+commit.6c089d02.js&optimize=false&gist=
pragma solidity ^0.6.6;
contract HegicReproduceBug {
Option[] public options;
enum State { Active, Exercised, Expired }
struct Option {
State state;
uint expiration;
}
// depending on ETH or ERC20, there's a different `create` function
// and its matching `exercise` (omitted here since it's not important)
function create() public returns (uint optionID) {
optionID = options.length;
options.push(Option ({
state: State.Active,
expiration: now // for simplicity let's assume it instantly expires
}));
}
function unlock(uint[] memory optionIDs) public {
// why would you write this function in such confusing way,
// to save 1 line of code?
for(uint i; i < options.length; unlock(optionIDs[i++])){}
}
function unlock(uint optionID) internal {
Option storage option = options[optionID];
require(option.expiration < now, "Option has not expired yet");
require(option.state == State.Active, "Option is not active");
option.state = State.Expired;
// unlock the option (give money back to users)
}
function generateOptionIDs(uint maxId) public pure returns (uint[] memory) {
uint[] memory optionIDs = new uint[](maxId + 1);
for (uint i = 0; i < optionIDs.length; i++) {
optionIDs[i] = i;
}
return optionIDs;
}
}
pragma solidity >=0.4.0 <0.7.0;
import "remix_tests.sol"; // this import is automatically injected by Remix.
import "gists/a55da6926711885eae74b5e0276f1057/Hegic.sol";
contract HegicTest {
HegicReproduceBug hegicInstance;
uint lastOptionID;
function beforeAll() public {
hegicInstance = new HegicReproduceBug();
}
function testCreateOne() public {
lastOptionID = hegicInstance.create();
Assert.equal(lastOptionID, 0, "should start from zero");
HegicReproduceBug.State state;
uint expiration;
(state, expiration) = hegicInstance.options(lastOptionID);
Assert.equal(uint(state), uint(HegicReproduceBug.State.Active), "should be Active");
Assert.equal(expiration, now, "should happen now");
}
function testCreateMore() public {
uint amount = 2;
for (uint i; i < amount; i++) {
HegicReproduceBug.State state;
uint expiration;
lastOptionID = hegicInstance.create();
Assert.equal(lastOptionID, i + 1, "ID doesnt match");
(state, expiration) = hegicInstance.options(lastOptionID);
Assert.equal(uint(state), uint(HegicReproduceBug.State.Active), "should be Active");
Assert.equal(expiration, now, "should happen now");
}
}
function testUnlockPartial() public {
uint[] memory optionIDs = hegicInstance.generateOptionIDs(lastOptionID - 1);
Assert.equal(optionIDs.length, lastOptionID + 1, "length doesnt match");
hegicInstance.unlock(optionIDs);
}
function testUnlockAll() public {
uint[] memory optionIDs = hegicInstance.generateOptionIDs(lastOptionID);
Assert.equal(optionIDs.length, lastOptionID + 1, "length doesnt match");
hegicInstance.unlock(optionIDs);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment