Skip to content

Commit

Permalink
add onchain sync functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiaszimmermann committed Dec 21, 2024
1 parent fc875fd commit 7a2283c
Show file tree
Hide file tree
Showing 31 changed files with 886 additions and 214 deletions.
7 changes: 4 additions & 3 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ forge script script/MockSetup.s.sol --fork-url http://127.0.0.1:8545 --broadcast
```shell
cd app
eval $(echo export $(grep MNEMONIC .env))
eval $(echo export $(grep CONTRACT_ADDRESS .env))
uv run python3
```

Expand All @@ -384,9 +385,9 @@ a = Wallet.create()
w3_uri = "http://127.0.0.1:8545"
w3 = Web3(Web3.HTTPProvider(w3_uri))

# replace the address with your own token contract address
token_address = "0x7A2E477883Bd134637a2eD18f84babD71B9bb4e1"
token = Contract(w3, "AccountingToken", token_address)
# replace contract addresses with your own
product = Contract(w3, "CropProduct", "0xdA0b2cf6B65a98d06Cd77212509537dD166A19cE")
token = Contract(w3, "AccountingToken", "0xB58192974A93B9143Ef5F91Ab8b0545092b65803")

token.transfer(a, 100, {'from':w})
token.balanceOf(a)
Expand Down
136 changes: 0 additions & 136 deletions app/locations.csv

This file was deleted.

15 changes: 15 additions & 0 deletions app/server/api/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from datetime import datetime

from fastapi.responses import FileResponse
from fastapi.routing import APIRouter

from server.config import settings
from server.error import raise_with_log
from server.model.config import ConfigIn, ConfigOut
from server.mongo import create_in_collection, find_in_collection, get_list_of_models_in_collection, get_list_of_dicts_in_collection

Expand All @@ -19,6 +22,18 @@
@router.post("/", response_model=ConfigOut, response_description="Config data created")
async def create_config(config: ConfigIn):
logger.info(f"POST {PATH_PREFIX} {config}")

# check season start and end and calculate season days
season_start = datetime.fromisoformat(config.startOfSeason)
season_end = datetime.fromisoformat(config.endOfSeason)
if season_start >= season_end:
raise_with_log(ValueError, f"season start {config.startOfSeason} must be before season end {config.endOfSeason}")

document = config.toMongoDict()
document['year'] = season_start.year
document['seasonDays'] = (season_end - season_start).days + 1
config = ConfigOut.fromMongoDict(document)

return create_in_collection(config, ConfigOut)


Expand Down
6 changes: 6 additions & 0 deletions app/server/api/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,9 @@ async def get_all_locations_csv(
documents = get_list_of_dicts_in_collection(LocationOut, page, items)
field_list = get_field_list(fields)
return write_csv_temp_file(field_list, documents, delimiter)


@router.get("/all/pending", response_model=list[LocationOut], response_description="Locations obtained")
async def get_all_locations_to_sync(page: int = 1, items: int = settings.MONGO_DOCUMENTS_PER_PAGE):
logger.info(f"GET {PATH_PREFIX}/all/json")
return get_new_locations()
2 changes: 1 addition & 1 deletion app/server/api/person.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from server.mongo import count_documents, create_in_collection, find_in_collection, get_list_of_models_in_collection, get_list_of_dicts_in_collection
from util.csv import write_csv_temp_file, get_field_list
from util.logging import get_logger
from web3_utils.wallet import Wallet
from web3utils.wallet import Wallet


PATH_PREFIX = "/person"
Expand Down
15 changes: 6 additions & 9 deletions app/server/api/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
from server.api.util import verify_person_exists, verify_risk_exists
from server.model.policy import PolicyIn, PolicyOut
from server.mongo import create_in_collection, find_in_collection, get_collection_for_class, get_list_of_models_in_collection, get_list_of_dicts_in_collection
from server.sync.policy import sync_policy_onchain

from data.offchain_data import get_policy_data, get_policies_data
from data.onchain_data import get_onchain_onboarding_data, amend_onchain_data
from util.csv import write_csv_temp_file, get_field_list
from util.logging import get_logger

Expand All @@ -27,6 +26,10 @@ async def create_policy(policy: PolicyIn) -> PolicyOut:
verify_risk_exists(policy.riskId)
return create_in_collection(policy, PolicyOut)

@router.post("/{policy_id}/sync", response_description="Policy synched onchain")
async def sync_policy(policy_id: str):
policy = find_in_collection(policy_id, PolicyOut)
sync_policy_onchain(policy)

@router.get("/{policy_id}", response_description="Policy data obtained")
async def get_policy(policy_id: str):
Expand All @@ -44,12 +47,6 @@ async def get_payouts(policy_id: str) -> List[PayoutOut]:
payouts = payout_collection.find({"policyId": policy_id})
return [PayoutOut.fromMongoDict(p) for p in payouts]


# @router.get("/{policy_id}/onchain", response_description="Policy onchain data obtained")
# async def get_onchain_policy_data(policy_id: str) -> dict:
# return get_onchain_onboarding_data(policy_id)


@router.get("/all/json", response_description="Policies data obtained")
async def get_all_policies(page:int = 1, items:int = settings.MONGO_DOCUMENTS_PER_PAGE):
logger.info(f"GET {PATH_PREFIX}/all/json")
Expand All @@ -58,7 +55,7 @@ async def get_all_policies(page:int = 1, items:int = settings.MONGO_DOCUMENTS_PE

@router.get("/all/csv", response_class=FileResponse, response_description="Locations csv created")
async def get_all_locations_csv(
fields: str = settings.MODEL_CSV_LOCATION_FIELDS,
fields: str = settings.MODEL_CSV_POLICY_FIELDS,
delimiter: str = settings.MODEL_CSV_DELIMITER,
page: int = 1,
items: int = settings.MONGO_DOCUMENTS_PER_PAGE
Expand Down
21 changes: 19 additions & 2 deletions app/server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,36 @@ class Settings(BaseSettings):
APP_TITLE: str = "Etherisc API Server"
APP_DEBUG: bool = False

# list of valid crops
VALID_CROPS: list = ["coffee", "maize"]

# model fields settings
MODEL_ID_ATTRIBUTE: str = "id"
MODEL_CSV_DELIMITER: str = ";"
MODEL_CSV_PERSON_FIELDS: str = "id,locationId,firstName,lastName,gender,mobilePhone,externalId,walletIndex,wallet"
MODEL_CSV_LOCATION_FIELDS: str = "id,country,region,province,department,village,latitude,longitude,openstreetmap,coordinatesLevel"
MODEL_CSV_POLICY_FIELDS: str = "id,year,seasonStart,seasonEnd,indexType,locationNanoId,region,province,department,city,beneficiarySex,subscriptionDate,premium,sumInsured,triggerSevere,payoutSevere,triggerMedium,payoutMedium,triggerLow,payoutLow,indexReferenceValue,indexEndOfSeasonValue,indexRatio,payoutEstimated"
MODEL_CSV_POLICY_FIELDS: str = "id,personId,riskId,subscriptionDate,sumInsuredAmount,premiumAmount,nft,tx"
MODEL_CSV_CLAIM_FIELDS: str = "id,onChainId,policyId,claimAmount,paidAmount,closedAt,createdAt,updatedAt"
MODEL_CSV_PAYOUT_FIELDS: str = "id,onChainId,policyId,claimId,amount,paidAt,beneficiary,createdAt,updatedAt"
MODEL_CSV_RISK_FIELDS: str = "id,isValid,configId,locationId,crop,createdAt,updatedAt"
MODEL_CSV_CONFIG_FIELDS: str = "id,isValid,name,year,startOfSeason,endOfSeason,createdAt,updatedAt"

# farmer wallet mnemonic (only via .env)
# account mnemonics (only via .env)
FARMER_WALLET_MNEMONIC: str | None
OPERATOR_WALLET_MNEMONIC: str | None

# farmer minimum funding amount
FARMER_FUNDING_AMOUNT: int = 100000001

# smart contracs settings
PRODUCT_CONTRACT_ADDRESS: str | None
TOKEN_CONTRACT_ADDRESS: str | None

# onchain latitude longitude decimals
LOCATION_DECIMALS: int = 6

# rpc node settings (default is local anvil node)
RPC_NODE_URL: str | None = "http://127.0.0.1:8545"

# mongodb settings
MONGO_ID_ATTRIBUTE: str = "_id"
Expand Down
34 changes: 20 additions & 14 deletions app/server/model/config.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
from pydantic import BaseModel, Field
from datetime import datetime

from pydantic import BaseModel, field_validator, Field
from server.error import raise_with_log
from server.mongo import MongoModel

EXAMPLE_IN = {
"isValid": True,
"name": "MainSeasons2024",
"year": 2024,
"startOfSeason": "2024-08-01",
"endOfSeason": "2024-12-31",
"seasonDays": 120,
"franchise": 0.1,
"createdAt": 1700316957,
"updatedAt": 1700316957,
"endOfSeason": "2024-12-31"
}

EXAMPLE_OUT = EXAMPLE_IN
EXAMPLE_OUT["_id"] = "7Zv4TZoBLxUi"
EXAMPLE_OUT["year"] = 2014
EXAMPLE_OUT["seasonDays"] = 120

class ConfigIn(MongoModel):
isValid:bool
name:str
year:int
startOfSeason:str
endOfSeason:str
seasonDays:int
franchise:float
createdAt:int
updatedAt:int

@field_validator('startOfSeason', 'endOfSeason')
@classmethod
def date_must_be_iso(cls, v: str) -> str:
date = v.strip()
try:
datetime.fromisoformat(date)
except ValueError:
raise ValueError("Provided string is not a valid ISO date.")
raise_with_log(ValueError, f"date {date} is not iso format (YYYY-MM-DD)")

return date

class Config:
json_schema_extra = {
Expand All @@ -35,6 +39,8 @@ class Config:

class ConfigOut(ConfigIn):
_id: str
year:int
seasonDays:int
id: str = Field(default=None)
tx: str | None = Field(default=None)

Expand Down
5 changes: 2 additions & 3 deletions app/server/model/person.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from server.error import raise_with_log
from server.mongo import MongoModel
from util.nanoid import is_valid_nanoid
from web3_utils.wallet import Wallet
from web3utils.wallet import Wallet

EXAMPLE_IN = {
"locationId": "U6ufadiIe0Xz",
Expand Down Expand Up @@ -47,7 +47,7 @@ def name_must_not_be_empty(cls, v: str) -> str:

@field_validator('gender')
@classmethod
def sex_must_be_m_or_f(cls, v: str) -> str:
def gender_must_be_m_or_f(cls, v: str) -> str:
if v is None:
return None

Expand All @@ -72,7 +72,6 @@ class PersonOut(PersonIn):
@field_validator('walletIndex')
@classmethod
def wallet_index_must_be_positive(cls, v: int) -> int:
print(f"validating wallet index {v} ...")
wallet_index = v
if not isinstance(wallet_index, int):
raise_with_log(ValueError, f"wallet index must be of type int")
Expand Down
Loading

0 comments on commit 7a2283c

Please sign in to comment.