Miguel Palhas
@naps62

Subvisual // Lightshift Capital

Developer // Researcher

A web3 focused venture studio that builds, invests, and supports projects aiming to shape the future by leveraging blockchain technology.

Early-stage crypto VC backing  the most promising blockchain, crypto, and web3 projects with the potential to transform the financial services sector.

Who are you?

Agenda for today

1. What is a smart contract?

2. Solidity crash course

3. somewhere in between: coffee break

4. practice

5. clickbait for developers

Toolkit for today

Option #1

remix.ethereum.org/

 

Option #2

CLI + hardhat/truffle

hardhat.org/

https://www.trufflesuite.com/

What is a blockchain?

we all know this by now, right?

Consensus
(PoW, PoS, ...)

Protocol

(Bitcoin, Ethereum, polkadot)

(D)apps

Smart Contracts

What is a transaction?

A user may say this ☝️

But we nerds know better 👨‍💻

BEGIN TRANSACTION; -- pay bounties
  UPDATE balances SET balance = balance - 1
  WHERE username = 'ethlisbon'


  UPDATE balances SET balance = balance + 500
  WHERE username = 'naps62'
COMMIT;

Transactions...

... update the state, with a set of operations

Account Balance
pinkroom Ξ 10000
naps62 Ξ 0
mario Ξ 0

pay_salaries()

Account Balance
pinkroom Ξ 9498
naps62 Ξ 500
mario Ξ 2
function pay_salaries() {
  for (int i = 0; i < employees.length; ++i) {
    balances[COMPANY_ADDRESS] -= employees[i].salary;
    balances[employees[i].address] += employees[i].salary;
  }
}

EVM / Solidity

Solidity code:

pragma solidity 0.4.25;

contract Demo1 {
  uint public balance;
  uint public totalAdditions;
  
  function add(uint value) public returns (uint256) {
        balance = balance + value;
        totalAdditions += 1;
        return balance;
  }
}

EVM bytecode:

608060405234801561001057600080fd5b5060c78061001f6000396000f3
0060806040526004361060485763ffffffff7c0100000000000000000000
0000000000000000000000000000000000006000350416631003e2d28114
604d578063b69ef8a8146074575b600080fd5b348015605857600080fd5b
5060626004356086565b60408051918252519081900360200190f35b3480
15607f57600080fd5b5060626095565b6000805482019081905591905056
5b600054815600a165627a7a7230582063aa00920d824233ab5307ef3a379
c757bdbee62fe00fe36a5d852c766e58fef0029
pragma solidity ^0.8.6;

contract ExtremelyBasicERC20 {
  uint mapping(address => uint256) public balances;
  
  function constructor() {
    balances[msg.sender] = 1e10; // 10000000000
  }
  
  function transfer(address to, uint256 amount) public {
        balances[msg.sender] -= amount;
        balances[to] += amount;
  }
}
interface ERC20 {
  function totalSupply() external view returns (uint256);
  
  function balanceOf(address who) external view returns (uint256);
  
  function allowance(address owner, address spender)
    external view returns (uint256);

  function transfer(address to, uint256 value)
    external returns (bool);

  function approve(address spender, uint256 value)
    external returns (bool);

  function transferFrom(address from, address to, uint256 value)
    external returns (bool);
}

Solidity Crash Course

Contracts / Instances

contract FooToken {
  string public name;
  
  function constructor(name _name) {
    name = _name;
  }
}
const foo1 = Foo.deploy("foo")
// 0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7

const foo2 = Foo.deploy("another_foo")
// 0xc365c3315cf926351ccaf13fa7d19c8c4058c8e1

Variables

contract FooToken {
  string public name;
  string private symbol;
  address owner;
  
  mapping(address => uint256) => balances;
  
  struct Item {
    address addr;
    uint id;
  }
  
  Item[] items;
}

Functions

contract FooToken {
  function balanceOf(address x) public view returns (uint256) {
    return balances[x];
  }
  
  function transfer(address to, uint256 amount) public {
    balances[msg.sender] -= amount;
    balances[to] += amount;
  }
  
  function notCallableFromOutside() private {
    // internal logic
  }
}

Inheritance

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract FooToken is ERC20 {
  function constructor() ERC20("CoimbraBlockchain", "CMB") {
    
  }
}

Send/Receive Ether

contract FooToken {
  function mint() public payable {
    balances[msg.sender] += msg.value;
  }
  
  function burn(uint256 amount) public {
    balances[msg.sender] -+ amount;
    payable(msg.sender).transfer(amount);
  }
}

Verify Hashes

contract Foo {
  bytes32 secret;
  string original;
  
  constructor(bytes32 _secret) {
    secret = _secret;
  }
  
  function reveal(string _original, string _password) public { 
    bytes32 hash = keccak256(abi.encodePacked(_original, _password));
    require(hash == secret);
    original = _original;
  }
}

Solidity, part 2

Require (fail-early)

contract Ownable {
  address owner;
  
  function adminOperation() public {
    require(msg.sender == owner, "not owner");
    
    veryDangerousFunction();
  }
}

Modifiers

contract Ownable {
  address owner;
  
  function constructor() {
    owner = msg.sender;
  }
  
  modifier onlyOwner() {
    require(msg.sender == owner, "not owner");
    _;
  }
  
  function changeOwner(address _newOwner) public onlyOwner {
    owner = _newOwner;
  }
}

Inter-contract interactions

contract Token { /* ... */ }

contract TokenVault {
  Token token;
  mapping(address => uint256) balances;
  
  function deposit(uint256 amount) public {
    balances[msg.sender] += amount;
    token.transferFrom(msg.sender, address(this), amount);
  }
  
  function withdraw(uint256 amount) public {
    balances[msg.sender] -= amount;
    token.transfer(msg.sender, amount);
  }
}

Exercise #1

Build a simple token (ERC20-like) contract:

- must keep a list of balances

- must allow transfers

- must allow exchanging Ether for minting new tokens

- each transfer charges a 1% fee, sent to the contract deployer

https://slides.com/naps62/coimbra-solidity-101

web3.js

Actually, two alternatives:

  • web3.js
  • ethers.js

Live demo

Exercise #2

// player 1
play("rock");

// player 2
play("paper");

// winner account can call this
// contract will check that sender is the winner
claimPrize();
contract RockPaperScissor {
  address public p1;
  address public p2;
  string public m1;
  string public m2;
}
contract RockPaperScissor {
  // ...
  
  function play(string _move) public payable {
    require(!finished(), "all moves set");
    
    if (p1 == address(0)) {
      p1 = msg.sender;
      m1 = _move;
    } else {
      require(p1 != msg.sender, "can't play both sides");
      
      p2 = msg.sender;
      m2 = _move;
    }
  }
}
contract RockPaperScissor {
  // ...
  
  function winner() internal view returns (address) {
    require(finished(), "moves missing");
    
    if ((m1 == "rock" && m2 == "scissor") ||
        (m1 == "paper" && m2 == "rock") ||
        (m1 == "scissor" && m2 == "paper")) {
      return p1;
    } else {
      return p2;
    }
  }
  
  function finished() internal view returns (bool) {
    return p2 != address(0);
  }
}
contract RockPaperScissor {
  // ...
  
  function claimReward() public {
    require(winner() == msg.sender);
    
    uint256 reward = address(this).balance;
    
    payable(msg.sender).transfer(reward);
  }
}

But wait, something's wrong!

// player 1
play("rock"); // this submits a transaction

// player 2 can then read existing transactions,
// and spy on what player 1's move was
play("paper");
// player 1
// plays a hash: keccack256("rock-secr3t")
play("d05c2b9c8221593088d05e5603e95a65629c485c7491a5cc5d394f0b489e4308");

// player 2
// plays a hash: keccack256("paper-12345")
play("bc12654d21eed85d6b0b3de3ef094c5c8f7c436b44ecf61f8bf01c11cc26fae2");

revealMove("rock", "-secr3t");
revealMove("paper", "-12345");

// winner account can call this
// contract will check that sender is the winner
claimPrize();
contract RockPaperScissor {
  // ...
  
  function revealMove(string _move, string _password) public {
      bytes32 m = keccak256(abi.encodePacked(_move, _password));
      
      if (m1_encrypted == m) {
          m1 = _move;
      } else if (m2_encrypted == m) {
          m2 = move;
      }
  }
}

Clickbait

  • https://secureum.xyz/epoch0
  • https://yacademy.dev/
  • https://ethernaut.openzeppelin.com/
  • https://www.damnvulnerabledefi.xyz/

Learn

  • https://rekt.news/
  • https://t.me/lobsters_chat
  • https://twitter.com/officer_cia

Watch

  • https://spearbit.com/
  • https://code4rena.com/
  • https://gitcoin.co/
  • https://immunefi.com/

Earn

MEV

  • https://docs.flashbots.net/new-to-mev

Thank you

(?)

Coimbra Blockchain - Solidity 101

By Miguel Palhas

Coimbra Blockchain - Solidity 101

  • 353