Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/simplify interaction with deployed artefacts #37

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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
225 changes: 114 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,21 +255,85 @@ brownie run scripts/instance.py dump_sources 0x2852593b21796b549555d09873155B252

## Full Deployment with Example Product

Before attempting to deploy the setup on a life chain ensure that the
`instanceOperator` has sufficient funds to cover the setup.

For testnets faucet funds may be used

* [avax-test (Fuji (C-Chain))](https://faucet.avax.network/)
* [polygon-test](https://faucet.polygon.technology/)

Using the ganache scenario shown below ensures that all addresses used are sufficiently funded.

```bash
matthiaszimmermann marked this conversation as resolved.
Show resolved Hide resolved
# --- ganache accounts setup -------------
instanceOperator=accounts[0]
instanceWallet=accounts[1]
oracleProvider=accounts[2]
chainlinkNodeOperator=accounts[3]
riskpoolKeeper=accounts[4]
riskpoolWallet=accounts[5]
investor=accounts[6]
productOwner=accounts[7]
insurer=accounts[8]
customer=accounts[9]
customer2=accounts[10]
from scripts.deploy import (
stakeholders_accounts_ganache,
check_funds,
amend_funds,
deploy,
from_registry,
from_component,
)

from scripts.instance import (
GifInstance,
dump_sources
)

from scripts.util import (
s2b,
b2s,
contract_from_address,
)

# for ganche the command below may be used
# for other chains, use accounts.add() and record the mnemonics
a = stakeholders_accounts_ganache()

# check_funds checks which stakeholder accounts need funding for the deploy
# also, it checks if the instanceOperator has a balance that allows to provided
# the missing funds for the other accounts
check_funds(a)

# amend_funds transfers missing funds to stakeholder addresses using the
# avaulable balance of the instanceOperator
amend_funds(a)

publishSource=False
d = deploy(a, publishSource)

(
componentOwnerService,customer1,customer2,erc20Token,instance,instanceOperator,instanceOperatorService,instanceService,
instanceWallet,insurer,investor,oracle,oracleProvider,processId1,processId2,product,productOwner,riskId1,riskId2,
riskpool,riskpoolKeeper,riskpoolWallet
)=(
d['componentOwnerService'],d['customer1'],d['customer2'],d['erc20Token'],d['instance'],d['instanceOperator'],d['instanceOperatorService'],d['instanceService'],
d['instanceWallet'],d['insurer'],d['investor'],d['oracle'],d['oracleProvider'],d['processId1'],d['processId2'],d['product'],d['productOwner'],d['riskId1'],d['riskId2'],
d['riskpool'],d['riskpoolKeeper'],d['riskpoolWallet']
)

# the deployed setup can now be used
# example usage
instanceOperator
instance.getRegistry()
instanceService.getInstanceId()

product.getId()
b2s(product.getName())

customer1
instanceService.getMetadata(processId1)
instanceService.getApplication(processId1)
instanceService.getPolicy(processId1)
```

For a first time setup on a live chain the setup below can be used.

IMPORTANT: Make sure to write down the generated mnemonics for the
stakeholder accounts. To reuse the same accounts replace `accounts.add`
with `accounts.from_mnemonic` using the recorded mnemonics.

# --- test net accounts setup -------------
```bash
instanceOperator=accounts.add()
instanceWallet=accounts.add()
oracleProvider=accounts.add()
Expand All @@ -279,108 +343,47 @@ riskpoolWallet=accounts.add()
investor=accounts.add()
productOwner=accounts.add()
insurer=accounts.add()
customer=accounts.add()
customer1=accounts.add()
customer2=accounts.add()

# --- optional erc20 token deploy -------------
# skip this if the value token for the product and
# riskpool is already deployed

erc20Token = TestCoin.deploy({'from': instanceOperator})

# --- gif instance deploy deploy -------------
# if the gif instance is already deployed replace
# the command below with the following line
# instance = GifInstance(registryAddress='0x...')
from scripts.instance import GifInstance

instance = GifInstance(instanceOperator, instanceWallet=instanceWallet)
instanceService = instance.getInstanceService()

instance.getRegistry()

# --- example product deploy deploy -------------
from scripts.ayii_product import GifAyiiProductComplete

ayiiDeploy = GifAyiiProductComplete(instance, productOwner, insurer, oracleProvider, chainlinkNodeOperator, riskpoolKeeper, investor, erc20Token, riskpoolWallet)

ayiiProduct = ayiiDeploy.getProduct()
ayiiOracle = ayiiProduct.getOracle()
ayiiRiskpool = ayiiProduct.getRiskpool()

product = ayiiProduct.getContract()
oracle = ayiiOracle.getContract()
riskpool = ayiiRiskpool.getContract()
a = {
'instanceOperator': instanceOperator,
'instanceWallet': instanceWallet,
'oracleProvider': oracleProvider,
'chainlinkNodeOperator': chainlinkNodeOperator,
'riskpoolKeeper': riskpoolKeeper,
'riskpoolWallet': riskpoolWallet,
'investor': investor,
'productOwner': productOwner,
'insurer': insurer,
'customer1': customer1,
'customer2': customer2,
}
```

## Interact with Example Product
To interact with an existing setup use the following helper methods as shown below.

```bash
from scripts.util import s2b32

#--- setup risk (group policy) definition -----------------
projectId = s2b32('test-project')
uaiId = s2b32('some-region-id')
cropId = s2b32('maize')

multiplier = product.getPercentageMultiplier()
trigger = 0.75 * multiplier
exit_ = 0.1 * multiplier # exit is needed to exit the console
tsi = 0.9 * multiplier
aph = 2.0 * multiplier

tx = product.createRisk(projectId, uaiId, cropId, trigger, exit_, tsi, aph,
{'from': insurer})
riskId = tx.return_value

#--- fund investor which in turn creates a risk bundle ---
bundleInitialFunding=1000000
erc20Token.transfer(investor, bundleInitialFunding, {'from': instanceOperator})
erc20Token.approve(instance.getTreasury(), bundleInitialFunding, {'from': investor})

applicationFilter = bytes(0)
riskpool.createBundle(applicationFilter, bundleInitialFunding, {'from': investor})

instanceService.getBundle(1)
erc20Token.balanceOf(riskpoolWallet.address)
erc20Token.balanceOf(instanceWallet.address)

# approvel for payouts/defunding
maxUint256 = 2**256-1
erc20Token.approve(instance.getTreasury(), maxUint256, {'from': riskpoolWallet})

#--- fund customer which in turn applies for a policy ---
customerFunding=1000
erc20Token.transfer(customer, customerFunding, {'from': instanceOperator})

premium = 100
sumInsured = 20000

tx = product.applyForPolicy(customer, premium, sumInsured, riskId,
{'from': insurer})
policyId = tx.return_value

# print data for bundle and newly created policy
riskpool.getTotalValueLocked() # shows the 20000 of locked capital to cover the sum insurance
instanceService.getBundle(1) # bundle state, locked capital (20000 to cover sum insured)
instanceService.getMetadata(policyId) # policy owner and product id
instanceService.getApplication(policyId) # premium, sum insurec, risk id
instanceService.getPolicy(policyId) # policy state, premium payed (=0 for now)

# premium payment in bits, allowance set for full premium
erc20Token.approve(instance.getTreasury(), 100, {'from': customer})

# first installment
product.collectPremium(policyId, 40, {'from':insurer})
instanceService.getPolicy(policyId)

# second installment
product.collectPremium(policyId, 60, {'from':insurer})
instanceService.getPolicy(policyId)

# TODO add:
# - oracle call
# - policy processing
# - payout to customer
# - definding back to inverster
from scripts.deploy import (
from_registry,
from_component,
)

from scripts.instance import (
GifInstance,
)

from scripts.util import (
s2b,
b2s,
contract_from_address,
)

# for the case of a known registry address,
# eg '0xE7eD6747FaC5360f88a2EFC03E00d25789F69291'
(instance, product, oracle, riskpool) = from_registry('0xE7eD6747FaC5360f88a2EFC03E00d25789F69291')

# or for a known address of a component, eg
# eg product address '0xF039D8acecbB47763c67937D66A254DB48c87757'
(instance, product, oracle, riskpool) = from_component('0xF039D8acecbB47763c67937D66A254DB48c87757')
```
15 changes: 15 additions & 0 deletions contracts/modules/ComponentController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ pragma solidity ^0.8.0;
import "../shared/CoreController.sol";

import "@etherisc/gif-interface/contracts/components/IComponent.sol";
import "@etherisc/gif-interface/contracts/components/IOracle.sol";
import "@etherisc/gif-interface/contracts/components/IProduct.sol";
import "@etherisc/gif-interface/contracts/components/IRiskpool.sol";
import "@etherisc/gif-interface/contracts/modules/IComponentEvents.sol";

contract ComponentController is
Expand Down Expand Up @@ -202,6 +205,18 @@ contract ComponentController is
return _componentState[id];
}

function getOracleId(uint256 idx) public view returns (uint256 oracleId) {
return _oracles[idx];
}

function getRiskpoolId(uint256 idx) public view returns (uint256 riskpoolId) {
return _riskpools[idx];
}

function getProductId(uint256 idx) public view returns (uint256 productId) {
return _products[idx];
}

function getRequiredRole(IComponent.ComponentType componentType) external returns (bytes32) {
if (componentType == IComponent.ComponentType.Product) { return _access.getProductOwnerRole(); }
else if (componentType == IComponent.ComponentType.Oracle) { return _access.getOracleProviderRole(); }
Expand Down
23 changes: 19 additions & 4 deletions contracts/services/InstanceService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import "../shared/CoreController.sol";
import "../services/InstanceOperatorService.sol";

import "@etherisc/gif-interface/contracts/components/IComponent.sol";
import "@etherisc/gif-interface/contracts/components/IOracle.sol";
import "@etherisc/gif-interface/contracts/components/IProduct.sol";
import "@etherisc/gif-interface/contracts/components/IRiskpool.sol";
import "@etherisc/gif-interface/contracts/modules/IPolicy.sol";
import "@etherisc/gif-interface/contracts/modules/IRegistry.sol";
import "@etherisc/gif-interface/contracts/services/IComponentOwnerService.sol";
Expand Down Expand Up @@ -137,10 +140,6 @@ contract InstanceService is
return _component.getComponentId(componentAddress);
}

function getComponent(uint256 id) external override view returns(IComponent) {
return _component.getComponent(id);
}

function getComponentType(uint256 componentId)
external override
view
Expand All @@ -157,6 +156,22 @@ contract InstanceService is
componentState = _component.getComponentState(componentId);
}

function getComponent(uint256 id) external override view returns(IComponent) {
return _component.getComponent(id);
}

function getOracleId(uint256 idx) public view returns (uint256 oracleId) {
return _component.getOracleId(idx);
}

function getRiskpoolId(uint256 idx) public view returns (uint256 riskpoolId) {
return _component.getRiskpoolId(idx);
}

function getProductId(uint256 idx) public view returns (uint256 productId) {
return _component.getProductId(idx);
}

/* service staking */
function getStakingRequirements(uint256 id)
external override
Expand Down
12 changes: 6 additions & 6 deletions scripts/ayii_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,15 @@ def __init__(self,
self.clToken = ClToken.deploy(
clTokenOwner,
clTokenSupply,
{'from': oracleProvider})
{'from': oracleProvider},
publish_source=publishSource)

# 2b) chainlink operator deploy
self.chainlinkOperator = ClOperator.deploy(
self.clToken,
chainlinkNodeOperator,
{'from': oracleProvider})
{'from': oracleProvider},
publish_source=publishSource)

# set oracleProvider as authorized to call fullfill on operator
self.chainlinkOperator.setAuthorizedSenders([chainlinkNodeOperator])
Expand All @@ -163,9 +165,8 @@ def __init__(self,
chainLinkOracleAddress,
chainLinkJobId,
chainLinkPaymentAmount,
{'from': oracleProvider})
# {'from': oracleProvider},
# publish_source=publishSource)
{'from': oracleProvider},
publish_source=publishSource)

# 3) oracle owner proposes oracle to instance
componentOwnerService.propose(
Expand Down Expand Up @@ -277,7 +278,6 @@ def getPolicy(self, policyId: str):
return self.policy.getPolicy(policyId)



class GifAyiiProductComplete(object):

def __init__(self,
Expand Down
Loading