diff --git a/app/model/db/__init__.py b/app/model/db/__init__.py index 0b2f471c..14f2aaf7 100644 --- a/app/model/db/__init__.py +++ b/app/model/db/__init__.py @@ -72,8 +72,8 @@ ) from .idx_transfer import ( IDXTransfer, - IDXTransfersSortItem, - IDXTransferBlockNumber + IDXTransferBlockNumber, + IDXTransferSourceEventType ) from .idx_transfer_approval import ( IDXTransferApproval, diff --git a/app/model/db/idx_transfer.py b/app/model/db/idx_transfer.py index 84b1712c..28690514 100644 --- a/app/model/db/idx_transfer.py +++ b/app/model/db/idx_transfer.py @@ -22,12 +22,19 @@ Column, BigInteger, String, - DateTime + DateTime, + JSON ) from .base import Base +class IDXTransferSourceEventType(str, Enum): + """Transfer source event type""" + TRANSFER = "Transfer" + UNLOCK = "Unlock" + + class IDXTransfer(Base): """INDEX Transfer""" __tablename__ = "idx_transfer" @@ -43,17 +50,14 @@ class IDXTransfer(Base): to_address = Column(String(42), index=True) # transfer amount amount = Column(BigInteger) + # Source Event (IDXTransferSourceEventType) + source_event = Column(String(50), nullable=False) + # Data + data = Column(JSON) # block timestamp block_timestamp = Column(DateTime) -class IDXTransfersSortItem(str, Enum): - BLOCK_TIMESTAMP = "block_timestamp" - FROM_ADDRESS = "from_address" - TO_ADDRESS = "to_address" - AMOUNT = "amount" - - class IDXTransferBlockNumber(Base): """Synchronized blockNumber of IDXTransfer""" __tablename__ = "idx_transfer_block_number" diff --git a/app/model/schema/__init__.py b/app/model/schema/__init__.py index e661f5a4..3cc4f5e9 100644 --- a/app/model/schema/__init__.py +++ b/app/model/schema/__init__.py @@ -17,63 +17,78 @@ SPDX-License-Identifier: Apache-2.0 """ from .account import ( + # Request AccountCreateKeyRequest, AccountGenerateRsaKeyRequest, AccountChangeEOAPasswordRequest, AccountChangeRSAPassphraseRequest, AccountAuthTokenRequest, + # Response AccountResponse, AccountAuthTokenResponse ) from .batch_issue_redeem import ( + # Response BatchIssueRedeemUploadIdResponse, GetBatchIssueRedeemResponse, GetBatchIssueRedeemResult, ListBatchIssueRedeemUploadResponse ) from .bc_explorer import ( + # Request ListBlockDataQuery, ListTxDataQuery, + # Response BlockDataResponse, BlockDataListResponse, TxDataResponse, TxDataListResponse ) from .bulk_transfer import ( + # Response BulkTransferUploadIdResponse, BulkTransferUploadResponse, BulkTransferResponse ) from .e2e_messaging import ( + # Request E2EMessagingAccountCreateRequest, E2EMessagingAccountUpdateRsaKeyRequest, E2EMessagingAccountChangeEOAPasswordRequest, E2EMessagingAccountChangeRSAPassphraseRequest, + # Response E2EMessagingAccountResponse, E2EMessagingResponse, ListAllE2EMessagingResponse ) from .file import ( + # Request UploadFileRequest, + # Response FileResponse, ListAllFilesResponse, DownloadFileResponse ) from .holder import ( + # Response HolderResponse, HolderCountResponse ) from .index import ( + # Response E2EEResponse, BlockNumberResponse ) from .issue_redeem import ( + # Response IssueRedeemEvent, IssueRedeemHistoryResponse ) from .ledger import ( + # Request CreateUpdateLedgerTemplateRequest, CreateUpdateLedgerDetailsDataRequest, + # Response ListAllLedgerHistoryResponse, RetrieveLedgerHistoryResponse, LedgerTemplateResponse, @@ -83,8 +98,10 @@ ) from .notification import ListAllNotificationsResponse from .personal_info import ( + # Request ModifyPersonalInfoRequest, RegisterPersonalInfoRequest, + # Response BatchRegisterPersonalInfoUploadResponse, ListBatchRegisterPersonalInfoUploadResponse, GetBatchRegisterPersonalInfoResponse, @@ -103,8 +120,10 @@ ListAllLockEventsResponse ) from .scheduled_events import ( + # Request IbetStraightBondScheduledUpdate, IbetShareScheduledUpdate, + # Response ScheduledEventIdResponse, ScheduledEventResponse ) @@ -126,14 +145,20 @@ IbetShareResponse ) from .token_holders import ( + # Request CreateTokenHoldersListRequest, + # Response CreateTokenHoldersListResponse, RetrieveTokenHoldersListResponse, ListAllTokenHolderCollectionsResponse ) from .transfer import ( + # Request UpdateTransferApprovalRequest, UpdateTransferApprovalOperationType, + ListTransferHistorySortItem, + ListTransferHistoryQuery, + # Response TransferResponse, TransferHistoryResponse, TransferApprovalsResponse, diff --git a/app/model/schema/transfer.py b/app/model/schema/transfer.py index 0febbdbc..1afeb3fc 100644 --- a/app/model/schema/transfer.py +++ b/app/model/schema/transfer.py @@ -21,18 +21,50 @@ List, Optional ) +from fastapi import Query from pydantic import ( BaseModel, - Field + Field, + NonNegativeInt ) +from pydantic.dataclasses import dataclass from .types import ResultSet +############################ +# COMMON +############################ + +class TransferSourceEventType(str, Enum): + Transfer = "Transfer" + Unlock = "Unlock" + + ############################ # REQUEST ############################ +class ListTransferHistorySortItem(str, Enum): + BLOCK_TIMESTAMP = "block_timestamp" + FROM_ADDRESS = "from_address" + TO_ADDRESS = "to_address" + AMOUNT = "amount" + + +@dataclass +class ListTransferHistoryQuery: + source_event: Optional[TransferSourceEventType] = Query(default=None, description="source event of transfer") + data: Optional[str] = Query(default=None, description="source event data") + + sort_item: ListTransferHistorySortItem = Query( + default=ListTransferHistorySortItem.BLOCK_TIMESTAMP, description="sort item" + ) + sort_order: int = Query(default=1, ge=0, le=1, description="0:asc, 1:desc") + offset: Optional[NonNegativeInt] = Query(default=None, description="start position") + limit: Optional[NonNegativeInt] = Query(default=None, description="number of set") + + class UpdateTransferApprovalOperationType(str, Enum): APPROVE = "approve" CANCEL = "cancel" @@ -54,6 +86,8 @@ class TransferResponse(BaseModel): from_address: str to_address: str amount: int + source_event: TransferSourceEventType = Field(description="Source Event") + data: dict | None = Field(description="Event data") block_timestamp: str diff --git a/app/routers/bond.py b/app/routers/bond.py index c9ff0fa9..73121c9b 100644 --- a/app/routers/bond.py +++ b/app/routers/bond.py @@ -37,7 +37,9 @@ and_, or_, func, - literal_column + literal_column, + cast, + String ) from sqlalchemy.orm import ( Session, @@ -50,11 +52,20 @@ from app import log from app.database import db_session from app.model.schema import ( + # Request IbetStraightBondCreate, IbetStraightBondUpdate, IbetStraightBondTransfer, IbetStraightBondAdditionalIssue, IbetStraightBondRedeem, + ModifyPersonalInfoRequest, + RegisterPersonalInfoRequest, + IbetStraightBondScheduledUpdate, + UpdateTransferApprovalOperationType, + UpdateTransferApprovalRequest, + ListTransferHistorySortItem, + ListTransferHistoryQuery, + # Response IbetStraightBondResponse, TokenAddressResponse, HolderResponse, @@ -63,16 +74,11 @@ BulkTransferUploadIdResponse, BulkTransferUploadResponse, BulkTransferResponse, - IbetStraightBondScheduledUpdate, ScheduledEventIdResponse, ScheduledEventResponse, - ModifyPersonalInfoRequest, - RegisterPersonalInfoRequest, TransferApprovalsResponse, TransferApprovalHistoryResponse, TransferApprovalTokenResponse, - UpdateTransferApprovalRequest, - UpdateTransferApprovalOperationType, BatchIssueRedeemUploadIdResponse, GetBatchIssueRedeemResponse, ListBatchIssueRedeemUploadResponse, @@ -92,7 +98,6 @@ BulkTransfer, BulkTransferUpload, IDXTransfer, - IDXTransfersSortItem, IDXTransferApproval, IDXTransferApprovalsSortItem, IDXIssueRedeem, @@ -141,7 +146,6 @@ ContractRevertError, AuthorizationError ) -from config import TZ router = APIRouter( prefix="/bond", @@ -149,7 +153,7 @@ ) LOG = log.get_logger() -local_tz = timezone(TZ) +local_tz = timezone(config.TZ) # POST: /bond/tokens @@ -1610,7 +1614,7 @@ def modify_holder_personal_info( @router.post( "/tokens/{token_address}/personal_info", response_model=None, - responses=get_routers_responses(422, 401, 404, InvalidParameterError, SendTransactionError, ContractRevertError) + responses=get_routers_responses(422, 401, 404, AuthorizationError, InvalidParameterError, SendTransactionError, ContractRevertError) ) def register_holder_personal_info( request: Request, @@ -1931,12 +1935,9 @@ def transfer_ownership( responses=get_routers_responses(422, 404, InvalidParameterError) ) def list_transfer_history( - token_address: str, - sort_item: IDXTransfersSortItem = Query(IDXTransfersSortItem.BLOCK_TIMESTAMP), - sort_order: int = Query(1, ge=0, le=1, description="0:asc, 1:desc"), - offset: Optional[int] = Query(None), - limit: Optional[int] = Query(None), - db: Session = Depends(db_session) + token_address: str, + request_query: ListTransferHistoryQuery = Depends(), + db: Session = Depends(db_session) ): """List token transfer history""" # Get token @@ -1955,24 +1956,27 @@ def list_transfer_history( filter(IDXTransfer.token_address == token_address) total = query.count() - # NOTE: Because it don`t filter, `total` and `count` will be the same. - count = total + if request_query.source_event is not None: + query = query.filter(IDXTransfer.source_event == request_query.source_event.value) + if request_query.data is not None: + query = query.filter(cast(IDXTransfer.data, String).like("%" + request_query.data + "%")) + count = query.count() # Sort - sort_attr = getattr(IDXTransfer, sort_item.value, None) - if sort_order == 0: # ASC + sort_attr = getattr(IDXTransfer, request_query.sort_item.value, None) + if request_query.sort_order == 0: # ASC query = query.order_by(sort_attr) else: # DESC query = query.order_by(desc(sort_attr)) - if sort_item != IDXTransfersSortItem.BLOCK_TIMESTAMP: + if request_query.sort_item != ListTransferHistorySortItem.BLOCK_TIMESTAMP: # NOTE: Set secondary sort for consistent results query = query.order_by(desc(IDXTransfer.block_timestamp)) # Pagination - if limit is not None: - query = query.limit(limit) - if offset is not None: - query = query.offset(offset) + if request_query.limit is not None: + query = query.limit(request_query.limit) + if request_query.offset is not None: + query = query.offset(request_query.offset) _transfers = query.all() transfer_history = [] @@ -1984,14 +1988,16 @@ def list_transfer_history( "from_address": _transfer.from_address, "to_address": _transfer.to_address, "amount": _transfer.amount, + "source_event": _transfer.source_event, + "data": _transfer.data, "block_timestamp": block_timestamp_utc.astimezone(local_tz).isoformat() }) return json_response({ "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": request_query.offset, + "limit": request_query.limit, "total": total }, "transfer_history": transfer_history @@ -2005,10 +2011,10 @@ def list_transfer_history( responses=get_routers_responses(422) ) def list_transfer_approval_history( - issuer_address: Optional[str] = Header(None), - offset: Optional[int] = Query(None), - limit: Optional[int] = Query(None), - db: Session = Depends(db_session) + issuer_address: Optional[str] = Header(None), + offset: Optional[int] = Query(None), + limit: Optional[int] = Query(None), + db: Session = Depends(db_session) ): """List transfer approval history""" # Create a subquery for 'status' added IDXTransferApproval diff --git a/app/routers/share.py b/app/routers/share.py index c9eafae2..8ec8d5a7 100644 --- a/app/routers/share.py +++ b/app/routers/share.py @@ -38,7 +38,9 @@ and_, or_, func, - literal_column + literal_column, + cast, + String ) from sqlalchemy.orm import ( Session, @@ -51,36 +53,40 @@ from app import log from app.database import db_session from app.model.schema import ( + # Request IbetShareCreate, IbetShareUpdate, IbetShareTransfer, IbetShareAdditionalIssue, IbetShareRedeem, + ModifyPersonalInfoRequest, + RegisterPersonalInfoRequest, + IbetShareScheduledUpdate, + UpdateTransferApprovalOperationType, + UpdateTransferApprovalRequest, + ListTransferHistorySortItem, + ListTransferHistoryQuery, + # Response IbetShareResponse, TokenAddressResponse, HolderResponse, HolderCountResponse, - TransferApprovalsResponse, TransferHistoryResponse, - TransferApprovalHistoryResponse, - TransferApprovalTokenResponse, BulkTransferUploadIdResponse, BulkTransferUploadResponse, BulkTransferResponse, - IbetShareScheduledUpdate, ScheduledEventIdResponse, ScheduledEventResponse, - ModifyPersonalInfoRequest, - RegisterPersonalInfoRequest, - UpdateTransferApprovalRequest, + TransferApprovalsResponse, + TransferApprovalHistoryResponse, + TransferApprovalTokenResponse, BatchIssueRedeemUploadIdResponse, GetBatchIssueRedeemResponse, ListBatchIssueRedeemUploadResponse, + IssueRedeemHistoryResponse, BatchRegisterPersonalInfoUploadResponse, ListBatchRegisterPersonalInfoUploadResponse, GetBatchRegisterPersonalInfoResponse, - UpdateTransferApprovalOperationType, - IssueRedeemHistoryResponse ) from app.model.db import ( Account, @@ -93,9 +99,11 @@ BulkTransfer, BulkTransferUpload, IDXTransfer, - IDXTransfersSortItem, IDXTransferApproval, IDXTransferApprovalsSortItem, + IDXIssueRedeem, + IDXIssueRedeemEventType, + IDXIssueRedeemSortItem, ScheduledEvents, UTXO, BatchIssueRedeemUpload, @@ -104,9 +112,6 @@ BatchRegisterPersonalInfoUpload, BatchRegisterPersonalInfoUploadStatus, BatchRegisterPersonalInfo, - IDXIssueRedeemSortItem, - IDXIssueRedeem, - IDXIssueRedeemEventType, TransferApprovalHistory, TransferApprovalOperationType ) @@ -1593,6 +1598,68 @@ def modify_holder_personal_info( return +# POST: /share/tokens/{token_address}/personal_info +@router.post( + "/tokens/{token_address}/personal_info", + response_model=None, + responses=get_routers_responses(422, 401, 404, AuthorizationError, InvalidParameterError, SendTransactionError, ContractRevertError) +) +def register_holder_personal_info( + request: Request, + token_address: str, + personal_info: RegisterPersonalInfoRequest, + issuer_address: str = Header(...), + eoa_password: Optional[str] = Header(None), + auth_token: Optional[str] = Header(None), + db: Session = Depends(db_session)): + """Register the holder's personal information""" + + # Validate Headers + validate_headers( + issuer_address=(issuer_address, address_is_valid_address), + eoa_password=(eoa_password, eoa_password_is_encrypted_value) + ) + + # Authentication + check_auth( + request=request, + db=db, + issuer_address=issuer_address, + eoa_password=eoa_password, + auth_token=auth_token + ) + + # Verify that the token is issued by the issuer_address + _token = db.query(Token). \ + filter(Token.type == TokenType.IBET_SHARE.value). \ + filter(Token.issuer_address == issuer_address). \ + filter(Token.token_address == token_address). \ + filter(Token.token_status != 2). \ + first() + if _token is None: + raise HTTPException(status_code=404, detail="token not found") + if _token.token_status == 0: + raise InvalidParameterError("this token is temporarily unavailable") + + # Register Personal Info + token_contract = IbetShareContract(token_address).get() + try: + personal_info_contract = PersonalInfoContract( + db=db, + issuer_address=issuer_address, + contract_address=token_contract.personal_info_contract_address + ) + personal_info_contract.register_info( + account_address=personal_info.account_address, + data=personal_info.dict(), + default_value=None + ) + except SendTransactionError: + raise SendTransactionError("failed to register personal information") + + return + + # GET: /share/tokens/{token_address}/personal_info/batch @router.get( "/tokens/{token_address}/personal_info/batch", @@ -1667,68 +1734,6 @@ def list_all_personal_info_batch_registration_uploads( }) -# POST: /share/tokens/{token_address}/personal_info -@router.post( - "/tokens/{token_address}/personal_info", - response_model=None, - responses=get_routers_responses(422, 401, 404, AuthorizationError, InvalidParameterError, SendTransactionError, ContractRevertError) -) -def register_holder_personal_info( - request: Request, - token_address: str, - personal_info: RegisterPersonalInfoRequest, - issuer_address: str = Header(...), - eoa_password: Optional[str] = Header(None), - auth_token: Optional[str] = Header(None), - db: Session = Depends(db_session)): - """Register the holder's personal information""" - - # Validate Headers - validate_headers( - issuer_address=(issuer_address, address_is_valid_address), - eoa_password=(eoa_password, eoa_password_is_encrypted_value) - ) - - # Authentication - check_auth( - request=request, - db=db, - issuer_address=issuer_address, - eoa_password=eoa_password, - auth_token=auth_token - ) - - # Verify that the token is issued by the issuer_address - _token = db.query(Token). \ - filter(Token.type == TokenType.IBET_SHARE.value). \ - filter(Token.issuer_address == issuer_address). \ - filter(Token.token_address == token_address). \ - filter(Token.token_status != 2). \ - first() - if _token is None: - raise HTTPException(status_code=404, detail="token not found") - if _token.token_status == 0: - raise InvalidParameterError("this token is temporarily unavailable") - - # Register Personal Info - token_contract = IbetShareContract(token_address).get() - try: - personal_info_contract = PersonalInfoContract( - db=db, - issuer_address=issuer_address, - contract_address=token_contract.personal_info_contract_address - ) - personal_info_contract.register_info( - account_address=personal_info.account_address, - data=personal_info.dict(), - default_value=None - ) - except SendTransactionError: - raise SendTransactionError("failed to register personal information") - - return - - # POST: /share/tokens/{token_address}/personal_info/batch @router.post( "/tokens/{token_address}/personal_info/batch", @@ -1918,12 +1923,9 @@ def transfer_ownership( responses=get_routers_responses(422, 404, InvalidParameterError) ) def list_transfer_history( - token_address: str, - sort_item: IDXTransfersSortItem = Query(IDXTransfersSortItem.BLOCK_TIMESTAMP), - sort_order: int = Query(1, ge=0, le=1, description="0:asc, 1:desc"), - offset: Optional[int] = Query(None), - limit: Optional[int] = Query(None), - db: Session = Depends(db_session) + token_address: str, + request_query: ListTransferHistoryQuery = Depends(), + db: Session = Depends(db_session) ): """List token transfer history""" # Get token @@ -1942,24 +1944,27 @@ def list_transfer_history( filter(IDXTransfer.token_address == token_address) total = query.count() - # NOTE: Because it don`t filter, `total` and `count` will be the same. + if request_query.source_event is not None: + query = query.filter(IDXTransfer.source_event == request_query.source_event.value) + if request_query.data is not None: + query = query.filter(cast(IDXTransfer.data, String).like("%" + request_query.data + "%")) count = query.count() # Sort - sort_attr = getattr(IDXTransfer, sort_item.value, None) - if sort_order == 0: # ASC + sort_attr = getattr(IDXTransfer, request_query.sort_item.value, None) + if request_query.sort_order == 0: # ASC query = query.order_by(sort_attr) else: # DESC query = query.order_by(desc(sort_attr)) - if sort_item != IDXTransfersSortItem.BLOCK_TIMESTAMP: + if request_query.sort_item != ListTransferHistorySortItem.BLOCK_TIMESTAMP: # NOTE: Set secondary sort for consistent results query = query.order_by(desc(IDXTransfer.block_timestamp)) # Pagination - if limit is not None: - query = query.limit(limit) - if offset is not None: - query = query.offset(offset) + if request_query.limit is not None: + query = query.limit(request_query.limit) + if request_query.offset is not None: + query = query.offset(request_query.offset) _transfers = query.all() transfer_history = [] @@ -1971,14 +1976,16 @@ def list_transfer_history( "from_address": _transfer.from_address, "to_address": _transfer.to_address, "amount": _transfer.amount, + "source_event": _transfer.source_event, + "data": _transfer.data, "block_timestamp": block_timestamp_utc.astimezone(local_tz).isoformat() }) return json_response({ "result_set": { "count": count, - "offset": offset, - "limit": limit, + "offset": request_query.offset, + "limit": request_query.limit, "total": total }, "transfer_history": transfer_history @@ -1992,10 +1999,10 @@ def list_transfer_history( responses=get_routers_responses(422) ) def list_transfer_approval_history( - issuer_address: Optional[str] = Header(None), - offset: Optional[int] = Query(None), - limit: Optional[int] = Query(None), - db: Session = Depends(db_session) + issuer_address: Optional[str] = Header(None), + offset: Optional[int] = Query(None), + limit: Optional[int] = Query(None), + db: Session = Depends(db_session) ): """List transfer approval history""" # Create a subquery for 'status' added IDXTransferApproval diff --git a/batch/indexer_transfer.py b/batch/indexer_transfer.py index ea762f87..4a8fd496 100644 --- a/batch/indexer_transfer.py +++ b/batch/indexer_transfer.py @@ -16,6 +16,7 @@ SPDX-License-Identifier: Apache-2.0 """ +import json import os import sys import time @@ -38,7 +39,8 @@ from app.model.db import ( Token, IDXTransfer, - IDXTransferBlockNumber + IDXTransferBlockNumber, + IDXTransferSourceEventType ) from app.utils.contract_utils import ContractUtils from app.utils.web3_utils import Web3Wrapper @@ -186,6 +188,8 @@ def __sync_transfer(self, db_session: Session, block_from: int, block_to: int): from_address=args["from"], to_address=args["to"], amount=args["value"], + source_event=IDXTransferSourceEventType.TRANSFER, + data_str=None, block_timestamp=block_timestamp ) except Exception: @@ -216,6 +220,7 @@ def __sync_unlock(self, db_session: Session, block_from: int, block_to: int): else: from_address = args.get("accountAddress", ZERO_ADDRESS) to_address = args.get("recipientAddress", ZERO_ADDRESS) + data_str = args.get("data", "") if from_address != to_address: self.__sink_on_transfer( db_session=db_session, @@ -224,6 +229,8 @@ def __sync_unlock(self, db_session: Session, block_from: int, block_to: int): from_address=from_address, to_address=to_address, amount=args["value"], + source_event=IDXTransferSourceEventType.UNLOCK, + data_str=data_str, block_timestamp=block_timestamp ) except Exception: @@ -236,13 +243,24 @@ def __sink_on_transfer(db_session: Session, from_address: str, to_address: str, amount: int, + source_event: IDXTransferSourceEventType, + data_str: str | None, block_timestamp: datetime): + if data_str is not None: + try: + data = json.loads(data_str) + except: + data = {} + else: + data = None transfer_record = IDXTransfer() transfer_record.transaction_hash = transaction_hash transfer_record.token_address = token_address transfer_record.from_address = from_address transfer_record.to_address = to_address transfer_record.amount = amount + transfer_record.source_event = source_event.value + transfer_record.data = data transfer_record.block_timestamp = block_timestamp db_session.add(transfer_record) LOG.debug(f"Transfer: transaction_hash={transaction_hash}") diff --git a/migrations/versions/3a0cc5e324b4_v23_3_0_feature_465.py b/migrations/versions/3a0cc5e324b4_v23_3_0_feature_465.py new file mode 100644 index 00000000..305dd2ee --- /dev/null +++ b/migrations/versions/3a0cc5e324b4_v23_3_0_feature_465.py @@ -0,0 +1,39 @@ +"""v23.3.0_feature_465 + +Revision ID: 3a0cc5e324b4 +Revises: 6920ad60f134 +Create Date: 2023-01-17 18:15:07.271586 + +""" +from alembic import op +import sqlalchemy as sa + + +from app.database import get_db_schema + +# revision identifiers, used by Alembic. +revision = '3a0cc5e324b4' +down_revision = '6920ad60f134' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('idx_transfer', sa.Column('data', sa.JSON(), nullable=True), schema=get_db_schema()) + # ### end Alembic commands ### + + # NOTE: Manually modified + # 1. Added server_default arg to migrate existing record. + # 2. Added alter column operation to remove server default setting. + op.add_column('idx_transfer', sa.Column('source_event', sa.String(length=50), server_default='Transfer', nullable=False), schema=get_db_schema()) + op.alter_column('idx_transfer', 'source_event', + existing_type=sa.String(length=50), + existing_nullable=False, server_default=None, schema=get_db_schema()) + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('idx_transfer', 'data', schema=get_db_schema()) + op.drop_column('idx_transfer', 'source_event', schema=get_db_schema()) + # ### end Alembic commands ### diff --git a/tests/test_app_routers_bond_transfers_{token_Address}_GET.py b/tests/test_app_routers_bond_transfers_{token_Address}_GET.py index 91313ef8..84e25116 100644 --- a/tests/test_app_routers_bond_transfers_{token_Address}_GET.py +++ b/tests/test_app_routers_bond_transfers_{token_Address}_GET.py @@ -24,7 +24,8 @@ from app.model.db import ( Token, TokenType, - IDXTransfer + IDXTransfer, + IDXTransferSourceEventType ) local_tz = timezone(config.TZ) @@ -74,6 +75,8 @@ def test_normal_1(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = i + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[i] db.add(_idx_transfer) @@ -98,6 +101,8 @@ def test_normal_1(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 0, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] }, { @@ -106,6 +111,8 @@ def test_normal_1(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -114,16 +121,17 @@ def test_normal_1(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, ] } assert resp.json() == assumed_response - # + # # offset, limit - # default sort - def test_normal_2(self, client, db): + def test_normal_2_1(self, client, db): # prepare data: Token _token = Token() _token.type = TokenType.IBET_STRAIGHT_BOND.value @@ -141,6 +149,8 @@ def test_normal_2(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = i + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[i] db.add(_idx_transfer) @@ -165,12 +175,170 @@ def test_normal_2(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[2] }, ] } assert resp.json() == assumed_response + # + # filter: source_event + def test_normal_2_2(self, client, db): + # prepare data: Token + _token = Token() + _token.type = TokenType.IBET_STRAIGHT_BOND.value + _token.tx_hash = self.test_transaction_hash + _token.issuer_address = self.test_issuer_address + _token.token_address = self.test_token_address + _token.abi = {} + db.add(_token) + + # prepare data: IDXTransfer + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_2" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 0 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None + _idx_transfer.block_timestamp = self.test_block_timestamp[0] + db.add(_idx_transfer) + + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_2" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None + _idx_transfer.block_timestamp = self.test_block_timestamp[1] + db.add(_idx_transfer) + + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_1" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} + _idx_transfer.block_timestamp = self.test_block_timestamp[2] + db.add(_idx_transfer) + + # request target API + resp = client.get( + self.base_url.format(self.test_token_address), + params={ + "source_event": IDXTransferSourceEventType.UNLOCK.value + } + ) + + # assertion + assert resp.status_code == 200 + assumed_response = { + "result_set": { + "count": 1, + "offset": None, + "limit": None, + "total": 3 + }, + "transfer_history": [ + { + "transaction_hash": self.test_transaction_hash, + "token_address": self.test_token_address, + "from_address": "test_from_address_1", + "to_address": self.test_to_address, + "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, + "block_timestamp": self.test_block_timestamp_str[2] + } + ] + } + assert resp.json() == assumed_response + + # + # filter: data + def test_normal_2_3(self, client, db): + # prepare data: Token + _token = Token() + _token.type = TokenType.IBET_STRAIGHT_BOND.value + _token.tx_hash = self.test_transaction_hash + _token.issuer_address = self.test_issuer_address + _token.token_address = self.test_token_address + _token.abi = {} + db.add(_token) + + # prepare data: IDXTransfer + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_2" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 0 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None + _idx_transfer.block_timestamp = self.test_block_timestamp[0] + db.add(_idx_transfer) + + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_2" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None + _idx_transfer.block_timestamp = self.test_block_timestamp[1] + db.add(_idx_transfer) + + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_1" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} + _idx_transfer.block_timestamp = self.test_block_timestamp[2] + db.add(_idx_transfer) + + # request target API + resp = client.get( + self.base_url.format(self.test_token_address), + params={ + "data": "unlo" + } + ) + + # assertion + assert resp.status_code == 200 + assumed_response = { + "result_set": { + "count": 1, + "offset": None, + "limit": None, + "total": 3 + }, + "transfer_history": [ + { + "transaction_hash": self.test_transaction_hash, + "token_address": self.test_token_address, + "from_address": "test_from_address_1", + "to_address": self.test_to_address, + "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, + "block_timestamp": self.test_block_timestamp_str[2] + } + ] + } + assert resp.json() == assumed_response + # # sort: block_timestamp ASC def test_normal_3(self, client, db): @@ -191,6 +359,8 @@ def test_normal_3(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = i + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[i] db.add(_idx_transfer) @@ -219,6 +389,8 @@ def test_normal_3(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, { @@ -227,6 +399,8 @@ def test_normal_3(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -235,6 +409,8 @@ def test_normal_3(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 0, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] } ] @@ -260,6 +436,8 @@ def test_normal_4(self, client, db): _idx_transfer.from_address = "test_from_address_2" _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 0 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[0] db.add(_idx_transfer) @@ -269,6 +447,8 @@ def test_normal_4(self, client, db): _idx_transfer.from_address = "test_from_address_2" _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[1] db.add(_idx_transfer) @@ -278,6 +458,8 @@ def test_normal_4(self, client, db): _idx_transfer.from_address = "test_from_address_1" _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} _idx_transfer.block_timestamp = self.test_block_timestamp[2] db.add(_idx_transfer) @@ -306,6 +488,8 @@ def test_normal_4(self, client, db): "from_address": "test_from_address_1", "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -314,6 +498,8 @@ def test_normal_4(self, client, db): "from_address": "test_from_address_2", "to_address": self.test_to_address, "amount": 0, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] }, { @@ -322,6 +508,8 @@ def test_normal_4(self, client, db): "from_address": "test_from_address_2", "to_address": self.test_to_address, "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, ] @@ -347,6 +535,8 @@ def test_normal_5(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = "test_to_address_2" _idx_transfer.amount = 0 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[0] db.add(_idx_transfer) @@ -356,6 +546,8 @@ def test_normal_5(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = "test_to_address_1" _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[1] db.add(_idx_transfer) @@ -365,6 +557,8 @@ def test_normal_5(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = "test_to_address_1" _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} _idx_transfer.block_timestamp = self.test_block_timestamp[2] db.add(_idx_transfer) @@ -393,6 +587,8 @@ def test_normal_5(self, client, db): "from_address": self.test_from_address, "to_address": "test_to_address_2", "amount": 0, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] }, { @@ -401,6 +597,8 @@ def test_normal_5(self, client, db): "from_address": self.test_from_address, "to_address": "test_to_address_1", "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -409,6 +607,8 @@ def test_normal_5(self, client, db): "from_address": self.test_from_address, "to_address": "test_to_address_1", "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, ] @@ -434,6 +634,8 @@ def test_normal_6(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[0] db.add(_idx_transfer) @@ -443,6 +645,8 @@ def test_normal_6(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[1] db.add(_idx_transfer) @@ -452,6 +656,8 @@ def test_normal_6(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} _idx_transfer.block_timestamp = self.test_block_timestamp[2] db.add(_idx_transfer) @@ -480,6 +686,8 @@ def test_normal_6(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] }, { @@ -488,6 +696,8 @@ def test_normal_6(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -496,6 +706,8 @@ def test_normal_6(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, ] diff --git a/tests/test_app_routers_share_transfers_{token_Address}_GET.py b/tests/test_app_routers_share_transfers_{token_Address}_GET.py index ba4a01ef..9b8e87ca 100644 --- a/tests/test_app_routers_share_transfers_{token_Address}_GET.py +++ b/tests/test_app_routers_share_transfers_{token_Address}_GET.py @@ -24,7 +24,8 @@ from app.model.db import ( Token, TokenType, - IDXTransfer + IDXTransfer, + IDXTransferSourceEventType ) local_tz = timezone(config.TZ) @@ -74,6 +75,8 @@ def test_normal_1(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = i + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[i] db.add(_idx_transfer) @@ -98,6 +101,8 @@ def test_normal_1(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 0, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] }, { @@ -106,6 +111,8 @@ def test_normal_1(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -114,16 +121,17 @@ def test_normal_1(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, ] } assert resp.json() == assumed_response - # + # # offset, limit - # default sort - def test_normal_2(self, client, db): + def test_normal_2_1(self, client, db): # prepare data: Token _token = Token() _token.type = TokenType.IBET_SHARE.value @@ -141,6 +149,8 @@ def test_normal_2(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = i + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[i] db.add(_idx_transfer) @@ -165,6 +175,164 @@ def test_normal_2(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, + "block_timestamp": self.test_block_timestamp_str[2] + }, + ] + } + assert resp.json() == assumed_response + + # + # filter: source_event + def test_normal_2_2(self, client, db): + # prepare data: Token + _token = Token() + _token.type = TokenType.IBET_SHARE.value + _token.tx_hash = self.test_transaction_hash + _token.issuer_address = self.test_issuer_address + _token.token_address = self.test_token_address + _token.abi = {} + db.add(_token) + + # prepare data: IDXTransfer + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_2" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 0 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None + _idx_transfer.block_timestamp = self.test_block_timestamp[0] + db.add(_idx_transfer) + + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_2" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None + _idx_transfer.block_timestamp = self.test_block_timestamp[1] + db.add(_idx_transfer) + + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_1" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} + _idx_transfer.block_timestamp = self.test_block_timestamp[2] + db.add(_idx_transfer) + + # request target API + resp = client.get( + self.base_url.format(self.test_token_address), + params={ + "source_event": IDXTransferSourceEventType.UNLOCK.value + } + ) + + # assertion + assert resp.status_code == 200 + assumed_response = { + "result_set": { + "count": 1, + "offset": None, + "limit": None, + "total": 3 + }, + "transfer_history": [ + { + "transaction_hash": self.test_transaction_hash, + "token_address": self.test_token_address, + "from_address": "test_from_address_1", + "to_address": self.test_to_address, + "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, + "block_timestamp": self.test_block_timestamp_str[2] + }, + ] + } + assert resp.json() == assumed_response + + # + # filter: data + def test_normal_2_3(self, client, db): + # prepare data: Token + _token = Token() + _token.type = TokenType.IBET_SHARE.value + _token.tx_hash = self.test_transaction_hash + _token.issuer_address = self.test_issuer_address + _token.token_address = self.test_token_address + _token.abi = {} + db.add(_token) + + # prepare data: IDXTransfer + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_2" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 0 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None + _idx_transfer.block_timestamp = self.test_block_timestamp[0] + db.add(_idx_transfer) + + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_2" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None + _idx_transfer.block_timestamp = self.test_block_timestamp[1] + db.add(_idx_transfer) + + _idx_transfer = IDXTransfer() + _idx_transfer.transaction_hash = self.test_transaction_hash + _idx_transfer.token_address = self.test_token_address + _idx_transfer.from_address = "test_from_address_1" + _idx_transfer.to_address = self.test_to_address + _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} + _idx_transfer.block_timestamp = self.test_block_timestamp[2] + db.add(_idx_transfer) + + # request target API + resp = client.get( + self.base_url.format(self.test_token_address), + params={ + "data": "unlo" + } + ) + + # assertion + assert resp.status_code == 200 + assumed_response = { + "result_set": { + "count": 1, + "offset": None, + "limit": None, + "total": 3 + }, + "transfer_history": [ + { + "transaction_hash": self.test_transaction_hash, + "token_address": self.test_token_address, + "from_address": "test_from_address_1", + "to_address": self.test_to_address, + "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, "block_timestamp": self.test_block_timestamp_str[2] }, ] @@ -191,6 +359,8 @@ def test_normal_3(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = i + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[i] db.add(_idx_transfer) @@ -219,6 +389,8 @@ def test_normal_3(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, { @@ -227,6 +399,8 @@ def test_normal_3(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -235,6 +409,8 @@ def test_normal_3(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 0, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] } ] @@ -260,6 +436,8 @@ def test_normal_4(self, client, db): _idx_transfer.from_address = "test_from_address_2" _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 0 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[0] db.add(_idx_transfer) @@ -269,6 +447,8 @@ def test_normal_4(self, client, db): _idx_transfer.from_address = "test_from_address_2" _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[1] db.add(_idx_transfer) @@ -278,6 +458,8 @@ def test_normal_4(self, client, db): _idx_transfer.from_address = "test_from_address_1" _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} _idx_transfer.block_timestamp = self.test_block_timestamp[2] db.add(_idx_transfer) @@ -306,6 +488,8 @@ def test_normal_4(self, client, db): "from_address": "test_from_address_1", "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -314,6 +498,8 @@ def test_normal_4(self, client, db): "from_address": "test_from_address_2", "to_address": self.test_to_address, "amount": 0, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] }, { @@ -322,6 +508,8 @@ def test_normal_4(self, client, db): "from_address": "test_from_address_2", "to_address": self.test_to_address, "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, ] @@ -347,6 +535,8 @@ def test_normal_5(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = "test_to_address_2" _idx_transfer.amount = 0 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[0] db.add(_idx_transfer) @@ -356,6 +546,8 @@ def test_normal_5(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = "test_to_address_1" _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[1] db.add(_idx_transfer) @@ -365,6 +557,8 @@ def test_normal_5(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = "test_to_address_1" _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} _idx_transfer.block_timestamp = self.test_block_timestamp[2] db.add(_idx_transfer) @@ -393,6 +587,8 @@ def test_normal_5(self, client, db): "from_address": self.test_from_address, "to_address": "test_to_address_2", "amount": 0, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] }, { @@ -401,6 +597,8 @@ def test_normal_5(self, client, db): "from_address": self.test_from_address, "to_address": "test_to_address_1", "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -409,6 +607,8 @@ def test_normal_5(self, client, db): "from_address": self.test_from_address, "to_address": "test_to_address_1", "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, ] @@ -434,6 +634,8 @@ def test_normal_6(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 1 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[0] db.add(_idx_transfer) @@ -443,6 +645,8 @@ def test_normal_6(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.TRANSFER.value + _idx_transfer.data = None _idx_transfer.block_timestamp = self.test_block_timestamp[1] db.add(_idx_transfer) @@ -452,6 +656,8 @@ def test_normal_6(self, client, db): _idx_transfer.from_address = self.test_from_address _idx_transfer.to_address = self.test_to_address _idx_transfer.amount = 2 + _idx_transfer.source_event = IDXTransferSourceEventType.UNLOCK.value + _idx_transfer.data = {"message": "unlock"} _idx_transfer.block_timestamp = self.test_block_timestamp[2] db.add(_idx_transfer) @@ -480,6 +686,8 @@ def test_normal_6(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 1, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[0] }, { @@ -488,6 +696,8 @@ def test_normal_6(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.UNLOCK.value, + "data": {"message": "unlock"}, "block_timestamp": self.test_block_timestamp_str[2] }, { @@ -496,6 +706,8 @@ def test_normal_6(self, client, db): "from_address": self.test_from_address, "to_address": self.test_to_address, "amount": 2, + "source_event": IDXTransferSourceEventType.TRANSFER.value, + "data": None, "block_timestamp": self.test_block_timestamp_str[1] }, ] diff --git a/tests/test_batch_indexer_transfer.py b/tests/test_batch_indexer_transfer.py index e7f0b8d3..0dee2550 100644 --- a/tests/test_batch_indexer_transfer.py +++ b/tests/test_batch_indexer_transfer.py @@ -16,6 +16,7 @@ SPDX-License-Identifier: Apache-2.0 """ +import json from datetime import datetime from eth_keyfile import decode_keyfile_json import logging @@ -26,14 +27,30 @@ from unittest.mock import patch from app.exceptions import ServiceUnavailableError -from app.model.db import Token, TokenType, IDXTransfer, IDXTransferBlockNumber -from app.model.blockchain import IbetStraightBondContract, IbetShareContract +from app.model.db import ( + Token, + TokenType, + IDXTransfer, + IDXTransferBlockNumber, + IDXTransferSourceEventType +) +from app.model.blockchain import ( + IbetStraightBondContract, + IbetShareContract +) from app.model.blockchain.tx_params.ibet_straight_bond import UpdateParams as IbetStraightBondUpdateParams from app.model.blockchain.tx_params.ibet_share import UpdateParams as IbetShareUpdateParams from app.utils.web3_utils import Web3Wrapper from app.utils.contract_utils import ContractUtils -from batch.indexer_transfer import Processor, LOG, main -from config import CHAIN_ID, TX_GAS_LIMIT +from batch.indexer_transfer import ( + Processor, + LOG, + main +) +from config import ( + CHAIN_ID, + TX_GAS_LIMIT +) from tests.account_config import config_eth_account from tests.utils.contract_utils import PersonalInfoContractTestUtils @@ -294,7 +311,7 @@ def test_normal_2_1(self, processor, db, personal_info_contract): issuer_address, user_address_1, 10, - "" + json.dumps({"message": "unlock"}) ).build_transaction({ "chainId": CHAIN_ID, "from": lock_account["address"], @@ -318,6 +335,8 @@ def test_normal_2_1(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_1 assert _transfer.amount == 40 + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None block = web3.eth.get_block(tx_receipt_1["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) @@ -328,6 +347,8 @@ def test_normal_2_1(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_1 assert _transfer.amount == 10 + assert _transfer.source_event == IDXTransferSourceEventType.UNLOCK.value + assert _transfer.data == {"message": "unlock"} block = web3.eth.get_block(tx_receipt_2["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) @@ -395,7 +416,7 @@ def test_normal_2_2(self, processor, db, personal_info_contract): issuer_address, issuer_address, 10, - "" + json.dumps({"message": "unlock"}) ).build_transaction({ "chainId": CHAIN_ID, "from": lock_account["address"], @@ -508,7 +529,7 @@ def test_normal_3_1(self, processor, db, personal_info_contract): issuer_address, user_address_1, 10, - "" + json.dumps({"message": "unlock"}) ).build_transaction({ "chainId": CHAIN_ID, "from": lock_account["address"], @@ -533,7 +554,7 @@ def test_normal_3_1(self, processor, db, personal_info_contract): issuer_address, user_address_1, 10, - "" + json.dumps({"message": "unlock"}) ).build_transaction({ "chainId": CHAIN_ID, "from": lock_account["address"], @@ -557,6 +578,8 @@ def test_normal_3_1(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_1 assert _transfer.amount == 40 + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None block = web3.eth.get_block(tx_receipt_1["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) @@ -567,6 +590,8 @@ def test_normal_3_1(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_2 assert _transfer.amount == 30 + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None block = web3.eth.get_block(tx_receipt_2["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) @@ -577,6 +602,8 @@ def test_normal_3_1(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_1 assert _transfer.amount == 10 + assert _transfer.source_event == IDXTransferSourceEventType.UNLOCK.value + assert _transfer.data == {"message": "unlock"} block = web3.eth.get_block(tx_receipt_3["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) @@ -587,6 +614,8 @@ def test_normal_3_1(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_1 assert _transfer.amount == 10 + assert _transfer.source_event == IDXTransferSourceEventType.UNLOCK.value + assert _transfer.data == {"message": "unlock"} block = web3.eth.get_block(tx_receipt_4["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) @@ -681,6 +710,8 @@ def test_normal_3_2(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == address_list1[i] assert _transfer.amount == value_list1[i] + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) block = web3.eth.get_block(tx_receipt_2["blockNumber"]) @@ -692,6 +723,8 @@ def test_normal_3_2(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == address_list2[i] assert _transfer.amount == value_list2[i] + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) _idx_transfer_block_number = db.query(IDXTransferBlockNumber).first() @@ -787,6 +820,8 @@ def test_normal_4(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_1 assert _transfer.amount == 40 + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None block = web3.eth.get_block(tx_receipt_1["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) _transfer = _transfer_list[1] @@ -796,6 +831,8 @@ def test_normal_4(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_2 assert _transfer.amount == 30 + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None block = web3.eth.get_block(tx_receipt_2["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) @@ -806,6 +843,8 @@ def test_normal_4(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_1 assert _transfer.amount == 40 + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None block = web3.eth.get_block(tx_receipt_3["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"]) @@ -816,6 +855,8 @@ def test_normal_4(self, processor, db, personal_info_contract): assert _transfer.from_address == issuer_address assert _transfer.to_address == user_address_2 assert _transfer.amount == 30 + assert _transfer.source_event == IDXTransferSourceEventType.TRANSFER.value + assert _transfer.data is None block = web3.eth.get_block(tx_receipt_4["blockNumber"]) assert _transfer.block_timestamp == datetime.utcfromtimestamp(block["timestamp"])