Skip to content
This repository has been archived by the owner on Aug 1, 2023. It is now read-only.

Changes after the OZ audit #254

Merged
merged 7 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions ethereum/contracts/CashToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,30 @@ contract CashToken is ICash {
/// @notice The amount of cash principal per account
mapping (address => uint128) public cashPrincipal;

bool public initialized = false;

/**
* @notice Construct a Cash Token
* @dev You must call `initialize()` after construction
* @param admin_ The address of admin
*/
constructor(address admin_) {
constructor(address admin_) {
admin = admin_;
}
}

/**
* @notice Initialize Cash token contract
* @param initialYield The initial value for Cash token APY in BPS (e.g. 100=1%)
* @param initialYieldStart The timestamp when Cash index and yield were activated on Gateway
*/
function initialize(uint128 initialYield, uint initialYieldStart) external {
require(cashYieldAndIndex.index == 0, "Cash Token already initialized");
require(initialized == false, "Cash Token already initialized");

// Note: we don't check that this is in the past, but calls will revert until it is.
cashYieldStart = initialYieldStart;
cashYieldAndIndex = CashYieldAndIndex({yield: initialYield, index: 1e18});

initialized = true;
}

/**
Expand Down Expand Up @@ -121,6 +125,8 @@ contract CashToken is ICash {
*/
function setFutureYield(uint128 nextYield, uint128 nextIndex, uint nextYieldStart) external override {
require(msg.sender == admin, "Must be admin");
require(nextYield <= 1e4, "Invalid yield range");
require(nextYieldStart > cashYieldStart, "Invalid yield start");
uint nextStart = nextCashYieldStart;

// Updating cash yield and index to the 'old' next values
Expand All @@ -130,6 +136,8 @@ contract CashToken is ICash {
}
nextCashYieldStart = nextYieldStart;
nextCashYieldAndIndex = CashYieldAndIndex({yield: nextYield, index: nextIndex});

emit SetFutureYield(nextYield, nextIndex, nextYieldStart);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions ethereum/contracts/ICash.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ interface ICash is IERC20 {
function burn(address account, uint amount) external returns (uint128);
function setFutureYield(uint128 nextYield, uint128 nextIndex, uint nextYieldStartAt) external;
function getCashIndex() external view returns (uint128);

event SetFutureYield(uint128 nextCashYield, uint128 nextCashYieldIndex, uint nextCashYieldStart);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion ethereum/contracts/Starport.sol
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ contract Starport {
* @dev Externally-owned accounts may call `execTrxRequest` with a signed message to avoid Ethereum fees.
* @param trxRequest An ASCII-encoded transaction request
*/
function execTrxRequest(string calldata trxRequest) public payable {
function execTrxRequest(string calldata trxRequest) public {
emit ExecTrxRequest(msg.sender, trxRequest);
}

Expand Down
6 changes: 3 additions & 3 deletions ethereum/contracts/test/CashToken2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ pragma solidity ^0.8.1;
import "../CashToken.sol";

contract CashToken2 is CashToken {
bool public intiailized_ = false;
bool public initialized_ = false;
uint public counter = 0;

constructor(address admin_) CashToken(admin_) {
}

function initialize_(uint counter_) public {
require(intiailized_ == false, "cannot reinitialize");
require(initialized_ == false, "cannot reinitialize");
counter = counter_;
intiailized_ = true;
initialized_ = true;
}

/// Simple function to test notices
Expand Down
27 changes: 21 additions & 6 deletions ethereum/tests/cash_token_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ describe('CashToken', () => {
expect(await call(cash, 'admin')).toMatchAddress(admin);
let cashYieldAndIndex = await call(cash, 'cashYieldAndIndex');
let cashYieldStart = await call(cash, 'cashYieldStart');
let initialized = await call(cash, 'initialized');
expect(cashYieldAndIndex.index).toEqualNumber(1e18);
expect(cashYieldAndIndex.yield).toEqualNumber(0);
expect(cashYieldStart).toEqualNumber(start);
expect(initialized).toEqual(true);
});

it('should have correct admin and yield references when non-zero', async () => {
Expand Down Expand Up @@ -172,7 +174,7 @@ describe('CashToken', () => {
const start_before = await call(cash, 'cashYieldStart');

// Update future yield, first change
await send(cash, 'setFutureYield', [43628, 1e6, nextYieldTimestamp], { from: admin });
await send(cash, 'setFutureYield', [362, 1e6, nextYieldTimestamp], { from: admin });
const yieldAndIndex_change = await call(cash, 'cashYieldAndIndex');
const start_change = await call(cash, 'cashYieldStart');
const nextYieldAndIndex_change = await call(cash, 'nextCashYieldAndIndex');
Expand All @@ -181,14 +183,14 @@ describe('CashToken', () => {
expect(yieldAndIndex_change.yield).toEqualNumber(yieldAndIndex_before.yield);
expect(yieldAndIndex_change.index).toEqualNumber(yieldAndIndex_before.index);
expect(start_change).toEqualNumber(start_before);
expect(nextYieldAndIndex_change.yield).toEqualNumber(43628);
expect(nextYieldAndIndex_change.yield).toEqualNumber(362);
expect(nextYieldAndIndex_change.index).toEqualNumber(1e6);
expect(nextStart_change).toEqualNumber(nextYieldTimestamp);

await sendRPC(web3, "evm_increaseTime", [31 * 60]);

// Update future yield, second change, current yield, index and time are set to previous next values
await send(cash, 'setFutureYield', [43629, 11e5, nextYieldTimestamp + 60 * 60], { from: admin });
await send(cash, 'setFutureYield', [369, 11e5, nextYieldTimestamp + 60 * 60], { from: admin });
const yieldAndIndex_change2 = await call(cash, 'cashYieldAndIndex');
const start_change2 = await call(cash, 'cashYieldStart');
const nextYieldAndIndex_change2 = await call(cash, 'nextCashYieldAndIndex');
Expand All @@ -197,7 +199,7 @@ describe('CashToken', () => {
expect(yieldAndIndex_change2.yield).toEqualNumber(nextYieldAndIndex_change.yield);
expect(yieldAndIndex_change2.index).toEqualNumber(nextYieldAndIndex_change.index);
expect(start_change2).toEqualNumber(nextStart_change);
expect(nextYieldAndIndex_change2.yield).toEqualNumber(43629);
expect(nextYieldAndIndex_change2.yield).toEqualNumber(369);
expect(nextYieldAndIndex_change2.index).toEqualNumber(11e5);
expect(nextStart_change2).toEqualNumber(nextYieldTimestamp + 60 * 60);
});
Expand All @@ -206,8 +208,21 @@ describe('CashToken', () => {
const blockNumber = await web3.eth.getBlockNumber();
const block = await web3.eth.getBlock(blockNumber);
const nextYieldTimestamp = block.timestamp + 30 * 60;
await expect(send(cash, 'setFutureYield', [43628, 1e6, nextYieldTimestamp], { from: account1 })).rejects.toRevert("revert Must be admin");
})
await expect(send(cash, 'setFutureYield', [300, 1e6, nextYieldTimestamp], { from: account1 })).rejects.toRevert("revert Must be admin");
});

it('should fail if next yield start is before current yield start', async() => {
const start_yield = await call(cash, 'cashYieldStart');
await expect(send(cash, 'setFutureYield', [300, 1e6, start_yield], { from: admin })).rejects.toRevert("revert Invalid yield start");
await expect(send(cash, 'setFutureYield', [300, 1e6, start_yield - 1000], { from: admin })).rejects.toRevert("revert Invalid yield start");
});

it('should fail if yield range is invalid', async() => {
const blockNumber = await web3.eth.getBlockNumber();
const block = await web3.eth.getBlock(blockNumber);
const nextYieldTimestamp = block.timestamp + 30 * 60;
await expect(send(cash, 'setFutureYield', [30000, 1e6, nextYieldTimestamp], { from: admin })).rejects.toRevert("revert Invalid yield range");
});
});

describe('#mint', () => {
Expand Down
18 changes: 12 additions & 6 deletions ethereum/tests/starport_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1485,11 +1485,13 @@ describe('Starport', () => {

const tx = await send(starport, 'setFutureYield', [nextCashYield, nextCashYieldIndex, nextCashYieldStart], { from: root });

expect(tx.events.SetFutureYield.returnValues).toMatchObject({
const expectedYieldEvent = {
nextCashYield: nextCashYield.toString(),
nextCashYieldIndex: nextCashYieldIndex.toString(),
nextCashYieldStart: nextCashYieldStart.toString(),
});
};
expect(tx.events.SetFutureYield[0].returnValues).toMatchObject(expectedYieldEvent);
expect(tx.events.SetFutureYield[1].returnValues).toMatchObject(expectedYieldEvent);

expect(await call(cash, 'cashYieldAndIndex')).toMatchObject({
yield: "0",
Expand Down Expand Up @@ -1522,11 +1524,13 @@ describe('Starport', () => {
index: "1234",
});

expect(tx.events.SetFutureYield.returnValues).toMatchObject({
const expectedYieldEvent = {
nextCashYield: nextCashYield.toString(),
nextCashYieldIndex: nextCashYieldIndex.toString(),
nextCashYieldStart: nextCashYieldStart.toString(),
});
};
expect(tx.events.SetFutureYield[0].returnValues).toMatchObject(expectedYieldEvent);
expect(tx.events.SetFutureYield[1].returnValues).toMatchObject(expectedYieldEvent);
});

it('should set future yield via hand-coded notice', async () => {
Expand All @@ -1543,11 +1547,13 @@ describe('Starport', () => {
const signatures = signAll(setFutureYieldNotice, authorityWallets);
const tx = await send(starport, 'invoke', [setFutureYieldNotice, signatures], { from: account1 });

expect(tx.events.SetFutureYield.returnValues).toMatchObject({
const expectedYieldEvent = {
nextCashYield: "1200",
nextCashYieldIndex: "1234",
nextCashYieldStart: "1644703495",
});
}
expect(tx.events.SetFutureYield[0].returnValues).toMatchObject(expectedYieldEvent);
expect(tx.events.SetFutureYield[1].returnValues).toMatchObject(expectedYieldEvent);
});

it('should fail when not called by self or admin', async () => {
Expand Down