Skip to content

Commit

Permalink
Open source the wrapped-tokens codebase.
Browse files Browse the repository at this point in the history
  • Loading branch information
KNWR authored Oct 28, 2022
0 parents commit e975f67
Show file tree
Hide file tree
Showing 25 changed files with 17,148 additions and 0 deletions.
12 changes: 12 additions & 0 deletions @types/TransactionRawLog.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface TransactionRawLog {
logIndex: number;
transactionIndex: number;
transactionHash: string;
blockHash: string;
blockNumber: number;
address: string;
data: string;
topics: string[];
type: string;
id: string;
}
119 changes: 119 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# wrapped-tokens

Wrapped tokens representing staked and generic assets.

## Setup

Requirements:

- Node >= v12
- Yarn

```
$ cd wrapped-tokens
$ npm i -g yarn # Install yarn if you don't already have it
$ yarn install # Install dependencies
$ yarn setup # Setup Git hooks
```

## TypeScript type definition files for the contracts

To generate type definitions:

```
$ yarn compile && yarn typechain
```

## Linting and Formatting

To check code for problems:

```
$ yarn typecheck # Type-check TypeScript code
$ yarn lint # Check JavaScript and TypeScript code
$ yarn lint --fix # Fix problems where possible
$ yarn solhint # Check Solidity code
$ yarn slither # Run Slither
```

To auto-format code:

```
$ yarn fmt
```

## Testing

Run all tests:

```
$ yarn test
```

To run tests in a specific file, run:

```
$ yarn test [path/to/file]
```

To run tests and generate test coverage, run:

```
$ yarn coverage
```

## Contracts

[High Level Flow](./doc/weth2SmartContractsHighLevel.png)

The implementation consists of 4 separate contracts, reusing
[centre-tokens](https://github.com/centrehq/centre-tokens) audited and battle
tested code whenever possible.

- A
[proxy contract](https://github.com/centrehq/centre-tokens/blob/v2.1.0/contracts/v1/FiatTokenProxy.sol)
which is an exact duplicate of the proxy contract used be centre-tokens.
- A token contract which for generic wrapped assets will be an exact duplicate
of centre-tokens
[fiat token](https://github.com/centrehq/centre-tokens/blob/v2.1.0/contracts/v2/FiatTokenV2_1.sol)
or for wrapped staked assets will be a staked token (`StakedTokenV1.sol`)
which inherits directly from centre-token's fiat tokens and adds exchange rate
functionality.
- A mint forwarder contract (`MinterForwarder.sol`) which contains rate limited
minting functionality for our wrapped tokens.
- An exchange rate updater contract (`ExchangeRateUpdater.sol`) which will only
be used for wrapped staked assets and contains rate limited exchange rate
updating functionality.

### ERC20 compatible

All wrapped tokens implement the ERC20 interface.

### Staked Token Differences from FiatToken

Wrapped staked tokens will be used to wrap staked assets. The wrapped staked
tokens inherit from Centre's fiat token contract and add an oracle role that can
set an exchangeRate. Both the `oracle` and the `exchangeRate` are stored in
unstructured storage to maximize forward compatibility with future centre fiat
token upgrades.

### Rate Limited Minting

The fiat token contract's built in minting has fixed minting allowances that
when depleted require the `masterMinter` cold key to restore the mint allowance.
We've introduced a
minting forwarder contract that'll allow us to continously mint up to N tokens
over M time, with the mint allowance replenishing programmatically.

### Rate Limited Exchange Rate Updates

Wrapped staked tokens will have a floating exchange rate that is set off-chain.
Given the high frequency with which we'll have to update wrapped
staked tokens exchange rates we'll utilize a seperate rate limited exchange rate
updater contract to minimize operational load.

### Ownable

The contract has an Owner, who can change the `owner`, `pauser`, `blacklister`,
`masterMinter`, or `oracle` addresses. The `owner` can not change the
`proxyOwner` address.
46 changes: 46 additions & 0 deletions contracts/test/ExchangeRateUtilTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2022 Coinbase, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

pragma solidity 0.8.6;

import {
ExchangeRateUtil
} from "../wrapped-tokens/staking/ExchangeRateUtil.sol";

contract ExchangeRateUtilTest {
function safeGetExchangeRate(address tokenContract)
external
view
returns (uint256)
{
return ExchangeRateUtil.safeGetExchangeRate(tokenContract);
}

function safeUpdateExchangeRate(
uint256 newExchangeRate,
address tokenContract
) external {
ExchangeRateUtil.safeUpdateExchangeRate(newExchangeRate, tokenContract);
}
}
37 changes: 37 additions & 0 deletions contracts/test/MintUtilTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2022 Coinbase, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

pragma solidity 0.8.6;

import { MintUtil } from "../wrapped-tokens/MintUtil.sol";

contract MintUtilTest {
function safeMint(
address to,
uint256 value,
address tokenContract
) external {
MintUtil.safeMint(to, value, tokenContract);
}
}
37 changes: 37 additions & 0 deletions contracts/test/RateLimitTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2022 Coinbase, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

pragma solidity 0.8.6;

import { RateLimit } from "../wrapped-tokens/RateLimit.sol";

contract RateLimitTest is RateLimit {
function _replenishAllowanceTest(address caller) external {
_replenishAllowance(caller);
}

function useRateLimitTest(uint256 amount) external {
allowances[msg.sender] = allowances[msg.sender] - amount;
}
}
27 changes: 27 additions & 0 deletions contracts/wrapped-tokens/FiatTokenProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2022 Coinbase, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

pragma solidity 0.6.12;

import { FiatTokenProxy } from "centre-tokens/contracts/v1/FiatTokenProxy.sol";
104 changes: 104 additions & 0 deletions contracts/wrapped-tokens/MintForwarder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2022 Coinbase, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

pragma solidity 0.8.6;

import { RateLimit } from "./RateLimit.sol";
import { MintUtil } from "./MintUtil.sol";

/**
* @title MintForwarder
* @notice Forwarding contract to ERC20 tokens with mint functionality
*/
contract MintForwarder is RateLimit {
/**
* @dev Gets the mintable token contract address
* @return The address of the mintable token contract
*/
address public tokenContract;

/**
* @dev Indicates that the contract has been initialized
*/
bool internal initialized;

/**
* @notice Emitted on mints
* @param minter The address initiating the mint
* @param to The address the tokens are minted to
* @param amount The amount of tokens minted
*/
event Mint(address indexed minter, address indexed to, uint256 amount);

/**
* @dev Function to initialize the contract
* @dev Can an only be called once by the deployer of the contract
* @dev The caller is responsible for ensuring that both the new owner and the token contract are configured correctly
* @param newOwner The address of the new owner of the mint contract, can either be an EOA or a contract
* @param newTokenContract The address of the token contract that is minted
*/
function initialize(address newOwner, address newTokenContract)
external
onlyOwner
{
require(!initialized, "MintForwarder: contract is already initialized");
require(
newOwner != address(0),
"MintForwarder: owner is the zero address"
);
require(
newTokenContract != address(0),
"MintForwarder: tokenContract is the zero address"
);
transferOwnership(newOwner);
tokenContract = newTokenContract;
initialized = true;
}

/**
* @dev Rate limited function to mint tokens
* @dev The _amount must be less than or equal to the allowance of the caller
* @param _to The address that will receive the minted tokens
* @param _amount The amount of tokens to mint
*/
function mint(address _to, uint256 _amount) external onlyCallers {
require(
_to != address(0),
"MintForwarder: cannot mint to the zero address"
);
require(_amount > 0, "MintForwarder: mint amount not greater than 0");

_replenishAllowance(msg.sender);

require(
_amount <= allowances[msg.sender],
"MintForwarder: mint amount exceeds caller allowance"
);

allowances[msg.sender] = allowances[msg.sender] - _amount;

MintUtil.safeMint(_to, _amount, tokenContract);
emit Mint(msg.sender, _to, _amount);
}
}
Loading

0 comments on commit e975f67

Please sign in to comment.