Doug Hoyte
pragma solidity ^0.8.0;
contract MyContractName {
// code goes here
}
pragma
line: What version of solidity you want0.8.0
: This course does not cover security issues of earlier versionscontract
: Everything inside the curly braces is your contractcontract SimpleAdder {
function addOne(uint256 a) public pure returns(uint256) {
return a + 1;
}
}
function addOne(uint256 a) public pure returns(uint256)
function addOne(uint256 a) public pure returns(uint256)
function addOne(uint256 a) public pure returns(uint256)
X
is the number of bits: uint256
, uint32
uintX
except signed (negatives allowed): int256
, int64
bytes32
true
or false
function addOne(uint256 a) public pure returns(uint256) {
return a + 1;
}
addOne()
should always succeed right?uint256
1
to the biggest uint256
value (2256-1)function addOne(uint256 a) public pure returns(uint256) {
unchecked {
return a + 1;
}
}
unchecked
blocksfunction addOne(uint256 a) public pure returns(uint256) {
require(a < type(uint256).max, "sorry, a is too big");
return a + 1;
}
function addOne(uint256 a) public pure returns(uint256) {
require(a < type(uint256).max, "sorry, a is too big");
uint256 output = a + 1;
assert(output != 0); // 0 should be impossible
return output;
}
require
)assert
is used by special programs that analyze your code so they can prove things about it uint256 balance;
function withdraw(uint256 amount) {
require(balance - amount >= 0, "insufficient funds");
}
amount
is greater than balance
, the subtraction underflowsuint256
values are >= 0
(that's what unsigned means)if (x < 0) x *= -1;
x
is most negative signed integersafeAdd
, safeMul
, and safeSub
assert
if so:function safeAdd(uint256 a, uint256 b) private pure returns(uint256) { uint c = a + b; assert(c >= a && c >= b); return c; }
contract SimpleCounter {
uint256 public counter = 0;
function increment() public {
counter = counter + 1;
}
}
counter
increment()
is called, goes up by 1public
so it automatically creates a getter function named counter
private
or internal
contract SimpleCounter {
uint256 public counter = 0;
function add(uint256 a) public {
uint256 oldCounter = counter;
counter += a;
require(a < 100, "a too big");
}
}
a
after we have modified storagemsg.sender
- The address of who called your function (usually who created the transaction)msg.value
- Amount of wei sentblock.timestamp
- The current timeblock.number
- The current block heightcontract MyContract {
uint256 public myPersonalNumber = 0;
function changePersonalNumber(uint256 newNum) public {
require(msg.sender == 0x1234..., "only I can change this");
setPersonalNumber(newNum);
}
function setPersonalNumber(uint256 newNum) public {
myPersonalNumber = newNum;
}
}
contract MyContract {
uint256 public myPersonalNumber = 0;
function changePersonalNumber(uint256 newNum) public {
require(msg.sender == 0x1234..., "only I can change this");
setPersonalNumber(newNum);
}
function setPersonalNumber(uint256 newNum) public {
myPersonalNumber = newNum;
}
}
private
!contract MyContract {
address owner;
constructor() public {
owner = msg.sender;
}
function doStuff() public {
require(msg.sender == owner, "only owner can do stuff");
// do owner stuff
}
}
modifier onlyOwner() { require(msg.sender == owner); _; } function doStuff() public onlyOwner { // do owner stuff }
_;
is replaced with the function body (in this case, doStuff
's body)function deposit() public payable { require(msg.value >= 1 ether, "please send more"); }
payable
can receive ethermsg.value
is how much was sent1 ether
is using solidity's units featureether
just multiplies by 1e18
fallback() external { // ... do something }
receive() external payable { require(false, "please don't send me ETH"); }
function withdrawAll() public { uint256 totalAmount = address(this).balance; msg.sender.transfer(totalAmount); }
this
is the current contract (and can be turned into an address)msg.sender
is also an addressbalance
: How much ETH is owned by this addresstransfer
: Method to send ETH to this addressselfdestruct(beneficiary);
msg.sender
)mapping(address => uint256) balance; function deposit() public payable { balance[msg.sender] += msg.value; }
0
by defaultaddress
, get a uint256
address[] users; function addMyself() public { users.push(msg.sender); } function richestUser() public view returns(address) { address richest = address(0); uint256 richestBalance = 0; for (uint256 i = 0; i < users.length; i++) { if (users[i].balance > richestBalance) { richest = users[i]; } } return richest; }
users
array?users
array gets too big, we may not be able to loop over it without running out of gaslength
string name = "Alice";
struct Account { uint256 balance; uint256 lastUpdatedTimestamp; } struct User { string name; mapping(address => Account) accounts; }
event LogDeposit(address indexed account, uint256 amount);
emit
ted inside functions:function deposit() public payable { // ... emit LogDeposit(msg.sender, msg.value); }