diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..37ffb5a --- /dev/null +++ b/.prettierrc @@ -0,0 +1,16 @@ +{ + "overrides": [ + { + "files": "*.js", + "options": { + "semi": false + } + }, + { + "files": "*.sol", + "options": { + "tabWidth": 2 + } + } + ] +} diff --git a/contracts/Contracts.sol b/contracts/Contracts.sol index b24dbfa..e1ab652 100644 --- a/contracts/Contracts.sol +++ b/contracts/Contracts.sol @@ -4,21 +4,20 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; contract Contracts { + mapping(bytes32 => bool) private ids; // contract id, equal to hash of bid + mapping(bytes32 => uint256) private durations; // contract duration in blocks + mapping(bytes32 => uint256) private sizes; // storage size in bytes + mapping(bytes32 => bytes32) private contentHashes; // hash of data to be stored + mapping(bytes32 => uint256) private proofPeriods; // period between proofs + mapping(bytes32 => uint256) private proofTimeouts; // timeout for proof submission + mapping(bytes32 => uint256) private prices; // price in coins + mapping(bytes32 => address) private hosts; // host that provides storage - mapping(bytes32=>bool) private ids; // contract id, equal to hash of bid - mapping(bytes32=>uint) private durations; // contract duration in blocks - mapping(bytes32=>uint) private sizes; // storage size in bytes - mapping(bytes32=>bytes32) private contentHashes; // hash of data to be stored - mapping(bytes32=>uint) private proofPeriods; // period between proofs - mapping(bytes32=>uint) private proofTimeouts; // timeout for proof submission - mapping(bytes32=>uint) private prices; // price in coins - mapping(bytes32=>address) private hosts; // host that provides storage - - function _duration(bytes32 id) internal view returns (uint) { + function _duration(bytes32 id) internal view returns (uint256) { return durations[id]; } - function _size(bytes32 id) internal view returns (uint) { + function _size(bytes32 id) internal view returns (uint256) { return sizes[id]; } @@ -26,15 +25,15 @@ contract Contracts { return contentHashes[id]; } - function _proofPeriod(bytes32 id) internal view returns (uint) { + function _proofPeriod(bytes32 id) internal view returns (uint256) { return proofPeriods[id]; } - function _proofTimeout(bytes32 id) internal view returns (uint) { + function _proofTimeout(bytes32 id) internal view returns (uint256) { return proofTimeouts[id]; } - function _price(bytes32 id) internal view returns (uint) { + function _price(bytes32 id) internal view returns (uint256) { return prices[id]; } @@ -43,21 +42,18 @@ contract Contracts { } function _newContract( - uint duration, - uint size, + uint256 duration, + uint256 size, bytes32 contentHash, - uint proofPeriod, - uint proofTimeout, + uint256 proofPeriod, + uint256 proofTimeout, bytes32 nonce, - uint price, + uint256 price, address host, - uint bidExpiry, + uint256 bidExpiry, bytes memory requestSignature, bytes memory bidSignature - ) - internal - returns (bytes32 id) - { + ) internal returns (bytes32 id) { bytes32 requestHash = _hashRequest( duration, size, @@ -84,57 +80,52 @@ contract Contracts { // Creates hash for a storage request that can be used to check its signature. function _hashRequest( - uint duration, - uint size, + uint256 duration, + uint256 size, bytes32 hash, - uint proofPeriod, - uint proofTimeout, + uint256 proofPeriod, + uint256 proofTimeout, bytes32 nonce - ) - private pure - returns (bytes32) - { - return keccak256(abi.encode( - "[dagger.request.v1]", - duration, - size, - hash, - proofPeriod, - proofTimeout, - nonce - )); + ) private pure returns (bytes32) { + return + keccak256( + abi.encode( + "[dagger.request.v1]", + duration, + size, + hash, + proofPeriod, + proofTimeout, + nonce + ) + ); } // Creates hash for a storage bid that can be used to check its signature. - function _hashBid(bytes32 requestHash, uint expiry, uint price) - private pure - returns (bytes32) - { - return keccak256(abi.encode( - "[dagger.bid.v1]", - requestHash, - expiry, - price - )); + function _hashBid( + bytes32 requestHash, + uint256 expiry, + uint256 price + ) private pure returns (bytes32) { + return keccak256(abi.encode("[dagger.bid.v1]", requestHash, expiry, price)); } // Checks a signature for a storage request or bid, given its hash. - function _checkSignature(bytes memory signature, bytes32 hash, address signer) - private pure - { + function _checkSignature( + bytes memory signature, + bytes32 hash, + address signer + ) private pure { bytes32 messageHash = ECDSA.toEthSignedMessageHash(hash); address recovered = ECDSA.recover(messageHash, signature); require(recovered == signer, "Invalid signature"); } - function _checkBidExpiry(uint expiry) private view { + function _checkBidExpiry(uint256 expiry) private view { require(expiry > block.timestamp, "Bid expired"); } function _checkId(bytes32 id) private view { - require( - !ids[id], - "A contract with this id already exists" - ); + require(!ids[id], "A contract with this id already exists"); } } diff --git a/contracts/Proofs.sol b/contracts/Proofs.sol index 1315c05..623115f 100644 --- a/contracts/Proofs.sol +++ b/contracts/Proofs.sol @@ -2,45 +2,44 @@ pragma solidity ^0.8.0; contract Proofs { + mapping(bytes32 => bool) private ids; + mapping(bytes32 => uint256) private periods; + mapping(bytes32 => uint256) private timeouts; + mapping(bytes32 => uint256) private starts; + mapping(bytes32 => uint256) private ends; + mapping(bytes32 => uint256) private markers; + mapping(bytes32 => uint256) private missed; + mapping(bytes32 => mapping(uint256 => bool)) private received; + mapping(bytes32 => mapping(uint256 => bool)) private missing; - mapping(bytes32=>bool) private ids; - mapping(bytes32=>uint) private periods; - mapping(bytes32=>uint) private timeouts; - mapping(bytes32=>uint) private starts; - mapping(bytes32=>uint) private ends; - mapping(bytes32=>uint) private markers; - mapping(bytes32=>uint) private missed; - mapping(bytes32=>mapping(uint=>bool)) private received; - mapping(bytes32=>mapping(uint=>bool)) private missing; - - function _period(bytes32 id) internal view returns (uint) { + function _period(bytes32 id) internal view returns (uint256) { return periods[id]; } - function _timeout(bytes32 id) internal view returns (uint) { + function _timeout(bytes32 id) internal view returns (uint256) { return timeouts[id]; } - function _end(bytes32 id) internal view returns (uint) { + function _end(bytes32 id) internal view returns (uint256) { return ends[id]; } - function _missed(bytes32 id) internal view returns (uint) { + function _missed(bytes32 id) internal view returns (uint256) { return missed[id]; } // Checks that proof timeout is <= 128. Only the latest 256 blocks can be // checked in a smart contract, so that leaves a period of at least 128 blocks // after timeout for a validator to signal the absence of a proof. - function _checkTimeout(uint timeout) private pure { + function _checkTimeout(uint256 timeout) private pure { require(timeout <= 128, "Invalid proof timeout, needs to be <= 128"); } function _expectProofs( bytes32 id, - uint period, - uint timeout, - uint duration + uint256 period, + uint256 timeout, + uint256 duration ) internal { require(!ids[id], "Proof id already in use"); _checkTimeout(timeout); @@ -49,32 +48,28 @@ contract Proofs { timeouts[id] = timeout; starts[id] = block.number; ends[id] = block.number + duration + 2 * timeout; - markers[id] = uint(blockhash(block.number - 1)) % period; + markers[id] = uint256(blockhash(block.number - 1)) % period; } // Check whether a proof is required at the time of the block with the // specified block number. A proof has to be submitted within the proof // timeout for it to be valid. Whether a proof is required is determined // randomly, but on average it is once every proof period. - function _isProofRequired( - bytes32 id, - uint blocknumber - ) - internal view + function _isProofRequired(bytes32 id, uint256 blocknumber) + internal + view returns (bool) { if (blocknumber < starts[id] || blocknumber >= ends[id]) { return false; } bytes32 hash = blockhash(blocknumber - 1); - return hash != 0 && uint(hash) % periods[id] == markers[id]; + return hash != 0 && uint256(hash) % periods[id] == markers[id]; } - function _isProofTimedOut( - bytes32 id, - uint blocknumber - ) - internal view + function _isProofTimedOut(bytes32 id, uint256 blocknumber) + internal + view returns (bool) { return block.number >= blocknumber + timeouts[id]; @@ -82,11 +77,9 @@ contract Proofs { function _submitProof( bytes32 id, - uint blocknumber, + uint256 blocknumber, bool proof - ) - internal - { + ) internal { require(proof, "Invalid proof"); // TODO: replace bool by actual proof require( _isProofRequired(id, blocknumber), @@ -100,19 +93,10 @@ contract Proofs { received[id][blocknumber] = true; } - function _markProofAsMissing(bytes32 id, uint blocknumber) internal { - require( - _isProofTimedOut(id, blocknumber), - "Proof has not timed out yet" - ); - require( - !received[id][blocknumber], - "Proof was submitted, not missing" - ); - require( - _isProofRequired(id, blocknumber), - "Proof was not required" - ); + function _markProofAsMissing(bytes32 id, uint256 blocknumber) internal { + require(_isProofTimedOut(id, blocknumber), "Proof has not timed out yet"); + require(!received[id][blocknumber], "Proof was submitted, not missing"); + require(_isProofRequired(id, blocknumber), "Proof was not required"); require(!missing[id][blocknumber], "Proof already marked as missing"); missing[id][blocknumber] = true; missed[id] += 1; diff --git a/contracts/Stakes.sol b/contracts/Stakes.sol index 0b17b74..8cf9fad 100644 --- a/contracts/Stakes.sol +++ b/contracts/Stakes.sol @@ -4,10 +4,9 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract Stakes { - IERC20 private token; - mapping(address=>uint) private stakes; - mapping(address=>uint) private locks; + mapping(address => uint256) private stakes; + mapping(address => uint256) private locks; constructor(IERC20 __token) { token = __token; @@ -17,11 +16,11 @@ contract Stakes { return token; } - function _stake(address account) internal view returns (uint) { + function _stake(address account) internal view returns (uint256) { return stakes[account]; } - function _increaseStake(uint amount) internal { + function _increaseStake(uint256 amount) internal { token.transferFrom(msg.sender, address(this), amount); stakes[msg.sender] += amount; } @@ -40,7 +39,7 @@ contract Stakes { locks[account] -= 1; } - function _slash(address account, uint percentage) internal { - stakes[account] = stakes[account] * (100 - percentage) / 100; + function _slash(address account, uint256 percentage) internal { + stakes[account] = (stakes[account] * (100 - percentage)) / 100; } } diff --git a/contracts/Storage.sol b/contracts/Storage.sol index 9c8fcb1..1f33c29 100644 --- a/contracts/Storage.sol +++ b/contracts/Storage.sol @@ -6,41 +6,36 @@ import "./Proofs.sol"; import "./Stakes.sol"; contract Storage is Contracts, Proofs, Stakes { + uint256 public stakeAmount; + uint256 public slashMisses; + uint256 public slashPercentage; - uint public stakeAmount; - uint public slashMisses; - uint public slashPercentage; - - mapping(bytes32=>bool) private finished; + mapping(bytes32 => bool) private finished; constructor( IERC20 token, - uint _stakeAmount, - uint _slashMisses, - uint _slashPercentage - ) - Stakes(token) - { + uint256 _stakeAmount, + uint256 _slashMisses, + uint256 _slashPercentage + ) Stakes(token) { stakeAmount = _stakeAmount; slashMisses = _slashMisses; slashPercentage = _slashPercentage; } function newContract( - uint _duration, - uint _size, + uint256 _duration, + uint256 _size, bytes32 _contentHash, - uint _proofPeriod, - uint _proofTimeout, + uint256 _proofPeriod, + uint256 _proofTimeout, bytes32 _nonce, - uint _price, + uint256 _price, address _host, - uint _bidExpiry, + uint256 _bidExpiry, bytes memory requestSignature, bytes memory bidSignature - ) - public - { + ) public { require(_stake(_host) >= stakeAmount, "Insufficient stake"); _lockStake(_host); _token().transferFrom(msg.sender, address(this), _price); @@ -76,11 +71,11 @@ contract Storage is Contracts, Proofs, Stakes { finished[id] = true; } - function duration(bytes32 contractId) public view returns (uint) { + function duration(bytes32 contractId) public view returns (uint256) { return _duration(contractId); } - function size(bytes32 contractId) public view returns (uint) { + function size(bytes32 contractId) public view returns (uint256) { return _size(contractId); } @@ -88,7 +83,7 @@ contract Storage is Contracts, Proofs, Stakes { return _contentHash(contractId); } - function price(bytes32 contractId) public view returns (uint) { + function price(bytes32 contractId) public view returns (uint256) { return _price(contractId); } @@ -96,41 +91,37 @@ contract Storage is Contracts, Proofs, Stakes { return _host(contractId); } - function proofPeriod(bytes32 contractId) public view returns (uint) { + function proofPeriod(bytes32 contractId) public view returns (uint256) { return _proofPeriod(contractId); } - function proofTimeout(bytes32 contractId) public view returns (uint) { + function proofTimeout(bytes32 contractId) public view returns (uint256) { return _proofTimeout(contractId); } - function proofEnd(bytes32 contractId) public view returns (uint) { + function proofEnd(bytes32 contractId) public view returns (uint256) { return _end(contractId); } - function missingProofs(bytes32 contractId) public view returns (uint) { + function missingProofs(bytes32 contractId) public view returns (uint256) { return _missed(contractId); } - function stake(address account) public view returns (uint) { + function stake(address account) public view returns (uint256) { return _stake(account); } - function isProofRequired( - bytes32 contractId, - uint blocknumber - ) - public view + function isProofRequired(bytes32 contractId, uint256 blocknumber) + public + view returns (bool) { return _isProofRequired(contractId, blocknumber); } - function isProofTimedOut( - bytes32 contractId, - uint blocknumber - ) - public view + function isProofTimedOut(bytes32 contractId, uint256 blocknumber) + public + view returns (bool) { return _isProofTimedOut(contractId, blocknumber); @@ -138,22 +129,20 @@ contract Storage is Contracts, Proofs, Stakes { function submitProof( bytes32 contractId, - uint blocknumber, + uint256 blocknumber, bool proof - ) - public - { + ) public { _submitProof(contractId, blocknumber, proof); } - function markProofAsMissing(bytes32 contractId, uint blocknumber) public { + function markProofAsMissing(bytes32 contractId, uint256 blocknumber) public { _markProofAsMissing(contractId, blocknumber); if (_missed(contractId) % slashMisses == 0) { _slash(host(contractId), slashPercentage); } } - function increaseStake(uint amount) public { + function increaseStake(uint256 amount) public { _increaseStake(amount); } diff --git a/contracts/TestContracts.sol b/contracts/TestContracts.sol index b8a3c7c..88cfd2a 100644 --- a/contracts/TestContracts.sol +++ b/contracts/TestContracts.sol @@ -5,22 +5,19 @@ import "./Contracts.sol"; // exposes internal functions of Contracts for testing contract TestContracts is Contracts { - function newContract( - uint _duration, - uint _size, + uint256 _duration, + uint256 _size, bytes32 _contentHash, - uint _proofPeriod, - uint _proofTimeout, + uint256 _proofPeriod, + uint256 _proofTimeout, bytes32 _nonce, - uint _price, + uint256 _price, address _host, - uint _bidExpiry, + uint256 _bidExpiry, bytes memory requestSignature, bytes memory bidSignature - ) - public - { + ) public { _newContract( _duration, _size, @@ -32,14 +29,15 @@ contract TestContracts is Contracts { _host, _bidExpiry, requestSignature, - bidSignature); + bidSignature + ); } - function duration(bytes32 id) public view returns (uint) { + function duration(bytes32 id) public view returns (uint256) { return _duration(id); } - function size(bytes32 id) public view returns (uint) { + function size(bytes32 id) public view returns (uint256) { return _size(id); } @@ -47,7 +45,7 @@ contract TestContracts is Contracts { return _contentHash(id); } - function price(bytes32 id) public view returns (uint) { + function price(bytes32 id) public view returns (uint256) { return _price(id); } diff --git a/contracts/TestProofs.sol b/contracts/TestProofs.sol index 125b057..e477e20 100644 --- a/contracts/TestProofs.sol +++ b/contracts/TestProofs.sol @@ -5,37 +5,34 @@ import "./Proofs.sol"; // exposes internal functions of Proofs for testing contract TestProofs is Proofs { - - function period(bytes32 id) public view returns (uint) { + function period(bytes32 id) public view returns (uint256) { return _period(id); } - function timeout(bytes32 id) public view returns (uint) { + function timeout(bytes32 id) public view returns (uint256) { return _timeout(id); } - function end(bytes32 id) public view returns (uint) { + function end(bytes32 id) public view returns (uint256) { return _end(id); } - function missed(bytes32 id) public view returns (uint) { + function missed(bytes32 id) public view returns (uint256) { return _missed(id); } function expectProofs( bytes32 id, - uint _period, - uint _timeout, - uint _duration + uint256 _period, + uint256 _timeout, + uint256 _duration ) public { _expectProofs(id, _period, _timeout, _duration); } - function isProofRequired( - bytes32 id, - uint blocknumber - ) - public view + function isProofRequired(bytes32 id, uint256 blocknumber) + public + view returns (bool) { return _isProofRequired(id, blocknumber); @@ -43,15 +40,13 @@ contract TestProofs is Proofs { function submitProof( bytes32 id, - uint blocknumber, + uint256 blocknumber, bool proof - ) - public - { + ) public { _submitProof(id, blocknumber, proof); } - function markProofAsMissing(bytes32 id, uint blocknumber) public { - _markProofAsMissing(id, blocknumber); + function markProofAsMissing(bytes32 id, uint256 blocknumber) public { + _markProofAsMissing(id, blocknumber); } } diff --git a/contracts/TestStakes.sol b/contracts/TestStakes.sol index 19e4abb..1993952 100644 --- a/contracts/TestStakes.sol +++ b/contracts/TestStakes.sol @@ -5,14 +5,13 @@ import "./Stakes.sol"; // exposes internal functions of Stakes for testing contract TestStakes is Stakes { - constructor(IERC20 token) Stakes(token) {} - function stake(address account) public view returns (uint) { + function stake(address account) public view returns (uint256) { return _stake(account); } - function increaseStake(uint amount) public { + function increaseStake(uint256 amount) public { _increaseStake(amount); } @@ -28,7 +27,7 @@ contract TestStakes is Stakes { _unlockStake(account); } - function slash(address account, uint percentage) public { + function slash(address account, uint256 percentage) public { _slash(account, percentage); } } diff --git a/contracts/TestToken.sol b/contracts/TestToken.sol index b36fc78..863d9f2 100644 --- a/contracts/TestToken.sol +++ b/contracts/TestToken.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract TestToken is ERC20 { constructor() ERC20("TestToken", "TST") {} - function mint(address holder, uint amount) public { + function mint(address holder, uint256 amount) public { _mint(holder, amount); } } diff --git a/deploy/storage.js b/deploy/storage.js index 45febe0..e7d0785 100644 --- a/deploy/storage.js +++ b/deploy/storage.js @@ -1,12 +1,12 @@ -module.exports = async ({deployments, getNamedAccounts}) => { - const token = await deployments.get('TestToken') +module.exports = async ({ deployments, getNamedAccounts }) => { + const token = await deployments.get("TestToken") const stakeAmount = 100 const slashMisses = 3 const slashPercentage = 10 const args = [token.address, stakeAmount, slashMisses, slashPercentage] const { deployer } = await getNamedAccounts() - await deployments.deploy('Storage', { args, from: deployer }) + await deployments.deploy("Storage", { args, from: deployer }) } -module.exports.tags = ['Storage'] -module.exports.dependencies = ['TestToken'] +module.exports.tags = ["Storage"] +module.exports.dependencies = ["TestToken"] diff --git a/deploy/token.js b/deploy/token.js index 76b271c..c977fef 100644 --- a/deploy/token.js +++ b/deploy/token.js @@ -1,6 +1,6 @@ -module.exports = async ({deployments, getNamedAccounts}) => { +module.exports = async ({ deployments, getNamedAccounts }) => { const { deployer } = await getNamedAccounts() - await deployments.deploy('TestToken', { from: deployer }) + await deployments.deploy("TestToken", { from: deployer }) } -module.exports.tags = ['TestToken'] +module.exports.tags = ["TestToken"] diff --git a/package-lock.json b/package-lock.json index 11d48dd..641e622 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1338,6 +1338,12 @@ "color-convert": "^1.9.0" } }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -12982,11 +12988,112 @@ "dev": true }, "prettier": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", - "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "dev": true }, + "prettier-plugin-solidity": { + "version": "1.0.0-beta.19", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz", + "integrity": "sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.14.0", + "emoji-regex": "^10.0.0", + "escape-string-regexp": "^4.0.0", + "semver": "^7.3.5", + "solidity-comments-extractor": "^0.0.7", + "string-width": "^4.2.3" + }, + "dependencies": { + "@solidity-parser/parser": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.0.tgz", + "integrity": "sha512-cX0JJRcmPtNUJpzD2K7FdA7qQsTOk1UZnFx2k7qAg9ZRvuaH5NBe5IEdBMXGlmf2+FmjhqbygJ26H8l2SV7aKQ==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.0.0.tgz", + "integrity": "sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, "printj": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", @@ -13360,6 +13467,12 @@ } } }, + "solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index 3b2c4a8..40dbad5 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "license": "MIT", "scripts": { "test": "hardhat test", - "start": "hardhat node --export 'deployment-localhost.json'" + "start": "hardhat node --export 'deployment-localhost.json'", + "format": "prettier --write contracts/**/*.sol test/**/*.js" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.0.2", @@ -14,6 +15,8 @@ "ethers": "^5.4.7", "hardhat": "^2.6.5", "hardhat-deploy": "^0.9.8", - "hardhat-deploy-ethers": "^0.3.0-beta.11" + "hardhat-deploy-ethers": "^0.3.0-beta.11", + "prettier": "^2.5.1", + "prettier-plugin-solidity": "^1.0.0-beta.19" } } diff --git a/test/Contracts.test.js b/test/Contracts.test.js index 296bf03..ccbc647 100644 --- a/test/Contracts.test.js +++ b/test/Contracts.test.js @@ -4,7 +4,6 @@ const { hashRequest, hashBid, sign } = require("./marketplace") const { exampleRequest, exampleBid } = require("./examples") describe("Contracts", function () { - const request = exampleRequest() const bid = exampleBid() @@ -14,11 +13,11 @@ describe("Contracts", function () { let id beforeEach(async function () { - [client, host] = await ethers.getSigners() + ;[client, host] = await ethers.getSigners() let Contracts = await ethers.getContractFactory("TestContracts") contracts = await Contracts.deploy() requestHash = hashRequest(request) - bidHash = hashBid({...bid, requestHash}) + bidHash = hashBid({ ...bid, requestHash }) id = bidHash }) @@ -57,72 +56,83 @@ describe("Contracts", function () { await sign(client, requestHash), await sign(host, bidHash) ) - await expect(contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - await sign(host, bidHash) - )).to.be.revertedWith("A contract with this id already exists") + await expect( + contracts.newContract( + request.duration, + request.size, + request.contentHash, + request.proofPeriod, + request.proofTimeout, + request.nonce, + bid.price, + await host.getAddress(), + bid.bidExpiry, + await sign(client, requestHash), + await sign(host, bidHash) + ) + ).to.be.revertedWith("A contract with this id already exists") }) it("cannot be created when client signature is invalid", async function () { - let invalidHash = hashRequest({...request, duration: request.duration + 1}) + let invalidHash = hashRequest({ + ...request, + duration: request.duration + 1, + }) let invalidSignature = await sign(client, invalidHash) - await expect(contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - invalidSignature, - await sign(host, bidHash) - )).to.be.revertedWith("Invalid signature") + await expect( + contracts.newContract( + request.duration, + request.size, + request.contentHash, + request.proofPeriod, + request.proofTimeout, + request.nonce, + bid.price, + await host.getAddress(), + bid.bidExpiry, + invalidSignature, + await sign(host, bidHash) + ) + ).to.be.revertedWith("Invalid signature") }) it("cannot be created when host signature is invalid", async function () { - let invalidBid = hashBid({...bid, requestHash, price: bid.price - 1}) + let invalidBid = hashBid({ ...bid, requestHash, price: bid.price - 1 }) let invalidSignature = await sign(host, invalidBid) - await expect(contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - bid.bidExpiry, - await sign(client, requestHash), - invalidSignature - )).to.be.revertedWith("Invalid signature") + await expect( + contracts.newContract( + request.duration, + request.size, + request.contentHash, + request.proofPeriod, + request.proofTimeout, + request.nonce, + bid.price, + await host.getAddress(), + bid.bidExpiry, + await sign(client, requestHash), + invalidSignature + ) + ).to.be.revertedWith("Invalid signature") }) it("cannot be created when bid has expired", async function () { let expired = Math.round(Date.now() / 1000) - 60 // 1 minute ago - let bidHash = hashBid({...bid, requestHash, bidExpiry: expired}) - await expect(contracts.newContract( - request.duration, - request.size, - request.contentHash, - request.proofPeriod, - request.proofTimeout, - request.nonce, - bid.price, - await host.getAddress(), - expired, - await sign(client, requestHash), - await sign(host, bidHash), - )).to.be.revertedWith("Bid expired") + let bidHash = hashBid({ ...bid, requestHash, bidExpiry: expired }) + await expect( + contracts.newContract( + request.duration, + request.size, + request.contentHash, + request.proofPeriod, + request.proofTimeout, + request.nonce, + bid.price, + await host.getAddress(), + expired, + await sign(client, requestHash), + await sign(host, bidHash) + ) + ).to.be.revertedWith("Bid expired") }) }) diff --git a/test/Proofs.test.js b/test/Proofs.test.js index 1e21f52..a4e0951 100644 --- a/test/Proofs.test.js +++ b/test/Proofs.test.js @@ -1,9 +1,8 @@ const { expect } = require("chai") const { ethers } = require("hardhat") -const { mineBlock, minedBlockNumber } = require ("./mining") +const { mineBlock, minedBlockNumber } = require("./mining") describe("Proofs", function () { - const id = ethers.utils.randomBytes(32) const period = 10 const timeout = 5 @@ -16,20 +15,20 @@ describe("Proofs", function () { proofs = await Proofs.deploy() }) - it("indicates that proofs are required", async function() { + it("indicates that proofs are required", async function () { await proofs.expectProofs(id, period, timeout, duration) expect(await proofs.period(id)).to.equal(period) expect(await proofs.timeout(id)).to.equal(timeout) }) - it("calculates an endtime based on duration and timeout", async function() { + it("calculates an endtime based on duration and timeout", async function () { await proofs.expectProofs(id, period, timeout, duration) let start = await minedBlockNumber() let end = start + duration + 2 * timeout expect(await proofs.end(id)).to.equal(end) }) - it("does not allow ids to be reused", async function() { + it("does not allow ids to be reused", async function () { await proofs.expectProofs(id, period, timeout, duration) await expect( proofs.expectProofs(id, period, timeout, duration) @@ -47,7 +46,7 @@ describe("Proofs", function () { let blocks = 600 let amount = 0 await proofs.expectProofs(id, period, timeout, blocks) - for (let i=0; i ({ contentHash: ethers.utils.sha256("0xdeadbeef"), proofPeriod: 8, // 8 blocks ≈ 2 minutes proofTimeout: 4, // 4 blocks ≈ 1 minute - nonce: ethers.utils.randomBytes(32) + nonce: ethers.utils.randomBytes(32), }) const exampleBid = () => ({ price: 42, - bidExpiry: Math.round(Date.now() / 1000) + 60 * 60 // 1 hour from now + bidExpiry: Math.round(Date.now() / 1000) + 60 * 60, // 1 hour from now }) module.exports = { exampleRequest, exampleBid } diff --git a/test/marketplace.js b/test/marketplace.js index fc89306..7b9e930 100644 --- a/test/marketplace.js +++ b/test/marketplace.js @@ -1,21 +1,30 @@ const { ethers } = require("hardhat") function hashRequest({ - duration, size, contentHash, proofPeriod, proofTimeout, nonce + duration, + size, + contentHash, + proofPeriod, + proofTimeout, + nonce, }) { const type = "[dagger.request.v1]" - return ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode( - ["string", "uint", "uint", "bytes32", "uint", "uint", "bytes32"], - [type, duration, size, contentHash, proofPeriod, proofTimeout, nonce] - )) + return ethers.utils.keccak256( + ethers.utils.defaultAbiCoder.encode( + ["string", "uint", "uint", "bytes32", "uint", "uint", "bytes32"], + [type, duration, size, contentHash, proofPeriod, proofTimeout, nonce] + ) + ) } -function hashBid({requestHash, bidExpiry, price}) { +function hashBid({ requestHash, bidExpiry, price }) { const type = "[dagger.bid.v1]" - return ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode( - ["string", "bytes32", "uint", "uint"], - [type, requestHash, bidExpiry, price] - )) + return ethers.utils.keccak256( + ethers.utils.defaultAbiCoder.encode( + ["string", "bytes32", "uint", "uint"], + [type, requestHash, bidExpiry, price] + ) + ) } async function sign(signer, hash) {