diff --git a/README.md b/README.md
index 31404c0..30bb48f 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,242 @@
-# Bzzzar Hardhat Migration
+
+

+
BZZ Smart Contract Ecosystem
+
-This repo has been set up to move the Bzzzar contracts from an Etherlime development environment to Hardhat, as Etherlime is no longer under active development. This was necessitated due to changes to the Eth Broker contract which caused the contract to longer pass its test suite in the Etherlime environment.
+---
-This branch of the repo still has failing tests in the Eth Broker test suite. There was a desire for separate PRs for migrating to Hardhat and fixing the Eth Broker tests. As a result, in this branch the tests and deploy script have been migrated to Hardhat, but broken tests have note been fixed.
+# Index
-### Setup
+#### [Repository Set Up](#repository-set-up)
+
+#### [Testing and Coverage](#testing-and-coverage)
+
+#### [Deployment](#deployment)
+
+- [Testnet Deployment](#testnet-deployment)
+- [Mainnet Deployment](#mainnet-deployment)
+
+#### [System Design](#system-design)
+
+### Additional documentation
+
+#### [~ `README`](./README.md)
+#### [> Audit Report and Info](./packages/chain/audit/Audit_report_and_info.md)
+##### [> Final audit report](./packages/chain/audit/Bzzaar_final_audit_report.pdf)
+#### [> Admin Permissions and Risks](./packages/chain/docs/admin_permissions_and_risks.md)
+#### [> Token Contract](./packages/chain/docs/token_contract.md)
+#### [> Curve Contract](./packages/chain/docs/curve_contract.md)
+#### [> ETH Broker Contract](./packages/chain/docs/eth_broker_contract.md)
+
+---
+
+# Repository Set Up
+
+To get the blockchain folder into a working state, you will need to install the required packages. To do so, in a terminal open in this directory, run the following:
-Install the relevant packages with:
```
yarn
```
-### Running the Tests
+This will install all the needed packages. This may take some time.
-To run all of the tests:
+# Testing and Coverage
+
+To run the tests you will need to run a local development blockchain:
+
+```
+yarn chain
+```
+
+Please ensure that you do not have anything else running on port 8545 or this will fail.
+
+Once the dev chain is up and running you can run the following command to run the tests:
-run
```
yarn test:chain
```
+# Deployment
+
+The bonding curve has a deployment script for the following networks:
+
+```
+local (31337) (Hardhat)
+Goerli (5)
+Mainnet (1)
+```
+
+Before you are able to deploy using this script, you will need to create an `.env` file in the `packages/chain/` directory. After you have created your `.env` file, you will need to copy the contents of the `.env.example` file (and, if deploying to Goerli or mainnet, fill in values for the private key and Infura API key):
+
+```
+# Deployer EOA private key
+GOERLI_DEPLOYER_PRIV_KEY=
+MAINNET_DEPLOYER_PRIV_KEY=
+
+# Infura key
+GOERLI_INFURA_KEY=
+MAINNET_INFURA_KEY=
+
+# BZZ bonding curve set up variables
+BZZ_DEPLOYED_MAINNET=
+DAI_ADDRESS_MAINNET=0x6b175474e89094c44da98b954eedeac495271d0f
+OWNER_ADDRESS=
+
+# TESTING SET UP
+ # Mock DAI (for testing) set up
+ COLLATERAL_TOKEN_NAME=
+ COLLATERAL_TOKEN_SYMBOL=
+ COLLATERAL_TOKEN_DECIMAL=18
+
+ # BZZ token set up variables
+ TOKEN_NAME=
+ TOKEN_SYMBOL=
+ # BZZ token has 16 decimals. DO NOT CHANGE THIS! This will break the bonding curve
+ TOKEN_DECIMAL=16
+ # BZZ needs this limit for the curve. DO NOT CHANGE THIS! This will break the bonding curve
+ TOKEN_CAP=1250000000000000000000000
+
+ # Testing address
+ ADDRESS_OF_TESTER=
+```
+
+The `.env` file is separated into logical sections to make deployment easier. The first section contains the private keys for deployment on the various networks. Please ensure that the private key that is being used has ETH on the respective network. It is recommended to have at least 0.5 ETH for deployment, more if you intend to deploy multiple times for testing.
+
+(In addition, there are `.env` fields for a number of networks not currently supported in the deploy script. This allows them to be accounted for in `hardhat.config.ts` more easily in the event that there would be a reason to add them.)
+
+**NOTE: Do not change the decimal or token cap of the BZZ token.** These variables are required as is in order for the bonding curve math to work. Changing these variables may result in unexpected behaviour.
+
+The deployment script itself has been split into deployment for testing and deployment for Mainnet. This has been done to reduce friction for testing. Below both deployment scripts shall be explained and walked through.
+
+## Testnet Deployment
+
+The deploy script functions differently when deploying in testing environments (Goerli and local) from mainnet.
+
+In testing environments, the script will deploy the BZZ token and bonding curve, as well as a Mock DAI. The script will also mint the test user address some Mock DAI. This speeds up the testing process.
+
+Please ensure that you have filled in all the following values from the `.env.example` before attempting to run the script (private key and Infura API key are only necessary for Goerli):
+
+```
+# Deployer EOA private key
+GOERLI_DEPLOYER_PRIV_KEY=
+
+# Infura key
+GOERLI_INFURA_KEY=
+
+# TESTING SET UP
+ # Mock DAI (for testing) set up
+ COLLATERAL_TOKEN_NAME=
+ COLLATERAL_TOKEN_SYMBOL=
+ COLLATERAL_TOKEN_DECIMAL=18
+
+ # BZZ token set up variables
+ TOKEN_NAME=
+ TOKEN_SYMBOL=
+ # BZZ token has 16 decimals. DO NOT CHANGE THIS! This will break the bonding curve
+ TOKEN_DECIMAL=16
+ # BZZ needs this limit for the curve. DO NOT CHANGE THIS! This will break the bonding curve
+ TOKEN_CAP=1250000000000000000000000
+
+ # Testing address
+ ADDRESS_OF_TESTER=
+```
+
+Please note that private keys need should not start with `0x` and will fail if they have been prefixed.
+
+When deploying locally please ensure a Hardhat development chain is running.
+To deploy locally run the following:
+
+```
+yarn deploy
+```
+
+When deploying to Goerli please ensure that the private key being used has Goerli ETH. [You can get Goerli ETH from the facet.](https://goerli-faucet.dappnode.net/) To deploy on Goerli, first go to `packages/chain/hardhat.config.ts` and uncomment the `goerli` network object:
+```
+goerli: {
+ url: `https://goerli.infura.io/v3/${process.env.GOERLI_INFURA_KEY}`,
+ accounts: [`${process.env.GOERLI_DEPLOYER_PRIV_KEY}`],
+},
+```
+Then run the following:
+```
+yarn deploy --network goerli
+```
+
+## Mainnet Deployment
+
+The mainnet deployment script will **only deploy the bonding curve**. You will need to enter the address of the deployed BZZ token into the `.env`. Please note that deploying the curve will not initialise it, this will need to be done manually either through [Remix](http://remix.ethereum.org/) or [Etherscan](https://etherscan.io/).
+
+Before running the deployment script, please ensure the following fields have been filled out in the `.env`:
+
+```
+# Deployer EOA private key
+MAINNET_DEPLOYER_PRIV_KEY=
+
+# Infura key (rinkeby + mainnet)
+MAINNET_INFURA_KEY=
+
+# BZZ bonding curve set up variables
+BZZ_DEPLOYED_MAINNET=
+DAI_ADDRESS_MAINNET=0x6b175474e89094c44da98b954eedeac495271d0f
+OWNER_ADDRESS=
+```
+
+Ensure the provided private key has sufficient ETH (at least 0.5) before attempting to run the script, and that the address of the deployer is not the same as the address of the owner. The address of DAI on the mainnet has been entered for convenience, but please double check this address before deploying. The address of the owner should preferably be that of a multisig wallet.
+
+Once all the values have been filled in the `.env`, first uncomment the `mainnet` network object in `packages/chain/hardhat.config.ts`:
+```
+mainnet: {
+ url: `https://mainnet.infura.io/v3/${process.env.MAINNET_INFURA_KEY}`,
+ accounts: [`${process.env.MAINNET_DEPLOYER_PRIV_KEY}`],
+},
+```
+Then run the following to deploy to mainnet:
-The command for running only the Eth Broker tests is:
```
-yarn test:chain ./packages/chain/test/broker.test.js
+yarn deploy --network mainnet
```
+
+Once deployment is complete you will have the address of the deployed bonding curve. To initialise the curve please follow the below steps (they will also be printed in the terminal during deployment):
+
+1. Add the BZZ Curve as a minter on the BZZ token
+2. Pre-minted at least the minimum number of tokens on the BZZ token (62500000 1e16)
+3. Ensure the calling address has sufficient collateral to initialise (call `requiredCollateral` on the BZZ curve to get the required collateral amount)
+4. Approve the BZZ curve address as a spender of the required collateral amount
+5. Call the init function
+
+After these steps have been completed the bonding curve will be operational and able to mint and burn tokens in exchange for DAI. Without following these steps the bonding curve will not function.
+
+# System Design
+
+This smart contract ecosystem has been designed to reduce the security risk and interdependency of the contracts. As such, the BZZ token is separate from the BZZ bonding curve. This allows the curve to be shut down independently from the token should the need arise. The BZZ ETH broker is separate from the BZZ curve and interacts like a normal user with the curve.
+
+
+

+
+
+Should the curve need to be shut down, it will remove itself as minter on the BZZ token. This will leave the BZZ token without a minter, thus capping the supply at the time of shut down at the current supply.
+
+The BZZ broker will check the liveness status of the curve, and will disable minting and burning accordingly.
+
+For more information on each of these contracts please see the specific documentation:
+
+#### [> Token Contract](./packages/chain/docs/token_contract.md)
+#### [> Curve Contract](./packages/chain/docs/curve_contract.md)
+#### [> ETH Broker Contract](./packages/chain/docs/eth_broker_contract.md)
+
+To understand the risks associated with these elevated permissions see:
+
+#### [> Admin Permissions and Risks](./packages/chain/docs/admin_permissions_and_risks.md)
+
+For the audit, see:
+
+#### [> Audit Report and Info](./packages/chain/audit/Audit_report_and_info.md)
+
+Or jump directly to the final audit report:
+
+#### [> Final audit report](./packages/chain/audit/Bzzaar_final_audit_report.pdf)
+
+---
+
+### License
+
+This library is distributed under the BSD-style license found in the LICENSE file.
diff --git a/packages/chain/audit/Buzzar_final_audit_report.pdf b/packages/chain/audit/Bzzaar_final_audit_report.pdf
similarity index 100%
rename from packages/chain/audit/Buzzar_final_audit_report.pdf
rename to packages/chain/audit/Bzzaar_final_audit_report.pdf
diff --git a/packages/chain/contracts/Eth_broker.sol b/packages/chain/contracts/Eth_broker.sol
index 533b85b..0cae0a5 100644
--- a/packages/chain/contracts/Eth_broker.sol
+++ b/packages/chain/contracts/Eth_broker.sol
@@ -22,7 +22,6 @@ contract Eth_broker {
// -------------------------------------------------------------------------
// Events
// -------------------------------------------------------------------------
-
// Emitted when tokens are minted
event mintTokensWithEth(
address indexed buyer, // The address of the buyer
@@ -217,7 +216,7 @@ contract Eth_broker {
mutex()
returns (bool)
{
- (uint256 daiNeeded, uint256 ethReceived) = _commonMint(
+ (uint256 daiNeeded, uint256 ethReceived, uint256 ethSpent) = _commonMint(
_tokenAmount,
_maxDaiSpendAmount,
_deadline,
@@ -228,7 +227,7 @@ contract Eth_broker {
msg.sender,
_tokenAmount,
daiNeeded,
- ethReceived,
+ ethSpent,
_maxDaiSpendAmount
);
// Returning that the mint executed successfully
@@ -263,7 +262,7 @@ contract Eth_broker {
mutex()
returns (bool)
{
- (uint256 daiNeeded, uint256 ethReceived) = _commonMint(
+ (uint256 daiNeeded, uint256 ethReceived, uint256 ethSpent) = _commonMint(
_tokenAmount,
_maxDaiSpendAmount,
_deadline,
@@ -275,7 +274,7 @@ contract Eth_broker {
_to,
_tokenAmount,
daiNeeded,
- ethReceived,
+ ethSpent,
_maxDaiSpendAmount
);
// Returning that the mint executed successfully
@@ -339,7 +338,7 @@ contract Eth_broker {
"Curve burn failed"
);
// Getting expected ETH for DAI
- uint256 ethMin = sellRewardDai(_minDaiSellValue);
+ uint256 ethMin = sellRewardDai(dai_.balanceOf(address(this)));
// Approving the router as a spender
require(
dai_.approve(
@@ -349,6 +348,7 @@ contract Eth_broker {
"DAI approve failed"
);
// Selling DAI received for ETH
+ uint[] memory swapOutputs = new uint[](2);
router_.swapExactTokensForETH(
daiReward,
ethMin,
@@ -361,7 +361,7 @@ contract Eth_broker {
msg.sender,
_tokenAmount,
daiReward,
- ethMin,
+ swapOutputs[1],
_minDaiSellValue
);
// Returning that the burn executed successfully
@@ -406,7 +406,8 @@ contract Eth_broker {
internal
returns(
uint256 daiNeeded,
- uint256 ethReceived
+ uint256 ethReceived,
+ uint256 ethSpent
)
{
// Getting the exact needed amount of DAI for desired token amount
@@ -417,7 +418,9 @@ contract Eth_broker {
"DAI required for trade above max"
);
// Swapping sent ETH for exact amount of DAI needed
- router_.swapETHForExactTokens.value(msg.value)(
+ uint256[] memory swapOutputs = new uint[](2);
+
+ swapOutputs = router_.swapETHForExactTokens.value(msg.value)(
daiNeeded,
getPath(true),
address(this),
@@ -425,6 +428,7 @@ contract Eth_broker {
);
// Getting the amount of ETH received
ethReceived = address(this).balance;
+ ethSpent = swapOutputs[0];
// Approving the curve as a spender
require(
dai_.approve(address(curve_), daiNeeded),
diff --git a/packages/chain/docs/Swarm-design.png b/packages/chain/docs/Swarm-design.png
new file mode 100644
index 0000000..e8c816b
Binary files /dev/null and b/packages/chain/docs/Swarm-design.png differ
diff --git a/packages/chain/docs/Swarm_Logo_Small.png b/packages/chain/docs/Swarm_Logo_Small.png
new file mode 100644
index 0000000..876d5b8
Binary files /dev/null and b/packages/chain/docs/Swarm_Logo_Small.png differ
diff --git a/packages/chain/docs/admin_permissions_and_risks.md b/packages/chain/docs/admin_permissions_and_risks.md
new file mode 100644
index 0000000..098a9ca
--- /dev/null
+++ b/packages/chain/docs/admin_permissions_and_risks.md
@@ -0,0 +1,95 @@
+
+

+
BZZ Smart Contract Ecosystem
+
Admin Permissions and Risks
+
+
+---
+
+# Index
+
+#### [Admin Permissions and Risks](#admin-permissions-and-risks)
+
+- [Ownable](#ownable) in Curve
+ - [Owner Permissions](#owner-permissions)
+ - [Risks of Ownership](#risks-of-ownership)
+- [MinterRole](#minterrole) in Token
+ - [MinterRole permissions](#minterrole-permissions)
+ - [Risks of MinterRole](#risks-of-minterrole)
+- [Shut Down](#shutdown) in Curve
+ - [Shutdown Risks](#shutdown-risks)
+- [Initialising](#initialising) in curve
+
+### Additional documentation
+
+#### [< `README`](../../../README.md)
+#### [~ Admin Permissions and Risks](./admin_permissions_and_risks.md)
+#### [> Audit Report and Info](../audit/Audit_report_and_info.md)
+#### [> Token Contract](./token_contract.md)
+#### [> Curve Contract](./curve_contract.md)
+#### [> ETH Broker Contract](./eth_broker_contract.md)
+
+---
+
+# Admin Permissions and Risks
+
+## Ownable
+
+The curve is Ownable, using the [OpenZeppelin Ownable smart contract](https://docs.openzeppelin.com/contracts/2.x/api/ownership). Through ownership, the owner can call functions that require elevated permissions. These elevated permissions will be explored in each of the specific instances. In this section, we will specifically discuss the ownable permissions and risks.
+
+### Owner Permissions
+
+1. The owner is able to call role protected functions `onlyOwner()`.
+2. The owner is able to renounce their ownership `renounceOwnership()`.
+3. The owner is able to transfer their ownership role to another address `transferOwnership(address newOwner)`.
+
+### Risks of Ownership
+
+It should be noted that the `owner` address will be a multiple signature smart contract wallet. This significantly decreases the risk of a "rouge" owner, and the risk of the owner wallet becoming compromised.
+
+1. Risks associated with raised permissions will be explored in the specific instances in the shutdown section.
+2. Should the owner choose to renounce their ownership the curve will not have an owner, and a new one can never be added. The side affects of the curve becoming un-owned will be explored in the specific instances in the shutdown section.
+3. Should the owner transfer ownership away from the multi-sig the new owner would be able to execute the raised permission protected functions.
+
+## MinterRole
+
+The token contract is both [OpenZeppelin (v2.x) `mintable`](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20Mintable) and [OpenZeppelin (v2.x) `burnable`](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20Burnable). In the token there is a permissioning change so that the `burnable` functions are protected by the same `minterRole` protections provided by the `mintable` contract.
+
+### MinterRole permissions
+
+Unlike the [Ownable](#ownable) role protections, `mintable` allows for multiple addresses to have the `mintable` role on the token contract. This role can be transferred, renounced, and new addresses added.
+
+This role allows addresses with the permissions to mint tokens freely. As burnable has been added to the protected role, addresses will also need the `minterRole` in order to `burn` and `burnFrom` against the token. The `burn` and `burnFrom` functionality was added under this protection to prevent a situation where a user might unknowingly burn tokens against the token contract instead of the curve contract, resulting in them permanently loosing the tokens without compensation.
+
+### Risks of MinterRole
+
+It should be noted that the `minterRole` will never be owned by more than one address. When the token is deployed the `minterRole` will be held by the same multiple signature smart contract wallet as the `ownable` role on the curve. During their mintable period, the pre-mint amount (125 000 000 bonded tokens) will be minted and distributed. When the curve is deployed the `minterRole` will be transferred, leaving the curve as the sole minter. Should the curve ever shut down, the token supply will become capped at the circulating supply at that time.
+
+1. Should a malicious address gain `minterRole` permissions, they would be able to mint tokens unchecked. The address would not be able to burn other users tokens unless those users have approved the address as a spender.
+2. Should the `minterRole` address choose to renounce their role without passing the permissions onto the curve, the token supply will become capped at the circulating supply and the curve will never be functional (it requires `minterRole` permissions in order to function).
+
+## Shutdown
+
+The curve has a shut down function protected by the `onlyOwner()` modifier. This `shutDown()` function allows the owner to permanently disable the curve's functionality, as well as the curve renouncing it's minter role on the token contract. Once the shut down function is called there will no longer be a minter on the token contract, effectively capping the token supply at the supply at the time of shut down.
+
+### Shutdown Risks
+
+1. Should an admin choose to, they are be able to shut down the curve and cap the supply. They would not be able to withdraw any collateral from the curve or mint themselves any tokens.
+2. Should an admin choose to renounce their ownership, the curve contract would be left without an owner. This would mean that the curve could never be shut down. This could have negative implications in the instance of a vulnerability being discovered on the curve. The curve would not be able to be disabled, and the potential for the curve to be drained is present.
+3. Should the ownership be transferred to a rouge account, the new owner would be able to cap the token supply by shutting down the curve contract.
+
+## Initialising
+
+This section will briefly cover the initialisation process, as while this is not a admin/owner protected role, it is important that the process is understood.
+
+The `init()` function allows _any_ address to call it. Calling init will only succeed if the following criteria is met:
+
+1. The curve contract has been deployed (`msg.sender` will become owner, see [Ownable](#ownable) for permissions and risks).
+2. The token has been set up as a minter on the BZZ token contract.
+3. The curve has not already been initialized.
+4. The BZZ token contract has already minted the required pre-mint amount.
+5. The caller has approved the curve as a spender of the required collateral amount in the given collateral currency (DAI). This amount can be checked by calling `requiredCollateral()` on the curve contract.
+
+If all the above criteria is met the function will transfer the required amount of collateral to the curve from the calling user. The function will then activate the curve and the curve will become operational for buy and sell functionally.
+
+---
\ No newline at end of file
diff --git a/packages/chain/docs/curve_contract.md b/packages/chain/docs/curve_contract.md
new file mode 100644
index 0000000..03ca274
--- /dev/null
+++ b/packages/chain/docs/curve_contract.md
@@ -0,0 +1,229 @@
+
+

+
BZZ Smart Contract Ecosystem
+
Curve Contract
+
+
+---
+
+# Index
+
+#### [Curve Contract](#curve-contract)
+
+- [Interface](#interface)
+- [Inheritance](#inheritance)
+- [Implementation](#implementation)
+ - [Views](#views)
+ - [`buyPrice`](#buyprice)
+ - [`sellReward`](#sellreward)
+ - [`isCurveActive`](#iscurveactive)
+ - [`requiredCollateral`](#requiredcollateral)
+ - [`bondedToken`](#bondedtoken)
+ - [`collateralToken`](#collateraltoken)
+ - [State Modifying](#state-modifying)
+ - [`init`](#init)
+ - [`mint`](#mint)
+ - [`burn`](#burn)
+ - [`shutDown`](#shutdown)
+
+### Additional documentation
+
+#### [< `README`](../../../README.md)
+#### [~ Curve Contract](./curve_contract.md)
+#### [> Audit Report and Info](../audit/Audit_report_and_info.md)
+#### [> Admin Permissions and Risks](./admin_permissions_and_risks.md)
+#### [> Token Contract](./token_contract.md)
+#### [> ETH Broker Contract](./eth_broker_contract.md)
+
+---
+
+# Curve Contract
+
+The curve contract enables users to be able to mint and burn [BZZ Tokens](./token_contract.md) with the selected collateral currency (DAI).
+
+## Interface
+
+The full interface of publicly callable functions for the Token contract can be found [here](../contracts/I_Curve.sol).
+
+## Inheritance
+
+The curve contract inherits `ownable` and `I_Curve`. For more information around the `ownable` risks, see [admin permissions and risks: Ownable](./admin_permissions_and_risks.md#ownable).
+
+## Implementation
+
+Below is a function by function breakdown of the curve contract.
+
+### Views
+
+Below is a function by function breakdown of the `view` (non state changing) curve functions.
+
+#### `buyPrice`
+
+**Purpose:** The `buyPrice` function allows a user to check how much it will cost them in the collateral token (DAI) to buy the desired amount of the bonded token (BZZ).
+
+**Parameters:**
+- The `_amount` of bonded tokens (BZZ) the user would like to buy.
+
+**Returns:**
+- The `collateralRequired` in the collateral token (DAI) to buy the desired amount of bonded tokens.
+
+**Possible Exceptions:**
+- If the curve has not been initialised the function will revert with `"Curve inactive"`.
+
+#### `sellReward`
+
+**Purpose:** The `sellReward` function allows a user to check how much they can get in collateral tokens (DAI) for selling the desired amount of bonded tokens (BZZ).
+
+**Parameters:**
+- The `_amount` of bonded tokens (BZZ) the user would like to sell.
+
+**Returns:**
+- The `collateralReward` in collateral token (DAI) the user would receive for selling the specified amount of bonded tokens (BZZ).
+
+**Possible Exceptions:**
+- If the curve has not been initialised the function will revert with `"Curve inactive"`.
+
+#### `isCurveActive`
+
+**Purpose:** Allows a user to check that the curve contract has been initialised and has not been shut down.
+
+**Parameters:**
+- N/A
+
+**Returns:**
+- Will return `true` if the curve is initialised and active. Will return `false` if the curve has not been initialised or if the curve has been shut down.
+
+**Possible Exceptions:**
+- N/A
+
+#### `requiredCollateral`
+
+**Purpose:** Allows a user to check how much collateral token (DAI) would be needed to initialise the curve given the `_initialSupply` passed in. This allows a user to know how many collateral tokens to approve the curve as a spender on in order to initialise the contract.
+
+**Parameters:**
+- The `_initialSupply` expected.
+
+**Returns:**
+- The amount of collateral tokens needed in order to back fill the curve for all the minted tokens.
+
+**Possible Exceptions:**
+- N/A. **Note** that this function will not revert if the `_initialSupply` is less than the required pre-mint amount.
+
+#### `bondedToken`
+
+**Purpose:** Allows a user to check the address of the bonded token (BZZ).
+
+**Parameters:**
+- N/A
+
+**Returns:**
+- The address of the bonded token.
+
+**Possible Exceptions:**
+- N/A
+
+#### `collateralToken`
+
+**Purpose:** Allows a user to check the address off the collateral token (DAI).
+
+**Parameters:**
+- N/A
+
+**Returns:**
+- The address of the collateral token.
+
+**Possible Exceptions:**
+- N/A
+
+### State Modifying
+
+Below is a function by function breakdown of the state modifying curve functions.
+
+#### `init`
+This function will initialise the curve so that it can start functioning as the bonded curve to the bonded token. This function requires the caller to have approved the curve for the required collateral amount (this can be checked by calling [`requiredCollateral`](#requiredcollateral)). The user will also need to have the same required amount of collateral token in their wallet.
+
+**Purpose:** Allows a user to initialise the curve contract, and back fill the collateral token need for the pre-mint amount.
+
+**Parameters:**
+- N/A
+
+**Returns:**
+- N/A
+
+**Possible Exceptions:**
+- If the curve has already been initialised the revert message will be `"Curve is init"`.
+- If the curve has not been given `minterRole` permissions on the bonded token the revert message will be `"Curve is not minter"`.
+- If the bonded tokens supply is less than the expected pre-mint amount the revert message will be `"Curve equation requires pre-mint"`.
+- If the calling address has not _both approved and has_ the required collateral to back fill the curve in collateral tokens for the pre-mint amount the revert message will be `"Failed to collateralized the curve"`.
+
+#### `mint`
+
+**Purpose:** Allows the user to mint bonded tokens in exchange for the collateral token cost.
+
+**Parameters:**
+- The `_amount` of bonded tokens the user wants to buy.
+- The `_maxCollateralSpend` is the max amount of collateral tokens the user wants to spend in order to buy the desired amount of bonded tokens.
+
+**Returns:**
+- The `success` state of the mint. If `true` the mint executed successfully.
+
+**Events:**
+```
+// Emitted when tokens are minted
+ event mintTokens(
+ address indexed buyer, // The address of the buyer
+ uint256 amount, // The amount of bonded tokens to mint
+ uint256 pricePaid, // The price in collateral tokens
+ uint256 maxSpend // The max amount of collateral to spend
+ );
+```
+
+**Possible Exceptions:**
+- If the cost to buy the `_amount` of bonded tokens is higher than the users `_maxCollateralSpend` amount, the revert message will be `"Price exceeds max spend"`.
+- If the user has not approved the curve as a spender of the required amount of collateral the revert message will be `"Transferring collateral failed"`.
+- If the bonded token mint fails the revert message will be `"Minting tokens failed"`. **Note** that should this revert message be received there is a fatal flaw. This message should not be received.
+
+#### `burn`
+
+**Purpose:** Allows the user to sell bonded tokens in exchange for the collateral token reward.
+
+**Parameters:**
+- The `_amount` of tokens the user would like to sell.
+- The `_minCollateralReward` is the minimum amount of collateral the user is willing to receive in exchange for their bonded tokens.
+
+**Returns:**
+- The `success` state of the burn. If `true` the burn executed successfully.
+
+**Events:**
+```
+// Emitted when tokens are burnt
+ event burnTokens(
+ address indexed seller, // The address of the seller
+ uint256 amount, // The amount of bonded tokens to sell
+ uint256 rewardReceived, // The collateral tokens received
+ uint256 minReward // The min collateral reward for tokens
+ );
+```
+
+**Possible Exceptions:**
+- If the reward for selling the `_amount` of bonded tokens is lower than the `_minCollateralReward` the revert message will be `"Reward under min sell"`.
+- If the curve fails to send the user the required amount of collateral tokens the revert message will be `"Transferring collateral failed"`. **Note** that should this revert message be received there is a fatal flaw. This message should not be received.
+
+#### `shutDown`
+
+**Purpose:** Allows the owner to shut down the curve, so that the bonding curve can no longer mint or burn user tokens.
+
+**Parameters:**
+- N/A
+
+**Returns:**
+- N/A
+
+**Events:**
+```
+// Emitted when the curve is permanently shut down
+ event shutDownOccurred(address indexed owner);
+```
+
+**Possible Exceptions:**
+- Should the curve already be removed as a `minterRole` from the token the revert message will be `"Roles: account does not have role"`. **Note** that should this revert message be received there is a fatal flaw. This message should not be received.
\ No newline at end of file
diff --git a/packages/chain/docs/eth_broker_contract.md b/packages/chain/docs/eth_broker_contract.md
new file mode 100644
index 0000000..a7ba495
--- /dev/null
+++ b/packages/chain/docs/eth_broker_contract.md
@@ -0,0 +1,185 @@
+
+

+
BZZ Smart Contract Ecosystem
+
ETH Broker Contract
+
+
+---
+
+# Index
+
+#### [ETH Broker Contract](#eth-broker-contract)
+
+- [Inheritance](#inheritance)
+- [Implementation](#implementation)
+ - [Views](#views)
+ - [`buyPrice`](#buyprice)
+ - [`sellReward`](#sellreward)
+ - [`sellRewardDai`](#sellrewarddai)
+ - [`getPath`](#getpath)
+ - [`getTime`](#gettime)
+ - [State Modifying](#state-modifying)
+ - [`mint`](#mint)
+ - [`burn`](#burn)
+ - [Fallback Function](#fallback-function)
+
+### Additional documentation
+
+#### [< `README`](../../../README.md)
+#### [~ ETH Broker Contract](./eth_broker_contract.md)
+#### [> Audit Report and Info](../audit/Audit_report_and_info.md)
+#### [> Admin Permissions and Risks](./admin_permissions_and_risks.md)
+#### [> Token Contract](./token_contract.md)
+#### [> Curve Contract](./curve_contract.md)
+
+---
+
+# ETH Broker Contract
+
+The ETH broker contract enables users to be able to mint and burn [BZZ Tokens](./token_contract.md) with ETH rather than the collateral currency (DAI).
+
+## Implementation
+
+Below is a function by function breakdown of the curve contract.
+
+### Views
+
+#### `buyPrice`
+
+**Purpose:** The `buyPrice` function allows a user to check how much it will cost them in ETH to buy the desired amount of the bonded token (BZZ).
+
+**Parameters:**
+- The `_amount` of bonded tokens the user would like to buy.
+
+**Returns:**
+- The ETH cost for buying the token amount.
+
+**Possible Exceptions:**
+- N/A
+
+#### `sellReward`
+
+**Purpose:** The `sellReward` function allows the user to check how much ETH they will get for selling the specified amount of bonded tokens (BZZ).
+
+**Parameters:**
+- The `_amount` of bonded tokens the user would like to sell.
+
+**Returns:**
+- The ETH reward for selling the specified amount of bonded tokens.
+
+**Possible Exceptions:**
+- N/A
+
+#### `sellRewardDai`
+
+**Purpose:** Allows a user to see the current conversion rate between the collateral token of the curve (DAI) and ETH.
+
+**Parameters:**
+- The `_daiAmount`.
+
+**Returns:**
+- The ETH amount the user can get for selling the specified DAI amount.
+
+**Possible Exceptions:**
+- N/A
+
+#### `getPath`
+
+**Purpose:** Gets the trading path needed by Uniswap to trade between DAI and ETH.
+
+**Parameters:**
+- A `bool` switch for if it is a buy path.
+
+**Returns:**
+- If the `bool` is `true` then the path will return the WETH address followed by the DAI address, if `false` it will return the DAI address first, WETH second.
+
+**Possible Exceptions:**
+- N/A
+
+#### `getTime`
+
+**Purpose:** To return the current time stamp held on the blockchain.
+
+**Parameters:**
+- N/A
+
+**Returns:**
+- The current Unix time stamp.
+
+**Possible Exceptions:**
+- N/A
+
+### State Modifying
+
+#### `mint`
+
+**Purpose:** Allows a user to mint the curves bonded tokens (BZZ) with ETH.
+
+**Parameters:**
+- The `_tokenAmount` of bonded tokens the user would like to buy.
+- The `_maxDaiSpendAmount` is the max amount of collateral tokens the user wants to spend in order to buy the desired amount of bonded tokens.
+- The time stamp `_deadline` by which the transaction will expire and revert.
+
+**Returns:**
+- The success state of the mint. If `true` the mint executed successfully.
+
+**Events:**
+```
+// Emitted when tokens are minted
+ event mintTokensWithEth(
+ address indexed buyer, // The address of the buyer
+ uint256 amount, // The amount of bonded tokens to mint
+ uint256 priceForTokensDai, // The price in DAI for the token amount
+ uint256 EthTradedForDai, // The ETH amount sold for DAI
+ uint256 maxSpendDai // The max amount of DAI to spend
+ );
+```
+
+**Possible Exceptions:**
+- If the required DAI amount is higher than the users `_maxDaiSpendAmount` then the revert message will be `"DAI required for trade above max"`.
+- If the transferring of BZZ from the broker to the user fails the revert message will be `"Transferring of bzz failed"`. **Note** that should this revert message be received there is a fatal flaw. This message should not be received.
+
+#### `burn`
+
+**Purpose:** Allows a user to burn their bonded tokens (BZZ) for ETH.
+
+**Parameters:**
+- The `_tokenAmount` of bonded tokens (BZZ) the user would like to buy.
+- The `_minDaiSellValue` is the minimum amount of collateral token (DAI) the user is willing to receive for selling the specified amount of bonded tokens.
+- The time stamp `_deadline` by which the transaction will expire and revert.
+
+**Returns:**
+- The success state of the burn. If `true` the burn executed successfully.
+
+**Events:**
+```
+// Emitted when tokens are burnt
+ event burnTokensWithEth(
+ address indexed seller, // The address of the seller
+ uint256 amount, // The amount of bonded tokens to burn
+ uint256 rewardReceivedDai, // The amount of DAI received for selling
+ uint256 ethReceivedForDai, // How much ETH the DAI was traded for
+ uint256 minRewardDai // The min amount of DAI to sell for
+ );
+```
+
+**Possible Exceptions:**
+- If the DAI reward for selling the bonded tokens is below the users `_minDaiSellValue` then the revert message will be `"DAI required for trade below min"`.
+- If the user has not approved the broker as a spender of their bonded tokens (BZZ) the revert message will be `"Transferring BZZ failed"`.
+- If the broker fails to burn the bonded tokens against the curve the revert message will be `"Curve burn failed"`. **Note** that should this revert message be received there is a fatal flaw. This message should not be received.
+
+#### Fallback Function
+
+**Purpose:** Allows the Uniswap router to send ETH to the broker.
+
+**Parameters:**
+- N/A
+
+**Returns:**
+- N/A
+
+**Events:**
+- N/A
+
+**Possible Exceptions:**
+- If the `msg.sender` is not the router address the revert message will be `"ETH not accepted outside router"`.
\ No newline at end of file
diff --git a/packages/chain/docs/imgs_token-inheritance-full.png b/packages/chain/docs/imgs_token-inheritance-full.png
new file mode 100644
index 0000000..294d356
Binary files /dev/null and b/packages/chain/docs/imgs_token-inheritance-full.png differ
diff --git a/packages/chain/docs/imgs_token-inheritance.png b/packages/chain/docs/imgs_token-inheritance.png
new file mode 100644
index 0000000..e09e7d3
Binary files /dev/null and b/packages/chain/docs/imgs_token-inheritance.png differ
diff --git a/packages/chain/docs/token_contract.md b/packages/chain/docs/token_contract.md
new file mode 100644
index 0000000..f54feed
--- /dev/null
+++ b/packages/chain/docs/token_contract.md
@@ -0,0 +1,111 @@
+
+

+
BZZ Token Contract
+
+
+---
+
+# Index
+
+#### [BZZ Token Contract](#bzz-token-contract)
+
+- [Interface](#interface)
+- [Inheritance](#inheritance)
+ - [ERC20Detailed](#erc20detailed)
+ - [ERC20Capped](#erc20capped)
+ - [ERC20Burnable](#erc20burnable)
+- [Inheritance Visuals](#inheritance-visuals)
+ - [Simplified](#simplified)
+ - [Complete](#complete)
+
+### Additional documentation
+
+#### [< `README`](../../../README.md)
+#### [~ Token Contract](./token_contract.md)
+#### [> Admin Permissions and Risks](./admin_permissions_and_risks.md)
+#### [> Curve Contract](./curve_contract.md)
+#### [> ETH Broker Contract](./eth_broker_contract.md)
+
+---
+
+# BZZ Token Contract
+
+The Token is designed to inherit the following implementations from the [OpenZeppelin library (V2)](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20):
+1. `ERC20` [(docs)](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20)
+ The ERC20 standard as implemented in the OpenZeppelin library.
+2. `ERC20Detailed` [(docs)](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20Detailed)
+ This extension allows for the storing of a name, symbol and explicit decimal.
+3. `ERC20Capped` [(docs)](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20Capped)
+ This extension allows for an explicit cap on the number of tokens that can ever be in existence simultaneously .
+4. `ERC20Mintable` [(docs)](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20Mintable)
+ This extension allows users with the `Mintable` role to mint tokens freely. This is included to allow for future compatibility with a bonding curve.
+5. `ERC20Burnable`[(docs)](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#ERC20Burnable)
+ This allows a user to burn tokens, as well as allows approved addresses to burn tokens on the users behalf. This again is included for future compatibility. **Note that this functionally has been modified in order to have the `burn` and `burnFrom` functionally protected by the `minterRole`.**
+
+## Interface
+
+The full interface of publicly callable functions for the Token contract can be found [here](../contracts/I_Token.sol).
+
+## Inheritance
+
+The `Token` contract inherits the above contracts as follows:
+```
+contract Token is ERC20Detailed, ERC20Capped, ERC20Burnable {
+```
+
+As you can see, it seems as if all the contracts are not there. But when we dig a bit deeper, we can see all the contracts are in fact, present.
+
+### `ERC20Detailed`
+Detailed imports the IERC20 interface:
+```
+contract ERC20Detailed is IERC20 {
+```
+
+### `ERC20Capped`
+Capped is Mintable, meaning that by inheriting capped we are inheriting mintable.
+```
+contract ERC20Capped is ERC20Mintable {
+```
+
+### `ERC20Burnable`
+Burnable inherits from ERC20, so we fully implement the interface imported by Detailed, meaning the contract is not abstract and all ERC20 functionality is present.
+```
+contract ERC20Burnable is Context, ERC20 {
+```
+
+The modifications the the burnable functionality look as follows:
+
+```
+ /**
+ * @dev Destroys `amount` tokens from the caller.
+ *
+ * See {ERC20-_burn}.
+ */
+ function burn(uint256 amount) public onlyMinter {
+ _burn(_msgSender(), amount);
+ }
+
+ /**
+ * @dev See {ERC20-_burnFrom}.
+ */
+ function burnFrom(address account, uint256 amount) public onlyMinter {
+ _burnFrom(account, amount);
+ }
+```
+
+The `onlyMinter` modifier has been added to both functions. This is done to protect users against accidentally burning their tokens. For more information see [admin permissions and risks: MinterRole](./admin_permissions_and_risks.md#minterrole)
+
+### Inheritance Visuals
+
+Below we can see the inheritance (simply) laid out in order. Here we are only looking at the first level of inheritance, i.e we are not looking at what the inherited contracts inherit.
+
+#### Simplified
+This simple diagram shows how all the required extensions are inherited.
+
+
+
+#### Complete
+
+For the full inheritance structure, please see the below diagram
+
+
diff --git a/packages/chain/test/broker.test.js b/packages/chain/test/broker.test.ts
similarity index 93%
rename from packages/chain/test/broker.test.js
rename to packages/chain/test/broker.test.ts
index 64a24dd..6c1fc5c 100644
--- a/packages/chain/test/broker.test.js
+++ b/packages/chain/test/broker.test.ts
@@ -1,37 +1,33 @@
-require("@nomiclabs/hardhat-waffle");
-const hre = require("hardhat");
-const { expect, assert } = require("chai");
-const {
- ethers,
- curve_abi,
- token_abi,
- mock_dai_abi,
- eth_broker_abi,
- mock_router_abi,
+import { formatUnits } from "@ethersproject/units";
+import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
+import { expect, assert } from "chai";
+import { Contract } from "ethers";
+import { ethers, waffle } from "hardhat";
+import {
pre_mint_sequence,
tokenSettings,
test_settings,
-} = require("./settings.test.js");
-const { network } = require("hardhat");
+} from "./settings.test";
+
describe("🤝 Broker tests", () => {
- let investor;
- let owner;
- let user;
- let user_two;
+ let investor: SignerWithAddress;
+ let owner: SignerWithAddress;
+ let user: SignerWithAddress;
+ let user_two: SignerWithAddress;
- let deployer;
- let tokenInstance;
- let curveInstance;
- let collateralInstance;
- let brokerInstance;
- let mockRouterInstance;
- let mockWethInstance;
+ let tokenInstance: Contract;
+ let curveInstance: Contract;
+ let collateralInstance: Contract;
+ let brokerInstance: Contract;
+ let mockRouterInstance: Contract;
+ let mockWethInstance: Contract;
- const provider = new ethers.providers.JsonRpcProvider();
+ const provider = waffle.provider;
beforeEach(async () => {
- const accounts = await ethers.getSigners();
+ await provider.ready
+ const accounts = await ethers.getSigners();
owner = accounts[0];
investor = accounts[1];
user = accounts[2];
@@ -51,7 +47,6 @@ describe("🤝 Broker tests", () => {
tokenSettings.dai.symbol,
tokenSettings.dai.decimals
);
-
const curveArtifacts = await ethers.getContractFactory("Curve");
curveInstance = await curveArtifacts.deploy(
tokenInstance.address,
@@ -99,12 +94,7 @@ describe("🤝 Broker tests", () => {
mockRouterInstance = await mockRouterArtifacts.deploy(
mockWethInstance.address,
);
- // priv key for account 0 of Hardhat
- const ownerWallet = new ethers.Wallet(
- "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
- provider
- );
- await ownerWallet.sendTransaction({
+ await owner.sendTransaction({
to: mockRouterInstance.address,
value: test_settings.eth_broker.eth.seed_eth_amount
});
@@ -248,25 +238,21 @@ describe("🤝 Broker tests", () => {
);
// Testing expected behaviour
- // expect(mockRouterEthBalance.toString()).to.equal(test_settings.eth_broker.eth.seed_eth_amount.toString());
assert.equal(
mockRouterEthBalance.toString(),
test_settings.eth_broker.eth.seed_eth_amount.toString(),
"Eth balance of broker is incorrect"
);
- // expect(mockRouterEthBalanceAfter.toString()).to.equal(test_settings.eth_broker.eth.mock_router_eth_balance_after_swap.toString());
assert.equal(
mockRouterEthBalanceAfter.toString(),
test_settings.eth_broker.eth.mock_router_eth_balance_after_swap.toString(),
"Eth balance of broker is incorrect after swap"
);
- // expect(balanceOfUserDAI.toString()).to.equal(test_settings.eth_broker.dai.almost_one_eth);
assert.equal(
balanceOfUserDAI.toString(),
test_settings.eth_broker.dai.almost_one_eth,
"User started with incorrect DAI balance"
);
- // expect(balanceOfUserDaiAfter.toString()).to.equal("0");
assert.equal(
balanceOfUserDaiAfter.toString(),
0,
@@ -283,7 +269,6 @@ describe("🤝 Broker tests", () => {
it("buy price expected", async () => {
let buyPrice = await brokerInstance.buyPrice(test_settings.bzz.buyAmount);
- // expect(buyPrice.toString()).to.equal(test_settings.eth_broker.eth.buy_price);
assert.equal(
buyPrice.toString(),
test_settings.eth_broker.eth.buy_price,
@@ -300,7 +285,6 @@ describe("🤝 Broker tests", () => {
);
// Testing expected behaviour
- // expect(sellRewardAmount.toString()).to.equal(test_settings.eth_broker.eth.sell_reward);
assert.equal(
sellRewardAmount.toString(),
test_settings.eth_broker.eth.sell_reward,
@@ -317,7 +301,6 @@ describe("🤝 Broker tests", () => {
);
// Testing expected behaviour
- // expect(sellRewardAmount.toString()).to.equal(test_settings.eth_broker.eth.almost_one_eth);
assert.equal(
sellRewardAmount.toString(),
test_settings.eth_broker.eth.almost_one_eth,
@@ -334,25 +317,21 @@ describe("🤝 Broker tests", () => {
let hardCodedWethAddress = "0xacDdD0dBa07959Be810f6cd29E41b127b29E4A8a";
// Testing expected behaviour
- // expect(buyPath[0]).to.equal(hardCodedWethAddress);
assert.equal(
buyPath[0],
hardCodedWethAddress,
"WETH address in trade route incorrect"
);
- // expect(sellPath[1]).to.equal(hardCodedWethAddress);
assert.equal(
sellPath[1],
hardCodedWethAddress,
"WETH address in trade route incorrect"
);
- // expect(buyPath[1]).to.equal(collateralInstance.address);
assert.equal(
buyPath[1],
collateralInstance.address,
"DAI address in trade route incorrect"
);
- // expect(sellPath[0]).to.equal(collateralInstance.address);
assert.equal(
sellPath[0],
collateralInstance.address,
@@ -365,7 +344,6 @@ describe("🤝 Broker tests", () => {
it("get time works as expected", async () => {
let time = await brokerInstance.getTime();
- // expect(time.toString()).to.not.equal("0");
assert.notEqual(time.toString(), 0, "Time has not be correctly relayed");
});
});
@@ -467,57 +445,47 @@ describe("🤝 Broker tests", () => {
// Testing expected behaviour
assert.equal(
mockRouterEthBalance.toString(),
- test_settings.eth_broker.eth.seed_eth_amount,
+ test_settings.eth_broker.eth.seed_eth_amount.toString(),
"Mock router ETH balance incorrect"
);
-
assert.equal(
mockRouterEthBalanceAfter.toString(),
test_settings.eth_broker.eth.mock_router_eth_balance_after_mint,
"Mock router ETH balance incorrect after mint"
);
-
assert.notEqual(
userEthBalance.toString(),
userEthBalanceAfter.toString(),
"User ETH balance does not change with mint"
);
-
assert.equal(
daiCost.toString(),
test_settings.dai.buyCost,
"DAI cost for token amount unexpected"
);
-
assert.equal(
ethCost.toString(),
test_settings.eth_broker.eth.buy_price,
"ETH cost for token amount unexpected"
);
-
assert.equal(
buyPrice.toString(),
test_settings.eth_broker.eth.buy_price,
"ETH (raw) cost for token amount unexpected"
);
// user balances changes as expected with mint
-
assert.equal(userDaiBalance.toString(), 0, "User starts without DAI");
-
assert.equal(userBzzBalance.toString(), 0, "User starts without BZZ");
-
assert.notEqual(
userEthBalance.toString(),
userEthBalanceAfter.toString(),
"User ETH balance did not change with mint"
);
-
assert.equal(
userDaiBalanceAfter.toString(),
0,
"User DAI balance incorrectly changed with eth mint"
);
-
assert.equal(
userBzzBalanceAfter.toString(),
test_settings.bzz.buyAmount,
@@ -525,31 +493,26 @@ describe("🤝 Broker tests", () => {
);
// broker balance remains 0 on all assets
assert.equal(0, brokerDaiBalance.toString(), "broker dai balance non 0");
-
assert.equal(
brokerBzzBalance.toString(),
brokerDaiBalance.toString(),
"broker bzz balance non 0"
);
-
assert.equal(
brokerEthBalance.toString(),
brokerDaiBalance.toString(),
"broker eth balance non 0"
);
-
assert.equal(
brokerDaiBalanceAfter.toString(),
brokerDaiBalance.toString(),
"broker dai balance after non 0"
);
-
assert.equal(
brokerBzzBalanceAfter.toString(),
brokerDaiBalance.toString(),
"broker bzz balance after non 0"
);
-
assert.equal(
brokerEthBalanceAfter.toString(),
brokerDaiBalance.toString(),
@@ -561,7 +524,6 @@ describe("🤝 Broker tests", () => {
pre_mint_sequence.dai.cost,
"Curve DAI is not as expected before mint"
);
-
assert.equal(
curveDaiBalanceAfter.toString(),
test_settings.dai.curve_collateral_after_buy,
@@ -573,7 +535,6 @@ describe("🤝 Broker tests", () => {
test_settings.eth_broker.bzz.initial_supply,
"initial supply of bzz token unexpected"
);
-
assert.equal(
tokenSupplyAfter.toString(),
test_settings.eth_broker.bzz.after_buy,
@@ -585,13 +546,11 @@ describe("🤝 Broker tests", () => {
mockRouterBzzBalanceAfter.toString(),
"Mock router BZZ balance incorrect (non 0)"
);
-
assert.equal(
mockRouterDaiBalance.toString(),
test_settings.eth_broker.eth.seed_eth_amount,
"mock router starts with incorrect dai balance"
);
-
assert.equal(
mockRouterDaiBalanceAfter.toString(),
test_settings.eth_broker.dai.mock_router_dai_balance_after_mint,
@@ -691,22 +650,19 @@ describe("🤝 Broker tests", () => {
// Testing expected behaviour
assert.equal(
mockRouterEthBalance.toString(),
- test_settings.eth_broker.eth.seed_eth_amount,
+ test_settings.eth_broker.eth.seed_eth_amount.toString(),
"Mock router ETH balance incorrect"
);
-
assert.equal(
mockRouterEthBalanceAfter.toString(),
test_settings.eth_broker.eth.mock_router_eth_balance_after_mint,
"Mock router ETH balance incorrect after mint"
);
-
assert.notEqual(
userEthBalance.toString(),
userEthBalanceAfter.toString(),
"User ETH balance does not change with mint"
);
-
assert.equal(
daiCost.toString(),
test_settings.dai.buyCost,
@@ -718,7 +674,6 @@ describe("🤝 Broker tests", () => {
test_settings.eth_broker.eth.buy_price,
"ETH cost for token amount unexpected"
);
-
assert.equal(
buyPrice.toString(),
test_settings.eth_broker.eth.buy_price,
@@ -726,21 +681,17 @@ describe("🤝 Broker tests", () => {
);
// user balances changes as expected with mint
assert.equal(userDaiBalance.toString(), 0, "User starts without DAI");
-
assert.equal(userBzzBalance.toString(), 0, "User starts without BZZ");
-
assert.notEqual(
userEthBalance.toString(),
userEthBalanceAfter.toString(),
"User ETH balance did not change with mint"
);
-
assert.equal(
userDaiBalanceAfter.toString(),
0,
"User DAI balance incorrectly changed with eth mint"
);
-
assert.equal(
userBzzBalanceAfter.toString(),
0,
@@ -748,21 +699,17 @@ describe("🤝 Broker tests", () => {
);
// user receiver balances changes as expected with mint
assert.equal(userReceiverDaiBalance.toString(), 0, "User starts without DAI");
-
assert.equal(userReceiverBzzBalance.toString(), 0, "User starts without BZZ");
-
assert.notEqual(
userReceiverEthBalance.toString(),
userEthBalanceAfter.toString(),
"User ETH balance did not change with mint"
);
-
assert.equal(
userReceiverDaiBalanceAfter.toString(),
0,
"User DAI balance incorrectly changed with eth mint"
);
-
assert.equal(
userReceiverBzzBalanceAfter.toString(),
test_settings.bzz.buyAmount.toString(),
@@ -770,31 +717,26 @@ describe("🤝 Broker tests", () => {
);
// broker balance remains 0 on all assets
assert.equal(0, brokerDaiBalance.toString(), "broker dai balance non 0");
-
assert.equal(
brokerBzzBalance.toString(),
brokerDaiBalance.toString(),
"broker bzz balance non 0"
);
-
assert.equal(
brokerEthBalance.toString(),
brokerDaiBalance.toString(),
"broker eth balance non 0"
);
-
assert.equal(
brokerDaiBalanceAfter.toString(),
brokerDaiBalance.toString(),
"broker dai balance after non 0"
);
-
assert.equal(
brokerBzzBalanceAfter.toString(),
brokerDaiBalance.toString(),
"broker bzz balance after non 0"
);
-
assert.equal(
brokerEthBalanceAfter.toString(),
brokerDaiBalance.toString(),
@@ -806,7 +748,6 @@ describe("🤝 Broker tests", () => {
pre_mint_sequence.dai.cost,
"Curve DAI is not as expected before mint"
);
-
assert.equal(
curveDaiBalanceAfter.toString(),
test_settings.dai.curve_collateral_after_buy,
@@ -818,7 +759,6 @@ describe("🤝 Broker tests", () => {
test_settings.eth_broker.bzz.initial_supply,
"initial supply of bzz token unexpected"
);
-
assert.equal(
tokenSupplyAfter.toString(),
test_settings.eth_broker.bzz.after_buy,
@@ -830,13 +770,11 @@ describe("🤝 Broker tests", () => {
mockRouterBzzBalanceAfter.toString(),
"Mock router BZZ balance incorrect (non 0)"
);
-
assert.equal(
mockRouterDaiBalance.toString(),
test_settings.eth_broker.eth.seed_eth_amount,
"mock router starts with incorrect dai balance"
);
-
assert.equal(
mockRouterDaiBalanceAfter.toString(),
test_settings.eth_broker.dai.mock_router_dai_balance_after_mint,
@@ -958,16 +896,14 @@ describe("🤝 Broker tests", () => {
);
// User balance in various currencies expected
assert.equal(userDaiBalance.toString(), 0, "User DAI balance incorrect");
-
assert.equal(
userBzzBalance.toString(),
test_settings.bzz.buyAmount.toString(),
"User BZZ balance incorrect"
);
-
assert.notEqual(
userEthBalance.toString(),
- 0,
+ "0",
"User ETH balance incorrect"
);
// broker balances are as expected
@@ -976,16 +912,14 @@ describe("🤝 Broker tests", () => {
0,
"broker incorrectly has a balance in DAI"
);
-
assert.equal(
brokerBzzBalance.toString(),
0,
"broker incorrectly has a balance in BZZ"
);
-
assert.equal(
brokerEthBalance.toString(),
- 0,
+ "0",
"broker incorrectly has a balance in ETH"
);
// Curve has correct balance
@@ -1000,13 +934,11 @@ describe("🤝 Broker tests", () => {
test_settings.eth_broker.eth.seed_eth_amount.toString(),
"Mock router has incorrect DAI balance"
);
-
assert.equal(
mockRouterBzzBalance.toString(),
0,
"Mock router has incorrect BZZ balance"
);
-
assert.equal(
mockRouterEthBalance.toString(),
test_settings.eth_broker.eth.seed_eth_amount.toString(),
@@ -1018,19 +950,16 @@ describe("🤝 Broker tests", () => {
test_settings.eth_broker.bzz.initial_supply,
"BZZ current supply incorrect"
);
-
assert.equal(
daiCost.toString(),
test_settings.eth_broker.dai.buy_cost,
"DAI cost for token amount unexpected"
);
-
assert.equal(
ethCost.toString(),
test_settings.eth_broker.eth.sell_reward,
"ETH cost for token amount unexpected"
);
-
assert.equal(
buyPrice.toString(),
test_settings.eth_broker.eth.sell_reward,
@@ -1042,13 +971,11 @@ describe("🤝 Broker tests", () => {
0,
"User incorrectly has left over DAI after burn"
);
-
assert.equal(
userBzzBalanceAfter.toString(),
0,
"User incorrectly has left over BZZ after burn"
);
-
assert.notEqual(
userEthBalanceAfter.toString(),
userEthBalance.toString(),
@@ -1060,16 +987,14 @@ describe("🤝 Broker tests", () => {
0,
"broker incorrectly has a balance in DAI"
);
-
assert.equal(
brokerBzzBalanceAfter.toString(),
0,
"broker incorrectly has a balance in BZZ"
);
-
assert.equal(
brokerEthBalanceAfter.toString(),
- 0,
+ "0",
"broker incorrectly has a balance in ETH after burn"
);
// Curve has correct balance
@@ -1084,13 +1009,11 @@ describe("🤝 Broker tests", () => {
test_settings.eth_broker.dai.mock_router_dai_balance_after_burn.toString(),
"Mock router has incorrect DAI balance"
);
-
assert.equal(
mockRouterBzzBalanceAfter.toString(),
0,
"Mock router has incorrect BZZ balance"
);
-
assert.equal(
mockRouterEthBalanceAfter.toString(),
test_settings.eth_broker.eth.mock_router_eth_balance_after_burn.toString(),
diff --git a/packages/chain/test/curve.test.js b/packages/chain/test/curve.test.ts
similarity index 97%
rename from packages/chain/test/curve.test.js
rename to packages/chain/test/curve.test.ts
index 9f81964..329b6e9 100644
--- a/packages/chain/test/curve.test.js
+++ b/packages/chain/test/curve.test.ts
@@ -1,26 +1,22 @@
-require("@nomiclabs/hardhat-waffle");
-const hre = require("hardhat");
-const { expect, assert } = require("chai");
-const {
- ethers,
- curve_abi,
- token_abi,
- mock_dai_abi,
+import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
+import { expect, assert } from "chai";
+import { Contract } from "ethers";
+import { ethers } from "hardhat";
+import {
pre_mint_sequence,
tokenSettings,
test_settings
- } = require("./settings.test.js");
+ } from "./settings.test";
describe('📈 Curve tests', () => {
- let investor;
- let owner;
- let user;
- let user_two;
+ let investor: SignerWithAddress;
+ let owner: SignerWithAddress;
+ let user: SignerWithAddress;
+ let user_two: SignerWithAddress;
- let deployer;
- let tokenInstance;
- let curveInstance;
- let collateralInstance;
+ let tokenInstance: Contract;
+ let curveInstance: Contract;
+ let collateralInstance: Contract;
beforeEach(async () => {
const accounts = await ethers.getSigners();
@@ -970,6 +966,12 @@ const {
await expect(tokenInstance.connect(user).burn(
test_settings.bzz.sellAmount
)).to.be.revertedWith(test_settings.errors.minter_is_minter);
+ // await assert.revertWith(
+ // tokenInstance.connect(user).burn(
+ // test_settings.bzz.sellAmount
+ // ),
+ // test_settings.errors.minter_is_minter
+ // );
// Approve a spender
await tokenInstance.connect(user).approve(
user_two.address,
@@ -980,6 +982,13 @@ const {
user_two.address,
test_settings.bzz.sellAmount
)).to.be.revertedWith(test_settings.errors.minter_is_minter);
+ // await assert.revertWith(
+ // tokenInstance.connect(user).burnFrom(
+ // user_two.address,
+ // test_settings.bzz.sellAmount
+ // ),
+ // test_settings.errors.minter_is_minter
+ // );
});
/**
* Tests that if a user with a minter role can burn and burnFrom.
diff --git a/packages/chain/test/curve_calc.test.js b/packages/chain/test/curve_calc.test.ts
similarity index 94%
rename from packages/chain/test/curve_calc.test.js
rename to packages/chain/test/curve_calc.test.ts
index a2891d8..7ade589 100644
--- a/packages/chain/test/curve_calc.test.js
+++ b/packages/chain/test/curve_calc.test.ts
@@ -1,33 +1,27 @@
-require("@nomiclabs/hardhat-waffle");
-const hre = require("hardhat");
-const { expect } = require("chai");
-const {
- ethers,
- curve_test_abi,
- token_abi,
- mock_dai_abi,
+import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
+import { expect } from "chai";
+import { Contract } from "ethers";
+import { ethers } from "hardhat";
+import {
pre_mint_sequence,
tokenSettings,
test_settings
-} = require("./settings.test.js");
+} from "./settings.test";
describe("🧮 Curve Calculations Tests", () => {
- let investor;
- let owner;
- let user;
- let user_two;
+ let investor: SignerWithAddress;
+ let owner: SignerWithAddress;
+ let user: SignerWithAddress;
- let deployer;
- let tokenInstance;
- let collateralInstance;
- let curveTestInstance;
+ let tokenInstance: Contract;
+ let collateralInstance: Contract;
+ let curveTestInstance: Contract;
beforeEach(async () => {
const accounts = await ethers.getSigners();
owner = accounts[0];
investor = accounts[1];
user = accounts[2];
- user_two = accounts[3];
const accountSlice = accounts.slice(4,19);
const lossaEther = ethers.utils.parseEther("9999.99");
@@ -86,6 +80,7 @@ describe("🧮 Curve Calculations Tests", () => {
expect(initialCost.toString()).to.equal(pre_mint_sequence.dai.cost);
expect(primFuncAtZero.toString()).to.equal("0");
+
});
/**
* Testing that the price per token is never 0, even before the curve has
@@ -98,6 +93,7 @@ describe("🧮 Curve Calculations Tests", () => {
expect(spotPriceAtStart.toString()).to.not.equal("0");
expect(spotPriceAtStart.toString()).to.equal("1");
+
});
});
@@ -143,6 +139,7 @@ describe("🧮 Curve Calculations Tests", () => {
let helper = await curveTestInstance.helper(pre_mint_sequence.whole);
// Testing expected behaviour
expect(helper.toString()).to.equal(test_settings.helper_value);
+
});
/**
* Testing that after the curve has pre-minted that the price for each
@@ -172,6 +169,7 @@ describe("🧮 Curve Calculations Tests", () => {
expect(primFuncAtPreMint.toString()).to.equal(test_settings.dai.curve_coll_at_prem);
expect(spotPricePostMint.toString()).to.equal(test_settings.dai.one_cost);
+
});
/**
* Testing that after the curves pre-mint the sell price for each token
@@ -200,6 +198,7 @@ describe("🧮 Curve Calculations Tests", () => {
);
// Testing expected behaviour
expect(sellRewardWithdraw[0].toString()).to.equal(test_settings.dai.buyCost);
+
});
});
});
\ No newline at end of file
diff --git a/packages/chain/test/curve_pre_mint.test.js b/packages/chain/test/curve_pre_mint.test.ts
similarity index 98%
rename from packages/chain/test/curve_pre_mint.test.js
rename to packages/chain/test/curve_pre_mint.test.ts
index 42eaaed..f20c990 100644
--- a/packages/chain/test/curve_pre_mint.test.js
+++ b/packages/chain/test/curve_pre_mint.test.ts
@@ -1,33 +1,27 @@
-require("@nomiclabs/hardhat-waffle");
-const hre = require("hardhat");
-const { expect, assert } = require("chai");
-const {
- ethers,
- curve_abi,
- token_abi,
- mock_dai_abi,
+import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
+import { expect, assert } from "chai";
+import { Contract } from "ethers";
+import { ethers } from "hardhat";
+import {
pre_mint_sequence,
tokenSettings,
test_settings
- } = require("./settings.test.js");
+ } from "./settings.test";
describe('🍃 Curve pre-mint tests', () => {
- let investor;
- let owner;
- let user;
- let user_two;
+ let investor: SignerWithAddress;
+ let owner: SignerWithAddress;
+ let user: SignerWithAddress;
- let deployer;
- let tokenInstance;
- let curveInstance;
- let collateralInstance;
+ let tokenInstance: Contract;
+ let curveInstance: Contract;
+ let collateralInstance: Contract;
beforeEach(async () => {
const accounts = await ethers.getSigners();
owner = accounts[0];
investor = accounts[1];
user = accounts[2];
- user_two = accounts[3];
const tokenArtifacts = await ethers.getContractFactory("Token");
tokenInstance = await tokenArtifacts.deploy(
diff --git a/packages/chain/test/settings.test.js b/packages/chain/test/settings.test.ts
similarity index 84%
rename from packages/chain/test/settings.test.js
rename to packages/chain/test/settings.test.ts
index 37f42ee..576b3cd 100644
--- a/packages/chain/test/settings.test.js
+++ b/packages/chain/test/settings.test.ts
@@ -1,14 +1,6 @@
-const { ethers } = require("hardhat");
-let curve_abi = require("../artifacts/contracts/Curve.sol/Curve.json");
-let curve_test_abi = require("../artifacts/contracts/Curve_test.sol/curve_test.json");
-let token_abi = require("../artifacts/contracts/Token.sol/Token.json");
-let i_token_abi = require("../artifacts/contracts/I_Token.sol/I_Token.json");
-let i_curve_abi = require("../artifacts/contracts/I_Curve.sol/I_Curve.json");
-let mock_dai_abi = require("../artifacts/contracts/Mock_dai.sol/Mock_dai.json");
-let eth_broker_abi = require("../artifacts/contracts/Eth_broker.sol/Eth_broker.json");
-let mock_router_abi = require("../artifacts/contracts/Mock_router.sol/Mock_router.json");
+import { ethers } from "hardhat";
-const pre_mint_sequence = {
+export const pre_mint_sequence = {
// These amounts are each half of the open market supply
first_half: ethers.utils.parseUnits("31250000", 16),
second_half: ethers.utils.parseUnits("31250000", 16),
@@ -29,7 +21,7 @@ const pre_mint_sequence = {
},
};
-const tokenSettings = {
+export const tokenSettings = {
dai: {
name: "DAI",
symbol: "DAI",
@@ -48,7 +40,7 @@ const tokenSettings = {
},
};
-const test_settings = {
+export const test_settings = {
bzz: {
one: ethers.utils.parseUnits("1", tokenSettings.bzz.decimals),
buyAmount: ethers.utils.parseUnits("1000", tokenSettings.bzz.decimals),
@@ -132,7 +124,7 @@ const test_settings = {
},
};
-var erc20 = {
+export var erc20 = {
events: {
transfer: "Transfer",
approval: "Approval",
@@ -164,20 +156,3 @@ var erc20 = {
zero_address: "0x0000000000000000000000000000000000000000",
},
};
-
-module.exports = {
- ethers,
- curve_abi,
- curve_test_abi,
- token_abi,
- i_token_abi,
- i_curve_abi,
- mock_dai_abi,
- eth_broker_abi,
- mock_router_abi,
- pre_mint_sequence,
- tokenSettings,
- test_settings,
- erc20,
-};
-
diff --git a/packages/chain/test/token.test.js b/packages/chain/test/token.test.ts
similarity index 89%
rename from packages/chain/test/token.test.js
rename to packages/chain/test/token.test.ts
index 934be29..ce4894e 100644
--- a/packages/chain/test/token.test.js
+++ b/packages/chain/test/token.test.ts
@@ -1,12 +1,9 @@
-require("@nomiclabs/hardhat-waffle");
-const hre = require("hardhat");
-const { expect, assert } = require("chai");
-const {
- ethers,
- token_abi,
+import { expect, assert } from "chai";
+import { ethers } from "hardhat";
+import {
erc20,
tokenSettings
-} = require("./settings.test.js");
+} from "./settings.test";
describe("🤑 Token Tests", () => {
// Contract instance