Solidity

Solidity is statically typed, supports inheritance, libraries, and complex user-defined types, among other features.

Contract language for voting, auctions, multi-sig wallets, etc. Contract is collection of functions and data stored on blockchain.

Functions that aren't pure/view cost gas

Account have storage which is persistent between function calls/transcations. Memory for each call.

Foundry

Smart contract development toolchain with building, testing, etc

curl -L https://foundry.paradigm.xyz | bash

Follow instructions perhaps

foundryup

Solidity

Basic Program

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract Coin {
    // public variables accessible from other contracts
    address public minter;
    mapping(address => uint) public balances;

    // Events are subscribeable by clients
    event Sent(address from, address to, uint amount);

    constructor() {
        minter = msg.sender;
    }

    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        balances[receiver] += amount;
    }

    error InsufficientBalance(uint requested, uint available);

    function send(address receiver, uint amount) public {
        if (amount > balances[msg.sender])
            revert InsufficientBalance({
                requested: amount,
                available: balances[msg.sender]
            });

        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

Variable Visibility

// no visibility
string n1 = "N1"
//only within contract
string private n2 = "N2"
//only within contract, but can be inherited
string internal n3 = "N3"
//see within, outside, and can be inherited
string public n4 = "N4"

//similar for functions; internal, public, external
function increment() external {
  count = count + 1;
}

Function Modifiers

string public name = "Example 5";
uint public balance;

//doesn't modify state, but reads
function getName() public view return(string memory) {
	return name;
}

//can't read or modify state
function add(uint a, uint b) public pure returns(uint) {
	return a + b;
}

//recieves eth or crypto
function pay() public payable {
	payer = msg.sender;
	origin = tx.origin;
	amount = msg.value;
}

Custom Modifer

address private owner;
string public name = "";

modifier onlyOwner {
	require(msg.sender == owner, 'caller must be owner');
	_;
}

function setName(string memory _name) onlyOwner public {
	name = _name;
}

Mapping

   mapping(address => uint) public balances;

   function updateBalance(uint newBalance) public {
      balances[msg.sender] = newBalance;
   }

Enum

contract EnumContract {
    enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
    ActionChoices choice;
    ActionChoices constant defaultChoice = ActionChoices.GoStraight;

    function setGoStraight() public {
        choice = ActionChoices.GoStraight;
    }

    // Since enum types are not part of the ABI, the signature of "getChoice"
    // will automatically be changed to "getChoice() returns (uint8)"
    // for all matters external to Solidity.
    function getChoice() public view returns (ActionChoices) {
        return choice;
    }

    function getDefaultChoice() public pure returns (uint) {
        return uint(defaultChoice);
    }

    function getLargestValue() public pure returns (ActionChoices) {
        return type(ActionChoices).max;
    }

    function getSmallestValue() public pure returns (ActionChoices) {
        return type(ActionChoices).min;
    }
}

Custom Error

    // custom error statement
    error LackOfFunds(uint withdrawAmt, uint availableAmt);
     
         function checkCustomError(address _receiver,uint _withdrawAmt) public {
        if (bal[msg.sender]< _withdrawAmt) {
            revert LackOfFunds({withdrawAmt: _withdrawAmt, availableAmt: bal[msg.sender]});
        }
        bal[msg.sender] -= _withdrawAmt;
        bal[_receiver]+=_withdrawAmt;
    }

Foundry Unit Tests

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../src/Counter.sol";

contract CounterTest is Test {
  // an address created by casting a decimal to an address
  address owner = address(1234);

    function setUp() public {
        counter = new Counter();
        counter.setNumber(0);
    }

    function testIncrement() public {
        counter.increment();
        assertEq(counter.number(), 1);
    }

  function testChangeOwner() public {
  		//prank to change msg.sender
      vm.prank(owner);
      contractToTest.changeOwner(newOwner);
      assertEq(contractToTest.owner(), newOwner);
  }
}

Last updated