Solidity CS1951 L Spring 2019 19 February 2019 Maurice Herlihy

Slides:



Advertisements
Similar presentations
Secure Multiparty Computations on Bitcoin
Advertisements

Written by: Dr. JJ Shepherd
1 1 Lecture 4 Structure – Array, Records and Alignment Memory- How to allocate memory to speed up operation Structure – Array, Records and Alignment Memory-
ECE122 L6: Problem Definition and Implementation February 15, 2007 ECE 122 Engineering Problem Solving with Java Lecture 6 Problem Definition and Implementation.
Run time vs. Compile time
Computer Science II Exam I Review Monday, February 6, 2006.
Data Abstraction and Object- Oriented Programming CS351 – Programming Paradigms.
1 Run time vs. Compile time The compiler must generate code to handle issues that arise at run time Representation of various data types Procedure linkage.
OOP Languages: Java vs C++
1 CISC181 Introduction to Computer Science Dr. McCoy Lecture 19 Clicker Questions November 3, 2009.
Inheritance in C++ CS-1030 Dr. Mark L. Hornick.
“is a”  Define a new class DerivedClass which extends BaseClass class BaseClass { // class contents } class DerivedClass : BaseClass { // class.
Writing Classes (Chapter 4)
1 Chapter 10: Data Abstraction and Object Orientation Aaron Bloomfield CS 415 Fall 2005.
Polymorphism, Inheritance Pt. 1 COMP 401, Fall 2014 Lecture 7 9/9/2014.
Programming in Java Unit 2. Class and variable declaration A class is best thought of as a template from which objects are created. You can create many.
Functional Programming and Lisp. Overview In a functional programming language, functions are first class objects. In a functional programming language,
Low-Level Detailed Design SAD (Soft Arch Design) Mid-level Detailed Design Low-Level Detailed Design Design Finalization Design Document.
CSC1401 Classes - 2. Learning Goals Computing concepts Adding a method To show the pictures in the slide show Creating accessors and modifiers That protect.
Session 7 Methods Strings Constructors this Inheritance.
Inter-Type Declarations in AspectJ Awais Rashid Steffen Zschaler © Awais Rashid, Steffen Zschaler 2009.
CSCI 1100/1202 April 1-3, Program Development The creation of software involves four basic activities: –establishing the requirements –creating.
Chapter 10: Classes and Data Abstraction. Objectives In this chapter, you will: Learn about classes Learn about private, protected, and public members.
CSE 332: C++ Statements C++ Statements In C++ statements are basic units of execution –Each ends with ; (can use expressions to compute values) –Statements.
1/33 Basic Scheme February 8, 2007 Compound expressions Rules of evaluation Creating procedures by capturing common patterns.
Programming Fundamentals. Topics to be covered Today Recursion Inline Functions Scope and Storage Class A simple class Constructor Destructor.
Written by: Dr. JJ Shepherd
Object Oriented Programming. OOP  The fundamental idea behind object-oriented programming is:  The real world consists of objects. Computer programs.
Chapter 10: Classes and Data Abstraction. Classes Object-oriented design (OOD): a problem solving methodology Objects: components of a solution Class:
72 4/11/98 CSE 143 Abstract Data Types [Sections , ]
Recap Introduction to Inheritance Inheritance in C++ IS-A Relationship Polymorphism in Inheritance Classes in Inheritance Visibility Rules Constructor.
(c) University of Washington10-1 CSC 143 Java Errors and Exceptions Reading: Ch. 15.
Reference Types CSE301 University of Sunderland Harry R Erwin, PhD.
Object-Oriented Programming: Classes and Objects Chapter 1 1.
COP INTERMEDIATE JAVA Inheritance, Polymorphism, Interfaces.
CSE 332: C++ Exceptions Motivation for C++ Exceptions Void Number:: operator/= (const double denom) { if (denom == 0.0) { // what to do here? } m_value.
CS314 – Section 5 Recitation 9
Memory Management.
Dynamic Storage Allocation
Copyright © Jim Fawcett Spring 2017
Blockchain Infrastructure for e-Science
Chapter 6 CS 3370 – C++ Functions.
CSE 374 Programming Concepts & Tools
Object-Oriented Programming: Classes and Objects
7. Inheritance and Polymorphism
Andy Wang Object Oriented Programming in C++ COP 3330
Inheritance and Polymorphism
Review: Two Programming Paradigms
Chapter 4: Writing Classes
Object-Oriented Programming: Classes and Objects
This pointer, Dynamic memory allocation, Constructors and Destructor
Inheritance Often, software encapsulates multiple concepts for which some attributes/behaviors overlap E.g. A computer (role-playing) game has: Monsters:
Lecture 23 Polymorphism Richard Gesick.
Exceptions An exception signals an error, and has the ability to propagate upward through the call stack for easier management To “raise” an exception,
Packages and Interfaces
Object Oriented Programming
Data Abstraction: The Walls
Dynamic Scoping Lazy Evaluation
Dr. Bhargavi Dept of CS CHRIST
CSE 153 Design of Operating Systems Winter 19
Data Structures in Ethereum
Ethereum Virtual Machine
CSC 143 Java Errors and Exceptions.
Chap 2. Identifiers, Keywords, and Types
Analysing Vulnerabilities in Smart Contracts
Solidity Pitfalls and Hazards
Concurrency in Smart Contracts
Solidity Pitfalls and Hazards
Classes and Objects Systems Programming.
SPL – PS3 C++ Classes.
Presentation transcript:

Solidity CS1951 L Spring 2019 19 February 2019 Maurice Herlihy Brown University

Solidity Tutorial Solidity is usual high-level language for the EVM Based on Javascript Here, example-based tutorial Use on-line docs and compiler to learn

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … }

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … } This program needs compiler version 0.5.2 or later

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … } A contract is like a class. This contract manages a simple coin

that lives in the EVM’s storage Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … } A contract encompasses long-lived state that lives in the EVM’s storage

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … } Name of an account (person or contract).

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … } Name of an account (person or contract). Here, only one allowed to mint new coins.

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … } Like a hash table

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … } Like a hash table Initially, every address maps to zero

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … } Like a hash table Initially, every address maps to zero Tracks client balances

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; constructor() public { minter = msg.sender; } Initializes a contract

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; constructor() public { minter = msg.sender; } address of contract making the call

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; constructor() public { minter = msg.sender; } Remember the creator’s address.

Coin Example A function is like a method. pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … function mint(address owner, uint amount) public { if (msg.sender != minter) return; balances[owner] += amount; } A function is like a method.

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … function mint(address owner, uint amount) public { if (msg.sender != minter) return; balances[owner] += amount; } Coin Example If the caller is not authorized, just return.

Coin Example pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … function mint(address owner, uint amount) public { if (msg.sender != minter) return; balances[owner] += amount; } Coin Example Otherwise credit the amount to the owner’s balance

Coin Example One party transfers coins to counterparty pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … function send(address receiver, uint amount) public { if (balances[msg.sender] < amount) return; balances[msg.sender] -= amount; balances[receiver] += amount; } One party transfers coins to counterparty

Coin Example Quit if insufficient funds pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … function send(address receiver, uint amount) public { if (balances[msg.sender] < amount) return; balances[msg.sender] -= amount; balances[receiver] += amount; } Quit if insufficient funds

Coin Example transfer amount from one account to the other pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; … function send(address receiver, uint amount) public { if (balances[msg.sender] < amount) return; balances[msg.sender] -= amount; balances[receiver] += amount; } transfer amount from one account to the other

The Flippening Alice and Bob want to flip a fair coin Each one is willing to cheat Obvious sources of randomness: time, block hashes, etc. don’t work Let’s try sometihng else

Coin Flip Contract pragma solidity ^0.5.1; contract CoinFlipMaybe { address[2] player; mapping (address => uint) vote; mapping (address => bool) played; bool result; bool done; …

Coin Flip Example declare contract and compiler version pragma solidity ^0.5.1; contract CoinFlipMaybe { address[2] player; mapping (address => uint) vote; mapping (address => bool) played; bool result; bool done; … declare contract and compiler version

Coin Flip Example pragma solidity ^0.5.1; contract CoinFlipMaybe { address[2] player; mapping (address => uint) vote; mapping (address => bool) played; bool result; bool done; … will want to restrict interactions to the two players

Coin Flip Example each player contributes to the result pragma solidity ^0.5.1; contract CoinFlipMaybe { address[2] player; mapping (address => uint) vote; mapping (address => bool) played; bool result; bool done; … each player contributes to the result

Coin Flip Example each player gets one move only pragma solidity ^0.5.1; contract CoinFlipMaybe { address[2] player; mapping (address => uint) vote; mapping (address => bool) played; bool result; bool done; … each player gets one move only

Coin Flip Example remember outcome pragma solidity ^0.5.1; contract CoinFlipMaybe { address[2] player; mapping (address => uint) vote; mapping (address => bool) played; bool result; bool done; … remember outcome

Coin Flip Example pragma solidity ^0.5.1; contract CoinFlipMaybe { … constructor (address alice, address bob) public { player[0] = alice; player[1] = bob; }

Coin Flip Example constructor just remembers players pragma solidity ^0.5.1; contract CoinFlipMaybe { … constructor (address alice, address bob) public { player[0] = alice; player[1] = bob; } constructor just remembers players

Coin Flip Example function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; }

Coin Flip Example require(condition) function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } require(condition) means abort computation if condition not satisfied. Like throwing an exception

Only Alice and Bob allowed to play Coin Flip Example function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } Only Alice and Bob allowed to play

Each player can play only once Coin Flip Example function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } Each player can play only once

Coin Flip Example record player’s vote function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } record player’s vote

record that player voted Coin Flip Example function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } record that player voted

we are done if both players voted Coin Flip Example function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } we are done if both players voted

Coin Flip Example remember we are done function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } remember we are done

Coin Flip Example take XOR of votes function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } take XOR of votes

flip value is parity of XOR of votes Coin Flip Example function play(uint _vote) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!played[msg.sender]); vote[msg.sender] = _vote; played[msg.sender] = true; if (played[player[0]] && played[player[1]]) { done = true; result = ((vote[player[0]] ^ vote[player[1]]) % 2) == 1; } flip value is parity of XOR of votes

Coin Flip Example function getResult() public view returns (bool) { require (done); return result; }

anyone can request outcome Coin Flip Example function getResult() public view returns (bool) { require (done); return result; } anyone can request outcome

make sure outcome is ready Coin Flip Example function getResult() public view returns (bool) { require (done); return result; } make sure outcome is ready

This Contract is Insecure Suppose Alice plays first Bob then observes contract state on Etherscan.io Picks his vote after seeing hers Bob controls coin flip outcome

Commit-Reveal Pattern Step One: commit to a value without revealing it you cannot change your value Step Two: Wait for others to commit Step Three: reveal your value you can check validity

Commit-Reveal Pattern Alice generates a random value r Alice commits to r by sending hash(r) to contract Alice waits for Bob to commit All done off-chain! Alice reveals r to contract Compute outcome when Bob reveals

Commit-Reveal Flip contract CoinFlipCR { address[2] player; mapping (address => uint) commitment; mapping (address => uint) revelation; mapping (address => bool) committed; mapping (address => bool) revealed; bool result; bool done;

track both commit and reveal Commit-Reveal Flip contract CoinFlipCR { address[2] player; mapping (address => uint) commitment; mapping (address => uint) revelation; mapping (address => bool) committed; mapping (address => bool) revealed; bool result; bool done; track both commit and reveal

Commit-Reveal Flip function commit(uint _commit) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!committed[msg.sender]); commitment[msg.sender] = _commit; committed[msg.sender] = true; }

Commit-Reveal Flip members only function commit(uint _commit) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!committed[msg.sender]); commitment[msg.sender] = _commit; committed[msg.sender] = true; } members only

Commit-Reveal Flip You only commit once function commit(uint _commit) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!committed[msg.sender]); commitment[msg.sender] = _commit; committed[msg.sender] = true; } You only commit once

Commit-Reveal Flip close the deal function commit(uint _commit) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!committed[msg.sender]); commitment[msg.sender] = _commit; committed[msg.sender] = true; } close the deal

Coin Flip Example function reveal(uint _reveal) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!revealed[msg.sender]); require( commitment[msg.sender]==hash(_reveal)); revelation[msg.sender] = _reveal; revealed[msg.sender] = true; if (revealed[player[0]] && revealed[player[1]]) { done = true; result = ((revelation[player[0]] ^ revelation[player[1]]) % 2) == 1; } Coin Flip Example

Coin Flip Example Usual preconditions (do we actually care?) function reveal(uint _reveal) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!revealed[msg.sender]); require( commitment[msg.sender]==hash(_reveal)); revelation[msg.sender] = _reveal; revealed[msg.sender] = true; if (revealed[player[0]] && revealed[player[1]]) { done = true; result = ((revelation[player[0]] ^ revelation[player[1]]) % 2) == 1; } Coin Flip Example Usual preconditions (do we actually care?)

make sure reveal is sincere function reveal(uint _reveal) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!revealed[msg.sender]); require( commitment[msg.sender]==hash(_reveal)); revelation[msg.sender] = _reveal; revealed[msg.sender] = true; if (revealed[player[0]] && revealed[player[1]]) { done = true; result = ((revelation[player[0]] ^ revelation[player[1]]) % 2) == 1; } Coin Flip Example make sure reveal is sincere

Coin Flip Example record revelation function reveal(uint _reveal) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!revealed[msg.sender]); require( commitment[msg.sender]==hash(_reveal)); revelation[msg.sender] = _reveal; revealed[msg.sender] = true; if (revealed[player[0]] && revealed[player[1]]) { done = true; result = ((revelation[player[0]] ^ revelation[player[1]]) % 2) == 1; } Coin Flip Example record revelation

If done, compute outcome as before function reveal(uint _reveal) public { require(msg.sender == player[0] || msg.sender == player[1]); require(!revealed[msg.sender]); require( commitment[msg.sender]==hash(_reveal)); revelation[msg.sender] = _reveal; revealed[msg.sender] = true; if (revealed[player[0]] && revealed[player[1]]) { done = true; result = ((revelation[player[0]] ^ revelation[player[1]]) % 2) == 1; } Coin Flip Example If done, compute outcome as before

Solidity Details

Scalar Types int8, … int256 = int uint8, …, uint256 = uint bool address bytes1, …,bytes32

Enums enum Actions{ GoLeft, GoRight, GoStraight} Actions choice; Actions constant default = Actions.GoStraight.

Static Arrays uint[8] a; // 8 256-bit uints

Dynamic Arrays uint[] a = new uint[](8); // 8 256-bit uints

Structs struct Funder { address addr; uint amount; }

Mappings Every key implicitly bound to all-zero value struct Funder { address addr; uint amount; } struct Funder { address addr; uint amount; } struct Funder { address addr; uint amount; } struct Funder { address addr; uint amount; } Mappings mapping (address => uint) Every key implicitly bound to all-zero value binding always defined

Call Opcode A calls B’s function … which runs in B’s address space Contract A Contract B A calls B’s function … which runs in B’s address space

DelegateCall Opcode A delegatecalls B’s function … Contract A Contract B Contract B’s code A delegatecalls B’s function … which runs in A’s address space

Contract where every function call Library library SafeMath { … } Syntactic sugar Contract where every function call is a delegate call

Abstract Contracts At least one function implementation missing contract Config { {// defined function name() public returns (string) return “Config”; } // undefined function lookup(uint id) public returns (address); At least one function implementation missing Compiler type-checking, inheritance

Interfaces All function implementations missing interface Config { function lookup(uint id) public returns (address); } All function implementations missing Compiler type-checking, inheritance

Inheritance Like other languages contract Feline { function utterance() public returns (bytes32); } contract Cat is Feline { public returns (bytes32) { return "meow"; Like other languages

Events An event is a public record that something happened event Deposit(address from, uint value); … emit Deposit(msg.sender, msg.value); Events can be monitored from outside the blockchain

Function Visibility External: only from outside Public: only internal or external Internal: only current or derived contracts Private: only current not derived contracts

Fallback Function Transaction data includes: Function selector (hashed name) Function arguments

Fallback Function contract Example { uint x = 0; function foo() public { x = 1; } function () public payable { x = 2;

Fallback Function contract Example { uint x = 0; function foo() public { x = 1; } function () public payable { x = 2; named regular function

Fallback Function Often used to receive payments contract Example { uint x = 0; function foo() public { x = 1; } function () public payable { x = 2; named regular function nameless fallback function Often used to receive payments

Fallback Function Idiosyncrasies Limited to 2300 gas function () { balances[msg.sender] += msg.value; } This will not work

Fallback Function Idiosyncrasies revert(); } function deposit() external { balances[msg.sender] += msg.value; This works

Function Call fn foo() fn bar() fn () A calls B’s “foo” function … Contract A Contract B not me! call “bar” fn foo() me! fn bar() fn () A calls B’s “foo” function …

Fallback Function fn foo() fn bar() fn () Contract A Contract B not me! call “xyzzy” fn foo() not me! fn bar() fn () me, by default A calls B’s “xyzzy” function …

Sending Ether to a Payable Fallback Function address.send(amount); Limited to 2300 gas Protects against re-entrancy attack requires near-trivial fallback function If transfer fails, returns Boolean Programming pitfall

Sending Ether to a Payable Fallback Function address.transfer(amount); Limited to 2300 gas Protects against re-entrancy attack requires near-trivial fallback function If transfer fails, reverts transaction Safer programming practice

Sending Ether to a Payable Fallback Function address.call.value(amount).gas(extra); Can specify how much gas No re-entrancy protection non-trivial fallback functions OK If transfer fails, reverts transaction Safer programming practice

Sending Ether to a Payable Named Function address.fun.value(amount)(args); Uses as much gas as needed No re-entrancy protection If transfer fails, reverts transaction Safer programming practice

Sending Ether to a Payable Named Function address.fun.value(amount).gas(limit)(args); Limits gas as shown No re-entrancy protection If transfer fails, reverts transaction Safer programming practice

Moral Payment breaks abstaction You don’t know how to call a fallback function … unless you know what it does See later lectures on pitfalls!

require() and assert() Roll back if condition fails require(msg.sender == owner) require() might fail if input is bad assert(msg.sender == owner) assert() should never fail

Function Modifiers modifier ownerOnly() { require (msg.sender == owner); _; } If test passes … Execute function body

Function Modifiers If test passes … function pay(address _payto, uint amount) public ownerOnly() { balance[_payTo] += amount; } Execute function body

Self Destruction terminates contract selfDestruct(sendMoneyTo) terminates contract sends remaining balance to argument beneficiary cannot refuse

Data Location storage or memory memory is default for arg & result passing storage is default for local vars assignment across regions is copying

Ethereum Storage 2256-1 32 bytes A very, very big array Initially all 0s 32 bytes

Variables contract aContract { uint256 a; … } a

Static Arrays uint256[2] b; a b b 1 2

Structs a b b c c struct aStruct{ uint256 id; uint256 value; } aStruct c; a b b c c 1 2 3 4

Dynamic Arrays struct aStruct{ uint256 id; uint256 value; } aStruct d[]; d.length d[0] d[0] d[1] d[1] 5 Hash(5)

Mappings mapping(uint256 => uint 256) e; 6 empty Hash(123,6) e[123]

Simple Variable declaration T v; value location v v’s slot

Fixed-Size Arrays declaration T[10] v; value location V[1] (v’s slot)+i*(sizeof T)

Dynamic Arrays declaration T[10] v; value location v[i] hash(v’s slot)+i*(sizeof T) v.length v’s slot

Mappings declaration mapping(T1 => T2) v; value location v[i] hash(i.(v’s slot)) https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/

Datatype layouts in EVM memory Ideas we covered in this lecture Coin example Data types Modifiers require() and assert() Various Features Datatype layouts in EVM memory

Public vs Private blockchains Ideas we covered in this lecture Public vs Private keys Encryption and signatures Public vs Private blockchains Consensus

Variables pragma solidity ^0.5.2; contract Coin { address minter; mapping (address => uint) balances; constructor() public { minter = msg.sender; } function mint(address owner, uint amount) public { if (msg.sender != minter) return; balances[owner] += amount; function send(address receiver, uint amount) public { if (balances[msg.sender] < amount) return; balances[msg.sender] -= amount; balances[receiver] += amount; function queryBalance(address addr) public view returns (uint balance) { return balances[addr]; Variables