Skip to content

Latest commit

 

History

History
755 lines (641 loc) · 68.6 KB

eth-dev.md

File metadata and controls

755 lines (641 loc) · 68.6 KB

Ethereum Smart Contract Development Reference

The purpose of this document is to collect notes and resources related to Ethereum smart contract development. Primarily, it is a personal tool for its author, Dan Forbes; however, it is being made publicly available in the hopes that others find it useful. Please contact Dan (dan@danforbes.dev) or use a GitHub Issue or Pull Request if you have any questions or would like to suggest any changes.

🤓 Smart Contracts

Smart contracts are programs that run on the Ethereum blockchain and read and modify its state.

  • Ethereum smart contracts are powerful because they are bound by the rules of the Ethereum blockchain.
    • Deterministic - a smart contract must always provide the same output for any given set of inputs
    • Terminable - the execution of a smart contract must always terminate
    • Isolated - smart contracts must be kept in a “sandbox” to prevent bugs from propagating

🚙 Gas

Gas is a unit that measures the amount of computational effort it will take to execute operations on the Ethereum blockchain.

  • Gas is integral to ensuring Ethereum smart contracts are terminable as well as incentivizing miners to participate in the blockchain.
  • Every single Ethereum operation, be it a transaction or smart contract execution, requires some amount of gas.
  • Miners get paid an amount in Ether, which is directly related to the total amount of gas it took them to execute Ethereum operations.
  • Transaction senders specify a transaction’s gas limit, which is the maximum amount of gas they are willing to pay for a transaction.
    • If the limit is not high enough to complete the transaction’s execution, the state changes caused by the transaction are reverted and the sender is charged 100% of the gas limit.
    • If the limit is sufficient to complete the transaction’s execution, the state changes caused by the transaction are persisted and the sender is refunded any unused gas.
    • There is a limit on the total amount of gas a miner can accept, so transaction senders should not set artificially high gas limits.
  • The sender of a transaction specifies the gas price (expressed in gwei).
    • Miners are more likely to pick up transactions that have higher gas prices.
  • Some operations (deletion) refund gas; refunds are limited to 50% of the gas used by a transaction.
  • Anecdotally, gas is extremely expensive; Ethereum is “400 million times” more expensive than AWS.

Further Reading

Ethereum smart contracts have three areas where they can store data - storage, memory and the stack.

Storage

  • Persistent between function calls and transactions
  • Comparatively high gas cost to read, and even higher to initialize and modify
  • Contract obtains a freshly cleared instance for each message call
  • Memory is more costly the larger it grows (resizable array); scales quadratically

The Stack

  • Runtime state; the program stack
  • Access to the stack is limited to copying one of the topmost 16 elements to the top of the stack or swapping the topmost element with one of the 16 elements below it

Further Reading

💻 The Ethereum Virtual Machine (EVM)

The EVM is the runtime environment for Ethereum smart contracts. It is a simple yet powerful Turing Complete 256-bit virtual machine.

  • Turing Complete - a system that can be mathematically proven to have the capability of performing any possible calculation or computer program
  • In order to interact with the EVM, users must provide EVM bytecode.
    • High-level languages like Solidity are compiled to EVM bytecode.
  • The EVM is a transaction-based state machine; transactions are submitted and validated before the state is updated.
  • The EVM manages the state of a number of components.
    • Accounts - user accounts or smart contracts
    • Blocks - information like the hash of the last block
    • Runtime - information used to execute a transaction
  • User (“externally-owned”) accounts are associated with private keys.
  • Contract accounts are associated with the code that defines them.
  • The EVM has message-passing capabilities that allow accounts to interact.
    • User accounts can send messages by signing them with their private key.
    • Passing a message to a contract account will execute the contract’s code and allow it to manipulate its storage.
  • All Ethereum accounts are comprised of four elements.
    • Nonce - a number that increases with account activity
      • User - the number of transactions sent from the account address
      • Contract - the number of contracts created by the account
    • Balance - the amount of wei controlled by the account
    • Hash - 160-bit account address
      • User - calculated with public/private key pair
      • Contract - calculated with creator address and nonce
    • Storage - a mapping of 256-bit words to 256-bit words

Further Reading

Application Binary Interface (ABI)

The Ethereum ABI is the standard way to interact with EVM smart contracts, both from outside the blockchain and for contract-to-contract interaction.

  • A formal specification for encoding smart contract function selectors and arguments.
  • There is a JSON format for describing a contract’s interface.

Solidity

Solidity is an object-oriented, high-level language for implementing smart contracts. Solidity was influenced by C++, Python and JavaScript, and is designed to target the EVM.

Overview

  • No concept of null or undefined in Solidity; variables are initialized with default values
  • Value types - passed by value (copied) when used in function arguments or assignments
  • Reference types - passed by reference when used in function arguments or assignments
    • Changes will propagate to the original since no copy is made
    • Reference types are annotated with a data location
    • Structs - custom types that can be used to group related values
    • Arrays - collections with compile-time fixed size or dynamic size
      • The types bytes and string are special arrays
    • Mappings - associate elementary type values with other values; like hash tables
  • Solidity functions can return multiple values.
  • Solidity functions can be modified with keywords.
    • public - can be called either internally or externally
    • internal - can only be called from within the contract or its descendants
    • private - can only be called from within the contract
    • external - cannot be called from within the contract
    • view - will not modify the state of the contract
    • pure - will not read or modify the state of the contract
    • payable - will accept any Ether sent to it
  • Each contract can have one fallback function.
    • Cannot take any arguments
    • Must be marked external
    • Executed if the contract is invoked without a function selector (as in a transfer of Ether) or if the function selector is invalid
    • Must be marked payable if the contract is to be able to receive Ether through regular transactions
  • Event types are defined in contracts and are inheritable.
  • Event instances are stored on the blockchain in transaction logs.
  • External applications can listen to contract events via the RPC log interface of an Ethereum client.
    • Log data is not accessible from within contracts.
  • Events can have up to three indexed attributes, which will be easily accessible via logs.
    • Attributes that are not indexed will be ABI-encoded into the log data.
  • A hash of the event’s signature will be written to the logs unless the event is anonymous.
    • Anonymous events are cheaper to deploy and call but cannot be filtered.
  • Log subscribers can filter by contract, event signature or indexed attributes.

Further Reading

💿 Remix Integrated Development Environment (IDE)

Remix is a powerful, open-source web IDE that allows users to write, debug, deploy and interact with Ethereum smart contracts straight from the browser.

Further Reading

web3.js

web3.js is the Javascript API for the Ethereum ecosystem.

  • web3.js is a collection of libraries for interacting with Ethereum nodes and related services.
    • web3.eth - tools for interacting with the Ethereum blockchain and Ethereum smart contracts
    • web3.eth.subscribe - tools for subscribing to Ethereum events
    • web3.eth.Contract - an object to abstract Ethereum smart contracts and expose their capabilities
    • web3.eth.accounts - functions to generate accounts and use them to sign transactions and data
    • web3.eth.abi - a library for ABI encoding and decoding
    • web3.utils - common utilities for Ethereum development, like hexadecimal encoding and decoding

🍄 Truffle

Truffle is framework for developing Ethereum smart contract projects.

Further Reading

OpenZeppelin

OpenZeppelin provides tools to write, deploy and operate decentralized applications on the Ethereum blockchain.

  • OpenZeppelin maintains a number of products for Ethereum development.
    • Contracts - an open-source collection of commonly reusable contracts
    • SDK - a toolkit for compiling, upgrading, deploying, and interacting with smart contracts
    • Starter Kits - templates for scaffolding dApps

💡 Ethereum Improvement Proposals (EIPs)

Ethereum Improvement Proposals (EIPs) describe standards for the Ethereum platform, including core protocol specifications, client APIs, and contract standards.

  • The EIP program is described in EIP-1.
  • EIPs are divided into types (and in some cases, sub-types).
    • Standard Track - improvements that affect Ethereum implementations or the interoperability of applications using Ethereum
      • Core - improvements related to “core dev” discussions including those requiring a consensus fork
      • Networking - improvements to networking protocols
      • Interface - improvements such as those to API/RPC specification or language-level standards
      • ERC (Ethereum Request for Comment) - application-level standards and conventions
    • Meta - official EIPs that do not relate to the Ethereum protocol or codebase
    • Informational - used to provide general information, like Ethereum design issues
    • There is an EIP life cycle comprised of multiple stages.
      • Draft - open EIPs undergoing rapid change
      • Last Call - a “finished” EIP that is ready for wide review
      • Accepted - an EIP that has been in the Last Call stage for at least two weeks and whose author has addressed any requested technical changes
        • For non-core EIPs this is the Final stage
      • Final - core EIPs that the core devs have decided will be (or already have been) released in a hard fork
  • An interface that describes basic functionality to transfer tokens as well as approve and facilitate transfers initiated by third-parties
  • Example: OpenZeppelin ERC20.sol
  • The ERC-20 standard defines several log event types.
    • Transfer(address indexed, address indexed, uint256) - log a transfer of a specified token amount from one account to another
      • Token contracts should log a Transfer event from account 0x0 when tokens are created.
    • Approval(address indexed, address indexed, uint256) - log an approval for one account to spend tokens from another account, up to some specified maximum value
  • The ERC-20 standard defines several required functions.
    • totalSupply() public view returns (uint256) - returns the total token supply
    • balanceOf(address) public view returns (uint256) - returns the token balance of the supplied account
    • transfer(address, uint256) public returns (bool) - transfers the specified amount of the token to the provided account
      • Must fire a Transfer event (even if amount is 0)
      • Should raise an error if sender’s balance is insufficient
    • transferFrom(address, address, uint256) public returns (bool) - transfers the specified amount of the token from one account to another
      • Should raise an error if the account to send funds from has not provided authorization to the caller of this function
    • approve(address, uint256) public returns (bool) - approve another account to withdraw tokens from your account, up to some provided maximum value
      • Must fire an Approval event
    • allowance(address, address) public view returns (uint256) - returns the amount of the token that one account is approved to withdraw on behalf of another
  • The ERC-20 standard defines several optional functions.
    • name() public view returns (string) - returns the name of the token
    • symbol() public view returns (string) - returns the symbol of the token
    • decimals() public view returns (uint8) - returns the maximum decimal precision supported by the token
  • This proposal, which was superseded by EIP 777, is motivated by one of the limitations of the EIP 20 specification.
    • The ERC-20 standard defines different semantics for transferring tokens to user and contract accounts.
    • To transfer ERC-20 tokens to a user account, the transfer function is used.
    • To transfer ERC-20 tokens to a contract account, a combination of the approve and transferFrom functions are used in order to approve the contract to transfer tokens on behalf of a user account.
    • If the transfer function is incorrectly used to send ERC-20 tokens to a contract account, those tokens may be "lost" forever because the contract may not have any capabilities to handle the tokens.
    • This is because, unlike a transfer of Ether, which invokes a smart contract function (the fallback function), transfers of ERC-20 tokens do not actually involve the receiver in any way.
    • Anecdotally, this limitation to the ERC-20 specification has resulted in hundreds-of-thousands in US dollars of ERC-20 tokens being rendered inaccessible.
  • In order to receive ERC-223 tokens, smart contract accounts must implement a function that is specified by this EIP.
    • tokenFallback(address, uint256, bytes) - meant to emulate the fallback function that is used for Ether transfers
    • When the tokenFallback function is invoked, msg.sender should refer to the address of the ERC-223 token.
    • The function's address parameter specifies the sender of the transfer and the uint parameter specifies the amount of the token to be transferred.
    • The final bytes parameter is optional and can be used to include data with a transfer, although this will cost additional gas.
  • EIP 223 is backwards-compatible with EIP 20.
  • ERC-223 token contracts must also implement a transfer(address, uint, bytes) function.
    • This function must always be called as part of a token transfer.
    • If the receiver address belongs to a contract account, this function must invoke the tokenFallback function on the receiver. If the tokenFallback function does not exist at the receiver address, then the transfer must fail.
    • The EIP provides a recommended way to check if an address belongs to a contract account.
  • Example: ERC-223 Reference Implementation
  • The ERC-20 standard defines an interface for fungible tokens. An asset is referred to as "fungible" if all instances of the asset are equal, like a one-dollar bill.
    • For fungible assets, it does not matter which instances of that asset someone controls; what matters is how much of that asset they control.
  • An example of a non-fungible asset is a property deed; although all instances of a given property deed type are "the same", the difference in value between two deeds may be enormous.
    • For non-fungible assets, it not only matters how many someone controls, but also which ones.
  • Instances of a non-fungible token (NFT) are distinguishable from one another and the ownership of each one must be tracked separately.
  • EIP 721 specifies an interface for NFTs that builds on the ERC-20 token standard.
    • In addition to providing capabilities to track individual tokens, the standard is designed to allow applications to efficiently handle large quantities of NFTs.
  • The ERC-721 standard specifies the use of a uint256 unique identifier for NFTs.
  • Although EIP 721 requires EIP 165, this requirement comes with a caveat and is not included in any of the proposal's reference implementations. The authors of EIP 721 explicitly state their support for an interface registry, such as that defined by EIP 1820.
  • Example: ERC-721 Reference Implementation

Receiver Function

  • Similar to EIP 223, EIP 721 specifies that contract accounts must implement a function in order to receive safe transfers of ERC-721 tokens.
  • onERC721Received(address, address, uint256, bytes) external returns(bytes4) - handles the receipt of an NFT
    • This interface specifies the account initiating the transfer as well as the account that previously owned the NFT, since these two values may not be equal.
    • When this function is invoked, msg.sender is always the address of the ERC-721 contract.
    • This function may throw an error in order for the contract to reject a transfer.
    • This function must return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")) or else the transfer will fail.
  • Note that contract accounts can still receive transfers of ERC-721 tokens if the transferFrom function is used (see below).
  • Approval(address indexed, address indexed, uint256 indexed) - logs that the account authorized to manage this NFT on behalf of its owner has been changed or reaffirmed
    • A zero-valued address indicates that no account is authorized to manage the NFT on behalf of its owner.
  • ApprovalForAll(address indexed, address indexed, bool) - logs that permission to manage all NFTs for a specified account has been enabled or disabled for another account
  • Transfer(address indexed, address indexed, uint256 indexed) - log a transfer in ownership of a specified NFT from one account to another
    • This event may be emitted when NFTs are created (transfers from account 0x0) and must be emitted when NFTs are destroyed (transfers to account 0x0).
    • A Transfer event implies that there are no longer any accounts authorized to manage the specified NFT on behalf of its owner.

Functions

  • balanceOf(address) external view returns (uint256) - returns the amount of an ERC-721 token owned by an account
    • If the address parameter is 0x0, this function will fail.
  • ownerOf(uint256) external view returns (address) - returns the account that owns a specified NFT
    • If the ID is that of an NFT that has been destroyed (owned by account 0x0), this function will fail.
  • setApprovalForAll(address, bool) external - enables or disables permission for an account to manage all NFTs on behalf of the account corresponding to msg.sender
    • This function must fire an ApprovalForAll event.
    • An account that has been authorized to manage all NFTs for another account is known as an "operator" of that account.
    • EIP 721 specifies that ERC-721 contracts must support multiple operators per account.
  • isApprovedForAll(address, address) external view returns (bool) - returns whether or not one account is an authorized operator for another
  • approve(address, uint256) external payable - change or reaffirm the account that is authorized to manage an NFT on behalf of its owner
    • If msg.sender is not equal to the current owner of the NFT or one of their authorized operators, this function will fail.
    • This function must log an Approval event.
  • getApproved(uint256) external view returns (address) - returns the account that is approved to manage the specified NFT on behalf of its owner
    • This function will fail if the token ID is invalid.
  • safeTransferFrom(address, address, uint256, bytes) external payable - transfers the ownership of a specified NFT from one account to another
    • This function will fail in the following scenarios:
      • msg.sender is not equal to the current owner of the NFT, the account specified as the "approved" account for this NFT or an authorized operator account for the NFT's owner
      • The parameter that specifies the account sending the transfer is not equal to the account that owns the NFT
      • The parameter that specifies the account receiving the transfer is 0x0
      • The token ID is invalid
    • This function will check if the receiving account is a contract account after it has completed the transfer and, if so, will call the onERC721Received function on that contract.
      • If onERC721Received does not return bytes4(keccak256("onERC721Received(address,uint256,bytes)")) this function will fail.
    • This function must log a Transfer event.
  • safeTransferFrom(address, address, uint256) external payable - an alias for the other safeTransferFrom function that sets the final parameter to ""
  • transferFrom(address, address, uint256) external payable - similar to safeTransferFrom(address, address, uint256) but without invoking onERC721Received on receivers that are contracts

Optional Metadata Extension

  • This extension to EIP 721 allows ERC-721 contracts to be interrogated for details about the token type as well as for details about individual tokens.
  • The EIP 721 Metadata Extension defines several functions.
    • name() external view returns (string) - returns a descriptive name for the collection of NFTs defined by the contract
    • symbol() external view returns (string) - returns an abbreviated name for the collection of NFTs defined by the contract
    • tokenURI(uint256 _tokenId) external view returns (string) - returns a distinct Uniform Resource Identifier (URI) for the specified NFT
      • If the token ID is invalid this function will fail.
      • The URI for an NFT may change from time-to-time.
      • The return value of this function is not usable on-chain, but the EIP authors justify that decision in the proposal.
  • This extension defines a JSON schema, which may be the target of URIs returned by the tokenURI function.
  • Example: Reference Implementation

Optional Enumeration Extension

  • This extension to EIP 721 allows ERC-721 contracts to publish their full collection of NFTs and make them discoverable.
  • The EIP 721 Enumeration Extension defines several functions.
    • totalSupply() external view returns (uint256) - returns the count of valid NFTs tracked by the contract
      • A valid NFT is one with an assigned and queryable owner that is not equal to 0x0.
    • tokenByIndex(uint256) external view returns (uint256) - returns the ID of the NFT at the specified index
      • If the specified index is greater than or equal to the value returned by totalSupply, this function will fail.
      • Note that this extension to the EIP 721 standard does not specify the sort order which is to be used for NFTs.
    • tokenOfOwnerByIndex(address, uint256) external view returns (uint256) - returns the ID of the NFT at the specified index for the specified owner
      • If the specified index is greater than or equal to the value returned by balanceOf(address), this function will fail.
      • If the specified owner account is 0x0, this function will fail.
  • Example: Reference Implementation
  • This proposal defines a new way to interact with a non-fungible token contract while remaining backwards-compatible with EIP 20.
    • This EIP states that ERC-20 functions should only be called from old contracts.
    • Applications must take care to not double-count token movement based on the ERC-20 and ERC777 log events of tokens that implement both standards.
    • Applications should consider tokens either ERC777 or ERC-20 but not both.
  • EIP 777 improves on EIP 20 by introducing operators and hooks.
    • These enhancements address the same issue as EIP 223, and this EIP supersedes the former EIP.
    • Operators are accounts that are authorized to manage tokens on behalf of another account.
      • Accounts may specify multiple operators.
      • ERC777 contracts may specify default operators.
        • If an ERC777 token specifies default operators, this value must be set when the token contract is created and may not ever be modified.
      • Account owners may authorize, revoke and reauthorize operators (including default operators).
      • Accounts are always considered operators for themselves and this cannot be revoked.
    • Hooks are function interfaces that are intended to offer token holders more control over their tokens.
  • This EIP requires EIP 1820.
    • ERC777 contracts must use the EIP 1820 registry to register the ERC777Token interface with their own address.
    • If an ERC777 contract has a switch to enable and disable the capabilities described by EIP 777, it must update the EIP 1820 registry accordingly.
    • If an ERC777 contract implements the ERC-20 standard, it must use the EIP 1820 registry to register the ERC20Token interface with its own address.
    • If an ERC777 contract has a switch to enable and disable its ERC-20 capabilities, it must update the EIP 1820 registry accordingly.
  • The design for this standard takes several considerations into account.
    • Token Life Cycle - a clearly-defined life cycle is important for consistency and accuracy, especially when token value is derived from scarcity
      • The ERC777 standard includes consideration for the minting, managing and destruction (burning) of tokens.
    • Data - allow token transfers to include a data component like the transfer of Ether
    • Hooks - offer token holders more control over their tokens
    • EIP 1820 Integration - EIP 1820 was, in fact, written to support this EIP
    • Operators - an idiomatic way to allow one account to control the tokens of another
  • The ERC777 standard requires that tokens support 18-points of decimal precision.
    • The ERC-20 decimals function is optional for ERC777 tokens, since the value returned by this function will be 18 for all ERC777 tokens.
  • EIP 777 specifies functions for managing account operators as well as sending and burning tokens. ERC777 tokens may expose other functions to address these features.
  • This EIP specifies that dApps and wallets should first estimate the gas required when sending, minting, or burning tokens by using eth_estimateGas to avoid running out of gas during the transaction.
  • This EIP includes a logo that may be used to promote valid implementations of the ERC777 standard.
  • One of the authors of this EIP submitted a more detailed version of this standard as his master thesis.
  • Example: OpenZeppelin ERC777

Hooks

  • tokensToSend(address, address, address, uint256, bytes, bytes) external - notifies the receiver of a request to decrease the balance of their account
    • This function is specified by the ERC777TokensSender interface.
    • This function specifies three addresses: from, operator and to.
      • If the to account is 0x0 then the tokens are being burned.
    • The final two parameters are for data and operatorData, respectively.
    • The value of msg.spender will be the address of an ERC777 token contract.
      • This function may be called from multiple token contracts.
    • This hook is optional for both user and contract accounts.
    • Accounts that wish to be notified of token debits may register the address of a contract implementing the ERC777TokensSender interface with the EIP 1820 registry.
      • If an account has registered an implementation of this function, the token contract must call it when sending or burning tokens from the account.
      • An account may block a send or burn of tokens by throwing an error in this hook.
    • This function will be called before updating the state of the token contract, i.e. before the account balance of the receiver has been decreased.
    • This function, if specified, must be called when ERC777 tokens are sent by way of the ERC-20 transfer or transferFrom functions.
    • This function must not be called outside of a burn or send (or ERC-20 transfer) process.
    • One implementation of this function may be shared by multiple accounts.
  • tokensReceived(address, address, address, uint256, bytes, bytes) external - notifies the receiver of an increase to the balance of their account
    • This function is specified by the ERC777TokensRecipient interface.
    • This function specifies three addresses: from, operator and to.
      • If the from account is 0x0 then the tokens are being minted.
    • The final two parameters are for data and operatorData, respectively.
    • The value of msg.spender will be the address of an ERC777 token contract.
      • This function may be called from multiple token contracts.
    • Contract accounts must implement this function if they wish to receive ERC777 tokens when they are minted or transferred using the send function.
      • Contract accounts that do not implement this function may still receive ERC777 tokens by other means (e.g. ERC-20 transfer).
    • Accounts that wish to be notified of token transfers may register the address of a contract implementing the ERC777TokensRecipient interface with the EIP 1820 registry.
      • If an account has registered an implementation of this function, the token contract must call it when sending or minting tokens to the account.
      • An account may block a send or mint of tokens by throwing an error in this hook.
    • This function will be called after updating the state of the token contract, i.e. after the account balance of the receiver has been increased.
    • This function, if specified, must be called when ERC777 tokens are sent by way of the ERC-20 transfer or transferFrom functions.
    • This function must not be called outside of a mint or send (or ERC-20 transfer) process.
    • One implementation of this function may be shared by multiple accounts.
  • Sent(address indexed, address indexed, address indexed, uint256, bytes, bytes) - logs that tokens have been sent from one account to another
    • This event specifies three addresses: from, operator and to.
    • This event must not be logged outside of a send (or ERC-20 transfer) process.
    • ERC777 tokens must log Sent events from the ERC-20 transfer and transferFrom functions.
    • A single operation on the token contract may result in the logging of multiple Sent events.
      • An example use case that involves logging multiple Sent events is a token contract that applies a fee when tokens are sent; in this case, there must be a Sent event for the recipient of the transfer as well as one for the recipient of the transfer fee.
      • A Sent event must be logged for each from-to pair with a value that is equal to amount for that pair.
      • The sum of the values specified by all Sent events must be equal to the total amount sent.
  • Minted(address indexed, address indexed, uint256, bytes, bytes) - logs that tokens have been minted and sent from an account by an operator account
    • This event must not be logged outside of the minting process.
    • A single operation on the token contract may result in the logging of multiple Minted events.
      • A Minted event must be logged for each token recipient.
      • The sum of the values specified by all Minted events must be equal to the total amount minted.
  • Burned(address indexed, address indexed, uint256, bytes, bytes) - logs that tokens have been burned from an account by an operator account
    • A single operation on the token contract may result in the logging of multiple Burned events.
      • A Burned event must be logged for each token holder.
      • The sum of the values specified by all Burned events must be equal to the total amount burned.
  • AuthorizedOperator(address indexed, address indexed) - logs that one account has been authorized as an operator for another account
    • This event will not be logged if default operators are set when an ERC777 contract is created.
    • This event must not be logged outside of the operator authorization process.
  • RevokedOperator(address indexed, address indexed) - logs that one account has had its authorization as operator for another account revoked
    • This event must not be logged outside of the operator revocation process.

Functions

  • name() external view returns (string) - returns the name of the token
  • symbol() external view returns (string) - returns the symbol of the token
  • totalSupply() external view returns (uint256) - returns the total number of tokens in existence
    • The value returned by this function must equal the sum of the balances of all accounts, which must be equal to the sum of all minted tokens minus the sum of all burned tokens.
  • balanceOf(address) external view returns (uint256) - returns the amount of the token owned by an account
  • granularity() external view returns (uint256) - returns the maximum granularity supported by the token
    • The granularity is a constant, positive number that is set when an ERC777 contract is constructed
    • Tokens must always be minted and burned in amounts that are multiples of the granularity.
    • Any operation that would result in an account having a token balance that is not a multiple of the granularity must result in error.
    • This EIP specifies that tokens should use a granularity of 1 unless there is a compelling reason otherwise.
  • defaultOperators() external view returns (address[]) - returns the list of default operators; a token contract with no default operators will return an empty list
  • isOperatorFor(address, address) external view returns (bool) - returns whether one account is an operator for another
    • In order for an application to determine all authorized operators for an account, it must call this function once for each default operator and parse all AuthorizedOperator and RevokedOperatorevents for the account.
  • authorizeOperator(address) external - authorize an account as an operator for the account specified by msg.sender
    • If the address parameter is equal to the value of msg.sender, this function will fail.
    • This function may be used to reaffirm the authorization of an operator for the account of the message sender.
    • This function must log an AuthorizedOperator event.
  • revokeOperator(address) external - revoke authorization from an account to act as operator for the account specified by msg.sender
    • If the address parameter is equal to the value of msg.sender, this function will fail.
    • This function may be used to reaffirm that an account is not authorized as an operator for the account of the message sender.
    • This function must log an RevokedOperator event.
  • send(address, uint256, bytes) external - sends a specified amount of tokens from the account specified by msg.sender to another account
    • Calling this function will cause the balance of the sender's account to decrease by the specified amount and the balance of the recipient's account to increase by the same amount.
    • The semantics of this function are meant to emulate a fallback function and the final parameter can be used to include data with a token transfer.
    • If the sender has specified a tokensToSend hook per the EIP 1820 registry, this function must invoke it before updating the state of the token contract.
    • If the receiver has specified a tokensReceived hook per the EIP 1820 registry, this function must invoke it after updating the state of the token contract.
    • This function will fail in the following scenarios:
      • Transferring the specified amount of tokens would cause any account balance to no longer be a multiple of the token's granularity
      • The recipient of the transfer is a contract that does not specify an implementation of the ERC777TokensRecipient interface per the EIP 1820 registry
      • The recipient of the transfer is account 0x0
      • Transferring the specified amount of tokens would cause the balance of the sender's account to become negative
      • Any of the hooks invoked by this function fail
    • This function must log a Sent event.
    • For tokens that also implement the ERC-20 standard, this function must log a Transfer event.
  • operatorSend(address, address, uint256, bytes, bytes) external - sends a specified amount of tokens from one account to another
    • This function is only different from the send function in a few ways.
      • The account from which tokens are sent may not be the same as that specified by msg.sender.
      • The function signature includes an additional parameter for operatorData.
      • If the account specified by msg.sender is not an authorized operator for the account to send tokens from, this function will fail.
    • If the account specified by msg.sender is equal to the account to send tokens from, invoking this function must have the same effects as invoking the send function.
    • This EIP specifies that the value of operatorData must only be provided by the operator. Furthermore, it states that it is intended mostly for logging purposes.
  • burn(uint256, bytes) external - burn a specified amount of tokens from the account specified by msg.sender
    • If the account from which tokens are being burned has specified a tokensToSend hook per the EIP 1820 registry, this function must invoke it before updating the state of the token contract.
    • This function must log a Burned event.
    • For tokens that also implement the ERC-20 standard, this function should log a Transfer event.
  • operatorBurn(address, uint256, bytes, bytes) external - burn a specified amount of tokens from a specified account
    • This function is only different from the burn function in a few ways.
      • The account from which tokens are burned may not be the same as that specified by msg.sender.
      • The function signature includes an additional parameter for operatorData.
      • If the account specified by msg.sender is not an authorized operator for the account to burn tokens from, this function will fail.
    • If the account specified by msg.sender is equal to the account to send tokens from, invoking this function must have the same effects as invoking the burn function.
    • This EIP specifies that the value of operatorData must only be provided by the operator.

Minting Tokens

  • In order to support the greatest number of use cases, this EIP does not define any functions that mint tokens.
  • Tokens must be minted in quantities that are multiples of the token contract's granularity.
  • Tokens may be minted for any account except 0x0.
  • Minting tokens may not decrease the balance of account 0x0.
  • Minting a given amount of tokens must result in an equivalent increase in the value returned by the totalSupply function.
  • Minting a given amount of tokens must result in an equivalent increase in the balances of the recipient accounts.
  • The token contract must log one Minted event for each recipient account.
  • Tokens that also implement the ERC-20 standard should log at least one Transfer event when tokens are minted.
  • The token contract must call the tokensReceived hook of each of the recipients if they have registered an ERC777TokensRecipient implementation per the EIP 1820 registry.
    • If a recipient account is a contract, it must provide an ERC777TokensRecipient implementation.
    • If a tokensReceived hook fails, so will the minting function.
  • The values of data and operatorData must be equal for all tokensReceived hooks and Minted log events that are part of a single mint operation.
  • When an ERC777 contract is created, it must log Minted events and invoke tokensReceived hooks for all recipients of its initial supply.
  • EIP 777 specifies that minting an amount of zero tokens is valid.
  • Unlike sending or burning a token, tokens that are minted do not originate from a holder account, so the data sent to the tokensReceived hook and Minted event may be interpreted as originating from the token contract or operator.
  • A method to publish and detect what interfaces a smart contract implements by establishing several standards:
    • Interface identification
    • Publication of implemented interfaces
    • Detection of support for the ERC-165 standard
    • Detection of support for any given interface
  • An interface’s identifier is calculated as the XOR (exclusive-or) of the function selectors that define the interface.
  • Smart contracts that are compliant with the ERC-165 standard must implement a function that is specified in the EIP.
    • function supportsInterface(bytes4 interfaceID) external view returns (bool);
    • Must return true when called with the ID of any interface the implementing smart contract supports, including the ID of the detection function (0x01ffc9a7)
    • Must return false when called with the ID of any interface the implementing smart contract does not support, or the special value 0xffffffff
    • Must not use more than 30,000 gas
  • The EIP specifies a procedure for checking if a smart contract implements this standard as well as example implementations of the supportsInterface function.
  • Defines a fully-decentralized universal registry smart contract where any Ethereum account can register which interfaces it supports and which smart contracts are responsible for their implementations
  • Addresses limitations of previous approaches: EIP165, EIP672
    • Backwards-compatible with EIP165
  • The registry associates Ethereum addresses with the interfaces that they implement and the addresses of the implementations.
    • Interface identifers are generated by hashing the interface name.
    • The EIP specifies standards for interface names, as well as a hashing standard (keccak256).
    • The registry contract provides a helper function to generate the hash for an interface name.
  • For any given address, there is exactly one address that can update its corresponding values in the registry; the latter address is referred to as the "manager" of the former address.
    • Initially, an address is its own manager.
    • The registry exposes a function that allows an address's manager to transfer this role at any time.
  • Any contract that implements an interface on behalf of another address must implement an additional function: canImplementInterfaceForAddress(bytes32, address) external view returns(bytes32).
    • In order to indicate that the contract implements the provided interface for a given address, this function must return a special sentinel value, which the EIP defines as keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC")).
  • The EIP specifies a standard deployment protocol for the registry contract along with the definition of the registry.
    • The registry is deployed using a single-use address, for which no one knows the private key.
    • The address of the registry contract is identical for every chain on which it is deployed, 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24.
// TODO
// TODO
// TODO

🚀 The Ethernaut

The Ethernaut is a Web3/Solidity based wargame inspired on overthewire.org, played in the Ethereum Virtual Machine. Each level is a smart contract that needs to be 'hacked'.