Skip to content

Commit

Permalink
fix policy sync implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
doerfli committed Dec 30, 2024
1 parent 56c85f8 commit 23d2f24
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 12 deletions.
2 changes: 1 addition & 1 deletion app/abi/CropProduct.sol/CropProduct.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions app/server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Settings(BaseSettings):

# farmer minimum funding amount
FARMER_FUNDING_AMOUNT: int = 100000001
FARMER_ETH_FUNDING_AMOUNT: int = 0.005 * 10 ** 18

# smart contracs settings
PRODUCT_CONTRACT_ADDRESS: str | None
Expand All @@ -37,6 +38,9 @@ class Settings(BaseSettings):
# rpc node settings (default is local anvil node)
RPC_NODE_URL: str | None = "http://127.0.0.1:8545"

# gas price settings
GAS_PRICE: int = 25.5 * 10 ** 9

# mongodb settings
MONGO_ID_ATTRIBUTE: str = "_id"
MONGO_CREATE_COLLECTIONS: bool = True
Expand Down
2 changes: 1 addition & 1 deletion app/server/sync/onchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
token = Contract(w3, "AccountingToken", settings.TOKEN_CONTRACT_ADDRESS, out_path="./app/abi")

operator = Wallet.from_mnemonic(settings.OPERATOR_WALLET_MNEMONIC, index=settings.OPERATOR_ACCOUNT_INDEX)

logger.info(f"operator wallet {operator.address}")
22 changes: 19 additions & 3 deletions app/server/sync/person.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from util.logging import get_logger
from web3utils.blocks import wait_for_blocks
from web3utils.send_eth import send_eth
from web3utils.wallet import Wallet

from server.config import settings
from server.model.person import PersonOut
from server.mongo import update_in_collection
from server.sync.onchain import token, operator
from server.sync.onchain import token, operator, product, w3

# setup for module
logger = get_logger()
Expand All @@ -18,10 +21,10 @@ def sync_person_onchain(person: PersonOut, force: bool = False):
# check balance of wallet
balance = token.balanceOf(person.wallet)
logger.info(f"balance {balance} (min amount {settings.FARMER_FUNDING_AMOUNT}) for wallet {person.wallet}")
funding = settings.FARMER_FUNDING_AMOUNT - balance

# send tokens to wallet if balance is below threshold
if balance < settings.FARMER_FUNDING_AMOUNT:
funding = settings.FARMER_FUNDING_AMOUNT - balance
if balance < settings.FARMER_FUNDING_AMOUNT or force:

# execute transaction
tx = token.transfer(person.wallet, funding, {'from': operator})
Expand All @@ -31,3 +34,16 @@ def sync_person_onchain(person: PersonOut, force: bool = False):
person.tx = tx
update_in_collection(person, PersonOut)

# fund wallet with eth for approval
send_eth(operator, person.wallet, settings.FARMER_ETH_FUNDING_AMOUNT, settings.GAS_PRICE)

# initialze farmer wallet
farmer_wallet = Wallet.from_mnemonic(settings.FARMER_WALLET_MNEMONIC, index=person.walletIndex)
product_token_handler = product.getTokenHandler()
farmer_wallet_balance = w3.eth.get_balance(farmer_wallet.address)
logger.info(f"farmer wallet {farmer_wallet.address} token handler {product_token_handler} approval of {settings.FARMER_FUNDING_AMOUNT} balance {farmer_wallet_balance}")

# and approve token handler for policy payment
tx2 = token.approve(product_token_handler, settings.FARMER_FUNDING_AMOUNT, {'from': farmer_wallet, 'gasPrice': settings.GAS_PRICE, 'gasLimit': 50000})
logger.info(f"tx {tx2} approval of {funding} token to {product_token_handler}")

8 changes: 5 additions & 3 deletions app/server/sync/policy.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import datetime
from util.logging import get_logger

from server.config import settings
from server.mongo import find_in_collection, update_in_collection
from server.model.person import PersonOut
from server.model.policy import PolicyOut
Expand Down Expand Up @@ -34,10 +35,11 @@ def sync_policy_onchain(policy: PolicyOut, force: bool = False):
risk_id = product.getRiskId(risk_id_str)
subscription_date = datetime.fromisoformat(policy.subscriptionDate)
activate_at = int(subscription_date.timestamp())
sum_insured = int(policy.sumInsuredAmount)
premium = int(policy.premiumAmount)
sum_insured = int(policy.sumInsuredAmount) * 10 ** settings.LOCATION_DECIMALS
premium = int(policy.premiumAmount) * 10 ** settings.LOCATION_DECIMALS

tx = product.createPolicy(policy_holder, risk_id, activate_at, sum_insured, premium, {'from': operator})
logger.info(f"creating policy policy_holder {policy_holder} risk_id {risk_id} activate_at {activate_at} sum_insured {sum_insured} premium {premium}")
tx = product.createPolicy(policy_holder, risk_id, activate_at, sum_insured, premium, {'from': operator, 'gasLimit': 10000000, 'gasPrice': settings.GAS_PRICE})

logger.info(f"{tx} onchain policy {policy.id} created")

Expand Down
15 changes: 15 additions & 0 deletions app/web3utils/blocks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from util.logging import get_logger
from server.sync.onchain import w3
import time

logger = get_logger()

def wait_for_blocks(blocks=10):
initial_block_number = w3.eth.block_number

while True:
current_block_number = w3.eth.block_number
if current_block_number >= initial_block_number + blocks:
break
logger.info(f"Waiting for blocks... Current: {current_block_number - initial_block_number}, Required: {blocks}")
time.sleep(5) # Wait for 5 seconds before checking again
21 changes: 17 additions & 4 deletions app/web3utils/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
from web3.contract import Contract as Web3Contract
from web3.exceptions import TimeExhausted
from web3.types import FilterParams
from util.logging import get_logger
from web3utils.wallet import Wallet

logger = get_logger()

class Contract:

FOUNDRY_OUT = "../out"
Expand Down Expand Up @@ -92,23 +95,30 @@ def write_method(*args) -> str:

try:
wallet = tx_params['from']
logger.info(f"Sending transaction for function '{func_name}' with wallet: {wallet.address}")

# create tx properties
chain_id = self.w3.eth.chain_id
gas = tx_params.get('gas', self.GAS)
gas_price = tx_params.get('gasPrice', self.w3.eth.gas_price)
gas_limit = tx_params.get('gasLimit', None)
nonce = self.w3.eth.get_transaction_count(wallet.address)

# transform wallet args to addresses (str)
modified_args = [arg.address if isinstance(arg, Wallet) else arg for arg in function_args]

# create tx
txn = getattr(self.contract.functions, func_name)(*modified_args).build_transaction({
options = {
'chainId': chain_id,
'gas': gas,
'gasPrice': gas_price,
'nonce': nonce,
})
}

if gas_limit:
options['gas'] = gas_limit

# create tx
txn = getattr(self.contract.functions, func_name)(*modified_args).build_transaction(options)

# sign tx
private_key = bytes(wallet.account.key)
Expand Down Expand Up @@ -138,7 +148,10 @@ def write_method(*args) -> str:

except Exception as e:
logger.warning(f"Error sending transaction for function '{func_name}': {e}")
return tx_hash.hex()
if 'tx_hash' in locals():
logger.warning(f"Transaction hash: {tx_hash.hex()}")
return tx_hash.hex()
return None

write_method.__name__ = func_name
write_method.__doc__ = f"Sends a transaction to the '{func_name}' function of the contract."
Expand Down
25 changes: 25 additions & 0 deletions app/web3utils/send_eth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from server.sync.onchain import w3
from util.logging import get_logger
from web3utils.wallet import Wallet

logger = get_logger()

def send_eth(sender: Wallet, rcpt: str, amount: int, gas_price: int) -> str:
"""Send a specified amount of wei to a specified address."""
nonce = w3.eth.get_transaction_count(sender.account.address)
tx = {
'nonce': nonce, #prevents from sending a transaction twice on ethereum
'to': rcpt,
'value': w3.to_wei(amount, 'wei'),
'gas': 21000,
'gasPrice': gas_price,
'chainId': w3.eth.chain_id
}
signed_tx = w3.eth.account.sign_transaction(tx, sender.account.key)
logger.info(f"Sending {amount} wei to {rcpt}")
#send the transaction
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
logger.info(f"Transaction sent: {tx_hash.hex()}")
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
logger.info(f"Transaction mined: {tx_hash}")

1 change: 1 addition & 0 deletions src/CropProduct.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ contract CropProduct {
function getSeason(Str seasonId) public view returns (Season memory season) {}
function getLocation(Str locationId) public view returns (Location location) {}
function getRisk(RiskId riskId) public view returns (bool exists, CropRisk memory cropRisk) {}
function getTokenHandler() public virtual view returns (address tokenHandler) {}

/// @dev converts the provided string into a short string.
/// code from OZ ShortStrings.toShortString
Expand Down

0 comments on commit 23d2f24

Please sign in to comment.