dev@locazia: add service wallet
This commit is contained in:
parent
164f280899
commit
4a51efed01
|
|
@ -6,3 +6,4 @@ sqlStorage
|
||||||
playground
|
playground
|
||||||
alembic.ini
|
alembic.ini
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
messages.pot
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,6 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
app.run(host='0.0.0.0', port=SANIC_PORT)
|
app.run(host='0.0.0.0', port=SANIC_PORT)
|
||||||
else:
|
else:
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
startup_fn = None
|
startup_fn = None
|
||||||
if startup_target == 'indexator':
|
if startup_target == 'indexator':
|
||||||
from app.core.background.indexator_service import main as target_fn
|
from app.core.background.indexator_service import main as target_fn
|
||||||
|
|
@ -88,6 +87,7 @@ if __name__ == '__main__':
|
||||||
startup_fn = startup_fn or target_fn
|
startup_fn = startup_fn or target_fn
|
||||||
assert startup_fn
|
assert startup_fn
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
try:
|
try:
|
||||||
loop.run_until_complete(startup_fn())
|
loop.run_until_complete(startup_fn())
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from app.core.models._blockchain.ton.connect import TonConnect, unpack_wallet_info
|
from app.core._blockchain.ton.connect import TonConnect, unpack_wallet_info
|
||||||
from sanic import response
|
from sanic import response
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
from sanic import response
|
from sanic import response
|
||||||
|
from base58 import b58encode
|
||||||
|
from app.core._secrets import hot_pubkey, service_wallet
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -8,6 +10,13 @@ def get_git_info():
|
||||||
return branch_name, commit_hash
|
return branch_name, commit_hash
|
||||||
|
|
||||||
|
|
||||||
|
async def s_api_system(request):
|
||||||
|
return response.json({
|
||||||
|
'id': b58encode(hot_pubkey).decode(),
|
||||||
|
'ton_address': service_wallet.address.to_string(1, 1, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
async def s_api_system_version(request):
|
async def s_api_system_version(request):
|
||||||
branch_name, commit_hash = get_git_info()
|
branch_name, commit_hash = get_git_info()
|
||||||
return response.json({
|
return response.json({
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from app.core._utils.tg_process_template import tg_process_template
|
||||||
from app.core._keyboards import get_inline_keyboard
|
from app.core._keyboards import get_inline_keyboard
|
||||||
from app.core.logger import logger
|
from app.core.logger import logger
|
||||||
from app.core.models.wallet_connection import WalletConnection
|
from app.core.models.wallet_connection import WalletConnection
|
||||||
from app.core.models._blockchain.ton.connect import TonConnect, unpack_wallet_info
|
from app.core._blockchain.ton.connect import TonConnect, unpack_wallet_info
|
||||||
from app.core._config import WEB_APP_URLS
|
from app.core._config import WEB_APP_URLS
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from app.core._utils.tg_process_template import tg_process_template
|
||||||
from app.core._keyboards import get_inline_keyboard
|
from app.core._keyboards import get_inline_keyboard
|
||||||
from app.core.logger import logger
|
from app.core.logger import logger
|
||||||
from app.core.models.wallet_connection import WalletConnection
|
from app.core.models.wallet_connection import WalletConnection
|
||||||
from app.core.models._blockchain.ton.connect import TonConnect, unpack_wallet_info
|
from app.core._blockchain.ton.connect import TonConnect, unpack_wallet_info
|
||||||
from app.core._config import WEB_APP_URLS
|
from app.core._config import WEB_APP_URLS
|
||||||
from aiogram import types, Router, F
|
from aiogram import types, Router, F
|
||||||
from aiogram.filters import Command
|
from aiogram.filters import Command
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from aiogram.filters import Command
|
||||||
from app.core._keyboards import get_inline_keyboard
|
from app.core._keyboards import get_inline_keyboard
|
||||||
from app.core._utils.tg_process_template import tg_process_template
|
from app.core._utils.tg_process_template import tg_process_template
|
||||||
from app.core.logger import make_log
|
from app.core.logger import make_log
|
||||||
from app.core.models._blockchain.ton.connect import TonConnect, unpack_wallet_info
|
from app.core._blockchain.ton.connect import TonConnect, unpack_wallet_info
|
||||||
from app.core.models.wallet_connection import WalletConnection
|
from app.core.models.wallet_connection import WalletConnection
|
||||||
from app.bot.routers.home import send_connect_wallets_list, send_home_menu
|
from app.bot.routers.home import send_connect_wallets_list, send_home_menu
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
from decimal import Decimal
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
from tonsdk.boc import Cell, begin_cell
|
||||||
|
from tonsdk.contract import Contract
|
||||||
|
from tonsdk.contract.wallet import WalletContract
|
||||||
|
from tonsdk.utils import Address
|
||||||
|
|
||||||
|
WALLET_V3_CR3_CODE_HEX = 'b5ee9c7241021001000162000114ff00f4a413f4bcf2c80b01020120020f02014803080202ce0407020120050600510ccc741d35c87e900c3e910c7b513420405035c874ffcc19aea6f0003cb41a750c341ffc00a456f8a000730074c7c860802ab06ea65b0874c1f50c007ec0380860802aa82ea384cc407cb81a75350c087ec100743b47bb54fb55380c0c7000372103fcbc20002349521d74ac2009801d401d022f00101e85b8020120090c0201200a0b0019bb39ced44d08020d721d3ff3080011b8c97ed44d0d31f3080201580d0e001bb71e3da89a1020481ae43a61e610001bb49f3da89a1020281ae43a7fe61000f6f28308d71820d31fd31fd31f3001f823bbf2d06ced44d0d31fd3ffd31fd3ff305151baf2e0695132baf2e06924f901541066f910f2e069f8007054715226ed44ed45ed479131ed67ed65ed64747fed118e1104d430d023c000917f9170e2f002045023ed41edf101f2ff04a4c8cb1f13cbffcb1fcbffcb0fc9ed542675fc7e'
|
||||||
|
|
||||||
|
|
||||||
|
class WalletV3CR3(WalletContract):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
kwargs['code'] = Cell.one_from_boc(WALLET_V3_CR3_CODE_HEX)
|
||||||
|
kwargs['subwallet_id'] = kwargs.get('subwallet_id', 0)
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
def create_data_cell(self):
|
||||||
|
return (
|
||||||
|
begin_cell()
|
||||||
|
.store_uint(0, 32)
|
||||||
|
.store_bytes(self.options['public_key'])
|
||||||
|
.store_uint(self.options['subwallet_id'], 32)
|
||||||
|
.store_uint(0, 256)
|
||||||
|
.end_cell()
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_signing_message(self, seqno=None, timeout=60) -> Cell:
|
||||||
|
seqno = seqno or 0
|
||||||
|
return begin_cell().store_uint(self.options['subwallet_id'], 32).store_uint(int(time() + timeout),
|
||||||
|
32).store_uint(seqno, 32).end_cell()
|
||||||
|
|
||||||
|
def create_transfer_message(self, recipients_list: list, seqno: int, timeout=60, dummy_signature=False) -> dict:
|
||||||
|
signing_message = begin_cell().store_cell(self.create_signing_message(seqno=seqno, timeout=timeout))
|
||||||
|
_commands = begin_cell()
|
||||||
|
for i, recipient in enumerate(recipients_list):
|
||||||
|
if not recipient: continue
|
||||||
|
payload_cell = Cell()
|
||||||
|
if recipient.get('payload'):
|
||||||
|
if type(recipient['payload']) == str:
|
||||||
|
if len(recipient['payload']) > 0:
|
||||||
|
payload_cell.bits.write_uint(0, 32)
|
||||||
|
payload_cell.bits.write_string(recipient['payload'])
|
||||||
|
elif hasattr(recipient['payload'], 'refs'):
|
||||||
|
payload_cell = recipient['payload']
|
||||||
|
else:
|
||||||
|
payload_cell.bits.write_bytes(recipient['payload'])
|
||||||
|
|
||||||
|
order_header = Contract.create_internal_message_header(
|
||||||
|
Address(recipient['address']), Decimal(recipient['amount'])
|
||||||
|
)
|
||||||
|
order = Contract.create_common_msg_info(
|
||||||
|
order_header, recipient.get('state_init'), payload_cell
|
||||||
|
)
|
||||||
|
_commands = _commands.store_ref(
|
||||||
|
begin_cell()
|
||||||
|
.store_uint(0xAAC1, 32)
|
||||||
|
.store_uint8(recipient.get('send_mode', 0))
|
||||||
|
.store_ref(order).end_cell()
|
||||||
|
)
|
||||||
|
|
||||||
|
signing_message = signing_message.store_ref(_commands.end_cell())
|
||||||
|
return self.create_external_message(signing_message.end_cell(), seqno, dummy_signature)
|
||||||
|
|
||||||
|
def create_upgrade_message(self, new_code: Cell, new_data: Cell) -> dict:
|
||||||
|
signing_message = begin_cell().store_cell(self.create_signing_message())
|
||||||
|
_commands = begin_cell()
|
||||||
|
_commands = _commands.store_ref(
|
||||||
|
begin_cell()
|
||||||
|
.store_uint(0xAAA0, 32)
|
||||||
|
.store_ref(new_code)
|
||||||
|
.store_ref(new_data)
|
||||||
|
.end_cell()
|
||||||
|
)
|
||||||
|
signing_message = signing_message.store_ref(_commands.end_cell())
|
||||||
|
return self.create_external_message(signing_message.end_cell(), 0, True)
|
||||||
|
|
@ -11,6 +11,10 @@ UPLOADS_DIR = os.getenv('UPLOADS_DIR', '/app/data')
|
||||||
if not os.path.exists(UPLOADS_DIR):
|
if not os.path.exists(UPLOADS_DIR):
|
||||||
os.makedirs(UPLOADS_DIR)
|
os.makedirs(UPLOADS_DIR)
|
||||||
|
|
||||||
|
CONFIG_FILE = os.getenv('CONFIG_FILE') or f"{UPLOADS_DIR}/../config"
|
||||||
|
from app.core.models._config import ConfigFile
|
||||||
|
config_manager = ConfigFile(CONFIG_FILE)
|
||||||
|
|
||||||
TELEGRAM_API_KEY = os.environ.get('TELEGRAM_API_KEY')
|
TELEGRAM_API_KEY = os.environ.get('TELEGRAM_API_KEY')
|
||||||
assert TELEGRAM_API_KEY, "Telegram API_KEY required"
|
assert TELEGRAM_API_KEY, "Telegram API_KEY required"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
from nacl.bindings import crypto_sign_seed_keypair
|
||||||
|
from app.core._config import config_manager
|
||||||
|
from app.core.logger import make_log
|
||||||
|
from app.core._blockchain.ton.wallet_v3cr3 import WalletV3CR3
|
||||||
|
from os import urandom, getenv
|
||||||
|
from tonsdk.utils import Address
|
||||||
|
|
||||||
|
|
||||||
|
def load_hot_pair():
|
||||||
|
hot_seed = config_manager.get('private_key')
|
||||||
|
if hot_seed is None:
|
||||||
|
make_log("HotWallet", "No seed found, generating new one", level='info')
|
||||||
|
hot_seed = urandom(32).hex()
|
||||||
|
config_manager.set('private_key', hot_seed)
|
||||||
|
return load_hot_pair()
|
||||||
|
|
||||||
|
public_key, private_key = crypto_sign_seed_keypair(bytes.fromhex(hot_seed))
|
||||||
|
return public_key, private_key
|
||||||
|
|
||||||
|
|
||||||
|
_extra_ton_wallet_options = {}
|
||||||
|
if getenv('TON_CUSTOM_WALLET_ADDRESS'):
|
||||||
|
_extra_ton_wallet_options['wallet_address'] = Address(getenv('TON_CUSTOM_WALLET_ADDRESS'))
|
||||||
|
|
||||||
|
hot_pubkey, hot_privkey = load_hot_pair()
|
||||||
|
service_wallet = WalletV3CR3(
|
||||||
|
private_key=hot_privkey,
|
||||||
|
public_key=hot_pubkey,
|
||||||
|
**_extra_ton_wallet_options
|
||||||
|
)
|
||||||
|
|
@ -1,11 +1,18 @@
|
||||||
|
|
||||||
from app.core.logger import make_log
|
from app.core.logger import make_log
|
||||||
|
from app.core.storage import db_session
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
make_log("Uploader", "Service started", level="info")
|
make_log("Uploader", "Service started", level="info")
|
||||||
|
while True:
|
||||||
|
# make_log("Uploader", "Service running", level="debug")
|
||||||
|
# with db_session() as session:
|
||||||
|
# for stored_content in session.query(StoredContent).filter(StoredContent.uploaded == False).all():
|
||||||
|
# pass
|
||||||
|
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
from app.core.logger import make_log
|
||||||
|
from json import loads as json_loads
|
||||||
|
from json import dumps as json_dumps
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigFile:
|
||||||
|
def __init__(self, filepath: str):
|
||||||
|
self.filepath = filepath
|
||||||
|
with open(self.filepath, 'r') as file:
|
||||||
|
self.values = json_loads(file.read())
|
||||||
|
|
||||||
|
assert isinstance(self.values, dict)
|
||||||
|
|
||||||
|
def get(self, key, default=None):
|
||||||
|
return self.values.get(key, default)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
with open(self.filepath, 'w') as file:
|
||||||
|
file.write(
|
||||||
|
json_dumps(
|
||||||
|
self.values,
|
||||||
|
indent=4,
|
||||||
|
sort_keys=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def set(self, key, value):
|
||||||
|
self.values[key] = value
|
||||||
|
self.save()
|
||||||
|
make_log("ConfigFile", f"Edited {key}", level="debug")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -28,6 +28,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./logs:/app/logs
|
- ./logs:/app/logs
|
||||||
- ./storedContent:/app/data
|
- ./storedContent:/app/data
|
||||||
|
- ./activeConfig:/app/config
|
||||||
depends_on:
|
depends_on:
|
||||||
maria_db:
|
maria_db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
@ -44,6 +45,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./logs:/app/logs
|
- ./logs:/app/logs
|
||||||
- ./storedContent:/app/data
|
- ./storedContent:/app/data
|
||||||
|
- ./activeConfig:/app/config
|
||||||
depends_on:
|
depends_on:
|
||||||
maria_db:
|
maria_db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
@ -60,6 +62,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./logs:/app/logs
|
- ./logs:/app/logs
|
||||||
- ./storedContent:/app/data
|
- ./storedContent:/app/data
|
||||||
|
- ./activeConfig:/app/config
|
||||||
depends_on:
|
depends_on:
|
||||||
maria_db:
|
maria_db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue