Skip to content

Commit

Permalink
potential fix for front-runnable functions
Browse files Browse the repository at this point in the history
  • Loading branch information
yakuhito committed Aug 26, 2021
1 parent b717af4 commit 6e063fa
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 28 deletions.
40 changes: 29 additions & 11 deletions contracts/yakuSwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,57 +15,75 @@ contract yakuSwap is Ownable {
SwapStatus status;
uint startBlock;
uint amount;
bytes32 secretHash;
address fromAddress;
address toAddress;
uint16 maxBlockHeight;
}

mapping (bytes32 => Swap) public swaps; // key = secretHash
mapping (bytes32 => Swap) public swaps;
uint public totalFees = 0;

function getSwapId(bytes32 secretHash, address fromAddress) public pure returns (bytes32) {
return keccak256(abi.encodePacked(
secretHash,
fromAddress
));
}

function createSwap(bytes32 _secretHash, address _toAddress, uint16 _maxBlockHeight) payable public {
require(msg.value >= 1000);
require(_maxBlockHeight > 10);
require(swaps[_secretHash].status == SwapStatus.Uninitialized);
require(_toAddress != address(0) && msg.sender != address(0));

bytes32 swapId = getSwapId(_secretHash, msg.sender);
require(swaps[swapId].status == SwapStatus.Uninitialized);

uint swapAmount = msg.value / 1000 * 993;
Swap memory newSwap = Swap(
SwapStatus.Created,
block.number,
swapAmount,
_secretHash,
msg.sender,
_toAddress,
_maxBlockHeight
);

swaps[_secretHash] = newSwap;
swaps[swapId] = newSwap;
totalFees += msg.value - newSwap.amount;
}

function completeSwap(bytes32 _secretHash, string memory _secret) public {
Swap storage swap = swaps[_secretHash];
function completeSwap(bytes32 _swapId, string memory _secret) public {
Swap storage swap = swaps[_swapId];

require(swap.status == SwapStatus.Created);
require(block.number < swap.startBlock + swap.maxBlockHeight);
require(_secretHash == sha256(abi.encodePacked(_secret)));
require(swap.secretHash == sha256(abi.encodePacked(_secret)));

swap.status = SwapStatus.Completed;
payable(swap.toAddress).transfer(swap.amount);
if(!payable(swap.toAddress).send(swap.amount)) {
swap.status = SwapStatus.Created;
}
}

function cancelSwap(bytes32 _secretHash) public {
Swap storage swap = swaps[_secretHash];
function cancelSwap(bytes32 _swapId) public {
Swap storage swap = swaps[_swapId];

require(swap.status == SwapStatus.Created);
require(block.number >= swap.startBlock + swap.maxBlockHeight);

swap.status = SwapStatus.Cancelled;
payable(swap.fromAddress).transfer(swap.amount);
if(!payable(swap.fromAddress).send(swap.amount)) {
swap.status = SwapStatus.Created;
}
}

function getFees() public onlyOwner {
uint oldTotalFees = totalFees;
totalFees = 0;
payable(owner()).transfer(totalFees);
if(!payable(owner()).send(totalFees)) {
totalFees = oldTotalFees;
}
}
}
49 changes: 32 additions & 17 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ describe("yakuSwap Contract", function () {

await transaction.wait();

const swap = await yakuSwap.connect(addr3).swaps(SECRET_HASH);
const swapId = await yakuSwap.connect(addr3).getSwapId(SECRET_HASH, addr1.address);
const swap = await yakuSwap.connect(addr3).swaps(swapId);
const totalFees = await yakuSwap.connect(addr3).totalFees();
expect(swap.status).to.equal(1);
expect(swap.startBlock).to.equal(await ethers.provider.getBlockNumber());
expect(swap.amount).to.equal(SWAP_AMOUNT_AFTER_FEE);
expect(swap.secretHash).to.equal(SECRET_HASH);
expect(swap.fromAddress).to.equal(addr1.address);
expect(swap.toAddress).to.equal(addr2.address);
expect(swap.maxBlockHeight).to.equal(MAX_BLOCK_HEIGHT);
Expand All @@ -64,15 +66,15 @@ describe("yakuSwap Contract", function () {
).to.be.revertedWith("");
});

it("Should fail if the same secretHash is used twice", async function () {
it("Should fail if the same secretHash is used twice by the same address", async function () {
const transaction = await yakuSwap.connect(addr1).createSwap(SECRET_HASH, addr2.address, MAX_BLOCK_HEIGHT, {
value: SWAP_AMOUNT,
});

await transaction.wait();

await expect(
yakuSwap.connect(addr3).createSwap(SECRET_HASH, addrs[0].address, MAX_BLOCK_HEIGHT * 2, {
yakuSwap.connect(addr1).createSwap(SECRET_HASH, addrs[0].address, MAX_BLOCK_HEIGHT * 2, {
value: SWAP_AMOUNT.mul(2),
})
).to.be.revertedWith("");
Expand All @@ -88,33 +90,39 @@ describe("yakuSwap Contract", function () {
});

describe("completeSwap", function () {
let swapId;

beforeEach(async function () {
const transaction = await yakuSwap.connect(addr1).createSwap(SECRET_HASH, addr2.address, MAX_BLOCK_HEIGHT, {
value: SWAP_AMOUNT,
});

await transaction.wait();

swapId = await yakuSwap.connect(addr3).getSwapId(SECRET_HASH, addr1.address);
});


it("Should work if everyhting's ok", async function () {
const transaction = await yakuSwap.connect(addr3).completeSwap(SECRET_HASH, SECRET);
const transaction = await yakuSwap.connect(addr3).completeSwap(swapId, SECRET);

await transaction.wait();

const swap = await yakuSwap.connect(addr3).swaps(SECRET_HASH);
const swap = await yakuSwap.connect(addr3).swaps(swapId);
expect(swap.status).to.equal(2);
});

it("Should fail if secret is invalid", async function () {
await expect(
yakuSwap.connect(addr2).completeSwap(SECRET_HASH, WRONG_SECRET)
yakuSwap.connect(addr2).completeSwap(swapId, WRONG_SECRET)
).to.be.revertedWith("");
});

it("Should fail if secretHash is invalid", async function () {
const wrongSwapId = await yakuSwap.connect(addr3).getSwapId(WRONG_SECRET_HASH, addr1.address);

await expect(
yakuSwap.connect(addr2).completeSwap(WRONG_SECRET_HASH, WRONG_SECRET)
yakuSwap.connect(addr2).completeSwap(wrongSwapId, WRONG_SECRET)
).to.be.revertedWith("");
});

Expand All @@ -123,40 +131,44 @@ describe("yakuSwap Contract", function () {
await ethers.provider.send('evm_mine');
}
await expect(
yakuSwap.connect(addr2).completeSwap(SECRET_HASH, SECRET)
yakuSwap.connect(addr2).completeSwap(swapId, SECRET)
).to.be.revertedWith("");
});

it("Should fail if the swap was completed", async function () {
const transaction = await yakuSwap.connect(addr3).completeSwap(SECRET_HASH, SECRET);
const transaction = await yakuSwap.connect(addr3).completeSwap(swapId, SECRET);

await transaction.wait();

await expect(
yakuSwap.connect(addr2).completeSwap(SECRET_HASH, SECRET)
yakuSwap.connect(addr2).completeSwap(swapId, SECRET)
).to.be.revertedWith("");
});
});

describe("cancelSwap", function () {
let swapId;

beforeEach(async function () {
const transaction = await yakuSwap.connect(addr1).createSwap(SECRET_HASH, addr2.address, MAX_BLOCK_HEIGHT, {
value: SWAP_AMOUNT,
});

await transaction.wait();

swapId = await yakuSwap.connect(addr3).getSwapId(SECRET_HASH, addr1.address);
});

it("Should work if everyhting's ok", async function () {
for(var i = 0; i < MAX_BLOCK_HEIGHT; i++) {
await ethers.provider.send('evm_mine');
}

const transaction = await yakuSwap.connect(addr3).cancelSwap(SECRET_HASH);
const transaction = await yakuSwap.connect(addr3).cancelSwap(swapId);

await transaction.wait();

const swap = await yakuSwap.connect(addr3).swaps(SECRET_HASH);
const swap = await yakuSwap.connect(addr3).swaps(swapId);
expect(swap.status).to.equal(3);
});

Expand All @@ -165,19 +177,21 @@ describe("yakuSwap Contract", function () {
await ethers.provider.send('evm_mine');
}

const wrongSwapId = await yakuSwap.connect(addr3).getSwapId(WRONG_SECRET_HASH, addr1.address);

await expect(
yakuSwap.connect(addr1).cancelSwap(WRONG_SECRET_HASH)
yakuSwap.connect(addr1).cancelSwap(wrongSwapId)
).to.be.revertedWith("");
});

it("Should fail if maxBlockHeight hasn't been reached yet", async function () {
await expect(
yakuSwap.connect(addr1).cancelSwap(SECRET_HASH)
yakuSwap.connect(addr1).cancelSwap(swapId)
).to.be.revertedWith("");
});

it("Should fail if the swap has been completed before", async function () {
const transaction = await yakuSwap.connect(addr3).completeSwap(SECRET_HASH, SECRET);
const transaction = await yakuSwap.connect(addr3).completeSwap(swapId, SECRET);

await transaction.wait();

Expand All @@ -186,7 +200,7 @@ describe("yakuSwap Contract", function () {
}

await expect(
yakuSwap.connect(addr1).cancelSwap(SECRET_HASH)
yakuSwap.connect(addr1).cancelSwap(swapId)
).to.be.revertedWith("");
});
});
Expand All @@ -199,7 +213,8 @@ describe("yakuSwap Contract", function () {

await transaction.wait();

const transaction2 = await yakuSwap.connect(addr3).completeSwap(SECRET_HASH, SECRET);
const swapId = await yakuSwap.connect(addr3).getSwapId(SECRET_HASH, addr1.address);
const transaction2 = await yakuSwap.connect(addr3).completeSwap(swapId, SECRET);

await transaction2.wait();
});
Expand Down

0 comments on commit 6e063fa

Please sign in to comment.