# Solidity --- ## [Solidity Compiler](https://github.com/ethereum/solidity) converts object-oriented, high-level language to implement contract templates into simple binaries, assembly and various other related metadata ### pragma solidity ```javascript 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](https://github.com/ethereum/solc-bin/tree/gh-pages/bin)) --- # Simple `Coin` Contract Template --- ## Contract Template ### define State Variables Are like a single slot in a database. ```javascript 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). --- ## Contract Template ### define Functions * **`set`** and **`get` view** as part of **public** interface * functions can take arguments and can return values ```javascript pragma 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. --- ## Contract Template ### Access Modifier **`public`** keyword auto-generates a read access function for other accounts ```javascript pragma solidity >=0.4.0 <0.7.0; contract Coin { address public X; // behaves like: // function X() public view returns (address) { return X; } } ``` --- ## Contract Template ### `mapping` data type map key of type1 to value of type2 for later lookup ```javascript 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 --- ## Contract Template ### `mapping` data type map key of type1 to value of type2 for later lookup ```javascript 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 * e.g. `balances(minter)` => `123` --- ## Contract Template ### global variables ```javascript // 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) ``` --- ## Contract Template ### constructor Constructor function runs only once when the contract is published ```javascript 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 } } ``` --- ## Contract Template ### declare events declares an **`event`** which can be emitted and allows clients (e.g. dapps) to react ```javascript 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); } ``` --- ## Contract Template ### emit events Event listeners receive emitted arguments ```javascript 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; } } ``` --- ## Dapp ### event listening ```javascript // 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() ``` --- ## Dapp ### calling functions ```javascript // ... 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 } ``` --- ## Contract Template ### `require` guard If `"1st argument"` of `require` is `false`, execution ends and all state and ether balance changes are reverted. ```javascript 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 } } ``` --- ## Demo Time copy to open in [play-ed](https://playproject.io/play-ed) ```javascript 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; } } ``` --- # Simple `Ballot` Contract Template --- ## Contract Template ### `struct` type & `bool` type & [NatSpec](https://solidity.readthedocs.io/en/latest/natspec-format.html#natspec-format) ```javascript pragma 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`**) --- ## Contract Template ### `bytes32` type ```javascript pragma 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 } } ``` ```javascript ethers.utils.formatBytes32String('More flowers on the streets') ethers.utils.parseBytes32String('0x4d616b652062696767657220726f616473000000000000000000000000000000') ``` --- ## Contract Template ### `"struct array"` type ```javascript 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; // 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; } ``` --- ## Contract Template ### [Reference Types](https://solidity.readthedocs.io/en/latest/types.html#data-location) * `memory` keyword used for "reference types" ```javascript 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 { // ... } } ``` * [click here for more details](https://medium.com/cryptologic/memory-and-storage-in-solidity-4052c788ca86) --- ## Contract Template ### `for loop`, `"struct object"` and `array.push` ```javascript 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 })); } } } ``` --- ## Contract Template ### [Reference Types](https://solidity.readthedocs.io/en/latest/types.html#data-location) * `storage` keyword used for "reference types" * [click here for more details](https://medium.com/cryptologic/memory-and-storage-in-solidity-4052c788ca86) ```javascript 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; } } ``` --- ## Contract Template ### "named returns" and "function re-use" ```javascript 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 } } ``` --- ## Demo Time copy to open in [play-ed](https://playproject.io/play-ed) ```javascript ethers.utils.formatBytes32String('More flowers on the streets') ethers.utils.parseBytes32String('0x4d616b652062696767657220726f616473000000000000000000000000000000') ``` ```javascript 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; } } ``` --- # Thank you ### questions? #### connect with us twitter/telegram * [@ninabreznik](https://twitter.com/ninabreznik) * [@serapath](https://twitter.com/serapath) chat * [gitter.im/ethereum/play](https://gitter.im/ethereum/play)
{"metaMigratedAt":"2023-06-15T00:47:34.896Z","metaMigratedFrom":"YAML","title":"Solidity","breaks":true,"slideOptions":"{\"theme\":\"white\"}","contributors":"[{\"id\":\"f23eca56-446e-4236-82ac-d8f7524ed36e\",\"add\":93121,\"del\":75877},{\"id\":\"4fa59fe4-4b0e-40a7-beeb-0c8f8c93edbb\",\"add\":878,\"del\":914}]"}
    2388 views