Skip to content

Commit

Permalink
Merge pull request #694 from BoostryJP/feature/#682
Browse files Browse the repository at this point in the history
Manage the issuer's child keys as a deterministic wallet
  • Loading branch information
YoshihitoAso authored Sep 30, 2024
2 parents bcfca50 + 8525921 commit 9cd811c
Show file tree
Hide file tree
Showing 41 changed files with 4,012 additions and 133 deletions.
6 changes: 6 additions & 0 deletions app/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ class MultipleTokenTransferNotAllowedError(BadRequestError):
code = 9


class OperationNotPermittedForOlderIssuers(BadRequestError):
"""An operation not permitted for older issuers"""

code = 10


class OperationNotAllowedStateError(BadRequestError):
"""
Error returned when server-side data is not ready to process the request
Expand Down
9 changes: 8 additions & 1 deletion app/model/db/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@
SPDX-License-Identifier: Apache-2.0
"""

from .account import Account, AccountRsaKeyTemporary, AccountRsaStatus
from .account import (
Account,
AccountRsaKeyTemporary,
AccountRsaStatus,
ChildAccount,
ChildAccountIndex,
)
from .auth_token import AuthToken
from .base import Base
from .batch_issue_redeem import (
Expand Down Expand Up @@ -55,6 +61,7 @@
IDXPersonalInfo,
IDXPersonalInfoBlockNumber,
IDXPersonalInfoHistory,
PersonalInfoDataSource,
PersonalInfoEventType,
)
from .idx_position import (
Expand Down
33 changes: 30 additions & 3 deletions app/model/db/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from enum import Enum

from sqlalchemy import JSON, Boolean, Integer, String
from sqlalchemy import JSON, BigInteger, Boolean, Integer, String
from sqlalchemy.orm import Mapped, mapped_column

from .base import Base
Expand All @@ -32,9 +32,12 @@ class Account(Base):

# issuer address
issuer_address: Mapped[str] = mapped_column(String(42), primary_key=True)
# ethereum keyfile
# issuer public key (hex encoded)
# - NOTE: The value will be set in versions after v24.12.
issuer_public_key: Mapped[str | None] = mapped_column(String(66))
# ethereum private-key keyfile
keyfile: Mapped[str | None] = mapped_column(JSON)
# ethereum account password (encrypted)
# keyfile password (encrypted)
eoa_password: Mapped[str | None] = mapped_column(String(2000))
# rsa private key
rsa_private_key: Mapped[str | None] = mapped_column(String(8000))
Expand Down Expand Up @@ -75,3 +78,27 @@ class AccountRsaKeyTemporary(Base):
rsa_public_key: Mapped[str | None] = mapped_column(String(2000))
# rsa passphrase (encrypted)
rsa_passphrase: Mapped[str | None] = mapped_column(String(2000))


class ChildAccountIndex(Base):
"""Latest index of child account"""

__tablename__ = "child_account_index"

# issuer address
issuer_address: Mapped[str] = mapped_column(String(42), primary_key=True)
# next index
next_index: Mapped[int] = mapped_column(BigInteger, nullable=False)


class ChildAccount(Base):
"""Issuer's Child Account"""

__tablename__ = "child_account"

# issuer address
issuer_address: Mapped[str] = mapped_column(String(42), primary_key=True)
# child account index
child_account_index: Mapped[int] = mapped_column(BigInteger, primary_key=True)
# child account address
child_account_address: Mapped[str] = mapped_column(String(42), nullable=False)
18 changes: 15 additions & 3 deletions app/model/db/idx_personal_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,17 @@

import config

from .base import Base
from .base import Base, naive_utcnow

local_tz = pytz.timezone(config.TZ)
utc_tz = pytz.timezone("UTC")


class PersonalInfoDataSource(StrEnum):
ON_CHAIN = "on-chain"
OFF_CHAIN = "off-chain"


class IDXPersonalInfo(Base):
"""INDEX Personal information of the token holder (decrypted)"""

Expand All @@ -45,7 +50,7 @@ class IDXPersonalInfo(Base):
issuer_address: Mapped[str | None] = mapped_column(String(42), index=True)
# personal information
# {
# "key_manager": "string",
# "key_manager": "string", // If managed by the issuer itself, 'SELF' is set by default.
# "name": "string",
# "postal_code": "string",
# "address": "string",
Expand All @@ -55,6 +60,10 @@ class IDXPersonalInfo(Base):
# "tax_category": "integer"
# }
_personal_info = mapped_column("personal_info", JSON, nullable=False)
# data source
data_source: Mapped[PersonalInfoDataSource] = mapped_column(
String(10), nullable=False
)

@hybrid_property
def personal_info(self):
Expand Down Expand Up @@ -132,7 +141,10 @@ class IDXPersonalInfoHistory(Base):
# personal information
personal_info = mapped_column(JSON, nullable=False)
# block timestamp
block_timestamp: Mapped[datetime | None] = mapped_column(DateTime)
# - For off-chain transactions, UTC now at the time of record insertion is set.
block_timestamp: Mapped[datetime | None] = mapped_column(
DateTime, default=naive_utcnow
)

@staticmethod
def localize_datetime(_datetime: datetime) -> datetime | None:
Expand Down
5 changes: 5 additions & 0 deletions app/model/schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
AccountCreateKeyRequest,
AccountGenerateRsaKeyRequest,
AccountResponse,
ChildAccountResponse,
CreateChildAccountResponse,
CreateUpdateChildAccountRequest,
ListAllChildAccountQuery,
ListAllChildAccountResponse,
)
from .batch_issue_redeem import (
BatchIssueRedeemUploadIdResponse,
Expand Down
73 changes: 64 additions & 9 deletions app/model/schema/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,40 @@
"""

from datetime import datetime
from typing import Optional
from typing import Annotated, Optional

from pydantic import BaseModel, Field, field_validator
from fastapi import Query
from pydantic import BaseModel, Field, RootModel, field_validator
from pydantic.dataclasses import dataclass

from app.model.db import AccountRsaStatus
from app.model.schema.base import ResultSet, SortOrder
from app.model.schema.personal_info import PersonalInfo, PersonalInfoInput
from app.utils.check_utils import check_value_is_encrypted
from config import E2EE_REQUEST_ENABLED


############################
# COMMON
############################
class Account(BaseModel):
"""Account schema"""

issuer_address: str
rsa_public_key: Optional[str] = Field(...)
rsa_status: AccountRsaStatus
is_deleted: bool


class ChildAccount(BaseModel):
"""Child account schema"""

issuer_address: str
child_account_index: int
child_account_address: str
personal_information: PersonalInfo | None


############################
# REQUEST
############################
Expand Down Expand Up @@ -106,18 +131,29 @@ class AccountAuthTokenRequest(BaseModel):
) # The maximum valid duration shall be 3 days.


class CreateUpdateChildAccountRequest(BaseModel):
"""Create or update a issuer's child account schema (REQUEST)"""

personal_information: PersonalInfoInput


@dataclass
class ListAllChildAccountQuery:
sort_order: Annotated[
SortOrder,
Query(description="The sort order of the child_account_index. 0:asc, 1:desc"),
] = SortOrder.ASC
offset: Annotated[Optional[int], Query(description="Start position", ge=0)] = None
limit: Annotated[Optional[int], Query(description="Number of set", ge=0)] = None


############################
# RESPONSE
############################


class AccountResponse(BaseModel):
class AccountResponse(RootModel[Account]):
"""Account schema (Response)"""

issuer_address: str
rsa_public_key: Optional[str] = Field(...)
rsa_status: AccountRsaStatus
is_deleted: bool
pass


class AccountAuthTokenResponse(BaseModel):
Expand All @@ -126,3 +162,22 @@ class AccountAuthTokenResponse(BaseModel):
auth_token: str
usage_start: datetime
valid_duration: int


class CreateChildAccountResponse(BaseModel):
"""Create a issuer's child account schema (RESPONSE)"""

child_account_index: int


class ListAllChildAccountResponse(BaseModel):
"""List all child accounts schema (RESPONSE)"""

result_set: ResultSet
child_accounts: list[ChildAccount]


class ChildAccountResponse(RootModel[ChildAccount]):
"""Child account schema (Response)"""

pass
Loading

0 comments on commit 9cd811c

Please sign in to comment.