diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 093d5a902..c4c2b98b3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index a6f6dfd06..784453355 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -25,7 +25,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 2bc5ee80f..704f902c7 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -6,13 +6,13 @@ jobs:
name: 'Build docker image'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- uses: ./.github/actions/setup-test-image
lint-ruff:
name: 'Lint check (ruff)'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- uses: astral-sh/ruff-action@v3
unit-test:
name: 'Unit tests'
@@ -27,7 +27,7 @@ jobs:
'tests/batch/',
]
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- uses: ./.github/actions/setup-test-image
- name: build image on compose
run: docker compose build
@@ -59,7 +59,7 @@ jobs:
packages: read
pull-requests: write
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- uses: ./.github/actions/setup-test-image
- name: build image on compose
run: docker compose build
@@ -67,7 +67,7 @@ jobs:
run: |
sudo chown runner:docker /home/runner/work/ibet-Wallet-API/ibet-Wallet-API/cov
sudo chmod 777 /home/runner/work/ibet-Wallet-API/ibet-Wallet-API/cov
- - uses: actions/download-artifact@v4
+ - uses: actions/download-artifact@v5
with:
pattern: '.coverage-*'
path: cov/
@@ -76,12 +76,12 @@ jobs:
run: docker compose run -w /app/ibet-Wallet-API/cov ibet-wallet-api-postgres bash --login -c 'uv run coverage combine .coverage-*'
- name: generate coverage xml file
run: docker compose run -w /app/ibet-Wallet-API ibet-wallet-api-postgres bash --login -c 'uv run coverage xml --data-file=cov/.coverage -o cov/coverage.xml'
- - uses: actions/download-artifact@v4
+ - uses: actions/download-artifact@v5
with:
pattern: 'pytest-*'
path: cov/
merge-multiple: true
- - uses: actions/setup-node@v4
+ - uses: actions/setup-node@v5
with:
node-version: 20
- name: Install junit-report-merger
@@ -90,7 +90,7 @@ jobs:
run: jrm cov/pytest.xml "cov/pytest-*.xml"
- name: Pytest coverage comment
id: coverageComment
- uses: MishaKav/pytest-coverage-comment@13d3c18e21895566c746187c9ea74736372e5e91 # v1.1.54
+ uses: MishaKav/pytest-coverage-comment@1bdbba85fb74a2fdc1ec66383acec1091610f82b # v1.1.57
with:
report-only-changed-files: true
pytest-xml-coverage-path: cov/coverage.xml
@@ -115,7 +115,7 @@ jobs:
matrix:
db: [postgres, mysql]
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- uses: ./.github/actions/setup-test-image
- name: run unit test using ${{ matrix.db }}
run: docker compose run ibet-wallet-api-${{ matrix.db }} bash --login -c "cd /app/ibet-Wallet-API && uv run pytest -vv --test-alembic -m 'alembic'"
diff --git a/README.md b/README.md
index b1dd2fd1d..74500addd 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
# ibet Wallet API
-
+
diff --git a/README_JA.md b/README_JA.md
index 9e8b12f98..ef4ff5e09 100644
--- a/README_JA.md
+++ b/README_JA.md
@@ -5,7 +5,7 @@
# ibet Wallet API
-
+
diff --git a/app/__init__.py b/app/__init__.py
index 37f369b24..f5ba527c7 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -17,4 +17,4 @@
SPDX-License-Identifier: Apache-2.0
"""
-__version__ = "25.6.0"
+__version__ = "25.9.0"
diff --git a/app/api/routers/eth.py b/app/api/routers/eth.py
index 8ba8dc70a..aa4dc3416 100644
--- a/app/api/routers/eth.py
+++ b/app/api/routers/eth.py
@@ -28,7 +28,7 @@
from rlp import decode
from sqlalchemy import select
from web3.exceptions import ContractLogicError, TimeExhausted, Web3RPCError
-from web3.types import TxReceipt
+from web3.types import BlockIdentifier, TxReceipt
from app import config, log
from app.contracts import AsyncContract
@@ -286,7 +286,7 @@ async def send_raw_transaction(
)
if tx["status"] == 0:
# inspect reason of transaction fail
- err_msg = await inspect_tx_failure(tx_hash)
+ err_msg = await inspect_tx_failure(tx_hash, tx["blockNumber"])
code, message = error_code_msg(err_msg)
result.append(
{
@@ -518,7 +518,7 @@ async def wait_for_transaction_receipt(
)
if tx["status"] == 0:
# Inspect reason of transaction fail.
- err_msg = await inspect_tx_failure(transaction_hash)
+ err_msg = await inspect_tx_failure(transaction_hash, tx["blockNumber"])
code, message = error_code_msg(err_msg)
result["status"] = 0
result["error_code"] = code
@@ -531,8 +531,8 @@ async def wait_for_transaction_receipt(
return json_response({**SuccessResponse.default(), "data": result})
-async def inspect_tx_failure(tx_hash: HexBytes) -> str:
- tx = await async_web3.eth.get_transaction(tx_hash)
+async def inspect_tx_failure(tx_hash: HexBytes, block_number: BlockIdentifier) -> str:
+ tx = await AsyncContract.get_transaction(tx_hash, block_number)
# build a new transaction to replay:
replay_tx = {
diff --git a/app/api/routers/notification.py b/app/api/routers/notification.py
index 345add283..72af79302 100644
--- a/app/api/routers/notification.py
+++ b/app/api/routers/notification.py
@@ -61,6 +61,7 @@ async def list_all_notifications(
"""
Returns notifications filtered by given query.
"""
+ notification_category = request_query.notification_category
address = request_query.address
notification_type = request_query.notification_type
priority = request_query.priority
@@ -75,6 +76,8 @@ async def list_all_notifications(
)
# Search Filter
+ if notification_category is not None:
+ stmt = stmt.where(Notification.notification_category == notification_category)
if address is not None:
stmt = stmt.where(Notification.address == to_checksum_address(address))
if notification_type is not None:
diff --git a/app/contracts/contract.py b/app/contracts/contract.py
index 3a3bfcbd7..d4613de60 100644
--- a/app/contracts/contract.py
+++ b/app/contracts/contract.py
@@ -18,13 +18,19 @@
"""
import json
-from typing import Type, TypeVar
+from typing import Any, Never, Type, TypeVar
from eth_utils import to_checksum_address
+from hexbytes import HexBytes
from web3 import contract
from web3.contract.async_contract import AsyncContractEvents
from web3.eth.async_eth import AsyncContract as Web3AsyncContract
-from web3.exceptions import BadFunctionCallOutput, ContractLogicError
+from web3.exceptions import (
+ BadFunctionCallOutput,
+ ContractLogicError,
+ TransactionNotFound,
+)
+from web3.types import BlockIdentifier, TxData
from app.utils.web3_utils import AsyncWeb3Wrapper
@@ -134,3 +140,25 @@ async def call_function(
raise exc
return result
+
+ @staticmethod
+ async def get_transaction(
+ transaction_hash: HexBytes, block_number: BlockIdentifier
+ ) -> TxData | dict[Any, Never]:
+ """Get transaction
+
+ :param transaction_hash: Transaction hash
+ :param block_number: Block number
+ :return: Return the transaction data or empty dict
+ """
+ tx = {}
+ try:
+ tx = await async_web3.eth.get_transaction(transaction_hash)
+ except TransactionNotFound:
+ # Retrieve transaction from block data when node has pruned old transaction
+ block = await async_web3.eth.get_block(block_number, full_transactions=True)
+ for transaction in block.get("transactions", []):
+ if transaction.get("hash") == transaction_hash:
+ tx = transaction
+ break
+ return tx
diff --git a/app/contracts/json/IbetSecurityTokenInterface.json b/app/contracts/json/IbetSecurityTokenInterface.json
index 0a993454a..7d607199e 100644
--- a/app/contracts/json/IbetSecurityTokenInterface.json
+++ b/app/contracts/json/IbetSecurityTokenInterface.json
@@ -182,6 +182,43 @@
"name": "ChangeTransferApprovalRequired",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "lockAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "beforeAccountAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "afterAccountAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "data",
+ "type": "string"
+ }
+ ],
+ "name": "ForceChangeLockedAccount",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -726,6 +763,39 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_lockAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_beforeAccountAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_afterAccountAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_value",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_data",
+ "type": "string"
+ }
+ ],
+ "name": "forceChangeLockedAccount",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
diff --git a/app/contracts/json/IbetShare.json b/app/contracts/json/IbetShare.json
index 5de4bdee5..38fe10266 100644
--- a/app/contracts/json/IbetShare.json
+++ b/app/contracts/json/IbetShare.json
@@ -264,6 +264,43 @@
"name": "ChangeTransferApprovalRequired",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "lockAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "beforeAccountAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "afterAccountAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "data",
+ "type": "string"
+ }
+ ],
+ "name": "ForceChangeLockedAccount",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -870,6 +907,39 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_lockAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_beforeAccountAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_afterAccountAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_value",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_data",
+ "type": "string"
+ }
+ ],
+ "name": "forceChangeLockedAccount",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1568,6 +1638,6 @@
"type": "function"
}
],
- "bytecode": "60806040523480156200001157600080fd5b5060405162003dc838038062003dc88339810160408190526200003491620001d7565b600080546001600160a01b031916331790556001620000548a8262000370565b50600262000063898262000370565b50600080546001600160a01b03191633179055600f879055601281905560038690556014859055601562000098858262000370565b506016620000a7848262000370565b506010620000b6838262000370565b50506013805460ff199081169091556007805490911660011790555050600354600080546001600160a01b031681526008602052604090205550506009805460ff60a01b1916600160a01b179055506200043c92505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200013757600080fd5b81516001600160401b03808211156200015457620001546200010f565b604051601f8301601f19908116603f011681019082821181831017156200017f576200017f6200010f565b81604052838152602092508660208588010111156200019d57600080fd5b600091505b83821015620001c15785820183015181830184015290820190620001a2565b6000602085830101528094505050505092915050565b60008060008060008060008060006101208a8c031215620001f757600080fd5b89516001600160401b03808211156200020f57600080fd5b6200021d8d838e0162000125565b9a5060208c01519150808211156200023457600080fd5b620002428d838e0162000125565b995060408c0151985060608c0151975060808c0151965060a08c01519150808211156200026e57600080fd5b6200027c8d838e0162000125565b955060c08c01519150808211156200029357600080fd5b620002a18d838e0162000125565b945060e08c0151915080821115620002b857600080fd5b50620002c78c828d0162000125565b9250506101008a015190509295985092959850929598565b600181811c90821680620002f457607f821691505b6020821081036200031557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200036b576000816000526020600020601f850160051c81016020861015620003465750805b601f850160051c820191505b81811015620003675782815560010162000352565b5050505b505050565b81516001600160401b038111156200038c576200038c6200010f565b620003a4816200039d8454620002df565b846200031b565b602080601f831160018114620003dc5760008415620003c35750858301515b600019600386901b1c1916600185901b17855562000367565b600085815260208120601f198616915b828110156200040d57888601518255948401946001909101908401620003ec565b50858210156200042c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61397c806200044c6000396000f3fe608060405234801561001057600080fd5b50600436106103a45760003560e01c806383850bcb116101e9578063c267ce5f1161010f578063e8050052116100ad578063fd0e85691161007c578063fd0e8569146107e3578063fd14a222146107f7578063fef1b9c01461080a578063ff12dcea1461084a57600080fd5b8063e80500521461079d578063edaab208146107b0578063f2fde38b146107bd578063f7502a7c146107d057600080fd5b8063cb761015116100e9578063cb76101514610739578063d93220581461074c578063db20266f1461075f578063e7464db11461078a57600080fd5b8063c267ce5f14610700578063c7109ec914610713578063ca5cbbb51461072657600080fd5b8063996f3a4b11610187578063b2a90a6011610156578063b2a90a60146106b3578063b967a52e146106c7578063b9b3e06a146106da578063bfe30fb0146106ed57600080fd5b8063996f3a4b146106675780639cd237071461067a5780639d8886c81461068d578063a9059cbb146106a057600080fd5b80638ed8a9bc116101c35780638ed8a9bc1461061657806392ff0d31146106295780639301a78b1461063d57806395d89b411461065f57600080fd5b806383850bcb146105f35780638da5cb5b146105fb5780638db9877c1461060e57600080fd5b806340615cf8116102ce5780635c40f6f41161026c57806376fa7a311161023b57806376fa7a31146105a45780637da68d34146105b75780637ed6d103146105c057806381ebdd79146105d357600080fd5b80635c40f6f41461055e5780635ccef3e7146105715780636f3b993f1461058457806370a082311461059157600080fd5b8063428630f6116102a8578063428630f61461052e57806358c3b870146105365780635b4733271461053e5780635c2c20051461055557600080fd5b806340615cf8146104f557806340d1c4411461050857806340eba90e1461051b57600080fd5b8063200d2ed21161034657806327e235e31161031557806327e235e3146104a75780632e027abe146104c757806331cef447146104da57806336f7ab5e146104ed57600080fd5b8063200d2ed21461046157806323b872dd1461046e57806325287d421461048157806325d608611461049457600080fd5b80630ed5a933116103825780630ed5a93314610407578063153a1f3e1461042457806318160ddd146104375780631935a8801461044e57600080fd5b806306eaa0b7146103a957806306fdde03146103be5780630af7eb0f146103dc575b600080fd5b6103bc6103b73660046130c4565b61085d565b005b6103c6610b27565b6040516103d39190613151565b60405180910390f35b6009546103ef906001600160a01b031681565b6040516001600160a01b0390911681526020016103d3565b6013546104149060ff1681565b60405190151581526020016103d3565b6104146104323660046131b0565b610bb5565b61044060035481565b6040519081526020016103d3565b6103bc61045c36600461322d565b610e1d565b6007546104149060ff1681565b61041461047c366004613266565b610eae565b6004546103ef906001600160a01b031681565b6103bc6104a23660046132a2565b611095565b6104406104b53660046132df565b60086020526000908152604090205481565b6103c66104d53660046132fa565b6110ef565b6103bc6104e83660046130c4565b611108565b6103c6611283565b6103bc61050336600461331d565b611290565b6103bc610516366004613347565b61132e565b6103bc6105293660046133af565b61145d565b6103c6611744565b6103c6611751565b61054661175e565b6040516103d393929190613406565b610440600f5481565b6103bc61056c36600461322d565b611883565b6103bc61057f3660046130c4565b611912565b600b546104149060ff1681565b61044061059f3660046132df565b611c94565b6103bc6105b23660046132df565b611caf565b61044060125481565b6103bc6105ce36600461343b565b611d1b565b6104406105e13660046132df565b600d6020526000908152604090205481565b6103bc611e38565b6000546103ef906001600160a01b031681565b6103c6611eba565b6103bc6106243660046132a2565b611ec7565b60095461041490600160a81b900460ff1681565b61065061064b3660046132df565b611f1d565b6040516103d3939291906134d5565b6103c6611f45565b6103bc6106753660046134fd565b611f52565b6103bc61068836600461322d565b611fff565b6103bc61069b36600461343b565b612067565b6104146106ae36600461331d565b61217b565b60095461041490600160b01b900460ff1681565b6103bc6106d53660046132a2565b612242565b6104406106e8366004613560565b612298565b6103bc6106fb366004613347565b6122c3565b6103bc61070e3660046133af565b61239e565b6103bc61072136600461322d565b61247b565b6103bc610734366004613593565b61250e565b6103bc61074736600461360c565b61265d565b6103bc61075a3660046132a2565b6126ac565b61044061076d366004613560565b600e60209081526000928352604080842090915290825290205481565b6103bc610798366004613266565b612702565b6104146107ab36600461343b565b6128d0565b6017546104149060ff1681565b6103bc6107cb3660046132df565b6129f4565b6103bc6107de3660046132df565b612ade565b60095461041490600160a01b900460ff1681565b6103bc61080536600461322d565b612b4a565b61081d61081836600461360c565b612bb2565b604080516001600160a01b03958616815294909316602085015291830152151560608201526080016103d3565b6103bc610858366004613266565b612bfb565b336001600160a01b0316600c838154811061087a5761087a613625565b60009182526020909120600490910201546001600160a01b0316148015906108ad57506000546001600160a01b03163314155b156108ef57604080518082018252600681526531313038303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b60405180910390fd5b600c828154811061090257610902613625565b6000918252602082206003600490920201015460ff16151590036109545760408051808201825260068152651898981c181960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b600c828154811061096757610967613625565b90600052602060002090600402016002015460086000600c858154811061099057610990613625565b600091825260208083206004909202909101546001600160a01b03168352820192909252604001812080549091906109c9908490613651565b9091555050600c8054839081106109e2576109e2613625565b906000526020600020906004020160020154600d6000600c8581548110610a0b57610a0b613625565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610a44908490613664565b925050819055506000600c8381548110610a6057610a60613625565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817fa0cc3a4feb26502e6e6cd57b2113d58bdab80c6711d8252356be9a49945bb5f7600c8481548110610abd57610abd613625565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110610aee57610aee613625565b6000918252602090912060016004909202010154604051610b1b92916001600160a01b0316908690613677565b60405180910390a25050565b60018054610b34906136a3565b80601f0160208091040260200160405190810160405280929190818152602001828054610b60906136a3565b8015610bad5780601f10610b8257610100808354040283529160200191610bad565b820191906000526020600020905b815481529060010190602001808311610b9057829003601f168201915b505050505081565b600b5460009060ff161515600103610bfb57604080518082018252600681526531313035303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b838214610c365760408051808201825260068152651898981a981960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b6000805b85811015610c7057848482818110610c5457610c54613625565b9050602002013582610c669190613651565b9150600101610c3a565b5080610c7b33611c94565b1015610cb557604080518082018252600681526531313035303360d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6004546001600160a01b03163314610d16576009546040805180820190915260068152650c4c4c0d4c0d60d21b602082015290600160a81b900460ff161515600114610d145760405162461bcd60e51b81526004016108e69190613151565b505b606060006001935060005b87811015610e1157610d59898983818110610d3e57610d3e613625565b9050602002016020810190610d5391906132df565b3b151590565b15610dae57610da7898983818110610d7357610d73613625565b9050602002016020810190610d8891906132df565b888884818110610d9a57610d9a613625565b9050602002013585612d23565b9150610dfa565b610df7898983818110610dc357610dc3613625565b9050602002016020810190610dd891906132df565b888884818110610dea57610dea613625565b9050602002013585612e3e565b91505b811515600003610e0957600094505b600101610d21565b50505050949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610e665760405162461bcd60e51b81526004016108e69190613151565b50600b805460ff19168215159081179091556040519081527fe1455bc53682229469d6919bb96d7b338cbffea93170dfb5f02242c22fb6d07f9060200160405180910390a150565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610ef85760405162461bcd60e51b81526004016108e69190613151565b5081610f0385611c94565b1015610f3d57604080518082018252600681526531313036303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6060833b1561100257610f5983610f5387611c94565b90613002565b6001600160a01b038616600090815260086020526040902055610f8583610f7f86611c94565b90613015565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a90610fca903390889087906004016136dd565b600060405180830381600087803b158015610fe457600080fd5b505af1158015610ff8573d6000803e3d6000fd5b505050505061104f565b61100f83610f5387611c94565b6001600160a01b03861660009081526008602052604090205561103583610f7f86611c94565b6001600160a01b0385166000908152600860205260409020555b836001600160a01b0316856001600160a01b03166000805160206139278339815191528560405161108291815260200190565b60405180910390a3506001949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146110de5760405162461bcd60e51b81526004016108e69190613151565b5060116110eb8282613755565b5050565b60186020526000908152604090208054610b34906136a3565b60095460408051808201909152600681526531313130303160d01b602082015290600160b01b900460ff1615156001146111555760405162461bcd60e51b81526004016108e69190613151565b50600954600160a01b900460ff1615156001036112245760095460005460405163d3da927f60e01b81523360048201526001600160a01b03918216602482015291169063d3da927f90604401602060405180830381865afa1580156111be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e29190613815565b60408051808201909152600681526518989898181960d11b60208201529015156001146112225760405162461bcd60e51b81526004016108e69190613151565b505b336000908152600a602052604090208281556002016112438282613755565b507f3bb9553f633a7ecb4cbc5f9885e750a522496ce06deff1ed9184180ca83940c0338383604051611277939291906136dd565b60405180910390a15050565b60058054610b34906136a3565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146112d95760405162461bcd60e51b81526004016108e69190613151565b506001600160a01b0382166000818152600a6020908152604091829020600101849055815192835282018390527fa42bd6bdfcb8f9b815c68e4ce0e16dec3f1e7ac53967ee8309653de522a735b19101611277565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146113775760405162461bcd60e51b81526004016108e69190613151565b508161138284611c94565b10156113bc57604080518082018252600681526531313136303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6113c982610f5385611c94565b6001600160a01b0384166000908152600860205260409020556113f082610f7f8686612298565b6001600160a01b038086166000818152600e6020908152604080832094891680845294909152908190209390935591517fd7bb89baba75d47cbd55a36bae224d3c630a8d3114860f86a30b484b2af516029061144f9086908690613832565b60405180910390a350505050565b600b5460ff1615806114795750600954600160a81b900460ff16155b8061148b57508161148933611c94565b105b156114c457604080518082018252600681526531313037303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6000546001600160a01b038481169116148015906114f05750600954600160a01b900460ff1615156001145b156115af5760095460005460405163d3da927f60e01b81526001600160a01b038681166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015611549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156d9190613815565b6040805180820190915260068152651898981b981960d11b60208201529015156001146115ad5760405162461bcd60e51b81526004016108e69190613151565b505b33600090815260086020526040812080548492906115ce908490613664565b9091555050336000908152600d6020526040812080548492906115f2908490613651565b9091555050600c805460408051608081018252338082526001600160a01b038881166020840190815283850189815260016060860181815290880189556000989098529351600487027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7810180549285166001600160a01b031993841617905591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8830180549190941691161790915591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c983015593517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca909101805491151560ff1990921691909117905551909182917fa256c3bc72c26fbfd6285cfde8c7e345b4d0c7ccfc725d103e9f129c5d8a039a916117369188908890889061384b565b60405180910390a250505050565b60068054610b34906136a3565b60118054610b34906136a3565b6014805460158054919291611772906136a3565b80601f016020809104026020016040519081016040528092919081815260200182805461179e906136a3565b80156117eb5780601f106117c0576101008083540402835291602001916117eb565b820191906000526020600020905b8154815290600101906020018083116117ce57829003601f168201915b505050505090806002018054611800906136a3565b80601f016020809104026020016040519081016040528092919081815260200182805461182c906136a3565b80156118795780601f1061184e57610100808354040283529160200191611879565b820191906000526020600020905b81548152906001019060200180831161185c57829003601f168201915b5050505050905083565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146118cc5760405162461bcd60e51b81526004016108e69190613151565b506007805460ff191682151590811790915560405160ff9091161515907fe1e5c6f5867805bf3fab73f4df4b80d0e87e9262a7bc22ac7c2cb3fd5896222f90600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461195b5760405162461bcd60e51b81526004016108e69190613151565b50600954600160a81b900460ff1615156000036119a657604080518082018252600681526531313039303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b600c82815481106119b9576119b9613625565b6000918252602082206003600490920201015460ff1615159003611a0b5760408051808201825260068152651898981c981960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b600c8281548110611a1e57611a1e613625565b90600052602060002090600402016002015460086000600c8581548110611a4757611a47613625565b60009182526020808320600160049093020191909101546001600160a01b0316835282019290925260400181208054909190611a84908490613651565b9091555050600c805483908110611a9d57611a9d613625565b906000526020600020906004020160020154600d6000600c8581548110611ac657611ac6613625565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190611aff908490613664565b925050819055506000600c8381548110611b1b57611b1b613625565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817f6b50d6e4941ce7ae74ed7f7f51df5fb7680754c2815a094c66bea5ca80a40eb1600c8481548110611b7857611b78613625565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110611ba957611ba9613625565b6000918252602090912060016004909202010154604051611bd692916001600160a01b0316908690613677565b60405180910390a2600c8281548110611bf157611bf1613625565b6000918252602090912060016004909202010154600c80546001600160a01b039092169184908110611c2557611c25613625565b6000918252602090912060049091020154600c80546001600160a01b0390921691600080516020613927833981519152919086908110611c6757611c67613625565b906000526020600020906004020160020154604051611c8891815260200190565b60405180910390a35050565b6001600160a01b031660009081526008602052604090205490565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611cf85760405162461bcd60e51b81526004016108e69190613151565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d645760405162461bcd60e51b81526004016108e69190613151565b508483141580611d745750848114155b15611dad57604080518082018252600681526531313134303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b60005b85811015611e2f57611e27878783818110611dcd57611dcd613625565b9050602002016020810190611de291906132df565b868684818110611df457611df4613625565b9050602002016020810190611e0991906132df565b858585818110611e1b57611e1b613625565b90506020020135612702565b600101611db0565b50505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e815760405162461bcd60e51b81526004016108e69190613151565b506013805460ff191660011790556040517f8298c3671093b19970d7c94ce1f23925a962f36fec31d25075d9be072b73e10390600090a1565b60108054610b34906136a3565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611f105760405162461bcd60e51b81526004016108e69190613151565b5060066110eb8282613755565b600a6020526000908152604090208054600182015460028301805492939192611800906136a3565b60028054610b34906136a3565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611f9b5760405162461bcd60e51b81526004016108e69190613151565b5060148390556015611fad8382613755565b506016611fba8282613755565b506014546040517ff89b6034f2b759ebb2dfb08461be917a1b54f2e0523c895e7f9b5e5e14dd013e91611ff2916015906016906138fb565b60405180910390a1505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120485760405162461bcd60e51b81526004016108e69190613151565b5060098054911515600160a81b0260ff60a81b19909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120b05760405162461bcd60e51b81526004016108e69190613151565b5084831415806120c05750848114155b156120f957604080518082018252600681526531313133303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b60005b85811015611e2f5761217387878381811061211957612119613625565b905060200201602081019061212e91906132df565b86868481811061214057612140613625565b905060200201602081019061215591906132df565b85858581811061216757612167613625565b90506020020135612bfb565b6001016120fc565b60008161218733611c94565b10156040518060400160405280600681526020016531313034303160d01b815250906121c65760405162461bcd60e51b81526004016108e69190613151565b506009546040805180820190915260068152651898981a181960d11b602082015290600160a81b900460ff1615156001146122145760405162461bcd60e51b81526004016108e69190613151565b506060833b1561223157612229848483612d23565b91505061223c565b612229848483612e3e565b92915050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461228b5760405162461bcd60e51b81526004016108e69190613151565b5060056110eb8282613755565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205490565b816122ce3386612298565b101561230857604080518082018252600681526518989818981960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b61231682610f533387612298565b336000908152600e602090815260408083206001600160a01b038916845290915290205561234782610f7f85611c94565b6001600160a01b038085166000908152600860205260409081902092909255905133918616907f7a1a1088c929a111dda2dc0ca1cc650aa78525d11fd3089abf20c8474f5d82cc9061144f908790879087906136dd565b816123a833611c94565b10156123e257604080518082018252600681526518989818181960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b6123ef82610f5333611c94565b33600081815260086020526040902091909155612413908390610f7f908690612298565b6001600160a01b0384166000818152600e602090815260408083203380855292529182902093909355519091907ecd77abc69e7bbb6de9df8cbfcca8720df3a30decf9eefd187e72ab2ea2f5139061246e9086908690613832565b60405180910390a3505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146124c45760405162461bcd60e51b81526004016108e69190613151565b506009805460ff60b01b1916600160b01b831515908102919091179091556040517fa0c691180b8089c0c84e478ee67d6325768666cd889f13de016771c6f7af1f8890600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146125575760405162461bcd60e51b81526004016108e69190613151565b50816125638686612298565b101561259d57604080518082018252600681526531313132303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6125ab82610f538787612298565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556125de82610f7f85611c94565b60086000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550846001600160a01b0316846001600160a01b03167f66b661491f3fe4e137b9e9cf90e142a93be21bc10e70c9b740379a245e4f7d2585858560405161264e939291906136dd565b60405180910390a35050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126a65760405162461bcd60e51b81526004016108e69190613151565b50601255565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126f55760405162461bcd60e51b81526004016108e69190613151565b5060106110eb8282613755565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461274b5760405162461bcd60e51b81526004016108e69190613151565b506001600160a01b038216156127e957806127668385612298565b10156127a057604080518082018252600681526531313131303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6127ae81610f538486612298565b6001600160a01b038084166000908152600e60209081526040808320938816835292905220556003546127e19082613002565b600355612874565b6001600160a01b03831660009081526008602052604090205481111561283d57604080518082018252600681526518989898981960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b61284a81610f5385611c94565b6001600160a01b0384166000908152600860205260409020556003546128709082613002565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167fee02732fab40ece8284c756220846dff4b8d32058b86b35b4f0459bf172fcef0846040516128c391815260200190565b60405180910390a4505050565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461291a5760405162461bcd60e51b81526004016108e69190613151565b50858414158061292a5750858214155b1561296357604080518082018252600681526531313135303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b60005b868110156129e6576129dd88888381811061298357612983613625565b905060200201602081019061299891906132df565b8787848181106129aa576129aa613625565b90506020020160208101906129bf91906132df565b8686858181106129d1576129d1613625565b90506020020135610eae565b50600101612966565b506001979650505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612a3d5760405162461bcd60e51b81526004016108e69190613151565b5060408051808201909152600681526535303031303160d01b60208201526001600160a01b038216612a825760405162461bcd60e51b81526004016108e69190613151565b50600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612b275760405162461bcd60e51b81526004016108e69190613151565b50600980546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612b935760405162461bcd60e51b81526004016108e69190613151565b5060098054911515600160a01b0260ff60a01b19909216919091179055565b600c8181548110612bc257600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509116919060ff1684565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c445760405162461bcd60e51b81526004016108e69190613151565b506001600160a01b03821615612c9d57612c6281610f7f8486612298565b6001600160a01b038084166000908152600e6020908152604080832093881683529290522055600354612c959082613015565b600355612cd4565b612caa81610f7f85611c94565b6001600160a01b038416600090815260086020526040902055600354612cd09082613015565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167f65adeb76912378393e600cb6f64f3310842a42e1eae86273dc775d0c47a0f2dc846040516128c391815260200190565b60045460408051808201909152600681526531313033303160d01b60208201526000916001600160a01b03868116911614612d715760405162461bcd60e51b81526004016108e69190613151565b50612d7f83610f5333611c94565b33600090815260086020526040902055612d9c83610f7f86611c94565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a90612de1903390889088906004016136dd565b600060405180830381600087803b158015612dfb57600080fd5b505af1158015612e0f573d6000803e3d6000fd5b50506040518681526001600160a01b038816925033915060008051602061392783398151915290602001611082565b6004546000906001600160a01b03163314801590612e635750600b5460ff1615156001145b15612e9c57604080518082018252600681526531313032303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6000546001600160a01b03858116911614801590612ec85750600954600160a01b900460ff1615156001145b15612f875760095460005460405163d3da927f60e01b81526001600160a01b038781166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015612f21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f459190613815565b60408051808201909152600681526518989819181960d11b6020820152901515600114612f855760405162461bcd60e51b81526004016108e69190613151565b505b612f9483610f5333611c94565b33600090815260086020526040902055612fb183610f7f86611c94565b6001600160a01b03851660008181526008602052604090819020929092559051339060008051602061392783398151915290612ff09087815260200190565b60405180910390a35060019392505050565b600061300e8284613664565b9392505050565b600061300e8284613651565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261304857600080fd5b813567ffffffffffffffff8082111561306357613063613021565b604051601f8301601f19908116603f0116810190828211818310171561308b5761308b613021565b816040528381528660208588010111156130a457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156130d757600080fd5b82359150602083013567ffffffffffffffff8111156130f557600080fd5b61310185828601613037565b9150509250929050565b6000815180845260005b8181101561313157602081850181015186830182015201613115565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061300e602083018461310b565b60008083601f84011261317657600080fd5b50813567ffffffffffffffff81111561318e57600080fd5b6020830191508360208260051b85010111156131a957600080fd5b9250929050565b600080600080604085870312156131c657600080fd5b843567ffffffffffffffff808211156131de57600080fd5b6131ea88838901613164565b9096509450602087013591508082111561320357600080fd5b5061321087828801613164565b95989497509550505050565b801515811461322a57600080fd5b50565b60006020828403121561323f57600080fd5b813561300e8161321c565b80356001600160a01b038116811461326157600080fd5b919050565b60008060006060848603121561327b57600080fd5b6132848461324a565b92506132926020850161324a565b9150604084013590509250925092565b6000602082840312156132b457600080fd5b813567ffffffffffffffff8111156132cb57600080fd5b6132d784828501613037565b949350505050565b6000602082840312156132f157600080fd5b61300e8261324a565b60006020828403121561330c57600080fd5b813560ff8116811461300e57600080fd5b6000806040838503121561333057600080fd5b6133398361324a565b946020939093013593505050565b6000806000806080858703121561335d57600080fd5b6133668561324a565b93506133746020860161324a565b925060408501359150606085013567ffffffffffffffff81111561339757600080fd5b6133a387828801613037565b91505092959194509250565b6000806000606084860312156133c457600080fd5b6133cd8461324a565b925060208401359150604084013567ffffffffffffffff8111156133f057600080fd5b6133fc86828701613037565b9150509250925092565b83815260606020820152600061341f606083018561310b565b8281036040840152613431818561310b565b9695505050505050565b6000806000806000806060878903121561345457600080fd5b863567ffffffffffffffff8082111561346c57600080fd5b6134788a838b01613164565b9098509650602089013591508082111561349157600080fd5b61349d8a838b01613164565b909650945060408901359150808211156134b657600080fd5b506134c389828a01613164565b979a9699509497509295939492505050565b8381528260208201526060604082015260006134f4606083018461310b565b95945050505050565b60008060006060848603121561351257600080fd5b83359250602084013567ffffffffffffffff8082111561353157600080fd5b61353d87838801613037565b9350604086013591508082111561355357600080fd5b506133fc86828701613037565b6000806040838503121561357357600080fd5b61357c8361324a565b915061358a6020840161324a565b90509250929050565b600080600080600060a086880312156135ab57600080fd5b6135b48661324a565b94506135c26020870161324a565b93506135d06040870161324a565b925060608601359150608086013567ffffffffffffffff8111156135f357600080fd5b6135ff88828901613037565b9150509295509295909350565b60006020828403121561361e57600080fd5b5035919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561223c5761223c61363b565b8181038181111561223c5761223c61363b565b6001600160a01b038481168252831660208201526060604082018190526000906134f49083018461310b565b600181811c908216806136b757607f821691505b6020821081036136d757634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b03841681528260208201526060604082015260006134f4606083018461310b565b601f821115613750576000816000526020600020601f850160051c8101602086101561372d5750805b601f850160051c820191505b8181101561374c57828155600101613739565b5050505b505050565b815167ffffffffffffffff81111561376f5761376f613021565b6137838161377d84546136a3565b84613704565b602080601f8311600181146137b857600084156137a05750858301515b600019600386901b1c1916600185901b17855561374c565b600085815260208120601f198616915b828110156137e7578886015182559484019460019091019084016137c8565b50858210156138055787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561382757600080fd5b815161300e8161321c565b8281526040602082015260006132d7604083018461310b565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906134319083018461310b565b6000815461388b816136a3565b8085526020600183811680156138a857600181146138c2576138f0565b60ff1985168884015283151560051b8801830195506138f0565b866000528260002060005b858110156138e85781548a82018601529083019084016138cd565b890184019650505b505050505092915050565b838152606060208201526000613914606083018561387e565b8281036040840152613431818561387e56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220a5f7cb0ed50855b43fe1e45d2da79117e308826e2ea2368e83f41ee188965ca864736f6c63430008170033",
- "deployedBytecode": "608060405234801561001057600080fd5b50600436106103a45760003560e01c806383850bcb116101e9578063c267ce5f1161010f578063e8050052116100ad578063fd0e85691161007c578063fd0e8569146107e3578063fd14a222146107f7578063fef1b9c01461080a578063ff12dcea1461084a57600080fd5b8063e80500521461079d578063edaab208146107b0578063f2fde38b146107bd578063f7502a7c146107d057600080fd5b8063cb761015116100e9578063cb76101514610739578063d93220581461074c578063db20266f1461075f578063e7464db11461078a57600080fd5b8063c267ce5f14610700578063c7109ec914610713578063ca5cbbb51461072657600080fd5b8063996f3a4b11610187578063b2a90a6011610156578063b2a90a60146106b3578063b967a52e146106c7578063b9b3e06a146106da578063bfe30fb0146106ed57600080fd5b8063996f3a4b146106675780639cd237071461067a5780639d8886c81461068d578063a9059cbb146106a057600080fd5b80638ed8a9bc116101c35780638ed8a9bc1461061657806392ff0d31146106295780639301a78b1461063d57806395d89b411461065f57600080fd5b806383850bcb146105f35780638da5cb5b146105fb5780638db9877c1461060e57600080fd5b806340615cf8116102ce5780635c40f6f41161026c57806376fa7a311161023b57806376fa7a31146105a45780637da68d34146105b75780637ed6d103146105c057806381ebdd79146105d357600080fd5b80635c40f6f41461055e5780635ccef3e7146105715780636f3b993f1461058457806370a082311461059157600080fd5b8063428630f6116102a8578063428630f61461052e57806358c3b870146105365780635b4733271461053e5780635c2c20051461055557600080fd5b806340615cf8146104f557806340d1c4411461050857806340eba90e1461051b57600080fd5b8063200d2ed21161034657806327e235e31161031557806327e235e3146104a75780632e027abe146104c757806331cef447146104da57806336f7ab5e146104ed57600080fd5b8063200d2ed21461046157806323b872dd1461046e57806325287d421461048157806325d608611461049457600080fd5b80630ed5a933116103825780630ed5a93314610407578063153a1f3e1461042457806318160ddd146104375780631935a8801461044e57600080fd5b806306eaa0b7146103a957806306fdde03146103be5780630af7eb0f146103dc575b600080fd5b6103bc6103b73660046130c4565b61085d565b005b6103c6610b27565b6040516103d39190613151565b60405180910390f35b6009546103ef906001600160a01b031681565b6040516001600160a01b0390911681526020016103d3565b6013546104149060ff1681565b60405190151581526020016103d3565b6104146104323660046131b0565b610bb5565b61044060035481565b6040519081526020016103d3565b6103bc61045c36600461322d565b610e1d565b6007546104149060ff1681565b61041461047c366004613266565b610eae565b6004546103ef906001600160a01b031681565b6103bc6104a23660046132a2565b611095565b6104406104b53660046132df565b60086020526000908152604090205481565b6103c66104d53660046132fa565b6110ef565b6103bc6104e83660046130c4565b611108565b6103c6611283565b6103bc61050336600461331d565b611290565b6103bc610516366004613347565b61132e565b6103bc6105293660046133af565b61145d565b6103c6611744565b6103c6611751565b61054661175e565b6040516103d393929190613406565b610440600f5481565b6103bc61056c36600461322d565b611883565b6103bc61057f3660046130c4565b611912565b600b546104149060ff1681565b61044061059f3660046132df565b611c94565b6103bc6105b23660046132df565b611caf565b61044060125481565b6103bc6105ce36600461343b565b611d1b565b6104406105e13660046132df565b600d6020526000908152604090205481565b6103bc611e38565b6000546103ef906001600160a01b031681565b6103c6611eba565b6103bc6106243660046132a2565b611ec7565b60095461041490600160a81b900460ff1681565b61065061064b3660046132df565b611f1d565b6040516103d3939291906134d5565b6103c6611f45565b6103bc6106753660046134fd565b611f52565b6103bc61068836600461322d565b611fff565b6103bc61069b36600461343b565b612067565b6104146106ae36600461331d565b61217b565b60095461041490600160b01b900460ff1681565b6103bc6106d53660046132a2565b612242565b6104406106e8366004613560565b612298565b6103bc6106fb366004613347565b6122c3565b6103bc61070e3660046133af565b61239e565b6103bc61072136600461322d565b61247b565b6103bc610734366004613593565b61250e565b6103bc61074736600461360c565b61265d565b6103bc61075a3660046132a2565b6126ac565b61044061076d366004613560565b600e60209081526000928352604080842090915290825290205481565b6103bc610798366004613266565b612702565b6104146107ab36600461343b565b6128d0565b6017546104149060ff1681565b6103bc6107cb3660046132df565b6129f4565b6103bc6107de3660046132df565b612ade565b60095461041490600160a01b900460ff1681565b6103bc61080536600461322d565b612b4a565b61081d61081836600461360c565b612bb2565b604080516001600160a01b03958616815294909316602085015291830152151560608201526080016103d3565b6103bc610858366004613266565b612bfb565b336001600160a01b0316600c838154811061087a5761087a613625565b60009182526020909120600490910201546001600160a01b0316148015906108ad57506000546001600160a01b03163314155b156108ef57604080518082018252600681526531313038303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b60405180910390fd5b600c828154811061090257610902613625565b6000918252602082206003600490920201015460ff16151590036109545760408051808201825260068152651898981c181960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b600c828154811061096757610967613625565b90600052602060002090600402016002015460086000600c858154811061099057610990613625565b600091825260208083206004909202909101546001600160a01b03168352820192909252604001812080549091906109c9908490613651565b9091555050600c8054839081106109e2576109e2613625565b906000526020600020906004020160020154600d6000600c8581548110610a0b57610a0b613625565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610a44908490613664565b925050819055506000600c8381548110610a6057610a60613625565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817fa0cc3a4feb26502e6e6cd57b2113d58bdab80c6711d8252356be9a49945bb5f7600c8481548110610abd57610abd613625565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110610aee57610aee613625565b6000918252602090912060016004909202010154604051610b1b92916001600160a01b0316908690613677565b60405180910390a25050565b60018054610b34906136a3565b80601f0160208091040260200160405190810160405280929190818152602001828054610b60906136a3565b8015610bad5780601f10610b8257610100808354040283529160200191610bad565b820191906000526020600020905b815481529060010190602001808311610b9057829003601f168201915b505050505081565b600b5460009060ff161515600103610bfb57604080518082018252600681526531313035303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b838214610c365760408051808201825260068152651898981a981960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b6000805b85811015610c7057848482818110610c5457610c54613625565b9050602002013582610c669190613651565b9150600101610c3a565b5080610c7b33611c94565b1015610cb557604080518082018252600681526531313035303360d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6004546001600160a01b03163314610d16576009546040805180820190915260068152650c4c4c0d4c0d60d21b602082015290600160a81b900460ff161515600114610d145760405162461bcd60e51b81526004016108e69190613151565b505b606060006001935060005b87811015610e1157610d59898983818110610d3e57610d3e613625565b9050602002016020810190610d5391906132df565b3b151590565b15610dae57610da7898983818110610d7357610d73613625565b9050602002016020810190610d8891906132df565b888884818110610d9a57610d9a613625565b9050602002013585612d23565b9150610dfa565b610df7898983818110610dc357610dc3613625565b9050602002016020810190610dd891906132df565b888884818110610dea57610dea613625565b9050602002013585612e3e565b91505b811515600003610e0957600094505b600101610d21565b50505050949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610e665760405162461bcd60e51b81526004016108e69190613151565b50600b805460ff19168215159081179091556040519081527fe1455bc53682229469d6919bb96d7b338cbffea93170dfb5f02242c22fb6d07f9060200160405180910390a150565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610ef85760405162461bcd60e51b81526004016108e69190613151565b5081610f0385611c94565b1015610f3d57604080518082018252600681526531313036303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6060833b1561100257610f5983610f5387611c94565b90613002565b6001600160a01b038616600090815260086020526040902055610f8583610f7f86611c94565b90613015565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a90610fca903390889087906004016136dd565b600060405180830381600087803b158015610fe457600080fd5b505af1158015610ff8573d6000803e3d6000fd5b505050505061104f565b61100f83610f5387611c94565b6001600160a01b03861660009081526008602052604090205561103583610f7f86611c94565b6001600160a01b0385166000908152600860205260409020555b836001600160a01b0316856001600160a01b03166000805160206139278339815191528560405161108291815260200190565b60405180910390a3506001949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146110de5760405162461bcd60e51b81526004016108e69190613151565b5060116110eb8282613755565b5050565b60186020526000908152604090208054610b34906136a3565b60095460408051808201909152600681526531313130303160d01b602082015290600160b01b900460ff1615156001146111555760405162461bcd60e51b81526004016108e69190613151565b50600954600160a01b900460ff1615156001036112245760095460005460405163d3da927f60e01b81523360048201526001600160a01b03918216602482015291169063d3da927f90604401602060405180830381865afa1580156111be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e29190613815565b60408051808201909152600681526518989898181960d11b60208201529015156001146112225760405162461bcd60e51b81526004016108e69190613151565b505b336000908152600a602052604090208281556002016112438282613755565b507f3bb9553f633a7ecb4cbc5f9885e750a522496ce06deff1ed9184180ca83940c0338383604051611277939291906136dd565b60405180910390a15050565b60058054610b34906136a3565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146112d95760405162461bcd60e51b81526004016108e69190613151565b506001600160a01b0382166000818152600a6020908152604091829020600101849055815192835282018390527fa42bd6bdfcb8f9b815c68e4ce0e16dec3f1e7ac53967ee8309653de522a735b19101611277565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146113775760405162461bcd60e51b81526004016108e69190613151565b508161138284611c94565b10156113bc57604080518082018252600681526531313136303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6113c982610f5385611c94565b6001600160a01b0384166000908152600860205260409020556113f082610f7f8686612298565b6001600160a01b038086166000818152600e6020908152604080832094891680845294909152908190209390935591517fd7bb89baba75d47cbd55a36bae224d3c630a8d3114860f86a30b484b2af516029061144f9086908690613832565b60405180910390a350505050565b600b5460ff1615806114795750600954600160a81b900460ff16155b8061148b57508161148933611c94565b105b156114c457604080518082018252600681526531313037303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6000546001600160a01b038481169116148015906114f05750600954600160a01b900460ff1615156001145b156115af5760095460005460405163d3da927f60e01b81526001600160a01b038681166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015611549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156d9190613815565b6040805180820190915260068152651898981b981960d11b60208201529015156001146115ad5760405162461bcd60e51b81526004016108e69190613151565b505b33600090815260086020526040812080548492906115ce908490613664565b9091555050336000908152600d6020526040812080548492906115f2908490613651565b9091555050600c805460408051608081018252338082526001600160a01b038881166020840190815283850189815260016060860181815290880189556000989098529351600487027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7810180549285166001600160a01b031993841617905591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8830180549190941691161790915591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c983015593517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca909101805491151560ff1990921691909117905551909182917fa256c3bc72c26fbfd6285cfde8c7e345b4d0c7ccfc725d103e9f129c5d8a039a916117369188908890889061384b565b60405180910390a250505050565b60068054610b34906136a3565b60118054610b34906136a3565b6014805460158054919291611772906136a3565b80601f016020809104026020016040519081016040528092919081815260200182805461179e906136a3565b80156117eb5780601f106117c0576101008083540402835291602001916117eb565b820191906000526020600020905b8154815290600101906020018083116117ce57829003601f168201915b505050505090806002018054611800906136a3565b80601f016020809104026020016040519081016040528092919081815260200182805461182c906136a3565b80156118795780601f1061184e57610100808354040283529160200191611879565b820191906000526020600020905b81548152906001019060200180831161185c57829003601f168201915b5050505050905083565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146118cc5760405162461bcd60e51b81526004016108e69190613151565b506007805460ff191682151590811790915560405160ff9091161515907fe1e5c6f5867805bf3fab73f4df4b80d0e87e9262a7bc22ac7c2cb3fd5896222f90600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461195b5760405162461bcd60e51b81526004016108e69190613151565b50600954600160a81b900460ff1615156000036119a657604080518082018252600681526531313039303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b600c82815481106119b9576119b9613625565b6000918252602082206003600490920201015460ff1615159003611a0b5760408051808201825260068152651898981c981960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b600c8281548110611a1e57611a1e613625565b90600052602060002090600402016002015460086000600c8581548110611a4757611a47613625565b60009182526020808320600160049093020191909101546001600160a01b0316835282019290925260400181208054909190611a84908490613651565b9091555050600c805483908110611a9d57611a9d613625565b906000526020600020906004020160020154600d6000600c8581548110611ac657611ac6613625565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190611aff908490613664565b925050819055506000600c8381548110611b1b57611b1b613625565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817f6b50d6e4941ce7ae74ed7f7f51df5fb7680754c2815a094c66bea5ca80a40eb1600c8481548110611b7857611b78613625565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110611ba957611ba9613625565b6000918252602090912060016004909202010154604051611bd692916001600160a01b0316908690613677565b60405180910390a2600c8281548110611bf157611bf1613625565b6000918252602090912060016004909202010154600c80546001600160a01b039092169184908110611c2557611c25613625565b6000918252602090912060049091020154600c80546001600160a01b0390921691600080516020613927833981519152919086908110611c6757611c67613625565b906000526020600020906004020160020154604051611c8891815260200190565b60405180910390a35050565b6001600160a01b031660009081526008602052604090205490565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611cf85760405162461bcd60e51b81526004016108e69190613151565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d645760405162461bcd60e51b81526004016108e69190613151565b508483141580611d745750848114155b15611dad57604080518082018252600681526531313134303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b60005b85811015611e2f57611e27878783818110611dcd57611dcd613625565b9050602002016020810190611de291906132df565b868684818110611df457611df4613625565b9050602002016020810190611e0991906132df565b858585818110611e1b57611e1b613625565b90506020020135612702565b600101611db0565b50505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e815760405162461bcd60e51b81526004016108e69190613151565b506013805460ff191660011790556040517f8298c3671093b19970d7c94ce1f23925a962f36fec31d25075d9be072b73e10390600090a1565b60108054610b34906136a3565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611f105760405162461bcd60e51b81526004016108e69190613151565b5060066110eb8282613755565b600a6020526000908152604090208054600182015460028301805492939192611800906136a3565b60028054610b34906136a3565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611f9b5760405162461bcd60e51b81526004016108e69190613151565b5060148390556015611fad8382613755565b506016611fba8282613755565b506014546040517ff89b6034f2b759ebb2dfb08461be917a1b54f2e0523c895e7f9b5e5e14dd013e91611ff2916015906016906138fb565b60405180910390a1505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120485760405162461bcd60e51b81526004016108e69190613151565b5060098054911515600160a81b0260ff60a81b19909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120b05760405162461bcd60e51b81526004016108e69190613151565b5084831415806120c05750848114155b156120f957604080518082018252600681526531313133303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b60005b85811015611e2f5761217387878381811061211957612119613625565b905060200201602081019061212e91906132df565b86868481811061214057612140613625565b905060200201602081019061215591906132df565b85858581811061216757612167613625565b90506020020135612bfb565b6001016120fc565b60008161218733611c94565b10156040518060400160405280600681526020016531313034303160d01b815250906121c65760405162461bcd60e51b81526004016108e69190613151565b506009546040805180820190915260068152651898981a181960d11b602082015290600160a81b900460ff1615156001146122145760405162461bcd60e51b81526004016108e69190613151565b506060833b1561223157612229848483612d23565b91505061223c565b612229848483612e3e565b92915050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461228b5760405162461bcd60e51b81526004016108e69190613151565b5060056110eb8282613755565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205490565b816122ce3386612298565b101561230857604080518082018252600681526518989818981960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b61231682610f533387612298565b336000908152600e602090815260408083206001600160a01b038916845290915290205561234782610f7f85611c94565b6001600160a01b038085166000908152600860205260409081902092909255905133918616907f7a1a1088c929a111dda2dc0ca1cc650aa78525d11fd3089abf20c8474f5d82cc9061144f908790879087906136dd565b816123a833611c94565b10156123e257604080518082018252600681526518989818181960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b6123ef82610f5333611c94565b33600081815260086020526040902091909155612413908390610f7f908690612298565b6001600160a01b0384166000818152600e602090815260408083203380855292529182902093909355519091907ecd77abc69e7bbb6de9df8cbfcca8720df3a30decf9eefd187e72ab2ea2f5139061246e9086908690613832565b60405180910390a3505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146124c45760405162461bcd60e51b81526004016108e69190613151565b506009805460ff60b01b1916600160b01b831515908102919091179091556040517fa0c691180b8089c0c84e478ee67d6325768666cd889f13de016771c6f7af1f8890600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146125575760405162461bcd60e51b81526004016108e69190613151565b50816125638686612298565b101561259d57604080518082018252600681526531313132303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6125ab82610f538787612298565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556125de82610f7f85611c94565b60086000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550846001600160a01b0316846001600160a01b03167f66b661491f3fe4e137b9e9cf90e142a93be21bc10e70c9b740379a245e4f7d2585858560405161264e939291906136dd565b60405180910390a35050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126a65760405162461bcd60e51b81526004016108e69190613151565b50601255565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126f55760405162461bcd60e51b81526004016108e69190613151565b5060106110eb8282613755565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461274b5760405162461bcd60e51b81526004016108e69190613151565b506001600160a01b038216156127e957806127668385612298565b10156127a057604080518082018252600681526531313131303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6127ae81610f538486612298565b6001600160a01b038084166000908152600e60209081526040808320938816835292905220556003546127e19082613002565b600355612874565b6001600160a01b03831660009081526008602052604090205481111561283d57604080518082018252600681526518989898981960d11b6020820152905162461bcd60e51b81526108e69190600401613151565b61284a81610f5385611c94565b6001600160a01b0384166000908152600860205260409020556003546128709082613002565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167fee02732fab40ece8284c756220846dff4b8d32058b86b35b4f0459bf172fcef0846040516128c391815260200190565b60405180910390a4505050565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461291a5760405162461bcd60e51b81526004016108e69190613151565b50858414158061292a5750858214155b1561296357604080518082018252600681526531313135303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b60005b868110156129e6576129dd88888381811061298357612983613625565b905060200201602081019061299891906132df565b8787848181106129aa576129aa613625565b90506020020160208101906129bf91906132df565b8686858181106129d1576129d1613625565b90506020020135610eae565b50600101612966565b506001979650505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612a3d5760405162461bcd60e51b81526004016108e69190613151565b5060408051808201909152600681526535303031303160d01b60208201526001600160a01b038216612a825760405162461bcd60e51b81526004016108e69190613151565b50600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612b275760405162461bcd60e51b81526004016108e69190613151565b50600980546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612b935760405162461bcd60e51b81526004016108e69190613151565b5060098054911515600160a01b0260ff60a01b19909216919091179055565b600c8181548110612bc257600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509116919060ff1684565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c445760405162461bcd60e51b81526004016108e69190613151565b506001600160a01b03821615612c9d57612c6281610f7f8486612298565b6001600160a01b038084166000908152600e6020908152604080832093881683529290522055600354612c959082613015565b600355612cd4565b612caa81610f7f85611c94565b6001600160a01b038416600090815260086020526040902055600354612cd09082613015565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167f65adeb76912378393e600cb6f64f3310842a42e1eae86273dc775d0c47a0f2dc846040516128c391815260200190565b60045460408051808201909152600681526531313033303160d01b60208201526000916001600160a01b03868116911614612d715760405162461bcd60e51b81526004016108e69190613151565b50612d7f83610f5333611c94565b33600090815260086020526040902055612d9c83610f7f86611c94565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a90612de1903390889088906004016136dd565b600060405180830381600087803b158015612dfb57600080fd5b505af1158015612e0f573d6000803e3d6000fd5b50506040518681526001600160a01b038816925033915060008051602061392783398151915290602001611082565b6004546000906001600160a01b03163314801590612e635750600b5460ff1615156001145b15612e9c57604080518082018252600681526531313032303160d01b6020820152905162461bcd60e51b81526108e69190600401613151565b6000546001600160a01b03858116911614801590612ec85750600954600160a01b900460ff1615156001145b15612f875760095460005460405163d3da927f60e01b81526001600160a01b038781166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015612f21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f459190613815565b60408051808201909152600681526518989819181960d11b6020820152901515600114612f855760405162461bcd60e51b81526004016108e69190613151565b505b612f9483610f5333611c94565b33600090815260086020526040902055612fb183610f7f86611c94565b6001600160a01b03851660008181526008602052604090819020929092559051339060008051602061392783398151915290612ff09087815260200190565b60405180910390a35060019392505050565b600061300e8284613664565b9392505050565b600061300e8284613651565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261304857600080fd5b813567ffffffffffffffff8082111561306357613063613021565b604051601f8301601f19908116603f0116810190828211818310171561308b5761308b613021565b816040528381528660208588010111156130a457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156130d757600080fd5b82359150602083013567ffffffffffffffff8111156130f557600080fd5b61310185828601613037565b9150509250929050565b6000815180845260005b8181101561313157602081850181015186830182015201613115565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061300e602083018461310b565b60008083601f84011261317657600080fd5b50813567ffffffffffffffff81111561318e57600080fd5b6020830191508360208260051b85010111156131a957600080fd5b9250929050565b600080600080604085870312156131c657600080fd5b843567ffffffffffffffff808211156131de57600080fd5b6131ea88838901613164565b9096509450602087013591508082111561320357600080fd5b5061321087828801613164565b95989497509550505050565b801515811461322a57600080fd5b50565b60006020828403121561323f57600080fd5b813561300e8161321c565b80356001600160a01b038116811461326157600080fd5b919050565b60008060006060848603121561327b57600080fd5b6132848461324a565b92506132926020850161324a565b9150604084013590509250925092565b6000602082840312156132b457600080fd5b813567ffffffffffffffff8111156132cb57600080fd5b6132d784828501613037565b949350505050565b6000602082840312156132f157600080fd5b61300e8261324a565b60006020828403121561330c57600080fd5b813560ff8116811461300e57600080fd5b6000806040838503121561333057600080fd5b6133398361324a565b946020939093013593505050565b6000806000806080858703121561335d57600080fd5b6133668561324a565b93506133746020860161324a565b925060408501359150606085013567ffffffffffffffff81111561339757600080fd5b6133a387828801613037565b91505092959194509250565b6000806000606084860312156133c457600080fd5b6133cd8461324a565b925060208401359150604084013567ffffffffffffffff8111156133f057600080fd5b6133fc86828701613037565b9150509250925092565b83815260606020820152600061341f606083018561310b565b8281036040840152613431818561310b565b9695505050505050565b6000806000806000806060878903121561345457600080fd5b863567ffffffffffffffff8082111561346c57600080fd5b6134788a838b01613164565b9098509650602089013591508082111561349157600080fd5b61349d8a838b01613164565b909650945060408901359150808211156134b657600080fd5b506134c389828a01613164565b979a9699509497509295939492505050565b8381528260208201526060604082015260006134f4606083018461310b565b95945050505050565b60008060006060848603121561351257600080fd5b83359250602084013567ffffffffffffffff8082111561353157600080fd5b61353d87838801613037565b9350604086013591508082111561355357600080fd5b506133fc86828701613037565b6000806040838503121561357357600080fd5b61357c8361324a565b915061358a6020840161324a565b90509250929050565b600080600080600060a086880312156135ab57600080fd5b6135b48661324a565b94506135c26020870161324a565b93506135d06040870161324a565b925060608601359150608086013567ffffffffffffffff8111156135f357600080fd5b6135ff88828901613037565b9150509295509295909350565b60006020828403121561361e57600080fd5b5035919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561223c5761223c61363b565b8181038181111561223c5761223c61363b565b6001600160a01b038481168252831660208201526060604082018190526000906134f49083018461310b565b600181811c908216806136b757607f821691505b6020821081036136d757634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b03841681528260208201526060604082015260006134f4606083018461310b565b601f821115613750576000816000526020600020601f850160051c8101602086101561372d5750805b601f850160051c820191505b8181101561374c57828155600101613739565b5050505b505050565b815167ffffffffffffffff81111561376f5761376f613021565b6137838161377d84546136a3565b84613704565b602080601f8311600181146137b857600084156137a05750858301515b600019600386901b1c1916600185901b17855561374c565b600085815260208120601f198616915b828110156137e7578886015182559484019460019091019084016137c8565b50858210156138055787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561382757600080fd5b815161300e8161321c565b8281526040602082015260006132d7604083018461310b565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906134319083018461310b565b6000815461388b816136a3565b8085526020600183811680156138a857600181146138c2576138f0565b60ff1985168884015283151560051b8801830195506138f0565b866000528260002060005b858110156138e85781548a82018601529083019084016138cd565b890184019650505b505050505092915050565b838152606060208201526000613914606083018561387e565b8281036040840152613431818561387e56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220a5f7cb0ed50855b43fe1e45d2da79117e308826e2ea2368e83f41ee188965ca864736f6c63430008170033"
+ "bytecode": "60806040523480156200001157600080fd5b5060405162003f2638038062003f268339810160408190526200003491620001d7565b600080546001600160a01b031916331790556001620000548a8262000370565b50600262000063898262000370565b50600080546001600160a01b03191633179055600f879055601281905560038690556014859055601562000098858262000370565b506016620000a7848262000370565b506010620000b6838262000370565b50506013805460ff199081169091556007805490911660011790555050600354600080546001600160a01b031681526008602052604090205550506009805460ff60a01b1916600160a01b179055506200043c92505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200013757600080fd5b81516001600160401b03808211156200015457620001546200010f565b604051601f8301601f19908116603f011681019082821181831017156200017f576200017f6200010f565b81604052838152602092508660208588010111156200019d57600080fd5b600091505b83821015620001c15785820183015181830184015290820190620001a2565b6000602085830101528094505050505092915050565b60008060008060008060008060006101208a8c031215620001f757600080fd5b89516001600160401b03808211156200020f57600080fd5b6200021d8d838e0162000125565b9a5060208c01519150808211156200023457600080fd5b620002428d838e0162000125565b995060408c0151985060608c0151975060808c0151965060a08c01519150808211156200026e57600080fd5b6200027c8d838e0162000125565b955060c08c01519150808211156200029357600080fd5b620002a18d838e0162000125565b945060e08c0151915080821115620002b857600080fd5b50620002c78c828d0162000125565b9250506101008a015190509295985092959850929598565b600181811c90821680620002f457607f821691505b6020821081036200031557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200036b576000816000526020600020601f850160051c81016020861015620003465750805b601f850160051c820191505b81811015620003675782815560010162000352565b5050505b505050565b81516001600160401b038111156200038c576200038c6200010f565b620003a4816200039d8454620002df565b846200031b565b602080601f831160018114620003dc5760008415620003c35750858301515b600019600386901b1c1916600185901b17855562000367565b600085815260208120601f198616915b828110156200040d57888601518255948401946001909101908401620003ec565b50858210156200042c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613ada806200044c6000396000f3fe608060405234801561001057600080fd5b50600436106103af5760003560e01c806383850bcb116101f4578063c267ce5f1161011a578063e8050052116100ad578063fd0e85691161007c578063fd0e856914610801578063fd14a22214610815578063fef1b9c014610828578063ff12dcea1461086857600080fd5b8063e8050052146107bb578063edaab208146107ce578063f2fde38b146107db578063f7502a7c146107ee57600080fd5b8063d87f0986116100e9578063d87f098614610757578063d93220581461076a578063db20266f1461077d578063e7464db1146107a857600080fd5b8063c267ce5f1461070b578063c7109ec91461071e578063ca5cbbb514610731578063cb7610151461074457600080fd5b8063996f3a4b11610192578063b2a90a6011610161578063b2a90a60146106be578063b967a52e146106d2578063b9b3e06a146106e5578063bfe30fb0146106f857600080fd5b8063996f3a4b146106725780639cd23707146106855780639d8886c814610698578063a9059cbb146106ab57600080fd5b80638ed8a9bc116101ce5780638ed8a9bc1461062157806392ff0d31146106345780639301a78b1461064857806395d89b411461066a57600080fd5b806383850bcb146105fe5780638da5cb5b146106065780638db9877c1461061957600080fd5b806340615cf8116102d95780635c40f6f41161027757806376fa7a311161024657806376fa7a31146105af5780637da68d34146105c25780637ed6d103146105cb57806381ebdd79146105de57600080fd5b80635c40f6f4146105695780635ccef3e71461057c5780636f3b993f1461058f57806370a082311461059c57600080fd5b8063428630f6116102b3578063428630f61461053957806358c3b870146105415780635b473327146105495780635c2c20051461056057600080fd5b806340615cf81461050057806340d1c4411461051357806340eba90e1461052657600080fd5b8063200d2ed21161035157806327e235e31161032057806327e235e3146104b25780632e027abe146104d257806331cef447146104e557806336f7ab5e146104f857600080fd5b8063200d2ed21461046c57806323b872dd1461047957806325287d421461048c57806325d608611461049f57600080fd5b80630ed5a9331161038d5780630ed5a93314610412578063153a1f3e1461042f57806318160ddd146104425780631935a8801461045957600080fd5b806306eaa0b7146103b457806306fdde03146103c95780630af7eb0f146103e7575b600080fd5b6103c76103c2366004613222565b61087b565b005b6103d1610b45565b6040516103de91906132af565b60405180910390f35b6009546103fa906001600160a01b031681565b6040516001600160a01b0390911681526020016103de565b60135461041f9060ff1681565b60405190151581526020016103de565b61041f61043d36600461330e565b610bd3565b61044b60035481565b6040519081526020016103de565b6103c761046736600461338b565b610e3b565b60075461041f9060ff1681565b61041f6104873660046133c4565b610ecc565b6004546103fa906001600160a01b031681565b6103c76104ad366004613400565b6110b3565b61044b6104c036600461343d565b60086020526000908152604090205481565b6103d16104e0366004613458565b61110d565b6103c76104f3366004613222565b611126565b6103d16112a1565b6103c761050e36600461347b565b6112ae565b6103c76105213660046134a5565b61134c565b6103c761053436600461350d565b61147b565b6103d1611762565b6103d161176f565b61055161177c565b6040516103de93929190613564565b61044b600f5481565b6103c761057736600461338b565b6118a1565b6103c761058a366004613222565b611930565b600b5461041f9060ff1681565b61044b6105aa36600461343d565b611cb2565b6103c76105bd36600461343d565b611ccd565b61044b60125481565b6103c76105d9366004613599565b611d39565b61044b6105ec36600461343d565b600d6020526000908152604090205481565b6103c7611e56565b6000546103fa906001600160a01b031681565b6103d1611ed8565b6103c761062f366004613400565b611ee5565b60095461041f90600160a81b900460ff1681565b61065b61065636600461343d565b611f3b565b6040516103de93929190613633565b6103d1611f63565b6103c761068036600461365b565b611f70565b6103c761069336600461338b565b61201d565b6103c76106a6366004613599565b612085565b61041f6106b936600461347b565b612199565b60095461041f90600160b01b900460ff1681565b6103c76106e0366004613400565b612260565b61044b6106f33660046136be565b6122b6565b6103c76107063660046134a5565b6122e1565b6103c761071936600461350d565b6123bc565b6103c761072c36600461338b565b612499565b6103c761073f3660046136f1565b61252c565b6103c761075236600461376a565b61267b565b6103c76107653660046136f1565b6126ca565b6103c7610778366004613400565b61280a565b61044b61078b3660046136be565b600e60209081526000928352604080842090915290825290205481565b6103c76107b63660046133c4565b612860565b61041f6107c9366004613599565b612a2e565b60175461041f9060ff1681565b6103c76107e936600461343d565b612b52565b6103c76107fc36600461343d565b612c3c565b60095461041f90600160a01b900460ff1681565b6103c761082336600461338b565b612ca8565b61083b61083636600461376a565b612d10565b604080516001600160a01b03958616815294909316602085015291830152151560608201526080016103de565b6103c76108763660046133c4565b612d59565b336001600160a01b0316600c838154811061089857610898613783565b60009182526020909120600490910201546001600160a01b0316148015906108cb57506000546001600160a01b03163314155b1561090d57604080518082018252600681526531313038303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b60405180910390fd5b600c828154811061092057610920613783565b6000918252602082206003600490920201015460ff16151590036109725760408051808201825260068152651898981c181960d11b6020820152905162461bcd60e51b815261090491906004016132af565b600c828154811061098557610985613783565b90600052602060002090600402016002015460086000600c85815481106109ae576109ae613783565b600091825260208083206004909202909101546001600160a01b03168352820192909252604001812080549091906109e79084906137af565b9091555050600c805483908110610a0057610a00613783565b906000526020600020906004020160020154600d6000600c8581548110610a2957610a29613783565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610a629084906137c2565b925050819055506000600c8381548110610a7e57610a7e613783565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817fa0cc3a4feb26502e6e6cd57b2113d58bdab80c6711d8252356be9a49945bb5f7600c8481548110610adb57610adb613783565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110610b0c57610b0c613783565b6000918252602090912060016004909202010154604051610b3992916001600160a01b03169086906137d5565b60405180910390a25050565b60018054610b5290613801565b80601f0160208091040260200160405190810160405280929190818152602001828054610b7e90613801565b8015610bcb5780601f10610ba057610100808354040283529160200191610bcb565b820191906000526020600020905b815481529060010190602001808311610bae57829003601f168201915b505050505081565b600b5460009060ff161515600103610c1957604080518082018252600681526531313035303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b838214610c545760408051808201825260068152651898981a981960d11b6020820152905162461bcd60e51b815261090491906004016132af565b6000805b85811015610c8e57848482818110610c7257610c72613783565b9050602002013582610c8491906137af565b9150600101610c58565b5080610c9933611cb2565b1015610cd357604080518082018252600681526531313035303360d01b6020820152905162461bcd60e51b815261090491906004016132af565b6004546001600160a01b03163314610d34576009546040805180820190915260068152650c4c4c0d4c0d60d21b602082015290600160a81b900460ff161515600114610d325760405162461bcd60e51b815260040161090491906132af565b505b606060006001935060005b87811015610e2f57610d77898983818110610d5c57610d5c613783565b9050602002016020810190610d71919061343d565b3b151590565b15610dcc57610dc5898983818110610d9157610d91613783565b9050602002016020810190610da6919061343d565b888884818110610db857610db8613783565b9050602002013585612e81565b9150610e18565b610e15898983818110610de157610de1613783565b9050602002016020810190610df6919061343d565b888884818110610e0857610e08613783565b9050602002013585612f9c565b91505b811515600003610e2757600094505b600101610d3f565b50505050949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610e845760405162461bcd60e51b815260040161090491906132af565b50600b805460ff19168215159081179091556040519081527fe1455bc53682229469d6919bb96d7b338cbffea93170dfb5f02242c22fb6d07f9060200160405180910390a150565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610f165760405162461bcd60e51b815260040161090491906132af565b5081610f2185611cb2565b1015610f5b57604080518082018252600681526531313036303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6060833b1561102057610f7783610f7187611cb2565b90613160565b6001600160a01b038616600090815260086020526040902055610fa383610f9d86611cb2565b90613173565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a90610fe89033908890879060040161383b565b600060405180830381600087803b15801561100257600080fd5b505af1158015611016573d6000803e3d6000fd5b505050505061106d565b61102d83610f7187611cb2565b6001600160a01b03861660009081526008602052604090205561105383610f9d86611cb2565b6001600160a01b0385166000908152600860205260409020555b836001600160a01b0316856001600160a01b0316600080516020613a85833981519152856040516110a091815260200190565b60405180910390a3506001949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146110fc5760405162461bcd60e51b815260040161090491906132af565b50601161110982826138b3565b5050565b60186020526000908152604090208054610b5290613801565b60095460408051808201909152600681526531313130303160d01b602082015290600160b01b900460ff1615156001146111735760405162461bcd60e51b815260040161090491906132af565b50600954600160a01b900460ff1615156001036112425760095460005460405163d3da927f60e01b81523360048201526001600160a01b03918216602482015291169063d3da927f90604401602060405180830381865afa1580156111dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112009190613973565b60408051808201909152600681526518989898181960d11b60208201529015156001146112405760405162461bcd60e51b815260040161090491906132af565b505b336000908152600a6020526040902082815560020161126182826138b3565b507f3bb9553f633a7ecb4cbc5f9885e750a522496ce06deff1ed9184180ca83940c03383836040516112959392919061383b565b60405180910390a15050565b60058054610b5290613801565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146112f75760405162461bcd60e51b815260040161090491906132af565b506001600160a01b0382166000818152600a6020908152604091829020600101849055815192835282018390527fa42bd6bdfcb8f9b815c68e4ce0e16dec3f1e7ac53967ee8309653de522a735b19101611295565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146113955760405162461bcd60e51b815260040161090491906132af565b50816113a084611cb2565b10156113da57604080518082018252600681526531313136303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6113e782610f7185611cb2565b6001600160a01b03841660009081526008602052604090205561140e82610f9d86866122b6565b6001600160a01b038086166000818152600e6020908152604080832094891680845294909152908190209390935591517fd7bb89baba75d47cbd55a36bae224d3c630a8d3114860f86a30b484b2af516029061146d9086908690613990565b60405180910390a350505050565b600b5460ff1615806114975750600954600160a81b900460ff16155b806114a95750816114a733611cb2565b105b156114e257604080518082018252600681526531313037303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6000546001600160a01b0384811691161480159061150e5750600954600160a01b900460ff1615156001145b156115cd5760095460005460405163d3da927f60e01b81526001600160a01b038681166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015611567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158b9190613973565b6040805180820190915260068152651898981b981960d11b60208201529015156001146115cb5760405162461bcd60e51b815260040161090491906132af565b505b33600090815260086020526040812080548492906115ec9084906137c2565b9091555050336000908152600d6020526040812080548492906116109084906137af565b9091555050600c805460408051608081018252338082526001600160a01b038881166020840190815283850189815260016060860181815290880189556000989098529351600487027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7810180549285166001600160a01b031993841617905591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8830180549190941691161790915591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c983015593517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca909101805491151560ff1990921691909117905551909182917fa256c3bc72c26fbfd6285cfde8c7e345b4d0c7ccfc725d103e9f129c5d8a039a91611754918890889088906139a9565b60405180910390a250505050565b60068054610b5290613801565b60118054610b5290613801565b601480546015805491929161179090613801565b80601f01602080910402602001604051908101604052809291908181526020018280546117bc90613801565b80156118095780601f106117de57610100808354040283529160200191611809565b820191906000526020600020905b8154815290600101906020018083116117ec57829003601f168201915b50505050509080600201805461181e90613801565b80601f016020809104026020016040519081016040528092919081815260200182805461184a90613801565b80156118975780601f1061186c57610100808354040283529160200191611897565b820191906000526020600020905b81548152906001019060200180831161187a57829003601f168201915b5050505050905083565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146118ea5760405162461bcd60e51b815260040161090491906132af565b506007805460ff191682151590811790915560405160ff9091161515907fe1e5c6f5867805bf3fab73f4df4b80d0e87e9262a7bc22ac7c2cb3fd5896222f90600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146119795760405162461bcd60e51b815260040161090491906132af565b50600954600160a81b900460ff1615156000036119c457604080518082018252600681526531313039303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b600c82815481106119d7576119d7613783565b6000918252602082206003600490920201015460ff1615159003611a295760408051808201825260068152651898981c981960d11b6020820152905162461bcd60e51b815261090491906004016132af565b600c8281548110611a3c57611a3c613783565b90600052602060002090600402016002015460086000600c8581548110611a6557611a65613783565b60009182526020808320600160049093020191909101546001600160a01b0316835282019290925260400181208054909190611aa29084906137af565b9091555050600c805483908110611abb57611abb613783565b906000526020600020906004020160020154600d6000600c8581548110611ae457611ae4613783565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190611b1d9084906137c2565b925050819055506000600c8381548110611b3957611b39613783565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817f6b50d6e4941ce7ae74ed7f7f51df5fb7680754c2815a094c66bea5ca80a40eb1600c8481548110611b9657611b96613783565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110611bc757611bc7613783565b6000918252602090912060016004909202010154604051611bf492916001600160a01b03169086906137d5565b60405180910390a2600c8281548110611c0f57611c0f613783565b6000918252602090912060016004909202010154600c80546001600160a01b039092169184908110611c4357611c43613783565b6000918252602090912060049091020154600c80546001600160a01b0390921691600080516020613a85833981519152919086908110611c8557611c85613783565b906000526020600020906004020160020154604051611ca691815260200190565b60405180910390a35050565b6001600160a01b031660009081526008602052604090205490565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d165760405162461bcd60e51b815260040161090491906132af565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d825760405162461bcd60e51b815260040161090491906132af565b508483141580611d925750848114155b15611dcb57604080518082018252600681526531313134303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b60005b85811015611e4d57611e45878783818110611deb57611deb613783565b9050602002016020810190611e00919061343d565b868684818110611e1257611e12613783565b9050602002016020810190611e27919061343d565b858585818110611e3957611e39613783565b90506020020135612860565b600101611dce565b50505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e9f5760405162461bcd60e51b815260040161090491906132af565b506013805460ff191660011790556040517f8298c3671093b19970d7c94ce1f23925a962f36fec31d25075d9be072b73e10390600090a1565b60108054610b5290613801565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611f2e5760405162461bcd60e51b815260040161090491906132af565b50600661110982826138b3565b600a602052600090815260409020805460018201546002830180549293919261181e90613801565b60028054610b5290613801565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611fb95760405162461bcd60e51b815260040161090491906132af565b5060148390556015611fcb83826138b3565b506016611fd882826138b3565b506014546040517ff89b6034f2b759ebb2dfb08461be917a1b54f2e0523c895e7f9b5e5e14dd013e9161201091601590601690613a59565b60405180910390a1505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120665760405162461bcd60e51b815260040161090491906132af565b5060098054911515600160a81b0260ff60a81b19909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120ce5760405162461bcd60e51b815260040161090491906132af565b5084831415806120de5750848114155b1561211757604080518082018252600681526531313133303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b60005b85811015611e4d5761219187878381811061213757612137613783565b905060200201602081019061214c919061343d565b86868481811061215e5761215e613783565b9050602002016020810190612173919061343d565b85858581811061218557612185613783565b90506020020135612d59565b60010161211a565b6000816121a533611cb2565b10156040518060400160405280600681526020016531313034303160d01b815250906121e45760405162461bcd60e51b815260040161090491906132af565b506009546040805180820190915260068152651898981a181960d11b602082015290600160a81b900460ff1615156001146122325760405162461bcd60e51b815260040161090491906132af565b506060833b1561224f57612247848483612e81565b91505061225a565b612247848483612f9c565b92915050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146122a95760405162461bcd60e51b815260040161090491906132af565b50600561110982826138b3565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205490565b816122ec33866122b6565b101561232657604080518082018252600681526518989818981960d11b6020820152905162461bcd60e51b815261090491906004016132af565b61233482610f7133876122b6565b336000908152600e602090815260408083206001600160a01b038916845290915290205561236582610f9d85611cb2565b6001600160a01b038085166000908152600860205260409081902092909255905133918616907f7a1a1088c929a111dda2dc0ca1cc650aa78525d11fd3089abf20c8474f5d82cc9061146d9087908790879061383b565b816123c633611cb2565b101561240057604080518082018252600681526518989818181960d11b6020820152905162461bcd60e51b815261090491906004016132af565b61240d82610f7133611cb2565b33600081815260086020526040902091909155612431908390610f9d9086906122b6565b6001600160a01b0384166000818152600e602090815260408083203380855292529182902093909355519091907ecd77abc69e7bbb6de9df8cbfcca8720df3a30decf9eefd187e72ab2ea2f5139061248c9086908690613990565b60405180910390a3505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146124e25760405162461bcd60e51b815260040161090491906132af565b506009805460ff60b01b1916600160b01b831515908102919091179091556040517fa0c691180b8089c0c84e478ee67d6325768666cd889f13de016771c6f7af1f8890600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146125755760405162461bcd60e51b815260040161090491906132af565b508161258186866122b6565b10156125bb57604080518082018252600681526531313132303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6125c982610f7187876122b6565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556125fc82610f9d85611cb2565b60086000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550846001600160a01b0316846001600160a01b03167f66b661491f3fe4e137b9e9cf90e142a93be21bc10e70c9b740379a245e4f7d2585858560405161266c9392919061383b565b60405180910390a35050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126c45760405162461bcd60e51b815260040161090491906132af565b50601255565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146127135760405162461bcd60e51b815260040161090491906132af565b508161271f86866122b6565b101561275957604080518082018252600681526531313137303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b61276782610f7187876122b6565b6001600160a01b038087166000908152600e602090815260408083209389168352929052205561279b82610f9d87866122b6565b6001600160a01b038087166000818152600e602090815260408083208986168085529252918290209490945551918716917f5847ffcc1bce0ecfdd115863db8562df2b18b61698938e251adf381774e9e3be906127fb9087908790613990565b60405180910390a45050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128535760405162461bcd60e51b815260040161090491906132af565b50601061110982826138b3565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128a95760405162461bcd60e51b815260040161090491906132af565b506001600160a01b0382161561294757806128c483856122b6565b10156128fe57604080518082018252600681526531313131303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b61290c81610f7184866122b6565b6001600160a01b038084166000908152600e602090815260408083209388168352929052205560035461293f9082613160565b6003556129d2565b6001600160a01b03831660009081526008602052604090205481111561299b57604080518082018252600681526518989898981960d11b6020820152905162461bcd60e51b815261090491906004016132af565b6129a881610f7185611cb2565b6001600160a01b0384166000908152600860205260409020556003546129ce9082613160565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167fee02732fab40ece8284c756220846dff4b8d32058b86b35b4f0459bf172fcef084604051612a2191815260200190565b60405180910390a4505050565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612a785760405162461bcd60e51b815260040161090491906132af565b508584141580612a885750858214155b15612ac157604080518082018252600681526531313135303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b60005b86811015612b4457612b3b888883818110612ae157612ae1613783565b9050602002016020810190612af6919061343d565b878784818110612b0857612b08613783565b9050602002016020810190612b1d919061343d565b868685818110612b2f57612b2f613783565b90506020020135610ecc565b50600101612ac4565b506001979650505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612b9b5760405162461bcd60e51b815260040161090491906132af565b5060408051808201909152600681526535303031303160d01b60208201526001600160a01b038216612be05760405162461bcd60e51b815260040161090491906132af565b50600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c855760405162461bcd60e51b815260040161090491906132af565b50600980546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612cf15760405162461bcd60e51b815260040161090491906132af565b5060098054911515600160a01b0260ff60a01b19909216919091179055565b600c8181548110612d2057600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509116919060ff1684565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612da25760405162461bcd60e51b815260040161090491906132af565b506001600160a01b03821615612dfb57612dc081610f9d84866122b6565b6001600160a01b038084166000908152600e6020908152604080832093881683529290522055600354612df39082613173565b600355612e32565b612e0881610f9d85611cb2565b6001600160a01b038416600090815260086020526040902055600354612e2e9082613173565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167f65adeb76912378393e600cb6f64f3310842a42e1eae86273dc775d0c47a0f2dc84604051612a2191815260200190565b60045460408051808201909152600681526531313033303160d01b60208201526000916001600160a01b03868116911614612ecf5760405162461bcd60e51b815260040161090491906132af565b50612edd83610f7133611cb2565b33600090815260086020526040902055612efa83610f9d86611cb2565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a90612f3f9033908890889060040161383b565b600060405180830381600087803b158015612f5957600080fd5b505af1158015612f6d573d6000803e3d6000fd5b50506040518681526001600160a01b0388169250339150600080516020613a85833981519152906020016110a0565b6004546000906001600160a01b03163314801590612fc15750600b5460ff1615156001145b15612ffa57604080518082018252600681526531313032303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6000546001600160a01b038581169116148015906130265750600954600160a01b900460ff1615156001145b156130e55760095460005460405163d3da927f60e01b81526001600160a01b038781166004830152918216602482015291169063d3da927f90604401602060405180830381865afa15801561307f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a39190613973565b60408051808201909152600681526518989819181960d11b60208201529015156001146130e35760405162461bcd60e51b815260040161090491906132af565b505b6130f283610f7133611cb2565b3360009081526008602052604090205561310f83610f9d86611cb2565b6001600160a01b038516600081815260086020526040908190209290925590513390600080516020613a858339815191529061314e9087815260200190565b60405180910390a35060019392505050565b600061316c82846137c2565b9392505050565b600061316c82846137af565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126131a657600080fd5b813567ffffffffffffffff808211156131c1576131c161317f565b604051601f8301601f19908116603f011681019082821181831017156131e9576131e961317f565b8160405283815286602085880101111561320257600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561323557600080fd5b82359150602083013567ffffffffffffffff81111561325357600080fd5b61325f85828601613195565b9150509250929050565b6000815180845260005b8181101561328f57602081850181015186830182015201613273565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061316c6020830184613269565b60008083601f8401126132d457600080fd5b50813567ffffffffffffffff8111156132ec57600080fd5b6020830191508360208260051b850101111561330757600080fd5b9250929050565b6000806000806040858703121561332457600080fd5b843567ffffffffffffffff8082111561333c57600080fd5b613348888389016132c2565b9096509450602087013591508082111561336157600080fd5b5061336e878288016132c2565b95989497509550505050565b801515811461338857600080fd5b50565b60006020828403121561339d57600080fd5b813561316c8161337a565b80356001600160a01b03811681146133bf57600080fd5b919050565b6000806000606084860312156133d957600080fd5b6133e2846133a8565b92506133f0602085016133a8565b9150604084013590509250925092565b60006020828403121561341257600080fd5b813567ffffffffffffffff81111561342957600080fd5b61343584828501613195565b949350505050565b60006020828403121561344f57600080fd5b61316c826133a8565b60006020828403121561346a57600080fd5b813560ff8116811461316c57600080fd5b6000806040838503121561348e57600080fd5b613497836133a8565b946020939093013593505050565b600080600080608085870312156134bb57600080fd5b6134c4856133a8565b93506134d2602086016133a8565b925060408501359150606085013567ffffffffffffffff8111156134f557600080fd5b61350187828801613195565b91505092959194509250565b60008060006060848603121561352257600080fd5b61352b846133a8565b925060208401359150604084013567ffffffffffffffff81111561354e57600080fd5b61355a86828701613195565b9150509250925092565b83815260606020820152600061357d6060830185613269565b828103604084015261358f8185613269565b9695505050505050565b600080600080600080606087890312156135b257600080fd5b863567ffffffffffffffff808211156135ca57600080fd5b6135d68a838b016132c2565b909850965060208901359150808211156135ef57600080fd5b6135fb8a838b016132c2565b9096509450604089013591508082111561361457600080fd5b5061362189828a016132c2565b979a9699509497509295939492505050565b8381528260208201526060604082015260006136526060830184613269565b95945050505050565b60008060006060848603121561367057600080fd5b83359250602084013567ffffffffffffffff8082111561368f57600080fd5b61369b87838801613195565b935060408601359150808211156136b157600080fd5b5061355a86828701613195565b600080604083850312156136d157600080fd5b6136da836133a8565b91506136e8602084016133a8565b90509250929050565b600080600080600060a0868803121561370957600080fd5b613712866133a8565b9450613720602087016133a8565b935061372e604087016133a8565b925060608601359150608086013567ffffffffffffffff81111561375157600080fd5b61375d88828901613195565b9150509295509295909350565b60006020828403121561377c57600080fd5b5035919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561225a5761225a613799565b8181038181111561225a5761225a613799565b6001600160a01b0384811682528316602082015260606040820181905260009061365290830184613269565b600181811c9082168061381557607f821691505b60208210810361383557634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b03841681528260208201526060604082015260006136526060830184613269565b601f8211156138ae576000816000526020600020601f850160051c8101602086101561388b5750805b601f850160051c820191505b818110156138aa57828155600101613897565b5050505b505050565b815167ffffffffffffffff8111156138cd576138cd61317f565b6138e1816138db8454613801565b84613862565b602080601f83116001811461391657600084156138fe5750858301515b600019600386901b1c1916600185901b1785556138aa565b600085815260208120601f198616915b8281101561394557888601518255948401946001909101908401613926565b50858210156139635787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561398557600080fd5b815161316c8161337a565b8281526040602082015260006134356040830184613269565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061358f90830184613269565b600081546139e981613801565b808552602060018381168015613a065760018114613a2057613a4e565b60ff1985168884015283151560051b880183019550613a4e565b866000528260002060005b85811015613a465781548a8201860152908301908401613a2b565b890184019650505b505050505092915050565b838152606060208201526000613a7260608301856139dc565b828103604084015261358f81856139dc56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202f59b4608df7aba4398b68008895ae4247fc729d20f7173cdd3960dbb00144a864736f6c63430008170033",
+ "deployedBytecode": "608060405234801561001057600080fd5b50600436106103af5760003560e01c806383850bcb116101f4578063c267ce5f1161011a578063e8050052116100ad578063fd0e85691161007c578063fd0e856914610801578063fd14a22214610815578063fef1b9c014610828578063ff12dcea1461086857600080fd5b8063e8050052146107bb578063edaab208146107ce578063f2fde38b146107db578063f7502a7c146107ee57600080fd5b8063d87f0986116100e9578063d87f098614610757578063d93220581461076a578063db20266f1461077d578063e7464db1146107a857600080fd5b8063c267ce5f1461070b578063c7109ec91461071e578063ca5cbbb514610731578063cb7610151461074457600080fd5b8063996f3a4b11610192578063b2a90a6011610161578063b2a90a60146106be578063b967a52e146106d2578063b9b3e06a146106e5578063bfe30fb0146106f857600080fd5b8063996f3a4b146106725780639cd23707146106855780639d8886c814610698578063a9059cbb146106ab57600080fd5b80638ed8a9bc116101ce5780638ed8a9bc1461062157806392ff0d31146106345780639301a78b1461064857806395d89b411461066a57600080fd5b806383850bcb146105fe5780638da5cb5b146106065780638db9877c1461061957600080fd5b806340615cf8116102d95780635c40f6f41161027757806376fa7a311161024657806376fa7a31146105af5780637da68d34146105c25780637ed6d103146105cb57806381ebdd79146105de57600080fd5b80635c40f6f4146105695780635ccef3e71461057c5780636f3b993f1461058f57806370a082311461059c57600080fd5b8063428630f6116102b3578063428630f61461053957806358c3b870146105415780635b473327146105495780635c2c20051461056057600080fd5b806340615cf81461050057806340d1c4411461051357806340eba90e1461052657600080fd5b8063200d2ed21161035157806327e235e31161032057806327e235e3146104b25780632e027abe146104d257806331cef447146104e557806336f7ab5e146104f857600080fd5b8063200d2ed21461046c57806323b872dd1461047957806325287d421461048c57806325d608611461049f57600080fd5b80630ed5a9331161038d5780630ed5a93314610412578063153a1f3e1461042f57806318160ddd146104425780631935a8801461045957600080fd5b806306eaa0b7146103b457806306fdde03146103c95780630af7eb0f146103e7575b600080fd5b6103c76103c2366004613222565b61087b565b005b6103d1610b45565b6040516103de91906132af565b60405180910390f35b6009546103fa906001600160a01b031681565b6040516001600160a01b0390911681526020016103de565b60135461041f9060ff1681565b60405190151581526020016103de565b61041f61043d36600461330e565b610bd3565b61044b60035481565b6040519081526020016103de565b6103c761046736600461338b565b610e3b565b60075461041f9060ff1681565b61041f6104873660046133c4565b610ecc565b6004546103fa906001600160a01b031681565b6103c76104ad366004613400565b6110b3565b61044b6104c036600461343d565b60086020526000908152604090205481565b6103d16104e0366004613458565b61110d565b6103c76104f3366004613222565b611126565b6103d16112a1565b6103c761050e36600461347b565b6112ae565b6103c76105213660046134a5565b61134c565b6103c761053436600461350d565b61147b565b6103d1611762565b6103d161176f565b61055161177c565b6040516103de93929190613564565b61044b600f5481565b6103c761057736600461338b565b6118a1565b6103c761058a366004613222565b611930565b600b5461041f9060ff1681565b61044b6105aa36600461343d565b611cb2565b6103c76105bd36600461343d565b611ccd565b61044b60125481565b6103c76105d9366004613599565b611d39565b61044b6105ec36600461343d565b600d6020526000908152604090205481565b6103c7611e56565b6000546103fa906001600160a01b031681565b6103d1611ed8565b6103c761062f366004613400565b611ee5565b60095461041f90600160a81b900460ff1681565b61065b61065636600461343d565b611f3b565b6040516103de93929190613633565b6103d1611f63565b6103c761068036600461365b565b611f70565b6103c761069336600461338b565b61201d565b6103c76106a6366004613599565b612085565b61041f6106b936600461347b565b612199565b60095461041f90600160b01b900460ff1681565b6103c76106e0366004613400565b612260565b61044b6106f33660046136be565b6122b6565b6103c76107063660046134a5565b6122e1565b6103c761071936600461350d565b6123bc565b6103c761072c36600461338b565b612499565b6103c761073f3660046136f1565b61252c565b6103c761075236600461376a565b61267b565b6103c76107653660046136f1565b6126ca565b6103c7610778366004613400565b61280a565b61044b61078b3660046136be565b600e60209081526000928352604080842090915290825290205481565b6103c76107b63660046133c4565b612860565b61041f6107c9366004613599565b612a2e565b60175461041f9060ff1681565b6103c76107e936600461343d565b612b52565b6103c76107fc36600461343d565b612c3c565b60095461041f90600160a01b900460ff1681565b6103c761082336600461338b565b612ca8565b61083b61083636600461376a565b612d10565b604080516001600160a01b03958616815294909316602085015291830152151560608201526080016103de565b6103c76108763660046133c4565b612d59565b336001600160a01b0316600c838154811061089857610898613783565b60009182526020909120600490910201546001600160a01b0316148015906108cb57506000546001600160a01b03163314155b1561090d57604080518082018252600681526531313038303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b60405180910390fd5b600c828154811061092057610920613783565b6000918252602082206003600490920201015460ff16151590036109725760408051808201825260068152651898981c181960d11b6020820152905162461bcd60e51b815261090491906004016132af565b600c828154811061098557610985613783565b90600052602060002090600402016002015460086000600c85815481106109ae576109ae613783565b600091825260208083206004909202909101546001600160a01b03168352820192909252604001812080549091906109e79084906137af565b9091555050600c805483908110610a0057610a00613783565b906000526020600020906004020160020154600d6000600c8581548110610a2957610a29613783565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610a629084906137c2565b925050819055506000600c8381548110610a7e57610a7e613783565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817fa0cc3a4feb26502e6e6cd57b2113d58bdab80c6711d8252356be9a49945bb5f7600c8481548110610adb57610adb613783565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110610b0c57610b0c613783565b6000918252602090912060016004909202010154604051610b3992916001600160a01b03169086906137d5565b60405180910390a25050565b60018054610b5290613801565b80601f0160208091040260200160405190810160405280929190818152602001828054610b7e90613801565b8015610bcb5780601f10610ba057610100808354040283529160200191610bcb565b820191906000526020600020905b815481529060010190602001808311610bae57829003601f168201915b505050505081565b600b5460009060ff161515600103610c1957604080518082018252600681526531313035303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b838214610c545760408051808201825260068152651898981a981960d11b6020820152905162461bcd60e51b815261090491906004016132af565b6000805b85811015610c8e57848482818110610c7257610c72613783565b9050602002013582610c8491906137af565b9150600101610c58565b5080610c9933611cb2565b1015610cd357604080518082018252600681526531313035303360d01b6020820152905162461bcd60e51b815261090491906004016132af565b6004546001600160a01b03163314610d34576009546040805180820190915260068152650c4c4c0d4c0d60d21b602082015290600160a81b900460ff161515600114610d325760405162461bcd60e51b815260040161090491906132af565b505b606060006001935060005b87811015610e2f57610d77898983818110610d5c57610d5c613783565b9050602002016020810190610d71919061343d565b3b151590565b15610dcc57610dc5898983818110610d9157610d91613783565b9050602002016020810190610da6919061343d565b888884818110610db857610db8613783565b9050602002013585612e81565b9150610e18565b610e15898983818110610de157610de1613783565b9050602002016020810190610df6919061343d565b888884818110610e0857610e08613783565b9050602002013585612f9c565b91505b811515600003610e2757600094505b600101610d3f565b50505050949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610e845760405162461bcd60e51b815260040161090491906132af565b50600b805460ff19168215159081179091556040519081527fe1455bc53682229469d6919bb96d7b338cbffea93170dfb5f02242c22fb6d07f9060200160405180910390a150565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610f165760405162461bcd60e51b815260040161090491906132af565b5081610f2185611cb2565b1015610f5b57604080518082018252600681526531313036303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6060833b1561102057610f7783610f7187611cb2565b90613160565b6001600160a01b038616600090815260086020526040902055610fa383610f9d86611cb2565b90613173565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a90610fe89033908890879060040161383b565b600060405180830381600087803b15801561100257600080fd5b505af1158015611016573d6000803e3d6000fd5b505050505061106d565b61102d83610f7187611cb2565b6001600160a01b03861660009081526008602052604090205561105383610f9d86611cb2565b6001600160a01b0385166000908152600860205260409020555b836001600160a01b0316856001600160a01b0316600080516020613a85833981519152856040516110a091815260200190565b60405180910390a3506001949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146110fc5760405162461bcd60e51b815260040161090491906132af565b50601161110982826138b3565b5050565b60186020526000908152604090208054610b5290613801565b60095460408051808201909152600681526531313130303160d01b602082015290600160b01b900460ff1615156001146111735760405162461bcd60e51b815260040161090491906132af565b50600954600160a01b900460ff1615156001036112425760095460005460405163d3da927f60e01b81523360048201526001600160a01b03918216602482015291169063d3da927f90604401602060405180830381865afa1580156111dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112009190613973565b60408051808201909152600681526518989898181960d11b60208201529015156001146112405760405162461bcd60e51b815260040161090491906132af565b505b336000908152600a6020526040902082815560020161126182826138b3565b507f3bb9553f633a7ecb4cbc5f9885e750a522496ce06deff1ed9184180ca83940c03383836040516112959392919061383b565b60405180910390a15050565b60058054610b5290613801565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146112f75760405162461bcd60e51b815260040161090491906132af565b506001600160a01b0382166000818152600a6020908152604091829020600101849055815192835282018390527fa42bd6bdfcb8f9b815c68e4ce0e16dec3f1e7ac53967ee8309653de522a735b19101611295565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146113955760405162461bcd60e51b815260040161090491906132af565b50816113a084611cb2565b10156113da57604080518082018252600681526531313136303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6113e782610f7185611cb2565b6001600160a01b03841660009081526008602052604090205561140e82610f9d86866122b6565b6001600160a01b038086166000818152600e6020908152604080832094891680845294909152908190209390935591517fd7bb89baba75d47cbd55a36bae224d3c630a8d3114860f86a30b484b2af516029061146d9086908690613990565b60405180910390a350505050565b600b5460ff1615806114975750600954600160a81b900460ff16155b806114a95750816114a733611cb2565b105b156114e257604080518082018252600681526531313037303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6000546001600160a01b0384811691161480159061150e5750600954600160a01b900460ff1615156001145b156115cd5760095460005460405163d3da927f60e01b81526001600160a01b038681166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015611567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158b9190613973565b6040805180820190915260068152651898981b981960d11b60208201529015156001146115cb5760405162461bcd60e51b815260040161090491906132af565b505b33600090815260086020526040812080548492906115ec9084906137c2565b9091555050336000908152600d6020526040812080548492906116109084906137af565b9091555050600c805460408051608081018252338082526001600160a01b038881166020840190815283850189815260016060860181815290880189556000989098529351600487027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7810180549285166001600160a01b031993841617905591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8830180549190941691161790915591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c983015593517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca909101805491151560ff1990921691909117905551909182917fa256c3bc72c26fbfd6285cfde8c7e345b4d0c7ccfc725d103e9f129c5d8a039a91611754918890889088906139a9565b60405180910390a250505050565b60068054610b5290613801565b60118054610b5290613801565b601480546015805491929161179090613801565b80601f01602080910402602001604051908101604052809291908181526020018280546117bc90613801565b80156118095780601f106117de57610100808354040283529160200191611809565b820191906000526020600020905b8154815290600101906020018083116117ec57829003601f168201915b50505050509080600201805461181e90613801565b80601f016020809104026020016040519081016040528092919081815260200182805461184a90613801565b80156118975780601f1061186c57610100808354040283529160200191611897565b820191906000526020600020905b81548152906001019060200180831161187a57829003601f168201915b5050505050905083565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146118ea5760405162461bcd60e51b815260040161090491906132af565b506007805460ff191682151590811790915560405160ff9091161515907fe1e5c6f5867805bf3fab73f4df4b80d0e87e9262a7bc22ac7c2cb3fd5896222f90600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146119795760405162461bcd60e51b815260040161090491906132af565b50600954600160a81b900460ff1615156000036119c457604080518082018252600681526531313039303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b600c82815481106119d7576119d7613783565b6000918252602082206003600490920201015460ff1615159003611a295760408051808201825260068152651898981c981960d11b6020820152905162461bcd60e51b815261090491906004016132af565b600c8281548110611a3c57611a3c613783565b90600052602060002090600402016002015460086000600c8581548110611a6557611a65613783565b60009182526020808320600160049093020191909101546001600160a01b0316835282019290925260400181208054909190611aa29084906137af565b9091555050600c805483908110611abb57611abb613783565b906000526020600020906004020160020154600d6000600c8581548110611ae457611ae4613783565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190611b1d9084906137c2565b925050819055506000600c8381548110611b3957611b39613783565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817f6b50d6e4941ce7ae74ed7f7f51df5fb7680754c2815a094c66bea5ca80a40eb1600c8481548110611b9657611b96613783565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110611bc757611bc7613783565b6000918252602090912060016004909202010154604051611bf492916001600160a01b03169086906137d5565b60405180910390a2600c8281548110611c0f57611c0f613783565b6000918252602090912060016004909202010154600c80546001600160a01b039092169184908110611c4357611c43613783565b6000918252602090912060049091020154600c80546001600160a01b0390921691600080516020613a85833981519152919086908110611c8557611c85613783565b906000526020600020906004020160020154604051611ca691815260200190565b60405180910390a35050565b6001600160a01b031660009081526008602052604090205490565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d165760405162461bcd60e51b815260040161090491906132af565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d825760405162461bcd60e51b815260040161090491906132af565b508483141580611d925750848114155b15611dcb57604080518082018252600681526531313134303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b60005b85811015611e4d57611e45878783818110611deb57611deb613783565b9050602002016020810190611e00919061343d565b868684818110611e1257611e12613783565b9050602002016020810190611e27919061343d565b858585818110611e3957611e39613783565b90506020020135612860565b600101611dce565b50505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e9f5760405162461bcd60e51b815260040161090491906132af565b506013805460ff191660011790556040517f8298c3671093b19970d7c94ce1f23925a962f36fec31d25075d9be072b73e10390600090a1565b60108054610b5290613801565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611f2e5760405162461bcd60e51b815260040161090491906132af565b50600661110982826138b3565b600a602052600090815260409020805460018201546002830180549293919261181e90613801565b60028054610b5290613801565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611fb95760405162461bcd60e51b815260040161090491906132af565b5060148390556015611fcb83826138b3565b506016611fd882826138b3565b506014546040517ff89b6034f2b759ebb2dfb08461be917a1b54f2e0523c895e7f9b5e5e14dd013e9161201091601590601690613a59565b60405180910390a1505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120665760405162461bcd60e51b815260040161090491906132af565b5060098054911515600160a81b0260ff60a81b19909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120ce5760405162461bcd60e51b815260040161090491906132af565b5084831415806120de5750848114155b1561211757604080518082018252600681526531313133303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b60005b85811015611e4d5761219187878381811061213757612137613783565b905060200201602081019061214c919061343d565b86868481811061215e5761215e613783565b9050602002016020810190612173919061343d565b85858581811061218557612185613783565b90506020020135612d59565b60010161211a565b6000816121a533611cb2565b10156040518060400160405280600681526020016531313034303160d01b815250906121e45760405162461bcd60e51b815260040161090491906132af565b506009546040805180820190915260068152651898981a181960d11b602082015290600160a81b900460ff1615156001146122325760405162461bcd60e51b815260040161090491906132af565b506060833b1561224f57612247848483612e81565b91505061225a565b612247848483612f9c565b92915050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146122a95760405162461bcd60e51b815260040161090491906132af565b50600561110982826138b3565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205490565b816122ec33866122b6565b101561232657604080518082018252600681526518989818981960d11b6020820152905162461bcd60e51b815261090491906004016132af565b61233482610f7133876122b6565b336000908152600e602090815260408083206001600160a01b038916845290915290205561236582610f9d85611cb2565b6001600160a01b038085166000908152600860205260409081902092909255905133918616907f7a1a1088c929a111dda2dc0ca1cc650aa78525d11fd3089abf20c8474f5d82cc9061146d9087908790879061383b565b816123c633611cb2565b101561240057604080518082018252600681526518989818181960d11b6020820152905162461bcd60e51b815261090491906004016132af565b61240d82610f7133611cb2565b33600081815260086020526040902091909155612431908390610f9d9086906122b6565b6001600160a01b0384166000818152600e602090815260408083203380855292529182902093909355519091907ecd77abc69e7bbb6de9df8cbfcca8720df3a30decf9eefd187e72ab2ea2f5139061248c9086908690613990565b60405180910390a3505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146124e25760405162461bcd60e51b815260040161090491906132af565b506009805460ff60b01b1916600160b01b831515908102919091179091556040517fa0c691180b8089c0c84e478ee67d6325768666cd889f13de016771c6f7af1f8890600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146125755760405162461bcd60e51b815260040161090491906132af565b508161258186866122b6565b10156125bb57604080518082018252600681526531313132303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6125c982610f7187876122b6565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556125fc82610f9d85611cb2565b60086000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550846001600160a01b0316846001600160a01b03167f66b661491f3fe4e137b9e9cf90e142a93be21bc10e70c9b740379a245e4f7d2585858560405161266c9392919061383b565b60405180910390a35050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126c45760405162461bcd60e51b815260040161090491906132af565b50601255565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146127135760405162461bcd60e51b815260040161090491906132af565b508161271f86866122b6565b101561275957604080518082018252600681526531313137303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b61276782610f7187876122b6565b6001600160a01b038087166000908152600e602090815260408083209389168352929052205561279b82610f9d87866122b6565b6001600160a01b038087166000818152600e602090815260408083208986168085529252918290209490945551918716917f5847ffcc1bce0ecfdd115863db8562df2b18b61698938e251adf381774e9e3be906127fb9087908790613990565b60405180910390a45050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128535760405162461bcd60e51b815260040161090491906132af565b50601061110982826138b3565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128a95760405162461bcd60e51b815260040161090491906132af565b506001600160a01b0382161561294757806128c483856122b6565b10156128fe57604080518082018252600681526531313131303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b61290c81610f7184866122b6565b6001600160a01b038084166000908152600e602090815260408083209388168352929052205560035461293f9082613160565b6003556129d2565b6001600160a01b03831660009081526008602052604090205481111561299b57604080518082018252600681526518989898981960d11b6020820152905162461bcd60e51b815261090491906004016132af565b6129a881610f7185611cb2565b6001600160a01b0384166000908152600860205260409020556003546129ce9082613160565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167fee02732fab40ece8284c756220846dff4b8d32058b86b35b4f0459bf172fcef084604051612a2191815260200190565b60405180910390a4505050565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612a785760405162461bcd60e51b815260040161090491906132af565b508584141580612a885750858214155b15612ac157604080518082018252600681526531313135303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b60005b86811015612b4457612b3b888883818110612ae157612ae1613783565b9050602002016020810190612af6919061343d565b878784818110612b0857612b08613783565b9050602002016020810190612b1d919061343d565b868685818110612b2f57612b2f613783565b90506020020135610ecc565b50600101612ac4565b506001979650505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612b9b5760405162461bcd60e51b815260040161090491906132af565b5060408051808201909152600681526535303031303160d01b60208201526001600160a01b038216612be05760405162461bcd60e51b815260040161090491906132af565b50600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c855760405162461bcd60e51b815260040161090491906132af565b50600980546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612cf15760405162461bcd60e51b815260040161090491906132af565b5060098054911515600160a01b0260ff60a01b19909216919091179055565b600c8181548110612d2057600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509116919060ff1684565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612da25760405162461bcd60e51b815260040161090491906132af565b506001600160a01b03821615612dfb57612dc081610f9d84866122b6565b6001600160a01b038084166000908152600e6020908152604080832093881683529290522055600354612df39082613173565b600355612e32565b612e0881610f9d85611cb2565b6001600160a01b038416600090815260086020526040902055600354612e2e9082613173565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167f65adeb76912378393e600cb6f64f3310842a42e1eae86273dc775d0c47a0f2dc84604051612a2191815260200190565b60045460408051808201909152600681526531313033303160d01b60208201526000916001600160a01b03868116911614612ecf5760405162461bcd60e51b815260040161090491906132af565b50612edd83610f7133611cb2565b33600090815260086020526040902055612efa83610f9d86611cb2565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a90612f3f9033908890889060040161383b565b600060405180830381600087803b158015612f5957600080fd5b505af1158015612f6d573d6000803e3d6000fd5b50506040518681526001600160a01b0388169250339150600080516020613a85833981519152906020016110a0565b6004546000906001600160a01b03163314801590612fc15750600b5460ff1615156001145b15612ffa57604080518082018252600681526531313032303160d01b6020820152905162461bcd60e51b815261090491906004016132af565b6000546001600160a01b038581169116148015906130265750600954600160a01b900460ff1615156001145b156130e55760095460005460405163d3da927f60e01b81526001600160a01b038781166004830152918216602482015291169063d3da927f90604401602060405180830381865afa15801561307f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130a39190613973565b60408051808201909152600681526518989819181960d11b60208201529015156001146130e35760405162461bcd60e51b815260040161090491906132af565b505b6130f283610f7133611cb2565b3360009081526008602052604090205561310f83610f9d86611cb2565b6001600160a01b038516600081815260086020526040908190209290925590513390600080516020613a858339815191529061314e9087815260200190565b60405180910390a35060019392505050565b600061316c82846137c2565b9392505050565b600061316c82846137af565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126131a657600080fd5b813567ffffffffffffffff808211156131c1576131c161317f565b604051601f8301601f19908116603f011681019082821181831017156131e9576131e961317f565b8160405283815286602085880101111561320257600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561323557600080fd5b82359150602083013567ffffffffffffffff81111561325357600080fd5b61325f85828601613195565b9150509250929050565b6000815180845260005b8181101561328f57602081850181015186830182015201613273565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061316c6020830184613269565b60008083601f8401126132d457600080fd5b50813567ffffffffffffffff8111156132ec57600080fd5b6020830191508360208260051b850101111561330757600080fd5b9250929050565b6000806000806040858703121561332457600080fd5b843567ffffffffffffffff8082111561333c57600080fd5b613348888389016132c2565b9096509450602087013591508082111561336157600080fd5b5061336e878288016132c2565b95989497509550505050565b801515811461338857600080fd5b50565b60006020828403121561339d57600080fd5b813561316c8161337a565b80356001600160a01b03811681146133bf57600080fd5b919050565b6000806000606084860312156133d957600080fd5b6133e2846133a8565b92506133f0602085016133a8565b9150604084013590509250925092565b60006020828403121561341257600080fd5b813567ffffffffffffffff81111561342957600080fd5b61343584828501613195565b949350505050565b60006020828403121561344f57600080fd5b61316c826133a8565b60006020828403121561346a57600080fd5b813560ff8116811461316c57600080fd5b6000806040838503121561348e57600080fd5b613497836133a8565b946020939093013593505050565b600080600080608085870312156134bb57600080fd5b6134c4856133a8565b93506134d2602086016133a8565b925060408501359150606085013567ffffffffffffffff8111156134f557600080fd5b61350187828801613195565b91505092959194509250565b60008060006060848603121561352257600080fd5b61352b846133a8565b925060208401359150604084013567ffffffffffffffff81111561354e57600080fd5b61355a86828701613195565b9150509250925092565b83815260606020820152600061357d6060830185613269565b828103604084015261358f8185613269565b9695505050505050565b600080600080600080606087890312156135b257600080fd5b863567ffffffffffffffff808211156135ca57600080fd5b6135d68a838b016132c2565b909850965060208901359150808211156135ef57600080fd5b6135fb8a838b016132c2565b9096509450604089013591508082111561361457600080fd5b5061362189828a016132c2565b979a9699509497509295939492505050565b8381528260208201526060604082015260006136526060830184613269565b95945050505050565b60008060006060848603121561367057600080fd5b83359250602084013567ffffffffffffffff8082111561368f57600080fd5b61369b87838801613195565b935060408601359150808211156136b157600080fd5b5061355a86828701613195565b600080604083850312156136d157600080fd5b6136da836133a8565b91506136e8602084016133a8565b90509250929050565b600080600080600060a0868803121561370957600080fd5b613712866133a8565b9450613720602087016133a8565b935061372e604087016133a8565b925060608601359150608086013567ffffffffffffffff81111561375157600080fd5b61375d88828901613195565b9150509295509295909350565b60006020828403121561377c57600080fd5b5035919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561225a5761225a613799565b8181038181111561225a5761225a613799565b6001600160a01b0384811682528316602082015260606040820181905260009061365290830184613269565b600181811c9082168061381557607f821691505b60208210810361383557634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b03841681528260208201526060604082015260006136526060830184613269565b601f8211156138ae576000816000526020600020601f850160051c8101602086101561388b5750805b601f850160051c820191505b818110156138aa57828155600101613897565b5050505b505050565b815167ffffffffffffffff8111156138cd576138cd61317f565b6138e1816138db8454613801565b84613862565b602080601f83116001811461391657600084156138fe5750858301515b600019600386901b1c1916600185901b1785556138aa565b600085815260208120601f198616915b8281101561394557888601518255948401946001909101908401613926565b50858210156139635787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561398557600080fd5b815161316c8161337a565b8281526040602082015260006134356040830184613269565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061358f90830184613269565b600081546139e981613801565b808552602060018381168015613a065760018114613a2057613a4e565b60ff1985168884015283151560051b880183019550613a4e565b866000528260002060005b85811015613a465781548a8201860152908301908401613a2b565b890184019650505b505050505092915050565b838152606060208201526000613a7260608301856139dc565b828103604084015261358f81856139dc56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212202f59b4608df7aba4398b68008895ae4247fc729d20f7173cdd3960dbb00144a864736f6c63430008170033"
}
\ No newline at end of file
diff --git a/app/contracts/json/IbetStraightBond.json b/app/contracts/json/IbetStraightBond.json
index 57e9cf20f..f937a0ce3 100644
--- a/app/contracts/json/IbetStraightBond.json
+++ b/app/contracts/json/IbetStraightBond.json
@@ -275,6 +275,43 @@
"name": "ChangeTransferApprovalRequired",
"type": "event"
},
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "lockAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "beforeAccountAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "afterAccountAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "data",
+ "type": "string"
+ }
+ ],
+ "name": "ForceChangeLockedAccount",
+ "type": "event"
+ },
{
"anonymous": false,
"inputs": [
@@ -884,6 +921,39 @@
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_lockAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_beforeAccountAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_afterAccountAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_value",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "_data",
+ "type": "string"
+ }
+ ],
+ "name": "forceChangeLockedAccount",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
{
"inputs": [
{
@@ -1722,6 +1792,6 @@
"type": "function"
}
],
- "bytecode": "60806040523480156200001157600080fd5b5060405162004011380380620040118339810160408190526200003491620001f5565b600080546001600160a01b0319908116339182161717905560016200005a8c8262000431565b506002620000698b8262000431565b506003899055600f889055601962000082888262000431565b50601262000091878262000431565b506013859055601b620000a5858262000431565b506014620000b4848262000431565b506015620000c3838262000431565b506016620000d2828262000431565b5050600354600080546001600160a01b031681526008602052604090205550506018805460ff1990811690915560078054909116600117905550506009805460ff60a01b1916600160a01b17905550620004fd945050505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200015557600080fd5b81516001600160401b03808211156200017257620001726200012d565b604051601f8301601f19908116603f011681019082821181831017156200019d576200019d6200012d565b8160405283815260209250866020858801011115620001bb57600080fd5b600091505b83821015620001df5785820183015181830184015290820190620001c0565b6000602085830101528094505050505092915050565b60008060008060008060008060008060006101608c8e0312156200021857600080fd5b8b516001600160401b038111156200022f57600080fd5b6200023d8e828f0162000143565b60208e0151909c5090506001600160401b038111156200025c57600080fd5b6200026a8e828f0162000143565b9a505060408c0151985060608c0151975060808c015160018060401b038111156200029457600080fd5b620002a28e828f0162000143565b60a08e015190985090506001600160401b03811115620002c157600080fd5b620002cf8e828f0162000143565b60c08e015160e08f0151919850965090506001600160401b03811115620002f557600080fd5b620003038e828f0162000143565b6101008e015190955090506001600160401b038111156200032357600080fd5b620003318e828f0162000143565b6101208e015190945090506001600160401b038111156200035157600080fd5b6200035f8e828f0162000143565b6101408e015190935090506001600160401b038111156200037f57600080fd5b6200038d8e828f0162000143565b9150509295989b509295989b9093969950565b600181811c90821680620003b557607f821691505b602082108103620003d657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200042c576000816000526020600020601f850160051c81016020861015620004075750805b601f850160051c820191505b81811015620004285782815560010162000413565b5050505b505050565b81516001600160401b038111156200044d576200044d6200012d565b62000465816200045e8454620003a0565b84620003dc565b602080601f8311600181146200049d5760008415620004845750858301515b600019600386901b1c1916600185901b17855562000428565b600085815260208120601f198616915b82811015620004ce57888601518255948401946001909101908401620004ad565b5085821015620004ed5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613b04806200050d6000396000f3fe608060405234801561001057600080fd5b50600436106104335760003560e01c806381ebdd7911610236578063c7109ec91161013b578063ef4474cd116100c3578063fc590d0911610087578063fc590d09146108fd578063fd0e856914610905578063fd14a22214610919578063fef1b9c01461092c578063ff12dcea1461096c57600080fd5b8063ef4474cd146108b3578063ef8032ef146108bc578063f2fde38b146108cf578063f35eeaef146108e2578063f7502a7c146108ea57600080fd5b8063e7464db11161010a578063e7464db11461085f578063e805005214610872578063eb68757f14610885578063ed62c2a014610898578063ee0cfa40146108a057600080fd5b8063c7109ec914610806578063ca5cbbb514610819578063d5d9d0c71461082c578063db20266f1461083457600080fd5b80639cd23707116101be578063b2a90a601161018d578063b2a90a60146107a6578063b967a52e146107ba578063b9b3e06a146107cd578063bfe30fb0146107e0578063c267ce5f146107f357600080fd5b80639cd237071461075a5780639d8886c81461076d578063a9059cbb14610780578063ab62f92e1461079357600080fd5b8063919fe52d11610205578063919fe52d146106f657806392ff0d31146107095780639301a78b1461071d57806395d89b411461073f57806397e4c5131461074757600080fd5b806381ebdd791461069d5780638ac08bf1146106bd5780638da5cb5b146106d05780638ed8a9bc146106e357600080fd5b806340615cf81161033c5780635f84f302116102c457806370740aab1161029357806370740aab1461065357806370a082311461065b57806376fa7a311461066e5780637c3a00fd146106815780637ed6d1031461068a57600080fd5b80635f84f30214610618578063637834441461062b5780636666e49c1461063e5780636f3b993f1461064657600080fd5b806344fd9caa1161030b57806344fd9caa146105d957806358c3b870146105e257806359d93617146105ea5780635c40f6f4146105f25780635ccef3e71461060557600080fd5b806340615cf81461059857806340d1c441146105ab57806340eba90e146105be578063428630f6146105d157600080fd5b806325287d42116103bf57806331cef4471161038e57806331cef4471461055a578063329dbddc1461056d57806336f7ab5e146105755780633a2b69391461057d5780633b18b9841461058557600080fd5b806325287d421461050c57806325d608611461051f57806327e235e3146105325780632e0ad0041461055257600080fd5b8063153a1f3e11610406578063153a1f3e146104af57806318160ddd146104c25780631935a880146104d9578063200d2ed2146104ec57806323b872dd146104f957600080fd5b8063034f6b211461043857806306eaa0b71461045a57806306fdde031461046f5780630af7eb0f14610484575b600080fd5b6018546104459060ff1681565b60405190151581526020015b60405180910390f35b61046d6104683660046133a5565b61097f565b005b610477610c49565b6040516104519190613432565b600954610497906001600160a01b031681565b6040516001600160a01b039091168152602001610451565b6104456104bd366004613491565b610cd7565b6104cb60035481565b604051908152602001610451565b61046d6104e736600461350e565b610efb565b6007546104459060ff1681565b610445610507366004613547565b610f8d565b600454610497906001600160a01b031681565b61046d61052d366004613583565b611174565b6104cb6105403660046135c0565b60086020526000908152604090205481565b6104776111ce565b61046d6105683660046133a5565b6111db565b610477611356565b610477611363565b610477611370565b61046d6105933660046135db565b61137d565b61046d6105a63660046135f4565b6113fc565b61046d6105b936600461361e565b61149a565b61046d6105cc366004613686565b6115c9565b6104776118b0565b6104cb600f5481565b6104776118bd565b6104776118ca565b61046d61060036600461350e565b6118d7565b61046d6106133660046133a5565b611966565b61046d6106263660046135db565b611ce8565b61046d610639366004613583565b611d37565b610477611d8d565b600b546104459060ff1681565b610477611d9a565b6104cb6106693660046135c0565b611da7565b61046d61067c3660046135c0565b611dc2565b6104cb60105481565b61046d6106983660046136dd565b611e2e565b6104cb6106ab3660046135c0565b600d6020526000908152604090205481565b61046d6106cb366004613583565b611f4b565b600054610497906001600160a01b031681565b61046d6106f1366004613583565b611fa1565b61046d610704366004613583565b611ff7565b60095461044590600160a81b900460ff1681565b61073061072b3660046135c0565b61204d565b60405161045193929190613777565b6104776120f8565b61046d610755366004613583565b612105565b61046d61076836600461350e565b61215b565b61046d61077b3660046136dd565b6121c3565b61044561078e3660046135f4565b6122d7565b61046d6107a1366004613583565b61239e565b60095461044590600160b01b900460ff1681565b61046d6107c8366004613583565b6123f4565b6104cb6107db36600461379f565b61244a565b61046d6107ee36600461361e565b612475565b61046d610801366004613686565b612550565b61046d61081436600461350e565b61262d565b61046d6108273660046137d2565b6126c0565b61046d61280f565b6104cb61084236600461379f565b600e60209081526000928352604080842090915290825290205481565b61046d61086d366004613547565b612891565b6104456108803660046136dd565b612a5f565b61046d610893366004613583565b612b83565b610477612bd9565b61046d6108ae366004613583565b612be6565b6104cb60135481565b61046d6108ca3660046135db565b612c3c565b61046d6108dd3660046135c0565b612cbb565b610477612da5565b61046d6108f83660046135c0565b612db2565b610477612e1e565b60095461044590600160a01b900460ff1681565b61046d61092736600461350e565b612e2b565b61093f61093a3660046135db565b612e93565b604080516001600160a01b0395861681529490931660208501529183015215156060820152608001610451565b61046d61097a366004613547565b612edc565b336001600160a01b0316600c838154811061099c5761099c61384b565b60009182526020909120600490910201546001600160a01b0316148015906109cf57506000546001600160a01b03163314155b15610a1157604080518082018252600681526531323038303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b60405180910390fd5b600c8281548110610a2457610a2461384b565b6000918252602082206003600490920201015460ff1615159003610a765760408051808201825260068152651899181c181960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b600c8281548110610a8957610a8961384b565b90600052602060002090600402016002015460086000600c8581548110610ab257610ab261384b565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610aeb908490613877565b9091555050600c805483908110610b0457610b0461384b565b906000526020600020906004020160020154600d6000600c8581548110610b2d57610b2d61384b565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610b6690849061388a565b925050819055506000600c8381548110610b8257610b8261384b565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817fa0cc3a4feb26502e6e6cd57b2113d58bdab80c6711d8252356be9a49945bb5f7600c8481548110610bdf57610bdf61384b565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110610c1057610c1061384b565b6000918252602090912060016004909202010154604051610c3d92916001600160a01b031690869061389d565b60405180910390a25050565b60018054610c56906138c9565b80601f0160208091040260200160405190810160405280929190818152602001828054610c82906138c9565b8015610ccf5780601f10610ca457610100808354040283529160200191610ccf565b820191906000526020600020905b815481529060010190602001808311610cb257829003601f168201915b505050505081565b6000838214610d1457604080518082018252600681526531323035303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6000805b85811015610d4e57848482818110610d3257610d3261384b565b9050602002013582610d449190613877565b9150600101610d18565b5080610d5933611da7565b1015610d935760408051808201825260068152651899181a981960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b6004546001600160a01b03163314610df45760095460408051808201909152600681526531323035303360d01b602082015290600160a81b900460ff161515600114610df25760405162461bcd60e51b8152600401610a089190613432565b505b606060006001935060005b87811015610eef57610e37898983818110610e1c57610e1c61384b565b9050602002016020810190610e3191906135c0565b3b151590565b15610e8c57610e85898983818110610e5157610e5161384b565b9050602002016020810190610e6691906135c0565b888884818110610e7857610e7861384b565b9050602002013585613004565b9150610ed8565b610ed5898983818110610ea157610ea161384b565b9050602002016020810190610eb691906135c0565b888884818110610ec857610ec861384b565b905060200201358561311f565b91505b811515600003610ee757600094505b600101610dff565b50505050949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610f445760405162461bcd60e51b8152600401610a089190613432565b50600b805460ff19168215159081179091556040519081527fe1455bc53682229469d6919bb96d7b338cbffea93170dfb5f02242c22fb6d07f906020015b60405180910390a150565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610fd75760405162461bcd60e51b8152600401610a089190613432565b5081610fe285611da7565b101561101c57604080518082018252600681526531323036303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6060833b156110e1576110388361103287611da7565b906132e3565b6001600160a01b0386166000908152600860205260409020556110648361105e86611da7565b906132f6565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a906110a990339088908790600401613903565b600060405180830381600087803b1580156110c357600080fd5b505af11580156110d7573d6000803e3d6000fd5b505050505061112e565b6110ee8361103287611da7565b6001600160a01b0386166000908152600860205260409020556111148361105e86611da7565b6001600160a01b0385166000908152600860205260409020555b836001600160a01b0316856001600160a01b0316600080516020613aaf8339815191528560405161116191815260200190565b60405180910390a3506001949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146111bd5760405162461bcd60e51b8152600401610a089190613432565b5060176111ca828261397b565b5050565b601a8054610c56906138c9565b60095460408051808201909152600681526531323130303160d01b602082015290600160b01b900460ff1615156001146112285760405162461bcd60e51b8152600401610a089190613432565b50600954600160a01b900460ff1615156001036112f75760095460005460405163d3da927f60e01b81523360048201526001600160a01b03918216602482015291169063d3da927f90604401602060405180830381865afa158015611291573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b59190613a3b565b60408051808201909152600681526518991898181960d11b60208201529015156001146112f55760405162461bcd60e51b8152600401610a089190613432565b505b336000908152600a60205260409020828155600201611316828261397b565b507f3bb9553f633a7ecb4cbc5f9885e750a522496ce06deff1ed9184180ca83940c033838360405161134a93929190613903565b60405180910390a15050565b60118054610c56906138c9565b60058054610c56906138c9565b60198054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146113c65760405162461bcd60e51b8152600401610a089190613432565b5060138190556040518181527fe451abe602c33e612ea61221b5a142f7fe3c044286e42c8340ffe7fa86a5859790602001610f82565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146114455760405162461bcd60e51b8152600401610a089190613432565b506001600160a01b0382166000818152600a6020908152604091829020600101849055815192835282018390527fa42bd6bdfcb8f9b815c68e4ce0e16dec3f1e7ac53967ee8309653de522a735b1910161134a565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146114e35760405162461bcd60e51b8152600401610a089190613432565b50816114ee84611da7565b101561152857604080518082018252600681526531323136303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6115358261103285611da7565b6001600160a01b03841660009081526008602052604090205561155c8261105e868661244a565b6001600160a01b038086166000818152600e6020908152604080832094891680845294909152908190209390935591517fd7bb89baba75d47cbd55a36bae224d3c630a8d3114860f86a30b484b2af51602906115bb9086908690613a58565b60405180910390a350505050565b600b5460ff1615806115e55750600954600160a81b900460ff16155b806115f75750816115f533611da7565b105b1561163057604080518082018252600681526531323037303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6000546001600160a01b0384811691161480159061165c5750600954600160a01b900460ff1615156001145b1561171b5760095460005460405163d3da927f60e01b81526001600160a01b038681166004830152918216602482015291169063d3da927f90604401602060405180830381865afa1580156116b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d99190613a3b565b6040805180820190915260068152651899181b981960d11b60208201529015156001146117195760405162461bcd60e51b8152600401610a089190613432565b505b336000908152600860205260408120805484929061173a90849061388a565b9091555050336000908152600d60205260408120805484929061175e908490613877565b9091555050600c805460408051608081018252338082526001600160a01b038881166020840190815283850189815260016060860181815290880189556000989098529351600487027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7810180549285166001600160a01b031993841617905591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8830180549190941691161790915591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c983015593517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca909101805491151560ff1990921691909117905551909182917fa256c3bc72c26fbfd6285cfde8c7e345b4d0c7ccfc725d103e9f129c5d8a039a916118a291889088908890613a71565b60405180910390a250505050565b60068054610c56906138c9565b60178054610c56906138c9565b601b8054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146119205760405162461bcd60e51b8152600401610a089190613432565b506007805460ff191682151590811790915560405160ff9091161515907fe1e5c6f5867805bf3fab73f4df4b80d0e87e9262a7bc22ac7c2cb3fd5896222f90600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146119af5760405162461bcd60e51b8152600401610a089190613432565b50600954600160a81b900460ff1615156000036119fa57604080518082018252600681526531323039303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b600c8281548110611a0d57611a0d61384b565b6000918252602082206003600490920201015460ff1615159003611a5f5760408051808201825260068152651899181c981960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b600c8281548110611a7257611a7261384b565b90600052602060002090600402016002015460086000600c8581548110611a9b57611a9b61384b565b60009182526020808320600160049093020191909101546001600160a01b0316835282019290925260400181208054909190611ad8908490613877565b9091555050600c805483908110611af157611af161384b565b906000526020600020906004020160020154600d6000600c8581548110611b1a57611b1a61384b565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190611b5390849061388a565b925050819055506000600c8381548110611b6f57611b6f61384b565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817f6b50d6e4941ce7ae74ed7f7f51df5fb7680754c2815a094c66bea5ca80a40eb1600c8481548110611bcc57611bcc61384b565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110611bfd57611bfd61384b565b6000918252602090912060016004909202010154604051611c2a92916001600160a01b031690869061389d565b60405180910390a2600c8281548110611c4557611c4561384b565b6000918252602090912060016004909202010154600c80546001600160a01b039092169184908110611c7957611c7961384b565b6000918252602090912060049091020154600c80546001600160a01b0390921691600080516020613aaf833981519152919086908110611cbb57611cbb61384b565b906000526020600020906004020160020154604051611cdc91815260200190565b60405180910390a35050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d315760405162461bcd60e51b8152600401610a089190613432565b50601055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d805760405162461bcd60e51b8152600401610a089190613432565b5060116111ca828261397b565b60128054610c56906138c9565b60168054610c56906138c9565b6001600160a01b031660009081526008602052604090205490565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e0b5760405162461bcd60e51b8152600401610a089190613432565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e775760405162461bcd60e51b8152600401610a089190613432565b508483141580611e875750848114155b15611ec057604080518082018252600681526531323134303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b60005b85811015611f4257611f3a878783818110611ee057611ee061384b565b9050602002016020810190611ef591906135c0565b868684818110611f0757611f0761384b565b9050602002016020810190611f1c91906135c0565b858585818110611f2e57611f2e61384b565b90506020020135612891565b600101611ec3565b50505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611f945760405162461bcd60e51b8152600401610a089190613432565b5060196111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611fea5760405162461bcd60e51b8152600401610a089190613432565b5060066111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120405760405162461bcd60e51b8152600401610a089190613432565b50601b6111ca828261397b565b600a6020526000908152604090208054600182015460028301805492939192612075906138c9565b80601f01602080910402602001604051908101604052809291908181526020018280546120a1906138c9565b80156120ee5780601f106120c3576101008083540402835291602001916120ee565b820191906000526020600020905b8154815290600101906020018083116120d157829003601f168201915b5050505050905083565b60028054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461214e5760405162461bcd60e51b8152600401610a089190613432565b50601c6111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146121a45760405162461bcd60e51b8152600401610a089190613432565b5060098054911515600160a81b0260ff60a81b19909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461220c5760405162461bcd60e51b8152600401610a089190613432565b50848314158061221c5750848114155b1561225557604080518082018252600681526531323133303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b60005b85811015611f42576122cf8787838181106122755761227561384b565b905060200201602081019061228a91906135c0565b86868481811061229c5761229c61384b565b90506020020160208101906122b191906135c0565b8585858181106122c3576122c361384b565b90506020020135612edc565b600101612258565b6000816122e333611da7565b10156040518060400160405280600681526020016531323034303160d01b815250906123225760405162461bcd60e51b8152600401610a089190613432565b506009546040805180820190915260068152651899181a181960d11b602082015290600160a81b900460ff1615156001146123705760405162461bcd60e51b8152600401610a089190613432565b506060833b1561238d57612385848483613004565b915050612398565b61238584848361311f565b92915050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146123e75760405162461bcd60e51b8152600401610a089190613432565b50601a6111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461243d5760405162461bcd60e51b8152600401610a089190613432565b5060056111ca828261397b565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205490565b81612480338661244a565b10156124ba57604080518082018252600681526518991818981960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b6124c882611032338761244a565b336000908152600e602090815260408083206001600160a01b03891684529091529020556124f98261105e85611da7565b6001600160a01b038085166000908152600860205260409081902092909255905133918616907f7a1a1088c929a111dda2dc0ca1cc650aa78525d11fd3089abf20c8474f5d82cc906115bb90879087908790613903565b8161255a33611da7565b101561259457604080518082018252600681526518991818181960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b6125a18261103233611da7565b336000818152600860205260409020919091556125c590839061105e90869061244a565b6001600160a01b0384166000818152600e602090815260408083203380855292529182902093909355519091907ecd77abc69e7bbb6de9df8cbfcca8720df3a30decf9eefd187e72ab2ea2f513906126209086908690613a58565b60405180910390a3505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126765760405162461bcd60e51b8152600401610a089190613432565b506009805460ff60b01b1916600160b01b831515908102919091179091556040517fa0c691180b8089c0c84e478ee67d6325768666cd889f13de016771c6f7af1f8890600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146127095760405162461bcd60e51b8152600401610a089190613432565b5081612715868661244a565b101561274f57604080518082018252600681526531323132303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b61275d82611032878761244a565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556127908261105e85611da7565b60086000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550846001600160a01b0316846001600160a01b03167f66b661491f3fe4e137b9e9cf90e142a93be21bc10e70c9b740379a245e4f7d2585858560405161280093929190613903565b60405180910390a35050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128585760405162461bcd60e51b8152600401610a089190613432565b506018805460ff191660011790556040517f96151d7f1d8c50be29a45c0e3ae9ce2008888d1615b196e8f5ffd8c178e6dde890600090a1565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128da5760405162461bcd60e51b8152600401610a089190613432565b506001600160a01b0382161561297857806128f5838561244a565b101561292f57604080518082018252600681526531323131303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b61293d81611032848661244a565b6001600160a01b038084166000908152600e602090815260408083209388168352929052205560035461297090826132e3565b600355612a03565b6001600160a01b0383166000908152600860205260409020548111156129cc57604080518082018252600681526518991898981960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b6129d98161103285611da7565b6001600160a01b0384166000908152600860205260409020556003546129ff90826132e3565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167fee02732fab40ece8284c756220846dff4b8d32058b86b35b4f0459bf172fcef084604051612a5291815260200190565b60405180910390a4505050565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612aa95760405162461bcd60e51b8152600401610a089190613432565b508584141580612ab95750858214155b15612af257604080518082018252600681526531323135303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b60005b86811015612b7557612b6c888883818110612b1257612b1261384b565b9050602002016020810190612b2791906135c0565b878784818110612b3957612b3961384b565b9050602002016020810190612b4e91906135c0565b868685818110612b6057612b6061384b565b90506020020135610f8d565b50600101612af5565b506001979650505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612bcc5760405162461bcd60e51b8152600401610a089190613432565b5060166111ca828261397b565b601c8054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c2f5760405162461bcd60e51b8152600401610a089190613432565b5060126111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c855760405162461bcd60e51b8152600401610a089190613432565b50600f8190556040518181527f82b19c9a00131a87eeff1903fcb9e4f2a3ba76dd86098586eea921a533e218dc90602001610f82565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612d045760405162461bcd60e51b8152600401610a089190613432565b5060408051808201909152600681526535303031303160d01b60208201526001600160a01b038216612d495760405162461bcd60e51b8152600401610a089190613432565b50600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60158054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612dfb5760405162461bcd60e51b8152600401610a089190613432565b50600980546001600160a01b0319166001600160a01b0392909216919091179055565b60148054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612e745760405162461bcd60e51b8152600401610a089190613432565b5060098054911515600160a01b0260ff60a01b19909216919091179055565b600c8181548110612ea357600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509116919060ff1684565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612f255760405162461bcd60e51b8152600401610a089190613432565b506001600160a01b03821615612f7e57612f438161105e848661244a565b6001600160a01b038084166000908152600e6020908152604080832093881683529290522055600354612f7690826132f6565b600355612fb5565b612f8b8161105e85611da7565b6001600160a01b038416600090815260086020526040902055600354612fb190826132f6565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167f65adeb76912378393e600cb6f64f3310842a42e1eae86273dc775d0c47a0f2dc84604051612a5291815260200190565b60045460408051808201909152600681526531323033303160d01b60208201526000916001600160a01b038681169116146130525760405162461bcd60e51b8152600401610a089190613432565b506130608361103233611da7565b3360009081526008602052604090205561307d8361105e86611da7565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a906130c290339088908890600401613903565b600060405180830381600087803b1580156130dc57600080fd5b505af11580156130f0573d6000803e3d6000fd5b50506040518681526001600160a01b0388169250339150600080516020613aaf83398151915290602001611161565b6004546000906001600160a01b031633148015906131445750600b5460ff1615156001145b1561317d57604080518082018252600681526531323032303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6000546001600160a01b038581169116148015906131a95750600954600160a01b900460ff1615156001145b156132685760095460005460405163d3da927f60e01b81526001600160a01b038781166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015613202573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132269190613a3b565b60408051808201909152600681526518991819181960d11b60208201529015156001146132665760405162461bcd60e51b8152600401610a089190613432565b505b6132758361103233611da7565b336000908152600860205260409020556132928361105e86611da7565b6001600160a01b038516600081815260086020526040908190209290925590513390600080516020613aaf833981519152906132d19087815260200190565b60405180910390a35060019392505050565b60006132ef828461388a565b9392505050565b60006132ef8284613877565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261332957600080fd5b813567ffffffffffffffff8082111561334457613344613302565b604051601f8301601f19908116603f0116810190828211818310171561336c5761336c613302565b8160405283815286602085880101111561338557600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156133b857600080fd5b82359150602083013567ffffffffffffffff8111156133d657600080fd5b6133e285828601613318565b9150509250929050565b6000815180845260005b81811015613412576020818501810151868301820152016133f6565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006132ef60208301846133ec565b60008083601f84011261345757600080fd5b50813567ffffffffffffffff81111561346f57600080fd5b6020830191508360208260051b850101111561348a57600080fd5b9250929050565b600080600080604085870312156134a757600080fd5b843567ffffffffffffffff808211156134bf57600080fd5b6134cb88838901613445565b909650945060208701359150808211156134e457600080fd5b506134f187828801613445565b95989497509550505050565b801515811461350b57600080fd5b50565b60006020828403121561352057600080fd5b81356132ef816134fd565b80356001600160a01b038116811461354257600080fd5b919050565b60008060006060848603121561355c57600080fd5b6135658461352b565b92506135736020850161352b565b9150604084013590509250925092565b60006020828403121561359557600080fd5b813567ffffffffffffffff8111156135ac57600080fd5b6135b884828501613318565b949350505050565b6000602082840312156135d257600080fd5b6132ef8261352b565b6000602082840312156135ed57600080fd5b5035919050565b6000806040838503121561360757600080fd5b6136108361352b565b946020939093013593505050565b6000806000806080858703121561363457600080fd5b61363d8561352b565b935061364b6020860161352b565b925060408501359150606085013567ffffffffffffffff81111561366e57600080fd5b61367a87828801613318565b91505092959194509250565b60008060006060848603121561369b57600080fd5b6136a48461352b565b925060208401359150604084013567ffffffffffffffff8111156136c757600080fd5b6136d386828701613318565b9150509250925092565b600080600080600080606087890312156136f657600080fd5b863567ffffffffffffffff8082111561370e57600080fd5b61371a8a838b01613445565b9098509650602089013591508082111561373357600080fd5b61373f8a838b01613445565b9096509450604089013591508082111561375857600080fd5b5061376589828a01613445565b979a9699509497509295939492505050565b83815282602082015260606040820152600061379660608301846133ec565b95945050505050565b600080604083850312156137b257600080fd5b6137bb8361352b565b91506137c96020840161352b565b90509250929050565b600080600080600060a086880312156137ea57600080fd5b6137f38661352b565b94506138016020870161352b565b935061380f6040870161352b565b925060608601359150608086013567ffffffffffffffff81111561383257600080fd5b61383e88828901613318565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561239857612398613861565b8181038181111561239857612398613861565b6001600160a01b03848116825283166020820152606060408201819052600090613796908301846133ec565b600181811c908216806138dd57607f821691505b6020821081036138fd57634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b038416815282602082015260606040820152600061379660608301846133ec565b601f821115613976576000816000526020600020601f850160051c810160208610156139535750805b601f850160051c820191505b818110156139725782815560010161395f565b5050505b505050565b815167ffffffffffffffff81111561399557613995613302565b6139a9816139a384546138c9565b8461392a565b602080601f8311600181146139de57600084156139c65750858301515b600019600386901b1c1916600185901b178555613972565b600085815260208120601f198616915b82811015613a0d578886015182559484019460019091019084016139ee565b5085821015613a2b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613a4d57600080fd5b81516132ef816134fd565b8281526040602082015260006135b860408301846133ec565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613aa4908301846133ec565b969550505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212205603470ddfb0f44164cb04123d9c86fdce49166a29e6c4eb3e468b682d39d3df64736f6c63430008170033",
- "deployedBytecode": "608060405234801561001057600080fd5b50600436106104335760003560e01c806381ebdd7911610236578063c7109ec91161013b578063ef4474cd116100c3578063fc590d0911610087578063fc590d09146108fd578063fd0e856914610905578063fd14a22214610919578063fef1b9c01461092c578063ff12dcea1461096c57600080fd5b8063ef4474cd146108b3578063ef8032ef146108bc578063f2fde38b146108cf578063f35eeaef146108e2578063f7502a7c146108ea57600080fd5b8063e7464db11161010a578063e7464db11461085f578063e805005214610872578063eb68757f14610885578063ed62c2a014610898578063ee0cfa40146108a057600080fd5b8063c7109ec914610806578063ca5cbbb514610819578063d5d9d0c71461082c578063db20266f1461083457600080fd5b80639cd23707116101be578063b2a90a601161018d578063b2a90a60146107a6578063b967a52e146107ba578063b9b3e06a146107cd578063bfe30fb0146107e0578063c267ce5f146107f357600080fd5b80639cd237071461075a5780639d8886c81461076d578063a9059cbb14610780578063ab62f92e1461079357600080fd5b8063919fe52d11610205578063919fe52d146106f657806392ff0d31146107095780639301a78b1461071d57806395d89b411461073f57806397e4c5131461074757600080fd5b806381ebdd791461069d5780638ac08bf1146106bd5780638da5cb5b146106d05780638ed8a9bc146106e357600080fd5b806340615cf81161033c5780635f84f302116102c457806370740aab1161029357806370740aab1461065357806370a082311461065b57806376fa7a311461066e5780637c3a00fd146106815780637ed6d1031461068a57600080fd5b80635f84f30214610618578063637834441461062b5780636666e49c1461063e5780636f3b993f1461064657600080fd5b806344fd9caa1161030b57806344fd9caa146105d957806358c3b870146105e257806359d93617146105ea5780635c40f6f4146105f25780635ccef3e71461060557600080fd5b806340615cf81461059857806340d1c441146105ab57806340eba90e146105be578063428630f6146105d157600080fd5b806325287d42116103bf57806331cef4471161038e57806331cef4471461055a578063329dbddc1461056d57806336f7ab5e146105755780633a2b69391461057d5780633b18b9841461058557600080fd5b806325287d421461050c57806325d608611461051f57806327e235e3146105325780632e0ad0041461055257600080fd5b8063153a1f3e11610406578063153a1f3e146104af57806318160ddd146104c25780631935a880146104d9578063200d2ed2146104ec57806323b872dd146104f957600080fd5b8063034f6b211461043857806306eaa0b71461045a57806306fdde031461046f5780630af7eb0f14610484575b600080fd5b6018546104459060ff1681565b60405190151581526020015b60405180910390f35b61046d6104683660046133a5565b61097f565b005b610477610c49565b6040516104519190613432565b600954610497906001600160a01b031681565b6040516001600160a01b039091168152602001610451565b6104456104bd366004613491565b610cd7565b6104cb60035481565b604051908152602001610451565b61046d6104e736600461350e565b610efb565b6007546104459060ff1681565b610445610507366004613547565b610f8d565b600454610497906001600160a01b031681565b61046d61052d366004613583565b611174565b6104cb6105403660046135c0565b60086020526000908152604090205481565b6104776111ce565b61046d6105683660046133a5565b6111db565b610477611356565b610477611363565b610477611370565b61046d6105933660046135db565b61137d565b61046d6105a63660046135f4565b6113fc565b61046d6105b936600461361e565b61149a565b61046d6105cc366004613686565b6115c9565b6104776118b0565b6104cb600f5481565b6104776118bd565b6104776118ca565b61046d61060036600461350e565b6118d7565b61046d6106133660046133a5565b611966565b61046d6106263660046135db565b611ce8565b61046d610639366004613583565b611d37565b610477611d8d565b600b546104459060ff1681565b610477611d9a565b6104cb6106693660046135c0565b611da7565b61046d61067c3660046135c0565b611dc2565b6104cb60105481565b61046d6106983660046136dd565b611e2e565b6104cb6106ab3660046135c0565b600d6020526000908152604090205481565b61046d6106cb366004613583565b611f4b565b600054610497906001600160a01b031681565b61046d6106f1366004613583565b611fa1565b61046d610704366004613583565b611ff7565b60095461044590600160a81b900460ff1681565b61073061072b3660046135c0565b61204d565b60405161045193929190613777565b6104776120f8565b61046d610755366004613583565b612105565b61046d61076836600461350e565b61215b565b61046d61077b3660046136dd565b6121c3565b61044561078e3660046135f4565b6122d7565b61046d6107a1366004613583565b61239e565b60095461044590600160b01b900460ff1681565b61046d6107c8366004613583565b6123f4565b6104cb6107db36600461379f565b61244a565b61046d6107ee36600461361e565b612475565b61046d610801366004613686565b612550565b61046d61081436600461350e565b61262d565b61046d6108273660046137d2565b6126c0565b61046d61280f565b6104cb61084236600461379f565b600e60209081526000928352604080842090915290825290205481565b61046d61086d366004613547565b612891565b6104456108803660046136dd565b612a5f565b61046d610893366004613583565b612b83565b610477612bd9565b61046d6108ae366004613583565b612be6565b6104cb60135481565b61046d6108ca3660046135db565b612c3c565b61046d6108dd3660046135c0565b612cbb565b610477612da5565b61046d6108f83660046135c0565b612db2565b610477612e1e565b60095461044590600160a01b900460ff1681565b61046d61092736600461350e565b612e2b565b61093f61093a3660046135db565b612e93565b604080516001600160a01b0395861681529490931660208501529183015215156060820152608001610451565b61046d61097a366004613547565b612edc565b336001600160a01b0316600c838154811061099c5761099c61384b565b60009182526020909120600490910201546001600160a01b0316148015906109cf57506000546001600160a01b03163314155b15610a1157604080518082018252600681526531323038303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b60405180910390fd5b600c8281548110610a2457610a2461384b565b6000918252602082206003600490920201015460ff1615159003610a765760408051808201825260068152651899181c181960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b600c8281548110610a8957610a8961384b565b90600052602060002090600402016002015460086000600c8581548110610ab257610ab261384b565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610aeb908490613877565b9091555050600c805483908110610b0457610b0461384b565b906000526020600020906004020160020154600d6000600c8581548110610b2d57610b2d61384b565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610b6690849061388a565b925050819055506000600c8381548110610b8257610b8261384b565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817fa0cc3a4feb26502e6e6cd57b2113d58bdab80c6711d8252356be9a49945bb5f7600c8481548110610bdf57610bdf61384b565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110610c1057610c1061384b565b6000918252602090912060016004909202010154604051610c3d92916001600160a01b031690869061389d565b60405180910390a25050565b60018054610c56906138c9565b80601f0160208091040260200160405190810160405280929190818152602001828054610c82906138c9565b8015610ccf5780601f10610ca457610100808354040283529160200191610ccf565b820191906000526020600020905b815481529060010190602001808311610cb257829003601f168201915b505050505081565b6000838214610d1457604080518082018252600681526531323035303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6000805b85811015610d4e57848482818110610d3257610d3261384b565b9050602002013582610d449190613877565b9150600101610d18565b5080610d5933611da7565b1015610d935760408051808201825260068152651899181a981960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b6004546001600160a01b03163314610df45760095460408051808201909152600681526531323035303360d01b602082015290600160a81b900460ff161515600114610df25760405162461bcd60e51b8152600401610a089190613432565b505b606060006001935060005b87811015610eef57610e37898983818110610e1c57610e1c61384b565b9050602002016020810190610e3191906135c0565b3b151590565b15610e8c57610e85898983818110610e5157610e5161384b565b9050602002016020810190610e6691906135c0565b888884818110610e7857610e7861384b565b9050602002013585613004565b9150610ed8565b610ed5898983818110610ea157610ea161384b565b9050602002016020810190610eb691906135c0565b888884818110610ec857610ec861384b565b905060200201358561311f565b91505b811515600003610ee757600094505b600101610dff565b50505050949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610f445760405162461bcd60e51b8152600401610a089190613432565b50600b805460ff19168215159081179091556040519081527fe1455bc53682229469d6919bb96d7b338cbffea93170dfb5f02242c22fb6d07f906020015b60405180910390a150565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610fd75760405162461bcd60e51b8152600401610a089190613432565b5081610fe285611da7565b101561101c57604080518082018252600681526531323036303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6060833b156110e1576110388361103287611da7565b906132e3565b6001600160a01b0386166000908152600860205260409020556110648361105e86611da7565b906132f6565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a906110a990339088908790600401613903565b600060405180830381600087803b1580156110c357600080fd5b505af11580156110d7573d6000803e3d6000fd5b505050505061112e565b6110ee8361103287611da7565b6001600160a01b0386166000908152600860205260409020556111148361105e86611da7565b6001600160a01b0385166000908152600860205260409020555b836001600160a01b0316856001600160a01b0316600080516020613aaf8339815191528560405161116191815260200190565b60405180910390a3506001949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146111bd5760405162461bcd60e51b8152600401610a089190613432565b5060176111ca828261397b565b5050565b601a8054610c56906138c9565b60095460408051808201909152600681526531323130303160d01b602082015290600160b01b900460ff1615156001146112285760405162461bcd60e51b8152600401610a089190613432565b50600954600160a01b900460ff1615156001036112f75760095460005460405163d3da927f60e01b81523360048201526001600160a01b03918216602482015291169063d3da927f90604401602060405180830381865afa158015611291573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b59190613a3b565b60408051808201909152600681526518991898181960d11b60208201529015156001146112f55760405162461bcd60e51b8152600401610a089190613432565b505b336000908152600a60205260409020828155600201611316828261397b565b507f3bb9553f633a7ecb4cbc5f9885e750a522496ce06deff1ed9184180ca83940c033838360405161134a93929190613903565b60405180910390a15050565b60118054610c56906138c9565b60058054610c56906138c9565b60198054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146113c65760405162461bcd60e51b8152600401610a089190613432565b5060138190556040518181527fe451abe602c33e612ea61221b5a142f7fe3c044286e42c8340ffe7fa86a5859790602001610f82565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146114455760405162461bcd60e51b8152600401610a089190613432565b506001600160a01b0382166000818152600a6020908152604091829020600101849055815192835282018390527fa42bd6bdfcb8f9b815c68e4ce0e16dec3f1e7ac53967ee8309653de522a735b1910161134a565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146114e35760405162461bcd60e51b8152600401610a089190613432565b50816114ee84611da7565b101561152857604080518082018252600681526531323136303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6115358261103285611da7565b6001600160a01b03841660009081526008602052604090205561155c8261105e868661244a565b6001600160a01b038086166000818152600e6020908152604080832094891680845294909152908190209390935591517fd7bb89baba75d47cbd55a36bae224d3c630a8d3114860f86a30b484b2af51602906115bb9086908690613a58565b60405180910390a350505050565b600b5460ff1615806115e55750600954600160a81b900460ff16155b806115f75750816115f533611da7565b105b1561163057604080518082018252600681526531323037303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6000546001600160a01b0384811691161480159061165c5750600954600160a01b900460ff1615156001145b1561171b5760095460005460405163d3da927f60e01b81526001600160a01b038681166004830152918216602482015291169063d3da927f90604401602060405180830381865afa1580156116b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d99190613a3b565b6040805180820190915260068152651899181b981960d11b60208201529015156001146117195760405162461bcd60e51b8152600401610a089190613432565b505b336000908152600860205260408120805484929061173a90849061388a565b9091555050336000908152600d60205260408120805484929061175e908490613877565b9091555050600c805460408051608081018252338082526001600160a01b038881166020840190815283850189815260016060860181815290880189556000989098529351600487027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7810180549285166001600160a01b031993841617905591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8830180549190941691161790915591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c983015593517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca909101805491151560ff1990921691909117905551909182917fa256c3bc72c26fbfd6285cfde8c7e345b4d0c7ccfc725d103e9f129c5d8a039a916118a291889088908890613a71565b60405180910390a250505050565b60068054610c56906138c9565b60178054610c56906138c9565b601b8054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146119205760405162461bcd60e51b8152600401610a089190613432565b506007805460ff191682151590811790915560405160ff9091161515907fe1e5c6f5867805bf3fab73f4df4b80d0e87e9262a7bc22ac7c2cb3fd5896222f90600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146119af5760405162461bcd60e51b8152600401610a089190613432565b50600954600160a81b900460ff1615156000036119fa57604080518082018252600681526531323039303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b600c8281548110611a0d57611a0d61384b565b6000918252602082206003600490920201015460ff1615159003611a5f5760408051808201825260068152651899181c981960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b600c8281548110611a7257611a7261384b565b90600052602060002090600402016002015460086000600c8581548110611a9b57611a9b61384b565b60009182526020808320600160049093020191909101546001600160a01b0316835282019290925260400181208054909190611ad8908490613877565b9091555050600c805483908110611af157611af161384b565b906000526020600020906004020160020154600d6000600c8581548110611b1a57611b1a61384b565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190611b5390849061388a565b925050819055506000600c8381548110611b6f57611b6f61384b565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817f6b50d6e4941ce7ae74ed7f7f51df5fb7680754c2815a094c66bea5ca80a40eb1600c8481548110611bcc57611bcc61384b565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110611bfd57611bfd61384b565b6000918252602090912060016004909202010154604051611c2a92916001600160a01b031690869061389d565b60405180910390a2600c8281548110611c4557611c4561384b565b6000918252602090912060016004909202010154600c80546001600160a01b039092169184908110611c7957611c7961384b565b6000918252602090912060049091020154600c80546001600160a01b0390921691600080516020613aaf833981519152919086908110611cbb57611cbb61384b565b906000526020600020906004020160020154604051611cdc91815260200190565b60405180910390a35050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d315760405162461bcd60e51b8152600401610a089190613432565b50601055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d805760405162461bcd60e51b8152600401610a089190613432565b5060116111ca828261397b565b60128054610c56906138c9565b60168054610c56906138c9565b6001600160a01b031660009081526008602052604090205490565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e0b5760405162461bcd60e51b8152600401610a089190613432565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e775760405162461bcd60e51b8152600401610a089190613432565b508483141580611e875750848114155b15611ec057604080518082018252600681526531323134303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b60005b85811015611f4257611f3a878783818110611ee057611ee061384b565b9050602002016020810190611ef591906135c0565b868684818110611f0757611f0761384b565b9050602002016020810190611f1c91906135c0565b858585818110611f2e57611f2e61384b565b90506020020135612891565b600101611ec3565b50505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611f945760405162461bcd60e51b8152600401610a089190613432565b5060196111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611fea5760405162461bcd60e51b8152600401610a089190613432565b5060066111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120405760405162461bcd60e51b8152600401610a089190613432565b50601b6111ca828261397b565b600a6020526000908152604090208054600182015460028301805492939192612075906138c9565b80601f01602080910402602001604051908101604052809291908181526020018280546120a1906138c9565b80156120ee5780601f106120c3576101008083540402835291602001916120ee565b820191906000526020600020905b8154815290600101906020018083116120d157829003601f168201915b5050505050905083565b60028054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461214e5760405162461bcd60e51b8152600401610a089190613432565b50601c6111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146121a45760405162461bcd60e51b8152600401610a089190613432565b5060098054911515600160a81b0260ff60a81b19909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461220c5760405162461bcd60e51b8152600401610a089190613432565b50848314158061221c5750848114155b1561225557604080518082018252600681526531323133303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b60005b85811015611f42576122cf8787838181106122755761227561384b565b905060200201602081019061228a91906135c0565b86868481811061229c5761229c61384b565b90506020020160208101906122b191906135c0565b8585858181106122c3576122c361384b565b90506020020135612edc565b600101612258565b6000816122e333611da7565b10156040518060400160405280600681526020016531323034303160d01b815250906123225760405162461bcd60e51b8152600401610a089190613432565b506009546040805180820190915260068152651899181a181960d11b602082015290600160a81b900460ff1615156001146123705760405162461bcd60e51b8152600401610a089190613432565b506060833b1561238d57612385848483613004565b915050612398565b61238584848361311f565b92915050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146123e75760405162461bcd60e51b8152600401610a089190613432565b50601a6111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461243d5760405162461bcd60e51b8152600401610a089190613432565b5060056111ca828261397b565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205490565b81612480338661244a565b10156124ba57604080518082018252600681526518991818981960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b6124c882611032338761244a565b336000908152600e602090815260408083206001600160a01b03891684529091529020556124f98261105e85611da7565b6001600160a01b038085166000908152600860205260409081902092909255905133918616907f7a1a1088c929a111dda2dc0ca1cc650aa78525d11fd3089abf20c8474f5d82cc906115bb90879087908790613903565b8161255a33611da7565b101561259457604080518082018252600681526518991818181960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b6125a18261103233611da7565b336000818152600860205260409020919091556125c590839061105e90869061244a565b6001600160a01b0384166000818152600e602090815260408083203380855292529182902093909355519091907ecd77abc69e7bbb6de9df8cbfcca8720df3a30decf9eefd187e72ab2ea2f513906126209086908690613a58565b60405180910390a3505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126765760405162461bcd60e51b8152600401610a089190613432565b506009805460ff60b01b1916600160b01b831515908102919091179091556040517fa0c691180b8089c0c84e478ee67d6325768666cd889f13de016771c6f7af1f8890600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146127095760405162461bcd60e51b8152600401610a089190613432565b5081612715868661244a565b101561274f57604080518082018252600681526531323132303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b61275d82611032878761244a565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556127908261105e85611da7565b60086000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550846001600160a01b0316846001600160a01b03167f66b661491f3fe4e137b9e9cf90e142a93be21bc10e70c9b740379a245e4f7d2585858560405161280093929190613903565b60405180910390a35050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128585760405162461bcd60e51b8152600401610a089190613432565b506018805460ff191660011790556040517f96151d7f1d8c50be29a45c0e3ae9ce2008888d1615b196e8f5ffd8c178e6dde890600090a1565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128da5760405162461bcd60e51b8152600401610a089190613432565b506001600160a01b0382161561297857806128f5838561244a565b101561292f57604080518082018252600681526531323131303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b61293d81611032848661244a565b6001600160a01b038084166000908152600e602090815260408083209388168352929052205560035461297090826132e3565b600355612a03565b6001600160a01b0383166000908152600860205260409020548111156129cc57604080518082018252600681526518991898981960d11b6020820152905162461bcd60e51b8152610a089190600401613432565b6129d98161103285611da7565b6001600160a01b0384166000908152600860205260409020556003546129ff90826132e3565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167fee02732fab40ece8284c756220846dff4b8d32058b86b35b4f0459bf172fcef084604051612a5291815260200190565b60405180910390a4505050565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612aa95760405162461bcd60e51b8152600401610a089190613432565b508584141580612ab95750858214155b15612af257604080518082018252600681526531323135303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b60005b86811015612b7557612b6c888883818110612b1257612b1261384b565b9050602002016020810190612b2791906135c0565b878784818110612b3957612b3961384b565b9050602002016020810190612b4e91906135c0565b868685818110612b6057612b6061384b565b90506020020135610f8d565b50600101612af5565b506001979650505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612bcc5760405162461bcd60e51b8152600401610a089190613432565b5060166111ca828261397b565b601c8054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c2f5760405162461bcd60e51b8152600401610a089190613432565b5060126111ca828261397b565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c855760405162461bcd60e51b8152600401610a089190613432565b50600f8190556040518181527f82b19c9a00131a87eeff1903fcb9e4f2a3ba76dd86098586eea921a533e218dc90602001610f82565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612d045760405162461bcd60e51b8152600401610a089190613432565b5060408051808201909152600681526535303031303160d01b60208201526001600160a01b038216612d495760405162461bcd60e51b8152600401610a089190613432565b50600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60158054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612dfb5760405162461bcd60e51b8152600401610a089190613432565b50600980546001600160a01b0319166001600160a01b0392909216919091179055565b60148054610c56906138c9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612e745760405162461bcd60e51b8152600401610a089190613432565b5060098054911515600160a01b0260ff60a01b19909216919091179055565b600c8181548110612ea357600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509116919060ff1684565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612f255760405162461bcd60e51b8152600401610a089190613432565b506001600160a01b03821615612f7e57612f438161105e848661244a565b6001600160a01b038084166000908152600e6020908152604080832093881683529290522055600354612f7690826132f6565b600355612fb5565b612f8b8161105e85611da7565b6001600160a01b038416600090815260086020526040902055600354612fb190826132f6565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167f65adeb76912378393e600cb6f64f3310842a42e1eae86273dc775d0c47a0f2dc84604051612a5291815260200190565b60045460408051808201909152600681526531323033303160d01b60208201526000916001600160a01b038681169116146130525760405162461bcd60e51b8152600401610a089190613432565b506130608361103233611da7565b3360009081526008602052604090205561307d8361105e86611da7565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a906130c290339088908890600401613903565b600060405180830381600087803b1580156130dc57600080fd5b505af11580156130f0573d6000803e3d6000fd5b50506040518681526001600160a01b0388169250339150600080516020613aaf83398151915290602001611161565b6004546000906001600160a01b031633148015906131445750600b5460ff1615156001145b1561317d57604080518082018252600681526531323032303160d01b6020820152905162461bcd60e51b8152610a089190600401613432565b6000546001600160a01b038581169116148015906131a95750600954600160a01b900460ff1615156001145b156132685760095460005460405163d3da927f60e01b81526001600160a01b038781166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015613202573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132269190613a3b565b60408051808201909152600681526518991819181960d11b60208201529015156001146132665760405162461bcd60e51b8152600401610a089190613432565b505b6132758361103233611da7565b336000908152600860205260409020556132928361105e86611da7565b6001600160a01b038516600081815260086020526040908190209290925590513390600080516020613aaf833981519152906132d19087815260200190565b60405180910390a35060019392505050565b60006132ef828461388a565b9392505050565b60006132ef8284613877565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261332957600080fd5b813567ffffffffffffffff8082111561334457613344613302565b604051601f8301601f19908116603f0116810190828211818310171561336c5761336c613302565b8160405283815286602085880101111561338557600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156133b857600080fd5b82359150602083013567ffffffffffffffff8111156133d657600080fd5b6133e285828601613318565b9150509250929050565b6000815180845260005b81811015613412576020818501810151868301820152016133f6565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006132ef60208301846133ec565b60008083601f84011261345757600080fd5b50813567ffffffffffffffff81111561346f57600080fd5b6020830191508360208260051b850101111561348a57600080fd5b9250929050565b600080600080604085870312156134a757600080fd5b843567ffffffffffffffff808211156134bf57600080fd5b6134cb88838901613445565b909650945060208701359150808211156134e457600080fd5b506134f187828801613445565b95989497509550505050565b801515811461350b57600080fd5b50565b60006020828403121561352057600080fd5b81356132ef816134fd565b80356001600160a01b038116811461354257600080fd5b919050565b60008060006060848603121561355c57600080fd5b6135658461352b565b92506135736020850161352b565b9150604084013590509250925092565b60006020828403121561359557600080fd5b813567ffffffffffffffff8111156135ac57600080fd5b6135b884828501613318565b949350505050565b6000602082840312156135d257600080fd5b6132ef8261352b565b6000602082840312156135ed57600080fd5b5035919050565b6000806040838503121561360757600080fd5b6136108361352b565b946020939093013593505050565b6000806000806080858703121561363457600080fd5b61363d8561352b565b935061364b6020860161352b565b925060408501359150606085013567ffffffffffffffff81111561366e57600080fd5b61367a87828801613318565b91505092959194509250565b60008060006060848603121561369b57600080fd5b6136a48461352b565b925060208401359150604084013567ffffffffffffffff8111156136c757600080fd5b6136d386828701613318565b9150509250925092565b600080600080600080606087890312156136f657600080fd5b863567ffffffffffffffff8082111561370e57600080fd5b61371a8a838b01613445565b9098509650602089013591508082111561373357600080fd5b61373f8a838b01613445565b9096509450604089013591508082111561375857600080fd5b5061376589828a01613445565b979a9699509497509295939492505050565b83815282602082015260606040820152600061379660608301846133ec565b95945050505050565b600080604083850312156137b257600080fd5b6137bb8361352b565b91506137c96020840161352b565b90509250929050565b600080600080600060a086880312156137ea57600080fd5b6137f38661352b565b94506138016020870161352b565b935061380f6040870161352b565b925060608601359150608086013567ffffffffffffffff81111561383257600080fd5b61383e88828901613318565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561239857612398613861565b8181038181111561239857612398613861565b6001600160a01b03848116825283166020820152606060408201819052600090613796908301846133ec565b600181811c908216806138dd57607f821691505b6020821081036138fd57634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b038416815282602082015260606040820152600061379660608301846133ec565b601f821115613976576000816000526020600020601f850160051c810160208610156139535750805b601f850160051c820191505b818110156139725782815560010161395f565b5050505b505050565b815167ffffffffffffffff81111561399557613995613302565b6139a9816139a384546138c9565b8461392a565b602080601f8311600181146139de57600084156139c65750858301515b600019600386901b1c1916600185901b178555613972565b600085815260208120601f198616915b82811015613a0d578886015182559484019460019091019084016139ee565b5085821015613a2b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613a4d57600080fd5b81516132ef816134fd565b8281526040602082015260006135b860408301846133ec565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613aa4908301846133ec565b969550505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212205603470ddfb0f44164cb04123d9c86fdce49166a29e6c4eb3e468b682d39d3df64736f6c63430008170033"
+ "bytecode": "60806040523480156200001157600080fd5b506040516200416f3803806200416f8339810160408190526200003491620001f5565b600080546001600160a01b0319908116339182161717905560016200005a8c8262000431565b506002620000698b8262000431565b506003899055600f889055601962000082888262000431565b50601262000091878262000431565b506013859055601b620000a5858262000431565b506014620000b4848262000431565b506015620000c3838262000431565b506016620000d2828262000431565b5050600354600080546001600160a01b031681526008602052604090205550506018805460ff1990811690915560078054909116600117905550506009805460ff60a01b1916600160a01b17905550620004fd945050505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200015557600080fd5b81516001600160401b03808211156200017257620001726200012d565b604051601f8301601f19908116603f011681019082821181831017156200019d576200019d6200012d565b8160405283815260209250866020858801011115620001bb57600080fd5b600091505b83821015620001df5785820183015181830184015290820190620001c0565b6000602085830101528094505050505092915050565b60008060008060008060008060008060006101608c8e0312156200021857600080fd5b8b516001600160401b038111156200022f57600080fd5b6200023d8e828f0162000143565b60208e0151909c5090506001600160401b038111156200025c57600080fd5b6200026a8e828f0162000143565b9a505060408c0151985060608c0151975060808c015160018060401b038111156200029457600080fd5b620002a28e828f0162000143565b60a08e015190985090506001600160401b03811115620002c157600080fd5b620002cf8e828f0162000143565b60c08e015160e08f0151919850965090506001600160401b03811115620002f557600080fd5b620003038e828f0162000143565b6101008e015190955090506001600160401b038111156200032357600080fd5b620003318e828f0162000143565b6101208e015190945090506001600160401b038111156200035157600080fd5b6200035f8e828f0162000143565b6101408e015190935090506001600160401b038111156200037f57600080fd5b6200038d8e828f0162000143565b9150509295989b509295989b9093969950565b600181811c90821680620003b557607f821691505b602082108103620003d657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200042c576000816000526020600020601f850160051c81016020861015620004075750805b601f850160051c820191505b81811015620004285782815560010162000413565b5050505b505050565b81516001600160401b038111156200044d576200044d6200012d565b62000465816200045e8454620003a0565b84620003dc565b602080601f8311600181146200049d5760008415620004845750858301515b600019600386901b1c1916600185901b17855562000428565b600085815260208120601f198616915b82811015620004ce57888601518255948401946001909101908401620004ad565b5085821015620004ed5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613c62806200050d6000396000f3fe608060405234801561001057600080fd5b506004361061043e5760003560e01c80638ac08bf111610236578063ca5cbbb51161013b578063ef4474cd116100c3578063fc590d0911610087578063fc590d091461091b578063fd0e856914610923578063fd14a22214610937578063fef1b9c01461094a578063ff12dcea1461098a57600080fd5b8063ef4474cd146108d1578063ef8032ef146108da578063f2fde38b146108ed578063f35eeaef14610900578063f7502a7c1461090857600080fd5b8063e7464db11161010a578063e7464db11461087d578063e805005214610890578063eb68757f146108a3578063ed62c2a0146108b6578063ee0cfa40146108be57600080fd5b8063ca5cbbb514610824578063d5d9d0c714610837578063d87f09861461083f578063db20266f1461085257600080fd5b80639d8886c8116101be578063b967a52e1161018d578063b967a52e146107c5578063b9b3e06a146107d8578063bfe30fb0146107eb578063c267ce5f146107fe578063c7109ec91461081157600080fd5b80639d8886c814610778578063a9059cbb1461078b578063ab62f92e1461079e578063b2a90a60146107b157600080fd5b806392ff0d311161020557806392ff0d31146107145780639301a78b1461072857806395d89b411461074a57806397e4c513146107525780639cd237071461076557600080fd5b80638ac08bf1146106c85780638da5cb5b146106db5780638ed8a9bc146106ee578063919fe52d1461070157600080fd5b806340615cf8116103475780635f84f302116102cf57806370a082311161029357806370a082311461066657806376fa7a31146106795780637c3a00fd1461068c5780637ed6d1031461069557806381ebdd79146106a857600080fd5b80635f84f3021461062357806363783444146106365780636666e49c146106495780636f3b993f1461065157806370740aab1461065e57600080fd5b806344fd9caa1161031657806344fd9caa146105e457806358c3b870146105ed57806359d93617146105f55780635c40f6f4146105fd5780635ccef3e71461061057600080fd5b806340615cf8146105a357806340d1c441146105b657806340eba90e146105c9578063428630f6146105dc57600080fd5b806325287d42116103ca57806331cef4471161039957806331cef44714610565578063329dbddc1461057857806336f7ab5e146105805780633a2b6939146105885780633b18b9841461059057600080fd5b806325287d421461051757806325d608611461052a57806327e235e31461053d5780632e0ad0041461055d57600080fd5b8063153a1f3e11610411578063153a1f3e146104ba57806318160ddd146104cd5780631935a880146104e4578063200d2ed2146104f757806323b872dd1461050457600080fd5b8063034f6b211461044357806306eaa0b71461046557806306fdde031461047a5780630af7eb0f1461048f575b600080fd5b6018546104509060ff1681565b60405190151581526020015b60405180910390f35b610478610473366004613503565b61099d565b005b610482610c67565b60405161045c9190613590565b6009546104a2906001600160a01b031681565b6040516001600160a01b03909116815260200161045c565b6104506104c83660046135ef565b610cf5565b6104d660035481565b60405190815260200161045c565b6104786104f236600461366c565b610f19565b6007546104509060ff1681565b6104506105123660046136a5565b610fab565b6004546104a2906001600160a01b031681565b6104786105383660046136e1565b611192565b6104d661054b36600461371e565b60086020526000908152604090205481565b6104826111ec565b610478610573366004613503565b6111f9565b610482611374565b610482611381565b61048261138e565b61047861059e366004613739565b61139b565b6104786105b1366004613752565b61141a565b6104786105c436600461377c565b6114b8565b6104786105d73660046137e4565b6115e7565b6104826118ce565b6104d6600f5481565b6104826118db565b6104826118e8565b61047861060b36600461366c565b6118f5565b61047861061e366004613503565b611984565b610478610631366004613739565b611d06565b6104786106443660046136e1565b611d55565b610482611dab565b600b546104509060ff1681565b610482611db8565b6104d661067436600461371e565b611dc5565b61047861068736600461371e565b611de0565b6104d660105481565b6104786106a336600461383b565b611e4c565b6104d66106b636600461371e565b600d6020526000908152604090205481565b6104786106d63660046136e1565b611f69565b6000546104a2906001600160a01b031681565b6104786106fc3660046136e1565b611fbf565b61047861070f3660046136e1565b612015565b60095461045090600160a81b900460ff1681565b61073b61073636600461371e565b61206b565b60405161045c939291906138d5565b610482612116565b6104786107603660046136e1565b612123565b61047861077336600461366c565b612179565b61047861078636600461383b565b6121e1565b610450610799366004613752565b6122f5565b6104786107ac3660046136e1565b6123bc565b60095461045090600160b01b900460ff1681565b6104786107d33660046136e1565b612412565b6104d66107e63660046138fd565b612468565b6104786107f936600461377c565b612493565b61047861080c3660046137e4565b61256e565b61047861081f36600461366c565b61264b565b610478610832366004613930565b6126de565b61047861282d565b61047861084d366004613930565b6128af565b6104d66108603660046138fd565b600e60209081526000928352604080842090915290825290205481565b61047861088b3660046136a5565b6129ef565b61045061089e36600461383b565b612bbd565b6104786108b13660046136e1565b612ce1565b610482612d37565b6104786108cc3660046136e1565b612d44565b6104d660135481565b6104786108e8366004613739565b612d9a565b6104786108fb36600461371e565b612e19565b610482612f03565b61047861091636600461371e565b612f10565b610482612f7c565b60095461045090600160a01b900460ff1681565b61047861094536600461366c565b612f89565b61095d610958366004613739565b612ff1565b604080516001600160a01b039586168152949093166020850152918301521515606082015260800161045c565b6104786109983660046136a5565b61303a565b336001600160a01b0316600c83815481106109ba576109ba6139a9565b60009182526020909120600490910201546001600160a01b0316148015906109ed57506000546001600160a01b03163314155b15610a2f57604080518082018252600681526531323038303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b60405180910390fd5b600c8281548110610a4257610a426139a9565b6000918252602082206003600490920201015460ff1615159003610a945760408051808201825260068152651899181c181960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b600c8281548110610aa757610aa76139a9565b90600052602060002090600402016002015460086000600c8581548110610ad057610ad06139a9565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610b099084906139d5565b9091555050600c805483908110610b2257610b226139a9565b906000526020600020906004020160020154600d6000600c8581548110610b4b57610b4b6139a9565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610b849084906139e8565b925050819055506000600c8381548110610ba057610ba06139a9565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817fa0cc3a4feb26502e6e6cd57b2113d58bdab80c6711d8252356be9a49945bb5f7600c8481548110610bfd57610bfd6139a9565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110610c2e57610c2e6139a9565b6000918252602090912060016004909202010154604051610c5b92916001600160a01b03169086906139fb565b60405180910390a25050565b60018054610c7490613a27565b80601f0160208091040260200160405190810160405280929190818152602001828054610ca090613a27565b8015610ced5780601f10610cc257610100808354040283529160200191610ced565b820191906000526020600020905b815481529060010190602001808311610cd057829003601f168201915b505050505081565b6000838214610d3257604080518082018252600681526531323035303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6000805b85811015610d6c57848482818110610d5057610d506139a9565b9050602002013582610d6291906139d5565b9150600101610d36565b5080610d7733611dc5565b1015610db15760408051808201825260068152651899181a981960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b6004546001600160a01b03163314610e125760095460408051808201909152600681526531323035303360d01b602082015290600160a81b900460ff161515600114610e105760405162461bcd60e51b8152600401610a269190613590565b505b606060006001935060005b87811015610f0d57610e55898983818110610e3a57610e3a6139a9565b9050602002016020810190610e4f919061371e565b3b151590565b15610eaa57610ea3898983818110610e6f57610e6f6139a9565b9050602002016020810190610e84919061371e565b888884818110610e9657610e966139a9565b9050602002013585613162565b9150610ef6565b610ef3898983818110610ebf57610ebf6139a9565b9050602002016020810190610ed4919061371e565b888884818110610ee657610ee66139a9565b905060200201358561327d565b91505b811515600003610f0557600094505b600101610e1d565b50505050949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610f625760405162461bcd60e51b8152600401610a269190613590565b50600b805460ff19168215159081179091556040519081527fe1455bc53682229469d6919bb96d7b338cbffea93170dfb5f02242c22fb6d07f906020015b60405180910390a150565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610ff55760405162461bcd60e51b8152600401610a269190613590565b508161100085611dc5565b101561103a57604080518082018252600681526531323036303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6060833b156110ff576110568361105087611dc5565b90613441565b6001600160a01b0386166000908152600860205260409020556110828361107c86611dc5565b90613454565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a906110c790339088908790600401613a61565b600060405180830381600087803b1580156110e157600080fd5b505af11580156110f5573d6000803e3d6000fd5b505050505061114c565b61110c8361105087611dc5565b6001600160a01b0386166000908152600860205260409020556111328361107c86611dc5565b6001600160a01b0385166000908152600860205260409020555b836001600160a01b0316856001600160a01b0316600080516020613c0d8339815191528560405161117f91815260200190565b60405180910390a3506001949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146111db5760405162461bcd60e51b8152600401610a269190613590565b5060176111e88282613ad9565b5050565b601a8054610c7490613a27565b60095460408051808201909152600681526531323130303160d01b602082015290600160b01b900460ff1615156001146112465760405162461bcd60e51b8152600401610a269190613590565b50600954600160a01b900460ff1615156001036113155760095460005460405163d3da927f60e01b81523360048201526001600160a01b03918216602482015291169063d3da927f90604401602060405180830381865afa1580156112af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d39190613b99565b60408051808201909152600681526518991898181960d11b60208201529015156001146113135760405162461bcd60e51b8152600401610a269190613590565b505b336000908152600a602052604090208281556002016113348282613ad9565b507f3bb9553f633a7ecb4cbc5f9885e750a522496ce06deff1ed9184180ca83940c033838360405161136893929190613a61565b60405180910390a15050565b60118054610c7490613a27565b60058054610c7490613a27565b60198054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146113e45760405162461bcd60e51b8152600401610a269190613590565b5060138190556040518181527fe451abe602c33e612ea61221b5a142f7fe3c044286e42c8340ffe7fa86a5859790602001610fa0565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146114635760405162461bcd60e51b8152600401610a269190613590565b506001600160a01b0382166000818152600a6020908152604091829020600101849055815192835282018390527fa42bd6bdfcb8f9b815c68e4ce0e16dec3f1e7ac53967ee8309653de522a735b19101611368565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146115015760405162461bcd60e51b8152600401610a269190613590565b508161150c84611dc5565b101561154657604080518082018252600681526531323136303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6115538261105085611dc5565b6001600160a01b03841660009081526008602052604090205561157a8261107c8686612468565b6001600160a01b038086166000818152600e6020908152604080832094891680845294909152908190209390935591517fd7bb89baba75d47cbd55a36bae224d3c630a8d3114860f86a30b484b2af51602906115d99086908690613bb6565b60405180910390a350505050565b600b5460ff1615806116035750600954600160a81b900460ff16155b8061161557508161161333611dc5565b105b1561164e57604080518082018252600681526531323037303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6000546001600160a01b0384811691161480159061167a5750600954600160a01b900460ff1615156001145b156117395760095460005460405163d3da927f60e01b81526001600160a01b038681166004830152918216602482015291169063d3da927f90604401602060405180830381865afa1580156116d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f79190613b99565b6040805180820190915260068152651899181b981960d11b60208201529015156001146117375760405162461bcd60e51b8152600401610a269190613590565b505b33600090815260086020526040812080548492906117589084906139e8565b9091555050336000908152600d60205260408120805484929061177c9084906139d5565b9091555050600c805460408051608081018252338082526001600160a01b038881166020840190815283850189815260016060860181815290880189556000989098529351600487027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7810180549285166001600160a01b031993841617905591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8830180549190941691161790915591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c983015593517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca909101805491151560ff1990921691909117905551909182917fa256c3bc72c26fbfd6285cfde8c7e345b4d0c7ccfc725d103e9f129c5d8a039a916118c091889088908890613bcf565b60405180910390a250505050565b60068054610c7490613a27565b60178054610c7490613a27565b601b8054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461193e5760405162461bcd60e51b8152600401610a269190613590565b506007805460ff191682151590811790915560405160ff9091161515907fe1e5c6f5867805bf3fab73f4df4b80d0e87e9262a7bc22ac7c2cb3fd5896222f90600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146119cd5760405162461bcd60e51b8152600401610a269190613590565b50600954600160a81b900460ff161515600003611a1857604080518082018252600681526531323039303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b600c8281548110611a2b57611a2b6139a9565b6000918252602082206003600490920201015460ff1615159003611a7d5760408051808201825260068152651899181c981960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b600c8281548110611a9057611a906139a9565b90600052602060002090600402016002015460086000600c8581548110611ab957611ab96139a9565b60009182526020808320600160049093020191909101546001600160a01b0316835282019290925260400181208054909190611af69084906139d5565b9091555050600c805483908110611b0f57611b0f6139a9565b906000526020600020906004020160020154600d6000600c8581548110611b3857611b386139a9565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190611b719084906139e8565b925050819055506000600c8381548110611b8d57611b8d6139a9565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817f6b50d6e4941ce7ae74ed7f7f51df5fb7680754c2815a094c66bea5ca80a40eb1600c8481548110611bea57611bea6139a9565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110611c1b57611c1b6139a9565b6000918252602090912060016004909202010154604051611c4892916001600160a01b03169086906139fb565b60405180910390a2600c8281548110611c6357611c636139a9565b6000918252602090912060016004909202010154600c80546001600160a01b039092169184908110611c9757611c976139a9565b6000918252602090912060049091020154600c80546001600160a01b0390921691600080516020613c0d833981519152919086908110611cd957611cd96139a9565b906000526020600020906004020160020154604051611cfa91815260200190565b60405180910390a35050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d4f5760405162461bcd60e51b8152600401610a269190613590565b50601055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d9e5760405162461bcd60e51b8152600401610a269190613590565b5060116111e88282613ad9565b60128054610c7490613a27565b60168054610c7490613a27565b6001600160a01b031660009081526008602052604090205490565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e295760405162461bcd60e51b8152600401610a269190613590565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e955760405162461bcd60e51b8152600401610a269190613590565b508483141580611ea55750848114155b15611ede57604080518082018252600681526531323134303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b60005b85811015611f6057611f58878783818110611efe57611efe6139a9565b9050602002016020810190611f13919061371e565b868684818110611f2557611f256139a9565b9050602002016020810190611f3a919061371e565b858585818110611f4c57611f4c6139a9565b905060200201356129ef565b600101611ee1565b50505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611fb25760405162461bcd60e51b8152600401610a269190613590565b5060196111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120085760405162461bcd60e51b8152600401610a269190613590565b5060066111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461205e5760405162461bcd60e51b8152600401610a269190613590565b50601b6111e88282613ad9565b600a602052600090815260409020805460018201546002830180549293919261209390613a27565b80601f01602080910402602001604051908101604052809291908181526020018280546120bf90613a27565b801561210c5780601f106120e15761010080835404028352916020019161210c565b820191906000526020600020905b8154815290600101906020018083116120ef57829003601f168201915b5050505050905083565b60028054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461216c5760405162461bcd60e51b8152600401610a269190613590565b50601c6111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146121c25760405162461bcd60e51b8152600401610a269190613590565b5060098054911515600160a81b0260ff60a81b19909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461222a5760405162461bcd60e51b8152600401610a269190613590565b50848314158061223a5750848114155b1561227357604080518082018252600681526531323133303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b60005b85811015611f60576122ed878783818110612293576122936139a9565b90506020020160208101906122a8919061371e565b8686848181106122ba576122ba6139a9565b90506020020160208101906122cf919061371e565b8585858181106122e1576122e16139a9565b9050602002013561303a565b600101612276565b60008161230133611dc5565b10156040518060400160405280600681526020016531323034303160d01b815250906123405760405162461bcd60e51b8152600401610a269190613590565b506009546040805180820190915260068152651899181a181960d11b602082015290600160a81b900460ff16151560011461238e5760405162461bcd60e51b8152600401610a269190613590565b506060833b156123ab576123a3848483613162565b9150506123b6565b6123a384848361327d565b92915050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146124055760405162461bcd60e51b8152600401610a269190613590565b50601a6111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461245b5760405162461bcd60e51b8152600401610a269190613590565b5060056111e88282613ad9565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205490565b8161249e3386612468565b10156124d857604080518082018252600681526518991818981960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b6124e6826110503387612468565b336000908152600e602090815260408083206001600160a01b03891684529091529020556125178261107c85611dc5565b6001600160a01b038085166000908152600860205260409081902092909255905133918616907f7a1a1088c929a111dda2dc0ca1cc650aa78525d11fd3089abf20c8474f5d82cc906115d990879087908790613a61565b8161257833611dc5565b10156125b257604080518082018252600681526518991818181960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b6125bf8261105033611dc5565b336000818152600860205260409020919091556125e390839061107c908690612468565b6001600160a01b0384166000818152600e602090815260408083203380855292529182902093909355519091907ecd77abc69e7bbb6de9df8cbfcca8720df3a30decf9eefd187e72ab2ea2f5139061263e9086908690613bb6565b60405180910390a3505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126945760405162461bcd60e51b8152600401610a269190613590565b506009805460ff60b01b1916600160b01b831515908102919091179091556040517fa0c691180b8089c0c84e478ee67d6325768666cd889f13de016771c6f7af1f8890600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146127275760405162461bcd60e51b8152600401610a269190613590565b50816127338686612468565b101561276d57604080518082018252600681526531323132303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b61277b826110508787612468565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556127ae8261107c85611dc5565b60086000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550846001600160a01b0316846001600160a01b03167f66b661491f3fe4e137b9e9cf90e142a93be21bc10e70c9b740379a245e4f7d2585858560405161281e93929190613a61565b60405180910390a35050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128765760405162461bcd60e51b8152600401610a269190613590565b506018805460ff191660011790556040517f96151d7f1d8c50be29a45c0e3ae9ce2008888d1615b196e8f5ffd8c178e6dde890600090a1565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128f85760405162461bcd60e51b8152600401610a269190613590565b50816129048686612468565b101561293e57604080518082018252600681526531323137303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b61294c826110508787612468565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556129808261107c8786612468565b6001600160a01b038087166000818152600e602090815260408083208986168085529252918290209490945551918716917f5847ffcc1bce0ecfdd115863db8562df2b18b61698938e251adf381774e9e3be906129e09087908790613bb6565b60405180910390a45050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612a385760405162461bcd60e51b8152600401610a269190613590565b506001600160a01b03821615612ad65780612a538385612468565b1015612a8d57604080518082018252600681526531323131303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b612a9b816110508486612468565b6001600160a01b038084166000908152600e6020908152604080832093881683529290522055600354612ace9082613441565b600355612b61565b6001600160a01b038316600090815260086020526040902054811115612b2a57604080518082018252600681526518991898981960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b612b378161105085611dc5565b6001600160a01b038416600090815260086020526040902055600354612b5d9082613441565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167fee02732fab40ece8284c756220846dff4b8d32058b86b35b4f0459bf172fcef084604051612bb091815260200190565b60405180910390a4505050565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c075760405162461bcd60e51b8152600401610a269190613590565b508584141580612c175750858214155b15612c5057604080518082018252600681526531323135303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b60005b86811015612cd357612cca888883818110612c7057612c706139a9565b9050602002016020810190612c85919061371e565b878784818110612c9757612c976139a9565b9050602002016020810190612cac919061371e565b868685818110612cbe57612cbe6139a9565b90506020020135610fab565b50600101612c53565b506001979650505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612d2a5760405162461bcd60e51b8152600401610a269190613590565b5060166111e88282613ad9565b601c8054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612d8d5760405162461bcd60e51b8152600401610a269190613590565b5060126111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612de35760405162461bcd60e51b8152600401610a269190613590565b50600f8190556040518181527f82b19c9a00131a87eeff1903fcb9e4f2a3ba76dd86098586eea921a533e218dc90602001610fa0565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612e625760405162461bcd60e51b8152600401610a269190613590565b5060408051808201909152600681526535303031303160d01b60208201526001600160a01b038216612ea75760405162461bcd60e51b8152600401610a269190613590565b50600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60158054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612f595760405162461bcd60e51b8152600401610a269190613590565b50600980546001600160a01b0319166001600160a01b0392909216919091179055565b60148054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612fd25760405162461bcd60e51b8152600401610a269190613590565b5060098054911515600160a01b0260ff60a01b19909216919091179055565b600c818154811061300157600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509116919060ff1684565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146130835760405162461bcd60e51b8152600401610a269190613590565b506001600160a01b038216156130dc576130a18161107c8486612468565b6001600160a01b038084166000908152600e60209081526040808320938816835292905220556003546130d49082613454565b600355613113565b6130e98161107c85611dc5565b6001600160a01b03841660009081526008602052604090205560035461310f9082613454565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167f65adeb76912378393e600cb6f64f3310842a42e1eae86273dc775d0c47a0f2dc84604051612bb091815260200190565b60045460408051808201909152600681526531323033303160d01b60208201526000916001600160a01b038681169116146131b05760405162461bcd60e51b8152600401610a269190613590565b506131be8361105033611dc5565b336000908152600860205260409020556131db8361107c86611dc5565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a9061322090339088908890600401613a61565b600060405180830381600087803b15801561323a57600080fd5b505af115801561324e573d6000803e3d6000fd5b50506040518681526001600160a01b0388169250339150600080516020613c0d8339815191529060200161117f565b6004546000906001600160a01b031633148015906132a25750600b5460ff1615156001145b156132db57604080518082018252600681526531323032303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6000546001600160a01b038581169116148015906133075750600954600160a01b900460ff1615156001145b156133c65760095460005460405163d3da927f60e01b81526001600160a01b038781166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015613360573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133849190613b99565b60408051808201909152600681526518991819181960d11b60208201529015156001146133c45760405162461bcd60e51b8152600401610a269190613590565b505b6133d38361105033611dc5565b336000908152600860205260409020556133f08361107c86611dc5565b6001600160a01b038516600081815260086020526040908190209290925590513390600080516020613c0d8339815191529061342f9087815260200190565b60405180910390a35060019392505050565b600061344d82846139e8565b9392505050565b600061344d82846139d5565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261348757600080fd5b813567ffffffffffffffff808211156134a2576134a2613460565b604051601f8301601f19908116603f011681019082821181831017156134ca576134ca613460565b816040528381528660208588010111156134e357600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561351657600080fd5b82359150602083013567ffffffffffffffff81111561353457600080fd5b61354085828601613476565b9150509250929050565b6000815180845260005b8181101561357057602081850181015186830182015201613554565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061344d602083018461354a565b60008083601f8401126135b557600080fd5b50813567ffffffffffffffff8111156135cd57600080fd5b6020830191508360208260051b85010111156135e857600080fd5b9250929050565b6000806000806040858703121561360557600080fd5b843567ffffffffffffffff8082111561361d57600080fd5b613629888389016135a3565b9096509450602087013591508082111561364257600080fd5b5061364f878288016135a3565b95989497509550505050565b801515811461366957600080fd5b50565b60006020828403121561367e57600080fd5b813561344d8161365b565b80356001600160a01b03811681146136a057600080fd5b919050565b6000806000606084860312156136ba57600080fd5b6136c384613689565b92506136d160208501613689565b9150604084013590509250925092565b6000602082840312156136f357600080fd5b813567ffffffffffffffff81111561370a57600080fd5b61371684828501613476565b949350505050565b60006020828403121561373057600080fd5b61344d82613689565b60006020828403121561374b57600080fd5b5035919050565b6000806040838503121561376557600080fd5b61376e83613689565b946020939093013593505050565b6000806000806080858703121561379257600080fd5b61379b85613689565b93506137a960208601613689565b925060408501359150606085013567ffffffffffffffff8111156137cc57600080fd5b6137d887828801613476565b91505092959194509250565b6000806000606084860312156137f957600080fd5b61380284613689565b925060208401359150604084013567ffffffffffffffff81111561382557600080fd5b61383186828701613476565b9150509250925092565b6000806000806000806060878903121561385457600080fd5b863567ffffffffffffffff8082111561386c57600080fd5b6138788a838b016135a3565b9098509650602089013591508082111561389157600080fd5b61389d8a838b016135a3565b909650945060408901359150808211156138b657600080fd5b506138c389828a016135a3565b979a9699509497509295939492505050565b8381528260208201526060604082015260006138f4606083018461354a565b95945050505050565b6000806040838503121561391057600080fd5b61391983613689565b915061392760208401613689565b90509250929050565b600080600080600060a0868803121561394857600080fd5b61395186613689565b945061395f60208701613689565b935061396d60408701613689565b925060608601359150608086013567ffffffffffffffff81111561399057600080fd5b61399c88828901613476565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156123b6576123b66139bf565b818103818111156123b6576123b66139bf565b6001600160a01b038481168252831660208201526060604082018190526000906138f49083018461354a565b600181811c90821680613a3b57607f821691505b602082108103613a5b57634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b03841681528260208201526060604082015260006138f4606083018461354a565b601f821115613ad4576000816000526020600020601f850160051c81016020861015613ab15750805b601f850160051c820191505b81811015613ad057828155600101613abd565b5050505b505050565b815167ffffffffffffffff811115613af357613af3613460565b613b0781613b018454613a27565b84613a88565b602080601f831160018114613b3c5760008415613b245750858301515b600019600386901b1c1916600185901b178555613ad0565b600085815260208120601f198616915b82811015613b6b57888601518255948401946001909101908401613b4c565b5085821015613b895787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613bab57600080fd5b815161344d8161365b565b828152604060208201526000613716604083018461354a565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613c029083018461354a565b969550505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122061defbbe8b73a970d84efe79630b66e96950d98e87fcc71249e9eba64f55024464736f6c63430008170033",
+ "deployedBytecode": "608060405234801561001057600080fd5b506004361061043e5760003560e01c80638ac08bf111610236578063ca5cbbb51161013b578063ef4474cd116100c3578063fc590d0911610087578063fc590d091461091b578063fd0e856914610923578063fd14a22214610937578063fef1b9c01461094a578063ff12dcea1461098a57600080fd5b8063ef4474cd146108d1578063ef8032ef146108da578063f2fde38b146108ed578063f35eeaef14610900578063f7502a7c1461090857600080fd5b8063e7464db11161010a578063e7464db11461087d578063e805005214610890578063eb68757f146108a3578063ed62c2a0146108b6578063ee0cfa40146108be57600080fd5b8063ca5cbbb514610824578063d5d9d0c714610837578063d87f09861461083f578063db20266f1461085257600080fd5b80639d8886c8116101be578063b967a52e1161018d578063b967a52e146107c5578063b9b3e06a146107d8578063bfe30fb0146107eb578063c267ce5f146107fe578063c7109ec91461081157600080fd5b80639d8886c814610778578063a9059cbb1461078b578063ab62f92e1461079e578063b2a90a60146107b157600080fd5b806392ff0d311161020557806392ff0d31146107145780639301a78b1461072857806395d89b411461074a57806397e4c513146107525780639cd237071461076557600080fd5b80638ac08bf1146106c85780638da5cb5b146106db5780638ed8a9bc146106ee578063919fe52d1461070157600080fd5b806340615cf8116103475780635f84f302116102cf57806370a082311161029357806370a082311461066657806376fa7a31146106795780637c3a00fd1461068c5780637ed6d1031461069557806381ebdd79146106a857600080fd5b80635f84f3021461062357806363783444146106365780636666e49c146106495780636f3b993f1461065157806370740aab1461065e57600080fd5b806344fd9caa1161031657806344fd9caa146105e457806358c3b870146105ed57806359d93617146105f55780635c40f6f4146105fd5780635ccef3e71461061057600080fd5b806340615cf8146105a357806340d1c441146105b657806340eba90e146105c9578063428630f6146105dc57600080fd5b806325287d42116103ca57806331cef4471161039957806331cef44714610565578063329dbddc1461057857806336f7ab5e146105805780633a2b6939146105885780633b18b9841461059057600080fd5b806325287d421461051757806325d608611461052a57806327e235e31461053d5780632e0ad0041461055d57600080fd5b8063153a1f3e11610411578063153a1f3e146104ba57806318160ddd146104cd5780631935a880146104e4578063200d2ed2146104f757806323b872dd1461050457600080fd5b8063034f6b211461044357806306eaa0b71461046557806306fdde031461047a5780630af7eb0f1461048f575b600080fd5b6018546104509060ff1681565b60405190151581526020015b60405180910390f35b610478610473366004613503565b61099d565b005b610482610c67565b60405161045c9190613590565b6009546104a2906001600160a01b031681565b6040516001600160a01b03909116815260200161045c565b6104506104c83660046135ef565b610cf5565b6104d660035481565b60405190815260200161045c565b6104786104f236600461366c565b610f19565b6007546104509060ff1681565b6104506105123660046136a5565b610fab565b6004546104a2906001600160a01b031681565b6104786105383660046136e1565b611192565b6104d661054b36600461371e565b60086020526000908152604090205481565b6104826111ec565b610478610573366004613503565b6111f9565b610482611374565b610482611381565b61048261138e565b61047861059e366004613739565b61139b565b6104786105b1366004613752565b61141a565b6104786105c436600461377c565b6114b8565b6104786105d73660046137e4565b6115e7565b6104826118ce565b6104d6600f5481565b6104826118db565b6104826118e8565b61047861060b36600461366c565b6118f5565b61047861061e366004613503565b611984565b610478610631366004613739565b611d06565b6104786106443660046136e1565b611d55565b610482611dab565b600b546104509060ff1681565b610482611db8565b6104d661067436600461371e565b611dc5565b61047861068736600461371e565b611de0565b6104d660105481565b6104786106a336600461383b565b611e4c565b6104d66106b636600461371e565b600d6020526000908152604090205481565b6104786106d63660046136e1565b611f69565b6000546104a2906001600160a01b031681565b6104786106fc3660046136e1565b611fbf565b61047861070f3660046136e1565b612015565b60095461045090600160a81b900460ff1681565b61073b61073636600461371e565b61206b565b60405161045c939291906138d5565b610482612116565b6104786107603660046136e1565b612123565b61047861077336600461366c565b612179565b61047861078636600461383b565b6121e1565b610450610799366004613752565b6122f5565b6104786107ac3660046136e1565b6123bc565b60095461045090600160b01b900460ff1681565b6104786107d33660046136e1565b612412565b6104d66107e63660046138fd565b612468565b6104786107f936600461377c565b612493565b61047861080c3660046137e4565b61256e565b61047861081f36600461366c565b61264b565b610478610832366004613930565b6126de565b61047861282d565b61047861084d366004613930565b6128af565b6104d66108603660046138fd565b600e60209081526000928352604080842090915290825290205481565b61047861088b3660046136a5565b6129ef565b61045061089e36600461383b565b612bbd565b6104786108b13660046136e1565b612ce1565b610482612d37565b6104786108cc3660046136e1565b612d44565b6104d660135481565b6104786108e8366004613739565b612d9a565b6104786108fb36600461371e565b612e19565b610482612f03565b61047861091636600461371e565b612f10565b610482612f7c565b60095461045090600160a01b900460ff1681565b61047861094536600461366c565b612f89565b61095d610958366004613739565b612ff1565b604080516001600160a01b039586168152949093166020850152918301521515606082015260800161045c565b6104786109983660046136a5565b61303a565b336001600160a01b0316600c83815481106109ba576109ba6139a9565b60009182526020909120600490910201546001600160a01b0316148015906109ed57506000546001600160a01b03163314155b15610a2f57604080518082018252600681526531323038303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b60405180910390fd5b600c8281548110610a4257610a426139a9565b6000918252602082206003600490920201015460ff1615159003610a945760408051808201825260068152651899181c181960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b600c8281548110610aa757610aa76139a9565b90600052602060002090600402016002015460086000600c8581548110610ad057610ad06139a9565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610b099084906139d5565b9091555050600c805483908110610b2257610b226139a9565b906000526020600020906004020160020154600d6000600c8581548110610b4b57610b4b6139a9565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190610b849084906139e8565b925050819055506000600c8381548110610ba057610ba06139a9565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817fa0cc3a4feb26502e6e6cd57b2113d58bdab80c6711d8252356be9a49945bb5f7600c8481548110610bfd57610bfd6139a9565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110610c2e57610c2e6139a9565b6000918252602090912060016004909202010154604051610c5b92916001600160a01b03169086906139fb565b60405180910390a25050565b60018054610c7490613a27565b80601f0160208091040260200160405190810160405280929190818152602001828054610ca090613a27565b8015610ced5780601f10610cc257610100808354040283529160200191610ced565b820191906000526020600020905b815481529060010190602001808311610cd057829003601f168201915b505050505081565b6000838214610d3257604080518082018252600681526531323035303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6000805b85811015610d6c57848482818110610d5057610d506139a9565b9050602002013582610d6291906139d5565b9150600101610d36565b5080610d7733611dc5565b1015610db15760408051808201825260068152651899181a981960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b6004546001600160a01b03163314610e125760095460408051808201909152600681526531323035303360d01b602082015290600160a81b900460ff161515600114610e105760405162461bcd60e51b8152600401610a269190613590565b505b606060006001935060005b87811015610f0d57610e55898983818110610e3a57610e3a6139a9565b9050602002016020810190610e4f919061371e565b3b151590565b15610eaa57610ea3898983818110610e6f57610e6f6139a9565b9050602002016020810190610e84919061371e565b888884818110610e9657610e966139a9565b9050602002013585613162565b9150610ef6565b610ef3898983818110610ebf57610ebf6139a9565b9050602002016020810190610ed4919061371e565b888884818110610ee657610ee66139a9565b905060200201358561327d565b91505b811515600003610f0557600094505b600101610e1d565b50505050949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610f625760405162461bcd60e51b8152600401610a269190613590565b50600b805460ff19168215159081179091556040519081527fe1455bc53682229469d6919bb96d7b338cbffea93170dfb5f02242c22fb6d07f906020015b60405180910390a150565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314610ff55760405162461bcd60e51b8152600401610a269190613590565b508161100085611dc5565b101561103a57604080518082018252600681526531323036303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6060833b156110ff576110568361105087611dc5565b90613441565b6001600160a01b0386166000908152600860205260409020556110828361107c86611dc5565b90613454565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a906110c790339088908790600401613a61565b600060405180830381600087803b1580156110e157600080fd5b505af11580156110f5573d6000803e3d6000fd5b505050505061114c565b61110c8361105087611dc5565b6001600160a01b0386166000908152600860205260409020556111328361107c86611dc5565b6001600160a01b0385166000908152600860205260409020555b836001600160a01b0316856001600160a01b0316600080516020613c0d8339815191528560405161117f91815260200190565b60405180910390a3506001949350505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146111db5760405162461bcd60e51b8152600401610a269190613590565b5060176111e88282613ad9565b5050565b601a8054610c7490613a27565b60095460408051808201909152600681526531323130303160d01b602082015290600160b01b900460ff1615156001146112465760405162461bcd60e51b8152600401610a269190613590565b50600954600160a01b900460ff1615156001036113155760095460005460405163d3da927f60e01b81523360048201526001600160a01b03918216602482015291169063d3da927f90604401602060405180830381865afa1580156112af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d39190613b99565b60408051808201909152600681526518991898181960d11b60208201529015156001146113135760405162461bcd60e51b8152600401610a269190613590565b505b336000908152600a602052604090208281556002016113348282613ad9565b507f3bb9553f633a7ecb4cbc5f9885e750a522496ce06deff1ed9184180ca83940c033838360405161136893929190613a61565b60405180910390a15050565b60118054610c7490613a27565b60058054610c7490613a27565b60198054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146113e45760405162461bcd60e51b8152600401610a269190613590565b5060138190556040518181527fe451abe602c33e612ea61221b5a142f7fe3c044286e42c8340ffe7fa86a5859790602001610fa0565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146114635760405162461bcd60e51b8152600401610a269190613590565b506001600160a01b0382166000818152600a6020908152604091829020600101849055815192835282018390527fa42bd6bdfcb8f9b815c68e4ce0e16dec3f1e7ac53967ee8309653de522a735b19101611368565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146115015760405162461bcd60e51b8152600401610a269190613590565b508161150c84611dc5565b101561154657604080518082018252600681526531323136303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6115538261105085611dc5565b6001600160a01b03841660009081526008602052604090205561157a8261107c8686612468565b6001600160a01b038086166000818152600e6020908152604080832094891680845294909152908190209390935591517fd7bb89baba75d47cbd55a36bae224d3c630a8d3114860f86a30b484b2af51602906115d99086908690613bb6565b60405180910390a350505050565b600b5460ff1615806116035750600954600160a81b900460ff16155b8061161557508161161333611dc5565b105b1561164e57604080518082018252600681526531323037303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6000546001600160a01b0384811691161480159061167a5750600954600160a01b900460ff1615156001145b156117395760095460005460405163d3da927f60e01b81526001600160a01b038681166004830152918216602482015291169063d3da927f90604401602060405180830381865afa1580156116d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f79190613b99565b6040805180820190915260068152651899181b981960d11b60208201529015156001146117375760405162461bcd60e51b8152600401610a269190613590565b505b33600090815260086020526040812080548492906117589084906139e8565b9091555050336000908152600d60205260408120805484929061177c9084906139d5565b9091555050600c805460408051608081018252338082526001600160a01b038881166020840190815283850189815260016060860181815290880189556000989098529351600487027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7810180549285166001600160a01b031993841617905591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8830180549190941691161790915591517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c983015593517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8ca909101805491151560ff1990921691909117905551909182917fa256c3bc72c26fbfd6285cfde8c7e345b4d0c7ccfc725d103e9f129c5d8a039a916118c091889088908890613bcf565b60405180910390a250505050565b60068054610c7490613a27565b60178054610c7490613a27565b601b8054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461193e5760405162461bcd60e51b8152600401610a269190613590565b506007805460ff191682151590811790915560405160ff9091161515907fe1e5c6f5867805bf3fab73f4df4b80d0e87e9262a7bc22ac7c2cb3fd5896222f90600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146119cd5760405162461bcd60e51b8152600401610a269190613590565b50600954600160a81b900460ff161515600003611a1857604080518082018252600681526531323039303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b600c8281548110611a2b57611a2b6139a9565b6000918252602082206003600490920201015460ff1615159003611a7d5760408051808201825260068152651899181c981960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b600c8281548110611a9057611a906139a9565b90600052602060002090600402016002015460086000600c8581548110611ab957611ab96139a9565b60009182526020808320600160049093020191909101546001600160a01b0316835282019290925260400181208054909190611af69084906139d5565b9091555050600c805483908110611b0f57611b0f6139a9565b906000526020600020906004020160020154600d6000600c8581548110611b3857611b386139a9565b600091825260208083206004909202909101546001600160a01b0316835282019290925260400181208054909190611b719084906139e8565b925050819055506000600c8381548110611b8d57611b8d6139a9565b906000526020600020906004020160030160006101000a81548160ff021916908315150217905550817f6b50d6e4941ce7ae74ed7f7f51df5fb7680754c2815a094c66bea5ca80a40eb1600c8481548110611bea57611bea6139a9565b6000918252602090912060049091020154600c80546001600160a01b039092169186908110611c1b57611c1b6139a9565b6000918252602090912060016004909202010154604051611c4892916001600160a01b03169086906139fb565b60405180910390a2600c8281548110611c6357611c636139a9565b6000918252602090912060016004909202010154600c80546001600160a01b039092169184908110611c9757611c976139a9565b6000918252602090912060049091020154600c80546001600160a01b0390921691600080516020613c0d833981519152919086908110611cd957611cd96139a9565b906000526020600020906004020160020154604051611cfa91815260200190565b60405180910390a35050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d4f5760405162461bcd60e51b8152600401610a269190613590565b50601055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611d9e5760405162461bcd60e51b8152600401610a269190613590565b5060116111e88282613ad9565b60128054610c7490613a27565b60168054610c7490613a27565b6001600160a01b031660009081526008602052604090205490565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e295760405162461bcd60e51b8152600401610a269190613590565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611e955760405162461bcd60e51b8152600401610a269190613590565b508483141580611ea55750848114155b15611ede57604080518082018252600681526531323134303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b60005b85811015611f6057611f58878783818110611efe57611efe6139a9565b9050602002016020810190611f13919061371e565b868684818110611f2557611f256139a9565b9050602002016020810190611f3a919061371e565b858585818110611f4c57611f4c6139a9565b905060200201356129ef565b600101611ee1565b50505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314611fb25760405162461bcd60e51b8152600401610a269190613590565b5060196111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146120085760405162461bcd60e51b8152600401610a269190613590565b5060066111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461205e5760405162461bcd60e51b8152600401610a269190613590565b50601b6111e88282613ad9565b600a602052600090815260409020805460018201546002830180549293919261209390613a27565b80601f01602080910402602001604051908101604052809291908181526020018280546120bf90613a27565b801561210c5780601f106120e15761010080835404028352916020019161210c565b820191906000526020600020905b8154815290600101906020018083116120ef57829003601f168201915b5050505050905083565b60028054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461216c5760405162461bcd60e51b8152600401610a269190613590565b50601c6111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146121c25760405162461bcd60e51b8152600401610a269190613590565b5060098054911515600160a81b0260ff60a81b19909216919091179055565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461222a5760405162461bcd60e51b8152600401610a269190613590565b50848314158061223a5750848114155b1561227357604080518082018252600681526531323133303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b60005b85811015611f60576122ed878783818110612293576122936139a9565b90506020020160208101906122a8919061371e565b8686848181106122ba576122ba6139a9565b90506020020160208101906122cf919061371e565b8585858181106122e1576122e16139a9565b9050602002013561303a565b600101612276565b60008161230133611dc5565b10156040518060400160405280600681526020016531323034303160d01b815250906123405760405162461bcd60e51b8152600401610a269190613590565b506009546040805180820190915260068152651899181a181960d11b602082015290600160a81b900460ff16151560011461238e5760405162461bcd60e51b8152600401610a269190613590565b506060833b156123ab576123a3848483613162565b9150506123b6565b6123a384848361327d565b92915050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146124055760405162461bcd60e51b8152600401610a269190613590565b50601a6111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b0316331461245b5760405162461bcd60e51b8152600401610a269190613590565b5060056111e88282613ad9565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205490565b8161249e3386612468565b10156124d857604080518082018252600681526518991818981960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b6124e6826110503387612468565b336000908152600e602090815260408083206001600160a01b03891684529091529020556125178261107c85611dc5565b6001600160a01b038085166000908152600860205260409081902092909255905133918616907f7a1a1088c929a111dda2dc0ca1cc650aa78525d11fd3089abf20c8474f5d82cc906115d990879087908790613a61565b8161257833611dc5565b10156125b257604080518082018252600681526518991818181960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b6125bf8261105033611dc5565b336000818152600860205260409020919091556125e390839061107c908690612468565b6001600160a01b0384166000818152600e602090815260408083203380855292529182902093909355519091907ecd77abc69e7bbb6de9df8cbfcca8720df3a30decf9eefd187e72ab2ea2f5139061263e9086908690613bb6565b60405180910390a3505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146126945760405162461bcd60e51b8152600401610a269190613590565b506009805460ff60b01b1916600160b01b831515908102919091179091556040517fa0c691180b8089c0c84e478ee67d6325768666cd889f13de016771c6f7af1f8890600090a250565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146127275760405162461bcd60e51b8152600401610a269190613590565b50816127338686612468565b101561276d57604080518082018252600681526531323132303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b61277b826110508787612468565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556127ae8261107c85611dc5565b60086000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550846001600160a01b0316846001600160a01b03167f66b661491f3fe4e137b9e9cf90e142a93be21bc10e70c9b740379a245e4f7d2585858560405161281e93929190613a61565b60405180910390a35050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128765760405162461bcd60e51b8152600401610a269190613590565b506018805460ff191660011790556040517f96151d7f1d8c50be29a45c0e3ae9ce2008888d1615b196e8f5ffd8c178e6dde890600090a1565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146128f85760405162461bcd60e51b8152600401610a269190613590565b50816129048686612468565b101561293e57604080518082018252600681526531323137303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b61294c826110508787612468565b6001600160a01b038087166000908152600e60209081526040808320938916835292905220556129808261107c8786612468565b6001600160a01b038087166000818152600e602090815260408083208986168085529252918290209490945551918716917f5847ffcc1bce0ecfdd115863db8562df2b18b61698938e251adf381774e9e3be906129e09087908790613bb6565b60405180910390a45050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612a385760405162461bcd60e51b8152600401610a269190613590565b506001600160a01b03821615612ad65780612a538385612468565b1015612a8d57604080518082018252600681526531323131303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b612a9b816110508486612468565b6001600160a01b038084166000908152600e6020908152604080832093881683529290522055600354612ace9082613441565b600355612b61565b6001600160a01b038316600090815260086020526040902054811115612b2a57604080518082018252600681526518991898981960d11b6020820152905162461bcd60e51b8152610a269190600401613590565b612b378161105085611dc5565b6001600160a01b038416600090815260086020526040902055600354612b5d9082613441565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167fee02732fab40ece8284c756220846dff4b8d32058b86b35b4f0459bf172fcef084604051612bb091815260200190565b60405180910390a4505050565b6000805460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612c075760405162461bcd60e51b8152600401610a269190613590565b508584141580612c175750858214155b15612c5057604080518082018252600681526531323135303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b60005b86811015612cd357612cca888883818110612c7057612c706139a9565b9050602002016020810190612c85919061371e565b878784818110612c9757612c976139a9565b9050602002016020810190612cac919061371e565b868685818110612cbe57612cbe6139a9565b90506020020135610fab565b50600101612c53565b506001979650505050505050565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612d2a5760405162461bcd60e51b8152600401610a269190613590565b5060166111e88282613ad9565b601c8054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612d8d5760405162461bcd60e51b8152600401610a269190613590565b5060126111e88282613ad9565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612de35760405162461bcd60e51b8152600401610a269190613590565b50600f8190556040518181527f82b19c9a00131a87eeff1903fcb9e4f2a3ba76dd86098586eea921a533e218dc90602001610fa0565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612e625760405162461bcd60e51b8152600401610a269190613590565b5060408051808201909152600681526535303031303160d01b60208201526001600160a01b038216612ea75760405162461bcd60e51b8152600401610a269190613590565b50600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60158054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612f595760405162461bcd60e51b8152600401610a269190613590565b50600980546001600160a01b0319166001600160a01b0392909216919091179055565b60148054610c7490613a27565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b03163314612fd25760405162461bcd60e51b8152600401610a269190613590565b5060098054911515600160a01b0260ff60a01b19909216919091179055565b600c818154811061300157600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509116919060ff1684565b60005460408051808201909152600681526535303030303160d01b6020820152906001600160a01b031633146130835760405162461bcd60e51b8152600401610a269190613590565b506001600160a01b038216156130dc576130a18161107c8486612468565b6001600160a01b038084166000908152600e60209081526040808320938816835292905220556003546130d49082613454565b600355613113565b6130e98161107c85611dc5565b6001600160a01b03841660009081526008602052604090205560035461310f9082613454565b6003555b816001600160a01b0316836001600160a01b0316336001600160a01b03167f65adeb76912378393e600cb6f64f3310842a42e1eae86273dc775d0c47a0f2dc84604051612bb091815260200190565b60045460408051808201909152600681526531323033303160d01b60208201526000916001600160a01b038681169116146131b05760405162461bcd60e51b8152600401610a269190613590565b506131be8361105033611dc5565b336000908152600860205260409020556131db8361107c86611dc5565b6001600160a01b0385166000818152600860205260409081902092909255905163607705c560e11b815285919063c0ee0b8a9061322090339088908890600401613a61565b600060405180830381600087803b15801561323a57600080fd5b505af115801561324e573d6000803e3d6000fd5b50506040518681526001600160a01b0388169250339150600080516020613c0d8339815191529060200161117f565b6004546000906001600160a01b031633148015906132a25750600b5460ff1615156001145b156132db57604080518082018252600681526531323032303160d01b6020820152905162461bcd60e51b8152610a269190600401613590565b6000546001600160a01b038581169116148015906133075750600954600160a01b900460ff1615156001145b156133c65760095460005460405163d3da927f60e01b81526001600160a01b038781166004830152918216602482015291169063d3da927f90604401602060405180830381865afa158015613360573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133849190613b99565b60408051808201909152600681526518991819181960d11b60208201529015156001146133c45760405162461bcd60e51b8152600401610a269190613590565b505b6133d38361105033611dc5565b336000908152600860205260409020556133f08361107c86611dc5565b6001600160a01b038516600081815260086020526040908190209290925590513390600080516020613c0d8339815191529061342f9087815260200190565b60405180910390a35060019392505050565b600061344d82846139e8565b9392505050565b600061344d82846139d5565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261348757600080fd5b813567ffffffffffffffff808211156134a2576134a2613460565b604051601f8301601f19908116603f011681019082821181831017156134ca576134ca613460565b816040528381528660208588010111156134e357600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561351657600080fd5b82359150602083013567ffffffffffffffff81111561353457600080fd5b61354085828601613476565b9150509250929050565b6000815180845260005b8181101561357057602081850181015186830182015201613554565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061344d602083018461354a565b60008083601f8401126135b557600080fd5b50813567ffffffffffffffff8111156135cd57600080fd5b6020830191508360208260051b85010111156135e857600080fd5b9250929050565b6000806000806040858703121561360557600080fd5b843567ffffffffffffffff8082111561361d57600080fd5b613629888389016135a3565b9096509450602087013591508082111561364257600080fd5b5061364f878288016135a3565b95989497509550505050565b801515811461366957600080fd5b50565b60006020828403121561367e57600080fd5b813561344d8161365b565b80356001600160a01b03811681146136a057600080fd5b919050565b6000806000606084860312156136ba57600080fd5b6136c384613689565b92506136d160208501613689565b9150604084013590509250925092565b6000602082840312156136f357600080fd5b813567ffffffffffffffff81111561370a57600080fd5b61371684828501613476565b949350505050565b60006020828403121561373057600080fd5b61344d82613689565b60006020828403121561374b57600080fd5b5035919050565b6000806040838503121561376557600080fd5b61376e83613689565b946020939093013593505050565b6000806000806080858703121561379257600080fd5b61379b85613689565b93506137a960208601613689565b925060408501359150606085013567ffffffffffffffff8111156137cc57600080fd5b6137d887828801613476565b91505092959194509250565b6000806000606084860312156137f957600080fd5b61380284613689565b925060208401359150604084013567ffffffffffffffff81111561382557600080fd5b61383186828701613476565b9150509250925092565b6000806000806000806060878903121561385457600080fd5b863567ffffffffffffffff8082111561386c57600080fd5b6138788a838b016135a3565b9098509650602089013591508082111561389157600080fd5b61389d8a838b016135a3565b909650945060408901359150808211156138b657600080fd5b506138c389828a016135a3565b979a9699509497509295939492505050565b8381528260208201526060604082015260006138f4606083018461354a565b95945050505050565b6000806040838503121561391057600080fd5b61391983613689565b915061392760208401613689565b90509250929050565b600080600080600060a0868803121561394857600080fd5b61395186613689565b945061395f60208701613689565b935061396d60408701613689565b925060608601359150608086013567ffffffffffffffff81111561399057600080fd5b61399c88828901613476565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156123b6576123b66139bf565b818103818111156123b6576123b66139bf565b6001600160a01b038481168252831660208201526060604082018190526000906138f49083018461354a565b600181811c90821680613a3b57607f821691505b602082108103613a5b57634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b03841681528260208201526060604082015260006138f4606083018461354a565b601f821115613ad4576000816000526020600020601f850160051c81016020861015613ab15750805b601f850160051c820191505b81811015613ad057828155600101613abd565b5050505b505050565b815167ffffffffffffffff811115613af357613af3613460565b613b0781613b018454613a27565b84613a88565b602080601f831160018114613b3c5760008415613b245750858301515b600019600386901b1c1916600185901b178555613ad0565b600085815260208120601f198616915b82811015613b6b57888601518255948401946001909101908401613b4c565b5085821015613b895787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613bab57600080fd5b815161344d8161365b565b828152604060208201526000613716604083018461354a565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613c029083018461354a565b969550505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122061defbbe8b73a970d84efe79630b66e96950d98e87fcc71249e9eba64f55024464736f6c63430008170033"
}
\ No newline at end of file
diff --git a/app/main.py b/app/main.py
index 4af4e117e..31dbb5e0d 100644
--- a/app/main.py
+++ b/app/main.py
@@ -119,7 +119,7 @@ async def lifespan(_: FastAPI):
title="ibet Wallet API",
description="RPC services that provides utility tools for building a wallet system on ibet network",
terms_of_service="",
- version="25.6.0",
+ version="25.9.0",
contact={"email": "dev@boostry.co.jp"},
license_info={
"name": "Apache 2.0",
diff --git a/app/model/db/__init__.py b/app/model/db/__init__.py
index 1cad05374..5a2421441 100644
--- a/app/model/db/__init__.py
+++ b/app/model/db/__init__.py
@@ -22,7 +22,7 @@
from .idx_agreement import AgreementStatus, IDXAgreement
from .idx_block_data import IDXBlockData, IDXBlockDataBlockNumber
from .idx_consume_coupon import IDXConsumeCoupon
-from .idx_lock_unlock import IDXLock, IDXUnlock
+from .idx_lock_unlock import IDXLock, IDXUnlock, LockDataMessage, UnlockDataMessage
from .idx_order import IDXOrder
from .idx_position import (
IDXLockedPosition,
@@ -42,17 +42,22 @@
)
from .idx_token_list_register import IDXTokenListBlockNumber, IDXTokenListRegister
from .idx_transfer import (
- DataMessage,
IDXTransfer,
IDXTransferBlockNumber,
IDXTransferSourceEventType,
+ TransferDataMessage,
)
from .idx_transfer_approval import IDXTransferApproval, IDXTransferApprovalBlockNumber
from .idx_tx_data import IDXTxData
from .listing import Listing
from .messaging import ChatWebhook, Mail
from .node import Node
-from .notification import Notification, NotificationBlockNumber, NotificationType
+from .notification import (
+ Notification,
+ NotificationAttributeValue,
+ NotificationBlockNumber,
+ NotificationType,
+)
from .public_info import PublicAccountList, TokenList
from .tokenholders import TokenHolder, TokenHolderBatchStatus, TokenHoldersList
from .user_info import AccountTag
diff --git a/app/model/db/idx_lock_unlock.py b/app/model/db/idx_lock_unlock.py
index 3f303c140..62c1e15b9 100644
--- a/app/model/db/idx_lock_unlock.py
+++ b/app/model/db/idx_lock_unlock.py
@@ -18,8 +18,10 @@
"""
from datetime import datetime, timedelta, timezone
+from enum import StrEnum
from zoneinfo import ZoneInfo
+from pydantic import BaseModel
from sqlalchemy import JSON, BigInteger, Boolean, DateTime, String
from sqlalchemy.orm import Mapped, mapped_column
@@ -30,6 +32,26 @@
local_tz = ZoneInfo(TZ)
+class LockMessage(StrEnum):
+ garnishment = "garnishment"
+ force_lock = "force_lock"
+ ibet_wst_bridge = "ibet_wst_bridge"
+
+
+class LockDataMessage(BaseModel):
+ message: LockMessage
+
+
+class UnlockMessage(StrEnum):
+ garnishment = "garnishment"
+ force_unlock = "force_unlock"
+ ibet_wst_bridge = "ibet_wst_bridge"
+
+
+class UnlockDataMessage(BaseModel):
+ message: UnlockMessage
+
+
class IDXLock(Base):
"""Token Lock Event (INDEX)"""
@@ -55,7 +77,7 @@ class IDXLock(Base):
account_address: Mapped[str] = mapped_column(String(42), index=True, nullable=False)
# Locked Amount
value: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
- # Data
+ # Data(LockDataMessage)
data: Mapped[dict] = mapped_column(JSON, nullable=False)
# Lock Datetime
block_timestamp: Mapped[datetime] = mapped_column(
@@ -135,7 +157,7 @@ class IDXUnlock(Base):
)
# Locked Amount
value: Mapped[int] = mapped_column(BigInteger, index=True, nullable=False)
- # Data
+ # Data(UnlockDataMessage)
data: Mapped[dict] = mapped_column(JSON, nullable=False)
# Lock Datetime
block_timestamp: Mapped[datetime] = mapped_column(
diff --git a/app/model/db/idx_transfer.py b/app/model/db/idx_transfer.py
index 1ff4d54f6..921b8f00b 100644
--- a/app/model/db/idx_transfer.py
+++ b/app/model/db/idx_transfer.py
@@ -39,13 +39,15 @@ class IDXTransferSourceEventType(StrEnum):
TRANSFER = "Transfer"
UNLOCK = "Unlock"
FORCE_UNLOCK = "ForceUnlock"
+ FORCE_CHANGE_LOCKED_ACCOUNT = "ForceChangeLockedAccount"
+ REALLOCATION = "Reallocation"
-class DataMessage(BaseModel):
+class TransferDataMessage(BaseModel):
message: Literal[
"garnishment",
- "inheritance",
"force_unlock",
+ "ibet_wst_bridge",
]
@@ -71,16 +73,18 @@ class IDXTransfer(Base):
String(50), nullable=False
)
# Data
- # source_event = "Transfer"
+ # source_event = "Transfer", "Reallocation"
# => None
- # source_event = "Unlock"
+ # source_event = "Unlock", "ForceUnlock", "ForceChangeLockedAccount"
# => DataMessage
data: Mapped[dict | None] = mapped_column(JSON)
# Message
- # source_event = "Transfer"
+ # source_event = "Transfer", "Reallocation"
# => None
- # source_event = "Unlock"
+ # source_event = "Unlock", "ForceUnlock"
# => "force_unlock", "garnishment" or "inheritance"
+ # source_event = "ForceChangeLockedAccount"
+ # => "ibet_wst_bridge"
message: Mapped[str | None] = mapped_column(String(50), index=True)
@staticmethod
diff --git a/app/model/db/notification.py b/app/model/db/notification.py
index 3d19f4cec..b80b5011b 100644
--- a/app/model/db/notification.py
+++ b/app/model/db/notification.py
@@ -20,6 +20,7 @@
import sys
from datetime import datetime
from enum import StrEnum
+from typing import Literal
from sqlalchemy import (
JSON,
@@ -63,13 +64,29 @@ class Notification(Base):
autoincrement=True,
)
+ # 通知分類
+ notification_category: Mapped[Literal["event_log", "attribute_change"]] = (
+ mapped_column(
+ String(20),
+ primary_key=True,
+ )
+ )
+
# 通知ID
- # Spec: 0x | | | |
+ # Spec: 0x | | | |
# ( | は文字列連結 )
- # : blockNumberをhexstringで表現したもの。12桁
- # : transactionIndex(block内でのトランザクションの採番)をhexstringで表現したもの。6桁
- # : logIndex(transaction内でのログの採番)をhexstringで表現したもの。6桁
- # : blockNumber, transactionIndex, logIndexが等しいが、通知としては複数にしたい場合に使用する識別子。2桁(デフォルトは00)
+ #
+ # notification_category = "event_log" の場合
+ # = : blockNumberをhexstringで表現したもの。12桁
+ # = : transactionIndex(block内でのトランザクションの採番)をhexstringで表現したもの。6桁
+ # = : logIndex(transaction内でのログの採番)をhexstringで表現したもの。6桁
+ # : blockNumber, transactionIndex, logIndexが等しいが、通知としては複数にしたい場合に使用する識別子。2桁(デフォルトは00)
+ #
+ # notification_category = "attribute_change" の場合
+ # = : ミリ秒タイムスタンプをhexstringで表現したもの。12桁
+ # = : コントラクトアドレス。40桁
+ # = : 属性名のkeccak256ハッシュ先頭8文字。8桁
+ # : 同一のコントラクト・属性で複数通知にする場合の識別子。2桁(デフォルトは00)
notification_id: Mapped[str] = mapped_column(String(256), primary_key=True)
# 通知タイプ(例:BuySettlementOK, BuyAgreementなど)
@@ -122,6 +139,7 @@ def __repr__(self):
def json(self):
return {
+ "notification_category": self.notification_category,
"notification_type": self.notification_type,
"id": self.notification_id,
"priority": self.priority,
@@ -185,6 +203,7 @@ def json(self):
class NotificationType(StrEnum):
+ # Event Log Notification
NEW_ORDER = "NewOrder"
NEW_ORDER_COUNTERPART = "NewOrderCounterpart"
CANCEL_ORDER = "CancelOrder"
@@ -203,6 +222,11 @@ class NotificationType(StrEnum):
CANCEL_TRANSFER = "CancelTransfer"
FORCE_LOCK = "ForceLock"
FORCE_UNLOCK = "ForceUnlock"
+ CHANGE_TO_REDEEMED = "ChangeToRedeemed"
+ CHANGE_TO_CANCELED = "ChangeToCanceled"
+
+ # Attribute Change Notification
+ TRANSFERABLE_CHANGED = "TransferableChanged"
class NotificationBlockNumber(Base):
@@ -224,3 +248,16 @@ class NotificationBlockNumber(Base):
}
FIELDS.update(Base.FIELDS)
+
+
+class NotificationAttributeValue(Base):
+ """Synchronized attribute value for Notification"""
+
+ __tablename__ = "notification_attribute_value"
+
+ # contract address
+ contract_address = mapped_column(String(42), primary_key=True)
+ # attribute key
+ attribute_key = mapped_column(String(256), primary_key=True)
+ # attribute
+ attribute = mapped_column(JSON, nullable=False)
diff --git a/app/model/db/public_info.py b/app/model/db/public_info.py
index 4871f8901..c826793be 100644
--- a/app/model/db/public_info.py
+++ b/app/model/db/public_info.py
@@ -43,9 +43,9 @@ class TokenList(Base):
# Token Address
token_address: Mapped[str] = mapped_column(String(42), primary_key=True)
# Token Template
- token_template: Mapped[Literal["ibetBond", "ibetShare"]] = mapped_column(
- String(50), nullable=False
- )
+ token_template: Mapped[
+ Literal["ibetBond", "ibetShare", "ibetMembership", "ibetCoupon"]
+ ] = mapped_column(String(50), nullable=False)
# Key Manager
key_manager: Mapped[list[str]] = mapped_column(JSON, nullable=False)
# Product Type
diff --git a/app/model/schema/notification.py b/app/model/schema/notification.py
index 333a78efe..64957ebcd 100644
--- a/app/model/schema/notification.py
+++ b/app/model/schema/notification.py
@@ -18,7 +18,7 @@
"""
from enum import StrEnum
-from typing import Optional
+from typing import Literal, Optional
from pydantic import BaseModel, Field
@@ -47,6 +47,9 @@ class NotificationsSortItem(StrEnum):
class NotificationsQuery(BasePaginationQuery):
+ notification_category: Optional[Literal["event_log", "attribute_change"]] = Field(
+ None
+ )
address: Optional[EthereumAddress] = Field(None, description="account address")
notification_type: Optional[NotificationType] = Field(None)
priority: Optional[int] = Field(None, ge=0, le=2)
@@ -85,8 +88,9 @@ class NotificationMetainfo(BaseModel):
class Notification(BaseModel):
- notification_type: NotificationType = Field(examples=[NotificationType.NEW_ORDER])
+ notification_category: Literal["event_log", "attribute_change"]
id: str = Field(examples=["0x00000373ca8600000000000000"])
+ notification_type: NotificationType = Field(examples=[NotificationType.NEW_ORDER])
priority: int
block_timestamp: str = Field(description="block timestamp")
is_read: bool
diff --git a/app/model/schema/public_info.py b/app/model/schema/public_info.py
index 8f2dcbd8c..97c472151 100644
--- a/app/model/schema/public_info.py
+++ b/app/model/schema/public_info.py
@@ -48,6 +48,16 @@ class IbetShareToken(TokenBase):
product_type: Literal[1, 2, 3, 4, 5]
+class IbetMembershipToken(TokenBase):
+ token_template: Literal["ibetMembership"]
+ product_type: Literal[1]
+
+
+class IbetCouponToken(TokenBase):
+ token_template: Literal["ibetCoupon"]
+ product_type: Literal[1]
+
+
class PublicAccount(BaseModel):
key_manager: str
key_manager_name: str
@@ -64,8 +74,8 @@ class ListAllPublicListedTokensSortItem(StrEnum):
class ListAllPublicListedTokensQuery(BasePaginationQuery):
- token_template: Literal["ibetBond", "ibetShare"] = Field(
- None, description="Token template"
+ token_template: Literal["ibetBond", "ibetShare", "ibetMembership", "ibetCoupon"] = (
+ Field(None, description="Token template")
)
sort_item: ListAllPublicListedTokensSortItem = Field(
default=ListAllPublicListedTokensSortItem.token_address, description="sort item"
@@ -97,7 +107,9 @@ class ListAllPublicAccountsQuery(BasePaginationQuery):
############################
class ListAllPublicListedTokensResponse(BaseModel):
result_set: ResultSet
- tokens: list[Union[IbetBondToken, IbetShareToken]]
+ tokens: list[
+ Union[IbetBondToken, IbetShareToken, IbetMembershipToken, IbetCouponToken]
+ ]
class ListAllPublicAccountsResponse(BaseModel):
diff --git a/app/model/schema/token.py b/app/model/schema/token.py
index a6b129f04..070275aaf 100644
--- a/app/model/schema/token.py
+++ b/app/model/schema/token.py
@@ -41,6 +41,8 @@ class TransferSourceEvent(StrEnum):
Transfer = "Transfer"
Unlock = "Unlock"
ForceUnlock = "ForceUnlock"
+ ForceChangeLockedAccount = "ForceChangeLockedAccount"
+ Reallocation = "Reallocation"
############################
@@ -407,6 +409,7 @@ class TransferHistoryBase(BaseModel):
"garnishment",
"inheritance",
"force_unlock",
+ "ibet_wst_bridge",
]
| None
)
@@ -416,30 +419,33 @@ class TransferHistoryBase(BaseModel):
class TransferHistory(TransferHistoryBase):
- source_event: Literal[TransferSourceEvent.Transfer] = Field(
- description="Source Event"
- )
+ source_event: Literal[
+ TransferSourceEvent.Transfer, TransferSourceEvent.Reallocation
+ ] = Field(description="Source Event")
data: None = Field(description="Event data")
-class DataMessage(BaseModel):
+class TransferDataMessage(BaseModel):
message: Literal[
"garnishment",
"inheritance",
"force_unlock",
+ "ibet_wst_bridge",
]
-class UnlockTransferHistory(TransferHistoryBase):
+class TransferWithMessage(TransferHistoryBase):
source_event: Literal[
- TransferSourceEvent.Unlock, TransferSourceEvent.ForceUnlock
+ TransferSourceEvent.Unlock,
+ TransferSourceEvent.ForceUnlock,
+ TransferSourceEvent.ForceChangeLockedAccount,
] = Field(description="Source Event")
- data: DataMessage | dict = Field(description="Event data")
+ data: TransferDataMessage | dict = Field(description="Event data")
class TransferHistoriesResponse(BaseModel):
result_set: ResultSet
- transfer_history: list[TransferHistory | UnlockTransferHistory] = Field(
+ transfer_history: list[TransferHistory | TransferWithMessage] = Field(
description="Transfer history"
)
diff --git a/app/utils/contract_error_code.py b/app/utils/contract_error_code.py
index 3ccc239e5..6d3ff49d9 100644
--- a/app/utils/contract_error_code.py
+++ b/app/utils/contract_error_code.py
@@ -68,6 +68,7 @@ def error_code_msg(code_str: str) -> Tuple[int, str]:
111401: "The length of the target address, the lock address and the amount don't match.",
111501: "The From, To and Value lengths don't match.",
111601: "Lock amount is greater than message sender balance.",
+ 111701: "Locked balance is not sufficient.",
# IbetStraightBond (12XXXX)
120001: "Lock address is invalid.", # < v22.12
120002: "Lock amount is greater than message sender balance.",
@@ -97,6 +98,7 @@ def error_code_msg(code_str: str) -> Tuple[int, str]:
121401: "The length of the target address, the lock address and the amount don't match.",
121501: "The From, To and Value lengths don't match.",
121601: "Lock amount is greater than message sender balance.",
+ 121701: "Locked balance is not sufficient.",
# IbetCoupon (13XXXX)
130001: "Destination address isn't tradable exchange.",
130101: "Message sender balance is insufficient.",
diff --git a/batch/indexer_Company_List.py b/batch/indexer_Company_List.py
index f31f2eff8..3ab1dbaf1 100644
--- a/batch/indexer_Company_List.py
+++ b/batch/indexer_Company_List.py
@@ -17,21 +17,26 @@
SPDX-License-Identifier: Apache-2.0
"""
-import asyncio
import hashlib
import json
import sys
import time
-import aiohttp
-from aiohttp import ClientTimeout
+import requests
from eth_utils import to_checksum_address
+from requests.adapters import HTTPAdapter
from sqlalchemy import delete
+from sqlalchemy.engine.create import create_engine
from sqlalchemy.exc import SQLAlchemyError
-from sqlalchemy.ext.asyncio import AsyncSession
-
-from app.config import COMPANY_LIST_SLEEP_INTERVAL, COMPANY_LIST_URL, REQUEST_TIMEOUT
-from app.database import BatchAsyncSessionLocal
+from sqlalchemy.orm.session import Session
+from urllib3 import Retry
+
+from app.config import (
+ COMPANY_LIST_SLEEP_INTERVAL,
+ COMPANY_LIST_URL,
+ DATABASE_URL,
+ REQUEST_TIMEOUT,
+)
from app.errors import ServiceUnavailable
from app.model.db import Company
from batch import free_malloc, log
@@ -39,6 +44,8 @@
process_name = "INDEXER-COMPANY-LIST"
LOG = log.get_logger(process_name=process_name)
+db_engine = create_engine(DATABASE_URL, echo=False, pool_pre_ping=True)
+
class Processor:
"""Processor for indexing company list"""
@@ -46,21 +53,22 @@ class Processor:
def __init__(self):
self.company_list_digest = None
- async def process(self):
+ def process(self):
LOG.info("Syncing company list")
# Get from COMPANY_LIST_URL
try:
- async with aiohttp.ClientSession(trust_env=True) as session:
- async with session.get(
- COMPANY_LIST_URL,
- timeout=ClientTimeout(
- connect=REQUEST_TIMEOUT[0], total=REQUEST_TIMEOUT[1]
- ),
- ) as response:
- if response.status != 200:
- raise Exception(f"status code={response.status}")
- company_list_json = await response.json()
+ with requests.Session() as session:
+ adapter = HTTPAdapter(max_retries=Retry(3, allowed_methods=["GET"]))
+ session.mount("http://", adapter)
+ session.mount("https://", adapter)
+ _resp = session.get(
+ url=COMPANY_LIST_URL,
+ timeout=REQUEST_TIMEOUT,
+ )
+ if _resp.status_code != 200:
+ raise Exception(f"status code={_resp.status_code}")
+ company_list_json = _resp.json()
except Exception:
LOG.exception("Failed to get company list")
return
@@ -76,10 +84,10 @@ async def process(self):
self.company_list_digest = _resp_digest
# Update DB data
- db_session = BatchAsyncSessionLocal()
+ db_session = Session(autocommit=False, autoflush=True, bind=db_engine)
try:
# Delete all company list from DB
- await db_session.execute(delete(Company))
+ db_session.execute(delete(Company))
# Insert company list
for i, company in enumerate(company_list_json):
@@ -105,7 +113,7 @@ async def process(self):
except ValueError:
LOG.notice(f"Invalid address: index={i} address={address}")
continue
- await self.__sink_on_company(
+ self.__sink_on_company(
db_session=db_session,
address=to_checksum_address(address),
corporate_name=corporate_name,
@@ -116,17 +124,17 @@ async def process(self):
LOG.notice(f"Missing required field: index={i}")
continue
- await db_session.commit()
- except Exception as e:
- await db_session.rollback()
- raise e
+ db_session.commit()
+ except Exception:
+ db_session.rollback()
+ raise
finally:
- await db_session.close()
+ db_session.close()
LOG.info("Sync job has been completed")
@staticmethod
- async def __sink_on_company(
- db_session: AsyncSession,
+ def __sink_on_company(
+ db_session: Session,
address: str,
corporate_name: str,
rsa_publickey: str,
@@ -137,17 +145,17 @@ async def __sink_on_company(
_company.corporate_name = corporate_name
_company.rsa_publickey = rsa_publickey
_company.homepage = homepage
- await db_session.merge(_company)
+ db_session.merge(_company)
-async def main():
+def main():
LOG.info("Service started successfully")
processor = Processor()
while True:
start_time = time.time()
try:
- await processor.process()
+ processor.process()
except ServiceUnavailable:
LOG.notice("An external service was unavailable")
except SQLAlchemyError as sa_err:
@@ -156,12 +164,12 @@ async def main():
LOG.exception("An exception occurred during processing")
elapsed_time = time.time() - start_time
- await asyncio.sleep(max(COMPANY_LIST_SLEEP_INTERVAL - elapsed_time, 0))
+ time.sleep(max(COMPANY_LIST_SLEEP_INTERVAL - elapsed_time, 0))
free_malloc()
if __name__ == "__main__":
try:
- asyncio.run(main())
+ main()
except KeyboardInterrupt:
sys.exit(1)
diff --git a/batch/indexer_Position_Bond.py b/batch/indexer_Position_Bond.py
index 4ace26ab0..b77943a3c 100644
--- a/batch/indexer_Position_Bond.py
+++ b/batch/indexer_Position_Bond.py
@@ -22,7 +22,7 @@
import sys
from datetime import datetime, timedelta, timezone
from itertools import groupby
-from typing import List, Optional, Sequence
+from typing import List, Literal, Optional, Sequence
from eth_utils import to_checksum_address
from sqlalchemy import select
@@ -43,6 +43,8 @@
IDXPositionBondBlockNumber,
IDXUnlock,
Listing,
+ LockDataMessage,
+ UnlockDataMessage,
)
from app.model.schema.base import TokenType
from app.utils.asyncio_utils import SemaphoreTaskGroup
@@ -300,6 +302,7 @@ async def __sync_all(self, db_session: AsyncSession, block_to: int):
await self.__sync_force_lock(db_session, block_to)
await self.__sync_unlock(db_session, block_to)
await self.__sync_force_unlock(db_session, block_to)
+ await self.__sync_force_change_locked_account(db_session, block_to)
await self.__sync_issue(db_session, block_to)
await self.__sync_redeem(db_session, block_to)
await self.__sync_apply_for_transfer(db_session, block_to)
@@ -411,7 +414,9 @@ async def __sync_lock(self, db_session: AsyncSession, block_to: int):
value = args.get("value", 0)
data = args.get("data", "")
event_created = await self.__gen_block_timestamp(event=event)
- tx = await async_web3.eth.get_transaction(event["transactionHash"])
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
msg_sender = tx["from"]
# Index Lock event
@@ -493,7 +498,9 @@ async def __sync_force_lock(self, db_session: AsyncSession, block_to: int):
value = args.get("value", 0)
data = args.get("data", "")
event_created = await self.__gen_block_timestamp(event=event)
- tx = await async_web3.eth.get_transaction(event["transactionHash"])
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
msg_sender = tx["from"]
# Index Lock event
@@ -577,7 +584,9 @@ async def __sync_unlock(self, db_session: AsyncSession, block_to: int):
value = args.get("value", 0)
data = args.get("data", "")
event_created = await self.__gen_block_timestamp(event=event)
- tx = await async_web3.eth.get_transaction(event["transactionHash"])
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
msg_sender = tx["from"]
# Index Unlock event
@@ -661,7 +670,9 @@ async def __sync_force_unlock(self, db_session: AsyncSession, block_to: int):
value = args.get("value", 0)
data = args.get("data", "")
event_created = await self.__gen_block_timestamp(event=event)
- tx = await async_web3.eth.get_transaction(event["transactionHash"])
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
msg_sender = tx["from"]
# Index Unlock event
@@ -718,6 +729,114 @@ async def __sync_force_unlock(self, db_session: AsyncSession, block_to: int):
except Exception as e:
raise e
+ async def __sync_force_change_locked_account(
+ self, db_session: AsyncSession, block_to: int
+ ):
+ """Sync ForceChangeLockedAccount Events
+
+ :param db_session: ORM session
+ :param block_to: To block
+ :return: None
+ """
+ for target in self.token_list:
+ token = target.token_contract
+ block_from = target.cursor
+ if block_from > block_to:
+ continue
+ try:
+ events = await token.events.ForceChangeLockedAccount.get_logs(
+ from_block=block_from, to_block=block_to
+ )
+ except ABIEventNotFound:
+ events = []
+ try:
+ lock_map: dict[str, dict[str, Literal[True]]] = {}
+ for event in events:
+ args = event["args"]
+ lock_address = args.get("lockAddress", "")
+ before_account_address = args.get("beforeAccountAddress", "")
+ after_account_address = args.get("afterAccountAddress", "")
+ value = args.get("value", 0)
+ data = args.get("data", "")
+ event_created = await self.__gen_block_timestamp(event=event)
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
+ msg_sender = tx["from"]
+
+ # Index Unlock event
+ # - Set after_account as recipient
+ self.__insert_unlock_idx(
+ db_session=db_session,
+ transaction_hash=event["transactionHash"].to_0x_hex(),
+ msg_sender=msg_sender,
+ block_number=event["blockNumber"],
+ token_address=token.address,
+ lock_address=lock_address,
+ account_address=before_account_address,
+ recipient_address=after_account_address,
+ value=value,
+ data_str=data,
+ block_timestamp=event_created,
+ is_forced=True,
+ )
+
+ # Index Lock event
+ self.__insert_lock_idx(
+ db_session=db_session,
+ transaction_hash=event["transactionHash"].to_0x_hex(),
+ msg_sender=msg_sender,
+ block_number=event["blockNumber"],
+ token_address=token.address,
+ lock_address=lock_address,
+ account_address=after_account_address,
+ value=value,
+ data_str=data,
+ block_timestamp=event_created,
+ is_forced=True,
+ )
+
+ if lock_address not in lock_map:
+ lock_map[lock_address] = {}
+ lock_map[lock_address][before_account_address] = True
+ lock_map[lock_address][after_account_address] = True
+
+ for lock_address in lock_map:
+ for account_address in lock_map[lock_address]:
+ # Update Locked Position
+ value = await self.__get_account_locked_token(
+ token, lock_address, account_address
+ )
+ await self.__sink_on_locked_position(
+ db_session=db_session,
+ token_address=to_checksum_address(token.address),
+ lock_address=lock_address,
+ account_address=account_address,
+ value=value,
+ )
+ except Exception:
+ pass
+ try:
+ accounts_filtered = self.remove_duplicate_event_by_token_account_desc(
+ events=events,
+ account_keys=["beforeAccountAddress", "afterAccountAddress"],
+ )
+ balances_list = await self.get_bulk_account_balance_token(
+ token=token,
+ accounts=accounts_filtered,
+ )
+ for balances in balances_list:
+ (account, balance, pending_transfer) = balances
+ await self.__sink_on_position(
+ db_session=db_session,
+ token_address=to_checksum_address(token.address),
+ account_address=account,
+ balance=balance,
+ pending_transfer=pending_transfer,
+ )
+ except Exception as e:
+ raise e
+
async def __sync_issue(self, db_session: AsyncSession, block_to: int):
"""Sync Issue Events
@@ -1644,6 +1763,7 @@ def __insert_lock_idx(
"""
try:
data = json.loads(data_str)
+ LockDataMessage.model_validate(data)
except Exception:
data = {}
lock = IDXLock()
@@ -1690,6 +1810,7 @@ def __insert_unlock_idx(
"""
try:
data = json.loads(data_str)
+ UnlockDataMessage.model_validate(data)
except:
data = {}
unlock = IDXUnlock()
@@ -1746,7 +1867,7 @@ async def __sink_on_position(
position.exchange_commitment = exchange_commitment
await db_session.merge(position)
elif any(
- value is not None and value > 0
+ value is not None
for value in [
balance,
pending_transfer,
diff --git a/batch/indexer_Position_Coupon.py b/batch/indexer_Position_Coupon.py
index b4b6b0521..36240d07f 100644
--- a/batch/indexer_Position_Coupon.py
+++ b/batch/indexer_Position_Coupon.py
@@ -944,7 +944,7 @@ async def __sink_on_position(
position.exchange_commitment = exchange_commitment
await db_session.merge(position)
elif any(
- value is not None and value > 0
+ value is not None
for value in [balance, exchange_balance, exchange_commitment]
):
LOG.debug(
diff --git a/batch/indexer_Position_Membership.py b/batch/indexer_Position_Membership.py
index 1213ce319..f72304130 100644
--- a/batch/indexer_Position_Membership.py
+++ b/batch/indexer_Position_Membership.py
@@ -908,7 +908,7 @@ async def __sink_on_position(
position.exchange_commitment = exchange_commitment
await db_session.merge(position)
elif any(
- value is not None and value > 0
+ value is not None
for value in [balance, exchange_balance, exchange_commitment]
):
LOG.debug(
diff --git a/batch/indexer_Position_Share.py b/batch/indexer_Position_Share.py
index 4d009d02f..5b031ba2e 100644
--- a/batch/indexer_Position_Share.py
+++ b/batch/indexer_Position_Share.py
@@ -22,7 +22,7 @@
import sys
from datetime import datetime, timedelta, timezone
from itertools import groupby
-from typing import List, Optional, Sequence
+from typing import List, Literal, Optional, Sequence
from eth_utils import to_checksum_address
from sqlalchemy import select
@@ -43,6 +43,8 @@
IDXPositionShareBlockNumber,
IDXUnlock,
Listing,
+ LockDataMessage,
+ UnlockDataMessage,
)
from app.model.schema.base import TokenType
from app.utils.asyncio_utils import SemaphoreTaskGroup
@@ -300,6 +302,7 @@ async def __sync_all(self, db_session: AsyncSession, block_to: int):
await self.__sync_force_lock(db_session, block_to)
await self.__sync_unlock(db_session, block_to)
await self.__sync_force_unlock(db_session, block_to)
+ await self.__sync_force_change_locked_account(db_session, block_to)
await self.__sync_issue(db_session, block_to)
await self.__sync_redeem(db_session, block_to)
await self.__sync_apply_for_transfer(db_session, block_to)
@@ -411,7 +414,9 @@ async def __sync_lock(self, db_session: AsyncSession, block_to: int):
value = args.get("value", 0)
data = args.get("data", "")
event_created = await self.__gen_block_timestamp(event=event)
- tx = await async_web3.eth.get_transaction(event["transactionHash"])
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
msg_sender = tx["from"]
# Index Lock event
@@ -493,7 +498,9 @@ async def __sync_force_lock(self, db_session: AsyncSession, block_to: int):
value = args.get("value", 0)
data = args.get("data", "")
event_created = await self.__gen_block_timestamp(event=event)
- tx = await async_web3.eth.get_transaction(event["transactionHash"])
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
msg_sender = tx["from"]
# Index Lock event
@@ -577,7 +584,9 @@ async def __sync_unlock(self, db_session: AsyncSession, block_to: int):
value = args.get("value", 0)
data = args.get("data", "")
event_created = await self.__gen_block_timestamp(event=event)
- tx = await async_web3.eth.get_transaction(event["transactionHash"])
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
msg_sender = tx["from"]
# Index Unlock event
@@ -661,7 +670,9 @@ async def __sync_force_unlock(self, db_session: AsyncSession, block_to: int):
value = args.get("value", 0)
data = args.get("data", "")
event_created = await self.__gen_block_timestamp(event=event)
- tx = await async_web3.eth.get_transaction(event["transactionHash"])
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
msg_sender = tx["from"]
# Index Unlock event
@@ -718,6 +729,114 @@ async def __sync_force_unlock(self, db_session: AsyncSession, block_to: int):
except Exception as e:
raise e
+ async def __sync_force_change_locked_account(
+ self, db_session: AsyncSession, block_to: int
+ ):
+ """Sync ForceChangeLockedAccount Events
+
+ :param db_session: ORM session
+ :param block_to: To block
+ :return: None
+ """
+ for target in self.token_list:
+ token = target.token_contract
+ block_from = target.cursor
+ if block_from > block_to:
+ continue
+ try:
+ events = await token.events.ForceChangeLockedAccount.get_logs(
+ from_block=block_from, to_block=block_to
+ )
+ except ABIEventNotFound:
+ events = []
+ try:
+ lock_map: dict[str, dict[str, Literal[True]]] = {}
+ for event in events:
+ args = event["args"]
+ lock_address = args.get("lockAddress", "")
+ before_account_address = args.get("beforeAccountAddress", "")
+ after_account_address = args.get("afterAccountAddress", "")
+ value = args.get("value", 0)
+ data = args.get("data", "")
+ event_created = await self.__gen_block_timestamp(event=event)
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
+ msg_sender = tx["from"]
+
+ # Index Unlock event
+ # - Set after_account as recipient
+ self.__insert_unlock_idx(
+ db_session=db_session,
+ transaction_hash=event["transactionHash"].to_0x_hex(),
+ msg_sender=msg_sender,
+ block_number=event["blockNumber"],
+ token_address=token.address,
+ lock_address=lock_address,
+ account_address=before_account_address,
+ recipient_address=after_account_address,
+ value=value,
+ data_str=data,
+ block_timestamp=event_created,
+ is_forced=True,
+ )
+
+ # Index Lock event
+ self.__insert_lock_idx(
+ db_session=db_session,
+ transaction_hash=event["transactionHash"].to_0x_hex(),
+ msg_sender=msg_sender,
+ block_number=event["blockNumber"],
+ token_address=token.address,
+ lock_address=lock_address,
+ account_address=after_account_address,
+ value=value,
+ data_str=data,
+ block_timestamp=event_created,
+ is_forced=True,
+ )
+
+ if lock_address not in lock_map:
+ lock_map[lock_address] = {}
+ lock_map[lock_address][before_account_address] = True
+ lock_map[lock_address][after_account_address] = True
+
+ for lock_address in lock_map:
+ for account_address in lock_map[lock_address]:
+ # Update Locked Position
+ value = await self.__get_account_locked_token(
+ token, lock_address, account_address
+ )
+ await self.__sink_on_locked_position(
+ db_session=db_session,
+ token_address=to_checksum_address(token.address),
+ lock_address=lock_address,
+ account_address=account_address,
+ value=value,
+ )
+ except Exception:
+ pass
+ try:
+ accounts_filtered = self.remove_duplicate_event_by_token_account_desc(
+ events=events,
+ account_keys=["beforeAccountAddress", "afterAccountAddress"],
+ )
+ balances_list = await self.get_bulk_account_balance_token(
+ token=token,
+ accounts=accounts_filtered,
+ )
+ for balances in balances_list:
+ (account, balance, pending_transfer) = balances
+ await self.__sink_on_position(
+ db_session=db_session,
+ token_address=to_checksum_address(token.address),
+ account_address=account,
+ balance=balance,
+ pending_transfer=pending_transfer,
+ )
+ except Exception as e:
+ raise e
+
async def __sync_issue(self, db_session: AsyncSession, block_to: int):
"""Sync Issue Events
@@ -1644,6 +1763,7 @@ def __insert_lock_idx(
"""
try:
data = json.loads(data_str)
+ LockDataMessage.model_validate(data)
except Exception:
data = {}
lock = IDXLock()
@@ -1690,6 +1810,7 @@ def __insert_unlock_idx(
"""
try:
data = json.loads(data_str)
+ UnlockDataMessage.model_validate(data)
except:
data = {}
unlock = IDXUnlock()
@@ -1746,7 +1867,7 @@ async def __sink_on_position(
position.exchange_commitment = exchange_commitment
await db_session.merge(position)
elif any(
- value is not None and value > 0
+ value is not None
for value in [
balance,
pending_transfer,
diff --git a/batch/indexer_PublicInfo_PublicAccountList.py b/batch/indexer_PublicInfo_PublicAccountList.py
index 4a96dfef9..b91580aff 100644
--- a/batch/indexer_PublicInfo_PublicAccountList.py
+++ b/batch/indexer_PublicInfo_PublicAccountList.py
@@ -17,25 +17,26 @@
SPDX-License-Identifier: Apache-2.0
"""
-import asyncio
import hashlib
import json
import sys
import time
-import aiohttp
-from aiohttp import ClientTimeout
+import requests
from eth_utils import to_checksum_address
+from requests.adapters import HTTPAdapter
from sqlalchemy import delete
+from sqlalchemy.engine.create import create_engine
from sqlalchemy.exc import SQLAlchemyError
-from sqlalchemy.ext.asyncio import AsyncSession
+from sqlalchemy.orm.session import Session
+from urllib3 import Retry
from app.config import (
+ DATABASE_URL,
PUBLIC_ACCOUNT_LIST_SLEEP_INTERVAL,
PUBLIC_ACCOUNT_LIST_URL,
REQUEST_TIMEOUT,
)
-from app.database import BatchAsyncSessionLocal
from app.errors import ServiceUnavailable
from app.model.db import PublicAccountList
from batch import free_malloc, log
@@ -43,6 +44,8 @@
process_name = "INDEXER-PUBLIC-INFO-PUBLIC-ACCOUNT"
LOG = log.get_logger(process_name=process_name)
+db_engine = create_engine(DATABASE_URL, echo=False, pool_pre_ping=True)
+
class Processor:
"""Processor for indexing public account list"""
@@ -50,21 +53,22 @@ class Processor:
def __init__(self):
self.account_list_digest = None
- async def process(self):
+ def process(self):
LOG.info("Syncing public account list")
# Get data from PUBLIC_ACCOUNT_LIST_URL
try:
- async with aiohttp.ClientSession(trust_env=True) as session:
- async with session.get(
- PUBLIC_ACCOUNT_LIST_URL,
- timeout=ClientTimeout(
- connect=REQUEST_TIMEOUT[0], total=REQUEST_TIMEOUT[1]
- ),
- ) as response:
- if response.status != 200:
- raise Exception(f"status code={response.status}")
- account_list_json = await response.json()
+ with requests.Session() as session:
+ adapter = HTTPAdapter(max_retries=Retry(3, allowed_methods=["GET"]))
+ session.mount("http://", adapter)
+ session.mount("https://", adapter)
+ _resp = session.get(
+ url=PUBLIC_ACCOUNT_LIST_URL,
+ timeout=REQUEST_TIMEOUT,
+ )
+ if _resp.status_code != 200:
+ raise Exception(f"status code={_resp.status_code}")
+ account_list_json = _resp.json()
except Exception:
LOG.exception("Failed to get public account list")
return
@@ -80,10 +84,10 @@ async def process(self):
self.account_list_digest = _resp_digest
# Update DB data
- db_session = BatchAsyncSessionLocal()
+ db_session = Session(autocommit=False, autoflush=True, bind=db_engine)
try:
# Delete all account list from DB
- await db_session.execute(delete(PublicAccountList))
+ db_session.execute(delete(PublicAccountList))
# Insert account list
for i, _account in enumerate(account_list_json):
@@ -109,7 +113,7 @@ async def process(self):
f"Invalid address: index={i} account_address={account_address}"
)
continue
- await self.__sink_on_account_list(
+ self.__sink_on_account_list(
db_session=db_session,
key_manager=key_manager,
key_manager_name=key_manager_name,
@@ -117,18 +121,18 @@ async def process(self):
account_address=account_address,
)
- await db_session.commit()
+ db_session.commit()
except Exception as e:
- await db_session.rollback()
+ db_session.rollback()
raise e
finally:
- await db_session.close()
+ db_session.close()
LOG.info("Sync job has been completed")
@staticmethod
- async def __sink_on_account_list(
- db_session: AsyncSession,
+ def __sink_on_account_list(
+ db_session: Session,
key_manager: str,
key_manager_name: str,
account_type: int,
@@ -139,17 +143,17 @@ async def __sink_on_account_list(
_account_list.key_manager_name = key_manager_name
_account_list.account_type = account_type
_account_list.account_address = account_address
- await db_session.merge(_account_list)
+ db_session.merge(_account_list)
-async def main():
+def main():
LOG.info("Service started successfully")
processor = Processor()
while True:
start_time = time.time()
try:
- await processor.process()
+ processor.process()
except ServiceUnavailable:
LOG.notice("An external service was unavailable")
except SQLAlchemyError as sa_err:
@@ -158,12 +162,12 @@ async def main():
LOG.exception("An exception occurred during processing")
elapsed_time = time.time() - start_time
- await asyncio.sleep(max(PUBLIC_ACCOUNT_LIST_SLEEP_INTERVAL - elapsed_time, 0))
+ time.sleep(max(PUBLIC_ACCOUNT_LIST_SLEEP_INTERVAL - elapsed_time, 0))
free_malloc()
if __name__ == "__main__":
try:
- asyncio.run(main())
+ main()
except KeyboardInterrupt:
sys.exit(1)
diff --git a/batch/indexer_PublicInfo_TokenList.py b/batch/indexer_PublicInfo_TokenList.py
index b15b74f11..6a62be199 100644
--- a/batch/indexer_PublicInfo_TokenList.py
+++ b/batch/indexer_PublicInfo_TokenList.py
@@ -17,21 +17,26 @@
SPDX-License-Identifier: Apache-2.0
"""
-import asyncio
import hashlib
import json
import sys
import time
-import aiohttp
-from aiohttp import ClientTimeout
+import requests
from eth_utils import to_checksum_address
+from requests.adapters import HTTPAdapter
from sqlalchemy import delete
+from sqlalchemy.engine.create import create_engine
from sqlalchemy.exc import SQLAlchemyError
-from sqlalchemy.ext.asyncio import AsyncSession
-
-from app.config import REQUEST_TIMEOUT, TOKEN_LIST_SLEEP_INTERVAL, TOKEN_LIST_URL
-from app.database import BatchAsyncSessionLocal
+from sqlalchemy.orm.session import Session
+from urllib3 import Retry
+
+from app.config import (
+ DATABASE_URL,
+ REQUEST_TIMEOUT,
+ TOKEN_LIST_SLEEP_INTERVAL,
+ TOKEN_LIST_URL,
+)
from app.errors import ServiceUnavailable
from app.model.db import TokenList
from batch import free_malloc, log
@@ -39,6 +44,8 @@
process_name = "INDEXER-PUBLIC-INFO-TOKEN-LIST"
LOG = log.get_logger(process_name=process_name)
+db_engine = create_engine(DATABASE_URL, echo=False, pool_pre_ping=True)
+
class Processor:
"""Processor for indexing token list"""
@@ -46,21 +53,22 @@ class Processor:
def __init__(self):
self.token_list_digest = None
- async def process(self):
+ def process(self):
LOG.info("Syncing token list")
# Get from TOKEN_LIST_URL
try:
- async with aiohttp.ClientSession(trust_env=True) as session:
- async with session.get(
- TOKEN_LIST_URL,
- timeout=ClientTimeout(
- connect=REQUEST_TIMEOUT[0], total=REQUEST_TIMEOUT[1]
- ),
- ) as response:
- if response.status != 200:
- raise Exception(f"status code={response.status}")
- token_list_json = await response.json()
+ with requests.Session() as session:
+ adapter = HTTPAdapter(max_retries=Retry(3, allowed_methods=["GET"]))
+ session.mount("http://", adapter)
+ session.mount("https://", adapter)
+ _resp = session.get(
+ url=TOKEN_LIST_URL,
+ timeout=REQUEST_TIMEOUT,
+ )
+ if _resp.status_code != 200:
+ raise Exception(f"status code={_resp.status_code}")
+ token_list_json = _resp.json()
except Exception:
LOG.exception("Failed to get token list")
return
@@ -74,10 +82,10 @@ async def process(self):
self.token_list_digest = _resp_digest
# Update DB data
- db_session = BatchAsyncSessionLocal()
+ db_session = Session(autocommit=False, autoflush=True, bind=db_engine)
try:
# Delete all token list from DB
- await db_session.execute(delete(TokenList))
+ db_session.execute(delete(TokenList))
# Insert token list
for i, token in enumerate(token_list_json):
@@ -104,7 +112,7 @@ async def process(self):
)
continue
- await self.__sink_on_token_list(
+ self.__sink_on_token_list(
db_session=db_session,
token_address=token_address,
token_template=token_template,
@@ -112,18 +120,18 @@ async def process(self):
product_type=product_type,
)
- await db_session.commit()
+ db_session.commit()
except Exception as e:
- await db_session.rollback()
+ db_session.rollback()
raise e
finally:
- await db_session.close()
+ db_session.close()
LOG.info("Sync job has been completed")
@staticmethod
- async def __sink_on_token_list(
- db_session: AsyncSession,
+ def __sink_on_token_list(
+ db_session: Session,
token_address: str,
token_template: str,
key_manager: list[str],
@@ -134,17 +142,17 @@ async def __sink_on_token_list(
_token_list.token_template = token_template
_token_list.key_manager = key_manager
_token_list.product_type = product_type
- await db_session.merge(_token_list)
+ db_session.merge(_token_list)
-async def main():
+def main():
LOG.info("Service started successfully")
processor = Processor()
while True:
start_time = time.time()
try:
- await processor.process()
+ processor.process()
except ServiceUnavailable:
LOG.notice("An external service was unavailable")
except SQLAlchemyError as sa_err:
@@ -153,12 +161,12 @@ async def main():
LOG.exception("An exception occurred during processing")
elapsed_time = time.time() - start_time
- await asyncio.sleep(max(TOKEN_LIST_SLEEP_INTERVAL - elapsed_time, 0))
+ time.sleep(max(TOKEN_LIST_SLEEP_INTERVAL - elapsed_time, 0))
free_malloc()
if __name__ == "__main__":
try:
- asyncio.run(main())
+ main()
except KeyboardInterrupt:
sys.exit(1)
diff --git a/batch/indexer_Token_Holders.py b/batch/indexer_Token_Holders.py
index 19f01a315..162cff177 100644
--- a/batch/indexer_Token_Holders.py
+++ b/batch/indexer_Token_Holders.py
@@ -260,6 +260,7 @@ async def __process_all(
await self.__process_force_lock(block_from, block_to)
await self.__process_unlock(block_from, block_to)
await self.__process_force_unlock(block_from, block_to)
+ await self.__process_force_change_locked_account(block_from, block_to)
if self.token_template == TokenType.IbetCoupon:
await self.__process_consume(block_from, block_to)
@@ -579,6 +580,41 @@ async def __process_force_unlock(self, block_from: int, block_to: int):
except Exception:
raise
+ async def __process_force_change_locked_account(
+ self, block_from: int, block_to: int
+ ):
+ """Process ForceChangeLockedAccount Event
+
+ - The process of updating Hold-Balance data by capturing the following events
+ - `ForceChangeLockedAccount` event on Token contracts
+
+ :param block_from: From block
+ :param block_to: To block
+ :return: None
+ """
+ try:
+ # Get "ForceChangeLockedAccount" events from token contract
+ events = await self.token_contract.events.ForceChangeLockedAccount.get_logs(
+ from_block=block_from, to_block=block_to
+ )
+ except ABIEventNotFound:
+ events = []
+ try:
+ for event in events:
+ args = event["args"]
+ before_account_address = args.get("beforeAccountAddress", ZERO_ADDRESS)
+ after_account_address = args.get("afterAccountAddress", ZERO_ADDRESS)
+ amount = args.get("value")
+ if amount is not None and amount <= sys.maxsize:
+ self.balance_book.store(
+ account_address=before_account_address, locked=-amount
+ )
+ self.balance_book.store(
+ account_address=after_account_address, locked=+amount
+ )
+ except Exception:
+ raise
+
@staticmethod
async def __save_holders(
db_session: AsyncSession,
diff --git a/batch/indexer_Transfer.py b/batch/indexer_Transfer.py
index e9d6a82af..13e788baf 100644
--- a/batch/indexer_Transfer.py
+++ b/batch/indexer_Transfer.py
@@ -24,6 +24,7 @@
from typing import List, Optional, Sequence
from eth_utils import to_checksum_address
+from hexbytes import HexBytes
from pydantic import ValidationError
from sqlalchemy import desc, select
from sqlalchemy.exc import SQLAlchemyError
@@ -36,11 +37,11 @@
from app.database import BatchAsyncSessionLocal
from app.errors import ServiceUnavailable
from app.model.db import (
- DataMessage,
IDXTransfer,
IDXTransferBlockNumber,
IDXTransferSourceEventType,
Listing,
+ TransferDataMessage,
)
from app.model.schema.base import TokenType
from app.utils.web3_utils import AsyncWeb3Wrapper
@@ -182,7 +183,7 @@ def __insert_idx(
if data_str is not None:
try:
data = json.loads(data_str)
- validated_data = DataMessage(**data)
+ validated_data = TransferDataMessage(**data)
message = validated_data.message
except ValidationError:
data = {}
@@ -319,6 +320,7 @@ async def __sync_all(
await self.__sync_transfer(db_session, block_from, block_to)
await self.__sync_unlock(db_session, block_from, block_to)
await self.__sync_force_unlock(db_session, block_from, block_to)
+ await self.__sync_force_change_locked_account(db_session, block_from, block_to)
await self.__update_skip_block(db_session)
async def __sync_transfer(
@@ -375,14 +377,33 @@ async def __sync_transfer(
f"Skip Registry Transfer data in DB: blockNumber={event['blockNumber']}"
)
continue
+
+ # Judge whether the transfer is a reallocation
+ transaction_hash = event["transactionHash"].to_0x_hex()
+ is_reallocation = False
+ tx = await AsyncContract.get_transaction(
+ event["transactionHash"], event["blockNumber"]
+ )
+ tx_data: HexBytes | None = tx.get("input")
+ # Check if the transaction data contains the reallocation marker("c0ffee00")
+ if "c0ffee00" in tx_data.hex():
+ try:
+ raw_call_data = tx_data.hex().split("c0ffee00", 1)[1]
+ call_data = json.loads(bytes.fromhex(raw_call_data))
+ if call_data.get("purpose") == "Reallocation":
+ is_reallocation = True
+ except (ValueError, json.JSONDecodeError):
+ pass
self.__insert_idx(
db_session=db_session,
- transaction_hash=event["transactionHash"].to_0x_hex(),
+ transaction_hash=transaction_hash,
token_address=to_checksum_address(token.address),
from_account_address=args.get("from", ZERO_ADDRESS),
to_account_address=args.get("to", ZERO_ADDRESS),
value=value,
- source_event=IDXTransferSourceEventType.TRANSFER,
+ source_event=IDXTransferSourceEventType.REALLOCATION
+ if is_reallocation is True
+ else IDXTransferSourceEventType.TRANSFER,
data_str=None,
event_created=event_created,
)
@@ -525,6 +546,74 @@ async def __sync_force_unlock(
except Exception:
raise
+ async def __sync_force_change_locked_account(
+ self, db_session: AsyncSession, block_from: int, block_to: int
+ ):
+ """Synchronize ForceChangeLockedAccount events
+
+ :param db_session: database session
+ :param block_from: from block number
+ :param block_to: to block number
+ :return: None
+ """
+ for target in self.token_list:
+ token = target.token_contract
+ skip_block = target.skip_block
+
+ # Get "ForceChangeLockedAccount" logs
+ try:
+ if skip_block is not None and block_to <= skip_block:
+ # Skip if the token has already been synchronized to block_to.
+ LOG.debug(f"{token.address}: block_to <= skip_block")
+ continue
+ elif skip_block is not None and block_from <= skip_block < block_to:
+ # block_from <= skip_block < block_to
+ LOG.debug(f"{token.address}: block_from <= skip_block < block_to")
+ events = await token.events.ForceChangeLockedAccount.get_logs(
+ from_block=skip_block + 1, to_block=block_to
+ )
+ else:
+ # No logs or
+ # skip_block < block_from < block_to
+ LOG.debug(f"{token.address}: skip_block < block_from < block_to")
+ events = await token.events.ForceChangeLockedAccount.get_logs(
+ from_block=block_from, to_block=block_to
+ )
+ except ABIEventNotFound:
+ events = []
+
+ # Index logs
+ try:
+ for event in events:
+ args = event["args"]
+ transaction_hash = event["transactionHash"].to_0x_hex()
+ block_timestamp = datetime.fromtimestamp(
+ (await async_web3.eth.get_block(event["blockNumber"]))[
+ "timestamp"
+ ],
+ UTC,
+ ).replace(tzinfo=None)
+ if args["value"] > sys.maxsize:
+ pass
+ else:
+ from_address = args.get("beforeAccountAddress", ZERO_ADDRESS)
+ to_address = args.get("afterAccountAddress", ZERO_ADDRESS)
+ data_str = args.get("data", "")
+ if from_address != to_address:
+ self.__insert_idx(
+ db_session=db_session,
+ transaction_hash=transaction_hash,
+ token_address=to_checksum_address(token.address),
+ from_account_address=from_address,
+ to_account_address=to_address,
+ value=args["value"],
+ source_event=IDXTransferSourceEventType.FORCE_CHANGE_LOCKED_ACCOUNT,
+ data_str=data_str,
+ event_created=block_timestamp,
+ )
+ except Exception:
+ raise
+
async def __update_skip_block(self, db_session: AsyncSession):
"""Memorize the block number where next processing should start from
diff --git a/batch/processor_Notifications_Coupon_Exchange.py b/batch/processor_Notifications_Coupon_Exchange.py
index a9e214aa8..0c9d21e20 100644
--- a/batch/processor_Notifications_Coupon_Exchange.py
+++ b/batch/processor_Notifications_Coupon_Exchange.py
@@ -236,6 +236,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -276,6 +277,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -319,6 +321,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 2
@@ -359,6 +362,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 1)
notification.notification_type = self.notification_type
notification.priority = 1
@@ -399,6 +403,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 2)
notification.notification_type = self.notification_type
notification.priority = 2
@@ -439,6 +444,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 1)
notification.notification_type = self.notification_type
notification.priority = 1
@@ -482,6 +488,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 2)
notification.notification_type = self.notification_type
notification.priority = 1
@@ -522,6 +529,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 1)
notification.notification_type = self.notification_type
notification.priority = 2
@@ -565,6 +573,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 2)
notification.notification_type = self.notification_type
notification.priority = 2
diff --git a/batch/processor_Notifications_Membership_Exchange.py b/batch/processor_Notifications_Membership_Exchange.py
index 28de790f7..7c0997ddb 100644
--- a/batch/processor_Notifications_Membership_Exchange.py
+++ b/batch/processor_Notifications_Membership_Exchange.py
@@ -236,6 +236,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -279,6 +280,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -322,6 +324,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 2
@@ -362,6 +365,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 1)
notification.notification_type = self.notification_type
notification.priority = 1
@@ -402,6 +406,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 2)
notification.notification_type = self.notification_type
notification.priority = 2
@@ -445,6 +450,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 1)
notification.notification_type = self.notification_type
notification.priority = 1
@@ -488,6 +494,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 2)
notification.notification_type = self.notification_type
notification.priority = 1
@@ -531,6 +538,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 1)
notification.notification_type = self.notification_type
notification.priority = 2
@@ -574,6 +582,7 @@ async def watch(self, db_session: AsyncSession, entries):
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry, 2)
notification.notification_type = self.notification_type
notification.priority = 2
diff --git a/batch/processor_Notifications_Token.py b/batch/processor_Notifications_Token.py
index 1153b9599..ae2166e10 100644
--- a/batch/processor_Notifications_Token.py
+++ b/batch/processor_Notifications_Token.py
@@ -26,8 +26,11 @@
from sqlalchemy import and_, select
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.ext.asyncio import AsyncSession
+from web3 import Web3
from web3.contract import AsyncContract as Web3AsyncContract
-from web3.exceptions import ABIEventNotFound
+from web3.exceptions import (
+ ABIEventNotFound,
+)
from web3.types import EventData
from app.config import (
@@ -38,13 +41,16 @@
from app.contracts import AsyncContract
from app.database import BatchAsyncSessionLocal
from app.errors import ServiceUnavailable
+from app.model.blockchain import BondToken, CouponToken, MembershipToken, ShareToken
from app.model.db import (
IDXTokenListRegister,
Listing,
Notification,
+ NotificationAttributeValue,
NotificationBlockNumber,
NotificationType,
)
+from app.model.schema.base import TokenType
from app.utils.asyncio_utils import SemaphoreTaskGroup
from app.utils.company_list import CompanyList
from app.utils.web3_utils import AsyncWeb3Wrapper
@@ -66,14 +72,25 @@
token_list = TokenList(list_contract)
-# Watcher
-class Watcher:
+# EventWatcher
+class EventWatcher:
contract_cache: dict[str, Web3AsyncContract] = {}
- def __init__(self, filter_name: str, filter_params: dict, notification_type: str):
+ def __init__(
+ self,
+ filter_name: str,
+ filter_params: dict,
+ notification_type: str,
+ token_type_list: list[TokenType] = None,
+ skip_past_data_on_initial_sync: bool = False,
+ ):
+ if token_type_list is None:
+ token_type_list = list([])
self.filter_name = filter_name
self.filter_params = filter_params
self.notification_type = notification_type
+ self.token_type_list = token_type_list
+ self.skip_past_data_on_initial_sync = skip_past_data_on_initial_sync
@staticmethod
def _gen_notification_id(entry, option_type=0):
@@ -91,15 +108,19 @@ async def _gen_block_timestamp(entry):
).replace(tzinfo=None)
@staticmethod
- async def _get_token_all_list(db_session: AsyncSession):
+ async def _get_token_all_list(
+ db_session: AsyncSession, token_type_list: list[TokenType]
+ ):
_tokens = []
+
+ stmt = select(IDXTokenListRegister).join(
+ Listing,
+ and_(Listing.token_address == IDXTokenListRegister.token_address),
+ )
+ if len(token_type_list) != 0:
+ stmt = stmt.where(IDXTokenListRegister.token_template.in_(token_type_list))
registered_tokens: Sequence[IDXTokenListRegister] = (
- await db_session.scalars(
- select(IDXTokenListRegister).join(
- Listing,
- and_(Listing.token_address == IDXTokenListRegister.token_address),
- )
- )
+ await db_session.scalars(stmt)
).all()
for registered_token in registered_tokens:
_tokens.append(
@@ -126,7 +147,9 @@ async def loop(self):
try:
# Get listed tokens
- _token_list = await self._get_token_all_list(db_session)
+ _token_list = await self._get_token_all_list(
+ db_session, self.token_type_list
+ )
latest_block_number = await async_web3.eth.block_number
for _token in _token_list:
@@ -136,6 +159,8 @@ async def loop(self):
db_session=db_session,
contract_address=_token["token"].token_address,
notification_type=self.notification_type,
+ latest_block_number=latest_block_number,
+ skip_past_data_on_initial_sync=self.skip_past_data_on_initial_sync,
)
+ 1
)
@@ -210,7 +235,11 @@ async def loop(self):
@staticmethod
async def __get_synchronized_block_number(
- db_session: AsyncSession, contract_address: str, notification_type: str
+ db_session: AsyncSession,
+ contract_address: str,
+ notification_type: str,
+ latest_block_number: int,
+ skip_past_data_on_initial_sync: bool,
):
"""Get latest synchronized blockNumber"""
notification_block_number: NotificationBlockNumber | None = (
@@ -222,6 +251,8 @@ async def __get_synchronized_block_number(
)
).first()
if notification_block_number is None:
+ if skip_past_data_on_initial_sync is True:
+ return latest_block_number - 1
return -1
else:
return notification_block_number.latest_block_number
@@ -250,7 +281,7 @@ async def __set_synchronized_block_number(
await db_session.merge(notification_block_number)
-class WatchTransfer(Watcher):
+class WatchTransfer(EventWatcher):
"""Watch Token Receive Event
- Process for registering a notification when a token is received
@@ -288,6 +319,7 @@ async def db_merge(
"token_type": token_type,
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -298,7 +330,7 @@ async def db_merge(
await db_session.merge(notification)
-class WatchApplyForTransfer(Watcher):
+class WatchApplyForTransfer(EventWatcher):
"""Watch Token ApplyForTransfer Event
- Process for registering a notification when application for transfer is submitted
@@ -333,6 +365,7 @@ async def db_merge(
"token_type": token_type,
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -343,7 +376,7 @@ async def db_merge(
await db_session.merge(notification)
-class WatchApproveTransfer(Watcher):
+class WatchApproveTransfer(EventWatcher):
"""Watch Token ApproveTransfer Event
- Process for registering a notification when application for transfer is approved
@@ -378,6 +411,7 @@ async def db_merge(
"token_type": token_type,
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -388,7 +422,7 @@ async def db_merge(
await db_session.merge(notification)
-class WatchCancelTransfer(Watcher):
+class WatchCancelTransfer(EventWatcher):
"""Watch Token CancelTransfer Event
- Process for registering a notification when application for transfer is canceled
@@ -423,6 +457,7 @@ async def db_merge(
"token_type": token_type,
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -433,7 +468,7 @@ async def db_merge(
await db_session.merge(notification)
-class WatchForceLock(Watcher):
+class WatchForceLock(EventWatcher):
"""Watch ForceLock Event
- Process for registering a notification when a token is forcibly locked.
@@ -464,6 +499,7 @@ async def db_merge(
"token_type": token_type,
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -474,7 +510,7 @@ async def db_merge(
await db_session.merge(notification)
-class WatchForceUnlock(Watcher):
+class WatchForceUnlock(EventWatcher):
"""Watch ForceUnlock Event
- Process for registering a notification when a token is forcibly unlocked.
@@ -505,6 +541,7 @@ async def db_merge(
"token_type": token_type,
}
notification = Notification()
+ notification.notification_category = "event_log"
notification.notification_id = self._gen_notification_id(entry)
notification.notification_type = self.notification_type
notification.priority = 0
@@ -515,6 +552,358 @@ async def db_merge(
await db_session.merge(notification)
+class WatchChangeToRedeemed(EventWatcher):
+ """Watch ChangeToRedeemed Event for Bond Token
+
+ - Process for registering a notification when a token status is changed to redeemed.
+ """
+
+ def __init__(self):
+ super().__init__(
+ filter_name="ChangeToRedeemed",
+ filter_params={},
+ notification_type=NotificationType.CHANGE_TO_REDEEMED,
+ token_type_list=[TokenType.IbetStraightBond],
+ skip_past_data_on_initial_sync=True,
+ )
+
+ async def db_merge(
+ self,
+ db_session: AsyncSession,
+ token_contract: Web3AsyncContract,
+ token_type: str,
+ log_entries: list[EventData],
+ token_owner_address: str,
+ ):
+ company_list = await CompanyList.get()
+ token_name = await AsyncContract.call_function(
+ contract=token_contract, function_name="name", args=(), default_returns=""
+ )
+ for entry in log_entries:
+ company = company_list.find(token_owner_address)
+ metadata = {
+ "company_name": company.corporate_name,
+ "token_address": entry["address"],
+ "token_name": token_name,
+ "exchange_address": "",
+ "token_type": token_type,
+ }
+ notification = Notification()
+ notification.notification_category = "event_log"
+ notification.notification_id = self._gen_notification_id(entry)
+ notification.notification_type = self.notification_type
+ notification.priority = 0
+ notification.address = None
+ notification.block_timestamp = await self._gen_block_timestamp(entry)
+ notification.args = dict(entry["args"])
+ notification.metainfo = metadata
+ await db_session.merge(notification)
+
+
+class WatchChangeToCanceled(EventWatcher):
+ """Watch ChangeToCanceled Event for Share Token
+
+ - Process for registering a notification when a token status is changed to canceled.
+ """
+
+ def __init__(self):
+ super().__init__(
+ filter_name="ChangeToCanceled",
+ filter_params={},
+ notification_type=NotificationType.CHANGE_TO_CANCELED,
+ token_type_list=[TokenType.IbetShare],
+ skip_past_data_on_initial_sync=True,
+ )
+
+ async def db_merge(
+ self,
+ db_session: AsyncSession,
+ token_contract: Web3AsyncContract,
+ token_type: str,
+ log_entries: list[EventData],
+ token_owner_address: str,
+ ):
+ company_list = await CompanyList.get()
+ token_name = await AsyncContract.call_function(
+ contract=token_contract, function_name="name", args=(), default_returns=""
+ )
+ for entry in log_entries:
+ company = company_list.find(token_owner_address)
+ metadata = {
+ "company_name": company.corporate_name,
+ "token_address": entry["address"],
+ "token_name": token_name,
+ "exchange_address": "",
+ "token_type": token_type,
+ }
+ notification = Notification()
+ notification.notification_category = "event_log"
+ notification.notification_id = self._gen_notification_id(entry)
+ notification.notification_type = self.notification_type
+ notification.priority = 0
+ notification.address = None
+ notification.block_timestamp = await self._gen_block_timestamp(entry)
+ notification.args = dict(entry["args"])
+ notification.metainfo = metadata
+ await db_session.merge(notification)
+
+
+# AttributeWatcher
+class AttributeWatcher:
+ def __init__(
+ self,
+ attribute_key: str,
+ notification_type: str,
+ token_type_list: list[TokenType] = None,
+ ):
+ if token_type_list is None:
+ token_type_list = list([])
+ self.notification_type = notification_type
+ self.token_type_list = token_type_list
+ self.attribute_key = attribute_key
+ self.attribute_key_hash = Web3.keccak(text=attribute_key).hex()[0:8]
+
+ @staticmethod
+ def _gen_notification_id(
+ timestamp_ms: int, contract_address: str, attribute_key_hash: str, option_type=0
+ ):
+ contract_address_without_prefix = contract_address.replace("0x", "").lower()
+ return f"0x{timestamp_ms:012x}{contract_address_without_prefix}{attribute_key_hash}{option_type:02x}"
+
+ @staticmethod
+ async def _get_token_all_list(
+ db_session: AsyncSession, token_type_list: list[TokenType]
+ ):
+ _tokens = []
+
+ stmt = select(IDXTokenListRegister).join(
+ Listing,
+ and_(Listing.token_address == IDXTokenListRegister.token_address),
+ )
+ if len(token_type_list) != 0:
+ stmt = stmt.where(IDXTokenListRegister.token_template.in_(token_type_list))
+ registered_tokens: Sequence[IDXTokenListRegister] = (
+ await db_session.scalars(stmt)
+ ).all()
+ for registered_token in registered_tokens:
+ _tokens.append(
+ {
+ "token": registered_token,
+ "token_type": registered_token.token_template,
+ }
+ )
+ return _tokens
+
+ async def db_merge(
+ self,
+ db_session: AsyncSession,
+ token_address: str,
+ token_type: str,
+ token_name: str,
+ token_owner_address: str,
+ previous_value: str | int | bool,
+ current_value: str | int | bool,
+ ):
+ pass
+
+ async def loop(self):
+ start_time = time.time()
+ db_session = BatchAsyncSessionLocal()
+
+ try:
+ # Get listed tokens
+ _token_list = await self._get_token_all_list(
+ db_session, self.token_type_list
+ )
+
+ for _token in _token_list:
+ try:
+ # Get previous attribute value from DB
+ previous_attribute_key_value = await self.__get_attribute_value(
+ db_session,
+ _token["token"].token_address,
+ self.attribute_key,
+ )
+ is_initial_sync = (
+ True if previous_attribute_key_value is None else False
+ )
+
+ # Get token detail by token type
+ if _token["token_type"] == TokenType.IbetStraightBond:
+ token_detail = await BondToken.get(
+ async_session=db_session,
+ token_address=_token["token"].token_address,
+ )
+ elif _token["token_type"] == TokenType.IbetShare:
+ token_detail = await ShareToken.get(
+ async_session=db_session,
+ token_address=_token["token"].token_address,
+ )
+ elif _token["token_type"] == TokenType.IbetCoupon:
+ token_detail = await CouponToken.get(
+ async_session=db_session,
+ token_address=_token["token"].token_address,
+ )
+ elif _token["token_type"] == TokenType.IbetMembership:
+ token_detail = await MembershipToken.get(
+ async_session=db_session,
+ token_address=_token["token"].token_address,
+ )
+ else: # pragma: no cover
+ continue
+
+ # Get current attribute value from token detail
+ current_attribute_value = token_detail.__dict__.get(
+ self.attribute_key
+ )
+
+ if is_initial_sync is False:
+ # Get previous attribute value from DB record
+ previous_attribute_value = (
+ previous_attribute_key_value.attribute.get(
+ self.attribute_key, None
+ )
+ )
+ # Register notification only if attribute value has changed
+ if (
+ current_attribute_value is not None
+ and current_attribute_value != previous_attribute_value
+ ):
+ token_name = token_detail.name
+ # Register attribute change notification
+ await self.db_merge(
+ db_session=db_session,
+ token_address=_token["token"].token_address,
+ token_type=_token["token_type"],
+ token_owner_address=_token["token"].owner_address,
+ token_name=token_name,
+ previous_value=previous_attribute_value,
+ current_value=current_attribute_value,
+ )
+
+ # Save latest attribute value to DB
+ await self.__set_attribute_value(
+ db_session,
+ _token["token"].token_address,
+ self.attribute_key,
+ current_attribute_value,
+ )
+ await db_session.commit()
+
+ except Exception: # Continue processing even if an exception occurs
+ LOG.exception("Failed to watch attribute")
+ continue
+
+ except SQLAlchemyError as sa_err:
+ LOG.error(f"A database error has occurred: code={sa_err.code}\n{sa_err}")
+ finally:
+ await db_session.close()
+ elapsed_time = time.time() - start_time
+ LOG.info(
+ "<{}> finished in {} secs".format(self.__class__.__name__, elapsed_time)
+ )
+
+ @staticmethod
+ async def __get_attribute_value(
+ db_session: AsyncSession, contract_address: str, attribute_key: str
+ ):
+ """Get latest synchronized attribute value"""
+ notification_attribute_value: NotificationAttributeValue | None = (
+ await db_session.scalars(
+ select(NotificationAttributeValue)
+ .where(
+ and_(
+ NotificationAttributeValue.contract_address == contract_address,
+ NotificationAttributeValue.attribute_key == attribute_key,
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ return notification_attribute_value
+
+ @staticmethod
+ async def __set_attribute_value(
+ db_session: AsyncSession,
+ contract_address: str,
+ attribute_key: str,
+ attribute_value: bool | int | str,
+ ):
+ """Set latest synchronized attribute value"""
+ notification_attribute_value: NotificationAttributeValue | None = (
+ await db_session.scalars(
+ select(NotificationAttributeValue)
+ .where(
+ and_(
+ NotificationAttributeValue.contract_address == contract_address,
+ NotificationAttributeValue.attribute_key == attribute_key,
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ if notification_attribute_value is None:
+ notification_attribute_value = NotificationAttributeValue()
+ notification_attribute_value.contract_address = contract_address
+ notification_attribute_value.attribute_key = attribute_key
+ notification_attribute_value.attribute = {attribute_key: attribute_value}
+ await db_session.merge(notification_attribute_value)
+
+
+class WatchTransferableAttribute(AttributeWatcher):
+ """Watch Transferable Attribute
+
+ - Process for registering a notification when a token attribute "transferable" is changed.
+ """
+
+ def __init__(self):
+ super().__init__(
+ attribute_key="transferable",
+ notification_type=NotificationType.TRANSFERABLE_CHANGED,
+ token_type_list=[TokenType.IbetShare, TokenType.IbetStraightBond],
+ )
+
+ async def db_merge(
+ self,
+ db_session: AsyncSession,
+ token_address: str,
+ token_type: str,
+ token_name: str,
+ token_owner_address: str,
+ previous_value: str | int | bool,
+ current_value: str | int | bool,
+ ):
+ company_list = await CompanyList.get()
+ company = company_list.find(token_owner_address)
+ metadata = {
+ "company_name": company.corporate_name,
+ "token_address": token_address,
+ "token_name": token_name,
+ "exchange_address": "",
+ "token_type": token_type,
+ }
+ timestamp_ms = int(time.time() * 1000)
+ notification = Notification()
+ notification.notification_category = "attribute_change"
+ notification.notification_id = self._gen_notification_id(
+ timestamp_ms=timestamp_ms,
+ contract_address=token_address,
+ attribute_key_hash=self.attribute_key_hash,
+ )
+ notification.notification_type = self.notification_type
+ notification.priority = 0
+ notification.address = None
+ notification.block_timestamp = datetime.fromtimestamp(timestamp_ms / 1000)
+ notification.args = dict(
+ {
+ "previous": previous_value,
+ "current": current_value,
+ }
+ )
+ notification.metainfo = metadata
+ await db_session.merge(notification)
+
+
# メイン処理
async def main():
watchers = [
@@ -524,6 +913,9 @@ async def main():
WatchCancelTransfer(),
WatchForceLock(),
WatchForceUnlock(),
+ WatchChangeToRedeemed(),
+ WatchChangeToCanceled(),
+ WatchTransferableAttribute(),
]
LOG.info("Service started successfully")
diff --git a/batch/processor_Send_Chat_Webhook.py b/batch/processor_Send_Chat_Webhook.py
index 0e272fcf2..77b6f7908 100644
--- a/batch/processor_Send_Chat_Webhook.py
+++ b/batch/processor_Send_Chat_Webhook.py
@@ -17,67 +17,68 @@
SPDX-License-Identifier: Apache-2.0
"""
-import asyncio
import sys
import time
from typing import Sequence
-import aiohttp
+import requests
from sqlalchemy import select
+from sqlalchemy.engine.create import create_engine
from sqlalchemy.exc import SQLAlchemyError
+from sqlalchemy.orm.session import Session
-from app.config import CHAT_WEBHOOK_URL
-from app.database import BatchAsyncSessionLocal
+from app.config import CHAT_WEBHOOK_URL, DATABASE_URL
from app.model.db import ChatWebhook
from batch import free_malloc, log
LOG = log.get_logger(process_name="PROCESSOR-SEND-CHAT-WEBHOOK")
+db_engine = create_engine(DATABASE_URL, echo=False, pool_pre_ping=True)
+
class Processor:
- async def process(self):
- db_session = BatchAsyncSessionLocal()
+ def process(self):
+ db_session = Session(autocommit=False, autoflush=True, bind=db_engine)
try:
hook_list: Sequence[ChatWebhook] = (
- await db_session.scalars(select(ChatWebhook))
+ db_session.scalars(select(ChatWebhook))
).all()
if len(hook_list) > 0:
LOG.info("Process start")
for hook in hook_list:
try:
- async with aiohttp.ClientSession(trust_env=True) as session:
- await session.post(CHAT_WEBHOOK_URL, json=hook.message)
+ requests.post(CHAT_WEBHOOK_URL, json=hook.message)
except Exception:
LOG.exception("Failed to send chat webhook")
finally:
# Delete the message regardless of the status code of the response.
- await db_session.delete(hook)
- await db_session.commit()
+ db_session.delete(hook)
+ db_session.commit()
LOG.info("Process end")
finally:
- await db_session.close()
+ db_session.close()
-async def main():
+def main():
LOG.info("Service started successfully")
processor = Processor()
while True:
start_time = time.time()
try:
- await processor.process()
+ processor.process()
except SQLAlchemyError as sa_err:
LOG.error(f"A database error has occurred: code={sa_err.code}\n{sa_err}")
except Exception as ex:
LOG.exception(ex)
elapsed_time = time.time() - start_time
- await asyncio.sleep(max(30 - elapsed_time, 0))
+ time.sleep(max(30 - elapsed_time, 0))
free_malloc()
if __name__ == "__main__":
try:
- asyncio.run(main())
+ main()
except KeyboardInterrupt:
sys.exit(1)
diff --git a/bin/run_indexer.sh b/bin/run_indexer.sh
index cd2093957..661f7a14a 100755
--- a/bin/run_indexer.sh
+++ b/bin/run_indexer.sh
@@ -58,6 +58,19 @@ if [ "${resp}" -ne 200 ]; then
echo "please confirm TOKEN_LIST_URL, which response code is ${resp}" >&2
fi
python batch/indexer_PublicInfo_TokenList.py &
+
+
+# check PUBLIC_ACCOUNT_LIST_URL
+if [ -z "${PUBLIC_ACCOUNT_LIST_URL:-}" ]; then
+ echo -n '[ERROR] Please ensure that the environment variable PUBLIC_ACCOUNT_LIST_URL is set.' >&2
+ exit 1
+fi
+# check PUBLIC_ACCOUNT_LIST_URL available
+resp=$(curl "${PUBLIC_ACCOUNT_LIST_URL}" -o /dev/null -w '%{http_code}\n' -s)
+if [ "${resp}" -ne 200 ]; then
+ echo -n "[WARNING] Could not access to PUBLIC_ACCOUNT_LIST_URL, " >&2
+ echo "please confirm PUBLIC_ACCOUNT_LIST_URL, which response code is ${resp}" >&2
+fi
python batch/indexer_PublicInfo_PublicAccountList.py &
diff --git a/cmd/explorer/pyproject.toml b/cmd/explorer/pyproject.toml
index def82606f..321100ce5 100644
--- a/cmd/explorer/pyproject.toml
+++ b/cmd/explorer/pyproject.toml
@@ -6,7 +6,7 @@ authors = [
{name = "BOOSTRY Co., Ltd.", email = "dev@boostry.co.jp"},
]
readme = "README.md"
-requires-python = "==3.12.2"
+requires-python = "==3.12.9"
dependencies = []
[project.scripts]
@@ -20,4 +20,4 @@ check_untyped_defs = true
[tool.setuptools.packages.find]
where = ["src/"]
-include = ["*"]
\ No newline at end of file
+include = ["*"]
diff --git a/cmd/explorer/uv.lock b/cmd/explorer/uv.lock
index b24abd34c..232581cce 100644
--- a/cmd/explorer/uv.lock
+++ b/cmd/explorer/uv.lock
@@ -1,5 +1,6 @@
version = 1
-requires-python = "==3.12.2"
+revision = 2
+requires-python = "==3.12.9"
[[package]]
name = "ibet-wallet-api-explorer"
diff --git a/docs/ibet_wallet_api.yaml b/docs/ibet_wallet_api.yaml
index 695d7f709..b3ae2669a 100644
--- a/docs/ibet_wallet_api.yaml
+++ b/docs/ibet_wallet_api.yaml
@@ -1,9 +1,9 @@
openapi: 3.1.0
info:
title: ibet Wallet API
- description: RPC services that provides utility tools for building a wallet system
- on ibet network
- version: 25.6.0
+ description: RPC services that provides utility tools for building a wallet
+ system on ibet network
+ version: 25.9.0
paths:
/:
get:
@@ -18,7 +18,8 @@ paths:
get:
tags:
- public_info
- summary: Information on issued tokens and associated institutions (key managers)
+ summary: Information on issued tokens and associated institutions (key
+ managers)
description: List issued tokens and associated institutions (key managers)
operationId: ListAllPublicListedTokens
parameters:
@@ -51,6 +52,8 @@ paths:
enum:
- ibetBond
- ibetShare
+ - ibetMembership
+ - ibetCoupon
type: string
description: Token template
title: Token Template
@@ -1070,7 +1073,8 @@ paths:
tags:
- eth_rpc
summary: Send signed transaction
- description: Sends raw transaction without waiting for transaction receipt.
+ description: Sends raw transaction without waiting for transaction
+ receipt.
operationId: SendRawTransactionNoWait
requestBody:
content:
@@ -2965,8 +2969,8 @@ paths:
tags:
- token_info
summary: Search Token holders
- description: Returns a list of token holders for a given token using detailed
- search query.
+ description: Returns a list of token holders for a given token using
+ detailed search query.
operationId: SearchTokenHolders
parameters:
- name: token_address
@@ -3069,7 +3073,8 @@ paths:
tags:
- token_info
summary: Execute Batch Getting Token Holders At Specific BlockNumber
- description: Enqueues task of collecting token holders for a given block number.
+ description: Enqueues task of collecting token holders for a given block
+ number.
operationId: TokenHoldersCollection
parameters:
- name: token_address
@@ -3130,13 +3135,13 @@ paths:
schema:
type: string
format: uuid
- description: Unique id to be assigned to each token holder list.This must
- be Version4 UUID.
+ description: Unique id to be assigned to each token holder list.This
+ must be Version4 UUID.
examples:
- cfd83622-34dc-4efe-a68b-2cc275d3d824
title: List Id
- description: Unique id to be assigned to each token holder list.This must
- be Version4 UUID.
+ description: Unique id to be assigned to each token holder list.This
+ must be Version4 UUID.
responses:
'200':
description: Successful Response
@@ -3496,8 +3501,8 @@ paths:
tags:
- token_info
summary: Search Token Transfer History
- description: Returns a list of transfer histories for a given token using detailed
- search query.
+ description: Returns a list of transfer histories for a given token using
+ detailed search query.
operationId: SearchTokenTransferHistory
parameters:
- name: token_address
@@ -3541,7 +3546,8 @@ paths:
tags:
- token_info
summary: Token Transfer Approval History
- description: Returns a list of transfer approval histories for a given token.
+ description: Returns a list of transfer approval histories for a given
+ token.
operationId: ListTokenTransferApprovalHistory
parameters:
- name: token_address
@@ -3654,8 +3660,8 @@ paths:
tags:
- token_info
summary: Search Token Transfer Approval History
- description: Returns a list of transfer approval histories for a given token
- using detailed search query.
+ description: Returns a list of transfer approval histories for a given
+ token using detailed search query.
operationId: SearchTokenTransferApprovalHistory
parameters:
- name: token_address
@@ -5041,6 +5047,17 @@ paths:
description: Limit for pagination
title: Limit
description: Limit for pagination
+ - name: notification_category
+ in: query
+ required: false
+ schema:
+ anyOf:
+ - enum:
+ - event_log
+ - attribute_change
+ type: string
+ - type: 'null'
+ title: Notification Category
- name: address
in: query
required: false
@@ -5237,8 +5254,8 @@ paths:
tags:
- messaging
summary: Retrieve message encryption key
- description: Returns encryption key for use in e2e messaging for given account
- address.
+ description: Returns encryption key for use in e2e messaging for given
+ account address.
operationId: EncryptionKey
parameters:
- name: account_address
@@ -5741,10 +5758,10 @@ paths:
required: true
schema:
$ref: '#/components/schemas/OrderType'
- description: Order type to be executed by the Orderer. If 'buy' is selected,
- the sell order book will be returned.
- description: Order type to be executed by the Orderer. If 'buy' is selected,
- the sell order book will be returned.
+ description: Order type to be executed by the Orderer. If 'buy' is
+ selected, the sell order book will be returned.
+ description: Order type to be executed by the Orderer. If 'buy' is
+ selected, the sell order book will be returned.
- name: account_address
in: query
required: false
@@ -5752,11 +5769,11 @@ paths:
anyOf:
- type: string
- type: 'null'
- description: Orderer's account address. Orders from the given address
- will not be included in the response.
+ description: Orderer's account address. Orders from the given
+ address will not be included in the response.
title: Account Address
- description: Orderer's account address. Orders from the given address will
- not be included in the response.
+ description: Orderer's account address. Orders from the given address
+ will not be included in the response.
responses:
'200':
description: Successful Response
@@ -5879,10 +5896,10 @@ paths:
required: true
schema:
$ref: '#/components/schemas/OrderType'
- description: Order type to be executed by the Orderer. If 'buy' is selected,
- the sell order book will be returned.
- description: Order type to be executed by the Orderer. If 'buy' is selected,
- the sell order book will be returned.
+ description: Order type to be executed by the Orderer. If 'buy' is
+ selected, the sell order book will be returned.
+ description: Order type to be executed by the Orderer. If 'buy' is
+ selected, the sell order book will be returned.
- name: account_address
in: query
required: false
@@ -5890,11 +5907,11 @@ paths:
anyOf:
- type: string
- type: 'null'
- description: Orderer's account address. Orders from the given address
- will not be included in the response.
+ description: Orderer's account address. Orders from the given
+ address will not be included in the response.
title: Account Address
- description: Orderer's account address. Orders from the given address will
- not be included in the response.
+ description: Orderer's account address. Orders from the given address
+ will not be included in the response.
responses:
'200':
description: Successful Response
@@ -6013,9 +6030,11 @@ paths:
anyOf:
- type: boolean
- type: 'null'
- description: Whether to include canceled orders or canceled agreements.
+ description: Whether to include canceled orders or canceled
+ agreements.
title: Include Canceled Items
- description: Whether to include canceled orders or canceled agreements.
+ description: Whether to include canceled orders or canceled
+ agreements.
responses:
'200':
description: Successful Response
@@ -6060,9 +6079,11 @@ paths:
anyOf:
- type: boolean
- type: 'null'
- description: Whether to include canceled orders or canceled agreements.
+ description: Whether to include canceled orders or canceled
+ agreements.
title: Include Canceled Items
- description: Whether to include canceled orders or canceled agreements.
+ description: Whether to include canceled orders or canceled
+ agreements.
responses:
'200':
description: Successful Response
@@ -6115,9 +6136,11 @@ paths:
anyOf:
- type: boolean
- type: 'null'
- description: Whether to include canceled orders or canceled agreements.
+ description: Whether to include canceled orders or canceled
+ agreements.
title: Include Canceled Items
- description: Whether to include canceled orders or canceled agreements.
+ description: Whether to include canceled orders or canceled
+ agreements.
responses:
'200':
description: Successful Response
@@ -6922,8 +6945,8 @@ components:
type: string
format: uuid4
title: List Id
- description: Unique id to be assigned to each token holder list.This must
- be Version4 UUID.
+ description: Unique id to be assigned to each token holder list.This
+ must be Version4 UUID.
examples:
- cfd83622-34dc-4efe-a68b-2cc275d3d824
block_number:
@@ -6941,8 +6964,8 @@ components:
type: string
format: uuid4
title: List Id
- description: Unique id to be assigned to each token holder list.This must
- be Version4 UUID.
+ description: Unique id to be assigned to each token holder list.This
+ must be Version4 UUID.
examples:
- cfd83622-34dc-4efe-a68b-2cc275d3d824
status:
@@ -6985,19 +7008,6 @@ components:
required:
- meta
title: DataConflictErrorResponse
- DataMessage:
- properties:
- message:
- type: string
- enum:
- - garnishment
- - inheritance
- - force_unlock
- title: Message
- type: object
- required:
- - message
- title: DataMessage
DataNotExistsErrorMetainfo:
properties:
code:
@@ -7122,7 +7132,8 @@ components:
required:
- result_set
- positions
- title: GenericSecurityTokenPositionsResponse[RetrieveStraightBondTokenResponse]
+ title:
+ GenericSecurityTokenPositionsResponse[RetrieveStraightBondTokenResponse]
GenericSuccessResponse_ABI_:
properties:
meta:
@@ -7432,7 +7443,8 @@ components:
required:
- meta
- data
- title: GenericSuccessResponse[ListAllLockEventsResponse[RetrieveShareTokenResponse]]
+ title:
+ GenericSuccessResponse[ListAllLockEventsResponse[RetrieveShareTokenResponse]]
GenericSuccessResponse_ListAllLockEventsResponse_RetrieveStraightBondTokenResponse__:
properties:
meta:
@@ -7533,7 +7545,8 @@ components:
required:
- meta
- data
- title: GenericSuccessResponse[ListAllOrderListResponse[RetrieveCouponTokenResponse]]
+ title:
+ GenericSuccessResponse[ListAllOrderListResponse[RetrieveCouponTokenResponse]]
GenericSuccessResponse_ListAllOrderListResponse_RetrieveMembershipTokenResponse__:
properties:
meta:
@@ -7842,7 +7855,8 @@ components:
required:
- meta
- data
- title: GenericSuccessResponse[RetrievePaymentAccountRegistrationStatusResponse]
+ title:
+ GenericSuccessResponse[RetrievePaymentAccountRegistrationStatusResponse]
GenericSuccessResponse_RetrievePersonalInfoRegistrationStatusResponse_:
properties:
meta:
@@ -7856,7 +7870,8 @@ components:
required:
- meta
- data
- title: GenericSuccessResponse[RetrievePersonalInfoRegistrationStatusResponse]
+ title:
+ GenericSuccessResponse[RetrievePersonalInfoRegistrationStatusResponse]
GenericSuccessResponse_RetrieveShareTokenResponse_:
properties:
meta:
@@ -8284,6 +8299,31 @@ components:
- token_template
- product_type
title: IbetBondToken
+ IbetCouponToken:
+ properties:
+ token_address:
+ type: string
+ title: Token Address
+ key_manager:
+ items:
+ type: string
+ type: array
+ title: Key Manager
+ token_template:
+ type: string
+ const: ibetCoupon
+ title: Token Template
+ product_type:
+ type: integer
+ const: 1
+ title: Product Type
+ type: object
+ required:
+ - token_address
+ - key_manager
+ - token_template
+ - product_type
+ title: IbetCouponToken
IbetEscrowEventType:
type: string
enum:
@@ -8293,6 +8333,31 @@ components:
- EscrowCanceled
- EscrowFinished
title: IbetEscrowEventType
+ IbetMembershipToken:
+ properties:
+ token_address:
+ type: string
+ title: Token Address
+ key_manager:
+ items:
+ type: string
+ type: array
+ title: Key Manager
+ token_template:
+ type: string
+ const: ibetMembership
+ title: Token Template
+ product_type:
+ type: integer
+ const: 1
+ title: Product Type
+ type: object
+ required:
+ - token_address
+ - key_manager
+ - token_template
+ - product_type
+ title: IbetMembershipToken
IbetSecurityTokenDVPEventType:
type: string
enum:
@@ -8711,6 +8776,8 @@ components:
anyOf:
- $ref: '#/components/schemas/IbetBondToken'
- $ref: '#/components/schemas/IbetShareToken'
+ - $ref: '#/components/schemas/IbetMembershipToken'
+ - $ref: '#/components/schemas/IbetCouponToken'
type: array
title: Tokens
type: object
@@ -8847,7 +8914,8 @@ components:
type: string
format: date-time
title: Block Timestamp
- description: block_timestamp when Lock log was emitted (local_timezone)
+ description: block_timestamp when Lock log was emitted
+ (local_timezone)
type: object
required:
- category
@@ -8925,7 +8993,8 @@ components:
type: string
format: date-time
title: Block Timestamp
- description: block_timestamp when Lock log was emitted (local_timezone)
+ description: block_timestamp when Lock log was emitted
+ (local_timezone)
token:
$ref: '#/components/schemas/RetrieveShareTokenResponse'
description: Token information
@@ -8992,7 +9061,8 @@ components:
type: string
format: date-time
title: Block Timestamp
- description: block_timestamp when Lock log was emitted (local_timezone)
+ description: block_timestamp when Lock log was emitted
+ (local_timezone)
token:
$ref: '#/components/schemas/RetrieveStraightBondTokenResponse'
description: Token information
@@ -9290,15 +9360,21 @@ components:
title: NotSupportedErrorResponse
Notification:
properties:
- notification_type:
- $ref: '#/components/schemas/NotificationType'
- examples:
- - NewOrder
+ notification_category:
+ type: string
+ enum:
+ - event_log
+ - attribute_change
+ title: Notification Category
id:
type: string
title: Id
examples:
- '0x00000373ca8600000000000000'
+ notification_type:
+ $ref: '#/components/schemas/NotificationType'
+ examples:
+ - NewOrder
priority:
type: integer
title: Priority
@@ -9340,8 +9416,9 @@ components:
description: datetime of create
type: object
required:
- - notification_type
+ - notification_category
- id
+ - notification_type
- priority
- block_timestamp
- is_read
@@ -9411,6 +9488,9 @@ components:
- CancelTransfer
- ForceLock
- ForceUnlock
+ - ChangeToRedeemed
+ - ChangeToCanceled
+ - TransferableChanged
title: NotificationType
NotificationUpdateResponse:
properties:
@@ -9674,8 +9754,8 @@ components:
- type: boolean
- type: 'null'
title: Skip Conflict Error
- description: If set to `True`, a `200` response will be returned instead
- of a `409` error in case of duplicate data.
+ description: If set to `True`, a `200` response will be returned
+ instead of a `409` error in case of duplicate data.
default: false
type: object
required:
@@ -10585,8 +10665,8 @@ components:
- 1
status:
$ref: '#/components/schemas/SendRawTransactionStatus'
- description: execution failure:0, execution success:1, execution success(pending
- transaction):2
+ description: execution failure:0, execution success:1, execution
+ success(pending transaction):2
examples:
- 1
transaction_hash:
@@ -11097,7 +11177,8 @@ components:
hold_balance:
type: integer
title: Hold Balance
- description: Amount of balance.This includes balance/pending_transfer/exchange_balance/exchange_commitment/locked.
+ description: Amount of balance.This includes
+ balance/pending_transfer/exchange_balance/exchange_commitment/locked.
locked_balance:
type: integer
title: Locked Balance
@@ -11117,7 +11198,8 @@ components:
$ref: '#/components/schemas/TokenHoldersCollectionHolder'
type: array
title: Holders
- description: Token holder list.This list is excluding token owner address.
+ description: Token holder list.This list is excluding token owner
+ address.
type: object
required:
- status
@@ -11324,6 +11406,20 @@ components:
- cancelled
- transfer_approved
title: TransferApprovalHistory
+ TransferDataMessage:
+ properties:
+ message:
+ type: string
+ enum:
+ - garnishment
+ - inheritance
+ - force_unlock
+ - ibet_wst_bridge
+ title: Message
+ type: object
+ required:
+ - message
+ title: TransferDataMessage
TransferHistoriesResponse:
properties:
result_set:
@@ -11332,7 +11428,7 @@ components:
items:
anyOf:
- $ref: '#/components/schemas/TransferHistory'
- - $ref: '#/components/schemas/UnlockTransferHistory'
+ - $ref: '#/components/schemas/TransferWithMessage'
type: array
title: Transfer History
description: Transfer history
@@ -11374,15 +11470,19 @@ components:
- garnishment
- inheritance
- force_unlock
+ - ibet_wst_bridge
- type: 'null'
title: Message
created:
type: string
title: Created
- description: block_timestamp when Transfer log was emitted (local timezone)
+ description: block_timestamp when Transfer log was emitted (local
+ timezone)
source_event:
type: string
- const: Transfer
+ enum:
+ - Transfer
+ - Reallocation
title: Source Event
description: Source Event
type: object
@@ -11403,7 +11503,72 @@ components:
- Transfer
- Unlock
- ForceUnlock
+ - ForceChangeLockedAccount
+ - Reallocation
title: TransferSourceEvent
+ TransferWithMessage:
+ properties:
+ transaction_hash:
+ type: string
+ title: Transaction Hash
+ description: Transaction hash
+ token_address:
+ type: string
+ title: Token Address
+ description: Token address
+ from_address:
+ type: string
+ title: From Address
+ description: Account address of transfer source
+ to_address:
+ type: string
+ title: To Address
+ description: Account address of transfer destination
+ value:
+ type: integer
+ title: Value
+ description: Transfer quantity
+ data:
+ anyOf:
+ - $ref: '#/components/schemas/TransferDataMessage'
+ - type: object
+ title: Data
+ description: Event data
+ message:
+ anyOf:
+ - type: string
+ enum:
+ - garnishment
+ - inheritance
+ - force_unlock
+ - ibet_wst_bridge
+ - type: 'null'
+ title: Message
+ created:
+ type: string
+ title: Created
+ description: block_timestamp when Transfer log was emitted (local
+ timezone)
+ source_event:
+ type: string
+ enum:
+ - Unlock
+ - ForceUnlock
+ - ForceChangeLockedAccount
+ title: Source Event
+ description: Source Event
+ type: object
+ required:
+ - transaction_hash
+ - token_address
+ - from_address
+ - to_address
+ - value
+ - data
+ - message
+ - created
+ - source_event
+ title: TransferWithMessage
TxData:
properties:
hash:
@@ -11527,66 +11692,6 @@ components:
TxDataResponse:
$ref: '#/components/schemas/TxDataDetail'
title: TxDataResponse
- UnlockTransferHistory:
- properties:
- transaction_hash:
- type: string
- title: Transaction Hash
- description: Transaction hash
- token_address:
- type: string
- title: Token Address
- description: Token address
- from_address:
- type: string
- title: From Address
- description: Account address of transfer source
- to_address:
- type: string
- title: To Address
- description: Account address of transfer destination
- value:
- type: integer
- title: Value
- description: Transfer quantity
- data:
- anyOf:
- - $ref: '#/components/schemas/DataMessage'
- - type: object
- title: Data
- description: Event data
- message:
- anyOf:
- - type: string
- enum:
- - garnishment
- - inheritance
- - force_unlock
- - type: 'null'
- title: Message
- created:
- type: string
- title: Created
- description: block_timestamp when Transfer log was emitted (local timezone)
- source_event:
- type: string
- enum:
- - Unlock
- - ForceUnlock
- title: Source Event
- description: Source Event
- type: object
- required:
- - transaction_hash
- - token_address
- - from_address
- - to_address
- - value
- - data
- - message
- - created
- - source_event
- title: UnlockTransferHistory
UpdateAdminTokenRequest:
properties:
is_public:
@@ -11717,6 +11822,7 @@ tags:
- name: contract_log
description: Contract event logs
- name: dex
- description: Trade related functions on IbetExchange (Only for utility tokens)
+ description: Trade related functions on IbetExchange (Only for utility
+ tokens)
- name: messaging
description: Messaging functions with external systems
diff --git a/migrations/versions/819325835c3d_v25_9_0_feature_1657.py b/migrations/versions/819325835c3d_v25_9_0_feature_1657.py
new file mode 100644
index 000000000..463cbccf7
--- /dev/null
+++ b/migrations/versions/819325835c3d_v25_9_0_feature_1657.py
@@ -0,0 +1,47 @@
+"""v25_9_0_feature_1657
+
+Revision ID: 819325835c3d
+Revises: 9a28ed8d4afd
+Create Date: 2025-07-23 18:08:21.277260
+
+"""
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy import update, cast, String
+
+
+from app.database import get_db_schema
+from app.model.db import IDXTransfer, IDXLock, IDXUnlock
+
+# revision identifiers, used by Alembic.
+revision = "819325835c3d"
+down_revision = "9a28ed8d4afd"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ connection = op.get_bind()
+
+ op.get_bind().execute(
+ update(IDXTransfer)
+ .values(message=None, data={})
+ .where(IDXTransfer.message == "inheritance")
+ )
+ op.get_bind().execute(
+ update(IDXLock)
+ .values(data={})
+ .where(cast(IDXLock.data, String).like(f"%inheritance%"))
+ )
+ op.get_bind().execute(
+ update(IDXUnlock)
+ .values(data={})
+ .where(cast(IDXUnlock.data, String).like(f"%inheritance%"))
+ )
+
+
+def downgrade():
+ connection = op.get_bind()
+
+ pass
diff --git a/migrations/versions/a5e395bf46a9_v25_9_0_feature_1662.py b/migrations/versions/a5e395bf46a9_v25_9_0_feature_1662.py
new file mode 100644
index 000000000..07a39c8a8
--- /dev/null
+++ b/migrations/versions/a5e395bf46a9_v25_9_0_feature_1662.py
@@ -0,0 +1,64 @@
+"""v25_9_0_feature_1662
+
+Revision ID: a5e395bf46a9
+Revises: 819325835c3d
+Create Date: 2025-07-31 12:02:12.029337
+
+"""
+
+from alembic import op
+import sqlalchemy as sa
+
+
+from app.database import get_db_schema
+from app.model.db import Notification
+
+# revision identifiers, used by Alembic.
+revision = "a5e395bf46a9"
+down_revision = "819325835c3d"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ connection = op.get_bind()
+
+ op.create_table(
+ "notification_attribute_value",
+ sa.Column("contract_address", sa.String(length=42), nullable=False),
+ sa.Column("attribute_key", sa.String(length=256), nullable=False),
+ sa.Column("attribute", sa.JSON(), nullable=False),
+ sa.Column("created", sa.DateTime(), nullable=True),
+ sa.Column("modified", sa.DateTime(), nullable=True),
+ sa.PrimaryKeyConstraint("contract_address", "attribute_key"),
+ schema=get_db_schema(),
+ )
+ op.add_column(
+ "notification",
+ sa.Column("notification_category", sa.String(length=20), nullable=True),
+ schema=get_db_schema(),
+ )
+ op.get_bind().execute(
+ sa.update(Notification).values(notification_category="event_log")
+ )
+ op.alter_column(
+ "notification",
+ "notification_category",
+ existing_type=sa.String(length=20),
+ nullable=False,
+ schema=get_db_schema(),
+ )
+ op.drop_constraint("notification_pkey", "notification", type_="primary")
+ op.create_primary_key(
+ "notification_pkey",
+ "notification",
+ ["notification_category", "notification_id"],
+ schema=get_db_schema(),
+ )
+
+
+def downgrade():
+ connection = op.get_bind()
+
+ op.drop_column("notification", "notification_category", schema=get_db_schema())
+ op.drop_table("notification_attribute_value", schema=get_db_schema())
diff --git a/package-lock.json b/package-lock.json
index 389b94007..5f760c9fc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,7 +5,7 @@
"packages": {
"": {
"devDependencies": {
- "hardhat": "^2.25.0"
+ "hardhat": "~2.26.3"
}
},
"node_modules/@ethereumjs/rlp": {
@@ -579,28 +579,28 @@
"license": "MIT"
},
"node_modules/@nomicfoundation/edr": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.1.tgz",
- "integrity": "sha512-P97XwcD9DdMMZm9aqw89+mzqzlKmqzSPM3feBES2WVRm5/LOiBYorhpeAX+ANj0X8532SKgxoZK/CN5OWv9vZA==",
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.3.tgz",
+ "integrity": "sha512-kqILRkAd455Sd6v8mfP3C1/0tCOynJWY+Ir+k/9Boocu2kObCrsFgG+ZWB7fSBVdd9cPVSNrnhWS+V+PEo637g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@nomicfoundation/edr-darwin-arm64": "0.11.1",
- "@nomicfoundation/edr-darwin-x64": "0.11.1",
- "@nomicfoundation/edr-linux-arm64-gnu": "0.11.1",
- "@nomicfoundation/edr-linux-arm64-musl": "0.11.1",
- "@nomicfoundation/edr-linux-x64-gnu": "0.11.1",
- "@nomicfoundation/edr-linux-x64-musl": "0.11.1",
- "@nomicfoundation/edr-win32-x64-msvc": "0.11.1"
+ "@nomicfoundation/edr-darwin-arm64": "0.11.3",
+ "@nomicfoundation/edr-darwin-x64": "0.11.3",
+ "@nomicfoundation/edr-linux-arm64-gnu": "0.11.3",
+ "@nomicfoundation/edr-linux-arm64-musl": "0.11.3",
+ "@nomicfoundation/edr-linux-x64-gnu": "0.11.3",
+ "@nomicfoundation/edr-linux-x64-musl": "0.11.3",
+ "@nomicfoundation/edr-win32-x64-msvc": "0.11.3"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@nomicfoundation/edr-darwin-arm64": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.1.tgz",
- "integrity": "sha512-vjca7gkl1o0yYqMjwxQpMEtdsb20nWHBnnxDO8ZBCTD5IwfYT5LiMxFaJo8NUJ7ODIRkF/zuEtAF3W7+ZlC5RA==",
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.3.tgz",
+ "integrity": "sha512-w0tksbdtSxz9nuzHKsfx4c2mwaD0+l5qKL2R290QdnN9gi9AV62p9DHkOgfBdyg6/a6ZlnQqnISi7C9avk/6VA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -608,9 +608,9 @@
}
},
"node_modules/@nomicfoundation/edr-darwin-x64": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.1.tgz",
- "integrity": "sha512-0aGStHq9XePXX9UqdU1w60HGO9AfYCgkNEir5sBpntU5E0TvZEK6jwyYr667+s90n2mihdeP97QSA0O/6PT6PA==",
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.3.tgz",
+ "integrity": "sha512-QR4jAFrPbOcrO7O2z2ESg+eUeIZPe2bPIlQYgiJ04ltbSGW27FblOzdd5+S3RoOD/dsZGKAvvy6dadBEl0NgoA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -618,9 +618,9 @@
}
},
"node_modules/@nomicfoundation/edr-linux-arm64-gnu": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.1.tgz",
- "integrity": "sha512-OWhCETc03PVdtzatW/c2tpOPx+GxlBfBaLmMuGRD1soAr1nMOmg2WZAlo4i6Up9fkQYl+paiYMMFVat1meaMvQ==",
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.3.tgz",
+ "integrity": "sha512-Ktjv89RZZiUmOFPspuSBVJ61mBZQ2+HuLmV67InNlh9TSUec/iDjGIwAn59dx0bF/LOSrM7qg5od3KKac4LJDQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -628,9 +628,9 @@
}
},
"node_modules/@nomicfoundation/edr-linux-arm64-musl": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.1.tgz",
- "integrity": "sha512-p0qvtIvDA2eZ8pQ5XUKnWdW1IrwFzSrjyrO88oYx6Lkw8nYwf2JEeETo5o5W84DDfimfoBGP7RWPTPcTBKCaLQ==",
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.3.tgz",
+ "integrity": "sha512-B3sLJx1rL2E9pfdD4mApiwOZSrX0a/KQSBWdlq1uAhFKqkl00yZaY4LejgZndsJAa4iKGQJlGnw4HCGeVt0+jA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -638,9 +638,9 @@
}
},
"node_modules/@nomicfoundation/edr-linux-x64-gnu": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.1.tgz",
- "integrity": "sha512-V4Us7Q0E8kng3O/czd5GRcxmZxWX+USgqz9yQ3o7DVq7FP96idaKvtcbMQp64tjHf2zNtX2y77sGzgbVau7Bww==",
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.3.tgz",
+ "integrity": "sha512-D/4cFKDXH6UYyKPu6J3Y8TzW11UzeQI0+wS9QcJzjlrrfKj0ENW7g9VihD1O2FvXkdkTjcCZYb6ai8MMTCsaVw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -648,9 +648,9 @@
}
},
"node_modules/@nomicfoundation/edr-linux-x64-musl": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.1.tgz",
- "integrity": "sha512-lCSXsF10Kjjvs5duGbM6pi1WciWHXFNWkMgDAY4pg6ZRIy4gh+uGC6CONMfP4BDZwfrALo2p6+LwyotrJEqpyg==",
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.3.tgz",
+ "integrity": "sha512-ergXuIb4nIvmf+TqyiDX5tsE49311DrBky6+jNLgsGDTBaN1GS3OFwFS8I6Ri/GGn6xOaT8sKu3q7/m+WdlFzg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -658,9 +658,9 @@
}
},
"node_modules/@nomicfoundation/edr-win32-x64-msvc": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.1.tgz",
- "integrity": "sha512-sNSmmRTURAd1sdKuyO5tqrFiJvHHVPZLM4HB53F21makGoyInFGhejdo3qZrkoinM8k0ewEJDbUp0YuMEgMOhQ==",
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.3.tgz",
+ "integrity": "sha512-snvEf+WB3OV0wj2A7kQ+ZQqBquMcrozSLXcdnMdEl7Tmn+KDCbmFKBt3Tk0X3qOU4RKQpLPnTxdM07TJNVtung==",
"dev": true,
"license": "MIT",
"engines": {
@@ -917,33 +917,6 @@
"node": ">=6"
}
},
- "node_modules/@types/bn.js": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz",
- "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/lru-cache": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz",
- "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@types/node": {
- "version": "22.13.10",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
- "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~6.20.0"
- }
- },
"node_modules/adm-zip": {
"version": "0.4.16",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
@@ -1642,19 +1615,17 @@
"license": "ISC"
},
"node_modules/hardhat": {
- "version": "2.25.0",
- "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.25.0.tgz",
- "integrity": "sha512-yBiA74Yj3VnTRj7lhnn8GalvBdvsMOqTKRrRATSy/2v0VIR2hR0Jcnmfn4aQBLtGAnr3Q2c8CxL0g3LYegUp+g==",
+ "version": "2.26.3",
+ "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.26.3.tgz",
+ "integrity": "sha512-gBfjbxCCEaRgMCRgTpjo1CEoJwqNPhyGMMVHYZJxoQ3LLftp2erSVf8ZF6hTQC0r2wst4NcqNmLWqMnHg1quTw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ethereumjs/util": "^9.1.0",
"@ethersproject/abi": "^5.1.2",
- "@nomicfoundation/edr": "^0.11.1",
+ "@nomicfoundation/edr": "^0.11.3",
"@nomicfoundation/solidity-analyzer": "^0.1.0",
"@sentry/node": "^5.18.1",
- "@types/bn.js": "^5.1.0",
- "@types/lru-cache": "^5.1.0",
"adm-zip": "^0.4.16",
"aggregate-error": "^3.0.0",
"ansi-escapes": "^4.3.0",
@@ -2742,13 +2713,6 @@
"node": ">=14.0"
}
},
- "node_modules/undici-types": {
- "version": "6.20.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
- "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
diff --git a/package.json b/package.json
index e22013225..37fc4f158 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
"devDependencies": {
- "hardhat": "^2.25.0"
+ "hardhat": "~2.26.3"
}
}
diff --git a/pyproject.toml b/pyproject.toml
index 09aa6c6d8..eee164dc6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "ibet-Wallet-API"
-version = "25.6"
+version = "25.9"
description = "RPC services that provides utility functions for building a wallet system on ibet-Network."
authors = [
{name = "BOOSTRY Co., Ltd.", email = "dev@boostry.co.jp"},
@@ -12,7 +12,7 @@ dependencies = [
"coincurve~=21.0.0",
"eth-keyfile~=0.9.1",
"eth-utils~=5.2.0",
- "fastapi~=0.115.0",
+ "fastapi~=0.116.1",
"gunicorn~=23.0.0",
"hexbytes~=1.3.0",
"orjson~=3.10.3",
@@ -26,7 +26,6 @@ dependencies = [
"alembic<2.0.0,>=1.14.0",
"aiomysql==0.2.0",
"httpx~=0.28.0",
- "aiohttp~=3.10.10",
"memray<2.0.0,>=1.14.0",
"py-spy>=0.4.0",
"asyncpg~=0.30.0",
@@ -41,6 +40,7 @@ dependencies = [
"opentelemetry-instrumentation-psycopg>=0.54b0,<1.0.0",
"opentelemetry-instrumentation-sqlalchemy>=0.54b0,<1.0.0",
"opentelemetry-exporter-otlp-proto-grpc>=1.33.1,<2.0.0",
+ "requests>=2.32.3",
]
[tool.uv]
@@ -66,6 +66,8 @@ ibet-explorer = [
"textual~=0.44.1",
"async-cache~=1.1.1",
"typer~=0.12.3",
+ "aiohttp~=3.12.13",
+ "async-cache==1.1.1",
]
[tool.uv.sources]
diff --git a/tests/app/notification_NotificationsCount_test.py b/tests/app/notification_NotificationsCount_test.py
index af4e73edd..f16079cbf 100644
--- a/tests/app/notification_NotificationsCount_test.py
+++ b/tests/app/notification_NotificationsCount_test.py
@@ -33,6 +33,7 @@ class TestNotificationCount:
def _insert_test_data(self, session):
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034300000000000000"
n.notification_type = "SampleNotification1"
n.priority = 1
@@ -51,6 +52,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034000000000000000"
n.notification_type = "SampleNotification2"
n.priority = 1
@@ -67,6 +69,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011034000000000000000"
n.notification_type = "SampleNotification3"
n.priority = 2
@@ -83,6 +86,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011032000000000000000"
n.notification_type = "SampleNotification4"
n.priority = 1
@@ -99,6 +103,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000001034000000000000000"
n.notification_type = "SampleNotification5"
n.priority = 0
diff --git a/tests/app/notification_NotificationsId_DELETE_test.py b/tests/app/notification_NotificationsId_DELETE_test.py
index 2ec072332..eb72a085a 100644
--- a/tests/app/notification_NotificationsId_DELETE_test.py
+++ b/tests/app/notification_NotificationsId_DELETE_test.py
@@ -36,6 +36,7 @@ class TestNotificationsIdDELETE:
def _insert_test_data(self, session):
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034300000000000000"
n.notification_type = "NewOrder"
n.priority = 1
@@ -55,6 +56,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034000000000000000"
n.notification_type = "NewOrderCounterpart"
n.priority = 1
@@ -72,6 +74,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011034000000000000000"
n.notification_type = "NewOrder"
n.priority = 2
@@ -89,6 +92,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011032000000000000000"
n.notification_type = "NewOrderCounterpart"
n.priority = 1
@@ -106,6 +110,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000001034000000000000000"
n.notification_type = "NewOrder"
n.priority = 0
diff --git a/tests/app/notification_NotificationsId_POST_test.py b/tests/app/notification_NotificationsId_POST_test.py
index 3c3108dae..2b14ca278 100644
--- a/tests/app/notification_NotificationsId_POST_test.py
+++ b/tests/app/notification_NotificationsId_POST_test.py
@@ -38,6 +38,7 @@ def _insert_test_data(self, session):
self.session = session # HACK: updateでcommitされてしまう対策
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034300000000000000"
n.notification_type = NotificationType.NEW_ORDER
n.priority = 1
@@ -56,6 +57,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034000000000000000"
n.notification_type = NotificationType.APPROVE_TRANSFER
n.priority = 1
@@ -72,6 +74,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011034000000000000000"
n.notification_type = NotificationType.APPLY_FOR_TRANSFER
n.priority = 2
@@ -88,6 +91,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011032000000000000000"
n.notification_type = NotificationType.BUY_AGREEMENT
n.priority = 1
@@ -104,6 +108,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = NotificationType.BUY_SETTLEMENT_NG
n.notification_type = "SampleNotification5"
n.priority = 0
diff --git a/tests/app/notification_NotificationsRead_test.py b/tests/app/notification_NotificationsRead_test.py
index f5fbb4acc..3ea39c0fa 100644
--- a/tests/app/notification_NotificationsRead_test.py
+++ b/tests/app/notification_NotificationsRead_test.py
@@ -44,6 +44,7 @@ def _insert_test_data(self, session):
self.session = session # HACK: updateでcommitされてしまう対策
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034300000000000000"
n.notification_type = "SampleNotification1"
n.priority = 1
@@ -64,6 +65,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034000000000000000"
n.notification_type = "SampleNotification2"
n.priority = 1
@@ -80,6 +82,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011034000000000000000"
n.notification_type = "SampleNotification3"
n.priority = 2
@@ -96,6 +99,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011032000000000000000"
n.notification_type = "SampleNotification4"
n.priority = 1
@@ -112,6 +116,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000001034000000000000000"
n.notification_type = "SampleNotification5"
n.priority = 0
diff --git a/tests/app/notification_Notifications_GET_test.py b/tests/app/notification_Notifications_GET_test.py
index c3281ab6c..a40504cf8 100644
--- a/tests/app/notification_Notifications_GET_test.py
+++ b/tests/app/notification_Notifications_GET_test.py
@@ -35,6 +35,7 @@ class TestNotificationsGet:
def _insert_test_data(self, session):
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034300000000000000"
n.notification_type = "NewOrder"
n.priority = 1
@@ -54,6 +55,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000021034000000000000000"
n.notification_type = "NewOrderCounterpart"
n.priority = 1
@@ -71,6 +73,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011034000000000000000"
n.notification_type = "NewOrder"
n.priority = 2
@@ -88,6 +91,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000011032000000000000000"
n.notification_type = "NewOrderCounterpart"
n.priority = 1
@@ -105,6 +109,7 @@ def _insert_test_data(self, session):
session.add(n)
n = Notification()
+ n.notification_category = "event_log"
n.notification_id = "0x00000001034000000000000000"
n.notification_type = "NewOrder"
n.priority = 0
@@ -140,6 +145,7 @@ def test_normal_1(self, client: TestClient, session: Session):
"result_set": {"count": 5, "offset": None, "limit": None, "total": 5},
"notifications": [
{
+ "notification_category": "event_log",
"notification_type": "NewOrder",
"id": "0x00000021034300000000000000",
"sort_id": 1,
@@ -157,6 +163,7 @@ def test_normal_1(self, client: TestClient, session: Session):
"created": "2022/01/01 15:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrderCounterpart",
"id": "0x00000021034000000000000000",
"sort_id": 2,
@@ -174,6 +181,7 @@ def test_normal_1(self, client: TestClient, session: Session):
"created": "2022/01/01 16:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrder",
"id": "0x00000011034000000000000000",
"sort_id": 3,
@@ -191,6 +199,7 @@ def test_normal_1(self, client: TestClient, session: Session):
"created": "2022/01/01 17:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrderCounterpart",
"id": "0x00000011032000000000000000",
"sort_id": 4,
@@ -208,6 +217,7 @@ def test_normal_1(self, client: TestClient, session: Session):
"created": "2022/01/01 18:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrder",
"id": "0x00000001034000000000000000",
"sort_id": 5,
@@ -252,6 +262,7 @@ def test_normal_2(self, client: TestClient, session: Session):
"result_set": {"count": 5, "offset": 1, "limit": 2, "total": 5},
"notifications": [
{
+ "notification_category": "event_log",
"notification_type": "NewOrderCounterpart",
"id": "0x00000021034000000000000000",
"sort_id": 2,
@@ -269,6 +280,7 @@ def test_normal_2(self, client: TestClient, session: Session):
"created": "2022/01/01 16:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrder",
"id": "0x00000011034000000000000000",
"sort_id": 3,
@@ -332,6 +344,7 @@ def test_normal_4(self, client: TestClient, session: Session):
"address": self.address,
"notification_type": "NewOrder",
"priority": 2,
+ "notification_category": "event_log",
},
)
@@ -339,6 +352,7 @@ def test_normal_4(self, client: TestClient, session: Session):
"result_set": {"count": 1, "offset": None, "limit": None, "total": 5},
"notifications": [
{
+ "notification_category": "event_log",
"notification_type": "NewOrder",
"id": "0x00000011034000000000000000",
"sort_id": 1,
@@ -410,6 +424,7 @@ def test_normal_6(self, client: TestClient, session: Session):
"result_set": {"count": 5, "offset": None, "limit": None, "total": 5},
"notifications": [
{
+ "notification_category": "event_log",
"notification_type": "NewOrder",
"id": "0x00000011034000000000000000",
"sort_id": 1,
@@ -427,6 +442,7 @@ def test_normal_6(self, client: TestClient, session: Session):
"created": "2022/01/01 17:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrder",
"id": "0x00000021034300000000000000",
"sort_id": 2,
@@ -444,6 +460,7 @@ def test_normal_6(self, client: TestClient, session: Session):
"created": "2022/01/01 15:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrderCounterpart",
"id": "0x00000021034000000000000000",
"sort_id": 3,
@@ -461,6 +478,7 @@ def test_normal_6(self, client: TestClient, session: Session):
"created": "2022/01/01 16:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrderCounterpart",
"id": "0x00000011032000000000000000",
"sort_id": 4,
@@ -478,6 +496,7 @@ def test_normal_6(self, client: TestClient, session: Session):
"created": "2022/01/01 18:20:30",
},
{
+ "notification_category": "event_log",
"notification_type": "NewOrder",
"id": "0x00000001034000000000000000",
"sort_id": 5,
@@ -544,10 +563,10 @@ def test_error_1(self, client: TestClient, session: Session):
{
"type": "enum",
"loc": ["query", "notification_type"],
- "msg": "Input should be 'NewOrder', 'NewOrderCounterpart', 'CancelOrder', 'CancelOrderCounterpart', 'ForceCancelOrder', 'BuyAgreement', 'BuySettlementOK', 'BuySettlementNG', 'SellAgreement', 'SellSettlementOK', 'SellSettlementNG', 'Transfer', 'ApplyForTransfer', 'ApproveTransfer', 'CancelTransfer', 'ForceLock' or 'ForceUnlock'",
+ "msg": "Input should be 'NewOrder', 'NewOrderCounterpart', 'CancelOrder', 'CancelOrderCounterpart', 'ForceCancelOrder', 'BuyAgreement', 'BuySettlementOK', 'BuySettlementNG', 'SellAgreement', 'SellSettlementOK', 'SellSettlementNG', 'Transfer', 'ApplyForTransfer', 'ApproveTransfer', 'CancelTransfer', 'ForceLock', 'ForceUnlock', 'ChangeToRedeemed', 'ChangeToCanceled' or 'TransferableChanged'",
"input": "hoge",
"ctx": {
- "expected": "'NewOrder', 'NewOrderCounterpart', 'CancelOrder', 'CancelOrderCounterpart', 'ForceCancelOrder', 'BuyAgreement', 'BuySettlementOK', 'BuySettlementNG', 'SellAgreement', 'SellSettlementOK', 'SellSettlementNG', 'Transfer', 'ApplyForTransfer', 'ApproveTransfer', 'CancelTransfer', 'ForceLock' or 'ForceUnlock'"
+ "expected": "'NewOrder', 'NewOrderCounterpart', 'CancelOrder', 'CancelOrderCounterpart', 'ForceCancelOrder', 'BuyAgreement', 'BuySettlementOK', 'BuySettlementNG', 'SellAgreement', 'SellSettlementOK', 'SellSettlementNG', 'Transfer', 'ApplyForTransfer', 'ApproveTransfer', 'CancelTransfer', 'ForceLock', 'ForceUnlock', 'ChangeToRedeemed', 'ChangeToCanceled' or 'TransferableChanged'"
},
},
{
diff --git a/tests/app/public_info_ListAllPublicListedTokens_test.py b/tests/app/public_info_ListAllPublicListedTokens_test.py
index f761b2c14..8ad5bbad7 100644
--- a/tests/app/public_info_ListAllPublicListedTokens_test.py
+++ b/tests/app/public_info_ListAllPublicListedTokens_test.py
@@ -78,6 +78,20 @@ def test_normal_2(self, client: TestClient, session: Session):
_token_list_item.product_type = 5
session.add(_token_list_item)
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_4
+ _token_list_item.token_template = "ibetMembership"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_5
+ _token_list_item.token_template = "ibetCoupon"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
session.commit()
resp = client.get(self.api_url, params={})
@@ -85,7 +99,7 @@ def test_normal_2(self, client: TestClient, session: Session):
assert resp.status_code == 200
assert resp.json()["meta"] == {"code": 200, "message": "OK"}
assert resp.json()["data"] == {
- "result_set": {"count": 3, "limit": None, "offset": None, "total": 3},
+ "result_set": {"count": 5, "limit": None, "offset": None, "total": 5},
"tokens": [
{
"key_manager": ["0000000000000"],
@@ -105,6 +119,18 @@ def test_normal_2(self, client: TestClient, session: Session):
"token_address": self.token_address_3,
"token_template": "ibetShare",
},
+ {
+ "key_manager": [],
+ "product_type": 1,
+ "token_address": self.token_address_4,
+ "token_template": "ibetMembership",
+ },
+ {
+ "key_manager": [],
+ "product_type": 1,
+ "token_address": self.token_address_5,
+ "token_template": "ibetCoupon",
+ },
],
}
@@ -122,18 +148,35 @@ def test_normal_3_1(
_token_list_item.key_manager = ["0000000000000"]
_token_list_item.product_type = 1
session.add(_token_list_item)
+
_token_list_item = TokenList()
_token_list_item.token_address = self.token_address_2
_token_list_item.token_template = "ibetBond"
_token_list_item.key_manager = ["0000000000000"]
_token_list_item.product_type = 1
session.add(_token_list_item)
+
_token_list_item = TokenList()
_token_list_item.token_address = self.token_address_3
_token_list_item.token_template = "ibetShare"
_token_list_item.key_manager = ["1111111111111"]
_token_list_item.product_type = 5
session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_4
+ _token_list_item.token_template = "ibetMembership"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_5
+ _token_list_item.token_template = "ibetCoupon"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
session.commit()
resp = client.get(self.api_url, params={"token_template": "ibetBond"})
@@ -141,7 +184,7 @@ def test_normal_3_1(
assert resp.status_code == 200
assert resp.json()["meta"] == {"code": 200, "message": "OK"}
assert resp.json()["data"] == {
- "result_set": {"count": 2, "limit": None, "offset": None, "total": 3},
+ "result_set": {"count": 2, "limit": None, "offset": None, "total": 5},
"tokens": [
{
"key_manager": ["0000000000000"],
@@ -172,18 +215,35 @@ def test_normal_3_2(
_token_list_item.key_manager = ["0000000000000"]
_token_list_item.product_type = 1
session.add(_token_list_item)
+
_token_list_item = TokenList()
_token_list_item.token_address = self.token_address_2
_token_list_item.token_template = "ibetBond"
_token_list_item.key_manager = ["0000000000000"]
_token_list_item.product_type = 1
session.add(_token_list_item)
+
_token_list_item = TokenList()
_token_list_item.token_address = self.token_address_3
_token_list_item.token_template = "ibetShare"
_token_list_item.key_manager = ["1111111111111"]
_token_list_item.product_type = 5
session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_4
+ _token_list_item.token_template = "ibetMembership"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_5
+ _token_list_item.token_template = "ibetCoupon"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
session.commit()
resp = client.get(self.api_url, params={"token_template": "ibetShare"})
@@ -191,7 +251,7 @@ def test_normal_3_2(
assert resp.status_code == 200
assert resp.json()["meta"] == {"code": 200, "message": "OK"}
assert resp.json()["data"] == {
- "result_set": {"count": 1, "limit": None, "offset": None, "total": 3},
+ "result_set": {"count": 1, "limit": None, "offset": None, "total": 5},
"tokens": [
{
"key_manager": ["1111111111111"],
@@ -202,6 +262,128 @@ def test_normal_3_2(
],
}
+ # <Normal_3_3>
+ # Filter: token_template (ibetMembership)
+ def test_normal_3_3(
+ self,
+ client: TestClient,
+ session: Session,
+ ):
+ # Prepare data
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_1
+ _token_list_item.token_template = "ibetBond"
+ _token_list_item.key_manager = ["0000000000000"]
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_2
+ _token_list_item.token_template = "ibetBond"
+ _token_list_item.key_manager = ["0000000000000"]
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_3
+ _token_list_item.token_template = "ibetShare"
+ _token_list_item.key_manager = ["1111111111111"]
+ _token_list_item.product_type = 5
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_4
+ _token_list_item.token_template = "ibetMembership"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_5
+ _token_list_item.token_template = "ibetCoupon"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ session.commit()
+
+ resp = client.get(self.api_url, params={"token_template": "ibetMembership"})
+
+ assert resp.status_code == 200
+ assert resp.json()["meta"] == {"code": 200, "message": "OK"}
+ assert resp.json()["data"] == {
+ "result_set": {"count": 1, "limit": None, "offset": None, "total": 5},
+ "tokens": [
+ {
+ "key_manager": [],
+ "product_type": 1,
+ "token_address": self.token_address_4,
+ "token_template": "ibetMembership",
+ },
+ ],
+ }
+
+ # <Normal_3_4>
+ # Filter: token_template (ibetCoupon)
+ def test_normal_3_4(
+ self,
+ client: TestClient,
+ session: Session,
+ ):
+ # Prepare data
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_1
+ _token_list_item.token_template = "ibetBond"
+ _token_list_item.key_manager = ["0000000000000"]
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_2
+ _token_list_item.token_template = "ibetBond"
+ _token_list_item.key_manager = ["0000000000000"]
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_3
+ _token_list_item.token_template = "ibetShare"
+ _token_list_item.key_manager = ["1111111111111"]
+ _token_list_item.product_type = 5
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_4
+ _token_list_item.token_template = "ibetMembership"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ _token_list_item = TokenList()
+ _token_list_item.token_address = self.token_address_5
+ _token_list_item.token_template = "ibetCoupon"
+ _token_list_item.key_manager = []
+ _token_list_item.product_type = 1
+ session.add(_token_list_item)
+
+ session.commit()
+
+ resp = client.get(self.api_url, params={"token_template": "ibetCoupon"})
+
+ assert resp.status_code == 200
+ assert resp.json()["meta"] == {"code": 200, "message": "OK"}
+ assert resp.json()["data"] == {
+ "result_set": {"count": 1, "limit": None, "offset": None, "total": 5},
+ "tokens": [
+ {
+ "key_manager": [],
+ "product_type": 1,
+ "token_address": self.token_address_5,
+ "token_template": "ibetCoupon",
+ },
+ ],
+ }
+
# <Normal_4>
# Offset
def test_normal_4(
@@ -306,11 +488,13 @@ def test_error_1(self, client: TestClient, session: Session):
"message": "Invalid Parameter",
"description": [
{
- "ctx": {"expected": "'ibetBond' or 'ibetShare'"},
- "input": "invalid_value",
- "loc": ["query", "token_template"],
- "msg": "Input should be 'ibetBond' or 'ibetShare'",
"type": "literal_error",
+ "loc": ["query", "token_template"],
+ "msg": "Input should be 'ibetBond', 'ibetShare', 'ibetMembership' or 'ibetCoupon'",
+ "input": "invalid_value",
+ "ctx": {
+ "expected": "'ibetBond', 'ibetShare', 'ibetMembership' or 'ibetCoupon'"
+ },
}
],
}
diff --git a/tests/batch/indexer_Company_List_test.py b/tests/batch/indexer_Company_List_test.py
index e8fe8e61b..bac54d095 100644
--- a/tests/batch/indexer_Company_List_test.py
+++ b/tests/batch/indexer_Company_List_test.py
@@ -50,15 +50,9 @@ def caplog(caplog: pytest.LogCaptureFixture):
class MockResponse:
def __init__(self, data: object, status_code: int = 200):
self.data = data
- self.status = status_code
+ self.status_code = status_code
- async def __aexit__(self, exc_type, exc, tb):
- pass
-
- async def __aenter__(self):
- return self
-
- async def json(self) -> object:
+ def json(self) -> object:
return self.data
@@ -70,7 +64,7 @@ class TestProcessor:
#
# 0 record
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_1(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -97,7 +91,7 @@ async def test_normal_1(self, mock_get, processor, session):
mock_get.side_effect = [MockResponse([])]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
session.rollback()
@@ -108,7 +102,7 @@ async def test_normal_1(self, mock_get, processor, session):
#
# 1 record
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_2(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -146,7 +140,7 @@ async def test_normal_2(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -163,7 +157,7 @@ async def test_normal_2(self, mock_get, processor, session):
#
# 2 record
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_3(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -206,7 +200,7 @@ async def test_normal_3(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -232,7 +226,7 @@ async def test_normal_3(self, mock_get, processor, session):
# Insert SKIP
# type error
# address
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_1_1(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -276,7 +270,7 @@ async def test_normal_4_1_1(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -295,7 +289,7 @@ async def test_normal_4_1_1(self, mock_get, processor, session):
# Insert SKIP
# type error
# corporate_name
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_1_2(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -339,7 +333,7 @@ async def test_normal_4_1_2(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -358,7 +352,7 @@ async def test_normal_4_1_2(self, mock_get, processor, session):
# Insert SKIP
# type error
# rsa_publickey
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_1_3(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -402,7 +396,7 @@ async def test_normal_4_1_3(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -421,7 +415,7 @@ async def test_normal_4_1_3(self, mock_get, processor, session):
# Insert SKIP
# type error
# homepage
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_1_4(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -465,7 +459,7 @@ async def test_normal_4_1_4(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -484,7 +478,7 @@ async def test_normal_4_1_4(self, mock_get, processor, session):
# Insert SKIP
# required error
# address
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_2_1(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -527,7 +521,7 @@ async def test_normal_4_2_1(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -546,7 +540,7 @@ async def test_normal_4_2_1(self, mock_get, processor, session):
# Insert SKIP
# required error
# corporate_name
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_2_2(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -589,7 +583,7 @@ async def test_normal_4_2_2(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -608,7 +602,7 @@ async def test_normal_4_2_2(self, mock_get, processor, session):
# Insert SKIP
# required error
# address
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_2_3(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -651,7 +645,7 @@ async def test_normal_4_2_3(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -669,7 +663,7 @@ async def test_normal_4_2_3(self, mock_get, processor, session):
#
# Insert SKIP
# invalid address error
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_3(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -713,7 +707,7 @@ async def test_normal_4_3(self, mock_get, processor, session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -731,7 +725,7 @@ async def test_normal_4_3(self, mock_get, processor, session):
#
# There are no differences from last time
# -> Skip this cycle
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_5_1(self, mock_get, processor, session, caplog):
# Run target process: 1st time
mock_get.side_effect = [
@@ -752,7 +746,7 @@ async def test_normal_5_1(self, mock_get, processor, session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Run target process: 2nd time
mock_get.side_effect = [
@@ -773,7 +767,7 @@ async def test_normal_5_1(self, mock_get, processor, session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -807,7 +801,7 @@ async def test_normal_5_1(self, mock_get, processor, session, caplog):
#
# There are differences from the previous cycle
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_5_2(self, mock_get, processor, session, caplog):
# Run target process: 1st time
mock_get.side_effect = [
@@ -828,7 +822,7 @@ async def test_normal_5_2(self, mock_get, processor, session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Run target process: 2nd time
mock_get.side_effect = [
@@ -843,7 +837,7 @@ async def test_normal_5_2(self, mock_get, processor, session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -875,7 +869,7 @@ async def test_normal_5_2(self, mock_get, processor, session, caplog):
# API error
# Connection error
@mock.patch(
- "aiohttp.client.ClientSession.get",
+ "requests.Session.get",
MagicMock(side_effect=requests.exceptions.ConnectionError),
)
async def test_error_1_1(self, processor, session):
@@ -901,7 +895,7 @@ async def test_error_1_1(self, processor, session):
session.commit()
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -912,7 +906,7 @@ async def test_error_1_1(self, processor, session):
#
# API error
# not succeed api
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_error_1_2(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -939,7 +933,7 @@ async def test_error_1_2(self, mock_get, processor, session):
mock_get.side_effect = [MockResponse([], 400)]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -950,7 +944,7 @@ async def test_error_1_2(self, mock_get, processor, session):
#
# not decode response
@mock.patch(
- "aiohttp.client.ClientSession.get",
+ "requests.Session.get",
MagicMock(side_effect=json.decoder.JSONDecodeError),
)
async def test_error_2(self, processor, session):
@@ -976,7 +970,7 @@ async def test_error_2(self, processor, session):
session.commit()
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
@@ -986,7 +980,7 @@ async def test_error_2(self, processor, session):
#
# other error
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_error_3(self, mock_get, processor, session):
# Prepare data
_company = Company()
@@ -1026,7 +1020,7 @@ async def test_error_3(self, mock_get, processor, session):
# Run target process
with pytest.raises(Exception):
- await processor.process()
+ processor.process()
# Assertion
_company_list: Sequence[Company] = session.scalars(
diff --git a/tests/batch/indexer_Position_Bond_test.py b/tests/batch/indexer_Position_Bond_test.py
index 3e70d8955..52c290b3e 100644
--- a/tests/batch/indexer_Position_Bond_test.py
+++ b/tests/batch/indexer_Position_Bond_test.py
@@ -30,7 +30,7 @@
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from web3 import Web3
-from web3.exceptions import ABIEventNotFound
+from web3.exceptions import ABIEventNotFound, TransactionNotFound
from web3.middleware import ExtraDataToPOAMiddleware
from app import config
@@ -499,7 +499,8 @@ async def test_normal_3(self, processor, shared_contract, session):
# Single Token
# Single event logs
# - Lock
- async def test_normal_4_1(self, processor, shared_contract, session):
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_4_1(self, processor, shared_contract, session, is_old_token):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract = shared_contract["PersonalInfo"]
@@ -515,15 +516,25 @@ async def test_normal_4_1(self, processor, shared_contract, session):
# Lock
token_contract.functions.lock(
- self.trader["account_address"], 1500, '{"message": "locked1"}'
+ self.trader["account_address"], 1500, '{"message": "garnishment"}'
).transact({"from": self.issuer["account_address"]})
token_contract.functions.lock(
- self.trader["account_address"], 1500, '{"message": "locked2"}'
+ self.trader["account_address"], 1500, '{"message": "ibet_wst_bridge"}'
+ ).transact({"from": self.issuer["account_address"]})
+ token_contract.functions.lock(
+ self.trader["account_address"], 1500, '{"message": "inheritance"}'
).transact({"from": self.issuer["account_address"]})
# Run target process
block_number = web3.eth.block_number
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
_position_list: Sequence[IDXPosition] = session.scalars(
@@ -541,7 +552,7 @@ async def test_normal_4_1(self, processor, shared_contract, session):
_position = _position_list[0]
assert _position.token_address == token["address"]
assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 3000
+ assert _position.balance == 1000000 - 4500
assert _position.pending_transfer == 0
assert _position.exchange_balance == 0
assert _position.exchange_commitment == 0
@@ -554,12 +565,12 @@ async def test_normal_4_1(self, processor, shared_contract, session):
assert _locked1.token_address == token["address"]
assert _locked1.lock_address == self.trader["account_address"]
assert _locked1.account_address == self.issuer["account_address"]
- assert _locked1.value == 3000
+ assert _locked1.value == 4500
_lock_list: Sequence[IDXLock] = session.scalars(
select(IDXLock).order_by(IDXLock.id)
).all()
- assert len(_lock_list) == 2
+ assert len(_lock_list) == 3
_lock1 = _lock_list[0]
assert _lock1.id == 1
assert _lock1.token_address == token["address"]
@@ -567,7 +578,7 @@ async def test_normal_4_1(self, processor, shared_contract, session):
assert _lock1.lock_address == self.trader["account_address"]
assert _lock1.account_address == self.issuer["account_address"]
assert _lock1.value == 1500
- assert _lock1.data == {"message": "locked1"}
+ assert _lock1.data == {"message": "garnishment"}
assert _lock1.is_forced is False
_lock2 = _lock_list[1]
assert _lock2.id == 2
@@ -576,14 +587,24 @@ async def test_normal_4_1(self, processor, shared_contract, session):
assert _lock2.lock_address == self.trader["account_address"]
assert _lock2.account_address == self.issuer["account_address"]
assert _lock2.value == 1500
- assert _lock2.data == {"message": "locked2"}
+ assert _lock2.data == {"message": "ibet_wst_bridge"}
assert _lock2.is_forced is False
+ _lock3 = _lock_list[2]
+ assert _lock3.id == 3
+ assert _lock3.token_address == token["address"]
+ assert _lock3.msg_sender == self.issuer["account_address"]
+ assert _lock3.lock_address == self.trader["account_address"]
+ assert _lock3.account_address == self.issuer["account_address"]
+ assert _lock3.value == 1500
+ assert _lock3.data == {}
+ assert _lock3.is_forced is False
#
# Single Token
# Single event logs
# - ForceLock
- async def test_normal_4_2(self, processor, shared_contract, session):
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_4_2(self, processor, shared_contract, session, is_old_token):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract = shared_contract["PersonalInfo"]
@@ -611,24 +632,50 @@ async def test_normal_4_2(self, processor, shared_contract, session):
self.issuer["account_address"],
self.trader["account_address"],
1500,
- '{"message": "force_locked1"}',
+ '{"message": "force_lock"}',
).transact({"from": self.issuer["account_address"]})
token_contract.functions.forceLock(
self.issuer["account_address"],
self.trader["account_address"],
1500,
- '{"message": "force_locked2"}',
+ '{"message": "force_lock"}',
).transact({"from": self.issuer["account_address"]})
# Run target process
block_number = web3.eth.block_number
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 3000
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 0
+ assert _position_issuer.exchange_commitment == 0
+
+ _position_trader: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.trader["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_trader.token_address == token["address"]
+ assert _position_trader.account_address == self.trader["account_address"]
+ assert _position_trader.balance == 0
+ assert _position_trader.pending_transfer == 0
+ assert _position_trader.exchange_balance == 0
+ assert _position_trader.exchange_commitment == 0
_idx_position_bond_block_number: IDXPositionBondBlockNumber = session.scalars(
select(IDXPositionBondBlockNumber)
@@ -637,14 +684,6 @@ async def test_normal_4_2(self, processor, shared_contract, session):
).first()
assert _idx_position_bond_block_number.latest_block_number == block_number
- _position = _position_list[0]
- assert _position.token_address == token["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 3000
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 0
- assert _position.exchange_commitment == 0
-
_locked_list: Sequence[IDXLockedPosition] = session.scalars(
select(IDXLockedPosition).order_by(IDXLockedPosition.created)
).all()
@@ -666,7 +705,7 @@ async def test_normal_4_2(self, processor, shared_contract, session):
assert _lock1.lock_address == self.issuer["account_address"]
assert _lock1.account_address == self.trader["account_address"]
assert _lock1.value == 1500
- assert _lock1.data == {"message": "force_locked1"}
+ assert _lock1.data == {"message": "force_lock"}
assert _lock1.is_forced is True
_lock2 = _lock_list[1]
assert _lock2.id == 2
@@ -675,14 +714,15 @@ async def test_normal_4_2(self, processor, shared_contract, session):
assert _lock2.lock_address == self.issuer["account_address"]
assert _lock2.account_address == self.trader["account_address"]
assert _lock2.value == 1500
- assert _lock2.data == {"message": "force_locked2"}
+ assert _lock2.data == {"message": "force_lock"}
assert _lock2.is_forced is True
#
# Single Token
# Single event logs
# - Unlock
- async def test_normal_5_1(self, processor, shared_contract, session):
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_5_1(self, processor, shared_contract, session, is_old_token):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract = shared_contract["PersonalInfo"]
@@ -698,7 +738,7 @@ async def test_normal_5_1(self, processor, shared_contract, session):
# Lock
token_contract.functions.lock(
- self.trader["account_address"], 3000, '{"message": "locked1"}'
+ self.trader["account_address"], 3000, '{"message": "garnishment"}'
).transact({"from": self.issuer["account_address"]})
# Unlock
@@ -706,12 +746,19 @@ async def test_normal_5_1(self, processor, shared_contract, session):
self.issuer["account_address"],
self.trader2["account_address"],
100,
- '{"message": "unlocked1"}',
+ '{"message": "garnishment"}',
).transact({"from": self.trader["account_address"]})
# Run target process
block_number = web3.eth.block_number
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
_position_list: Sequence[IDXPosition] = session.scalars(
@@ -781,7 +828,7 @@ async def test_normal_5_1(self, processor, shared_contract, session):
assert _lock1.lock_address == self.trader["account_address"]
assert _lock1.account_address == self.issuer["account_address"]
assert _lock1.value == 3000
- assert _lock1.data == {"message": "locked1"}
+ assert _lock1.data == {"message": "garnishment"}
_unlock_list: Sequence[IDXUnlock] = session.scalars(
select(IDXUnlock).order_by(IDXUnlock.id)
@@ -795,14 +842,15 @@ async def test_normal_5_1(self, processor, shared_contract, session):
assert _unlock1.account_address == self.issuer["account_address"]
assert _unlock1.recipient_address == self.trader2["account_address"]
assert _unlock1.value == 100
- assert _unlock1.data == {"message": "unlocked1"}
+ assert _unlock1.data == {"message": "garnishment"}
assert _unlock1.is_forced is False
#
# Single Token
# Single event logs
# - ForceUnlock
- async def test_normal_5_2(self, processor, shared_contract, session):
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_5_2(self, processor, shared_contract, session, is_old_token):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract = shared_contract["PersonalInfo"]
@@ -818,7 +866,7 @@ async def test_normal_5_2(self, processor, shared_contract, session):
# Lock
token_contract.functions.lock(
- self.trader["account_address"], 3000, '{"message": "locked1"}'
+ self.trader["account_address"], 3000, '{"message": "garnishment"}'
).transact({"from": self.issuer["account_address"]})
# ForceUnlock
@@ -827,12 +875,19 @@ async def test_normal_5_2(self, processor, shared_contract, session):
self.issuer["account_address"],
self.trader2["account_address"],
100,
- '{"message": "unlocked1"}',
+ '{"message": "garnishment"}',
).transact({"from": self.issuer["account_address"]})
# Run target process
block_number = web3.eth.block_number
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
_position_list: Sequence[IDXPosition] = session.scalars(
@@ -902,7 +957,7 @@ async def test_normal_5_2(self, processor, shared_contract, session):
assert _lock1.lock_address == self.trader["account_address"]
assert _lock1.account_address == self.issuer["account_address"]
assert _lock1.value == 3000
- assert _lock1.data == {"message": "locked1"}
+ assert _lock1.data == {"message": "garnishment"}
_unlock_list: Sequence[IDXUnlock] = session.scalars(
select(IDXUnlock).order_by(IDXUnlock.id)
@@ -916,7 +971,174 @@ async def test_normal_5_2(self, processor, shared_contract, session):
assert _unlock1.account_address == self.issuer["account_address"]
assert _unlock1.recipient_address == self.trader2["account_address"]
assert _unlock1.value == 100
- assert _unlock1.data == {"message": "unlocked1"}
+ assert _unlock1.data == {"message": "garnishment"}
+ assert _unlock1.is_forced is True
+
+ #
+ # Single Token
+ # Single event logs
+ # - ForceChangeLockedAccount
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_5_3(self, processor, shared_contract, session, is_old_token):
+ # Issue Token
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+ token = self.issue_token_bond(
+ self.issuer,
+ config.ZERO_ADDRESS,
+ personal_info_contract["address"],
+ token_list_contract,
+ )
+ self.listing_token(token["address"], session)
+
+ token_contract = Contract.get_contract("IbetStraightBond", token["address"])
+
+ PersonalInfoUtils.register(
+ self.trader["account_address"],
+ personal_info_contract["address"],
+ self.issuer["account_address"],
+ )
+
+ # Transfer
+ bond_transfer_to_exchange(
+ self.issuer, {"address": self.trader["account_address"]}, token, 3000
+ )
+
+ # Lock
+ token_contract.functions.lock(
+ self.issuer["account_address"], # lock address
+ 3000,
+ '{"message": "garnishment"}',
+ ).transact({"from": self.trader["account_address"]})
+
+ # ForceChangeLockedAccount
+ token_contract.functions.forceChangeLockedAccount(
+ self.issuer["account_address"], # lock address
+ self.trader["account_address"], # before account address
+ self.trader2["account_address"], # after account address
+ 100,
+ '{"message": "ibet_wst_bridge"}',
+ ).transact({"from": self.issuer["account_address"]})
+
+ # Run target process
+ block_number = web3.eth.block_number
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
+
+ # Assertion
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(
+ and_(
+ IDXPosition.token_address == token["address"],
+ IDXPosition.account_address == self.issuer["account_address"],
+ )
+ )
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 3000
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 0
+ assert _position_issuer.exchange_commitment == 0
+
+ _position_trader_1: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(
+ and_(
+ IDXPosition.token_address == token["address"],
+ IDXPosition.account_address == self.trader["account_address"],
+ )
+ )
+ .limit(1)
+ ).first()
+ assert _position_trader_1.token_address == token["address"]
+ assert _position_trader_1.account_address == self.trader["account_address"]
+ assert _position_trader_1.balance == 0
+ assert _position_trader_1.pending_transfer == 0
+ assert _position_trader_1.exchange_balance == 0
+ assert _position_trader_1.exchange_commitment == 0
+
+ _position_trader_2: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(
+ and_(
+ IDXPosition.token_address == token["address"],
+ IDXPosition.account_address == self.trader2["account_address"],
+ )
+ )
+ .limit(1)
+ ).first()
+ assert _position_trader_2.token_address == token["address"]
+ assert _position_trader_2.account_address == self.trader2["account_address"]
+ assert _position_trader_2.balance == 0
+ assert _position_trader_2.pending_transfer == 0
+ assert _position_trader_2.exchange_balance == 0
+ assert _position_trader_2.exchange_commitment == 0
+
+ _idx_position_bond_block_number: IDXPositionBondBlockNumber = session.scalars(
+ select(IDXPositionBondBlockNumber)
+ .where(IDXPositionBondBlockNumber.token_address == token["address"])
+ .limit(1)
+ ).first()
+ assert _idx_position_bond_block_number.latest_block_number == block_number
+
+ _locked_list: Sequence[IDXLockedPosition] = session.scalars(
+ select(IDXLockedPosition).order_by(IDXLockedPosition.created)
+ ).all()
+ assert len(_locked_list) == 2
+ _locked = _locked_list[0]
+ assert _locked.token_address == token["address"]
+ assert _locked.lock_address == self.issuer["account_address"]
+ assert _locked.account_address == self.trader["account_address"]
+ assert _locked.value == 2900
+ _locked = _locked_list[1]
+ assert _locked.token_address == token["address"]
+ assert _locked.lock_address == self.issuer["account_address"]
+ assert _locked.account_address == self.trader2["account_address"]
+ assert _locked.value == 100
+
+ _lock_list: Sequence[IDXLock] = session.scalars(
+ select(IDXLock).order_by(IDXLock.id)
+ ).all()
+ assert len(_lock_list) == 2
+ _lock1 = _lock_list[0]
+ assert _lock1.id == 1
+ assert _lock1.token_address == token["address"]
+ assert _lock1.msg_sender == self.trader["account_address"]
+ assert _lock1.lock_address == self.issuer["account_address"]
+ assert _lock1.account_address == self.trader["account_address"]
+ assert _lock1.value == 3000
+ assert _lock1.data == {"message": "garnishment"}
+ _lock2 = _lock_list[1]
+ assert _lock2.id == 2
+ assert _lock2.token_address == token["address"]
+ assert _lock2.msg_sender == self.issuer["account_address"]
+ assert _lock2.lock_address == self.issuer["account_address"]
+ assert _lock2.account_address == self.trader2["account_address"]
+ assert _lock2.value == 100
+ assert _lock2.data == {"message": "ibet_wst_bridge"}
+
+ _unlock_list: Sequence[IDXUnlock] = session.scalars(
+ select(IDXUnlock).order_by(IDXUnlock.id)
+ ).all()
+ assert len(_unlock_list) == 1
+ _unlock1 = _unlock_list[0]
+ assert _unlock1.id == 1
+ assert _unlock1.token_address == token["address"]
+ assert _unlock1.msg_sender == self.issuer["account_address"]
+ assert _unlock1.lock_address == self.issuer["account_address"]
+ assert _unlock1.account_address == self.trader["account_address"]
+ assert _unlock1.recipient_address == self.trader2["account_address"]
+ assert _unlock1.value == 100
+ assert _unlock1.data == {"message": "ibet_wst_bridge"}
assert _unlock1.is_forced is True
#
@@ -1015,7 +1237,6 @@ async def test_normal_7(self, processor, shared_contract, session):
#
# Single Token
# Single event logs
- # - Transfer
# - Apply For Transfer
async def test_normal_8(self, processor, shared_contract, session):
# Issue Token
@@ -1109,9 +1330,7 @@ async def test_normal_8(self, processor, shared_contract, session):
#
# Single Token
# Single event logs
- # - Transfer
- # - Apply For Transfer
- # - Approve
+ # - Approve Transfer
async def test_normal_9(self, processor, shared_contract, session):
# Issue Token
token_list_contract = shared_contract["TokenList"]
@@ -1226,9 +1445,7 @@ async def test_normal_9(self, processor, shared_contract, session):
#
# Single Token
# Single event logs
- # - Transfer
- # - Apply For Transfer
- # - Cancel
+ # - Cancel Transfer
async def test_normal_10(self, processor, shared_contract, session):
# Issue Token
token_list_contract = shared_contract["TokenList"]
@@ -1464,17 +1681,17 @@ async def test_normal_12(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
- _position: IDXPosition = _position_list[0]
- assert _position.token_address == token["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000 + 111 + 222
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 10000 - 111 - 222 - 333
- assert _position.exchange_commitment == 333
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 10000 + 111 + 222
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 10000 - 111 - 222 - 333
+ assert _position_issuer.exchange_commitment == 333
_idx_position_bond_block_number: IDXPositionBondBlockNumber = session.scalars(
select(IDXPositionBondBlockNumber)
@@ -1535,17 +1752,17 @@ async def test_normal_13(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
- _position: IDXPosition = _position_list[0]
- assert _position.token_address == token["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000 + 55
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 10000 - 55 - 66
- assert _position.exchange_commitment == 66
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 10000 + 55
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 10000 - 55 - 66
+ assert _position_issuer.exchange_commitment == 66
_idx_position_bond_block_number: IDXPositionBondBlockNumber = session.scalars(
select(IDXPositionBondBlockNumber)
@@ -1626,19 +1843,7 @@ async def test_normal_14(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 2
-
- _idx_position_bond_block_number: IDXPositionBondBlockNumber = session.scalars(
- select(IDXPositionBondBlockNumber)
- .where(IDXPositionBondBlockNumber.token_address == token["address"])
- .limit(1)
- ).first()
- assert _idx_position_bond_block_number.latest_block_number == block_number
-
- _position: IDXPosition = session.scalars(
+ _position_issuer: IDXPosition = session.scalars(
select(IDXPosition)
.where(
and_(
@@ -1648,14 +1853,14 @@ async def test_normal_14(self, processor, shared_contract, session):
)
.limit(1)
).first()
- assert _position.token_address == token["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 10000 - 200
- assert _position.exchange_commitment == 0
-
- _position: IDXPosition = session.scalars(
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 10000
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 10000 - 200
+ assert _position_issuer.exchange_commitment == 0
+
+ _position_trader: IDXPosition = session.scalars(
select(IDXPosition)
.where(
and_(
@@ -1665,12 +1870,19 @@ async def test_normal_14(self, processor, shared_contract, session):
)
.limit(1)
).first()
- assert _position.token_address == token["address"]
- assert _position.account_address == self.trader["account_address"]
- assert _position.balance == 0
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 200
- assert _position.exchange_commitment == 0
+ assert _position_trader.token_address == token["address"]
+ assert _position_trader.account_address == self.trader["account_address"]
+ assert _position_trader.balance == 0
+ assert _position_trader.pending_transfer == 0
+ assert _position_trader.exchange_balance == 200
+ assert _position_trader.exchange_commitment == 0
+
+ _idx_position_bond_block_number: IDXPositionBondBlockNumber = session.scalars(
+ select(IDXPositionBondBlockNumber)
+ .where(IDXPositionBondBlockNumber.token_address == token["address"])
+ .limit(1)
+ ).first()
+ assert _idx_position_bond_block_number.latest_block_number == block_number
#
# No event logs
@@ -1969,17 +2181,17 @@ async def test_normal_19(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
- _position: IDXPosition = _position_list[0]
- assert _position.token_address == token1["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000 + 55 - 100
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 10000 - 55 - 66
- assert _position.exchange_commitment == 66
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token1["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 10000 + 55 - 100
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 10000 - 55 - 66
+ assert _position_issuer.exchange_commitment == 66
_idx_position_bond_block_number: IDXPositionBondBlockNumber = session.scalars(
select(IDXPositionBondBlockNumber)
@@ -1998,11 +2210,6 @@ async def test_normal_19(self, processor, shared_contract, session):
session.rollback()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 2
-
_idx_position_bond_block_number1: IDXPositionBondBlockNumber = session.scalars(
select(IDXPositionBondBlockNumber)
.where(IDXPositionBondBlockNumber.token_address == token1["address"])
diff --git a/tests/batch/indexer_Position_Coupon_test.py b/tests/batch/indexer_Position_Coupon_test.py
index 3f97909ec..f94d6518b 100644
--- a/tests/batch/indexer_Position_Coupon_test.py
+++ b/tests/batch/indexer_Position_Coupon_test.py
@@ -898,10 +898,16 @@ async def test_normal_11(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
+ _position: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position.token_address == token1["address"]
+ assert _position.account_address == self.issuer["account_address"]
+ assert _position.balance == 1000000 - 10000 + 55 - 100
+ assert _position.exchange_balance == 10000 - 55 - 66
+ assert _position.exchange_commitment == 66
_idx_position_coupon_block_number: IDXPositionCouponBlockNumber = (
session.scalars(
@@ -912,13 +918,6 @@ async def test_normal_11(self, processor, shared_contract, session):
)
assert _idx_position_coupon_block_number.latest_block_number == block_number1
- _position: IDXPosition = _position_list[0]
- assert _position.token_address == token1["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000 + 55 - 100
- assert _position.exchange_balance == 10000 - 55 - 66
- assert _position.exchange_commitment == 66
-
# Token2 Listing
self.listing_token(token2["address"], session)
@@ -932,10 +931,6 @@ async def test_normal_11(self, processor, shared_contract, session):
session.rollback()
assert eth_getCode_mock.call_count == 0
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 2
_idx_position_coupon_block_number1: IDXPositionCouponBlockNumber = (
session.scalars(
diff --git a/tests/batch/indexer_Position_Membership_test.py b/tests/batch/indexer_Position_Membership_test.py
index fe41f2b23..c1b3e540e 100644
--- a/tests/batch/indexer_Position_Membership_test.py
+++ b/tests/batch/indexer_Position_Membership_test.py
@@ -852,10 +852,16 @@ async def test_normal_10(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
+ _position: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position.token_address == token1["address"]
+ assert _position.account_address == self.issuer["account_address"]
+ assert _position.balance == 1000000 - 10000 + 55
+ assert _position.exchange_balance == 10000 - 55 - 66
+ assert _position.exchange_commitment == 66
_idx_position_coupon_block_number: IDXPositionMembershipBlockNumber = (
session.scalars(
@@ -868,13 +874,6 @@ async def test_normal_10(self, processor, shared_contract, session):
)
assert _idx_position_coupon_block_number.latest_block_number == block_number1
- _position: IDXPosition = _position_list[0]
- assert _position.token_address == token1["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000 + 55
- assert _position.exchange_balance == 10000 - 55 - 66
- assert _position.exchange_commitment == 66
-
# Token2 Listing
self.listing_token(token2["address"], session)
@@ -883,11 +882,8 @@ async def test_normal_10(self, processor, shared_contract, session):
await processor.sync_new_logs()
session.rollback()
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 2
+ # Assertion
_idx_position_coupon_block_number1: IDXPositionMembershipBlockNumber = (
session.scalars(
select(IDXPositionMembershipBlockNumber)
diff --git a/tests/batch/indexer_Position_Share_test.py b/tests/batch/indexer_Position_Share_test.py
index fedc834eb..34f74c3b5 100644
--- a/tests/batch/indexer_Position_Share_test.py
+++ b/tests/batch/indexer_Position_Share_test.py
@@ -30,7 +30,7 @@
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from web3 import Web3
-from web3.exceptions import ABIEventNotFound
+from web3.exceptions import ABIEventNotFound, TransactionNotFound
from web3.middleware import ExtraDataToPOAMiddleware
from app import config
@@ -481,7 +481,8 @@ async def test_normal_3(self, processor, shared_contract, session):
# Single Token
# Single event logs
# - Lock
- async def test_normal_4_1(self, processor, shared_contract, session):
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_4_1(self, processor, shared_contract, session, is_old_token):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract = shared_contract["PersonalInfo"]
@@ -497,15 +498,25 @@ async def test_normal_4_1(self, processor, shared_contract, session):
# Lock
token_contract.functions.lock(
- self.trader["account_address"], 1500, '{"message": "locked1"}'
+ self.trader["account_address"], 1500, '{"message": "garnishment"}'
).transact({"from": self.issuer["account_address"]})
token_contract.functions.lock(
- self.trader["account_address"], 1500, '{"message": "locked2"}'
+ self.trader["account_address"], 1500, '{"message": "ibet_wst_bridge"}'
+ ).transact({"from": self.issuer["account_address"]})
+ token_contract.functions.lock(
+ self.trader["account_address"], 1500, '{"message": "inheritance"}'
).transact({"from": self.issuer["account_address"]})
# Run target process
block_number = web3.eth.block_number
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
_position_list: Sequence[IDXPosition] = session.scalars(
@@ -523,7 +534,7 @@ async def test_normal_4_1(self, processor, shared_contract, session):
_position = _position_list[0]
assert _position.token_address == token["address"]
assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 3000
+ assert _position.balance == 1000000 - 4500
assert _position.pending_transfer == 0
assert _position.exchange_balance == 0
assert _position.exchange_commitment == 0
@@ -537,10 +548,10 @@ async def test_normal_4_1(self, processor, shared_contract, session):
assert _locked1.token_address == token["address"]
assert _locked1.lock_address == self.trader["account_address"]
assert _locked1.account_address == self.issuer["account_address"]
- assert _locked1.value == 3000
+ assert _locked1.value == 4500
_lock_list = session.scalars(select(IDXLock).order_by(IDXLock.id)).all()
- assert len(_lock_list) == 2
+ assert len(_lock_list) == 3
_lock1 = _lock_list[0]
assert _lock1.id == 1
@@ -548,7 +559,7 @@ async def test_normal_4_1(self, processor, shared_contract, session):
assert _lock1.lock_address == self.trader["account_address"]
assert _lock1.account_address == self.issuer["account_address"]
assert _lock1.value == 1500
- assert _lock1.data == {"message": "locked1"}
+ assert _lock1.data == {"message": "garnishment"}
assert _lock1.is_forced is False
_lock2 = _lock_list[1]
assert _lock2.id == 2
@@ -556,14 +567,23 @@ async def test_normal_4_1(self, processor, shared_contract, session):
assert _lock2.lock_address == self.trader["account_address"]
assert _lock2.account_address == self.issuer["account_address"]
assert _lock2.value == 1500
- assert _lock2.data == {"message": "locked2"}
+ assert _lock2.data == {"message": "ibet_wst_bridge"}
assert _lock2.is_forced is False
+ _lock3 = _lock_list[2]
+ assert _lock3.id == 3
+ assert _lock3.token_address == token["address"]
+ assert _lock3.lock_address == self.trader["account_address"]
+ assert _lock3.account_address == self.issuer["account_address"]
+ assert _lock3.value == 1500
+ assert _lock3.data == {}
+ assert _lock3.is_forced is False
#
# Single Token
# Single event logs
# - ForceLock
- async def test_normal_4_2(self, processor, shared_contract, session):
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_4_2(self, processor, shared_contract, session, is_old_token):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract = shared_contract["PersonalInfo"]
@@ -591,24 +611,50 @@ async def test_normal_4_2(self, processor, shared_contract, session):
self.issuer["account_address"],
self.trader["account_address"],
1500,
- '{"message": "force_locked1"}',
+ '{"message": "force_lock"}',
).transact({"from": self.issuer["account_address"]})
token_contract.functions.forceLock(
self.issuer["account_address"],
self.trader["account_address"],
1500,
- '{"message": "force_locked2"}',
+ '{"message": "force_lock"}',
).transact({"from": self.issuer["account_address"]})
# Run target process
block_number = web3.eth.block_number
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 3000
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 0
+ assert _position_issuer.exchange_commitment == 0
+
+ _position_trader: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.trader["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_trader.token_address == token["address"]
+ assert _position_trader.account_address == self.trader["account_address"]
+ assert _position_trader.balance == 0
+ assert _position_trader.pending_transfer == 0
+ assert _position_trader.exchange_balance == 0
+ assert _position_trader.exchange_commitment == 0
_idx_position_share_block_number: IDXPositionShareBlockNumber = session.scalars(
select(IDXPositionShareBlockNumber)
@@ -617,14 +663,6 @@ async def test_normal_4_2(self, processor, shared_contract, session):
).first()
assert _idx_position_share_block_number.latest_block_number == block_number
- _position = _position_list[0]
- assert _position.token_address == token["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 3000
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 0
- assert _position.exchange_commitment == 0
-
_locked_list: Sequence[IDXLockedPosition] = session.scalars(
select(IDXLockedPosition).order_by(IDXLockedPosition.created)
).all()
@@ -646,7 +684,7 @@ async def test_normal_4_2(self, processor, shared_contract, session):
assert _lock1.lock_address == self.issuer["account_address"]
assert _lock1.account_address == self.trader["account_address"]
assert _lock1.value == 1500
- assert _lock1.data == {"message": "force_locked1"}
+ assert _lock1.data == {"message": "force_lock"}
assert _lock1.is_forced is True
_lock2 = _lock_list[1]
assert _lock2.id == 2
@@ -655,14 +693,15 @@ async def test_normal_4_2(self, processor, shared_contract, session):
assert _lock2.lock_address == self.issuer["account_address"]
assert _lock2.account_address == self.trader["account_address"]
assert _lock2.value == 1500
- assert _lock2.data == {"message": "force_locked2"}
+ assert _lock2.data == {"message": "force_lock"}
assert _lock2.is_forced is True
#
# Single Token
# Single event logs
# - Unlock
- async def test_normal_5_1(self, processor, shared_contract, session):
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_5_1(self, processor, shared_contract, session, is_old_token):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract = shared_contract["PersonalInfo"]
@@ -678,7 +717,7 @@ async def test_normal_5_1(self, processor, shared_contract, session):
# Lock
token_contract.functions.lock(
- self.trader["account_address"], 3000, '{"message": "locked1"}'
+ self.trader["account_address"], 3000, '{"message": "garnishment"}'
).transact({"from": self.issuer["account_address"]})
# Unlock
@@ -686,12 +725,19 @@ async def test_normal_5_1(self, processor, shared_contract, session):
self.issuer["account_address"],
self.trader2["account_address"],
100,
- '{"message": "unlocked1"}',
+ '{"message": "garnishment"}',
).transact({"from": self.trader["account_address"]})
# Run target process
block_number = web3.eth.block_number
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
_position_list: Sequence[IDXPosition] = session.scalars(
@@ -759,7 +805,7 @@ async def test_normal_5_1(self, processor, shared_contract, session):
assert _lock1.lock_address == self.trader["account_address"]
assert _lock1.account_address == self.issuer["account_address"]
assert _lock1.value == 3000
- assert _lock1.data == {"message": "locked1"}
+ assert _lock1.data == {"message": "garnishment"}
_unlock_list = session.scalars(select(IDXUnlock).order_by(IDXUnlock.id)).all()
assert len(_unlock_list) == 1
@@ -771,14 +817,15 @@ async def test_normal_5_1(self, processor, shared_contract, session):
assert _unlock1.account_address == self.issuer["account_address"]
assert _unlock1.recipient_address == self.trader2["account_address"]
assert _unlock1.value == 100
- assert _unlock1.data == {"message": "unlocked1"}
+ assert _unlock1.data == {"message": "garnishment"}
assert _unlock1.is_forced is False
#
# Single Token
# Single event logs
# - ForceUnlock
- async def test_normal_5_2(self, processor, shared_contract, session):
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_5_2(self, processor, shared_contract, session, is_old_token):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract = shared_contract["PersonalInfo"]
@@ -794,7 +841,7 @@ async def test_normal_5_2(self, processor, shared_contract, session):
# Lock
token_contract.functions.lock(
- self.trader["account_address"], 3000, '{"message": "locked1"}'
+ self.trader["account_address"], 3000, '{"message": "garnishment"}'
).transact({"from": self.issuer["account_address"]})
# Unlock
@@ -803,12 +850,19 @@ async def test_normal_5_2(self, processor, shared_contract, session):
self.issuer["account_address"],
self.trader2["account_address"],
100,
- '{"message": "unlocked1"}',
+ '{"message": "garnishment"}',
).transact({"from": self.issuer["account_address"]})
# Run target process
block_number = web3.eth.block_number
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
_position_list: Sequence[IDXPosition] = session.scalars(
@@ -876,7 +930,7 @@ async def test_normal_5_2(self, processor, shared_contract, session):
assert _lock1.lock_address == self.trader["account_address"]
assert _lock1.account_address == self.issuer["account_address"]
assert _lock1.value == 3000
- assert _lock1.data == {"message": "locked1"}
+ assert _lock1.data == {"message": "garnishment"}
_unlock_list = session.scalars(select(IDXUnlock).order_by(IDXUnlock.id)).all()
assert len(_unlock_list) == 1
@@ -888,7 +942,169 @@ async def test_normal_5_2(self, processor, shared_contract, session):
assert _unlock1.account_address == self.issuer["account_address"]
assert _unlock1.recipient_address == self.trader2["account_address"]
assert _unlock1.value == 100
- assert _unlock1.data == {"message": "unlocked1"}
+ assert _unlock1.data == {"message": "garnishment"}
+ assert _unlock1.is_forced is True
+
+ #
+ # Single Token
+ # Single event logs
+ # - ForceChangeLockedAccount
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_5_3(self, processor, shared_contract, session, is_old_token):
+ # Issue Token
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+ token = self.issue_token_share(
+ self.issuer,
+ config.ZERO_ADDRESS,
+ personal_info_contract["address"],
+ token_list_contract,
+ )
+ self.listing_token(token["address"], session)
+
+ token_contract = Contract.get_contract("IbetShare", token["address"])
+
+ PersonalInfoUtils.register(
+ self.trader["account_address"],
+ personal_info_contract["address"],
+ self.issuer["account_address"],
+ )
+ # Transfer
+ share_transfer_to_exchange(
+ self.issuer, {"address": self.trader["account_address"]}, token, 3000
+ )
+
+ # Lock
+ token_contract.functions.lock(
+ self.issuer["account_address"], # lock address
+ 3000,
+ '{"message": "garnishment"}',
+ ).transact({"from": self.trader["account_address"]})
+
+ # ForceChangeLockedAccount
+ token_contract.functions.forceChangeLockedAccount(
+ self.issuer["account_address"], # lock address
+ self.trader["account_address"], # before account address
+ self.trader2["account_address"], # after account address
+ 100,
+ '{"message": "ibet_wst_bridge"}',
+ ).transact({"from": self.issuer["account_address"]})
+
+ # Run target process
+ block_number = web3.eth.block_number
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
+
+ # Assertion
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(
+ and_(
+ IDXPosition.token_address == token["address"],
+ IDXPosition.account_address == self.issuer["account_address"],
+ )
+ )
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 3000
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 0
+ assert _position_issuer.exchange_commitment == 0
+
+ _position_trader_1: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(
+ and_(
+ IDXPosition.token_address == token["address"],
+ IDXPosition.account_address == self.trader["account_address"],
+ )
+ )
+ .limit(1)
+ ).first()
+ assert _position_trader_1.token_address == token["address"]
+ assert _position_trader_1.account_address == self.trader["account_address"]
+ assert _position_trader_1.balance == 0
+ assert _position_trader_1.pending_transfer == 0
+ assert _position_trader_1.exchange_balance == 0
+ assert _position_trader_1.exchange_commitment == 0
+
+ _position_trader_2: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(
+ and_(
+ IDXPosition.token_address == token["address"],
+ IDXPosition.account_address == self.trader2["account_address"],
+ )
+ )
+ .limit(1)
+ ).first()
+ assert _position_trader_2.token_address == token["address"]
+ assert _position_trader_2.account_address == self.trader2["account_address"]
+ assert _position_trader_2.balance == 0
+ assert _position_trader_2.pending_transfer == 0
+ assert _position_trader_2.exchange_balance == 0
+ assert _position_trader_2.exchange_commitment == 0
+
+ _idx_position_share_block_number: IDXPositionShareBlockNumber = session.scalars(
+ select(IDXPositionShareBlockNumber)
+ .where(IDXPositionShareBlockNumber.token_address == token["address"])
+ .limit(1)
+ ).first()
+ assert _idx_position_share_block_number.latest_block_number == block_number
+
+ _locked_list = session.scalars(
+ select(IDXLockedPosition).order_by(IDXLockedPosition.created)
+ ).all()
+ assert len(_locked_list) == 2
+ _locked = _locked_list[0]
+ assert _locked.token_address == token["address"]
+ assert _locked.lock_address == self.issuer["account_address"]
+ assert _locked.account_address == self.trader["account_address"]
+ assert _locked.value == 2900
+ _locked = _locked_list[1]
+ assert _locked.token_address == token["address"]
+ assert _locked.lock_address == self.issuer["account_address"]
+ assert _locked.account_address == self.trader2["account_address"]
+ assert _locked.value == 100
+
+ _lock_list = session.scalars(select(IDXLock).order_by(IDXLock.id)).all()
+ assert len(_lock_list) == 2
+ _lock1 = _lock_list[0]
+ assert _lock1.id == 1
+ assert _lock1.token_address == token["address"]
+ assert _lock1.msg_sender == self.trader["account_address"]
+ assert _lock1.lock_address == self.issuer["account_address"]
+ assert _lock1.account_address == self.trader["account_address"]
+ assert _lock1.value == 3000
+ assert _lock1.data == {"message": "garnishment"}
+ _lock2 = _lock_list[1]
+ assert _lock2.id == 2
+ assert _lock2.token_address == token["address"]
+ assert _lock2.msg_sender == self.issuer["account_address"]
+ assert _lock2.lock_address == self.issuer["account_address"]
+ assert _lock2.account_address == self.trader2["account_address"]
+ assert _lock2.value == 100
+ assert _lock2.data == {"message": "ibet_wst_bridge"}
+
+ _unlock_list = session.scalars(select(IDXUnlock).order_by(IDXUnlock.id)).all()
+ assert len(_unlock_list) == 1
+ _unlock1 = _unlock_list[0]
+ assert _unlock1.id == 1
+ assert _unlock1.token_address == token["address"]
+ assert _unlock1.msg_sender == self.issuer["account_address"]
+ assert _unlock1.lock_address == self.issuer["account_address"]
+ assert _unlock1.account_address == self.trader["account_address"]
+ assert _unlock1.recipient_address == self.trader2["account_address"]
+ assert _unlock1.value == 100
+ assert _unlock1.data == {"message": "ibet_wst_bridge"}
assert _unlock1.is_forced is True
#
@@ -988,7 +1204,6 @@ async def test_normal_7(self, processor, shared_contract, session):
#
# Single Token
# Single event logs
- # - Transfer
# - Apply For Transfer
async def test_normal_8(self, processor, shared_contract, session):
# Issue Token
@@ -1083,9 +1298,7 @@ async def test_normal_8(self, processor, shared_contract, session):
#
# Single Token
# Single event logs
- # - Transfer
- # - Apply For Transfer
- # - Approve
+ # - Approve Transfer
async def test_normal_9(self, processor, shared_contract, session):
# Issue Token
token_list_contract = shared_contract["TokenList"]
@@ -1200,9 +1413,7 @@ async def test_normal_9(self, processor, shared_contract, session):
#
# Single Token
# Single event logs
- # - Transfer
- # - Apply For Transfer
- # - Cancel
+ # - Cancel Transfer
async def test_normal_10(self, processor, shared_contract, session):
# Issue Token
token_list_contract = shared_contract["TokenList"]
@@ -1438,10 +1649,17 @@ async def test_normal_12(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 10000 + 111 + 222
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 10000 - 111 - 222 - 333
+ assert _position_issuer.exchange_commitment == 333
_idx_position_share_block_number: IDXPositionShareBlockNumber = session.scalars(
select(IDXPositionShareBlockNumber)
@@ -1450,14 +1668,6 @@ async def test_normal_12(self, processor, shared_contract, session):
).first()
assert _idx_position_share_block_number.latest_block_number == block_number
- _position: IDXPosition = _position_list[0]
- assert _position.token_address == token["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000 + 111 + 222
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 10000 - 111 - 222 - 333
- assert _position.exchange_commitment == 333
-
#
# Single Token
# Multi event with IbetExchange logs
@@ -1510,10 +1720,17 @@ async def test_normal_13(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 10000 + 55
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 10000 - 55 - 66
+ assert _position_issuer.exchange_commitment == 66
_idx_position_share_block_number: IDXPositionShareBlockNumber = session.scalars(
select(IDXPositionShareBlockNumber)
@@ -1522,14 +1739,6 @@ async def test_normal_13(self, processor, shared_contract, session):
).first()
assert _idx_position_share_block_number.latest_block_number == block_number
- _position: IDXPosition = _position_list[0]
- assert _position.token_address == token["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000 + 55
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 10000 - 55 - 66
- assert _position.exchange_commitment == 66
-
#
# Single Token
# Multi event with DVP logs
@@ -1602,19 +1811,7 @@ async def test_normal_14(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 2
-
- _idx_position_share_block_number: IDXPositionShareBlockNumber = session.scalars(
- select(IDXPositionShareBlockNumber)
- .where(IDXPositionShareBlockNumber.token_address == token["address"])
- .limit(1)
- ).first()
- assert _idx_position_share_block_number.latest_block_number == block_number
-
- _position: IDXPosition = session.scalars(
+ _position_issuer: IDXPosition = session.scalars(
select(IDXPosition)
.where(
and_(
@@ -1624,14 +1821,14 @@ async def test_normal_14(self, processor, shared_contract, session):
)
.limit(1)
).first()
- assert _position.token_address == token["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 10000 - 200
- assert _position.exchange_commitment == 0
-
- _position: IDXPosition = session.scalars(
+ assert _position_issuer.token_address == token["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 10000
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 10000 - 200
+ assert _position_issuer.exchange_commitment == 0
+
+ _position_trader: IDXPosition = session.scalars(
select(IDXPosition)
.where(
and_(
@@ -1641,12 +1838,19 @@ async def test_normal_14(self, processor, shared_contract, session):
)
.limit(1)
).first()
- assert _position.token_address == token["address"]
- assert _position.account_address == self.trader["account_address"]
- assert _position.balance == 0
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 200
- assert _position.exchange_commitment == 0
+ assert _position_trader.token_address == token["address"]
+ assert _position_trader.account_address == self.trader["account_address"]
+ assert _position_trader.balance == 0
+ assert _position_trader.pending_transfer == 0
+ assert _position_trader.exchange_balance == 200
+ assert _position_trader.exchange_commitment == 0
+
+ _idx_position_share_block_number: IDXPositionShareBlockNumber = session.scalars(
+ select(IDXPositionShareBlockNumber)
+ .where(IDXPositionShareBlockNumber.token_address == token["address"])
+ .limit(1)
+ ).first()
+ assert _idx_position_share_block_number.latest_block_number == block_number
#
# No event logs
@@ -1946,10 +2150,17 @@ async def test_normal_19(self, processor, shared_contract, session):
await processor.sync_new_logs()
# Assertion
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 1
+ _position_issuer: IDXPosition = session.scalars(
+ select(IDXPosition)
+ .where(IDXPosition.account_address == self.issuer["account_address"])
+ .limit(1)
+ ).first()
+ assert _position_issuer.token_address == token1["address"]
+ assert _position_issuer.account_address == self.issuer["account_address"]
+ assert _position_issuer.balance == 1000000 - 10000 + 55 - 100
+ assert _position_issuer.pending_transfer == 0
+ assert _position_issuer.exchange_balance == 10000 - 55 - 66
+ assert _position_issuer.exchange_commitment == 66
_idx_position_share_block_number: IDXPositionShareBlockNumber = session.scalars(
select(IDXPositionShareBlockNumber)
@@ -1958,14 +2169,6 @@ async def test_normal_19(self, processor, shared_contract, session):
).first()
assert _idx_position_share_block_number.latest_block_number == block_number1
- _position: IDXPosition = _position_list[0]
- assert _position.token_address == token1["address"]
- assert _position.account_address == self.issuer["account_address"]
- assert _position.balance == 1000000 - 10000 + 55 - 100
- assert _position.pending_transfer == 0
- assert _position.exchange_balance == 10000 - 55 - 66
- assert _position.exchange_commitment == 66
-
# Token2 Listing
self.listing_token(token2["address"], session)
@@ -1974,11 +2177,8 @@ async def test_normal_19(self, processor, shared_contract, session):
await processor.sync_new_logs()
session.rollback()
- _position_list: Sequence[IDXPosition] = session.scalars(
- select(IDXPosition).order_by(IDXPosition.created)
- ).all()
- assert len(_position_list) == 2
+ # Assertion
_idx_position_share_block_number1: IDXPositionShareBlockNumber = (
session.scalars(
select(IDXPositionShareBlockNumber)
diff --git a/tests/batch/indexer_PublicInfo_PublicAccountList_test.py b/tests/batch/indexer_PublicInfo_PublicAccountList_test.py
index 5efd8cb9b..ad23253ca 100644
--- a/tests/batch/indexer_PublicInfo_PublicAccountList_test.py
+++ b/tests/batch/indexer_PublicInfo_PublicAccountList_test.py
@@ -50,15 +50,9 @@ def caplog(caplog: pytest.LogCaptureFixture):
class MockResponse:
def __init__(self, data: object, status_code: int = 200):
self.data = data
- self.status = status_code
+ self.status_code = status_code
- async def __aexit__(self, exc_type, exc, tb):
- pass
-
- async def __aenter__(self):
- return self
-
- async def json(self) -> object:
+ def json(self) -> object:
return self.data
@@ -78,7 +72,7 @@ class TestProcessor:
#
# 0 record
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_1(self, mock_get, processor, async_session):
# Prepare data
_account_list = PublicAccountList()
@@ -93,7 +87,7 @@ async def test_normal_1(self, mock_get, processor, async_session):
mock_get.side_effect = [MockResponse([])]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
# - The cleanup process should remove all data.
@@ -105,7 +99,7 @@ async def test_normal_1(self, mock_get, processor, async_session):
#
# Multiple records
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_2(self, mock_get, processor, async_session):
# Prepare data
_account_list = PublicAccountList()
@@ -137,7 +131,7 @@ async def test_normal_2(self, mock_get, processor, async_session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
# - The cleanup process should remove all data.
@@ -169,7 +163,7 @@ async def test_normal_2(self, mock_get, processor, async_session):
#
# There are no differences from last time
# -> Skip this cycle
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_3_1(self, mock_get, processor, async_session, caplog):
# Run target process: 1st time
mock_get.side_effect = [
@@ -190,7 +184,7 @@ async def test_normal_3_1(self, mock_get, processor, async_session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Run target process: 2nd time
mock_get.side_effect = [
@@ -211,7 +205,7 @@ async def test_normal_3_1(self, mock_get, processor, async_session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Assertion
# - The cleanup process should remove all of your data.
@@ -250,7 +244,7 @@ async def test_normal_3_1(self, mock_get, processor, async_session, caplog):
#
# There are differences from last time
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_3_2(self, mock_get, processor, async_session, caplog):
# Run target process: 1st time
mock_get.side_effect = [
@@ -271,7 +265,7 @@ async def test_normal_3_2(self, mock_get, processor, async_session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Run target process: 2nd time
mock_get.side_effect = [
@@ -286,7 +280,7 @@ async def test_normal_3_2(self, mock_get, processor, async_session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Assertion
# - The cleanup process should remove all data.
@@ -323,7 +317,7 @@ async def test_normal_3_2(self, mock_get, processor, async_session, caplog):
#
# API error: ConnectionError
@mock.patch(
- "aiohttp.client.ClientSession.get",
+ "requests.Session.get",
MagicMock(side_effect=requests.exceptions.ConnectionError),
)
async def test_error_1_1(self, processor, async_session):
@@ -337,7 +331,7 @@ async def test_error_1_1(self, processor, async_session):
await async_session.commit()
# Run target process
- await processor.process()
+ processor.process()
# Assertion
# - The cleanup process should be rolled back and
@@ -362,7 +356,7 @@ async def test_error_1_1(self, processor, async_session):
#
# API error: Not succeed request
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_error_1_2(self, mock_get, processor, async_session):
# Prepare data
_account_list = PublicAccountList()
@@ -377,7 +371,7 @@ async def test_error_1_2(self, mock_get, processor, async_session):
mock_get.side_effect = [MockResponse([], 400)]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
# - The cleanup process should be rolled back and
@@ -403,7 +397,7 @@ async def test_error_1_2(self, mock_get, processor, async_session):
#
# API error: JSONDecodeError
@mock.patch(
- "aiohttp.client.ClientSession.get",
+ "requests.Session.get",
MagicMock(side_effect=json.decoder.JSONDecodeError),
)
async def test_error_1_3(self, processor, async_session):
@@ -417,7 +411,7 @@ async def test_error_1_3(self, processor, async_session):
await async_session.commit()
# Run target process
- await processor.process()
+ processor.process()
# Assertion
# - The cleanup process should be rolled back and
@@ -443,7 +437,7 @@ async def test_error_1_3(self, processor, async_session):
#
# Invalid type error
# -> Skip processing
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
@pytest.mark.parametrize(
"invalid_record",
[
@@ -513,7 +507,7 @@ async def test_error_2(self, mock_get, processor, async_session, invalid_record)
mock_get.side_effect = [MockResponse([invalid_record])]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
await async_session.rollback()
@@ -528,7 +522,7 @@ async def test_error_2(self, mock_get, processor, async_session, invalid_record)
#
# Other error
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_error_3(self, mock_get, processor, async_session):
# Mock
mock_get.side_effect = [
@@ -547,7 +541,7 @@ async def test_error_3(self, mock_get, processor, async_session):
# Run target process
with pytest.raises(Exception):
- await processor.process()
+ processor.process()
# Assertion
await async_session.rollback()
diff --git a/tests/batch/indexer_PublicInfo_TokenList_test.py b/tests/batch/indexer_PublicInfo_TokenList_test.py
index 2e364472c..128b04b39 100644
--- a/tests/batch/indexer_PublicInfo_TokenList_test.py
+++ b/tests/batch/indexer_PublicInfo_TokenList_test.py
@@ -50,15 +50,9 @@ def caplog(caplog: pytest.LogCaptureFixture):
class MockResponse:
def __init__(self, data: object, status_code: int = 200):
self.data = data
- self.status = status_code
+ self.status_code = status_code
- async def __aexit__(self, exc_type, exc, tb):
- pass
-
- async def __aenter__(self):
- return self
-
- async def json(self) -> object:
+ def json(self) -> object:
return self.data
@@ -76,7 +70,7 @@ class TestProcessor:
#
# 0 record
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_1(self, mock_get, processor, async_session):
# Prepare data
_token_list_item = TokenList()
@@ -103,7 +97,7 @@ async def test_normal_1(self, mock_get, processor, async_session):
mock_get.side_effect = [MockResponse([])]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
await async_session.rollback()
@@ -116,7 +110,7 @@ async def test_normal_1(self, mock_get, processor, async_session):
#
# 1 record
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_2(self, mock_get, processor, async_session):
# Prepare data
_token_list_item = TokenList()
@@ -154,7 +148,7 @@ async def test_normal_2(self, mock_get, processor, async_session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
await async_session.rollback()
@@ -171,7 +165,7 @@ async def test_normal_2(self, mock_get, processor, async_session):
#
# 2 record
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_3(self, mock_get, processor, async_session):
# Prepare data
_token_list_item = TokenList()
@@ -215,7 +209,7 @@ async def test_normal_3(self, mock_get, processor, async_session):
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
await async_session.rollback()
@@ -237,7 +231,7 @@ async def test_normal_3(self, mock_get, processor, async_session):
#
# There are no differences from last time
# -> Skip this cycle
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_1(self, mock_get, processor, async_session, caplog):
# Run target process: 1st time
mock_get.side_effect = [
@@ -258,7 +252,7 @@ async def test_normal_4_1(self, mock_get, processor, async_session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Run target process: 2nd time
mock_get.side_effect = [
@@ -279,7 +273,7 @@ async def test_normal_4_1(self, mock_get, processor, async_session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Assertion
await async_session.rollback()
@@ -308,7 +302,7 @@ async def test_normal_4_1(self, mock_get, processor, async_session, caplog):
#
# There are differences from the previous cycle
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_normal_4_2(self, mock_get, processor, async_session, caplog):
# Run target process: 1st time
mock_get.side_effect = [
@@ -329,7 +323,7 @@ async def test_normal_4_2(self, mock_get, processor, async_session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Run target process: 2nd time
mock_get.side_effect = [
@@ -344,7 +338,7 @@ async def test_normal_4_2(self, mock_get, processor, async_session, caplog):
]
)
]
- await processor.process()
+ processor.process()
# Assertion
await async_session.rollback()
@@ -374,7 +368,7 @@ async def test_normal_4_2(self, mock_get, processor, async_session, caplog):
#
# API error: ConnectionError
@mock.patch(
- "aiohttp.client.ClientSession.get",
+ "requests.Session.get",
MagicMock(side_effect=requests.exceptions.ConnectionError),
)
async def test_error_1_1(self, processor, async_session):
@@ -388,7 +382,7 @@ async def test_error_1_1(self, processor, async_session):
await async_session.commit()
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_token_list: Sequence[TokenList] = (
@@ -400,7 +394,7 @@ async def test_error_1_1(self, processor, async_session):
#
# API error: Not succeed request
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_error_1_2(self, mock_get, processor, async_session):
# Prepare data
_token_list_item = TokenList()
@@ -415,7 +409,7 @@ async def test_error_1_2(self, mock_get, processor, async_session):
mock_get.side_effect = [MockResponse([], 400)]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_token_list: Sequence[TokenList] = (
@@ -428,7 +422,7 @@ async def test_error_1_2(self, mock_get, processor, async_session):
#
# API error: JSONDecodeError
@mock.patch(
- "aiohttp.client.ClientSession.get",
+ "requests.Session.get",
MagicMock(side_effect=json.decoder.JSONDecodeError),
)
async def test_error_1_3(self, processor, async_session):
@@ -442,7 +436,7 @@ async def test_error_1_3(self, processor, async_session):
await async_session.commit()
# Run target process
- await processor.process()
+ processor.process()
# Assertion
_token_list: Sequence[TokenList] = (
@@ -455,7 +449,7 @@ async def test_error_1_3(self, processor, async_session):
#
# Invalid type error
# -> Skip processing
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
@pytest.mark.parametrize(
"invalid_record",
[
@@ -543,7 +537,7 @@ async def test_error_2(self, mock_get, processor, async_session, invalid_record)
]
# Run target process
- await processor.process()
+ processor.process()
# Assertion
await async_session.rollback()
@@ -560,7 +554,7 @@ async def test_error_2(self, mock_get, processor, async_session, invalid_record)
#
# Other error
- @mock.patch("aiohttp.client.ClientSession.get")
+ @mock.patch("requests.Session.get")
async def test_error_3(self, mock_get, processor, async_session):
# Prepare data
_token_list_item = TokenList()
@@ -600,7 +594,7 @@ async def test_error_3(self, mock_get, processor, async_session):
# Run target process
with pytest.raises(Exception):
- await processor.process()
+ processor.process()
# Assertion
_token_list: Sequence[TokenList] = (
diff --git a/tests/batch/indexer_Token_Holders_test.py b/tests/batch/indexer_Token_Holders_test.py
index cd24d7546..aa18b951c 100644
--- a/tests/batch/indexer_Token_Holders_test.py
+++ b/tests/batch/indexer_Token_Holders_test.py
@@ -40,6 +40,7 @@
bond_apply_for_transfer,
bond_approve_transfer,
bond_cancel_transfer,
+ bond_force_change_locked_account,
bond_force_lock,
bond_force_unlock,
bond_issue_from,
@@ -77,6 +78,7 @@
share_apply_for_transfer,
share_approve_transfer,
share_cancel_transfer,
+ share_force_change_locked_account,
share_force_lock,
share_force_unlock,
share_issue_from,
@@ -483,6 +485,7 @@ async def test_normal_1(
# - ForceLock
# - Unlock
# - ForceUnlock
+ # - ForceChangeLockAccount
async def test_normal_2(
self,
processor: Processor,
@@ -568,17 +571,17 @@ async def test_normal_2(
)
# user1: 13000 trader: 17000
- bond_lock(self.trader, token, self.issuer["account_address"], 1500)
- # user1: 13000 trader: (hold: 15500, locked: 1500)
+ bond_lock(self.trader, token, self.issuer["account_address"], 2000)
+ # user1: 13000 trader: (hold: 15000, locked: 2000)
bond_force_lock(
self.issuer,
token,
self.issuer["account_address"],
self.trader["account_address"],
- 1500,
+ 2000,
)
- # user1: 13000 trader: (hold: 14000, locked: 3000)
+ # user1: 13000 trader: (hold: 13000, locked: 4000)
bond_unlock(
self.issuer,
@@ -587,7 +590,7 @@ async def test_normal_2(
self.user1["account_address"],
1000,
)
- # user1: 15000 trader: (hold: 14000, locked: 2000)
+ # user1: 14000 trader: (hold: 13000, locked: 3000)
bond_force_unlock(
self.issuer,
@@ -597,7 +600,19 @@ async def test_normal_2(
self.user1["account_address"],
1000,
)
- # user1: 15000 trader: (hold: 14000, locked: 1000)
+ # user1: 15000 trader: (hold: 13000, locked: 2000)
+
+ bond_force_change_locked_account(
+ self.issuer,
+ token,
+ self.issuer["account_address"],
+ self.trader["account_address"],
+ self.user1["account_address"],
+ 1000,
+ "force_unlock",
+ )
+ # user1: (hold: 15000, locked: 1000)
+ # trader: (hold: 13000, locked: 1000)
# Insert collection record with above token and current block number
target_token_holders_list = self.token_holders_list(
@@ -647,8 +662,8 @@ async def test_normal_2(
)
).first()
assert user1_record.hold_balance == 15000
- assert user1_record.locked_balance == 0
- assert trader_record.hold_balance == 14000
+ assert user1_record.locked_balance == 1000
+ assert trader_record.hold_balance == 13000
assert trader_record.locked_balance == 1000
assert (
@@ -1020,6 +1035,7 @@ async def test_normal_4(
# - ForceLock
# - Unlock
# - ForceUnlock
+ # - ForceChangeLockAccount
async def test_normal_5(
self,
processor: Processor,
@@ -1105,17 +1121,17 @@ async def test_normal_5(
)
# user1: 13000 trader: 17000
- share_lock(self.trader, token, self.issuer["account_address"], 1500)
- # user1: 13000 trader: (hold: 15500, locked: 1500)
+ share_lock(self.trader, token, self.issuer["account_address"], 2000)
+ # user1: 13000 trader: (hold: 15500, locked: 2000)
share_force_lock(
self.issuer,
token,
self.issuer["account_address"],
self.trader["account_address"],
- 1500,
+ 2000,
)
- # user1: 13000 trader: (hold: 14000, locked: 3000)
+ # user1: 13000 trader: (hold: 13000, locked: 4000)
share_unlock(
self.issuer,
@@ -1124,7 +1140,7 @@ async def test_normal_5(
self.user1["account_address"],
1000,
)
- # user1: 15000 trader: (hold: 14000, locked: 2000)
+ # user1: 14000 trader: (hold: 13000, locked: 3000)
share_force_unlock(
self.issuer,
@@ -1134,7 +1150,19 @@ async def test_normal_5(
self.user1["account_address"],
1000,
)
- # user1: 15000 trader: (hold: 14000, locked: 1000)
+ # user1: 15000 trader: (hold: 13000, locked: 2000)
+
+ share_force_change_locked_account(
+ self.issuer,
+ token,
+ self.issuer["account_address"],
+ self.trader["account_address"],
+ self.user1["account_address"],
+ 1000,
+ "force_unlock",
+ )
+ # user1: (hold: 15000, locked: 1000)
+ # trader: (hold: 13000, locked: 1000)
# Insert collection record with above token and current block number
target_token_holders_list = self.token_holders_list(
@@ -1184,8 +1212,8 @@ async def test_normal_5(
)
).first()
assert user1_record.hold_balance == 15000
- assert user1_record.locked_balance == 0
- assert trader_record.hold_balance == 14000
+ assert user1_record.locked_balance == 1000
+ assert trader_record.hold_balance == 13000
assert trader_record.locked_balance == 1000
assert (
diff --git a/tests/batch/indexer_Transfer_test.py b/tests/batch/indexer_Transfer_test.py
index 60c3f33c3..e825907a9 100644
--- a/tests/batch/indexer_Transfer_test.py
+++ b/tests/batch/indexer_Transfer_test.py
@@ -28,7 +28,7 @@
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.ext.asyncio import AsyncSession
from web3 import Web3
-from web3.exceptions import ABIEventNotFound
+from web3.exceptions import ABIEventNotFound, TransactionNotFound
from web3.middleware import ExtraDataToPOAMiddleware
from web3.types import RPCEndpoint
@@ -50,8 +50,10 @@
issue_share_token,
membership_issue,
membership_register_list,
+ reallocate_share_token,
register_bond_list,
register_share_list,
+ share_force_change_locked_account,
share_force_unlock,
share_lock,
share_unlock,
@@ -232,7 +234,12 @@ async def listing_token(token_address, async_session):
# - Transfer
# - Unlock
# - ForceUnlock
- async def test_normal_1_1(self, processor, shared_contract, async_session):
+ # - ForceChangeLockedAccount
+ # - Reallocation
+ @pytest.mark.parametrize("is_old_token", [False, True])
+ async def test_normal_1_1(
+ self, processor, shared_contract, async_session, is_old_token
+ ):
# Issue Token
token_list_contract = shared_contract["TokenList"]
personal_info_contract_address = shared_contract["PersonalInfo"]["address"]
@@ -248,6 +255,11 @@ async def test_normal_1_1(self, processor, shared_contract, async_session):
personal_info_contract_address,
self.issuer["account_address"],
)
+ PersonalInfoUtils.register(
+ self.trader2["account_address"],
+ personal_info_contract_address,
+ self.issuer["account_address"],
+ )
# emit "Transfer"
transfer_share_token(
@@ -264,13 +276,13 @@ async def test_normal_1_1(self, processor, shared_contract, async_session):
share_lock(
invoker=self.trader,
token=share_token,
- lock_address=self.trader2["account_address"],
+ lock_address=self.issuer["account_address"],
amount=50000,
data_str=json.dumps({"message": "garnishment"}),
)
share_unlock(
- invoker=self.trader2,
+ invoker=self.issuer,
token=share_token,
target=self.trader["account_address"],
recipient=self.trader2["account_address"],
@@ -284,26 +296,52 @@ async def test_normal_1_1(self, processor, shared_contract, async_session):
share_force_unlock(
invoker=self.issuer,
token=share_token,
- lock_address=self.trader2["account_address"],
+ lock_address=self.issuer["account_address"],
target=self.trader["account_address"],
recipient=self.trader2["account_address"],
- amount=20000,
+ amount=10000,
data_str=json.dumps(
{"invalid_message": "invalid_value"}
), # invalid message format
)
block_number_3 = web3.eth.block_number
+ # emit "ForceChangeLockedAccount"
+ share_force_change_locked_account(
+ invoker=self.issuer,
+ token=share_token,
+ lock_address=self.issuer["account_address"],
+ before_account_address=self.trader["account_address"],
+ after_account_address=self.trader2["account_address"],
+ amount=10000,
+ data_str="",
+ )
+ block_number_4 = web3.eth.block_number
+
+ # emit "Reallocation"
+ reallocate_share_token(
+ invoker=self.trader,
+ to=self.trader2,
+ token=share_token,
+ amount=10000,
+ )
+ block_number_5 = web3.eth.block_number
+
# Execute batch processing
- await processor.sync_new_logs()
+ if is_old_token:
+ with mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_transaction",
+ MagicMock(side_effect=TransactionNotFound(message="")),
+ ):
+ await processor.sync_new_logs()
+ else:
+ await processor.sync_new_logs()
# Assertion
idx_transfer_list = (
- await async_session.scalars(
- select(IDXTransfer).order_by(IDXTransfer.created)
- )
+ await async_session.scalars(select(IDXTransfer).order_by(IDXTransfer.id))
).all()
- assert len(idx_transfer_list) == 3
+ assert len(idx_transfer_list) == 5
block1 = web3.eth.get_block(block_number_1)
idx_transfer: IDXTransfer = idx_transfer_list[0]
@@ -318,9 +356,23 @@ async def test_normal_1_1(self, processor, shared_contract, async_session):
assert idx_transfer.created is not None
assert idx_transfer.modified is not None
- block2 = web3.eth.get_block(block_number_2)
+ block5 = web3.eth.get_block(block_number_5)
idx_transfer: IDXTransfer = idx_transfer_list[1]
assert idx_transfer.id == 2
+ assert idx_transfer.transaction_hash == block5["transactions"][0].to_0x_hex()
+ assert idx_transfer.token_address == share_token["address"]
+ assert idx_transfer.from_address == self.trader["account_address"]
+ assert idx_transfer.to_address == self.trader2["account_address"]
+ assert idx_transfer.value == 10000
+ assert idx_transfer.source_event == IDXTransferSourceEventType.REALLOCATION
+ assert idx_transfer.data is None
+ assert idx_transfer.message is None
+ assert idx_transfer.created is not None
+ assert idx_transfer.modified is not None
+
+ block2 = web3.eth.get_block(block_number_2)
+ idx_transfer: IDXTransfer = idx_transfer_list[2]
+ assert idx_transfer.id == 3
assert idx_transfer.transaction_hash == block2["transactions"][0].to_0x_hex()
assert idx_transfer.token_address == share_token["address"]
assert idx_transfer.from_address == self.trader["account_address"]
@@ -333,19 +385,36 @@ async def test_normal_1_1(self, processor, shared_contract, async_session):
assert idx_transfer.modified is not None
block3 = web3.eth.get_block(block_number_3)
- idx_transfer: IDXTransfer = idx_transfer_list[2]
- assert idx_transfer.id == 3
+ idx_transfer: IDXTransfer = idx_transfer_list[3]
+ assert idx_transfer.id == 4
assert idx_transfer.transaction_hash == block3["transactions"][0].to_0x_hex()
assert idx_transfer.token_address == share_token["address"]
assert idx_transfer.from_address == self.trader["account_address"]
assert idx_transfer.to_address == self.trader2["account_address"]
- assert idx_transfer.value == 20000
+ assert idx_transfer.value == 10000
assert idx_transfer.source_event == IDXTransferSourceEventType.FORCE_UNLOCK
assert idx_transfer.data == {}
assert idx_transfer.message is None
assert idx_transfer.created is not None
assert idx_transfer.modified is not None
+ block4 = web3.eth.get_block(block_number_4)
+ idx_transfer: IDXTransfer = idx_transfer_list[4]
+ assert idx_transfer.id == 5
+ assert idx_transfer.transaction_hash == block4["transactions"][0].to_0x_hex()
+ assert idx_transfer.token_address == share_token["address"]
+ assert idx_transfer.from_address == self.trader["account_address"]
+ assert idx_transfer.to_address == self.trader2["account_address"]
+ assert idx_transfer.value == 10000
+ assert (
+ idx_transfer.source_event
+ == IDXTransferSourceEventType.FORCE_CHANGE_LOCKED_ACCOUNT
+ )
+ assert idx_transfer.data == {}
+ assert idx_transfer.message is None
+ assert idx_transfer.created is not None
+ assert idx_transfer.modified is not None
+
idx_block_number: IDXTransferBlockNumber = (
await async_session.scalars(
select(IDXTransferBlockNumber)
@@ -356,7 +425,7 @@ async def test_normal_1_1(self, processor, shared_contract, async_session):
.limit(1)
)
).first()
- assert idx_block_number.latest_block_number == block_number_3
+ assert idx_block_number.latest_block_number == block_number_5
#
# IbetShare
@@ -452,6 +521,7 @@ async def test_normal_1_2(self, processor, shared_contract, async_session):
# - Transfer(twice)
# - Unlock(twice)
# - ForceUnlock(twice)
+ # - ForceChangeLockedAccount(twice)
async def test_normal_2(self, processor, shared_contract, async_session):
# Issue Token
token_list_contract = shared_contract["TokenList"]
@@ -493,16 +563,16 @@ async def test_normal_2(self, processor, shared_contract, async_session):
)
block_number_2 = web3.eth.block_number
- # emit "Unlock"/"ForceUnlock"
+ # emit "Unlock"/"ForceUnlock"/"ForceChangeLockedAccount"
share_lock(
invoker=self.trader,
token=share_token,
- lock_address=self.trader2["account_address"],
+ lock_address=self.issuer["account_address"],
amount=100000,
data_str=json.dumps({"message": "garnishment"}),
)
share_unlock(
- invoker=self.trader2,
+ invoker=self.issuer,
token=share_token,
target=self.trader["account_address"],
recipient=self.trader2["account_address"],
@@ -511,7 +581,7 @@ async def test_normal_2(self, processor, shared_contract, async_session):
)
block_number_3 = web3.eth.block_number
share_unlock(
- invoker=self.trader2,
+ invoker=self.issuer,
token=share_token,
target=self.trader["account_address"],
recipient=self.trader2["account_address"],
@@ -522,23 +592,43 @@ async def test_normal_2(self, processor, shared_contract, async_session):
share_force_unlock(
invoker=self.issuer,
token=share_token,
- lock_address=self.trader2["account_address"],
+ lock_address=self.issuer["account_address"],
target=self.trader["account_address"],
recipient=self.trader2["account_address"],
- amount=20000,
+ amount=10000,
data_str=json.dumps({"message": "force_unlock"}),
)
block_number_5 = web3.eth.block_number
share_force_unlock(
invoker=self.issuer,
token=share_token,
- lock_address=self.trader2["account_address"],
+ lock_address=self.issuer["account_address"],
target=self.trader["account_address"],
recipient=self.trader2["account_address"],
- amount=20000,
- data_str=json.dumps({"message": "force_unlock"}),
+ amount=10000,
+ data_str=json.dumps({"message": "ibet_wst_bridge"}),
)
block_number_6 = web3.eth.block_number
+ share_force_change_locked_account(
+ invoker=self.issuer,
+ token=share_token,
+ lock_address=self.issuer["account_address"],
+ before_account_address=self.trader["account_address"],
+ after_account_address=self.trader2["account_address"],
+ amount=10000,
+ data_str=json.dumps({"message": "ibet_wst_bridge"}),
+ )
+ block_number_7 = web3.eth.block_number
+ share_force_change_locked_account(
+ invoker=self.issuer,
+ token=share_token,
+ lock_address=self.issuer["account_address"],
+ before_account_address=self.trader["account_address"],
+ after_account_address=self.trader2["account_address"],
+ amount=10000,
+ data_str=json.dumps({"message": "ibet_wst_bridge"}),
+ )
+ block_number_8 = web3.eth.block_number
# Execute batch processing
await processor.sync_new_logs()
@@ -549,7 +639,7 @@ async def test_normal_2(self, processor, shared_contract, async_session):
select(IDXTransfer).order_by(IDXTransfer.created)
)
).all()
- assert len(idx_transfer_list) == 6
+ assert len(idx_transfer_list) == 8
block = web3.eth.get_block(block_number_1)
idx_transfer = idx_transfer_list[0]
@@ -586,8 +676,8 @@ async def test_normal_2(self, processor, shared_contract, async_session):
assert idx_transfer.to_address == self.trader2["account_address"]
assert idx_transfer.value == 30000
assert idx_transfer.source_event == IDXTransferSourceEventType.UNLOCK
- assert idx_transfer.data == {"message": "inheritance"}
- assert idx_transfer.message == "inheritance"
+ assert idx_transfer.data == {}
+ assert idx_transfer.message is None
assert idx_transfer.created is not None
assert idx_transfer.modified is not None
@@ -600,8 +690,8 @@ async def test_normal_2(self, processor, shared_contract, async_session):
assert idx_transfer.to_address == self.trader2["account_address"]
assert idx_transfer.value == 30000
assert idx_transfer.source_event == IDXTransferSourceEventType.UNLOCK
- assert idx_transfer.data == {"message": "inheritance"}
- assert idx_transfer.message == "inheritance"
+ assert idx_transfer.data == {}
+ assert idx_transfer.message is None
assert idx_transfer.created is not None
assert idx_transfer.modified is not None
@@ -612,7 +702,7 @@ async def test_normal_2(self, processor, shared_contract, async_session):
assert idx_transfer.token_address == share_token["address"]
assert idx_transfer.from_address == self.trader["account_address"]
assert idx_transfer.to_address == self.trader2["account_address"]
- assert idx_transfer.value == 20000
+ assert idx_transfer.value == 10000
assert idx_transfer.source_event == IDXTransferSourceEventType.FORCE_UNLOCK
assert idx_transfer.data == {"message": "force_unlock"}
assert idx_transfer.message == "force_unlock"
@@ -626,10 +716,44 @@ async def test_normal_2(self, processor, shared_contract, async_session):
assert idx_transfer.token_address == share_token["address"]
assert idx_transfer.from_address == self.trader["account_address"]
assert idx_transfer.to_address == self.trader2["account_address"]
- assert idx_transfer.value == 20000
+ assert idx_transfer.value == 10000
assert idx_transfer.source_event == IDXTransferSourceEventType.FORCE_UNLOCK
- assert idx_transfer.data == {"message": "force_unlock"}
- assert idx_transfer.message == "force_unlock"
+ assert idx_transfer.data == {"message": "ibet_wst_bridge"}
+ assert idx_transfer.message == "ibet_wst_bridge"
+ assert idx_transfer.created is not None
+ assert idx_transfer.modified is not None
+
+ block = web3.eth.get_block(block_number_7)
+ idx_transfer = idx_transfer_list[6]
+ assert idx_transfer.id == 7
+ assert idx_transfer.transaction_hash == block["transactions"][0].to_0x_hex()
+ assert idx_transfer.token_address == share_token["address"]
+ assert idx_transfer.from_address == self.trader["account_address"]
+ assert idx_transfer.to_address == self.trader2["account_address"]
+ assert idx_transfer.value == 10000
+ assert (
+ idx_transfer.source_event
+ == IDXTransferSourceEventType.FORCE_CHANGE_LOCKED_ACCOUNT
+ )
+ assert idx_transfer.data == {"message": "ibet_wst_bridge"}
+ assert idx_transfer.message == "ibet_wst_bridge"
+ assert idx_transfer.created is not None
+ assert idx_transfer.modified is not None
+
+ block = web3.eth.get_block(block_number_8)
+ idx_transfer = idx_transfer_list[7]
+ assert idx_transfer.id == 8
+ assert idx_transfer.transaction_hash == block["transactions"][0].to_0x_hex()
+ assert idx_transfer.token_address == share_token["address"]
+ assert idx_transfer.from_address == self.trader["account_address"]
+ assert idx_transfer.to_address == self.trader2["account_address"]
+ assert idx_transfer.value == 10000
+ assert (
+ idx_transfer.source_event
+ == IDXTransferSourceEventType.FORCE_CHANGE_LOCKED_ACCOUNT
+ )
+ assert idx_transfer.data == {"message": "ibet_wst_bridge"}
+ assert idx_transfer.message == "ibet_wst_bridge"
assert idx_transfer.created is not None
assert idx_transfer.modified is not None
@@ -642,7 +766,7 @@ async def test_normal_2(self, processor, shared_contract, async_session):
.limit(1)
)
).first()
- assert idx_block_number.latest_block_number == block_number_6
+ assert idx_block_number.latest_block_number == block_number_8
#
# IbetStraightBond, IbetMembership, IbetCoupon
@@ -870,7 +994,7 @@ async def test_normal_4_1(self, processor, shared_contract, async_session, caplo
).first()
assert idx_block_number.latest_block_number == block_number_1
- assert 3 == caplog.record_tuples.count(
+ assert 4 == caplog.record_tuples.count(
(
LOG.name,
logging.DEBUG,
@@ -976,7 +1100,7 @@ async def test_normal_4_2(self, processor, shared_contract, async_session, caplo
).first()
assert idx_block_number.latest_block_number == block_number_2
- assert 3 == caplog.record_tuples.count(
+ assert 4 == caplog.record_tuples.count(
(
LOG.name,
logging.DEBUG,
@@ -1089,7 +1213,7 @@ async def test_normal_4_3(self, processor, shared_contract, async_session, caplo
).first()
assert idx_block_number.latest_block_number == block_number_2
- assert 3 == caplog.record_tuples.count(
+ assert 4 == caplog.record_tuples.count(
(
LOG.name,
logging.DEBUG,
@@ -1220,7 +1344,7 @@ async def test_normal_4_5(self, processor, shared_contract, async_session, caplo
).first()
assert idx_block_number.latest_block_number == block_number
- assert 3 == caplog.record_tuples.count(
+ assert 4 == caplog.record_tuples.count(
(
LOG.name,
logging.DEBUG,
diff --git a/tests/batch/processor_Notifications_Coupon_Exchange_test.py b/tests/batch/processor_Notifications_Coupon_Exchange_test.py
index 3614d3de2..3a0d0fdd5 100644
--- a/tests/batch/processor_Notifications_Coupon_Exchange_test.py
+++ b/tests/batch/processor_Notifications_Coupon_Exchange_test.py
@@ -133,6 +133,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 0
)
@@ -212,6 +213,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 0
)
@@ -237,6 +239,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 0
)
@@ -383,6 +386,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 0
)
@@ -461,6 +465,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 1, 0
)
@@ -486,6 +491,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 0
)
@@ -657,6 +663,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 0
)
@@ -763,6 +770,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 1, 0
)
@@ -790,6 +798,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 0
)
@@ -961,6 +970,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 1
)
@@ -1041,6 +1051,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 1
)
@@ -1067,6 +1078,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 1
)
@@ -1226,6 +1238,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 2
)
@@ -1304,6 +1317,7 @@ async def test_normal_2(
).all()
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 2
)
@@ -1329,6 +1343,7 @@ async def test_normal_2(
"token_type": "IbetCoupon",
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 2
)
@@ -1493,6 +1508,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 1
)
@@ -1581,6 +1597,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 1, 1
)
@@ -1609,6 +1626,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 1
)
@@ -1780,6 +1798,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 2
)
@@ -1868,6 +1887,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 1, 2
)
@@ -1896,6 +1916,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 2
)
@@ -2067,6 +2088,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 1
)
@@ -2155,6 +2177,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 1
)
@@ -2183,6 +2206,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 1
)
@@ -2354,6 +2378,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 2
)
@@ -2442,6 +2467,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 2
)
@@ -2470,6 +2496,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 2
)
diff --git a/tests/batch/processor_Notifications_Membership_Exchange_test.py b/tests/batch/processor_Notifications_Membership_Exchange_test.py
index 4b6e87a40..4e934ac55 100644
--- a/tests/batch/processor_Notifications_Membership_Exchange_test.py
+++ b/tests/batch/processor_Notifications_Membership_Exchange_test.py
@@ -133,6 +133,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 0
)
@@ -204,6 +205,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 0
)
@@ -229,6 +231,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 0
)
@@ -374,6 +377,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 0
)
@@ -451,6 +455,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 1, 0
)
@@ -476,6 +481,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 0
)
@@ -646,6 +652,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 0
)
@@ -752,6 +759,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 1, 0
)
@@ -779,6 +787,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 0
)
@@ -948,6 +957,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 1
)
@@ -1027,6 +1037,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 1
)
@@ -1053,6 +1064,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 1
)
@@ -1210,6 +1222,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 2
)
@@ -1289,6 +1302,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 2
)
@@ -1315,6 +1329,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 2
)
@@ -1475,6 +1490,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 1
)
@@ -1560,6 +1576,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 1, 1
)
@@ -1588,6 +1605,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 1
)
@@ -1753,6 +1771,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 2
)
@@ -1838,6 +1857,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 1, 2
)
@@ -1866,6 +1886,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 1, 2
)
@@ -2031,6 +2052,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 1
)
@@ -2116,6 +2138,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 1
)
@@ -2144,6 +2167,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 1
)
@@ -2309,6 +2333,7 @@ async def test_normal_1(
select(Notification).order_by(Notification.created).limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 2
)
@@ -2394,6 +2419,7 @@ async def test_normal_2(
assert len(_notification_list) == 2
_notification = _notification_list[0]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number - 1, 0, 0, 2
)
@@ -2422,6 +2448,7 @@ async def test_normal_2(
}
_notification = _notification_list[1]
+ assert _notification.notification_category == "event_log"
assert _notification.notification_id == "0x{:012x}{:06x}{:06x}{:02x}".format(
block_number, 0, 0, 2
)
diff --git a/tests/batch/processor_Notifications_Token_test.py b/tests/batch/processor_Notifications_Token_test.py
index daab5aab3..0342a5cce 100644
--- a/tests/batch/processor_Notifications_Token_test.py
+++ b/tests/batch/processor_Notifications_Token_test.py
@@ -19,6 +19,7 @@
from __future__ import annotations
+from datetime import datetime, timezone
from importlib import reload
from typing import TYPE_CHECKING, Callable
from unittest import mock
@@ -33,34 +34,41 @@
from app import config
from app.model.db import (
+ IDXShareToken,
IDXTokenListRegister,
Listing,
Notification,
+ NotificationAttributeValue,
NotificationBlockNumber,
NotificationType,
)
from tests.account_config import eth_account
from tests.conftest import DeployedContract, SharedContract, UnitTestAccount
from tests.contract_modules import (
+ bond_change_to_redeemed,
coupon_register_list,
coupon_transfer_to_exchange,
coupon_withdraw_from_exchange,
+ issue_bond_token,
issue_coupon_token,
issue_share_token,
+ register_bond_list,
register_personalinfo,
register_share_list,
share_apply_for_transfer,
share_approve_transfer,
share_cancel_transfer,
+ share_change_to_canceled,
share_force_lock,
share_force_unlock,
share_set_transfer_approval_required,
transfer_coupon_token,
transfer_share_token,
+ untransferable_share_token,
)
if TYPE_CHECKING:
- from batch.processor_Notifications_Token import Watcher
+ from batch.processor_Notifications_Token import EventWatcher
web3 = Web3(Web3.HTTPProvider(config.WEB3_HTTP_PROVIDER))
web3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
@@ -69,7 +77,7 @@
@pytest.fixture(scope="function")
def watcher_factory(
async_session: AsyncSession, shared_contract: SharedContract
-) -> Callable[[str], Watcher]:
+) -> Callable[[str], EventWatcher]:
def _watcher(cls_name):
config.TOKEN_LIST_CONTRACT_ADDRESS = shared_contract["TokenList"]["address"]
@@ -121,6 +129,64 @@ async def prepare_coupon_token(
return token
+async def prepare_bond_token(
+ issuer: UnitTestAccount,
+ exchange: DeployedContract,
+ token_list: DeployedContract,
+ personal_info: DeployedContract,
+ async_session: AsyncSession,
+):
+ # Issue token
+ args = {
+ "name": "テスト債券",
+ "symbol": "BOND",
+ "totalSupply": 1000000,
+ "tradableExchange": exchange["address"],
+ "faceValue": 10000,
+ "interestRate": 602,
+ "interestPaymentDate1": "0101",
+ "interestPaymentDate2": "0201",
+ "interestPaymentDate3": "0301",
+ "interestPaymentDate4": "0401",
+ "interestPaymentDate5": "0501",
+ "interestPaymentDate6": "0601",
+ "interestPaymentDate7": "0701",
+ "interestPaymentDate8": "0801",
+ "interestPaymentDate9": "0901",
+ "interestPaymentDate10": "1001",
+ "interestPaymentDate11": "1101",
+ "interestPaymentDate12": "1201",
+ "redemptionDate": "20191231",
+ "redemptionValue": 10000,
+ "returnDate": "20191231",
+ "returnAmount": "商品券をプレゼント",
+ "purpose": "新商品の開発資金として利用。",
+ "memo": "メモ",
+ "contactInformation": "問い合わせ先",
+ "privacyPolicy": "プライバシーポリシー",
+ "personalInfoAddress": personal_info["address"],
+ "transferable": True,
+ "isRedeemed": False,
+ "faceValueCurrency": "JPY",
+ "interestPaymentCurrency": "JPY",
+ "redemptionValueCurrency": "JPY",
+ "baseFxRate": "",
+ }
+ token = issue_bond_token(issuer, args)
+ register_bond_list(issuer, token, token_list)
+
+ _listing = Listing()
+ _listing.token_address = token["address"]
+ _listing.is_public = True
+ _listing.max_holding_quantity = 1000000
+ _listing.max_sell_amount = 1000000
+ _listing.owner_address = issuer["account_address"]
+ async_session.add(_listing)
+ await async_session.commit()
+
+ return token
+
+
async def prepare_share_token(
issuer: UnitTestAccount,
exchange: DeployedContract,
@@ -212,6 +278,7 @@ async def test_normal_1(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -293,6 +360,7 @@ async def test_normal_2(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -320,6 +388,7 @@ async def test_normal_2(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader2["account_address"]
@@ -454,6 +523,7 @@ async def test_normal_4(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.TRANSFER
assert _notification.priority == 0
assert _notification.address == exchange_contract["address"]
@@ -682,6 +752,7 @@ async def test_normal_2(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.APPLY_FOR_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader2["account_address"]
@@ -711,6 +782,7 @@ async def test_normal_2(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.APPLY_FOR_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader2["account_address"]
@@ -918,6 +990,7 @@ async def test_normal_1(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.APPROVE_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1011,6 +1084,7 @@ async def test_normal_2(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.APPROVE_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1039,6 +1113,7 @@ async def test_normal_2(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.APPROVE_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1246,6 +1321,7 @@ async def test_normal_1(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.CANCEL_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1339,6 +1415,7 @@ async def test_normal_2(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.CANCEL_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1367,6 +1444,7 @@ async def test_normal_2(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.CANCEL_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1484,6 +1562,7 @@ async def test_normal_3(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.CANCEL_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1512,6 +1591,7 @@ async def test_normal_3(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.CANCEL_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1540,6 +1620,7 @@ async def test_normal_3(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.CANCEL_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1568,6 +1649,7 @@ async def test_normal_3(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.CANCEL_TRANSFER
assert _notification.priority == 0
assert _notification.address == self.trader["account_address"]
@@ -1774,6 +1856,7 @@ async def test_normal_1(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.FORCE_LOCK
assert _notification.priority == 0
assert _notification.address == self.issuer["account_address"]
@@ -2038,6 +2121,7 @@ async def test_normal_1(
.limit(1)
)
).first()
+ assert _notification.notification_category == "event_log"
assert _notification.notification_type == NotificationType.FORCE_UNLOCK
assert _notification.priority == 0
assert _notification.address == self.issuer["account_address"]
@@ -2241,3 +2325,1156 @@ async def test_error_1(
await async_session.scalars(select(NotificationBlockNumber).limit(1))
).first()
assert _notification_block_number is None
+
+
+@pytest.mark.asyncio
+class TestWatchChangeToRedeemed:
+ issuer = eth_account["issuer"]
+
+ ###########################################################################
+ # Normal Case
+ ###########################################################################
+
+ #
+ # Initial Sync
+ async def test_normal_1(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToRedeemed")
+ exchange_contract = shared_contract["IbetStraightBondExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_bond_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetStraightBond"
+ async_session.add(idx_token_list_item)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ _notification = (
+ await async_session.scalars(
+ select(Notification)
+ .where(
+ Notification.notification_id
+ == "0x{:012x}{:06x}{:06x}{:02x}".format(block_number, 0, 0, 0)
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification is None
+
+ _notification_block_number: NotificationBlockNumber = (
+ await async_session.scalars(
+ select(NotificationBlockNumber)
+ .where(
+ and_(
+ NotificationBlockNumber.notification_type
+ == NotificationType.CHANGE_TO_REDEEMED,
+ NotificationBlockNumber.contract_address == token["address"],
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ #
+ # Single event logs
+ async def test_normal_2(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToRedeemed")
+ exchange_contract = shared_contract["IbetStraightBondExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_bond_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetStraightBond"
+ async_session.add(idx_token_list_item)
+
+ notification_block_number = NotificationBlockNumber()
+ notification_block_number.notification_type = (
+ NotificationType.CHANGE_TO_REDEEMED
+ )
+ notification_block_number.contract_address = token["address"]
+ notification_block_number.latest_block_number = web3.eth.block_number
+ async_session.add(notification_block_number)
+ await async_session.commit()
+
+ # Emit ChangeToRedeemed event
+ bond_change_to_redeemed(
+ invoker=self.issuer,
+ token=token,
+ )
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ async_session.expunge_all()
+
+ _notification_list = (await async_session.scalars(select(Notification))).all()
+ assert len(_notification_list) == 1
+ assert _notification_list[0].notification_category == "event_log"
+ assert (
+ _notification_list[0].notification_type
+ == NotificationType.CHANGE_TO_REDEEMED
+ )
+ assert _notification_list[0].priority == 0
+ assert _notification_list[0].address is None
+ assert _notification_list[0].args == {}
+ assert _notification_list[0].metainfo == {
+ "company_name": "株式会社DEMO",
+ "exchange_address": "",
+ "token_address": token["address"],
+ "token_name": "テスト債券",
+ "token_type": "IbetStraightBond",
+ }
+
+ _notification_block_number: NotificationBlockNumber = (
+ await async_session.scalars(
+ select(NotificationBlockNumber)
+ .where(
+ and_(
+ NotificationBlockNumber.notification_type
+ == NotificationType.CHANGE_TO_REDEEMED,
+ NotificationBlockNumber.contract_address == token["address"],
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ #
+ # Multi event logs
+ async def test_normal_3(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToRedeemed")
+ exchange_contract = shared_contract["IbetStraightBondExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_bond_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetStraightBond"
+ async_session.add(idx_token_list_item)
+
+ notification_block_number = NotificationBlockNumber()
+ notification_block_number.notification_type = (
+ NotificationType.CHANGE_TO_REDEEMED
+ )
+ notification_block_number.contract_address = token["address"]
+ notification_block_number.latest_block_number = web3.eth.block_number
+ async_session.add(notification_block_number)
+ await async_session.commit()
+
+ # Emit ChangeToRedeemed event
+ bond_change_to_redeemed(
+ invoker=self.issuer,
+ token=token,
+ )
+ bond_change_to_redeemed(
+ invoker=self.issuer,
+ token=token,
+ )
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ async_session.expunge_all()
+
+ _notification_list = (await async_session.scalars(select(Notification))).all()
+ assert len(_notification_list) == 2
+ assert _notification_list[0].notification_category == "event_log"
+ assert (
+ _notification_list[0].notification_type
+ == NotificationType.CHANGE_TO_REDEEMED
+ )
+ assert _notification_list[0].priority == 0
+ assert _notification_list[0].address is None
+ assert _notification_list[0].args == {}
+ assert _notification_list[0].metainfo == {
+ "company_name": "株式会社DEMO",
+ "exchange_address": "",
+ "token_address": token["address"],
+ "token_name": "テスト債券",
+ "token_type": "IbetStraightBond",
+ }
+ assert _notification_list[1].notification_category == "event_log"
+ assert (
+ _notification_list[1].notification_type
+ == NotificationType.CHANGE_TO_REDEEMED
+ )
+ assert _notification_list[1].priority == 0
+ assert _notification_list[1].address is None
+ assert _notification_list[1].args == {}
+ assert _notification_list[1].metainfo == {
+ "company_name": "株式会社DEMO",
+ "exchange_address": "",
+ "token_address": token["address"],
+ "token_name": "テスト債券",
+ "token_type": "IbetStraightBond",
+ }
+
+ _notification_block_number: NotificationBlockNumber = (
+ await async_session.scalars(
+ select(NotificationBlockNumber)
+ .where(
+ and_(
+ NotificationBlockNumber.notification_type
+ == NotificationType.CHANGE_TO_REDEEMED,
+ NotificationBlockNumber.contract_address == token["address"],
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ #
+ # No event logs
+ async def test_normal_4(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToRedeemed")
+ exchange_contract = shared_contract["IbetStraightBondExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_bond_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetStraightBond"
+ async_session.add(idx_token_list_item)
+
+ notification_block_number = NotificationBlockNumber()
+ notification_block_number.notification_type = (
+ NotificationType.CHANGE_TO_REDEEMED
+ )
+ notification_block_number.contract_address = token["address"]
+ notification_block_number.latest_block_number = web3.eth.block_number
+ async_session.add(notification_block_number)
+ await async_session.commit()
+
+ # Not emit ChangeToRedeemed event
+ pass
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ _notification_list = (await async_session.scalars(select(Notification))).all()
+ assert len(_notification_list) == 0
+
+ _notification_block_number = (
+ await async_session.scalars(select(NotificationBlockNumber).limit(1))
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ #
+ # Skip past data on initial sync
+ async def test_normal_5(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToRedeemed")
+ exchange_contract = shared_contract["IbetStraightBondExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_bond_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetStraightBond"
+ async_session.add(idx_token_list_item)
+ await async_session.commit()
+
+ # Emit ChangeToRedeemed event
+ bond_change_to_redeemed(
+ invoker=self.issuer,
+ token=token,
+ )
+ web3.provider.make_request(RPCEndpoint("evm_mine"), [])
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ _notification_list = (await async_session.scalars(select(Notification))).all()
+ assert len(_notification_list) == 0
+
+ _notification_block_number = (
+ await async_session.scalars(select(NotificationBlockNumber).limit(1))
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ # ###########################################################################
+ # # Error Case
+ # ###########################################################################
+
+ #
+ # Error occur
+ @mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_logs",
+ MagicMock(side_effect=Exception()),
+ )
+ async def test_error_1(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToRedeemed")
+ exchange_contract = shared_contract["IbetStraightBondExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_bond_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetStraightBond"
+ async_session.add(idx_token_list_item)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ _notification = (
+ await async_session.scalars(
+ select(Notification).order_by(Notification.created).limit(1)
+ )
+ ).first()
+ assert _notification is None
+
+ _notification_block_number = (
+ await async_session.scalars(select(NotificationBlockNumber).limit(1))
+ ).first()
+ assert _notification_block_number is None
+
+
+@pytest.mark.asyncio
+class TestWatchChangeToCanceled:
+ issuer = eth_account["issuer"]
+
+ ###########################################################################
+ # Normal Case
+ ###########################################################################
+
+ #
+ # Initial Sync
+ async def test_normal_1(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToCanceled")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ _notification = (
+ await async_session.scalars(
+ select(Notification)
+ .where(
+ Notification.notification_id
+ == "0x{:012x}{:06x}{:06x}{:02x}".format(block_number, 0, 0, 0)
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification is None
+
+ _notification_block_number: NotificationBlockNumber = (
+ await async_session.scalars(
+ select(NotificationBlockNumber)
+ .where(
+ and_(
+ NotificationBlockNumber.notification_type
+ == NotificationType.CHANGE_TO_CANCELED,
+ NotificationBlockNumber.contract_address == token["address"],
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ #
+ # Single event logs
+ async def test_normal_2(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToCanceled")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+
+ notification_block_number = NotificationBlockNumber()
+ notification_block_number.notification_type = (
+ NotificationType.CHANGE_TO_CANCELED
+ )
+ notification_block_number.contract_address = token["address"]
+ notification_block_number.latest_block_number = web3.eth.block_number
+ async_session.add(notification_block_number)
+ await async_session.commit()
+
+ # Emit ChangeToCanceled event
+ share_change_to_canceled(
+ invoker=self.issuer,
+ token=token,
+ )
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ async_session.expunge_all()
+
+ _notification_list = (await async_session.scalars(select(Notification))).all()
+ assert len(_notification_list) == 1
+ assert _notification_list[0].notification_category == "event_log"
+ assert (
+ _notification_list[0].notification_type
+ == NotificationType.CHANGE_TO_CANCELED
+ )
+ assert _notification_list[0].priority == 0
+ assert _notification_list[0].address is None
+ assert _notification_list[0].args == {}
+ assert _notification_list[0].metainfo == {
+ "company_name": "株式会社DEMO",
+ "exchange_address": "",
+ "token_address": token["address"],
+ "token_name": "テスト株式",
+ "token_type": "IbetShare",
+ }
+
+ _notification_block_number: NotificationBlockNumber = (
+ await async_session.scalars(
+ select(NotificationBlockNumber)
+ .where(
+ and_(
+ NotificationBlockNumber.notification_type
+ == NotificationType.CHANGE_TO_CANCELED,
+ NotificationBlockNumber.contract_address == token["address"],
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ #
+ # Multi event logs
+ async def test_normal_3(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToCanceled")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+
+ notification_block_number = NotificationBlockNumber()
+ notification_block_number.notification_type = (
+ NotificationType.CHANGE_TO_CANCELED
+ )
+ notification_block_number.contract_address = token["address"]
+ notification_block_number.latest_block_number = web3.eth.block_number
+ async_session.add(notification_block_number)
+ await async_session.commit()
+
+ # Emit ChangeToCanceled event
+ share_change_to_canceled(
+ invoker=self.issuer,
+ token=token,
+ )
+ share_change_to_canceled(
+ invoker=self.issuer,
+ token=token,
+ )
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ async_session.expunge_all()
+
+ _notification_list = (await async_session.scalars(select(Notification))).all()
+ assert len(_notification_list) == 2
+ assert _notification_list[0].notification_category == "event_log"
+ assert (
+ _notification_list[0].notification_type
+ == NotificationType.CHANGE_TO_CANCELED
+ )
+ assert _notification_list[0].priority == 0
+ assert _notification_list[0].address is None
+ assert _notification_list[0].args == {}
+ assert _notification_list[0].metainfo == {
+ "company_name": "株式会社DEMO",
+ "exchange_address": "",
+ "token_address": token["address"],
+ "token_name": "テスト株式",
+ "token_type": "IbetShare",
+ }
+ assert _notification_list[1].notification_category == "event_log"
+ assert (
+ _notification_list[1].notification_type
+ == NotificationType.CHANGE_TO_CANCELED
+ )
+ assert _notification_list[1].priority == 0
+ assert _notification_list[1].address is None
+ assert _notification_list[1].args == {}
+ assert _notification_list[1].metainfo == {
+ "company_name": "株式会社DEMO",
+ "exchange_address": "",
+ "token_address": token["address"],
+ "token_name": "テスト株式",
+ "token_type": "IbetShare",
+ }
+
+ _notification_block_number: NotificationBlockNumber = (
+ await async_session.scalars(
+ select(NotificationBlockNumber)
+ .where(
+ and_(
+ NotificationBlockNumber.notification_type
+ == NotificationType.CHANGE_TO_CANCELED,
+ NotificationBlockNumber.contract_address == token["address"],
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ #
+ # No event logs
+ async def test_normal_4(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToCanceled")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+
+ notification_block_number = NotificationBlockNumber()
+ notification_block_number.notification_type = (
+ NotificationType.CHANGE_TO_CANCELED
+ )
+ notification_block_number.contract_address = token["address"]
+ notification_block_number.latest_block_number = web3.eth.block_number
+ async_session.add(notification_block_number)
+ await async_session.commit()
+
+ # Not emit ChangeToCanceled event
+ pass
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ _notification_list = (await async_session.scalars(select(Notification))).all()
+ assert len(_notification_list) == 0
+
+ _notification_block_number = (
+ await async_session.scalars(select(NotificationBlockNumber).limit(1))
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ #
+ # Skip past data on initial sync
+ async def test_normal_5(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToCanceled")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+ await async_session.commit()
+
+ # Emit ChangeToCanceled event
+ share_change_to_canceled(
+ invoker=self.issuer,
+ token=token,
+ )
+ web3.provider.make_request(RPCEndpoint("evm_mine"), [])
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ block_number = web3.eth.block_number
+
+ _notification_list = (await async_session.scalars(select(Notification))).all()
+ assert len(_notification_list) == 0
+
+ _notification_block_number = (
+ await async_session.scalars(select(NotificationBlockNumber).limit(1))
+ ).first()
+ assert _notification_block_number.latest_block_number == block_number
+
+ # ###########################################################################
+ # # Error Case
+ # ###########################################################################
+
+ #
+ # Error occur
+ @mock.patch(
+ "web3.eth.async_eth.AsyncEth.get_logs",
+ MagicMock(side_effect=Exception()),
+ )
+ async def test_error_1(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchChangeToCanceled")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ _notification = (
+ await async_session.scalars(
+ select(Notification).order_by(Notification.created).limit(1)
+ )
+ ).first()
+ assert _notification is None
+
+ _notification_block_number = (
+ await async_session.scalars(select(NotificationBlockNumber).limit(1))
+ ).first()
+ assert _notification_block_number is None
+
+
+@pytest.mark.asyncio
+class TestWatchWatchTransferableAttribute:
+ issuer = eth_account["issuer"]
+
+ ###########################################################################
+ # Normal Case
+ ###########################################################################
+
+ #
+ # Initial Sync
+ async def test_normal_1(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchTransferableAttribute")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ _notification = (
+ await async_session.scalars(select(Notification).limit(1))
+ ).first()
+ assert _notification is None
+
+ _notification_attribute_value: NotificationAttributeValue = (
+ await async_session.scalars(
+ select(NotificationAttributeValue)
+ .where(
+ and_(
+ NotificationAttributeValue.contract_address == token["address"],
+ NotificationAttributeValue.attribute_key == "transferable",
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_attribute_value.attribute == {"transferable": True}
+
+ #
+ # Attribute not changed
+ @pytest.mark.freeze_time(datetime(2025, 7, 31, 1, 35, 0, tzinfo=timezone.utc))
+ async def test_normal_2(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchTransferableAttribute")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token = IDXShareToken()
+ idx_token.token_address = token["address"]
+ idx_token.token_template = "IbetShare"
+ idx_token.name = "test_token"
+ idx_token.transferable = True
+ idx_token.short_term_cache_created = datetime(
+ 2025, 7, 31, 1, 35, 0, tzinfo=timezone.utc
+ )
+ async_session.add(idx_token)
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+
+ notification_attribute_value = NotificationAttributeValue()
+ notification_attribute_value.contract_address = token["address"]
+ notification_attribute_value.attribute_key = "transferable"
+ notification_attribute_value.attribute = {"transferable": True}
+ async_session.add(notification_attribute_value)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ async_session.expunge_all()
+ _notification = (
+ await async_session.scalars(select(Notification).limit(1))
+ ).first()
+ assert _notification is None
+
+ _notification_attribute_value: NotificationAttributeValue = (
+ await async_session.scalars(
+ select(NotificationAttributeValue)
+ .where(
+ and_(
+ NotificationAttributeValue.contract_address == token["address"],
+ NotificationAttributeValue.attribute_key == "transferable",
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_attribute_value.attribute == {"transferable": True}
+
+ #
+ # Attribute changed
+ @pytest.mark.freeze_time(datetime(2025, 7, 31, 1, 35, 0, tzinfo=timezone.utc))
+ async def test_normal_3(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchTransferableAttribute")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token = IDXShareToken()
+ idx_token.token_address = token["address"]
+ idx_token.token_template = "IbetShare"
+ idx_token.name = "test_token"
+ idx_token.transferable = False
+ idx_token.short_term_cache_created = datetime(
+ 2025, 7, 31, 1, 35, 0, tzinfo=timezone.utc
+ )
+ async_session.add(idx_token)
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+
+ notification_attribute_value = NotificationAttributeValue()
+ notification_attribute_value.contract_address = token["address"]
+ notification_attribute_value.attribute_key = "transferable"
+ notification_attribute_value.attribute = {"transferable": True}
+ async_session.add(notification_attribute_value)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ async_session.expunge_all()
+ _notification = (
+ await async_session.scalars(select(Notification).limit(1))
+ ).first()
+ attribute_key_hash = Web3.keccak(text="transferable").hex()[0:8]
+ assert _notification.notification_category == "attribute_change"
+ assert (
+ _notification.notification_id[14:]
+ == f"{token['address'].replace('0x', '').lower()}{attribute_key_hash}00"
+ )
+ assert _notification.notification_type == NotificationType.TRANSFERABLE_CHANGED
+ assert _notification.priority == 0
+ assert _notification.address is None
+ assert _notification.block_timestamp is not None
+ assert _notification.args == {
+ "previous": True,
+ "current": False,
+ }
+ assert _notification.metainfo == {
+ "company_name": "株式会社DEMO",
+ "token_address": token["address"],
+ "token_name": "test_token",
+ "exchange_address": "",
+ "token_type": "IbetShare",
+ }
+
+ _notification_attribute_value: NotificationAttributeValue = (
+ await async_session.scalars(
+ select(NotificationAttributeValue)
+ .where(
+ and_(
+ NotificationAttributeValue.contract_address == token["address"],
+ NotificationAttributeValue.attribute_key == "transferable",
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_attribute_value.attribute == {"transferable": False}
+
+ #
+ # Attribute changed (On chain access)
+ @pytest.mark.freeze_time(datetime(2025, 7, 31, 1, 35, 0, tzinfo=timezone.utc))
+ async def test_normal_4(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchTransferableAttribute")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ untransferable_share_token(self.issuer, token)
+
+ idx_token = IDXShareToken()
+ idx_token.token_address = token["address"]
+ idx_token.token_template = "IbetShare"
+ idx_token.name = "test_token"
+ idx_token.transferable = True # Cache expired
+ idx_token.short_term_cache_created = datetime(
+ 2025, 7, 30, 1, 35, 0, tzinfo=timezone.utc
+ ) # Cache expired
+ async_session.add(idx_token)
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+
+ notification_attribute_value = NotificationAttributeValue()
+ notification_attribute_value.contract_address = token["address"]
+ notification_attribute_value.attribute_key = "transferable"
+ notification_attribute_value.attribute = {"transferable": True}
+ async_session.add(notification_attribute_value)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ async_session.expunge_all()
+ _notification = (
+ await async_session.scalars(select(Notification).limit(1))
+ ).first()
+ attribute_key_hash = Web3.keccak(text="transferable").hex()[0:8]
+ assert _notification.notification_category == "attribute_change"
+ assert (
+ _notification.notification_id[14:]
+ == f"{token['address'].replace('0x', '').lower()}{attribute_key_hash}00"
+ )
+ assert _notification.notification_type == NotificationType.TRANSFERABLE_CHANGED
+ assert _notification.priority == 0
+ assert _notification.address is None
+ assert _notification.block_timestamp is not None
+ assert _notification.args == {
+ "previous": True,
+ "current": False,
+ }
+ assert _notification.metainfo == {
+ "company_name": "株式会社DEMO",
+ "token_address": token["address"],
+ "token_name": "test_token",
+ "exchange_address": "",
+ "token_type": "IbetShare",
+ }
+
+ _notification_attribute_value: NotificationAttributeValue = (
+ await async_session.scalars(
+ select(NotificationAttributeValue)
+ .where(
+ and_(
+ NotificationAttributeValue.contract_address == token["address"],
+ NotificationAttributeValue.attribute_key == "transferable",
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_attribute_value.attribute == {"transferable": False}
+
+ # ###########################################################################
+ # # Error Case
+ # ###########################################################################
+
+ #
+ # Error occur
+ @mock.patch(
+ "app.model.blockchain.token.ShareToken.get",
+ MagicMock(side_effect=Exception()),
+ )
+ async def test_error_1(
+ self, watcher_factory, async_session, shared_contract, mocked_company_list
+ ):
+ watcher = watcher_factory("WatchTransferableAttribute")
+ exchange_contract = shared_contract["IbetShareExchange"]
+ token_list_contract = shared_contract["TokenList"]
+ personal_info_contract = shared_contract["PersonalInfo"]
+
+ # Issue token
+ token = await prepare_share_token(
+ self.issuer,
+ exchange_contract,
+ token_list_contract,
+ personal_info_contract,
+ async_session,
+ )
+
+ idx_token_list_item = IDXTokenListRegister()
+ idx_token_list_item.token_address = token["address"]
+ idx_token_list_item.owner_address = self.issuer["account_address"]
+ idx_token_list_item.token_template = "IbetShare"
+ async_session.add(idx_token_list_item)
+ await async_session.commit()
+
+ # Run target process
+ await watcher.loop()
+
+ # Assertion
+ async_session.expunge_all()
+ _notification = (
+ await async_session.scalars(select(Notification).limit(1))
+ ).first()
+ assert _notification is None
+
+ _notification_attribute_value: NotificationAttributeValue = (
+ await async_session.scalars(
+ select(NotificationAttributeValue)
+ .where(
+ and_(
+ NotificationAttributeValue.contract_address == token["address"],
+ NotificationAttributeValue.attribute_key == "transferable",
+ )
+ )
+ .limit(1)
+ )
+ ).first()
+ assert _notification_attribute_value is None
diff --git a/tests/batch/processor_Send_Chat_Webhook_test.py b/tests/batch/processor_Send_Chat_Webhook_test.py
index 05e6c6615..814d54ac0 100644
--- a/tests/batch/processor_Send_Chat_Webhook_test.py
+++ b/tests/batch/processor_Send_Chat_Webhook_test.py
@@ -20,7 +20,7 @@
import json
import logging
from unittest import mock
-from unittest.mock import AsyncMock
+from unittest.mock import MagicMock
import pytest
from sqlalchemy import select
@@ -53,10 +53,8 @@ class TestProcessorSendChatWebhook:
# No unsent hook exists
async def test_normal_1(self, processor, async_session, caplog):
# Run processor
- with mock.patch(
- "aiohttp.client.ClientSession.post", AsyncMock(side_effect=None)
- ):
- await processor.process()
+ with mock.patch("requests.post", MagicMock(side_effect=None)):
+ processor.process()
await async_session.commit()
# Assertion
@@ -75,10 +73,8 @@ async def test_normal_2(self, processor, async_session, caplog):
await async_session.commit()
# Run processor
- with mock.patch(
- "aiohttp.client.ClientSession.post", AsyncMock(side_effect=None)
- ):
- await processor.process()
+ with mock.patch("requests.post", MagicMock(side_effect=None)):
+ processor.process()
await async_session.commit()
# Assertion
@@ -96,10 +92,8 @@ async def test_normal_3(self, processor, async_session, caplog):
await async_session.commit()
# Run processor
- with mock.patch(
- "aiohttp.client.ClientSession.post", AsyncMock(side_effect=Exception())
- ):
- await processor.process()
+ with mock.patch("requests.post", MagicMock(side_effect=Exception())):
+ processor.process()
await async_session.commit()
# Assertion
@@ -126,13 +120,11 @@ async def test_error_1(self, processor, async_session, caplog):
# Run processor
with (
- mock.patch(
- "aiohttp.client.ClientSession.post", AsyncMock(side_effect=None)
- ),
+ mock.patch("requests.post", MagicMock(side_effect=None)),
mock.patch.object(Session, "commit", side_effect=SQLAlchemyError()),
pytest.raises(SQLAlchemyError),
):
- await processor.process()
+ processor.process()
await async_session.commit()
# Assertion
diff --git a/tests/contract_modules.py b/tests/contract_modules.py
index 1c3a99cbf..ab2899b42 100644
--- a/tests/contract_modules.py
+++ b/tests/contract_modules.py
@@ -329,6 +329,23 @@ def bond_force_unlock(
).transact({"from": invoker["account_address"]})
+# BONDトークン:資産ロック元強制変更
+def bond_force_change_locked_account(
+ invoker,
+ token,
+ lock_address: str,
+ before_account_address: str,
+ after_account_address: str,
+ amount: int,
+ data_str: str = "",
+):
+ web3.eth.default_account = invoker["account_address"]
+ TokenContract = Contract.get_contract("IbetStraightBond", token["address"])
+ TokenContract.functions.forceChangeLockedAccount(
+ lock_address, before_account_address, after_account_address, amount, data_str
+ ).transact({"from": invoker["account_address"]})
+
+
# BONDトークン:追加発行
def bond_issue_from(
invoker, token, target: str, amount: int, lock_address: str = config.ZERO_ADDRESS
@@ -364,6 +381,15 @@ def bond_set_tradable_exchange(invoker, token, exchange_address: str):
)
+# BONDトークン:償還状態に変更
+def bond_change_to_redeemed(invoker, token):
+ web3.eth.default_account = invoker["account_address"]
+ TokenContract = Contract.get_contract("IbetStraightBond", token["address"])
+ TokenContract.functions.changeToRedeemed().transact(
+ {"from": invoker["account_address"]}
+ )
+
+
###############################################################
# Share Token
###############################################################
@@ -456,6 +482,29 @@ def transfer_share_token(
)
+# SHAREトークン:移管
+def reallocate_share_token(
+ invoker: UnitTestAccount, to: UnitTestAccount, token: DeployedContract, amount: int
+):
+ web3.eth.default_account = invoker["account_address"]
+ TokenContract = Contract.get_contract("IbetShare", token["address"])
+ tx = TokenContract.functions.transfer(
+ to["account_address"], amount
+ ).build_transaction(
+ {
+ "from": invoker["account_address"],
+ "gas": 6000000,
+ "gasPrice": 0,
+ }
+ )
+ marker = b"\xc0\xff\xee\x00"
+ annotation_data = json.dumps(
+ {"purpose": "Reallocation"}, separators=(",", ":")
+ ).encode("utf-8")
+ tx["data"] += marker.hex() + annotation_data.hex()
+ web3.eth.send_transaction(tx)
+
+
# SHAREトークン:無効化
def invalidate_share_token(invoker, token):
web3.eth.default_account = invoker["account_address"]
@@ -570,6 +619,23 @@ def share_force_unlock(
).transact({"from": invoker["account_address"]})
+# SHAREトークン:資産ロック元強制変更
+def share_force_change_locked_account(
+ invoker,
+ token,
+ lock_address: str,
+ before_account_address: str,
+ after_account_address: str,
+ amount: int,
+ data_str: str = "",
+):
+ web3.eth.default_account = invoker["account_address"]
+ TokenContract = Contract.get_contract("IbetShare", token["address"])
+ TokenContract.functions.forceChangeLockedAccount(
+ lock_address, before_account_address, after_account_address, amount, data_str
+ ).transact({"from": invoker["account_address"]})
+
+
# SHAREトークン:追加発行
def share_issue_from(
invoker, token, target: str, amount: int, lock_address: str = config.ZERO_ADDRESS
@@ -608,6 +674,15 @@ def share_set_tradable_exchange(invoker, token, exchange_address: str):
)
+# SHAREトークン:消却状態に変更
+def share_change_to_canceled(invoker, token):
+ web3.eth.default_account = invoker["account_address"]
+ TokenContract = Contract.get_contract("IbetShare", token["address"])
+ TokenContract.functions.changeToCanceled().transact(
+ {"from": invoker["account_address"]}
+ )
+
+
###############################################################
# Coupon Token
###############################################################
diff --git a/tests/migrations/upgrade_test.py b/tests/migrations/upgrade_test.py
index 2e42c9308..7ad05475d 100644
--- a/tests/migrations/upgrade_test.py
+++ b/tests/migrations/upgrade_test.py
@@ -18,6 +18,7 @@
"""
import importlib
+import json
import logging
from datetime import datetime
from typing import Final
@@ -39,6 +40,7 @@
REVISION_23_12: Final = "f6f13d28bb48"
REVISION_24_3: Final = "3d3b90fda898"
REVISION_24_6: Final = "418af51b07b5"
+REVISION_25_6: Final = "9a28ed8d4afd"
REVISION_UP_TO_1_8 = [REVISION_22_3]
REVISION_UP_TO_22_6 = REVISION_UP_TO_1_8 + [REVISION_22_6]
@@ -925,3 +927,98 @@ def test_upgrade_v24_6(
else:
assert share_tokens[0].require_personal_info_registered is True
assert share_tokens[1].require_personal_info_registered is True
+
+ def test_upgrade_v25_6(
+ self, alembic_runner: MigrationContext, caplog: LogCaptureFixture
+ ):
+ # 1. Migrate to v25.6 initial
+ alembic_runner.migrate_up_to(REVISION_25_6)
+ meta = MetaData()
+ meta.reflect(bind=engine)
+
+ # 2. Insert test record
+ idx_transfer = meta.tables.get("transfer")
+ stmt1 = insert(idx_transfer).values(
+ id=1,
+ transaction_hash="test1",
+ token_address="test1",
+ from_address="test1",
+ to_address="test1",
+ value=1,
+ source_event="Unlock",
+ data={"message": "inheritance"},
+ message="inheritance",
+ )
+
+ idx_lock = meta.tables.get("lock")
+ stmt2 = insert(idx_lock).values(
+ id=1,
+ transaction_hash="test1",
+ msg_sender="test1",
+ block_number=1,
+ token_address="test1",
+ lock_address="test1",
+ account_address="test1",
+ value=1,
+ data={"message": "inheritance"},
+ block_timestamp=datetime(2025, 7, 23, 0, 0, 0),
+ is_forced=False,
+ )
+
+ idx_unlock = meta.tables.get("unlock")
+ stmt3 = insert(idx_unlock).values(
+ id=1,
+ transaction_hash="test1",
+ msg_sender="test1",
+ block_number=1,
+ token_address="test1",
+ lock_address="test1",
+ account_address="test1",
+ recipient_address="test1",
+ value=1,
+ data={"message": "inheritance"},
+ block_timestamp=datetime(2025, 7, 23, 0, 0, 0),
+ is_forced=False,
+ )
+
+ with engine.connect() as conn:
+ conn.execute(stmt1)
+ conn.execute(stmt2)
+ conn.execute(stmt3)
+ conn.commit()
+
+ # 3. Run to head
+ alembic_runner.migrate_up_to("head")
+
+ with engine.connect() as conn:
+ transfers = conn.execute(
+ text("SELECT * FROM transfer ORDER BY created ASC")
+ )
+ transfers = list(transfers)
+ if engine.name == "mysql":
+ assert json.loads(transfers[0].data) == {}
+ else:
+ assert transfers[0].data == {}
+ assert transfers[0].message is None
+
+ if engine.name == "mysql":
+ locks = conn.execute(text("SELECT * FROM `lock` ORDER BY created ASC"))
+ locks = list(locks)
+ assert json.loads(locks[0].data) == {}
+ else:
+ locks = conn.execute(text("SELECT * FROM lock ORDER BY created ASC"))
+ locks = list(locks)
+ assert locks[0].data == {}
+
+ if engine.name == "mysql":
+ unlocks = conn.execute(
+ text("SELECT * FROM `unlock` ORDER BY created ASC")
+ )
+ unlocks = list(unlocks)
+ assert json.loads(unlocks[0].data) == {}
+ else:
+ unlocks = conn.execute(
+ text("SELECT * FROM unlock ORDER BY created ASC")
+ )
+ unlocks = list(unlocks)
+ assert unlocks[0].data == {}
diff --git a/uv.lock b/uv.lock
index 69f87ce97..e3b78db5d 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1,5 +1,5 @@
version = 1
-revision = 2
+revision = 3
requires-python = "==3.12.9"
[[package]]
@@ -13,7 +13,7 @@ wheels = [
[[package]]
name = "aiohttp"
-version = "3.10.11"
+version = "3.12.15"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohappyeyeballs" },
@@ -21,25 +21,28 @@ dependencies = [
{ name = "attrs" },
{ name = "frozenlist" },
{ name = "multidict" },
+ { name = "propcache" },
{ name = "yarl" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/25/a8/8e2ba36c6e3278d62e0c88aa42bb92ddbef092ac363b390dab4421da5cf5/aiohttp-3.10.11.tar.gz", hash = "sha256:9dc2b8f3dcab2e39e0fa309c8da50c3b55e6f34ab25f1a71d3288f24924d33a7", size = 7551886, upload-time = "2024-11-13T16:40:33.335Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/01/16/077057ef3bd684dbf9a8273a5299e182a8d07b4b252503712ff8b5364fd1/aiohttp-3.10.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7480519f70e32bfb101d71fb9a1f330fbd291655a4c1c922232a48c458c52710", size = 584830, upload-time = "2024-11-13T16:37:49.608Z" },
- { url = "https://files.pythonhosted.org/packages/2c/cf/348b93deb9597c61a51b6682e81f7c7d79290249e886022ef0705d858d90/aiohttp-3.10.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f65267266c9aeb2287a6622ee2bb39490292552f9fbf851baabc04c9f84e048d", size = 397090, upload-time = "2024-11-13T16:37:51.539Z" },
- { url = "https://files.pythonhosted.org/packages/70/bf/903df5cd739dfaf5b827b3d8c9d68ff4fcea16a0ca1aeb948c9da30f56c8/aiohttp-3.10.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7400a93d629a0608dc1d6c55f1e3d6e07f7375745aaa8bd7f085571e4d1cee97", size = 392361, upload-time = "2024-11-13T16:37:53.586Z" },
- { url = "https://files.pythonhosted.org/packages/fb/97/e4792675448a2ac5bd56f377a095233b805dd1315235c940c8ba5624e3cb/aiohttp-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f34b97e4b11b8d4eb2c3a4f975be626cc8af99ff479da7de49ac2c6d02d35725", size = 1309839, upload-time = "2024-11-13T16:37:55.68Z" },
- { url = "https://files.pythonhosted.org/packages/96/d0/ba19b1260da6fbbda4d5b1550d8a53ba3518868f2c143d672aedfdbc6172/aiohttp-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e7b825da878464a252ccff2958838f9caa82f32a8dbc334eb9b34a026e2c636", size = 1348116, upload-time = "2024-11-13T16:37:58.232Z" },
- { url = "https://files.pythonhosted.org/packages/b3/b9/15100ee7113a2638bfdc91aecc54641609a92a7ce4fe533ebeaa8d43ff93/aiohttp-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9f92a344c50b9667827da308473005f34767b6a2a60d9acff56ae94f895f385", size = 1391402, upload-time = "2024-11-13T16:38:00.522Z" },
- { url = "https://files.pythonhosted.org/packages/c5/36/831522618ac0dcd0b28f327afd18df7fb6bbf3eaf302f912a40e87714846/aiohttp-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f1ab987a27b83c5268a17218463c2ec08dbb754195113867a27b166cd6087", size = 1304239, upload-time = "2024-11-13T16:38:04.195Z" },
- { url = "https://files.pythonhosted.org/packages/60/9f/b7230d0c48b076500ae57adb717aa0656432acd3d8febb1183dedfaa4e75/aiohttp-3.10.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1dc0f4ca54842173d03322793ebcf2c8cc2d34ae91cc762478e295d8e361e03f", size = 1256565, upload-time = "2024-11-13T16:38:07.218Z" },
- { url = "https://files.pythonhosted.org/packages/63/c2/35c7b4699f4830b3b0a5c3d5619df16dca8052ae8b488e66065902d559f6/aiohttp-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7ce6a51469bfaacff146e59e7fb61c9c23006495d11cc24c514a455032bcfa03", size = 1269285, upload-time = "2024-11-13T16:38:09.396Z" },
- { url = "https://files.pythonhosted.org/packages/51/48/bc20ea753909bdeb09f9065260aefa7453e3a57f6a51f56f5216adc1a5e7/aiohttp-3.10.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aad3cd91d484d065ede16f3cf15408254e2469e3f613b241a1db552c5eb7ab7d", size = 1276716, upload-time = "2024-11-13T16:38:12.039Z" },
- { url = "https://files.pythonhosted.org/packages/0c/7b/a8708616b3810f55ead66f8e189afa9474795760473aea734bbea536cd64/aiohttp-3.10.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f4df4b8ca97f658c880fb4b90b1d1ec528315d4030af1ec763247ebfd33d8b9a", size = 1315023, upload-time = "2024-11-13T16:38:15.155Z" },
- { url = "https://files.pythonhosted.org/packages/2a/d6/dfe9134a921e05b01661a127a37b7d157db93428905450e32f9898eef27d/aiohttp-3.10.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2e4e18a0a2d03531edbc06c366954e40a3f8d2a88d2b936bbe78a0c75a3aab3e", size = 1342735, upload-time = "2024-11-13T16:38:17.539Z" },
- { url = "https://files.pythonhosted.org/packages/ca/1a/3bd7f18e3909eabd57e5d17ecdbf5ea4c5828d91341e3676a07de7c76312/aiohttp-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6ce66780fa1a20e45bc753cda2a149daa6dbf1561fc1289fa0c308391c7bc0a4", size = 1302618, upload-time = "2024-11-13T16:38:19.865Z" },
- { url = "https://files.pythonhosted.org/packages/cf/51/d063133781cda48cfdd1e11fc8ef45ab3912b446feba41556385b3ae5087/aiohttp-3.10.11-cp312-cp312-win32.whl", hash = "sha256:a919c8957695ea4c0e7a3e8d16494e3477b86f33067478f43106921c2fef15bb", size = 360497, upload-time = "2024-11-13T16:38:21.996Z" },
- { url = "https://files.pythonhosted.org/packages/55/4e/f29def9ed39826fe8f85955f2e42fe5cc0cbe3ebb53c97087f225368702e/aiohttp-3.10.11-cp312-cp312-win_amd64.whl", hash = "sha256:b5e29706e6389a2283a91611c91bf24f218962717c8f3b4e528ef529d112ee27", size = 380577, upload-time = "2024-11-13T16:38:24.247Z" },
+ { url = "https://files.pythonhosted.org/packages/63/97/77cb2450d9b35f517d6cf506256bf4f5bda3f93a66b4ad64ba7fc917899c/aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7", size = 702333, upload-time = "2025-07-29T05:50:46.507Z" },
+ { url = "https://files.pythonhosted.org/packages/83/6d/0544e6b08b748682c30b9f65640d006e51f90763b41d7c546693bc22900d/aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444", size = 476948, upload-time = "2025-07-29T05:50:48.067Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/1d/c8c40e611e5094330284b1aea8a4b02ca0858f8458614fa35754cab42b9c/aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d", size = 469787, upload-time = "2025-07-29T05:50:49.669Z" },
+ { url = "https://files.pythonhosted.org/packages/38/7d/b76438e70319796bfff717f325d97ce2e9310f752a267bfdf5192ac6082b/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c", size = 1716590, upload-time = "2025-07-29T05:50:51.368Z" },
+ { url = "https://files.pythonhosted.org/packages/79/b1/60370d70cdf8b269ee1444b390cbd72ce514f0d1cd1a715821c784d272c9/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0", size = 1699241, upload-time = "2025-07-29T05:50:53.628Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/2b/4968a7b8792437ebc12186db31523f541943e99bda8f30335c482bea6879/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab", size = 1754335, upload-time = "2025-07-29T05:50:55.394Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/c1/49524ed553f9a0bec1a11fac09e790f49ff669bcd14164f9fab608831c4d/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb", size = 1800491, upload-time = "2025-07-29T05:50:57.202Z" },
+ { url = "https://files.pythonhosted.org/packages/de/5e/3bf5acea47a96a28c121b167f5ef659cf71208b19e52a88cdfa5c37f1fcc/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545", size = 1719929, upload-time = "2025-07-29T05:50:59.192Z" },
+ { url = "https://files.pythonhosted.org/packages/39/94/8ae30b806835bcd1cba799ba35347dee6961a11bd507db634516210e91d8/aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c", size = 1635733, upload-time = "2025-07-29T05:51:01.394Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/46/06cdef71dd03acd9da7f51ab3a9107318aee12ad38d273f654e4f981583a/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd", size = 1696790, upload-time = "2025-07-29T05:51:03.657Z" },
+ { url = "https://files.pythonhosted.org/packages/02/90/6b4cfaaf92ed98d0ec4d173e78b99b4b1a7551250be8937d9d67ecb356b4/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f", size = 1718245, upload-time = "2025-07-29T05:51:05.911Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/e6/2593751670fa06f080a846f37f112cbe6f873ba510d070136a6ed46117c6/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d", size = 1658899, upload-time = "2025-07-29T05:51:07.753Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/28/c15bacbdb8b8eb5bf39b10680d129ea7410b859e379b03190f02fa104ffd/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519", size = 1738459, upload-time = "2025-07-29T05:51:09.56Z" },
+ { url = "https://files.pythonhosted.org/packages/00/de/c269cbc4faa01fb10f143b1670633a8ddd5b2e1ffd0548f7aa49cb5c70e2/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea", size = 1766434, upload-time = "2025-07-29T05:51:11.423Z" },
+ { url = "https://files.pythonhosted.org/packages/52/b0/4ff3abd81aa7d929b27d2e1403722a65fc87b763e3a97b3a2a494bfc63bc/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3", size = 1726045, upload-time = "2025-07-29T05:51:13.689Z" },
+ { url = "https://files.pythonhosted.org/packages/71/16/949225a6a2dd6efcbd855fbd90cf476052e648fb011aa538e3b15b89a57a/aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1", size = 423591, upload-time = "2025-07-29T05:51:15.452Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/d8/fa65d2a349fe938b76d309db1a56a75c4fb8cc7b17a398b698488a939903/aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34", size = 450266, upload-time = "2025-07-29T05:51:17.239Z" },
]
[[package]]
@@ -56,14 +59,15 @@ wheels = [
[[package]]
name = "aiosignal"
-version = "1.3.2"
+version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "frozenlist" },
+ { name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
]
[[package]]
@@ -551,16 +555,16 @@ wheels = [
[[package]]
name = "fastapi"
-version = "0.115.12"
+version = "0.116.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "starlette" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" },
]
[[package]]
@@ -771,10 +775,9 @@ wheels = [
[[package]]
name = "ibet-wallet-api"
-version = "25.6"
+version = "25.9"
source = { virtual = "." }
dependencies = [
- { name = "aiohttp" },
{ name = "aiomysql" },
{ name = "alembic" },
{ name = "asyncpg" },
@@ -803,6 +806,7 @@ dependencies = [
{ name = "pymysql", extra = ["rsa"] },
{ name = "pyroscope-io" },
{ name = "pyroscope-otel" },
+ { name = "requests" },
{ name = "sqlalchemy", extra = ["asyncio"] },
{ name = "tzdata" },
{ name = "uvicorn", extra = ["standard"] },
@@ -811,6 +815,7 @@ dependencies = [
[package.optional-dependencies]
ibet-explorer = [
+ { name = "aiohttp" },
{ name = "async-cache" },
{ name = "ibet-wallet-api-explorer" },
{ name = "textual" },
@@ -836,16 +841,17 @@ dev = [
[package.metadata]
requires-dist = [
- { name = "aiohttp", specifier = "~=3.10.10" },
+ { name = "aiohttp", marker = "extra == 'ibet-explorer'", specifier = "~=3.12.13" },
{ name = "aiomysql", specifier = "==0.2.0" },
{ name = "alembic", specifier = ">=1.14.0,<2.0.0" },
+ { name = "async-cache", marker = "extra == 'ibet-explorer'", specifier = "==1.1.1" },
{ name = "async-cache", marker = "extra == 'ibet-explorer'", specifier = "~=1.1.1" },
{ name = "asyncpg", specifier = "~=0.30.0" },
{ name = "boto3", specifier = "~=1.37.0" },
{ name = "coincurve", specifier = "~=21.0.0" },
{ name = "eth-keyfile", specifier = "~=0.9.1" },
{ name = "eth-utils", specifier = "~=5.2.0" },
- { name = "fastapi", specifier = "~=0.115.0" },
+ { name = "fastapi", specifier = "~=0.116.1" },
{ name = "gunicorn", specifier = "~=23.0.0" },
{ name = "hexbytes", specifier = "~=1.3.0" },
{ name = "httpx", specifier = "~=0.28.0" },
@@ -867,6 +873,7 @@ requires-dist = [
{ name = "pymysql", extras = ["rsa"], specifier = "~=1.1.0" },
{ name = "pyroscope-io", specifier = ">=0.8.11" },
{ name = "pyroscope-otel", specifier = ">=0.4.1" },
+ { name = "requests", specifier = ">=2.32.3" },
{ name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0.33,<3.0.0" },
{ name = "textual", marker = "extra == 'ibet-explorer'", specifier = "~=0.44.1" },
{ name = "typer", marker = "extra == 'ibet-explorer'", specifier = "~=0.12.3" },
@@ -1887,7 +1894,7 @@ wheels = [
[[package]]
name = "requests"
-version = "2.32.3"
+version = "2.32.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
@@ -1895,9 +1902,9 @@ dependencies = [
{ name = "idna" },
{ name = "urllib3" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
]
[[package]]
@@ -2055,14 +2062,15 @@ asyncio = [
[[package]]
name = "starlette"
-version = "0.46.2"
+version = "0.47.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
+ { name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/15/b9/cc3017f9a9c9b6e27c5106cc10cc7904653c3eec0729793aec10479dd669/starlette-0.47.3.tar.gz", hash = "sha256:6bc94f839cc176c4858894f1f8908f0ab79dfec1a6b8402f6da9be26ebea52e9", size = 2584144, upload-time = "2025-08-24T13:36:42.122Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/fd/901cfa59aaa5b30a99e16876f11abe38b59a1a2c51ffb3d7142bb6089069/starlette-0.47.3-py3-none-any.whl", hash = "sha256:89c0778ca62a76b826101e7c709e70680a1699ca7da6b44d38eb0a7e61fe4b51", size = 72991, upload-time = "2025-08-24T13:36:40.887Z" },
]
[[package]]
@@ -2161,11 +2169,11 @@ wheels = [
[[package]]
name = "urllib3"
-version = "2.4.0"
+version = "2.5.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" },
]
[[package]]