crytic / building-secure-contracts

Guidelines and training material to write secure smart contracts
https://secure-contracts.com/
GNU Affero General Public License v3.0
2.21k stars 345 forks source link

Render better solidity file #247

Closed montyly closed 1 year ago

montyly commented 1 year ago

Right now, the solidity files are not directly rendered in secure-contracts, and the files are dl. We should investigate how to make this a better experience with mdbook

montyly commented 1 year ago

One solution is to change the links to point to the github page. Ex:

0xPhaze commented 1 year ago

How about just using a summary tag and embedding the solution into the markdown.

View solution ```solidity // SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.0; import "./MockERC20Permit.sol"; interface iHevm { //signs digest with private key sk function sign(uint256 sk, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); } contract TestDepositWithPermit { MockERC20Permit asset; iHevm hevm; event AssertionFailed(string reason); event LogBalance(uint256 balanceOwner, uint256 balanceCaller); address constant OWNER = 0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF; //address corresponding to private key 0x2 constructor() { hevm = iHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); asset = new MockERC20Permit("Permit Token", "PMT", 18); } //helper method to get signature, signs with private key 2 function getSignature( address owner, address spender, uint256 assetAmount ) internal returns (uint8 v, bytes32 r, bytes32 s) { bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", asset.DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"), owner, spender, assetAmount, asset.nonces(owner), block.timestamp ) ) ) ); (v, r, s) = hevm.sign(2, digest); //this gives us OWNER's signature } function testERC20PermitDeposit(uint256 amount) public { amount = 1 + (amount % 1000000e18); // we'll only consider transfers of up to 1M tokens asset.mint(OWNER, amount); uint256 previousOwnerBalance = asset.balanceOf(OWNER); uint256 previousCallerBalance = asset.balanceOf(address(this)); emit LogBalance(previousOwnerBalance, previousCallerBalance); (uint8 v, bytes32 r, bytes32 s) = getSignature(OWNER, address(this), amount); try asset.permit(OWNER, address(this), amount, block.timestamp, v, r, s) {} catch { emit AssertionFailed("signature is invalid"); } try asset.transferFrom(OWNER, address(this), amount) {} catch { emit AssertionFailed("transferFrom reverted"); } uint256 currentOwnerBalance = asset.balanceOf(OWNER); uint256 currentCallerBalance = asset.balanceOf(address(this)); emit LogBalance(currentOwnerBalance, currentCallerBalance); if (currentCallerBalance != previousCallerBalance + amount && currentOwnerBalance != 0) { emit AssertionFailed("incorrect amount transferred"); } } } ```
montyly commented 1 year ago

We want to keep the solidity code as separate solidity files, for a couple of reasons:

0xPhaze commented 1 year ago

Yes, I would suggest keeping them as separate files, but also including the solutions into the markdown as dropdowns (the user then doesn't have to look around in multiple pages). The problem here though is keeping the embedded code up-to-date. Perhaps we can take a look at:

This could be useful in a few other places as well

montyly commented 1 year ago

Done with #264