solidity

Basics

identify solidity version compatibility:

pragma solidity >=0.5.0 <0.6.0;

contract ContractName {
}

inhereitance and imports:


contract Animal {
  function somethingAllAnimalsDo() {
  }
}

contract Cat is Animal {
  // has access to `somethingAllAnimalsDo()`
}

in separate files:

// another file 'animal.sol' defines the Animal contract
require "./animal.sol"

contract Cat is Animal {
  // has access to `somethingAllAnimalsDo()`
}

data types:

struct

like an object:

struct Person {
	string name;
	uint age;
}

array

Person[] public people;
// variable name is `people`, it is publicly-readable and its type
// is an array of `Person` structs

mapping

like a map

mapping (uint => address) public personToOwner;
// mapping from some number to some eth address,
// publicly-readable, called 'personToOwner'

Access with square brackets, like personToOwner[115] // returns the address at this index

functions

private functions

underscore:

function _someFunctionName(string memory _name, uint numberedThing) private {
}

public functions

function somePublicFunction(string memory theString) public {
// do stuff
// return 
}

Returning

specify a return value if not void:


// this returns a uint
function _generateRandomDna(string memory _str) private view returns (uint) {
	uint rand = uint(keccak256(abi.encodePacked(_str)));
	return rand
}

Internal/External

internal is the same as private, except it is accessible from other contracts that inherit from this one.

external is like public, but can only be called from outside the contract.

emitting

for listeners on a front end to catch

event SomeEvent(unit eventId, string eventName);

// later:

emit SomeEvent(324, "something happened");
uint rand = uint(keccak256(abi.encodePacked(_str)));

Caller

msg:

smart contracts don’t do anything until they are called. the caller to a contract is in msg.sender. will be an eth address.

Other

keccak256() will deterministically hash a string. but it must be “packed” properly. use abi.encodePacked(string) to accomplish.

Control flow

require

require makes it so that a function will throw an error and stop if condition is not met.

function someFunction() {
  require(msg.sender == 0x123123123);
  // fails unless calling eth address is 0x123123123
}

Memory, storage, blockchain

storage refers to blockchain storage. memory is like RAM - erased between function calls.

State variables (defined outside of functions) are automatically in storage. variables within functions are transient.

however, you need to specify when working with structs and arrays.

when accessing an item in an array, declaring storage will make that variable a pointer to that item, thus updating it in place when it is changed.

  struct Sandwich {
    string name;
    string status;
  }

  Sandwich[] sandwiches;

  function eatSandwich(uint _index) public {
    Sandwich storage mySandwich = sandwiches[_index];
			         // ^ a pointer to       ^ this
    mySandwich.status = "Eaten!";
	// so now sandwiches[_index] is modified in place, in storage,
    // on the blockchain
}

The same example with temporary, in-memory variables:

// ...
  function eatSandwich(uint _index) public {
	Sandwich memory anotherSandwich = sandwiches[_index + 1];
	            //  ^ in-memory copy of          ^ this
	anotherSandwich.status = "Eaten!";
	// this only modifies the in-memory version
	sandwiches[_index + 1] = anotherSandwich;
	// THIS overwrites the blockchain (storage) version with the
	// in-memory copy.
 }
Links to this page