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` structsmapping
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.
}