converts object-oriented, high-level language to implement contract templates into simple binaries, assembly and various other related metadata
pragma solidity >=0.4.0 <0.7.0; // only compatible with
// solidity compiler bigger or equal to v0.4.0
// but smaller than v0.7.0
(see all compiler versions)
Coin
Contract TemplateAre like a single slot in a database.
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address X; // declares a state variable X which can store
// an address of an external (="wallet") or contract **account**.
// Other accounts have no access to this state variable
}
X
is of type address
(=160-bit value that does not allow any arithmetic operations).
set
and get
view as part of public interfacepragma solidity >=0.4.0 <0.7.0;
contract Coin {
address account;
// takes one argument `x` of type `address`
function set (address x) public { account = x; }
// `view` guarantees function to not change state
// (=read only of state)
// returns a value of type `address`
function get () public view returns (address) { return account; }
}
these functions can be used by other acounts
to set/modify/alter or get/query/retrieve a value of a state variable.
public
keyword auto-generates a read access function for other accounts
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address public X; // behaves like:
// function X() public view returns (address) { return X; }
}
mapping
data typemap key of type1 to value of type2 for later lookup
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address public minter;
mapping (address => uint) balances;
// type `uint` (=unsigned integer of 256 bits)
}
// lookup `balances[minter]` defaults to value `0` of type `uint`
// assign `balances[minter] = 123`
// => to map `minter` address to uint `123`
// lookup `balances[minter]` now returns `123` of type `uint`
All keys by default map to all zeros byte-representation values and listing all is not possible
mapping
data typemap key of type1 to value of type2 for later lookup
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address public minter;
mapping (address => uint) public balances;
// function balances(address X) external view returns (uint) {
// return balances[X];
// }
}
Using public
on a mapping
auto-generates a more complex read access function for other accounts to query the balance of a single account
balances(minter)
=> 123
// sender of the message (current call)
msg.sender (address payable)
// MORE:
// number of wei sent with the message
msg.value (uint)
msg.data (bytes calldata) // complete calldata
// first four bytes of the calldata (i.e. function identifier)
msg.sig (bytes4)
// current block timestamp (alias for block.timestamp)
now (uint)
gasleft() returns (uint256) // remaining gas
// gas price of the transaction
tx.gasprice (uint)
// sender of the transaction (full call chain)
tx.origin (address payable)
// hash of one of the most recent 256 blocks, but not current
blockhash(uint blockNumber) returns (bytes32)
block.coinbase (address payable) // current block miner’s address
block.difficulty (uint) // current block difficulty
block.gaslimit (uint) // current block gaslimit
block.number (uint) // current block number
// current block timestamp as seconds since unix epoch
block.timestamp (uint)
Constructor function runs only once when the contract is published
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address public minter; // will store address of publisher
mapping (address => uint) public balances;
// executes ONLY once at contract creation time
constructor () public {
minter = msg.sender; // `msg.sender` always refers to the
// account address which sent the current transaction
}
}
declares an event
which can be emitted and allows clients (e.g. dapps) to react
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address public minter;
mapping (address => uint) public balances;
constructor() public { minter = msg.sender; }
event Sent(address from, address to, uint amount);
}
Event listeners receive emitted arguments
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address public minter;
mapping (address => uint) public balances;
constructor() public { minter = msg.sender; }
event Sent(address from, address to, uint amount);
// Sends an amount of existing coins
// from any caller to an address
function send (address receiver, uint amount) public {
balances[msg.sender] -= amount;
// short for: balances[msg.sender] = balances[msg.sender] - amount;
balances[receiver] += amount;
// short for: balances[receiver] = balances[receiver] + amount;
emit Sent(msg.sender, receiver, amount);
// arguments (`from`,`to`,`amount`) to track transactions
}
// Sends an amount of newly created coins to an address
// Can only be called by the contract creator
function mint (address receiver, uint amount) public {
balances[receiver] += amount;
// short for: balances[receiver] = balances[receiver] + amount;
}
}
// ethers
// abi
// bytecode
var currentProvider = window.web3.currentProvider
var provider = new ethers.providers.Web3Provider(currentProvider)
var contractAddress = '' // paste contract's address
var dapp = new ethers.Contract(contractAddress, abi, provider)
async function getEvent () {
dapp.on("Sent", (from, to, event) => {
console.log(`From (address): ${from}`)
console.log(`To (address): ${to}`)
console.log(`Event: ${event}`)
})
}
getEvent()
// ...
const receiver = '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
const amount = 500
async function dapp (contract) {
await contract.mint(receiver, amount)
const currentValue = await contract.balances(receiver)
console.log(currentValue) // => 500
}
require
guardIf "1st argument"
of require
is false
,
execution ends and all state and ether balance changes are reverted.
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address public minter;
mapping (address => uint) public balances;
constructor() public { minter = msg.sender; }
event Sent(address from, address to, uint amount);
function send (address receiver, uint amount) public {
// use `require` to check if functions are called as intended.
// A 2nd argument can provide explanations about whats wrong.
require(amount <= balances[msg.sender], "Not enough funds.");
// guard: can be used by anyone who has the amount of tokens to send
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
function mint (address receiver, uint amount) public {
require(msg.sender == minter);
// guard: ensures only the contract publisher can call mint
require(amount < 1e60);
// guard: prevents overflow errors in the future
balances[receiver] += amount; // assign tokens to address
}
}
copy to open in play-ed
pragma solidity >=0.4.0 <0.7.0;
contract Coin {
address public minter;
mapping (address => uint) public balances;
constructor() public { minter = msg.sender; }
event Sent(address from, address to, uint amount);
function send (address receiver, uint amount) public {
require(amount <= balances[msg.sender], "Not enough funds.");
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
function mint (address receiver, uint amount) public {
require(msg.sender == minter);
require(amount < 1e60);
balances[receiver] += amount;
}
}
Ballot
Contract Templatestruct
type & bool
type & NatSpecpragma solidity >=0.4.22 <0.7.0;
// NatSpec uses `///` to include informative comments in compiler output
// see: https://solidity.readthedocs.io/en/latest/natspec-format.html#tags
/// @title Transparent voting with automated vote counting.
contract Ballot { // 1 contract per ballot with option short-names
address public chairperson;
// `struct` declares a new complex type to be used for variables later
struct Voter { // represents a single voter.
uint weight; // weight 0 prevents from voting
bool voted; // if true, that person already voted
uint vote; // index of the voted proposal
}
}
bool
can only store one of two values at a time (true
or false
)
bytes32
typepragma solidity >=0.4.22 <0.7.0;
contract Ballot {
address public chairperson;
struct Voter { uint weight; bool voted; uint vote; }
struct Proposal { // This is a struct type for a single proposal.
bytes32 name; // short name (up to 32 bytes) of text
uint voteCount; // (=unit256) number of accumulated votes
}
}
ethers.utils.formatBytes32String('More flowers on the streets')
ethers.utils.parseBytes32String('0x4d616b652062696767657220726f616473000000000000000000000000000000')
"struct array"
typepragma solidity >=0.4.22 <0.7.0;
contract Ballot {
struct Voter { uint weight; bool voted; uint vote; }
struct Proposal { bytes32 name; uint voteCount; }
address public chairperson;
// Declares state variable to store `Voter` struct for address.
mapping(address => Voter) public voters;
// A dynamically-sized array (="list") of `Proposal` structs.
Proposal[] public proposals;
}
memory
keyword used for "reference types"pragma solidity >=0.4.22 <0.7.0;
contract Ballot {
struct Voter { uint weight; bool voted; uint vote; }
struct Proposal { bytes32 name; uint voteCount; }
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
// Makes new `Ballot` contract to choose one of `proposalNames`.
constructor (bytes32[] memory proposalNames) public {
// ...
}
}
for loop
, "struct object"
and array.push
pragma solidity >=0.4.22 <0.7.0;
contract Ballot {
struct Voter { uint weight; bool voted; uint vote; }
struct Proposal { bytes32 name; uint voteCount; }
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
constructor (bytes32[] memory proposalNames) public {
chairperson = msg.sender; // creator is chairperson
voters[chairperson].weight = 1;
// For each of provided proposal names,
// create new proposal object to add to end of array.
for (uint i = 0; i < proposalNames.length; i++) {
// `Proposal({...})` creates a temporary Proposal object
// and `proposals.push(...)` appends it to end of `proposals`.
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
}
storage
keyword used for "reference types"pragma solidity >=0.4.22 <0.7.0;
contract Ballot {
struct Voter { uint weight; bool voted; uint vote; }
struct Proposal { bytes32 name; uint voteCount; }
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
constructor (bytes32[] memory proposalNames) public {
// ...
}
/// Give `voter` the right to vote on this ballot.
// May only be called by `chairperson`.
function giveRightToVote (address voter) public {
require(msg.sender == chairperson, "Only chairperson adds voters.");
require(!voters[voter].voted, "The voter already voted.");
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
/// Give your vote to proposal `proposals[proposal].name`.
function vote (uint proposal) public {
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote");
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
// If `proposal` is out of the range of the array,
// this will throw automatically and revert all
// changes.
proposals[proposal].voteCount += sender.weight;
}
}
pragma solidity >=0.4.22 <0.7.0;
contract Ballot {
struct Voter { uint weight; bool voted; uint vote; }
struct Proposal { bytes32 name; uint voteCount; }
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
constructor (bytes32[] memory proposalNames) public {
// ...
}
function giveRightToVote (address voter) public {
// ...
}
function vote (uint proposal) public {
// ...
}
/// @dev Computes winning proposal from all previous votes.
/// @return proposal with most votes.
function winningProposal () public view returns (uint winningProposal_) {
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
// returns `winningProposal_` at the end as the named return value
}
// Calls winningProposal() function to get the index
// of the winner contained in the proposals array and then
/// @return the name of the winning proposal
function winnerName() public view returns (bytes32 winnerName_) {
// re-uses the `winningProposal()` function to calculate result
winnerName_ = proposals[winningProposal()].name;
// returns `winnerName_` at the end as the named return value
}
}
copy to open in play-ed
ethers.utils.formatBytes32String('More flowers on the streets')
ethers.utils.parseBytes32String('0x4d616b652062696767657220726f616473000000000000000000000000000000')
pragma solidity >=0.4.22 <0.7.0;
contract Ballot {
struct Voter { uint weight; bool voted; uint vote; }
struct Proposal { bytes32 name; uint voteCount; }
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
constructor (bytes32[] memory proposalNames) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
for (uint i = 0; i < proposalNames.length; i++) {
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
function giveRightToVote (address voter) public {
require(msg.sender == chairperson, "Only chairperson adds voters.");
require(!voters[voter].voted, "The voter already voted.");
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
function vote (uint proposal) public {
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote");
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
proposals[proposal].voteCount += sender.weight;
}
function winningProposal () public view returns (uint winningProposal_) {
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
function winnerName() public view returns (bytes32 winnerName_) {
winnerName_ = proposals[winningProposal()].name;
}
}
twitter/telegram
chat