Skip to content

Commit

Permalink
Custom AML check and payout split config
Browse files Browse the repository at this point in the history
  • Loading branch information
dmytro-samoylenko committed Jan 6, 2025
1 parent 3f4adcf commit 9e59e61
Show file tree
Hide file tree
Showing 25 changed files with 1,810 additions and 553 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ build/
*.swp
*~
*.db
celerybeat-schedule
celerybeat*
data/
docker-compose*
.env
BUGS
4 changes: 1 addition & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
FROM python:3.8-slim
FROM python:3

WORKDIR /app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# CMD [ "python", "./kafka-to-ws.py" ]
45 changes: 37 additions & 8 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,68 @@

celery = Celery(
__name__,
broker=f'redis://{config["REDIS_HOST"]}',
backend=f'redis://{config["REDIS_HOST"]}',
task_serializer='pickle',
accept_content=['pickle'],
result_serializer='pickle',
result_accept_content=['pickle'],
broker=f"redis://{config.REDIS_HOST}",
backend=f"redis://{config.REDIS_HOST}",
task_serializer="pickle",
accept_content=["pickle"],
result_serializer="pickle",
result_accept_content=["pickle"],
)

import decimal, sqlite3

sqlite3.register_adapter(decimal.Decimal, lambda x: str(x))
sqlite3.register_converter("DECTEXT", lambda x: decimal.Decimal(x.decode()))


def create_app():

from flask.config import Config

class AttrConfig(Config):
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(key)

def __dir__(self):
out = set(self.keys())
out.update(super().__dir__())
return sorted(out)

Flask.config_class = AttrConfig

app = Flask(__name__)
app.config.from_mapping(config)

from . import db

db.init_app(app)

block_scanner.BlockScanner.set_watched_accounts(
[row['public'] for row in db.query_db2('select public from keys where type = "onetime"')]
[
row["public"]
for row in db.query_db2('select public from keys where type = "onetime"')
]
)

from . import utils

utils.init_wallet(app)

app.url_map.converters['decimal'] = utils.DecimalConverter
app.url_map.converters["decimal"] = utils.DecimalConverter

from .api import api as api_blueprint

app.register_blueprint(api_blueprint)

from .api import metrics_blueprint

app.register_blueprint(metrics_blueprint)

from .db import engine, SQLModel

SQLModel.metadata.create_all(engine)

return app
21 changes: 14 additions & 7 deletions app/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,30 @@
from ..config import config
from ..logging import logger

api = Blueprint('api', __name__, url_prefix='/<symbol>')
metrics_blueprint = Blueprint('metrics_blueprint', __name__, url_prefix='/')
api = Blueprint("api", __name__, url_prefix="/<symbol>")
metrics_blueprint = Blueprint("metrics_blueprint", __name__, url_prefix="/")


@metrics_blueprint.before_request
@api.before_request
def check_credentials():
auth = request.authorization
if not (auth and auth.username == config['API_USERNAME']
and auth.password == config['API_PASSWORD']):
return {'status': 'error', 'msg': 'authorization requred'}, 401
if not (
auth
and auth.username == config.API_USERNAME
and auth.password == config.API_PASSWORD
):
return {"status": "error", "msg": "authorization requred"}, 401


@api.url_defaults
def add_symbol(endpoint, values):
values.setdefault('symbol', g.symbol)
values.setdefault("symbol", g.symbol)


@api.url_value_preprocessor
def pull_symbol(endpoint, values):
g.symbol = values.pop('symbol').upper()
g.symbol = values.pop("symbol").upper()


@api.errorhandler(Exception)
Expand All @@ -32,4 +38,5 @@ def handle_exception(e):
logger.warn(f"Exception: {traceback.format_exc()}")
return {"status": "error", "msg": str(e)}


from . import payout, views, metrics
59 changes: 33 additions & 26 deletions app/api/payout.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,72 +14,79 @@
from ..logging import logger


@api.post('/calc-tx-fee/<decimal:amount>')
@api.post("/calc-tx-fee/<decimal:amount>")
def calc_tx_fee(amount):
return {'fee': config['TX_FEE']}
return {"fee": config.TX_FEE}

@api.post('/multipayout')

@api.post("/multipayout")
def multipayout():
try:
payout_list = request.get_json(force=True)
except Exception as e:
raise Exception(f"Bad JSON in payout list: {e}")

if not payout_list:
raise Exception(f"Payout list is empty!")
raise Exception(f"Payout list is empty!")

for transfer in payout_list:
try:
tronpy.keys.to_base58check_address(transfer['dest'])
tronpy.keys.to_base58check_address(transfer["dest"])
except Exception as e:
raise Exception(f"Bad destination address in {transfer}: {e}")
try:
transfer['amount'] = Decimal(transfer['amount'])
transfer["amount"] = Decimal(transfer["amount"])
except Exception as e:
raise Exception(f"Bad amount in {transfer}: {e}")

if transfer['amount'] <= 0:
if transfer["amount"] <= 0:
raise Exception(f"Payout amount should be a positive number: {transfer}")

wallet = Wallet(g.symbol)
balance = wallet.balance
need_tokens = sum([transfer['amount'] for transfer in payout_list])
need_tokens = sum([transfer["amount"] for transfer in payout_list])
if balance < need_tokens:
pass
#raise Exception(f"Not enough {g.symbol} tokens to make all payouts. Has: {balance}, need: {need_tokens}")
# raise Exception(f"Not enough {g.symbol} tokens to make all payouts. Has: {balance}, need: {need_tokens}")

need_currency = len(payout_list) * config['TX_FEE']
need_currency = len(payout_list) * config.TX_FEE
trx_balance = Wallet().balance
if trx_balance < need_currency:
raise Exception(f"Not enough TRX tokens at fee-deposit account {wallet.main_account} to pay payout fees. "
f"Has: {trx_balance}, need: {need_currency}")
raise Exception(
f"Not enough TRX tokens at fee-deposit account {wallet.main_account} to pay payout fees. "
f"Has: {trx_balance}, need: {need_currency}"
)

if 'dryrun' in request.args:
if "dryrun" in request.args:
return {
'currency': {
'need': need_currency,
'have': trx_balance,
"currency": {
"need": need_currency,
"have": trx_balance,
},
'tokens': {
'need': need_tokens,
'have': balance,
"tokens": {
"need": need_tokens,
"have": balance,
},
}

task = ( prepare_multipayout.s(payout_list, g.symbol) | payout_task.s(g.symbol) ).apply_async()
return {'task_id': task.id}
task = (
prepare_multipayout.s(payout_list, g.symbol) | payout_task.s(g.symbol)
).apply_async()
return {"task_id": task.id}

@api.post('/payout/<to>/<decimal:amount>')

@api.post("/payout/<to>/<decimal:amount>")
def payout(to, amount):
task = (
prepare_payout.s(to, amount, g.symbol) | payout_task.s(g.symbol)
).apply_async()
return {'task_id': task.id}
return {"task_id": task.id}


@api.post('/task/<id>')
@api.post("/task/<id>")
def get_task(id):
task = celery.AsyncResult(id)
if isinstance(task.result, Exception):
return {'status': task.status, 'result': task.result.args[0]}
return {"status": task.status, "result": task.result.args[0]}
else:
return {'status': task.status, 'result': task.result}
return {"status": task.status, "result": task.result}
Loading

0 comments on commit 9e59e61

Please sign in to comment.