Platform: Code4rena
Start Date: 24/02/2022
End Date: 26/02/2022
Period: 3 days
Status: Completed
Pot Size: $30,000 USDC
Participants: 28
Reporter: liveactionllama
Judge: Jack the Pug
Id: 95
League: ETH
hickuphh3 | 1/28 | $5,806.81 | 1 | 0 | 0 | 0 | 0 | - | 0 | 0 |
leastwood | 2/28 | $3,484.08 | 1 | 0 | 0 | 0 | 0 | - | 0 | 0 |
defsec | 3/28 | $2,140.01 | 2 | 0 | 0 | 0 | 0 | - | - | 0 |
cmichel | 4/28 | $2,065.92 | 1 | 0 | 0 | 0 | 0 | - | 0 | 0 |
TerrierLover | 5/28 | $1,338.95 | 2 | 0 | 0 | 0 | 0 | - | - | 0 |
kyliek | 6/28 | $1,286.85 | 1 | 0 | 0 | 0 | 0 | - | 0 | 0 |
gzeon | 7/28 | $1,092.49 | 2 | 0 | 0 | 0 | 0 | - | - | 0 |
Dravee | 8/28 | $1,085.16 | 2 | 0 | 0 | 0 | 0 | - | - | 0 |
IllIllI | 9/28 | $1,001.22 | 2 | 0 | 0 | 0 | 0 | - | - | 0 |
peritoflores | 10/28 | $913.22 | 2 | 0 | 0 | 0 | 0 | - | - | 0 |
Auditor per page
JPYC is the first of its kind as a Japanese yen stable coin in Japan on Ethereum. Legally it is "Prepaid payment instrument for own business" in Japan. JPYC has a current working product as we call it "previous JPYC" here. Previous JPYC's information, white paper, and more can be found here.
This time we decided to deploy a new version of JPYC with totally new smart contracts.
JPYC protocol is an ERC20 compatible token. It allows minting of tokens by multiple entities, pausing all activity, freezing of individual addresses, rescuing of tokens and UUPS proxy pattern to upgrade the contract so that bugs can be fixed or features added.
Protocol's contracts, Libraries and interfaces are below.
According to Openzeppelin's recent update and this contract's version. We need to keep the solidity version equal to or higher than pragma solidity 0.8.2
. We decided to use the comparatively new version of 0.8.11
.
Here is the list of main contracts in the protocol.
filename | language | code | comment | blank | total |
---|---|---|---|---|---|
JPYCv2/contracts/proxy/ERC1967Proxy.sol | Solidity | 12 | 17 | 4 | 33 |
JPYCv2/contracts/proxy/Proxy.sol | Solidity | 29 | 47 | 10 | 86 |
JPYCv2/contracts/upgradeability/ERC1967Upgrade.sol | Solidity | 48 | 43 | 11 | 102 |
JPYCv2/contracts/upgradeability/UUPSUpgradeable.sol | Solidity | 49 | 59 | 11 | 119 |
JPYCv2/contracts/upgradeability/draft-IERC1822.sol | Solidity | 4 | 14 | 2 | 20 |
JPYCv2/contracts/util/Address.sol | Solidity | 85 | 114 | 18 | 217 |
JPYCv2/contracts/util/Context.sol | Solidity | 10 | 12 | 4 | 26 |
JPYCv2/contracts/util/ECRecover.sol | Solidity | 22 | 48 | 5 | 75 |
JPYCv2/contracts/util/EIP712.sol | Solidity | 40 | 43 | 4 | 87 |
JPYCv2/contracts/util/IERC20.sol | Solidity | 15 | 58 | 9 | 82 |
JPYCv2/contracts/util/SafeERC20.sol | Solidity | 58 | 31 | 10 | 99 |
JPYCv2/contracts/util/StorageSlot.sol | Solidity | 51 | 39 | 10 | 100 |
JPYCv2/contracts/v1/AbstractFiatTokenV1.sol | Solidity | 24 | 23 | 6 | 53 |
JPYCv2/contracts/v1/Blocklistable.sol | Solidity | 43 | 46 | 11 | 100 |
JPYCv2/contracts/v1/EIP2612.sol | Solidity | 37 | 43 | 10 | 90 |
JPYCv2/contracts/v1/EIP3009.sol | Solidity | 134 | 94 | 22 | 250 |
JPYCv2/contracts/v1/EIP712Domain.sol | Solidity | 16 | 29 | 5 | 50 |
JPYCv2/contracts/v1/FiatTokenV1.sol | Solidity | 356 | 180 | 39 | 575 |
JPYCv2/contracts/v1/Ownable.sol | Solidity | 26 | 31 | 10 | 67 |
JPYCv2/contracts/v1/Pausable.sol | Solidity | 34 | 52 | 10 | 96 |
JPYCv2/contracts/v1/Rescuable.sol | Solidity | 32 | 40 | 10 | 82 |
JPYCv2/contracts/v2/FiatTokenV2.sol | Solidity | 419 | 205 | 46 | 670 |
JPYCv2/contracts/v2/FiatTokenV2test.sol | Solidity | 8 | 2 | 5 | 15 |
Transparent proxy pattern is one of the most used upgradeable patterns in the industry and even OpenZeppelin's plugin uses it as a default way to deploy upgradeable contracts. But it has some disadvantages. That's why openzeppelin team's recommendation is shifting towards UUPS proxy pattern.
Transparent proxy pattern puts upgradeTo(impl)
in the proxy contract. It could mean this pattern is vulnerable to "clash of fucntions" in proxy and implementation. In order to avoid it, in Transparent proxy pattern, not only ifAdmin
modifier was implemented in the proxy contract but also admin address needs to be stored in proxy. As a result, gas efficiency becomes worse and comlexity increases.
UUPS proxy pattern is recommended by the OpenZeppelin team. It is said that UUPS pattern is more lightweight and vasatile.
https://eips.ethereum.org/EIPS/eip-1822
ERC1967Proxy
. The proxy is not upgradeable by itself. It delegates calls to implementation contract.upgradeTo
function by inheritting UUPSUpgradeable
contract. Then we can upgrade the implementation contract by calling the upgradeTo
function.In light of the current condition, we were hesitating between UUPS parxy and Transparent proxy patterns. In the end, With the reasons below, we've chosen UUPS pattern.
https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/proxy
We adopted OpenZeppelin's library to implement the UUPS upgradeable pattern. The only thing we have changed is we added uint256[50] private _gap;
as the last part of several contracts in order to prepare for future upgradings(e.g. adding state variables) and be aligned with Openzeppelin's code.
This contract provides a _fallback
function that delegates all calls from proxy contract to implementation contract using _delegate
function. The virtual _implementation
function needs to be overrode.
This is an upgradeability mechanism designed for UUPS proxies. The contract is inherited by the implementation contract(FiatTokenV1
). By inheriting this contract, implementation contract acquires upgradeability.
We want to note that the _authorizeUpgrade
function must be overrode by the implementation contract. we have done that and set the access right onlyOwner
.
draft-IERC1822.sol
is from a recent Openzeppelin's update. We have adopted the update.
The contract is from EIP1967. It standardizes where proxies store the address of the logic contract they delegate to, as well as other proxy-specific information.
This is the Proxy contract. It is from OpenZeppelin's library. It needs implementation contract's address _logic
and _data
to be initialized.
_IMPLEMENTATION_SLOT
is right._logic
._data
is an encoded function call, and the function call initializes the storage of the proxy like a constructor
.Proxy.sol
and is called by function of Proxy.sol
.gap
, so that state variables can be added later.Here, I will explain every single added function for each contract.
A contract that manages the access rights of the contract.
It is the same as openzeppelin library except for not adding the function renounceOwnership
used for removing ownership.
A contract that manages the access rights of the pausability. If the pauser pause FiatTokenV1 contract, some functions is restricted.
A contract that manages the access rights of the blocklistability.
If you are registered in the blocklist, you will not be able to move your funds, etc.
FiatTokenV1
contract is blocklisted in the initialise
funciton.
A contract that manages the access rights of rescuing tokens.
Only the rescuer is able to send ERC20 tokens that were mistakenly sent to the proxy contract's address.
The contract uses the safeTransfer
function.
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md
The contract stores EIP712 Domain Separator. If the chain ID is different, it will be recalculated.
EIP3009 and EIP2612 require EIP712 Domain.
https://eips.ethereum.org/EIPS/eip-3009
A contract that enables transferring of fungible assets via a signed authorization.
The contract uses v, r and s to recover the address and verify if it matches the owner.
authorizationState
_transferWithAuthorization
_receiveWithAuthorization
_cancelAuthorization
_requireUnusedAuthorization
_requireValidAuthorization
_markAuthorizationAsUsed
https://eips.ethereum.org/EIPS/eip-2612
A contract that enables transferring of fungible assets via a signed authorization.
The contract uses v, r and s to recover the address and verify that it matches the authorizer.
nonce
for each user, and the same nonce
cannot be used twice.nonce
increases one by one.block.time
is valid._approve
is called.blocklisted[address(this)] = true
makeDomainSeparator(name, "1")
initialized = true
_authorizeUpgrade
function with onlyOwner
modifier.FiatTokenV1
with a new functionality whitelist
we may consider to add in the future.FiatTokenV1
.ERC1967Upgradeable.sol
and IBeacon.sol
’s code before, but it is not used totally because we selected UUPS upgradeable pattern. Functions like Beacon or Transparent pattern’s parts are not used in the current situation. We removed the unused parts.Install nodejs, refer to nodejs.
git clone https://github.com/code-423n4/2022-02-jpyc.git cd 2022-02-jpyc npm i // test npx hardhat test // When specifying the path npx hardhat test test/direcotry/file // coverage npx hardhat coverage // When specifying the path npx hardhat coverage test/direcotry/file // contract-sizer npx hardhat size-contracts
We created the tests for the smart contracts as below.
Test with proxy
If you want more information about how the contracts are forked or test files, see files below.
Openzeppelin's recent update
EIP1967
Transparent-vs-uups by Openzeppelin
the centre-tokens
UUPS proxy pattern explanation
EIP2535
Unstructured storage pattern