poa-bridge/truffle/test/foreign.js

506 lines
24 KiB
JavaScript

var ForeignBridge = artifacts.require("ForeignBridge");
var helpers = require("./helpers/helpers");
contract('ForeignBridge', function(accounts) {
it("should deploy contract", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.requiredSignatures.call();
}).then(function(result) {
assert.equal(requiredSignatures, result, "Contract has invalid number of requiredSignatures");
return Promise.all(authorities.map((_, index) => meta.authorities.call(index)));
}).then(function(result) {
assert.deepEqual(authorities, result, "Contract has invalid authorities");
})
})
it("should fail to deploy contract with not enough required signatures", function() {
var authorities = [accounts[0], accounts[1]];
return ForeignBridge.new(0, authorities, 0)
.then(function() {
assert(false, "Contract should fail to deploy");
}, helpers.ignoreExpectedError)
})
it("should fail to deploy contract with to many signatures", function() {
var authorities = [accounts[0], accounts[1]];
return ForeignBridge.new(3, authorities, 0)
.then(function() {
assert(false, "Contract should fail to deploy");
}, helpers.ignoreExpectedError)
})
it("should allow a single authority to confirm a deposit", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var value = web3.toWei(1, "ether");
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, value, hash, { from: authorities[0] });
}).then(function(result) {
assert.equal(2, result.logs.length)
assert.equal("Transfer", result.logs[0].event);
assert.equal("0x0000000000000000000000000000000000000000", result.logs[0].args.from);
assert.equal(userAccount, result.logs[0].args.to);
assert.equal(value, result.logs[0].args.tokens);
assert.equal("Deposit", result.logs[1].event);
assert.equal(userAccount, result.logs[1].args.recipient);
assert.equal(value, result.logs[1].args.value);
return meta.balances.call(userAccount);
}).then(function(result) {
assert.equal(value, result, "Contract balance should change");
})
})
it("should require 2 authorities to confirm deposit", function() {
var meta;
var requiredSignatures = 2;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var value = web3.toWei(1, "ether");
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, value, hash, { from: authorities[0] });
}).then(function(result) {
assert.equal(0, result.logs.length, "No event should be created");
return meta.balances.call(userAccount);
}).then(function(result) {
assert.equal(web3.toWei(0, "ether"), result, "Contract balance should not change yet");
return meta.deposit(userAccount, value, hash, { from: authorities[1] });
}).then(function(result) {
assert.equal(2, result.logs.length)
assert.equal("Transfer", result.logs[0].event);
assert.equal("0x0000000000000000000000000000000000000000", result.logs[0].args.from);
assert.equal(userAccount, result.logs[0].args.to);
assert.equal(value, result.logs[0].args.tokens);
assert.equal("Deposit", result.logs[1].event, "Event name should be Deposit");
assert.equal(userAccount, result.logs[1].args.recipient, "Event recipient should be transaction sender");
assert.equal(value, result.logs[1].args.value, "Event value should match deposited ether");
return meta.balances.call(userAccount);
}).then(function(result) {
assert.equal(value, result, "Contract balance should change");
})
})
it("should not be possible to do same deposit twice for same authority", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var value = web3.toWei(1, "ether");
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, value, hash, { from: authorities[0] });
}).then(function(_) {
return meta.deposit(userAccount, value, hash, { from: authorities[0] })
.then(function() {
assert(false, "doing same deposit twice from same authority should fail");
}, helpers.ignoreExpectedError)
})
})
it("should not allow non-authorities to execute deposit", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var value = web3.toWei(1, "ether");
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, value, hash, { from: userAccount })
.then(function() {
assert(false, "should fail");
}, helpers.ignoreExpectedError)
})
})
it("should ignore misbehaving authority when confirming deposit", function() {
var meta;
var requiredSignatures = 2;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1], accounts[2]];
var userAccount = accounts[3];
var invalidValue = web3.toWei(2, "ether");
var value = web3.toWei(1, "ether");
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, value, hash, { from: authorities[0] });
}).then(function(result) {
assert.equal(0, result.logs.length, "No event should be created yet");
return meta.deposit(userAccount, invalidValue, hash, { from: authorities[1] });
}).then(function(result) {
assert.equal(0, result.logs.length, "Misbehaving authority should be ignored");
return meta.deposit(userAccount, value, hash, { from: authorities[2] })
}).then(function(result) {
assert.equal(2, result.logs.length)
assert.equal("Transfer", result.logs[0].event);
assert.equal("0x0000000000000000000000000000000000000000", result.logs[0].args.from);
assert.equal(userAccount, result.logs[0].args.to);
assert.equal(value, result.logs[0].args.tokens);
assert.equal("Deposit", result.logs[1].event, "Event name should be Deposit");
assert.equal(userAccount, result.logs[1].args.recipient, "Event recipient should be transaction sender");
assert.equal(value, result.logs[1].args.value, "Event value should match transaction value");
return meta.balances.call(userAccount);
}).then(function(result) {
assert.equal(value, result, "Contract balance should change");
})
})
it("should not allow user to transfer value they don't have to home", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var homeGasPrice = web3.toBigNumber(10000);
var recipientAccount = accounts[3];
var userValue = web3.toWei(3, "ether");
var transferedValue = web3.toWei(4, "ether");
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, userValue, hash, { from: authorities[0] });
}).then(function(result) {
return meta.transferHomeViaRelay(recipientAccount, transferedValue, homeGasPrice, { from: userAccount })
.then(function() {
assert(false, "transferHomeViaRelay should fail");
}, helpers.ignoreExpectedError)
})
})
it("should fail to transfer 0 value to home", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var homeGasPrice = web3.toBigNumber(10000);
var recipientAccount = accounts[3];
var userValue = web3.toWei(3, "ether");
var transferedValue = web3.toWei(0, "ether");
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, userValue, hash, { from: authorities[0] });
}).then(function(result) {
return meta.transferHomeViaRelay(recipientAccount, transferedValue, homeGasPrice, { from: userAccount })
.then(function() {
assert(false, "transferHomeViaRelay should fail");
}, helpers.ignoreExpectedError)
})
})
it("should fail to transfer more than balance home", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var homeGasPrice = web3.toBigNumber(10000);
var recipientAccount = accounts[3];
var userValue = web3.toWei(3, "ether");
var transferedValue = web3.toWei(4, "ether");
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, userValue, hash, { from: authorities[0] });
}).then(function(result) {
return meta.transferHomeViaRelay(recipientAccount, transferedValue, homeGasPrice, { from: userAccount })
.then(function() {
assert(false, "transferHomeViaRelay should fail");
}, helpers.ignoreExpectedError)
})
})
it("should fail to transfer home with value that gets entirely burned on gas", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = web3.toBigNumber(10000);
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var homeGasPrice = web3.toBigNumber(10000);
var recipientAccount = accounts[3];
var userValue = web3.toWei(3, "ether");
var transferedValue = estimatedGasCostOfWithdraw.times(homeGasPrice);
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return meta.deposit(userAccount, userValue, hash, { from: authorities[0] });
}).then(function(result) {
return meta.transferHomeViaRelay(recipientAccount, transferedValue, homeGasPrice, { from: userAccount })
.then(function() {
assert(false, "transferHomeViaRelay should fail");
}, helpers.ignoreExpectedError)
})
})
it("should allow user to transfer home", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = web3.toBigNumber(10000);
var authorities = [accounts[0], accounts[1]];
var userAccount = accounts[2];
var userAccount2 = accounts[3];
var value = web3.toWei(3, "ether");
var homeGasPrice = web3.toBigNumber(web3.toWei(3, "gwei"));
var transferedValue = estimatedGasCostOfWithdraw.times(homeGasPrice).plus(1);
var hash = "0xe55bb43c36cdf79e23b4adc149cdded921f0d482e613c50c6540977c213bc408";
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
// top up balance so we can transfer
return meta.deposit(userAccount, value, hash, { from: authorities[0] });
}).then(function(result) {
return meta.transferHomeViaRelay(userAccount2, transferedValue, homeGasPrice, { from: userAccount });
}).then(function(result) {
assert.equal(2, result.logs.length)
assert.equal("Transfer", result.logs[0].event);
assert.equal(userAccount, result.logs[0].args.from);
assert.equal("0x0000000000000000000000000000000000000000", result.logs[0].args.to);
assert(transferedValue.equals(result.logs[0].args.tokens));
assert.equal("Withdraw", result.logs[1].event, "Event name should be Withdraw");
assert.equal(userAccount2, result.logs[1].args.recipient, "Event recipient should be equal to transaction recipient");
assert(transferedValue.equals(result.logs[1].args.value));
assert(homeGasPrice.equals(result.logs[1].args.homeGasPrice));
return Promise.all([
meta.balances.call(userAccount),
meta.balances.call(userAccount2)
])
}).then(function(result) {
assert(web3.toBigNumber(value).minus(transferedValue).equals(result[0]));
assert(web3.toBigNumber(web3.toWei(0, "ether")).equals(result[1]));
})
})
it("should successfully submit signature and trigger CollectedSignatures event", function() {
var meta;
var signature;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var recipientAccount = accounts[2];
var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
var homeGasPrice = web3.toBigNumber(web3.toWei(3, "gwei"));
var message = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice);
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return helpers.sign(authorities[0], message);
}).then(function(result) {
signature = result;
return meta.submitSignature(result, message, { from: authorities[0] });
}).then(function(result) {
assert.equal(1, result.logs.length, "Exactly one event should be created");
assert.equal("CollectedSignatures", result.logs[0].event, "Event name should be CollectedSignatures");
assert.equal(authorities[0], result.logs[0].args.authorityResponsibleForRelay, "Event authority should be equal to transaction sender");
return Promise.all([
meta.signature.call(result.logs[0].args.messageHash, 0),
meta.message(result.logs[0].args.messageHash),
])
}).then(function(result) {
assert.equal(signature, result[0]);
assert.equal(message, result[1]);
})
})
it("should successfully submit signature but not trigger CollectedSignatures event", function() {
var meta;
var requiredSignatures = 2;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var recipientAccount = accounts[2];
var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
var homeGasPrice = web3.toBigNumber(web3.toWei(3, "gwei"));
var message = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice);
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return helpers.sign(authorities[0], message);
}).then(function(result) {
return meta.submitSignature(result, message, { from: authorities[0] });
}).then(function(result) {
assert.equal(0, result.logs.length, "No events should be created");
})
})
it("should be able to collect signatures for multiple events in parallel", function() {
var meta;
var signatures_for_message = [];
var signatures_for_message2 = [];
var requiredSignatures = 2;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var recipientAccount = accounts[2];
var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
var homeGasPrice = web3.toBigNumber(web3.toWei(3, "gwei"));
var message = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice);
var message2 = helpers.createMessage(recipientAccount, web3.toBigNumber(2000), transactionHash, homeGasPrice);
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return Promise.all([
helpers.sign(authorities[0], message),
helpers.sign(authorities[1], message),
helpers.sign(authorities[0], message2),
helpers.sign(authorities[1], message2),
]);
}).then(function(result) {
signatures_for_message.push(result[0]);
signatures_for_message.push(result[1]);
signatures_for_message2.push(result[2]);
signatures_for_message2.push(result[3]);
return meta.submitSignature(signatures_for_message[0], message, { from: authorities[0] });
}).then(function(result) {
assert.equal(0, result.logs.length, "No events should be created");
return meta.submitSignature(signatures_for_message2[1], message2, { from: authorities[1] });
}).then(function(result) {
assert.equal(0, result.logs.length, "No events should be created");
return meta.submitSignature(signatures_for_message2[0], message2, { from: authorities[0] });
}).then(function(result) {
assert.equal(1, result.logs.length, "Exactly one event should be created");
assert.equal("CollectedSignatures", result.logs[0].event, "Event name should be CollectedSignatures");
assert.equal(authorities[0], result.logs[0].args.authorityResponsibleForRelay, "Event authority should be equal to transaction sender");
return Promise.all([
meta.signature.call(result.logs[0].args.messageHash, 0),
meta.signature.call(result.logs[0].args.messageHash, 1),
meta.message(result.logs[0].args.messageHash),
])
}).then(function(result) {
assert.equal(signatures_for_message2[1], result[0]);
assert.equal(signatures_for_message2[0], result[1]);
assert.equal(message2, result[2]);
return meta.submitSignature(signatures_for_message[1], message, { from: authorities[1] });
}).then(function(result) {
assert.equal(1, result.logs.length, "Exactly one event should be created");
assert.equal("CollectedSignatures", result.logs[0].event, "Event name should be CollectedSignatures");
assert.equal(authorities[1], result.logs[0].args.authorityResponsibleForRelay, "Event authority should be equal to transaction sender");
return Promise.all([
meta.signature.call(result.logs[0].args.messageHash, 0),
meta.signature.call(result.logs[0].args.messageHash, 1),
meta.message(result.logs[0].args.messageHash),
])
}).then(function(result) {
assert.equal(signatures_for_message[0], result[0]);
assert.equal(signatures_for_message[1], result[1]);
assert.equal(message, result[2]);
})
})
it("should not be possible to submit message that is too short", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var recipientAccount = accounts[2];
var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
var homeGasPrice = web3.toBigNumber(web3.toWei(3, "gwei"));
var message = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice);
var truncatedMessage = message.substr(0, 84);
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return helpers.sign(authorities[0], truncatedMessage);
}).then(function(signature) {
return meta.submitSignature(signature, truncatedMessage, { from: authorities[0] })
.then(function() {
assert(false, "submitSignature should fail for message that is too short");
}, helpers.ignoreExpectedError)
})
})
it("should not be possible to submit different message then the signed one", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var recipientAccount = accounts[2];
var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
var homeGasPrice = web3.toBigNumber(web3.toWei(3, "gwei"));
var homeGasPrice2 = web3.toBigNumber(web3.toWei(2, "gwei"));
var message = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice);
var message2 = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice2);
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return helpers.sign(authorities[0], message);
}).then(function(result) {
return meta.submitSignature(result, message2, { from: authorities[0] })
.then(function() {
assert(false, "submitSignature should fail");
}, helpers.ignoreExpectedError)
})
})
it("should not be possible to submit signature signed by different authority", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var recipientAccount = accounts[2];
var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
var homeGasPrice = web3.toBigNumber(web3.toWei(3, "gwei"));
var homeGasPrice2 = web3.toBigNumber(web3.toWei(2, "gwei"));
var message = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice);
var message2 = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice2);
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return helpers.sign(authorities[0], message);
}).then(function(result) {
return meta.submitSignature(result, message, { from: authorities[1] })
.then(function() {
assert(false, "submitSignature should fail");
}, helpers.ignoreExpectedError)
})
})
it("should not be possible to submit signature twice", function() {
var meta;
var requiredSignatures = 1;
var estimatedGasCostOfWithdraw = 0;
var authorities = [accounts[0], accounts[1]];
var recipientAccount = accounts[2];
var transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
var homeGasPrice = web3.toBigNumber(web3.toWei(3, "gwei"));
var message = helpers.createMessage(recipientAccount, web3.toBigNumber(1000), transactionHash, homeGasPrice);
var signature;
return ForeignBridge.new(requiredSignatures, authorities, estimatedGasCostOfWithdraw).then(function(instance) {
meta = instance;
return helpers.sign(authorities[0], message);
}).then(function(result) {
signature = result;
return meta.submitSignature(signature, message, { from: authorities[0] });
}).then(function(_) {
return meta.submitSignature(signature, message, { from: authorities[0] })
.then(function() {
assert(false, "submitSignature should fail");
}, helpers.ignoreExpectedError)
})
})
})