From c10d2c46f1ed7e932b158f04ae975859d25d19f3 Mon Sep 17 00:00:00 2001 From: lash Date: Sat, 13 May 2023 20:42:47 +0100 Subject: [PATCH] Add readme from texinfo docbook intermediary --- Makefile | 4 + README.md | 741 +++++++++++++++++++++++++++++++++++++++++++ doc/texinfo/Makefile | 2 + 3 files changed, 747 insertions(+) create mode 100644 README.md diff --git a/Makefile b/Makefile index b0bd8cf..36d252b 100644 --- a/Makefile +++ b/Makefile @@ -40,4 +40,8 @@ doc: bash texify.sh make -C doc/texinfo +readme: + make -C doc/texinfo readme + pandoc -f docbook -t gfm doc/texinfo/build/docbook.xml > README.md + .PHONY: clean install diff --git a/README.md b/README.md new file mode 100644 index 0000000..17d75ae --- /dev/null +++ b/README.md @@ -0,0 +1,741 @@ +# Smart contract interfaces + +## Technology + +CIC smart contracts are implemented using the *solidity* programming +language for the (Ethereum Virtual Machine (EVM). + +## Adopted standards + +### Signing + +### ERC - Direct use + +The following well-known solidity interfaces are used directly. + +- [ERC20 - Token Standard](https://eips.ethereum.org/EIPS/eip-20) + +- [ERC165 - Standard Interface + Detection](https://eips.ethereum.org/EIPS/eip-165) + +- [ERC173 - Contract Ownership + Standard](https://eips.ethereum.org/EIPS/eip-173) + +- [ERC191 - Signed Data + Standard](https://eips.ethereum.org/EIPS/eip-191) + +- [ERC712 - Typed structured data hashing and + signing](https://eips.ethereum.org/EIPS/eip-712) + +- [ERC721 - Non-Fungible Token + Standard](https://eips.ethereum.org/EIPS/eip-721) + +- [ERC5007 - Time NFT (EIP-721 Time + Extension)](https://eips.ethereum.org/EIPS/eip-5007) + +- [ERC5192 - Minimal Soulbound + NFTs](https://eips.ethereum.org/EIPS/eip-5192) + +### ERCs Partial use + +The following well-known solidity interfaces are partially implemented +in CIC native interfaces. + +- [ERC5679 - Token Minting and + Burning](https://eips.ethereum.org/EIPS/eip-5679) (See `Minter`, + `Burner`) + +## Native interfaces + +### Accounts Index + +Append-only list of addresses. Typically used for access control lists. + +Addresses may be *added*, *removed*, aswell as *deactivated* and +*activated*. Deactivated accounts still count towards the `entryCount`. + +The `entry` method is used to iterate the account list. The order of +which accounts are returned is not guaranteed. Any returned value +matching `address(0x00)` should be skipped, and not counted towards +`entryCount`. + +May optionally record time when account was added. + +ERC165 Interface identifier +b7bca625 + +Solidity interface definition + interface IAccountsIndex { + // Address added to store, index in array. + event AddressAdded(uint256 indexed _idx, address _account); + + // Return number of entries in index. + function entryCount() external view returns (uint256); + + // Return entry at the spceificed index. + // Will revert if index is beyond array length. + // An entry result of 0 means the entry should be skipped, and not count towards entry count. + function entry(uint256) external view returns (address); + + // Add an entry to the index. Incresases the entry count. + function add(address) external returns (bool); + + // Verify that the entry exists in the index. + function have(address) external view returns (bool); + + // Retrieve the timestamp when account was added. + // If time is not being tracked, a value of 0 should be returned. + function time(address) external view returns (uint256); + } + +Reference implementation + (v0.5.1) + +### Accounts Index Mutable + +Extends the functionality of `Accounts Index` to allow changes to the +address list. + +Addresses may be *added*, *removed*, aswell as *deactivated* and +*activated*. Deactivated accounts still count towards the `entryCount`. + +ERC165 Interface identifier +9479f0ae + +Solidity interface definition + interface IAccountsIndexMutable { + // Active status of address changed, and by whom changed. + event AddressActive(address indexed _account, bool _active); + + // Address removed from store, and by whom removed. + event AddressRemoved(address _account); + + // Remove an entry from the index. Reduces the entry count. + function remove(address) external returns (bool); + + // Deactivate account but keep in index. Does not affect entry count. + function deactivate(address) external returns (bool); + + // Activate previously deactivated account. Does not affect entry count. + function activate(address) external returns (bool); + + // Check if account exists and is active; + function isActive(address) external view returns (bool); + } + +Reference implementation + (v0.5.1) + +### Burner + +Attached to `ERC20` and `ERC721` tokens that may be *burned*. + +Implements the `burn(...)` part of `ERC5679` for interoperability. + +ERC165 Interface identifier +bc4babdd + +Solidity interface definition + interface IBurner { + // Token(s) successfully burned; by who and how much. + event Burn(address indexed _burner, uint256 _burned); + + // Satisfies ERC 5679 + function burn(address _from, uint256 _amount, bytes calldata _data) external; + + // Burn given amount of tokens held by signer. + function burn(uint256 _burn) external returns (bool); + + // Burn all tokens held by signer. + function burn() external returns (bool); + + // Total amount of tokens that have been burned. + function totalBurned() external returns (uint256); + + // Total amount of tokens ever minted. + // If totalSupply() is available (ERC20, ERC721 Enumerable), this equals totalSupply() + totalBurned(). + function totalMinted() external returns (uint256); + } + +Example implementation + + +### Chrono + +Define a creation time for a resource. + +Complements `ERC5007`. + +ERC165 Interface identifier +4db1ccd4 + +Solidity interface definition + interface IChrono { + // Returns the timestamp of when a resource corresponding to _idx was first created. + // int64 chosen as return value for simpler interoperability with ERC5007. + function createTime(uint256 _idx) external returns(int64); + } + +Example implementation + (BadgeToken contract) + +### Declarator + +Permissionless store of signed claims made by an address about other +addresses, or addresses about themselves. + +It is used to declare or respond to certifications of vouchers, NFT, +voucher members. + +Addresses may be Externally Owned Accounts or smart contracts. + +Claims may be made with or without topics. A missing topic is synonymous +with a topic value of `bytes32(0x00)`. + +Any number of claims can be made about an address under any number of +topics. All claims must be stored, and returned in the order which they +were added. + +ERC165 Interface identifier +21b7493b + +Solidity interface definition + interface IDeclarator { + event DeclarationAdded(address indexed _declarator, address indexed _subject, bytes32 indexed _topic, bytes32 _proof); + + // Get all declarations for a subject (without topic) signed by a declarator + function declaration(address _declarator, address _subject) external view returns ( bytes32[] memory ); + + // Get all declarations for a subject for the given topic signed by a declarator + function declaration(address _declarator, address _subject, bytes32 _topic) external view returns ( bytes32[] memory ); + + // Get number of declarations the declarator has ever signed + function declarationCount(address _declarator) external view returns ( uint256 ); + + // Get the subject of a declarator's declarations at the specific index + function declarationAddressAt(address _declarator, uint256 _idx) external view returns ( address ); + + // Add a declaration for the subject + function addDeclaration(address _subject, bytes32 _proof) external returns ( bool ); + + // Add a declaration with topic for the subject + function addDeclaration(address _subject, bytes32 _proof, bytes32 _topic) external returns ( bool ); + + // Get the declarator that signed a declaration at the specificed index for a subject + function declaratorAddressAt(address _subject, uint256 _idx) external view returns ( address ); + + // Get the number of declarators that have signed for a subject + function declaratorCount(address _subject) external view returns ( uint256 ); + } + +Reference implementation + + +### Digest + +Allows encoding of digests according to a specific encoding scheme. + +Primary use-case is the abstraction of self-describing +[Multhash](https://multiformats.io/multihash/) encoding. + +A default encoding *must* always be defined, and the encoding of a valid +digest *must* succeed with the default encoding. + +ERC165 Interface identifier +982ab05d + +Solidity interface definition + interface IDigest { + // Returns the default digest encoding used by the contract instance. + function defaultDigestEncoding() external view returns (uint256 _encoding); + + // Check if the given encoding has been implemented in the contract instance. + function haveDigestEncoding(uint256 _codec) external view returns(bool); + + // Verify and encode the given digest for a specific hashing algorithm. + // Returns a zero-length byte array if digest is invalid. + // Must succeed if called with the defaultDigestEncoding and a valid digest. + function encodeDigest(bytes memory _data, uint256 _encoding) external view returns (bytes memory); + + // Encodes the digest using the default digest encoding. + // Returns a zero-length byte array if digest is invalid. + // Must succeed with a valid digest. + function encodeDigest(bytes memory _data) external view returns (bytes memory); + } + +Example implementation + + +### Expire + +Defines an expiry time after which token balances or supply *cannot +change*. + +A contract defining an expiry *must not* allow changing the expiration +time to a time in the past. + +ERC165 Interface identifier +841a0e94 + +Solidity interface definition + interface IExpire { + // Contract has expired. + event Expired(uint256 _timestamp); + + // Expiry time has changed. + event ExpiryChange(uint256 indexed _oldTimestamp, uint256 _newTimestamp); + + // The current expiration timestamp. + function expires() external returns (uint256); + + // Check expiry and apply expiration if expired. + // Return values must be: + // 0: not yet expired. + // 1: already expired. + // >1: expiry executed. + function applyExpiry() external returns(uint8); + } + +Example implementation + + +### Faucet + +Used for dispensing tokens to any address. + +It can be used for gas tokens and *ERC20* alike. + +The interface is the same whether the faucet is dispensing from existing +balance or minting new tokens. + +The value dispersed *must* be the same for all addresses. + +In general, four criteria are expected to exist in any combination for +limiting access to the faucet: + +Time +A recipient may only use the faucet again after some time has passed. + +Balance threshold +A recipient may only use the faucet after its balance is below a certain +amount. + +Membership +A recipient may only use the faucet if it has been added to an access +control list. + +Capacity +The contract has sufficient token funds to dispense the current defined +amount to dispense. + +The *check(address)* contract call *must* evaluate all four criteria, +and *must* return `false` if any of the criteria are not met. + +ERC165 Interface identifier +1a3ac634 + +Solidity interface definition + interface IFaucet { + // Tokens were given to an address + event Give(address indexed _recipient, address indexed _token, uint256 _value); + + // The amount that the faucet disperses has changed + event FaucetAmountChange(uint256 _value); + + // Address of token the faucet represents + // The faucet will return gas tokens with the zero-address is returned. + function token() external returns (address); + + // Amount of tokens the faucet gives out + function tokenAmount() external returns (uint256); + + // Give tokens to the given recipient. Returns amount of tokens given. + function giveTo(address _recipient) external returns (uint256); + + // Give tokens to yourself. Returns amount of tokens given. + function gimme() external returns (uint256); + + // Check if faucet may be used in the current contract state by _recipient + function check(address _recipient) external view returns (bool); + + // Returns timestamp when faucet may be used again by _recipient + // If 0 is returned, the address has not yet been used. + // A return value of max(uint256) indicates that the faucet may not be used again. + function nextTime(address _recipient) external returns (uint256); + + // Returns the token balance under which faucet may be used again by _recipient + // A return value of max(uint256) indicates that the faucet may be used regardless + // of the token balance of _recipient + function nextBalance(address _recipient) external returns (uint256); + } + +Reference implementations +- + +- + +### Locator + +This interface supports `ERC721 Metadata`, in particular the +`tokenURI(uint256)` call. + +Off-chain resources in the CIC network *must* be defined in terms of +content addressed strings. + +It *must* be possible to refer to all off-chain resources directly by +the content address. + +Furthermore, it *should* be possible to refer to a resource by a +fully-qualified location on the web or an overlay network (e.g. tor). + +ERC165 Interface identifier +ed75b333 + +Solidity interface definition + interface ILocator { + // URI that may or may not point to a specific resource location. + function toURI(bytes memory _data) external view returns (string memory); + + // URL pointing to a specific resource location. + function toURL(bytes memory _data) external view returns(string memory); + } + +Example implementation + + +#### Expressing locators in terms of numetic token id + +Given the numeric token id `1234567890987654321` (`0x112210f4b16c1cb1` +hex), and a base url `https://contentgateway.grassecon.net`, the result +of the methods may be as follows: + +`toURI(toHex(1234567890987654321))` +-\> +`https://contentgateway.grassecon.net/000000000000000000000000000000000000000000000000112210f4b16c1cb1` + +`toURL(toHex(1234567890987654321))` +-\> +`https://contentgateway.grassecon.net/000000000000000000000000000000000000000000000000112210f4b16c1cb1` + +`tokenURI(1234567890987654321)` +-\> +`https://contentgateway.grassecon.net/000000000000000000000000000000000000000000000000112210f4b16c1cb1` + +#### Expressing locators in terms of a digest + +Given the data `foo`, the digest algorithm `sha256` and a base url +`https://contentgateway.grassecon.net`, the result of the methods may be +as follows: + +`toURI(sha256(foo))` +-\> +`"sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"` + +`toURL(sha256(foo))` +-\> +`"https://contentgateway.grassecon.net/2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"` + +`tokenURI(toUint(sha256(foo)))` +-\> +`"https://contentgateway.grassecon.net/2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"` + +#### Locator without URL + +Given the data `foo`, the digest algorithm `sha256` and no base url, the +result of the methods may be as follows: + +`toURI(sha256(foo))` +-\> +`"sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"` + +`toURL(sha256(foo))` +-\> `""` + +`tokenURI(toUint(sha256(foo)))` +-\> +`"sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"` + +### Minter + +Attached to `ERC20` and `ERC721` tokens that may be minted. + +Implements the `mint(...)` and `safeMint(...)` parts of `ERC5679` for +interoperability. + +ERC165 Interface identifier +5878bcf4 + +Solidity interface definition + interface IMinter { + // Tokens are successfully minted; by who, to whom and how much + event Mint(address indexed _minter, address indexed _beneficiary, uint256 value); + + // Mint the specified value of tokens to the specified recipient + function mintTo(address _beneficiary, uint256 value) external returns (bool); + + // Satisfies ERC5679 for ERC20 + function mint(address _beneficiary, uint256 value, bytes calldata _data) external; + + // Satisfies ERC5679 for ERC721 + function safeMint(address _beneficiary, uint256 value, bytes calldata _data) external; + } + +Example implementation + + +### Msg + +Enables a reference "message" to describe the contract using an +off-chain resource. + +The reference may or may not be mutable. + +The interface complements `Locator` and `MultiHash` to generate locators +for how to resolve the reference. + +ERC165 Interface identifier +a3002595 + +Solidity interface definition + interface IMsg { + // Emitted when a new message digest has been set + // Should not be emitted if the digest set is identical to the previous + event Msg(bytes _msgDigest); + + // Get the current message content hash + function getMsg() external view returns(bytes memory); + } + +Example implementation + + +### Registry + +The Registry interface is a key-value store resolving well-known +contract identifier names to contract addresses. + +It currently has two distinct uses in the CIC context: + +1. Entry-point to discover all relevant contracts of CIC networks. + +2. Unique (ERC20) token symbol resolver. + +ERC165 Interface identifier +effbf671 + +Solidity interface definition + interface IRegistryClient { + // Address added to store with the given key + event AddressKey(bytes32 indexed _key, address _address); + + // Return the address of the contract identified by the given byte string + function addressOf(bytes32) external view returns (address); + + // Indexed accessor for the full list of registred identifiers + function identifier(uint256) external view returns (bytes32); + + // Number of registered interfaces + function identifierCount() external view returns (uint256); + } + +Contract registry implementation + + +Token index implementation + + +### Seal + +Some smart contract parameters may need to be mutable over part of a +smart contract’s lifetime. + +This interface provides a method to explicitly signal when certain +parameters have been rendered immutable. + +The value of `sealState()` *must not* decrease, and must not exceed +`maxSealState`. + +`maxSealState` is used to define that *all mutable parameters* have been +rendered immutable. The practical implications of this will vary between +contracts. + +The implementer is encouraged to use simple, descriptive names in the +source code to describe the applicable seal states. + +Use cases of sealing include: + +- Whether more tokens can be minted + +- Allow ownership of a contract to be transferred + +- The expiry time of a token (see `Expire`) + +ERC165 Interface identifier +0d7491f8 + +Solidity interface definition + interface ISeal { + // Seal state has changed. + event SealStateChange(bool indexed _final, uint256 _sealState); + + // The current seal state. + function sealState() external view returns(uint256); + + // The numeric seal state in everything sealable has been sealed. + function maxSealState() external view returns(uint256); + } + +Example implementation + + +### TokenVend + +This interface defines the mechanism for which a specific ERC20 token +may be exchanged for a different ERC20 token. + +A typical use-case is generation of voting tokens based on a momentary +voucher balance. This is especially useful if the original ERC20 token +is subject to decay (demurrage). + +The tokens used for exchange **SHOULD** be locked for the full duration +of holding the vended tokens. + +The withdrawal function may or may not allow partial withdrawals. + +ERC165 Interface identifier +8a13249c + +Solidity interface definition + interface ITokenVend { + // A new vended token has been created. + event TokenCreated(uint256 indexed _tokenIdx, uint256 indexed _supply, address _token); + + // Create corresponding vended tokens for the control token balance of the caller. + function getFor(address _token) external returns (uint256); + + // Recover control tokens that were used to retrieve the corresponding vended tokens. + function withdrawFor(address _token) external returns (uint256); + } + +Reference implementations +- + +### TokenVote + +Execute elections with granular ERC20 token votes. + +A proposal submitted for vote may or may not contain multiple options. +If multiple options are available, an ERC20 token holder may distribute +its vote among the options with the granularity of the token balance. + +Voted tokens **SHOULD** be locked until the voting has finalized. + +Finalization of voting should be callable by anyone. + +ERC165 Interface identifier +28091366 + +Solidity interface definition + interface ITokenVote { + + // A new proposal has been created. + event ProposalAdded(uint256 indexed _blockDeadline, uint256 indexed voteTargetPpm, uint256 indexed _proposalIdx); + + // A proposal vote has been completed. + // The proposal is identified by the serial number in _proposalIdx. It is up to the implementer to define how the proposal should be retrieved by index. + // The proposal result may be in one of three states: + // * Ratified (_cancelled == false, _insufficient == false) + // * Cancelled (_cancelled == true, _insufficient == false) + // * Not reached quorum (_cancelled == false, _insufficient == true) + event ProposalCompleted(uint256 indexed _proposalIdx, bool indexed _cancelled, bool indexed _insufficient, uint256 _totalVote); + + // Propose a new vote. + // Voting is active until one of: + // * total cancel vote reach quorum (_targetVotePpm, ppm = parts-per-million). + // * _blockWait blocks from now. + function propose(bytes32 _description, uint256 _blockWait, uint24 _targetVotePpm) external returns (uint256); + + // Same as propose(...), but provide options to vote on. + function proposeMulti(bytes32 _description, bytes32[] memory _options, uint256 _blockWait, uint24 _targetVotePpm) external returns (uint256); + + // Get number of options available for the proposal. + // This decides the boundary of the index that can be used with voteOptions(...) + // If the result is 0, vote(...) can be used aswell. + function optionCount(uint256 _proposalIdx) external view returns(uint256); + + // Get proposal option. Assumes that proposal was created with proposeMulti(...) + function getOption(uint256 _proposalIdx, uint256 _optionIdx) external view returns (bytes32); + + // Get vote count for the given option. + // If proposal has no options, it should be called with _optionIdx = 0 + function voteCount(uint256 _proposalIdx, uint256 _optionIdx) external view returns(uint256); + + // Vote on a proposal without options. + // Assumes that proposal was created with propose(...) and will fail otherwise. + function vote(uint256 _value) external returns (bool); + + // Vote on a proposal option. Assumes that proposal was created with proposeMulti(...). + // Must work with a non-option proposal if _optionIndex is 0. + function voteOption(uint256 _optionIndex, uint256 _value) external returns (bool); + + // Vote to cancel a proposal. + // If cancel has the majority: + // * A vote without options will have rejected the proposal description. + // * A vote with options will have rejected the proposal description as well as all option descriptions. + function voteCancel(uint256 _value) external returns (bool); + + // Finalize the vote for a proposal. + // May be called if deadline has been passed, or if: + // * quorum has been reached with cancel votes. + // * quorum has been reached and proposal has no/only one option. + function finalize() external returns (bool); + } + +Reference implementations +- + +### Writer + +A complement to ERC173, which allows definition of a class of +super-users for a contract. + +A super-user address may perform *more* actions than a "normal" address, +aswell as *some* actions normally limited to the *contract owner*. + +If an *contract owner* is defined, No super-user should be able to +perform actions that *contract owner* cannot perform. + +Typically, only the *contract owner*, if it is defined, can add or +remove a super-user. + +Some use-case examples of super-user actions include: + +- Mint new tokens. + +- Change the amount dispensed by the faucet. + +- Edit access control lists. + +ERC165 Interface identifier +abe1f1f5 + +Solidity interface definition + interface IWriter { + // A writer has been added by _executor + event WriterAdded(address _writer); + + // A writer has been removed by _executor + event WriterDeleted(address _writer); + + // Add a new writer to the contract. + function addWriter(address _writer) external returns (bool); + + // Remove existing writer from the contract. + function deleteWriter(address _writer) external returns (bool); + + // Check whether the given address is a writer. + function isWriter(address _writer) external returns (bool); + } + +Example implementation + diff --git a/doc/texinfo/Makefile b/doc/texinfo/Makefile index 49c9710..e78e827 100644 --- a/doc/texinfo/Makefile +++ b/doc/texinfo/Makefile @@ -1,3 +1,5 @@ all: makeinfo --html index.texi +readme: + makeinfo --docbook --no-split -o build/docbook.xml index.texi