diff --git a/.github/workflows/deploy_api.yml b/.github/workflows/deploy_api.yml index fb9dd1b9..3e2e3c59 100644 --- a/.github/workflows/deploy_api.yml +++ b/.github/workflows/deploy_api.yml @@ -39,7 +39,7 @@ jobs: source venv/bin/activate pip3 install -r requirements.txt pip3 uninstall pyxfluencer -y - pip3 install pyxfluencer-1.2.1-py3-none-any.whl + latest_file=$(ls -v | grep 'pyxfluencer-[0-9.]*-py3-none-any.whl' | tail -n 1) && pip install $latest_file python3 manage.py migrate python3 manage.py collectstatic -link --noinput echo "Stopping previous processes..." diff --git a/.github/workflows/deploy_prod_api.yml b/.github/workflows/deploy_prod_api.yml index 47286f12..edbdf38b 100644 --- a/.github/workflows/deploy_prod_api.yml +++ b/.github/workflows/deploy_prod_api.yml @@ -41,7 +41,7 @@ jobs: source venv/bin/activate pip3 install -r requirements.txt pip3 uninstall pyxfluencer -y - pip3 install pyxfluencer-1.2.1-py3-none-any.whl + latest_file=$(ls -v | grep 'pyxfluencer-[0-9.]*-py3-none-any.whl' | tail -n 1) && pip install $latest_file python3 manage.py migrate python3 manage.py collectstatic -link --noinput echo "Stopping previous processes..." diff --git a/solana-python/dist/pyxfluencer-1.2.2-py3-none-any.whl b/solana-python/dist/pyxfluencer-1.2.2-py3-none-any.whl new file mode 100644 index 00000000..5ce2463d Binary files /dev/null and b/solana-python/dist/pyxfluencer-1.2.2-py3-none-any.whl differ diff --git a/solana-python/launch_validate.py b/solana-python/launch_validate.py index 6f69ae33..97d75119 100644 --- a/solana-python/launch_validate.py +++ b/solana-python/launch_validate.py @@ -1,8 +1,5 @@ import asyncio -from solders.pubkey import Pubkey -from solana.rpc.types import TxOpts - from pyxfluencer.instructions import validate_escrow_sol from pyxfluencer.utils import get_local_keypair_pubkey from pyxfluencer.utils import sign_and_send_transaction @@ -28,7 +25,7 @@ async def main(target_state): print(len(msg)*"*") configuration = load_configuration() - network = configuration["network"] + network = configuration["rpc"]["mainnet"] print("nework -->", network) @@ -36,47 +33,25 @@ async def main(target_state): validation_authority, validation_authority_pk \ = get_local_keypair_pubkey(path=keypair_paths.validation_authority) - _, business_pk = get_local_keypair_pubkey(path=keypair_paths.bussines_keypair) + _, business_pk = get_local_keypair_pubkey() #path=keypair_paths.bussines_keypair) _, influencer_pk = get_local_keypair_pubkey(path=keypair_paths.influencer_keypair) - + # check configuration matches local keypairs assert str(validation_authority_pk) == configuration["platform"] assert str(business_pk) == configuration["business"]["pubkey"] assert str(influencer_pk) == configuration["influencer"]["pubkey"] - order_code = configuration["order_code"] - SEEDS = [b"escrow", - bytes(business_pk), - bytes(influencer_pk), - bytes(str(order_code),"UTF-8") - ] - escrow_pda, _ = Pubkey.find_program_address(SEEDS, PROGRAM_ID) - print("Escrow SOL PDA",escrow_pda) - - # state 1 = unlock funds so business can re-fund - # state 2 = unlock funds so influencer can claim - # percentage_fee is passed is passed always (both cases cancel and deliver) - - args = {"target_state":target_state.value, "percentage_fee": 0 } + from pyxfluencer import EscrowValidator - accounts = { - "validation_authority": validation_authority_pk, - "influencer":influencer_pk, - "business":business_pk, - "escrow_account":escrow_pda - } - - opts = TxOpts(skip_confirmation = True, - skip_preflight = True, - preflight_commitment="processed") + escrow_validator = EscrowValidator(validation_authority, business_pk, influencer_pk, order_code, network) + if target_state == TargetState.CANCEL: + res = await escrow_validator.cancel() + else: + res = await escrow_validator.deliver() - ix = validate_escrow_sol(args, accounts, program_id=PROGRAM_ID) - - signers = [validation_authority] - - await sign_and_send_transaction(ix, signers, opts, network) + print("Results from Validator",res) import argparse @@ -93,5 +68,5 @@ async def main(target_state): exit() -asyncio.run(main(TargetState.DELIVERY)) +asyncio.run(main(target_state)) \ No newline at end of file diff --git a/solana-python/pyxfluencer/__init__.py b/solana-python/pyxfluencer/__init__.py index 3c2e6159..251a8e18 100644 --- a/solana-python/pyxfluencer/__init__.py +++ b/solana-python/pyxfluencer/__init__.py @@ -10,8 +10,16 @@ from .utils import sign_and_send_transaction from .program_id import PROGRAM_ID -xfluencer_solana_python_client_version="1.2.1" +xfluencer_solana_python_client_version = "1.2.2" +################### +# Version: 1.2.2 +# Bump: Patch +# Updated: 16.04.2024 +# - add re-try logic +# - add priority_ffes instruction +# - add compute unit instruction +# - add custom error treatment on simulation ################### # Version: 1.2.1 # Bump: Patch @@ -71,12 +79,13 @@ class EscrowState(Enum): @dataclass class EscrowValidator: validator_authority: Keypair - business_address: Pubkey - influencer_address: Pubkey + business_address: str | Pubkey + influencer_address: str | Pubkey order_code: int network: str = "https://api.devnet.solana.com" percentage_fee: int = 0 processing_spl_escrow: bool = False + priority_fees: int = 0 async def cancel(self): return await validate_escrow(self.validator_authority, @@ -85,8 +94,10 @@ async def cancel(self): EscrowState.CANCEL, self.order_code, self.network, - self.percentage_fee, - self.processing_spl_escrow) + percentage_fee = self.percentage_fee, + processing_spl_escrow = self.processing_spl_escrow, + priority_fees = self.priority_fees + ) async def deliver(self): return await validate_escrow(self.validator_authority, self.business_address, @@ -94,17 +105,21 @@ async def deliver(self): EscrowState.DELIVERED, self.order_code, self.network, - self.percentage_fee, - self.processing_spl_escrow) + percentage_fee = self.percentage_fee, + processing_spl_escrow = self.processing_spl_escrow, + priority_fees = self.priority_fees + ) # NON SPL escrow async def validate_escrow_to_cancel(validator_authority: Keypair, - business_address: str, - influencer_address: str, + business_address: str, #@TODO: Accept Pubkey as well + influencer_address: str, #@TODO: Accept Pubkey as well order_code:int, network: str = "https://api.devnet.solana.com", - percentage_fee: int = 0): + percentage_fee: int = 0, + priority_fees: int = 0 + ): """ Args: @@ -119,21 +134,25 @@ async def validate_escrow_to_cancel(validator_authority: Keypair, """ return await validate_escrow(validator_authority, - business_address, - influencer_address, - EscrowState.CANCEL, - order_code, - network, - percentage_fee, - processing_spl_escrow=False) + business_address, + influencer_address, + EscrowState.CANCEL, + order_code, + network, + percentage_fee=percentage_fee, + processing_spl_escrow=False, + priority_fees=priority_fees + ) # NON SPL escrow async def validate_escrow_to_delivered(validator_authority: Keypair, - business_address: str, - influencer_address: str, + business_address: str, #@TODO: Accept Pubkey as well + influencer_address: str, #@TODO: Accept Pubkey as well order_code:int, network: str = "https://api.devnet.solana.com", - percentage_fee: int = 0): + percentage_fee: int = 0, + priority_fees: int = 0 + ): """_summary_ Args: @@ -153,68 +172,83 @@ async def validate_escrow_to_delivered(validator_authority: Keypair, EscrowState.DELIVERED, order_code, network, - percentage_fee, - processing_spl_escrow=False) + percentage_fee=percentage_fee, + processing_spl_escrow=False, + priority_fees=priority_fees + ) async def validate_escrow(validation_authority: Keypair, - business_address: str, - influencer_address: str, - target_escrow_state: EscrowState, + business_address: str | Pubkey, + influencer_address: str | Pubkey, + target_escrow_state: EscrowState, order_code: int, network: str = "https://api.devnet.solana.com", percentage_fee: int = 0, - processing_spl_escrow: bool = False): + processing_spl_escrow: bool = False, + priority_fees: int = 0): - business_pk = Pubkey.from_string(business_address) - influencer_pk = Pubkey.from_string(influencer_address) + if isinstance(business_address,str): + business_pk = Pubkey.from_string(business_address) + else: + business_pk = business_address - opts = TxOpts(skip_confirmation = True, - skip_preflight = True, - preflight_commitment="processed") - - args = {"target_state":target_escrow_state.value, "percentage_fee": percentage_fee} - - signers = [validation_authority] - - if not processing_spl_escrow: + if isinstance(influencer_address,str): + influencer_pk = Pubkey.from_string(influencer_address) + else: + influencer_pk = influencer_address + + + args = {"target_state": target_escrow_state.value, + "percentage_fee": percentage_fee} + + signers = [validation_authority] + + if not processing_spl_escrow: print("Processing Escrow SOL case") SEEDS = [b"escrow", bytes(business_pk), bytes(influencer_pk), - bytes(str(order_code),"UTF-8")] + bytes(str(order_code), "UTF-8")] escrow_pda, _ = Pubkey.find_program_address(SEEDS, PROGRAM_ID) - + accounts = { - "validation_authority": validation_authority.pubkey(), - "influencer":influencer_pk, - "business":business_pk, - "escrow_account":escrow_pda - } - + "validation_authority": validation_authority.pubkey(), + "influencer": influencer_pk, + "business": business_pk, + "escrow_account": escrow_pda + } + ix = validate_escrow_sol(args, accounts, program_id=PROGRAM_ID) - #return await sign_and_send_transaction(ix, signers, opts, network) - + # return await sign_and_send_transaction(ix, signers, opts, network) + else: print("Processing Escrow SPL case") - - # find vault and escrows pdas + + # find vault and escrows pdas vault_account_pda, _ = \ - Pubkey.find_program_address([b"token-seed", - bytes(str(order_code),"UTF-8")], PROGRAM_ID) + Pubkey.find_program_address([b"token-seed", + bytes(str(order_code), "UTF-8")], PROGRAM_ID) escrow_account_pda, _ = \ - Pubkey.find_program_address([b"escrow-data", - bytes(str(order_code),"UTF-8")], PROGRAM_ID) - + Pubkey.find_program_address([b"escrow-data", + bytes(str(order_code), "UTF-8")], PROGRAM_ID) + accounts = { - "validation_authority": validation_authority.pubkey(), + "validation_authority": validation_authority.pubkey(), "vault_account": vault_account_pda, - "influencer":influencer_pk, - "business":business_pk, - "escrow_account":escrow_account_pda - } - + "influencer": influencer_pk, + "business": business_pk, + "escrow_account": escrow_account_pda + } + ix = validate_escrow_spl(args, accounts, program_id=PROGRAM_ID) - - return await sign_and_send_transaction(ix, signers, opts, network) \ No newline at end of file + + try: + tx_resp = await sign_and_send_transaction(ix, signers, network, priority_fees=priority_fees) + if tx_resp: + print(f"Escrow validation status: {tx_resp}") + return tx_resp + except Exception as e: + print(f"Error validating escrow {str(e)}") + raise Exception(f"Error validating escrow {e}") diff --git a/solana-python/pyxfluencer/utils.py b/solana-python/pyxfluencer/utils.py index d89a5ea5..16148507 100644 --- a/solana-python/pyxfluencer/utils.py +++ b/solana-python/pyxfluencer/utils.py @@ -1,12 +1,16 @@ +import json +from typing import List from solders.keypair import Keypair from solders.pubkey import Pubkey -from solana.rpc.api import Client -from solana.rpc.async_api import AsyncClient +from solana.rpc.api import Client # type: ignore +from solana.rpc.async_api import AsyncClient # type: ignore import json -from solana.transaction import Transaction -from solana.rpc.core import RPCException +from solana.transaction import Transaction # type: ignore +from solana.rpc.core import RPCException # type: ignore + +from solders.compute_budget import set_compute_unit_price, set_compute_unit_limit import os @@ -14,31 +18,31 @@ from anchorpy.utils import token from anchorpy.utils.rpc import AccountInfo +from .errors.custom import from_code +from solana.rpc.api import SimulateTransactionResp +from solders.transaction_status import TransactionErrorInstructionError def get_local_keypair_pubkey(keypair_file="id.json", path=None): home = os.getenv("HOME") assert home != None - ## take default_path from .env + # take default_path from .env default_path = f"{home}/.config/solana/{keypair_file}" path = default_path if path is None else path - with open(path,'r') as f: + with open(path, 'r') as f: secret_data = json.load(f) - - print(f"Loaded keypair secrets from {path}") + + print(f"Loaded keypair secrets from {path}") keypair_owner = Keypair.from_bytes(secret_data) pubkey_owner = keypair_owner.pubkey() return keypair_owner, pubkey_owner - - def select_client(network: str = None, async_client: bool = False, default_network: str = "devnet-helius"): - - + default_urls = { "devnet": "https://api.devnet.solana.com", "dev": "https://api.devnet.solana.com", @@ -50,13 +54,13 @@ def select_client(network: str = None, async_client: bool = False, default_netwo "devnet-helius": "https://devnet.helius-rpc.com/?api-key=b57191c8-c14e-4ae2-83b6-1ab88c2f3605", "mainnet-helius": "https://mainnet.helius-rpc.com/?api-key=b57191c8-c14e-4ae2-83b6-1ab88c2f3605" } - - if network is None: - print("[WARN] Client network selected is None, set devnet from 'helius' as default") - network=default_urls[default_network] - - try: + if network is None: + print( + "[WARN] Client network selected is None, set devnet from 'helius' as default") + network = default_urls[default_network] + + try: if async_client: return AsyncClient(network) return Client(network) @@ -65,33 +69,94 @@ def select_client(network: str = None, async_client: bool = False, default_netwo raise Exception(f"Selecting RPC Solana Client Network {e}") -async def get_token_account_info(ata_address: str, network : str) -> AccountInfo: - connection = select_client(network=network, async_client=True) +async def get_token_account_info(ata_address: str, network: str) -> AccountInfo: + connection = select_client(network=network, async_client=True) wallet = Wallet.local() provider = Provider(connection, wallet) - pubkey_token_account = Pubkey.from_string(ata_address) + pubkey_token_account = Pubkey.from_string(ata_address) try: return await token.get_token_account(provider, pubkey_token_account) except Exception as e: raise Exception(f"Getting Token Account Info {e}") -async def sign_and_send_transaction(ix, signers, opts, network, async_client: bool = True): - - try: - client = select_client(network=network, async_client=async_client) - tx = Transaction().add(ix) - - print("Sending transactions with options", opts) - - tx_res = await client.send_transaction(tx, *signers, opts=opts) - - print("Client Response tx signature: ", tx_res) - print("Waiting for transaction confirmation") - - signature_status = await client.confirm_transaction(tx_res.value) - - print("Confirm Transaction Status Value:", signature_status) - return signature_status.to_json() - except RPCException as e: - raise RPCException(f"RPC exception happened: {e}") - + +async def sign_and_send_transaction(ix, signers, network, async_client: bool = True, priority_fees: int = 0, extra_rpcs: List[str] = None): + client = select_client(network=network, async_client=async_client) + + recent_blockhash_resp = await client.get_latest_blockhash() + recent_blockhash = recent_blockhash_resp.value.blockhash + recent_block_height = recent_blockhash_resp.value.last_valid_block_height + block_height = (await client.get_block_height()).value + attempts = 0 + + print("Recent Block Height", recent_block_height, "Block Heigth",block_height) + + while True and attempts < 10: + try: + if block_height >= recent_block_height: + break + attempts += 1 + # Obtain a recent blockhash + print("Attempt", attempts) + # Create the transaction with the recent blockhash + tx = Transaction(recent_blockhash=recent_blockhash) + tx.add(ix) + + try: + simulated_transaction_resp: SimulateTransactionResp = await client.simulate_transaction(tx) + if simulated_transaction_resp.value.err is not None: + error_tx: TransactionErrorInstructionError = simulated_transaction_resp.value.err + error_tx_json : str = error_tx.to_json() + error_tx_dict : dict = json.loads(error_tx_json) + error: int = error_tx_dict[1]["Custom"] + if error >= 6000: + return from_code(error) + else: + print("Simulation Looks OK") + except (KeyError, Exception) as e: + print(f"Error simulating transaction: {e}") + print("Retrying...") + block_height = (await client.get_block_height()).value + continue + + # Set compute unit limit + cu_budget: int = simulated_transaction_resp.value.units_consumed * \ + 15 // 10 # increase 50% of simulated CU's + max_budget = 200_000 + cu_set = min(cu_budget, max_budget) + modify_compute_units = set_compute_unit_limit(cu_set) + tx.add(modify_compute_units) + + PRIORITY_FEE_IX = set_compute_unit_price(priority_fees) + tx.add(PRIORITY_FEE_IX) + + try: + tx_res = await client.send_transaction(tx, *signers) + print(tx_res) + except Exception as e: + print(f"Error sending transaction: {e}") + + raise + + if tx_res: + print("Client Response tx signature: ", tx_res) + print("Waiting for transaction confirmation") + + try: + signature_status = await client.confirm_transaction(tx_res.value, last_valid_block_height=recent_block_height) + except Exception as e: + print(f"Error confirming transaction: {e}") + print("Retrying...") + block_height = (await client.get_block_height()).value + continue # Continue to the next iteration of the loop + + if signature_status: + print("Confirm Transaction Status Value:", signature_status) + return signature_status.to_json() + except RPCException as e: + print(f"RPC exception happened: {e}") + except Exception as e: + print(f"An unexpected error occurred: {e}") + + # If max attempts reached, raise an exception + raise Exception("Max attempts reached, transaction failed") diff --git a/src/api/marketplace/Dockerfile b/src/api/marketplace/Dockerfile index 702fb655..9c9a1761 100644 --- a/src/api/marketplace/Dockerfile +++ b/src/api/marketplace/Dockerfile @@ -13,13 +13,13 @@ COPY ./requirements.txt /api/ RUN pip install --upgrade pip \ && pip install -r requirements.txt -COPY ./pyxfluencer-1.2.0-py3-none-any.whl /api/ -RUN pip install pyxfluencer-1.2.0-py3-none-any.whl - # copy project COPY . /api +# find the latest .whl file and install it +RUN LATEST_WHL=$(ls -v | grep 'pyxfluencer-[0-9.]*-py3-none-any.whl' | tail -n 1) && pip install $LATEST_WHL + # Make ports available for dev EXPOSE 8000 -CMD ["python", "manage.py", "runsslserver", "0.0.0.0:8000"] +CMD ["python", "manage.py", "runsslserver", "0.0.0.0:8000"] \ No newline at end of file diff --git a/src/api/marketplace/orders/tasks.py b/src/api/marketplace/orders/tasks.py index ecbedd9f..277c2cfc 100644 --- a/src/api/marketplace/orders/tasks.py +++ b/src/api/marketplace/orders/tasks.py @@ -20,6 +20,7 @@ from pyxfluencer import validate_escrow_to_cancel, validate_escrow_to_delivered, validate_escrow from pyxfluencer.utils import get_local_keypair_pubkey +from pyxfluencer.errors.custom import EscrowAlreadyCancel, EscrowAlreadyReleased import time import json @@ -63,26 +64,69 @@ def cancel_escrow(order_id: str, status: str): escrow=escrow, transaction_type='cancel_escrow' ) + priority_fees = int(Configuration.objects.get( + key='priority_fees').value) + if order_currency.currency_type == 'SOL': - result = asyncio.run(validate_escrow_to_cancel(validator_authority=val_auth_keypair, - business_address=buyer_primary_wallet.wallet_address_id, - influencer_address=influencer_primary_wallet.wallet_address_id, - order_code=order.order_number, - network=RPC_ENDPOINT, - )) + try: + result = asyncio.run(validate_escrow_to_cancel(validator_authority=val_auth_keypair, + business_address=buyer_primary_wallet.wallet_address_id, + influencer_address=influencer_primary_wallet.wallet_address_id, + order_code=order.order_number, + network=RPC_ENDPOINT, + priority_fees=priority_fees + )) + except Exception as e: + logger.error('Error in cancelling escrow: %s', str(e)) + on_chain_transaction.is_confirmed = False + on_chain_transaction.err = { + 'message': 'Error in cancelling escrow', 'error': str(e) + } + on_chain_transaction.save() + return False + elif order_currency.currency_type == 'SPL': - result = asyncio.run(validate_escrow( - validation_authority=val_auth_keypair, - business_address=buyer_primary_wallet.wallet_address_id, - influencer_address=influencer_primary_wallet.wallet_address_id, - target_escrow_state=EscrowState.CANCEL, - order_code=order.order_number, - network=RPC_ENDPOINT, - processing_spl_escrow=True - )) + try: + result = asyncio.run(validate_escrow( + validation_authority=val_auth_keypair, + business_address=buyer_primary_wallet.wallet_address_id, + influencer_address=influencer_primary_wallet.wallet_address_id, + target_escrow_state=EscrowState.CANCEL, + order_code=order.order_number, + network=RPC_ENDPOINT, + processing_spl_escrow=True, + priority_fees=priority_fees + )) + except Exception as e: + logger.error('Error in cancelling escrow: %s', str(e)) + on_chain_transaction.is_confirmed = False + on_chain_transaction.err = { + 'message': 'Error in cancelling escrow', 'error': str(e) + } + on_chain_transaction.save() + return False + + if isinstance(result, EscrowAlreadyCancel): + # Escrow already cancelled + # Update the order status to cancelled + if order.status != status: + order.status = status + order.save() + + create_order_tracking(order=order, status=status) + create_notification_for_order( + order=order, old_status='accepted', new_status=status) + + escrow.status = "cancelled" + escrow.save() + + on_chain_transaction.is_confirmed = True + on_chain_transaction.save() + + return True + + result_dict = json.loads(s=result) # Update all the values of the on_chain_transaction with result.value[0] - result_dict = json.loads(result) - # Access the first item in the 'value' list transaction_result = result_dict['result']['value'][0] @@ -118,7 +162,7 @@ def cancel_escrow(order_id: str, status: str): return False -@celery_app.task(base=QueueOnce, once={'graceful': True}, autoretry_for=(Exception,), retry_kwargs={'max_retries': 3}) +@celery_app.task(base=QueueOnce, once={'graceful': True}, autoretry_for=(Exception,), retry_kwargs={'max_retries': 5}) def confirm_escrow(order_id: str): try: # Get order and corresponding escrow @@ -143,25 +187,67 @@ def confirm_escrow(order_id: str): escrow=escrow, transaction_type='confirm_escrow' ) + priority_fees = int(Configuration.objects.get( + key='priority_fees').value) + if order_currency.currency_type == 'SOL': - result = asyncio.run(validate_escrow_to_delivered(validator_authority=val_auth_keypair, - business_address=buyer_primary_wallet.wallet_address_id, - influencer_address=influencer_primary_wallet.wallet_address_id, - order_code=order.order_number, - network=RPC_ENDPOINT, - percentage_fee=platform_fees - )) + try: + result = asyncio.run(validate_escrow_to_delivered(validator_authority=val_auth_keypair, + business_address=buyer_primary_wallet.wallet_address_id, + influencer_address=influencer_primary_wallet.wallet_address_id, + order_code=order.order_number, + network=RPC_ENDPOINT, + percentage_fee=platform_fees, + priority_fees=priority_fees + )) + except Exception as e: + logger.error('Error in confirming escrow: %s', str(e)) + on_chain_transaction.is_confirmed = False + on_chain_transaction.err = { + 'message': 'Error in confirming escrow', 'error': str(e) + } + on_chain_transaction.save() + raise Exception('Error in confirming escrow', str(e)) + elif order_currency.currency_type == 'SPL': - result = asyncio.run(validate_escrow( - validation_authority=val_auth_keypair, - business_address=buyer_primary_wallet.wallet_address_id, - influencer_address=influencer_primary_wallet.wallet_address_id, - target_escrow_state=EscrowState.DELIVERED, - order_code=order.order_number, - network=RPC_ENDPOINT, - percentage_fee=platform_fees, - processing_spl_escrow=True - )) + try: + result = asyncio.run(validate_escrow( + validation_authority=val_auth_keypair, + business_address=buyer_primary_wallet.wallet_address_id, + influencer_address=influencer_primary_wallet.wallet_address_id, + target_escrow_state=EscrowState.DELIVERED, + order_code=order.order_number, + network=RPC_ENDPOINT, + percentage_fee=platform_fees, + processing_spl_escrow=True, + priority_fees=priority_fees + )) + except Exception as e: + logger.error('Error in confirming escrow: %s', str(e)) + on_chain_transaction.is_confirmed = False + on_chain_transaction.err = { + 'message': 'Error in confirming escrow', 'error': str(e) + } + on_chain_transaction.save() + raise Exception('Error in confirming escrow', str(e)) + + if isinstance(result, EscrowAlreadyReleased): + # Escrow already released + if order.status != 'completed': + order.status = 'completed' + order.save() + + create_order_tracking(order=order, status=order.status) + create_notification_for_order( + order=order, old_status='accepted', new_status='completed') + + escrow.status = "delivered" + escrow.save() + + on_chain_transaction.is_confirmed = True + on_chain_transaction.save() + + return True # Update all the values of the on_chain_transaction with result.value[0] result_dict = json.loads(result) @@ -216,11 +302,6 @@ def check_order_status(pk): if is_completed: confirm_escrow.apply_async(args=[order.id]) - # Create a Order Tracking for the order - create_order_tracking(order=order, status=order.status) - # Send notification to business - create_notification_for_order(order=order, old_status='accepted', new_status='completed') - def tweet(text, client): try: diff --git a/src/api/marketplace/pyxfluencer-1.2.2-py3-none-any.whl b/src/api/marketplace/pyxfluencer-1.2.2-py3-none-any.whl new file mode 100644 index 00000000..5ce2463d Binary files /dev/null and b/src/api/marketplace/pyxfluencer-1.2.2-py3-none-any.whl differ