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

Commit

Permalink
Policy sync (#20)
Browse files Browse the repository at this point in the history
* work towards policy flow

* final tests

* deploy the market too

* publish to npm after contract deployment

* fix config error in circleci

* update

* deployedAddresses in gitignore

* make poliy flow test more robust by increasing premium interval to 100 seconds
  • Loading branch information
hiddentao committed Jan 31, 2020
1 parent 1202ad9 commit 24df747
Show file tree
Hide file tree
Showing 20 changed files with 392 additions and 170 deletions.
21 changes: 20 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ jobs:
- persist_to_workspace:
root: ~/repo
paths: .
deploy_contracts:
executor: smart_contracts
working_directory: ~/repo
steps:
- attach_workspace:
at: ~/repo
- run:
name: Deploy to Rinkeby
command: yarn deploy:rinkeby
- persist_to_workspace:
root: ~/repo
paths: .
publish_to_npm:
executor: smart_contracts
working_directory: ~/repo
Expand All @@ -78,10 +90,17 @@ workflows:
ci:
jobs:
- build_contracts
- publish_to_npm:
- deploy_contracts:
requires:
- build_contracts
filters:
branches:
only:
- master
- publish_to_npm:
requires:
- deploy_contracts
filters:
branches:
only:
- master
4 changes: 0 additions & 4 deletions .deployment-sample.js

This file was deleted.

3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ coverageEnv
coverage.json
tmp
log/*.log
.deployment.js
ganache.log
.0x*
scTopics
contracts.generated.js
deployedAddresses.json
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ First, run the dev network in a separate terminal:
yarn devnet
```

Compile the contracts:

```
yarn compile
```

Now deploy the contracts to it:

```
Expand All @@ -100,6 +106,14 @@ Now you can run the tests:
yarn test
```

### Deployments

Assuming you've followed the previous compilation step, deploy to rinkeby using:

```
MNEMONIC="..." INFURA_KEY="..." yarn deploy:rinkeby
```

## Notes

* We use `block.timestamp (now)` in the code. We assume this is safe to do since our timescales occur across days and months rather than seconds, see https://medium.com/@phillipgoldberg/smart-contract-best-practices-revisited-block-number-vs-timestamp-648905104323
47 changes: 24 additions & 23 deletions contracts/PolicyImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,11 @@ contract PolicyImpl is EternalStorage, Controller, IProxyImpl, IPolicyImpl, ITra
_;
}

modifier assertPendingState () {
require(dataUint256["state"] == STATE_PENDING, 'must be in pending state');
modifier assertPendingOrActiveState () {
require(dataUint256["state"] == STATE_PENDING || dataUint256["state"] == STATE_ACTIVE, 'must be in pending state');
_;
}


/**
* Constructor
*/
Expand Down Expand Up @@ -140,29 +139,37 @@ contract PolicyImpl is EternalStorage, Controller, IProxyImpl, IPolicyImpl, ITra
return dataUint256[string(abi.encodePacked(_index, "state"))];
}

function tranchPremiumsAreUptoDate (uint256 _index) public view returns (bool) {
function getNumberOfTranchPaymentsMissed (uint256 _index) public view returns (uint256) {
uint256 expectedPaid = 0;

// if inititation date has not yet passed
// if inititation date has passed
if (initiationDateHasPassed()) {
expectedPaid++;

// if start date has passed
if (startDateHasPassed()) {
expectedPaid++;

// add more
expectedPaid += (now - dataUint256["startDate"]) / dataUint256["premiumIntervalSeconds"];
// calculate the extra payments that should have been made by now
uint256 diff = now.sub(dataUint256["startDate"]).div(dataUint256["premiumIntervalSeconds"]);
expectedPaid = expectedPaid.add(diff);
}
}

// cap to no .of available premiums
uint256[] storage premiums = dataManyUint256[string(abi.encodePacked(_index, "premiums"))];

if (expectedPaid > premiums.length) {
expectedPaid = premiums.length;
}

// now check
return (dataUint256[string(abi.encodePacked(_index, "premiumsPaid"))] >= expectedPaid);
uint256 premiumsPaid = dataUint256[string(abi.encodePacked(_index, "premiumsPaid"))];

if (expectedPaid >= premiumsPaid) {
return expectedPaid.sub(premiumsPaid);
} else {
return 0;
}
}

function tranchPaymentsAllMade (uint256 _index) public view returns (bool) {
Expand Down Expand Up @@ -227,7 +234,7 @@ contract PolicyImpl is EternalStorage, Controller, IProxyImpl, IPolicyImpl, ITra
IMarket market = IMarket(settings().getMatchingMarket());

for (uint256 i = 0; dataUint256["numTranches"] > i; i += 1) {
require(tranchPremiumsAreUptoDate(i), 'tranch premiums are not up-to-date');
require(0 >= getNumberOfTranchPaymentsMissed(i), 'tranch premiums are not up-to-date');

// tranch/token address
address tranchAddress = dataAddress[string(abi.encodePacked(i, "address"))];
Expand All @@ -247,39 +254,33 @@ contract PolicyImpl is EternalStorage, Controller, IProxyImpl, IPolicyImpl, ITra

dataUint256["state"] = STATE_PENDING;

emit BeginSale(msg.sender);
emit BeginSale(address(this), msg.sender);
}


function endSale()
function checkAndUpdateState()
public
assertCanApprovePolicy
assertPendingState
assertPendingOrActiveState
{
// solhint-disable-next-line security/no-block-members
require(startDateHasPassed(), 'start date not yet passed');

bool atleastOneActiveTranch = false;

for (uint256 i = 0; dataUint256["numTranches"] > i; i += 1) {
uint256 state = dataUint256[string(abi.encodePacked(i, "state"))];

if (state == STATE_ACTIVE && tranchPremiumsAreUptoDate(i)) {
atleastOneActiveTranch = true;
} else {
if (state != STATE_ACTIVE || 0 < getNumberOfTranchPaymentsMissed(i)) {
dataUint256[string(abi.encodePacked(i, "state"))] = STATE_CANCELLED;
}
}

if (atleastOneActiveTranch) {
if (dataUint256["state"] != STATE_ACTIVE) {
dataUint256["state"] = STATE_ACTIVE;
emit PolicyActive(msg.sender);
} else {
dataUint256["state"] = STATE_CANCELLED;
emit PolicyCancelled(msg.sender);
emit PolicyActive(address(this), msg.sender);
}
}


function calculateMaxNumOfPremiums() public view returns (uint256) {
// first 2 payments + (endDate - startDate) / paymentInterval - 1
return (dataUint256["maturationDate"] - dataUint256["startDate"]) / dataUint256["premiumIntervalSeconds"] + 1;
Expand Down
9 changes: 4 additions & 5 deletions contracts/base/IPolicyImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ contract IPolicyImpl {
function getNumTranches () public view returns (uint256);
function getTranchToken (uint256 _index) public view returns (address);
function getTranchState (uint256 _index) public view returns (uint256);
function tranchPremiumsAreUptoDate (uint256 _index) public view returns (bool);
function getNumberOfTranchPaymentsMissed (uint256 _index) public view returns (uint256);
function tranchPaymentsAllMade (uint256 _index) public view returns (bool);
function getNextTranchPremiumAmount (uint256 _index) public view returns (uint256);
function payTranchPremium (uint256 _index) public;

function beginSale () public;
function endSale () public;
function checkAndUpdateState () public;

function initiationDateHasPassed () public view returns (bool);
function startDateHasPassed () public view returns (bool);
Expand All @@ -39,7 +39,6 @@ contract IPolicyImpl {
uint256 index
);

event BeginSale(address indexed caller);
event PolicyActive(address indexed caller);
event PolicyCancelled(address indexed caller);
event BeginSale(address indexed policy, address indexed caller);
event PolicyActive(address indexed policy, address indexed caller);
}
5 changes: 0 additions & 5 deletions deployedAddresses.json

This file was deleted.

47 changes: 27 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
const contractsForEvents = {
Proxy: require('./build/contracts/Proxy.json'),
IEtherToken: require('./build/contracts/IEtherToken.json'),
IACL: require('./build/contracts/IACL.json'),
IEntityDeployer: require('./build/contracts/IEntityDeployer.json'),
IEntityImpl: require('./build/contracts/IEntityImpl.json'),
IPolicyImpl: require('./build/contracts/IPolicyImpl.json'),
IERC20: require('./build/contracts/IERC20.json'),
IERC777: require('./build/contracts/IERC777.json'),
}
let deployedAddresses
try {
deployedAddresses = require('./deployedAddresses.json')
} catch (_ignore) {}

const contractsThatAreEntryPoints = {
ACL: require('./build/contracts/ACL.json'),
EntityDeployer: require('./build/contracts/EntityDeployer.json'),
}
const rawContracts = require('./contracts.generated.js')

const coreContracts = [
{ name: 'Settings', actual: 'ISettingsImpl' },
{ name: 'ACL', actual: 'IACL' },
{ name: 'Policy', actual: 'IPolicyImpl' },
{ name: 'EntityDeployer', actual: 'IEntityDeployer' },
{ name: 'Entity', actual: 'IEntityImpl' },
{ name: 'MatchingMarket', actual: 'IMarket' },
{ name: 'EtherToken', actual: 'IEtherToken' },
{ name: 'Proxy', actual: 'Proxy' },
{ name: 'ERC20', actual: 'IERC20' },
{ name: 'ERC777', actual: 'IERC777' },
].reduce((m, n) => {
m[n.name] = rawContracts[n.actual]
return m
}, {})

const extractEventsFromAbis = abis => abis.reduce((output, contract) => {
contract.abi.filter(({ type, name }) => type === 'event').forEach(e => {
if (output[e.name]) {
throw new Error(`Already got an event named ${e.name}`)
if (!output[e.name]) {
output[e.name] = e
}
output[e.name] = e
})
return output
}, {})

module.exports = {
addresses: require('./deployedAddresses.json'),
contracts: Object.assign({}, contractsForEvents, contractsThatAreEntryPoints),
events: extractEventsFromAbis(Object.values(contractsForEvents)),
addresses: deployedAddresses,
contracts: coreContracts,
rawContracts,
events: extractEventsFromAbis(Object.values(coreContracts)),
extractEventsFromAbis,
}
2 changes: 2 additions & 0 deletions migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const EntityImpl = artifacts.require("./EntityImpl")
const EntityDeployer = artifacts.require("./EntityDeployer")

const { ensureAclIsDeployed } = require('./utils/acl')
const { ensureMarketIsDeployed } = require('./utils/market')
const { ensureSettingsIsDeployed } = require('./utils/settings')
const { ensureEtherTokenIsDeployed } = require('./utils/etherToken')
const { ensureErc1820RegistryIsDeployed } = require('./utils/erc1820')
Expand All @@ -16,6 +17,7 @@ module.exports = async deployer => {
const acl = await ensureAclIsDeployed({ deployer, artifacts, logger: true })
const settings = await ensureSettingsIsDeployed({ deployer, artifacts, logger: true }, acl.address)
await ensureEtherTokenIsDeployed({ deployer, artifacts, logger: true }, acl.address, settings.address)
await ensureMarketIsDeployed({ deployer, artifacts, logger: true }, settings.address)

await deployer.deploy(EntityImpl, acl.address, settings.address)
await deployer.deploy(EntityDeployer, acl.address, settings.address, EntityImpl.address)
Expand Down
25 changes: 25 additions & 0 deletions migrations/utils/market.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const { createLog } = require('./log')
const { deploy } = require('./functions')

export const ensureMarketIsDeployed = async ({ deployer, artifacts, logger }, settingsAddress) => {
const log = createLog(logger)

log('Deploying Market ...')

// deploy market
const Market = artifacts.require('./MatchingMarket')
const market = await Market.new('0xFFFFFFFFFFFFFFFF')

log(`... deployed at ${market.address}`)

log('Saving market address to settings ...')

// save to settings
const Settings = artifacts.require('./ISettingsImpl')
const settings = await Settings.at(settingsAddress)
await settings.setMatchingMarket(market.address)

log('... saved')

return market
}
18 changes: 12 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
"access": "public"
},
"files": [
"constants.js",
"index.js",
"contracts.generated.js",
"build/**",
"contracts/**",
"deployedAddresses.json"
"deployedAddresses.json",
"README.md",
"LICENSE.md"
],
"scripts": {
"devnet": "ganache-cli -a 10 -m 'funny door sample enrich female wedding stereo crane setup shop dwarf dismiss'",
Expand All @@ -21,11 +24,12 @@
"trace": "MODE=trace yarn test",
"coverage": "rm -rf coverage && solidity-coverage && istanbul report lcov",
"profile": "MODE=profile yarn test && istanbul report lcov",
"copy-maker-otc-artifacts": "cp maker-otc/build/contracts/MatchingMarket.json build/contracts",
"compile": "yarn truffle compile --network test && yarn copy-maker-otc-artifacts",
"deploy:mainnet": "yarn truffle networks --clean && yarn truffle migrate --network mainnet && scripts/extractDeployedAddresses.js",
"deploy:rinkeby": "yarn truffle networks --clean && yarn truffle migrate --network rinkeby && scripts/extractDeployedAddresses.js",
"copy-maker-otc-artifacts": "./scripts/copyMakerOtcArtifacts.js",
"generate-index": "./scripts/generateIndex.js",
"compile": "rm -rf build && yarn truffle compile --network test && yarn copy-maker-otc-artifacts && yarn generate-index",
"deploy:rinkeby": "yarn truffle networks --clean && yarn truffle migrate --network rinkeby && yarn extract-deployed-addresses",
"deploy:local": "yarn truffle migrate --network test",
"extract-deployed-addresses": "./scripts/extractDeployedAddresses.js",
"setup": "[[ -f .deployment.js ]] || cp .deployment-sample.js .deployment.js",
"lint": "solhint --config ./.solhint.json contracts/**/*.sol",
"abi-encode": "./scripts/abiEncode.js"
Expand All @@ -49,8 +53,10 @@
"etherscan-api": "^3.0.11",
"ethval": "^1.3.0",
"faker": "^4.1.0",
"fs-extra": "^8.1.0",
"ganache-cli": "^6.7.0",
"get-stdin": "^7.0.0",
"glob": "^7.1.6",
"husky": "^3.0.3",
"lodash": "^4.17.11",
"moment": "^2.18.1",
Expand Down
10 changes: 10 additions & 0 deletions scripts/copyMakerOtcArtifacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env node

/* This script copies Maker OTC contract artifacts from git submodule into build folder */

const fse = require('fs-extra')
const path = require('path')

const projectDir = path.join(__dirname, '..')

fse.copySync(path.join(projectDir, 'maker-otc', 'build', 'contracts', 'MatchingMarket.json'), path.join(projectDir, 'build', 'contracts', 'MatchingMarket.json'))
Loading

0 comments on commit 24df747

Please sign in to comment.