diff --git a/README.md b/README.md
index 22ca5eb81..5173d802b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,35 @@
-# centre-tokens
-
-Fiat tokens on the [CENTRE](https://centre.io) network.
+
+
+# Circle's Stablecoin Smart Contracts on EVM-compatible blockchains
+
+
+This repository contains the smart contracts used by
+[Circle's](https://www.circle.com/) stablecoins on EVM-compatible blockchains.
+All contracts are written in [Solidity](https://soliditylang.org/) and managed
+by the [Truffle](https://trufflesuite.com/) framework.
+
+
+
+## Table of contents
+
+
+- [Setup](#setup)
+ - [Development Environment](#development-environment)
+ - [IDE](#ide)
+- [Development](#development)
+ - [TypeScript type definition files for the contracts](#typescript-type-definition-files-for-the-contracts)
+ - [Linting and Formatting](#linting-and-formatting)
+ - [Testing](#testing)
+- [Deployment](#deployment)
+- [Contracts](#contracts)
+- [FiatToken features](#fiattoken-features)
+ - [ERC20 compatible](#erc20-compatible)
+ - [Pausable](#pausable)
+ - [Upgradable](#upgradable)
+ - [Blacklist](#blacklist)
+ - [Minting/Burning](#mintingburning)
+ - [Ownable](#ownable)
+- [Additional Documentations](#additional-documentations)
## Setup
@@ -11,9 +40,9 @@ Requirements:
- Node 16.14.0
- Yarn 1.22.19
-```
-$ git clone git@github.com:centrehq/centre-tokens.git
-$ cd centre-tokens
+```sh
+$ git clone git@github.com:circlefin/stablecoin-evm.git
+$ cd stablecoin-evm
$ nvm use
$ npm i -g yarn@1.22.19 # Install yarn if you don't already have it
$ yarn install # Install dependencies
@@ -24,25 +53,27 @@ $ yarn install # Install dependencies
We recommend using VSCode for the project here with these
[extensions](./.vscode/extensions.json) installed.
-## TypeScript type definition files for the contracts
+## Development
+
+### TypeScript type definition files for the contracts
To generate type definitions:
-```
+```sh
$ yarn typechain
```
-## Linting and Formatting
+### Linting and Formatting
To check code for problems:
-```
+```sh
$ yarn static-check # Runs a static check on the repo.
```
or run the checks individually:
-```
+```sh
$ yarn typecheck # Type-check TypeScript code
$ yarn lint # Check JavaScript and TypeScript code
$ yarn lint --fix # Fix problems where possible
@@ -52,33 +83,33 @@ $ yarn slither # Run Slither
To auto-format code:
-```
+```sh
$ yarn fmt
```
-## Testing
+### Testing
First, make sure Ganache is running.
-```
+```sh
$ yarn ganache
```
Run all tests:
-```
+```sh
$ yarn test
```
To run tests in a specific file, run:
-```
+```sh
$ yarn test [path/to/file]
```
To run tests and generate test coverage, run:
-```
+```sh
$ yarn coverage
```
@@ -107,16 +138,22 @@ Run `yarn migrate --network NETWORK`, where NETWORK is either `mainnet` or
## Contracts
-The implementation uses 2 separate contracts - a proxy contract
-(`FiatTokenProxy.sol`) and an implementation contract (`FiatToken.sol`). This
-allows upgrading the contract, as a new implementation contact can be deployed
-and the Proxy updated to point to it.
+The FiatToken contracts adheres to OpenZeppelin's
+[Proxy Upgrade Pattern](https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies)
+([permalink](https://github.com/OpenZeppelin/openzeppelin-upgrades/blob/65cf285bd36af24570186ca6409341540c67238a/docs/modules/ROOT/pages/proxies.adoc#L1)).
+There are 2 main contracts - an implementation contract
+([`FiatTokenV2_2.sol`](./contracts/v2/FiatTokenV2_2.sol)) that contains the main
+logic for FiatToken's functionalities, and a proxy contract
+([`FiatTokenProxy.sol`](./contracts/v1/FiatTokenProxy.sol)) that redirects
+function calls to the implementation contract. This allows upgrading FiatToken's
+functionalities, as a new implementation contact can be deployed and the Proxy
+can be updated to point to it.
-### FiatToken
+## FiatToken features
The FiatToken offers a number of capabilities, which briefly are described
below. There are more [detailed design docs](./doc/tokendesign.md) in the `doc`
-folder.
+directory.
### ERC20 compatible
@@ -155,3 +192,13 @@ the `masterMinter`.
The contract has an Owner, who can change the `owner`, `pauser`, `blacklister`,
or `masterMinter` addresses. The `owner` can not change the `proxyOwner`
address.
+
+## Additional Documentations
+
+- [FiatToken design](./doc/tokendesign.md)
+- [MasterMinter design](./doc/masterminter.md)
+- [Deployment process](./doc/deployment.md)
+- [Preparing an upgrade](./doc/upgrade.md)
+- [Upgrading from v1 to v2](./doc/v2_upgrade.md)
+- [Upgrading from v2 to v2.1](./doc/v2.1_upgrade.md)
+- [Upgrading from v2.1 to v2.2](./doc/v2.2_upgrade.md)
diff --git a/doc/deployment.md b/doc/deployment.md
index 06181ed82..4671f23fa 100644
--- a/doc/deployment.md
+++ b/doc/deployment.md
@@ -3,37 +3,42 @@
This is the process for deploying a new proxy and implementation (as opposed to
upgrading an existing proxy).
-Since the proxy uses `delegatecall` to forward calls to the implementation
-initialization of the contracts becomes a little tricky because we can not
+Since the proxy uses `delegatecall` to forward calls to the implementation,
+initialization of the contracts becomes a little tricky because we cannot
initialize fields in the implementation contract via the constructor. Instead
there is an initialize method in the implementation contract, which is publicly
available, but can only be called once per proxy.
## Deploying the implementation contract
-1. Deploy [FiatTokenV1](../contracts/FiatTokenV1.sol)
-2. Initialize the fields in FiatToken via the `initialize` method. The values
- are not important, but this will stop anyone else initializing the roles and
- trying to use it as a token or pass it off as a real CENTRE token.
- ```
+1. Deploy [FiatTokenV2_2](../contracts/v2/FiatTokenV2_2.sol)
+2. Initialize the fields in FiatTokenV2_2 via the `initialize*` methods. The
+ values are not important, but this will stop anyone else initializing the
+ roles and trying to use it as a token or pass it off as a real Circle token.
+
+ ```js
initialize(
- "",
- "",
- "",
- 0,
- throwawayAddress,
- throwawayAddress,
- throwawayAddress,
- throwawayAddress
- )
+ "",
+ "",
+ "",
+ 0,
+ THROWAWAY_ADDRESS,
+ THROWAWAY_ADDRESS,
+ THROWAWAY_ADDRESS,
+ THROWAWAY_ADDRESS
+ );
+ initializeV2("");
+ initializeV2_1(THROWAWAY_ADDRESS);
+ initializeV2_2([], "");
```
+
3. Verify that all fields in the FiatToken have been initialized correctly and
have the expected values. See [README.validate.md](../validate/validate.js).
## Deploying a Proxy:
-1. Obtain addresses for the various contract roles from CENTRE ops. The keys for
- these addresses will be stored offline. The address needed are:
+1. Obtain addresses for the following contract roles. Ensure that the keys for
+ these addresses are securely stored.
```
admin
@@ -50,7 +55,7 @@ available, but can only be called once per proxy.
of the deployed implementation contract to the constructor, which will
initialize the `_implementation` field.
-3. The `admin` of the proxy contract defaults to msg.sender. You must either
+3. The `admin` of the proxy contract defaults to `msg.sender`. You must either
change the `admin` now, or send the remaining transactions from a different
address. The `admin` can only see methods in the Proxy, any method calls from
`admin` will not be forwarded to the implementation contract. The `admin`
@@ -59,47 +64,39 @@ available, but can only be called once per proxy.
```
changeAdmin(adminAddress)
-
```
-4. Initialize the proxy, via the `initialize` method. This call will get
+4. Initialize the proxy via the `initialize*` methods. This call will get
forwarded to the implementation contract, but since it is via `delegatecall`
it will run in the context of the Proxy contract, so the fields it is
- initializing will be stored it the storage of the Proxy. The values passed
+ initializing will be stored in the storage of the Proxy. The values passed
here are important, especially for the roles that will control the contract.
- These addresses should be obtained from CENTRE ops, and the keys will be
- stored offline.
- ```
+ ```js
initialize(
- "USD//C",
- "USDC",
- "USD",
- 6,
- masterMinterAddress,
- pauserAddress,
- blacklisterAddress,
- ownerAddress
- )
+ tokenName,
+ tokenSymbol,
+ tokenCurrency,
+ tokenDecimals,
+ masterMinterAddress,
+ pauserAddress,
+ blacklisterAddress,
+ ownerAddress
+ );
+ initializeV2(newTokenName);
+ initializeV2_1(lostAndFoundAddress);
+ initializeV2_2(accountsToBlacklist, newTokenSymbol);
```
5. Verify the fields have been properly initialized. Verification should be
performed independently by multiple people to make sure that the contract has
been deployed correctly. The following fields should be verified:
- - name, symbol, and currency are as expected
- - `decimals` is 6
- - `masterMinter` is the expected address
- - `pauser` is the expected address
- - `blacklister` is the expected address
- - `owner` is the expected address
- - `admin` is the expected address. Note that `admin` is not callable by
- anyone other than the admin, so this can be verified by calling
- `eth.getStorageAt(proxyAddress, 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b)`
- - `_implementation` is the address of the implementation contract. Note that
- `implementation` is not callable by anyone other than the admin, so this
- can be verified by calling
- `eth.getStorageAt(proxyAddress, 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3)`
+ - `admin` is the expected address
+ - `implementation` is the address of the implementation contract
+ - `name`, `symbol`, `currency` and `decimals` are as expected
+ - `version` is 2
+ - `owner`, `masterMinter`, `pauser`, `blacklister` are the expected addresses
- `totalSupply` is 0
- `initialized` is `true`
diff --git a/doc/masterminter.md b/doc/masterminter.md
index 54b168f74..bf7245f2c 100644
--- a/doc/masterminter.md
+++ b/doc/masterminter.md
@@ -1,12 +1,12 @@
# MasterMinter contract
The MasterMinter is a governance contract. It delegates the functionality of the
-`masterMinter` role in the CENTRE USDC contract to multiple addresses. (The
+`masterMinter` role in the Circle FiatToken contract to multiple addresses. (The
`masterMinter` role can add and remove minters from a FiatToken and set their
allowances.) The MasterMinter contract delegates the minter management
capability to `controllers`. Each `controller` manages exactly one `minter`, and
a single `minter` may be managed by multiple `controllers`. This allows
-separation of duties (off-line key management) and simplifies nonce management
+separation of duties (offline key management) and simplifies nonce management
for warm transactions.
Minters and FiatToken holders are not affected by replacing a `masterMinter`
@@ -45,8 +45,8 @@ contract to call minter management functions on the FiatToken contract:
Together, these four functions are defined as the `MinterManagementInterface`.
The `MasterMinter` contains the address of a `minterManager` that implements the
-`MinterManagementInterface`. The `MasterMinter` interacts with the USDC token
-via the `minterManager`.
+`MinterManagementInterface`. The `MasterMinter` interacts with the FiatToken
+contract via the `minterManager`.
When a `controller` calls a function on `MasterMinter`, the `MasterMinter` will
call the appropriate function on the `FiatToken` contract on its behalf. Both
@@ -108,13 +108,10 @@ We recommend assigning at least two `controllers` to each `minter`.
- SecurityController. Use this `controller` to sign a single
`removeMinter` transaction and store it for emergencies.
-The private keys to the `AllowanceController` and `SecurityController` should
-stay in cold storage. This configuration lets the Controller keep multiple warm
-`incrementMinterAllowance` transactions on hand, as well as the `removeMinter`
-transaction in case of a problem. Broadcasting the `removeMinter` transaction
-will cause all future `incrementMinterAllowance` transactions to `throw`. Since
-the two types of transactions are managed by different addresses, there is no
-need to worry about nonce management.
+This configuration allows the `removeMinter` transaction to be presigned as
+nonces for the `SecurityController` are deterministic, which reduces the time to
+respond when there's an issue. Broadcasting the `removeMinter` transaction will
+cause all future interactions from the `AllowanceController` to `throw`.
# MasterMinter vs. MintController
diff --git a/doc/tokendesign.md b/doc/tokendesign.md
index 36eca9357..7a986ffd3 100644
--- a/doc/tokendesign.md
+++ b/doc/tokendesign.md
@@ -1,6 +1,6 @@
-# CENTRE Fiat Token
+# Circle's FiatToken Design
-The CENTRE Fiat Token contract is an ERC-20 compatible token. It allows
+Circle's FiatToken contract is an ERC-20 compatible token. It allows
minting/burning of tokens by multiple entities, pausing all activity, freezing
of individual addresses, and a way to upgrade the contract so that bugs can be
fixed or features added.
@@ -18,10 +18,11 @@ functionality:
- `blacklister` - prevent all transfers to or from a particular address, and
prevents that address from minting or burning
- `owner` - re-assign any of the roles except for `admin`
-- `admin` - upgrade the contract, and re-assign itself
+- `admin` - manage the proxy-level functionalities such as switching the
+ implementation contract
+- `rescuer` - transfer any ERC-20 tokens that are locked up in the contract
-CENTRE will control the address of all roles except for minters, which will be
-controlled by the entities that CENTRE elects to make minters
+Circle will control the address of all roles.
## ERC-20
@@ -31,31 +32,30 @@ some changes:
- A blacklisted address will be unable to call `transfer` or `transferFrom`, and
will be unable to receive tokens.
- `approve` was not allowed for blacklisted addresses in FiatToken versions
- <2.2 but available in versions 2.2+. See "Blacklisting" section for more
- details.
+ <2.2 but available in versions 2.2+. See ["Blacklisting"](#blacklisting)
+ section for more details.
- `transfer`, `transferFrom`, and `approve` will fail if the contract has been
paused.
## Issuing and Destroying tokens
-The Fiat Token allows multiple entities to create and destroy tokens. These
-entities will have to be members of CENTRE, and will be vetted by CENTRE before
-they are allowed to create new tokens. CENTRE will not mint any tokens itself,
-it will approve members to mint and burn tokens.
-
-Each `minter` has a `mintingAllowance`, which CENTRE configures. The
-`mintingAllowance` is how many tokens that minter may issue, and as a `minter`
-issues tokens, its `mintingAllowance` declines. CENTRE will periodically reset
-the `mintingAllowance` as long as a `minter` remains in good standing with
-CENTRE and maintains adequate reserves for the tokens it has issued. The
-`mintingAllowance` is to limit the damage if any particular `minter` is
+The FiatToken contract allows multiple entities to create and destroy tokens.
+These entities will have to be members of Circle, and will be vetted by Circle
+before they are allowed to create new tokens.
+
+Each `minter` has a `minterAllowance`, which Circle configures. The
+`minterAllowance` is how many tokens that minter may issue, and as a `minter`
+issues tokens, its `minterAllowance` declines. Circle will periodically reset
+the `minterAllowance` as long as a `minter` remains in good standing with Circle
+and maintains adequate reserves for the tokens it has issued. The
+`minterAllowance` is to limit the damage if any particular `minter` is
compromised.
### Adding Minters
-CENTRE adds minters via the `configureMinter` method. When a minter is
-configured a `mintingAllowance` is specified, which is the number of tokens that
-address is allowed to mint. As a `minter` mints tokens, the `mintingAllowance`
+Circle adds minters via the `configureMinter` method. When a minter is
+configured a `minterAllowance` is specified, which is the number of tokens that
+address is allowed to mint. As a `minter` mints tokens, the `minterAllowance`
will decline.
- Only the `masterMinter` role may call configureMinter.
@@ -63,13 +63,13 @@ will decline.
### Resetting Minting Allowance
The `minters` will need their allowance reset periodically to allow them to
-continue minting. When a `minter`'s allowance is low, CENTRE can make another
-call to `configureMinter` to reset the `mintingAllowance` to a higher value.
+continue minting. When a `minter`'s allowance is low, Circle can make another
+call to `configureMinter` to reset the `minterAllowance` to a higher value.
### Removing Minters
-CENTRE removes minters via the `removeMinter` method. This will remove the
-`minter` from the list of `minters` and set its `mintingAllowance` to 0. Once a
+Circle removes minters via the `removeMinter` method. This will remove the
+`minter` from the list of `minters` and set its `minterAllowance` to 0. Once a
`minter` is removed it will no longer be able to mint or burn tokens.
- Only the `masterMinter` role may call `removeMinter`.
@@ -79,7 +79,7 @@ CENTRE removes minters via the `removeMinter` method. This will remove the
A `minter` mints tokens via the `mint` method. The `minter` specifies the
`amount` of tokens to create, and a `_to` address which will own the newly
created tokens. A `minter` may only mint an amount less than or equal to its
-`mintingAllowance`. The `mintingAllowance` will decrease by the amount of tokens
+`minterAllowance`. The `minterAllowance` will decrease by the amount of tokens
minted, and the balance of the `_to` address and `totalSupply` will each
increase by `amount`.
@@ -96,11 +96,11 @@ A `minter` burns tokens via the `burn` method. The `minter` specifies the
`amount` of tokens to burn, and the `minter` must have a `balance` greater than
or equal to the `amount`. Burning tokens is restricted to `minter` addresses to
avoid accidental burning of tokens by end users. A `minter` with a
-`mintingAllowance` of 0 is allowed to burn tokens. A `minter` can only burn
+`minterAllowance` of 0 is allowed to burn tokens. A `minter` can only burn
tokens which it owns. When a minter burns tokens, its balance and the
totalSupply are reduced by `amount`.
-Burning tokens will not increase the mintingAllowance of the address doing the
+Burning tokens will not increase the minterAllowance of the address doing the
burning.
- Only a minter may call burn.
@@ -126,7 +126,7 @@ are considered meaningless.
### Adding a blacklisted address
-CENTRE blacklists an address via the `blacklist` method. The specified `account`
+Circle blacklists an address via the `blacklist` method. The specified `account`
will be added to the blacklist.
- Only the `blacklister` role may call `blacklist`.
@@ -134,7 +134,7 @@ will be added to the blacklist.
### Removing a blacklisted address
-CENTRE removes an address from the blacklist via the `unblacklist` method. The
+Circle removes an address from the blacklist via the `unblacklist` method. The
specified `account` will be removed from the blacklist.
- Only the `blacklister` role may call `unblacklist`.
@@ -147,11 +147,11 @@ serious key compromise. All transfers, minting, burning, and adding minters will
be prevented while the contract is paused. Other functionality, such as
modifying the blacklist, removing minters, changing roles, and upgrading will
remain operational as those methods may be required to fix or mitigate the issue
-that caused CENTRE to pause the contract.
+that caused Circle to pause the contract.
### Pause
-CENTRE will pause the contract via the `pause` method. This method will set the
+Circle will pause the contract via the `pause` method. This method will set the
paused flag to true.
- Only the `pauser` role may call pause.
@@ -160,7 +160,7 @@ paused flag to true.
### Unpause
-CENTRE will unpause the contract via the `unpause` method. This method will set
+Circle will unpause the contract via the `unpause` method. This method will set
the `paused` flag to false. All functionality will be restored when the contract
is unpaused.
@@ -168,17 +168,44 @@ is unpaused.
- Unpausing emits an `Unpause()` event
+## Meta transactions compatibility
+
+### ERC-2612
+
+The contract is compatible with
+[ERC-2612](https://eips.ethereum.org/EIPS/eip-2612). Users may update their
+ERC-20 allowances by signing a `permit` message and passing the signed message
+to a relayer who will execute the on-chain transaction, instead of submitting a
+transaction themselves.
+
+### ERC-3009
+
+The contract is compatible with
+[ERC-3009](https://eips.ethereum.org/EIPS/eip-3009). Users may transfer assets
+to another user by signing an EIP-3009 authorization and passing the
+authorization to a relayer who will execute the authorization on chain, instead
+of submitting a transaction themselves.
+
+### Signature Validation schemes
+
+The contract supports signature validation via:
+
+1. ECDSA signatures for Externally Owned Accounts (EOAs)
+2. [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) for ERC-1271 compatible
+ Smart Contract Wallets
+
## Upgrading
-The Fiat Token uses the zeppelinos Unstructured-Storage Proxy pattern
-[https://docs.zeppelinos.org/docs/upgradeability_AdminUpgradeabilityProxy.html].
-[FiatTokenV1.sol](../contracts/FiatTokenV1.sol) is the implementation, the
-actual token will be a Proxy contract
-([FiatTokenProxy.sol](../contracts/FiatTokenProxy.sol)) which will forward all
-calls to `FiatToken` via delegatecall. This pattern allows CENTRE to upgrade the
-logic of any deployed tokens seamlessly.
+The FiatTokenProxy contract uses the zeppelinos Unstructured-Storage Proxy
+pattern
+[https://github.com/zeppelinos/zos-lib/blob/8a16ef3ad17ec7430e3a9d2b5e3f39b8204f8c8d/contracts/upgradeability/AdminUpgradeabilityProxy.sol].
+[FiatTokenV2_2.sol](../contracts/v2/FiatTokenV2_2.sol) is the implementation,
+the actual token will be a Proxy contract
+([FiatTokenProxy.sol](../contracts/v1/FiatTokenProxy.sol)) which will forward
+all calls to `FiatToken` via delegatecall. This pattern allows Circle to upgrade
+the logic of any deployed tokens seamlessly.
-- CENTRE will upgrade the token via a call to `upgradeTo` or `upgradeToAndCall`
+- Circle will upgrade the token via a call to `upgradeTo` or `upgradeToAndCall`
if initialization is required for the new version.
- Only the `admin` role may call `upgradeTo` or `upgradeToAndCall`.
@@ -211,3 +238,8 @@ reassign all roles (including itself) except for the `admin` role.
- `transferOwnership` updates the `owner` role to a new address.
- `transferOwnership` may only be called by the `owner` role.
+
+### Rescuer
+
+- `updateRescuer` updates the `rescuer` role to a new address.
+- `updateRescuer` may only be called by the `owner` role.
diff --git a/doc/upgrade.md b/doc/upgrade.md
index ae7578789..386c58ede 100644
--- a/doc/upgrade.md
+++ b/doc/upgrade.md
@@ -8,11 +8,24 @@ token, and pointing an existing proxy to the upgraded token.
An upgraded token can have:
1. New logic (functions)
-2. New fields (data)
-3. New logic and new fields
+2. New state variables (data)
+3. New logic and new state variables
+4. Renamed state variables
+5. Updated logic for existing functions
Each situation is addressed in a section below.
+> **_IMPORTANT_**: Do not remove existing state variables or modify the
+> inheritance order of contracts. Storage addresses for contract states are
+> defined during compilation and follow a sequential order based on the
+> declaration of state variables. Removing a state variable may cause other
+> variables to read/write from the wrong storage address which is dangerous.
+>
+> Be cautious when working with storage slots. Before upgrading, ensure that
+> storage addresses for existing state variables have not changed. You may rely
+> on [storageSlots.behavior.ts](../test/helpers/storageSlots.behavior.ts) to
+> validate this behavior.
+
### New Logic Only
A template for the next upgraded contract for new logic is kept in /contracts
@@ -20,7 +33,7 @@ with the file name FiatTokenV[X].sol where X is the version number. The upgraded
contract _must_ inherit from the current contract. For example, if upgrading
from version 1 to version 2, the contract would have the format:
-```
+```solidity
import './FiatTokenV1.sol';
/**
@@ -38,29 +51,30 @@ All that remains is to add the new logic (functions) as part of the body
_functions_ will not be inherited in subsequent contract versions and should be
added with care.
-### New Fields Only
-
-Adding new fields requires inheriting from the prior version of the contract as
-done in [New Logic](#new-logic-only). In addition, the new contract requires
-declaring new data fields and, if the data fields must be initialized to
-non-default values, adding initialization logic for the new fields. New
-variables added _must_ be declared as type `internal` or `public`, `private` can
-never be used. Note that `private` _functions_ will also not be inherited in
-subsequent contract versions and should be added with care. Also note that
-inline initialization of variables as part of declaration has no effect as the
-proxy never executes this code (for example, bool public newBool = true is not
-in fact initialized to true). If possible, new fields should be added that can
-start with default solidity values and do not need initialization. However, if
-any new fields require initialization to non-default values, the new token must
-add an _initialize_ function and a _initV[X]_ function, where X is the version
-of the contract. The initialization function allows the contract to be deployed
-from scratch and initialize all variables declared in the new contract and in
-prior contracts. The initV[X] function allows the contract to initialize only
-the new variables added in the new contract. A template is shown below for
-upgrading from version 1 to version 2. In the example, we add variables newBool,
-newAddress, and newUint, which would be replaced with the real variables added.
-
-```
+### New State Variables Only
+
+Adding new state variables requires inheriting from the prior version of the
+contract as done in [New Logic](#new-logic-only). In addition, the new contract
+requires declaring new state variables and, if the state variables must be
+initialized to non-default values, adding initialization logic for the new state
+variables. New variables added _must_ be declared as type `internal` or
+`public`, `private` can never be used. Note that `private` _functions_ will also
+not be inherited in subsequent contract versions and should be added with care.
+Also note that inline initialization of variables as part of declaration has no
+effect as the proxy never executes this code (for example, bool public newBool =
+true is not in fact initialized to true). If possible, new state variables
+should be added that can start with default Solidity values and do not need
+initialization. However, if any new state variables require initialization to
+non-default values, the new token must add an _initialize_ function and a
+_initV[X]_ function, where X is the version of the contract. The initialization
+function allows the contract to be deployed from scratch and initialize all
+variables declared in the new contract and in prior contracts. The initV[X]
+function allows the contract to initialize only the new variables added in the
+new contract. A template is shown below for upgrading from version 1 to
+version 2. In the example, we add variables newBool, newAddress, and newUint,
+which would be replaced with the real variables added.
+
+```solidity
import './FiatTokenV1.sol';
/**
@@ -106,18 +120,63 @@ _Note the addition of a new initializedV[X] variable that is checked and set in
initV[X]._ _Note the structure of initialized that uses a super call with
previously set parameters as well as a call to initV[X]._
-### New Logic and New Fields
+### New Logic and New State Variables
+
+The case requires the same steps as
+[New State Variables](#new-state-variables-only) plus the addition of new
+functions as done in [New Logic](#new-logic-only).
+
+### Updated Logic
+
+The logic in existing functions may be updated, but it should be done only if it
+does not cause breaking changes to users of the contract and it is absolutely
+necessary. This can be done by finding the function declaration in the existing
+contracts, marking the function as `virtual`, and `override` the function in the
+upgraded contract.
+
+```solidity
+contract FiatTokenV1 {
+ ...
+
+ function foo() external virtual pure returns (uint256) {
+ return 1;
+ }
+}
+```
+
+```solidity
+import './FiatTokenV1.sol';
+
+/**
+ \* @title FiatTokenV2
+ \* @dev ERC20 Token backed by fiat reserves
+ **/
+contract FiatTokenV2 is FiatTokenV1 {
+ ...
+
+ function foo() external override pure returns (uint256) {
+ return 2;
+ }
+}
+```
+
+### Renamed State Variables
-The case requires the same steps as [New Fields](#new-fields-only) plus the
-addition of new functions as done in [New Logic](#new-logic-only).
+State variables may be renamed to increase clarity or readability. This may be
+useful if there are state variables that have become unused but cannot be safely
+removed. Deprecating the variable can be done by finding the variable
+declaration in existing contracts, prefixing the variable with `deprecated` and
+replacing references to the variable with the new name.
## Upgraded Token Deployment
Deployment can be done in the following steps:
-1. Write any new logic and new fields in the new contract (as described above)
-2. Test any new fields and logic added to the contract (including positive,
- negative, and extended tests following the current testing strategy)
+1. Write any new logic and new state variables in the new contract (as described
+ above)
+2. Test any new state variables and logic added to the contract (including
+ positive, negative, and extended tests following the current testing
+ strategy)
3. Ensure the test suite has run on the final version of the new contract with
added tests and that the test suite passes with 100% code coverage
4. Complete any external audits as deemed necessary
@@ -131,8 +190,8 @@ Deployment can be done in the following steps:
## Upgrading the Proxy to point to the UpgradedToken
The proxy must be pointed to the new upgraded token. This is accomplished two
-ways depending on whether only new logic was added or if new fields (and
-possibly new logic) were added.
+ways depending on whether only new logic was added or if new state variables
+(and possibly new logic) were added.
### Upgrading if _ONLY_ New Logic Added
@@ -140,30 +199,20 @@ possibly new logic) were added.
address of the new upgraded token.
2. Broadcast the transaction
3. Check that the implementation field of the proxy matches the address of the
- upgraded token by calling web3.eth.getStorageAt(proxy.address, implSlot),
- where implSlot is defined in the contract as a hardcoded field. As of CENTRE
- Fiat Token v1.0.0 that slot is
- 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b.
- Alternatively, getImplementation may be called on the proxy with the
- adminAccount.
+ upgraded token by calling the `implementation` method
4. If the address in 3) does not match, it is likely a wrong address was used.
Repeat the process from step 1).
-### Upgrading if New Fields (and possibly new Logic) Added
+### Upgrading if New State Variables (and possibly new logic) Added
1. Prepare an upgradeToAndCall transaction from the adminAccount parameterized
with the address of the new upgraded token and an internal call to invoke
- initV[X] with the new data fields.
+ initV[X] with the new data state variables.
2. Broadcast the transaction
3. Check that the implementation field of the proxy matches the address of the
- upgraded token by calling web3.eth.getStorageAt(proxy.address, implSlot),
- where implSlot is defined in the contract as a hardcoded field. As of CENTRE
- Fiat Token v1.0.0 that slot is
- 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b.
- Alternatively, getImplementation may be called on the proxy with the admin
- account.
+ upgraded token by calling the `implementation` method
4. If the address in 3) does not match, it is likely a wrong address was used.
Repeat the process from step 1).
-5. Verify that the new fields were set correctly as done in _Deployment
+5. Verify that the new state variables were set correctly as done in _Deployment
Instructions_ [verification](deployment.md)
6. If verification fails, restart the process from step 1)
diff --git a/package.json b/package.json
index 974025fd9..911db56a4 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
- "name": "centre-tokens",
+ "name": "stablecoin-evm",
"version": "1.0.0",
- "description": "Fiat and non-fiat tokens part of the CENTRE network.",
+ "description": "Circle's Stablecoin Smart Contracts on EVM-compatible blockchains",
"main": "truffle-config.js",
"directories": {
"test": "test"
@@ -26,15 +26,15 @@
},
"repository": {
"type": "git",
- "url": "git+https://github.com/centrehq/centre-tokens.git"
+ "url": "git+https://github.com/circlefin/stablecoin-evm.git"
},
"keywords": [],
"author": "",
"license": "Apache-2.0",
"bugs": {
- "url": "https://github.com/centrehq/centre-tokens/issues"
+ "url": "https://github.com/circlefin/stablecoin-evm/issues"
},
- "homepage": "https://github.com/centrehq/centre-tokens#readme",
+ "homepage": "https://github.com/circlefin/stablecoin-evm#readme",
"dependencies": {},
"devDependencies": {
"@openzeppelin/contracts": "^3.1.0",