def create_transfer_account_for_user(user: User, token: Token, balance: float, is_default: bool = True, is_ghost: bool = False): transfer_account = TransferAccount(bound_entity=user) transfer_account.token = token transfer_account.balance = balance if is_default: user.default_transfer_account = transfer_account if is_ghost: transfer_account.is_ghost = True
def create_transfer_account(init_database, create_master_organisation): from server.models.transfer_account import TransferAccount transfer_account = TransferAccount() init_database.session.add(transfer_account) init_database.session.commit() return transfer_account
def __init__(self, **kwargs): super(Token, self).__init__(**kwargs) float_transfer_account = TransferAccount( private_key=config.ETH_FLOAT_PRIVATE_KEY, account_type=TransferAccountType.FLOAT, token=self, is_approved=True) self.float_account = float_transfer_account
def create_transfer_account_if_required(blockchain_address, token, account_type=TransferAccountType.EXTERNAL): transfer_account = TransferAccount.query.execution_options(show_all=True).filter_by(blockchain_address=blockchain_address).first() if transfer_account: return transfer_account else: return TransferAccount( blockchain_address=blockchain_address, token=token, account_type=account_type )
def __init__(self, chain='ETHEREUM', **kwargs): self.chain = chain super(Token, self).__init__(**kwargs) float_transfer_account = TransferAccount( private_key=current_app.config['CHAINS'][ self.chain]['FLOAT_PRIVATE_KEY'], account_type=TransferAccountType.FLOAT, token=self, is_approved=True) self.float_account = float_transfer_account
def create_float_wallet(app): print_section_title('Creating/Updating Float Wallet') float_wallet = TransferAccount.query.execution_options( show_all=True).filter( TransferAccount.account_type == TransferAccountType.FLOAT).first() if float_wallet is None: print('Creating Float Wallet') float_wallet = TransferAccount( private_key=app.config['ETH_FLOAT_PRIVATE_KEY'], account_type=TransferAccountType.FLOAT, is_approved=True) db.session.add(float_wallet) db.session.commit()
def create_float_transfer_account(app): print_section_title('Creating/Updating Float Transfer Accounts') tokens = db.session.query(Token) for t in tokens: if t.float_account_id is None: print(f'Creating Float Account for {t.name}') float_transfer_account = TransferAccount( private_key=app.config['ETH_FLOAT_PRIVATE_KEY'], account_type=TransferAccountType.FLOAT, token=t, is_approved=True ) db.session.add(float_transfer_account) db.session.flush() t.float_account = float_transfer_account db.session.commit() print_section_conclusion('Done Creating/Updating Float Wallet')
def create_float_transfer_account(app): print_section_title('Creating/Updating Float Transfer Accounts') tokens = db.session.query(Token).execution_options(show_all=True) for t in tokens: if t.float_account is None: print(f'Creating Float Account for {t.name}') chain_config = app.config['CHAINS'][app.config['DEFAULT_CHAIN']] float_transfer_account = TransferAccount( private_key=chain_config['FLOAT_PRIVATE_KEY'], account_type=TransferAccountType.FLOAT, token=t, is_approved=True) db.session.add(float_transfer_account) db.session.flush() t.float_account = float_transfer_account t.float_account.is_public = True db.session.commit() print_section_conclusion('Done Creating/Updating Float Wallet')
class CreditTransfer(ManyOrgBase, BlockchainTaskableBase): __tablename__ = 'credit_transfer' uuid = db.Column(db.String, unique=True) resolved_date = db.Column(db.DateTime) _transfer_amount_wei = db.Column(db.Numeric(27), default=0) transfer_type = db.Column(db.Enum(TransferTypeEnum), index=True) transfer_subtype = db.Column(db.Enum(TransferSubTypeEnum)) transfer_status = db.Column(db.Enum(TransferStatusEnum), default=TransferStatusEnum.PENDING) transfer_mode = db.Column(db.Enum(TransferModeEnum)) transfer_use = db.Column(JSON) transfer_metadata = db.Column(JSONB) exclude_from_limit_calcs = db.Column(db.Boolean, default=False) resolution_message = db.Column(db.String()) token_id = db.Column(db.Integer, db.ForeignKey(Token.id)) sender_transfer_account_id = db.Column( db.Integer, db.ForeignKey("transfer_account.id")) recipient_transfer_account_id = db.Column( db.Integer, db.ForeignKey("transfer_account.id")) sender_blockchain_address_id = db.Column( db.Integer, db.ForeignKey("blockchain_address.id")) recipient_blockchain_address_id = db.Column( db.Integer, db.ForeignKey("blockchain_address.id")) sender_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), index=True) recipient_user_id = db.Column(db.Integer, db.ForeignKey("user.id")) attached_images = db.relationship('UploadedResource', backref='credit_transfer', lazy=True) fiat_ramp = db.relationship('FiatRamp', backref='credit_transfer', lazy=True, uselist=False) __table_args__ = (Index('updated_index', "updated"), ) from_exchange = db.relationship('Exchange', backref='from_transfer', lazy=True, uselist=False, foreign_keys='Exchange.from_transfer_id') to_exchange = db.relationship('Exchange', backref='to_transfer', lazy=True, uselist=False, foreign_keys='Exchange.to_transfer_id') # TODO: Apply this to all transfer amounts/balances, work out the correct denominator size @hybrid_property def transfer_amount(self): return (self._transfer_amount_wei or 0) / int(1e16) @transfer_amount.setter def transfer_amount(self, val): self._transfer_amount_wei = val * int(1e16) def send_blockchain_payload_to_worker(self, is_retry=False, queue='high-priority'): sender_approval = self.sender_transfer_account.get_or_create_system_transfer_approval( ) recipient_approval = self.recipient_transfer_account.get_or_create_system_transfer_approval( ) self.blockchain_task_uuid = bt.make_token_transfer( signing_address=self.sender_transfer_account.organisation. system_blockchain_address, token=self.token, from_address=self.sender_transfer_account.blockchain_address, to_address=self.recipient_transfer_account.blockchain_address, amount=self.transfer_amount, prior_tasks=list( filter(lambda x: x is not None, [ sender_approval.eth_send_task_uuid, sender_approval.approval_task_uuid, recipient_approval.eth_send_task_uuid, recipient_approval.approval_task_uuid ])), queue=queue) def resolve_as_completed(self, existing_blockchain_txn=None, queue='high-priority'): self.check_sender_transfer_limits() self.resolved_date = datetime.datetime.utcnow() self.transfer_status = TransferStatusEnum.COMPLETE self.sender_transfer_account.decrement_balance(self.transfer_amount) self.recipient_transfer_account.increment_balance(self.transfer_amount) if self.transfer_type == TransferTypeEnum.PAYMENT and self.transfer_subtype == TransferSubTypeEnum.DISBURSEMENT: if self.recipient_user and self.recipient_user.transfer_card: self.recipient_user.transfer_card.update_transfer_card() if self.fiat_ramp and self.transfer_type in [ TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL ]: self.fiat_ramp.resolve_as_completed() if not existing_blockchain_txn: self.send_blockchain_payload_to_worker(queue=queue) def resolve_as_rejected(self, message=None): if self.fiat_ramp and self.transfer_type in [ TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL ]: self.fiat_ramp.resolve_as_rejected() self.resolved_date = datetime.datetime.utcnow() self.transfer_status = TransferStatusEnum.REJECTED if message: self.resolution_message = message def get_transfer_limits(self): import server.utils.transfer_limits return server.utils.transfer_limits.get_transfer_limits(self) def check_sender_transfer_limits(self): if self.sender_user is None: # skip if there is no sender, which implies system send return relevant_transfer_limits = self.get_transfer_limits() for limit in relevant_transfer_limits: if limit.no_transfer_allowed: raise NoTransferAllowedLimitError(token=self.token.name) if limit.transfer_count is not None: # GE Limits transaction_count = limit.apply_all_filters( self, db.session.query( func.count(CreditTransfer.id).label('count')) ).execution_options(show_all=True).first().count if (transaction_count or 0) > limit.transfer_count: message = 'Account Limit "{}" reached. Allowed {} transaction per {} days'\ .format(limit.name, limit.transfer_count, limit.time_period_days) self.resolve_as_rejected(message=message) raise TransferCountLimitError( transfer_count_limit=limit.transfer_count, limit_time_period_days=limit.time_period_days, token=self.token.name, message=message) if limit.transfer_balance_fraction is not None: allowed_transfer = limit.transfer_balance_fraction * self.sender_transfer_account.balance if self.transfer_amount > allowed_transfer: message = 'Account % Limit "{}" reached. {} available'.format( limit.name, max(allowed_transfer, 0)) self.resolve_as_rejected(message=message) raise TransferBalanceFractionLimitError( transfer_balance_fraction_limit=limit. transfer_balance_fraction, transfer_amount_avail=int(allowed_transfer), limit_time_period_days=limit.time_period_days, token=self.token.name, message=message) if limit.total_amount is not None: # Sempo Compliance Account Limits transaction_volume = limit.apply_all_filters( self, db.session.query( func.sum(CreditTransfer.transfer_amount).label('total') )).execution_options(show_all=True).first().total or 0 if transaction_volume > limit.total_amount: # Don't include the current transaction when reporting amount available amount_avail = limit.total_amount - transaction_volume + int( self.transfer_amount) message = 'Account Limit "{}" reached. {} available'.format( limit.name, max(amount_avail, 0)) self.resolve_as_rejected(message=message) raise TransferAmountLimitError( transfer_amount_limit=limit.total_amount, transfer_amount_avail=amount_avail, limit_time_period_days=limit.time_period_days, token=self.token.name, message=message) return relevant_transfer_limits def check_sender_has_sufficient_balance(self): return self.sender_user and self.sender_transfer_account.balance - self.transfer_amount >= 0 def check_sender_is_approved(self): return self.sender_user and self.sender_transfer_account.is_approved def check_recipient_is_approved(self): return self.recipient_user and self.recipient_transfer_account.is_approved def _select_transfer_account(self, token, user): if token is None: raise Exception("Token must be specified") return find_transfer_accounts_with_matching_token(user, token) def append_organisation_if_required(self, organisation): if organisation and organisation not in self.organisations: self.organisations.append(organisation) def __init__(self, amount, token=None, sender_user=None, recipient_user=None, sender_transfer_account=None, recipient_transfer_account=None, transfer_type: TransferTypeEnum = None, uuid=None, transfer_metadata=None, fiat_ramp=None, transfer_subtype: TransferSubTypeEnum = None, is_ghost_transfer=False): if amount < 0: raise Exception("Negative amount provided") self.transfer_amount = amount self.sender_user = sender_user self.recipient_user = recipient_user self.sender_transfer_account = sender_transfer_account or self._select_transfer_account( token, sender_user) self.token = token or self.sender_transfer_account.token self.fiat_ramp = fiat_ramp try: self.recipient_transfer_account = recipient_transfer_account or self._select_transfer_account( self.token, recipient_user) if is_ghost_transfer is False: self.recipient_transfer_account.is_ghost = False except NoTransferAccountError: self.recipient_transfer_account = TransferAccount( bound_entity=recipient_user, token=token, is_approved=True, is_ghost=is_ghost_transfer) db.session.add(self.recipient_transfer_account) if transfer_type is TransferTypeEnum.DEPOSIT: self.sender_transfer_account = self.recipient_transfer_account.get_float_transfer_account( ) if transfer_type is TransferTypeEnum.WITHDRAWAL: self.recipient_transfer_account = self.sender_transfer_account.get_float_transfer_account( ) if self.sender_transfer_account.token != self.recipient_transfer_account.token: raise Exception("Tokens do not match") self.transfer_type = transfer_type self.transfer_subtype = transfer_subtype self.transfer_metadata = transfer_metadata if uuid is not None: self.uuid = uuid self.append_organisation_if_required( self.recipient_transfer_account.organisation) self.append_organisation_if_required( self.sender_transfer_account.organisation)
def __init__(self, amount, token=None, sender_user=None, recipient_user=None, sender_transfer_account=None, recipient_transfer_account=None, transfer_type: TransferTypeEnum = None, uuid=None, transfer_metadata=None, fiat_ramp=None, transfer_subtype: TransferSubTypeEnum = None, is_ghost_transfer=False): if amount < 0: raise Exception("Negative amount provided") self.transfer_amount = amount self.sender_user = sender_user self.recipient_user = recipient_user self.sender_transfer_account = sender_transfer_account or self._select_transfer_account( token, sender_user) self.token = token or self.sender_transfer_account.token self.fiat_ramp = fiat_ramp try: self.recipient_transfer_account = recipient_transfer_account or self._select_transfer_account( self.token, recipient_user) if is_ghost_transfer is False: self.recipient_transfer_account.is_ghost = False except NoTransferAccountError: self.recipient_transfer_account = TransferAccount( bound_entity=recipient_user, token=token, is_approved=True, is_ghost=is_ghost_transfer) db.session.add(self.recipient_transfer_account) if transfer_type is TransferTypeEnum.DEPOSIT: self.sender_transfer_account = self.recipient_transfer_account.get_float_transfer_account( ) if transfer_type is TransferTypeEnum.WITHDRAWAL: self.recipient_transfer_account = self.sender_transfer_account.get_float_transfer_account( ) if self.sender_transfer_account.token != self.recipient_transfer_account.token: raise Exception("Tokens do not match") self.transfer_type = transfer_type self.transfer_subtype = transfer_subtype self.transfer_metadata = transfer_metadata if uuid is not None: self.uuid = uuid self.append_organisation_if_required( self.recipient_transfer_account.organisation) self.append_organisation_if_required( self.sender_transfer_account.organisation)
def create_transfer_account_user(first_name=None, last_name=None, preferred_language=None, phone=None, email=None, public_serial_number=None, uuid=None, organisation: Organisation = None, token=None, blockchain_address=None, transfer_account_name=None, use_precreated_pin=False, use_last_4_digits_of_id_as_initial_pin=False, existing_transfer_account=None, roles=None, is_self_sign_up=False, business_usage=None, initial_disbursement=None): user = User(first_name=first_name, last_name=last_name, preferred_language=preferred_language, blockchain_address=blockchain_address, phone=phone, email=email, uuid=uuid, public_serial_number=public_serial_number, is_self_sign_up=is_self_sign_up, business_usage=business_usage) precreated_pin = None is_activated = False try: transfer_card = TransferCard.get_transfer_card(public_serial_number) except Exception as e: transfer_card = None if use_precreated_pin: precreated_pin = transfer_card.PIN is_activated = True elif use_last_4_digits_of_id_as_initial_pin: precreated_pin = str(public_serial_number or phone)[-4:] is_activated = False user.set_pin(precreated_pin, is_activated) if roles: for role in roles: user.set_held_role(role[0], role[1]) else: user.remove_all_held_roles() if not organisation: organisation = Organisation.master_organisation() user.add_user_to_organisation(organisation, is_admin=False) db.session.add(user) if existing_transfer_account: transfer_account = existing_transfer_account user.transfer_accounts.append(existing_transfer_account) else: transfer_account = TransferAccount( bound_entity=user, blockchain_address=blockchain_address, organisation=organisation) top_level_roles = [r[0] for r in roles or []] is_vendor = 'VENDOR' in top_level_roles is_beneficiary = 'BENEFICIARY' in top_level_roles transfer_account.name = transfer_account_name transfer_account.is_vendor = is_vendor transfer_account.is_beneficiary = is_beneficiary if transfer_card: transfer_account.transfer_card = transfer_card if token: transfer_account.token = token if not is_self_sign_up: transfer_account.approve_and_disburse( initial_disbursement=initial_disbursement) db.session.add(transfer_account) user.default_transfer_account = transfer_account return user
def __init__(self, amount, token=None, sender_user=None, recipient_user=None, sender_transfer_account=None, recipient_transfer_account=None, transfer_type: TransferTypeEnum=None, uuid=None, transfer_metadata=None, fiat_ramp=None, transfer_subtype: TransferSubTypeEnum=None, transfer_mode: TransferModeEnum = None, is_ghost_transfer=False, require_sufficient_balance=True): if amount < 0: raise Exception("Negative amount provided") self.transfer_amount = amount self.sender_user = sender_user self.recipient_user = recipient_user self.sender_transfer_account = sender_transfer_account or self._select_transfer_account( token, sender_user ) self.token = token or self.sender_transfer_account.token self.fiat_ramp = fiat_ramp if transfer_type is TransferTypeEnum.DEPOSIT: self.sender_transfer_account = self.recipient_transfer_account.token.float_account if transfer_type is TransferTypeEnum.WITHDRAWAL: self.recipient_transfer_account = self.sender_transfer_account.token.float_account try: self.recipient_transfer_account = recipient_transfer_account or self.recipient_transfer_account or self._select_transfer_account( self.token, recipient_user ) if is_ghost_transfer is False: self.recipient_transfer_account.is_ghost = False except NoTransferAccountError: self.recipient_transfer_account = TransferAccount( bound_entity=recipient_user, token=token, is_approved=True, is_ghost=is_ghost_transfer ) db.session.add(self.recipient_transfer_account) if self.sender_transfer_account.token != self.recipient_transfer_account.token: raise Exception("Tokens do not match") self.transfer_type = transfer_type self.transfer_subtype = transfer_subtype self.transfer_mode = transfer_mode self.transfer_metadata = transfer_metadata if uuid is not None: self.uuid = uuid self.append_organisation_if_required(self.recipient_transfer_account.organisation) self.append_organisation_if_required(self.sender_transfer_account.organisation) if require_sufficient_balance and not self.check_sender_has_sufficient_balance(): message = "Sender {} has insufficient balance. Has {}, needs {}.".format( self.sender_transfer_account, self.sender_transfer_account.balance, self.transfer_amount ) self.resolve_as_rejected(message) raise InsufficientBalanceError(message) self.update_balances()
def new_transfer_account(create_master_organisation): from server.models.transfer_account import TransferAccount return TransferAccount()
def create_transfer_account_user(first_name=None, last_name=None, preferred_language=None, phone=None, email=None, public_serial_number=None, organisation: Organisation = None, token=None, blockchain_address=None, transfer_account_name=None, lat=None, lng=None, use_precreated_pin=False, use_last_4_digits_of_id_as_initial_pin=False, existing_transfer_account=None, is_beneficiary=False, is_vendor=False, is_tokenagent=False, is_groupaccount=False, is_self_sign_up=False, business_usage=None, initial_disbursement=None): user = User(first_name=first_name, last_name=last_name, lat=lat, lng=lng, preferred_language=preferred_language, phone=phone, email=email, public_serial_number=public_serial_number, is_self_sign_up=is_self_sign_up, business_usage=business_usage) precreated_pin = None is_activated = False try: transfer_card = TransferCard.get_transfer_card(public_serial_number) except Exception as e: transfer_card = None if use_precreated_pin: precreated_pin = transfer_card.PIN is_activated = True elif use_last_4_digits_of_id_as_initial_pin: precreated_pin = str(public_serial_number or phone)[-4:] is_activated = False user.set_pin(precreated_pin, is_activated) if not is_vendor: vendor_tier = None elif existing_transfer_account: vendor_tier = 'vendor' else: vendor_tier = 'supervendor' user.set_held_role('VENDOR', vendor_tier) if is_tokenagent: user.set_held_role('TOKEN_AGENT', 'grassroots_token_agent') if is_groupaccount: user.set_held_role('GROUP_ACCOUNT', 'grassroots_group_account') if is_beneficiary: user.set_held_role('BENEFICIARY', 'beneficiary') if not organisation: organisation = Organisation.master_organisation() user.add_user_to_organisation(organisation, is_admin=False) db.session.add(user) if existing_transfer_account: transfer_account = existing_transfer_account user.transfer_accounts.append(existing_transfer_account) else: transfer_account = TransferAccount( bound_entity=user, blockchain_address=blockchain_address, organisation=organisation) transfer_account.name = transfer_account_name transfer_account.is_vendor = is_vendor transfer_account.is_beneficiary = is_beneficiary if transfer_card: transfer_account.transfer_card = transfer_card if token: transfer_account.token = token if not is_self_sign_up: transfer_account.approve_and_disburse( initial_disbursement=initial_disbursement) db.session.add(transfer_account) user.default_transfer_account = transfer_account return user
class CreditTransfer(ManyOrgBase, BlockchainTaskableBase): __tablename__ = 'credit_transfer' uuid = db.Column(db.String, unique=True) resolved_date = db.Column(db.DateTime) _transfer_amount_wei = db.Column(db.Numeric(27), default=0) transfer_type = db.Column(db.Enum(TransferTypeEnum), index=True) transfer_subtype = db.Column(db.Enum(TransferSubTypeEnum)) transfer_status = db.Column(db.Enum(TransferStatusEnum), default=TransferStatusEnum.PENDING) transfer_mode = db.Column(db.Enum(TransferModeEnum)) transfer_use = db.Column(JSON) transfer_metadata = db.Column(JSONB) exclude_from_limit_calcs = db.Column(db.Boolean, default=False) resolution_message = db.Column(db.String()) token_id = db.Column(db.Integer, db.ForeignKey(Token.id)) sender_transfer_account_id = db.Column( db.Integer, db.ForeignKey("transfer_account.id")) recipient_transfer_account_id = db.Column( db.Integer, db.ForeignKey("transfer_account.id")) sender_blockchain_address_id = db.Column( db.Integer, db.ForeignKey("blockchain_address.id")) recipient_blockchain_address_id = db.Column( db.Integer, db.ForeignKey("blockchain_address.id")) sender_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), index=True) recipient_user_id = db.Column(db.Integer, db.ForeignKey("user.id")) attached_images = db.relationship('UploadedResource', backref='credit_transfer', lazy=True) fiat_ramp = db.relationship('FiatRamp', backref='credit_transfer', lazy=True, uselist=False) __table_args__ = (Index('updated_index', "updated"), ) from_exchange = db.relationship('Exchange', backref='from_transfer', lazy=True, uselist=False, foreign_keys='Exchange.from_transfer_id') to_exchange = db.relationship('Exchange', backref='to_transfer', lazy=True, uselist=False, foreign_keys='Exchange.to_transfer_id') # TODO: Apply this to all transfer amounts/balances, work out the correct denominator size @hybrid_property def transfer_amount(self): return (self._transfer_amount_wei or 0) / int(1e16) @transfer_amount.setter def transfer_amount(self, val): self._transfer_amount_wei = val * int(1e16) def send_blockchain_payload_to_worker(self, is_retry=False, queue='high-priority'): sender_approval = self.sender_transfer_account.get_or_create_system_transfer_approval( ) recipient_approval = self.recipient_transfer_account.get_or_create_system_transfer_approval( ) return bt.make_token_transfer( signing_address=self.sender_transfer_account.organisation. system_blockchain_address, token=self.token, from_address=self.sender_transfer_account.blockchain_address, to_address=self.recipient_transfer_account.blockchain_address, amount=self.transfer_amount, prior_tasks=list( filter(lambda x: x is not None, [ sender_approval.eth_send_task_uuid, sender_approval.approval_task_uuid, recipient_approval.eth_send_task_uuid, recipient_approval.approval_task_uuid ])), queue=queue, task_uuid=self.blockchain_task_uuid) def resolve_as_completed(self, existing_blockchain_txn=None, queue='high-priority'): if self.transfer_status not in [None, TransferStatusEnum.PENDING]: raise Exception( f'Transfer resolve function called multiple times for transaciton {self.id}' ) self.check_sender_transfer_limits() self.resolved_date = datetime.datetime.utcnow() self.transfer_status = TransferStatusEnum.COMPLETE self.sender_transfer_account.decrement_balance(self.transfer_amount) self.recipient_transfer_account.increment_balance(self.transfer_amount) if self.transfer_type == TransferTypeEnum.PAYMENT and self.transfer_subtype == TransferSubTypeEnum.DISBURSEMENT: if self.recipient_user and self.recipient_user.transfer_card: self.recipient_user.transfer_card.update_transfer_card() if self.fiat_ramp and self.transfer_type in [ TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL ]: self.fiat_ramp.resolve_as_completed() if not existing_blockchain_txn: self.blockchain_task_uuid = str(uuid4()) g.pending_transactions.append((self, queue)) def resolve_as_rejected(self, message=None): if self.transfer_status not in [None, TransferStatusEnum.PENDING]: raise Exception( f'Transfer resolve function called multiple times for transaciton {self.id}' ) if self.fiat_ramp and self.transfer_type in [ TransferTypeEnum.DEPOSIT, TransferTypeEnum.WITHDRAWAL ]: self.fiat_ramp.resolve_as_rejected() self.resolved_date = datetime.datetime.utcnow() self.transfer_status = TransferStatusEnum.REJECTED if message: self.resolution_message = message def get_transfer_limits(self): from server.utils.transfer_limits import ( LIMIT_IMPLEMENTATIONS, get_applicable_transfer_limits) return get_applicable_transfer_limits(LIMIT_IMPLEMENTATIONS, self) def check_sender_transfer_limits(self): if self.sender_user is None: # skip if there is no sender, which implies system send return relevant_transfer_limits = self.get_transfer_limits() for limit in relevant_transfer_limits: try: limit.validate_transfer(self) except (TransferAmountLimitError, TransferCountLimitError, TransferBalanceFractionLimitError, MaximumPerTransferLimitError, MinimumSentLimitError, NoTransferAllowedLimitError) as e: self.resolve_as_rejected(message=e.message) raise e return relevant_transfer_limits def check_sender_has_sufficient_balance(self): return self.sender_user and self.sender_transfer_account.balance - self.transfer_amount >= 0 def check_sender_is_approved(self): return self.sender_user and self.sender_transfer_account.is_approved def check_recipient_is_approved(self): return self.recipient_user and self.recipient_transfer_account.is_approved def _select_transfer_account(self, token, user): if token is None: raise Exception("Token must be specified") return find_transfer_accounts_with_matching_token(user, token) def append_organisation_if_required(self, organisation): if organisation and organisation not in self.organisations: self.organisations.append(organisation) def __init__(self, amount, token=None, sender_user=None, recipient_user=None, sender_transfer_account=None, recipient_transfer_account=None, transfer_type: TransferTypeEnum = None, uuid=None, transfer_metadata=None, fiat_ramp=None, transfer_subtype: TransferSubTypeEnum = None, transfer_mode: TransferModeEnum = None, is_ghost_transfer=False): if amount < 0: raise Exception("Negative amount provided") self.transfer_amount = amount self.sender_user = sender_user self.recipient_user = recipient_user self.sender_transfer_account = sender_transfer_account or self._select_transfer_account( token, sender_user) self.token = token or self.sender_transfer_account.token self.fiat_ramp = fiat_ramp try: self.recipient_transfer_account = recipient_transfer_account or self._select_transfer_account( self.token, recipient_user) if is_ghost_transfer is False: self.recipient_transfer_account.is_ghost = False except NoTransferAccountError: self.recipient_transfer_account = TransferAccount( bound_entity=recipient_user, token=token, is_approved=True, is_ghost=is_ghost_transfer) db.session.add(self.recipient_transfer_account) if transfer_type is TransferTypeEnum.DEPOSIT: self.sender_transfer_account = self.recipient_transfer_account.get_float_transfer_account( ) if transfer_type is TransferTypeEnum.WITHDRAWAL: self.recipient_transfer_account = self.sender_transfer_account.get_float_transfer_account( ) if self.sender_transfer_account.token != self.recipient_transfer_account.token: raise Exception("Tokens do not match") self.transfer_type = transfer_type self.transfer_subtype = transfer_subtype self.transfer_mode = transfer_mode self.transfer_metadata = transfer_metadata if uuid is not None: self.uuid = uuid self.append_organisation_if_required( self.recipient_transfer_account.organisation) self.append_organisation_if_required( self.sender_transfer_account.organisation)