def command_start(message): cid = message.chat.id tid = message.from_user.id tid_sql = sql_base.sqlrequest("SELECT tid FROM users WHERE tid='" + str(tid) + "'") if tid_sql is None: create = MinterWallet.create() address = create['address'] mnemonic = create['mnemonic'] mnstr = base64.urlsafe_b64encode(mnemonic.encode("utf-8")) mnstr = str(mnstr, "utf-8") create1 = MinterWallet.create() address1 = create1['address'] mnemonic1 = create1['mnemonic'] mnstr1 = base64.urlsafe_b64encode(mnemonic1.encode("utf-8")) mnstr1 = str(mnstr1, "utf-8") sql_base.sqlupdate( "INSERT INTO users (tid, addresses, mnemonics, pettiness) VALUES ('" + str(tid) + "', '" + str(address) + "', '" + str(mnstr) + "', '" + str(address1) + ',' + str(mnstr1) + "')") keyb = ReplyKeyboardMarkup(resize_keyboard=True) keyb.add('Главная', 'События') keyb.add('Оплатить', 'Ещё') bot.send_message(cid, 'Привет!', reply_markup=keyb, parse_mode='markdown')
def __init__(self, seed, pk=None, node=None): self.seed = seed self.private_key = pk or MinterWallet.create( mnemonic=seed)['private_key'] self.address = MinterWallet.create(mnemonic=seed)['address'] self.node = node self.API = MinterAPI(node['url'], headers=node['headers'], **node['timeouts']) if node else default_API
def send_coins(wallet: PushWallet, to=None, amount=None, payload='', wait=True, gas_coin=None): private_key = MinterWallet.create(mnemonic=wallet.mnemonic)['private_key'] response = NodeAPI.get_balance(wallet.address) nonce = int(response['transaction_count']) + 1 balances = response['balance'] balances_bip = effective_balance(balances) main_coin, main_balance_bip = max(balances_bip.items(), key=lambda i: i[1]) main_balance = float(to_bip(balances[main_coin])) gas_coin, tx_fee = find_gas_coin(balances, get_fee=True, payload=payload) gas_coin_balance = float(to_bip(balances.get(gas_coin, 0))) if not gas_coin or not tx_fee or gas_coin_balance < tx_fee: return 'Not enough balance to pay commission' tx_fee = float(tx_fee) # если в обычной пересылке пришлют сумму без учета комиссии - не будем мучать ошибками amount = main_balance - tx_fee if amount == truncate(main_balance, 4) \ and gas_coin == main_coin and not payload else amount tx_fee = tx_fee if gas_coin == main_coin else 0 if amount > main_balance - tx_fee: return 'Not enough balance' tx = send_coin_tx(private_key, main_coin, amount, to, nonce, payload=payload, gas_coin=gas_coin) NodeAPI.send_tx(tx, wait=wait) return True
def mobile_top_up(wallet: PushWallet, phone=None, amount=None): phone_reqs = get_tx_requirements(phone) if not phone_reqs: return False response = API.get_balance(wallet.address) balance = response['balance'] nonce = int(response['transaction_count']) + 1 bip_values = calc_bip_values(balance) total_bip = sum(bip_values.values()) to_send = amount or total_bip private_key = MinterWallet.create(mnemonic=wallet.mnemonic)['private_key'] tx = send_coin_tx(private_key, 'BIP', to_send, BIP2PHONE_PAYMENT_ADDRESS, nonce, payload=phone_reqs['payload']) fee = to_bip(tx.get_fee()) if to_send < phone_reqs['min_bip_value'] + fee: return False tx = send_coin_tx(private_key, 'BIP', to_send - fee, BIP2PHONE_PAYMENT_ADDRESS, nonce, payload=phone_reqs['payload']) API.send_tx(tx, wait=True) return True
def send_chat_detail(client: Client, chat: AllowedChat, user, root_message_id): chat.refresh_from_db() w = MinterWallet.create() chat_wallet, _ = ChatWallet.objects.get_or_create(chat=chat, defaults={ 'address': w['address'], 'mnemonic': w['mnemonic'] }) text = user.choice_localized(text_name='msg-owner-chat').format( address=chat_wallet.address, mnemonic=chat_wallet.mnemonic, coin=chat.coin, balances=chat_wallet.balance_formatted) btn_texts = { 'ulimit': user.choice_localized(text_name='btn-chat-setting-ulimit'), 'climit': user.choice_localized(text_name='btn-chat-setting-climit'), 'dt': user.choice_localized(text_name='btn-chat-setting-dt'), 'back': user.choice_localized(text_name='btn-chat-setting-back') } client.edit_message_text(user.id, root_message_id, text, reply_markup=markup_chat_actions(chat, btn_texts))
def get_sender_address(cls, tx): """ Get sender address from tx. Recover public key from tx and then get address from public key, if tx has single signature type, or get decoded sender address, if tx has multi signature type. Args: tx (dict): transaction dict Returns: Minter address (string) """ # Remember signature data and remove it from tx signature_data = tx.pop('signature_data') # If there is sender address in signature data (multi signature tx), return it if signature_data.get('from_mx'): return signature_data['from_mx'] # Otherwise (single signature tx), recover public key and get address from public key # Unhexlify (convert to bin (ascii)) all non-numeric dict values tx = MinterHelper.hex2bin_recursive(tx) # Encode tx data to RLP tx['data'] = rlp.encode(list(tx['data'].values())) # Message tx_rlp = rlp.encode(list(tx.values())) _keccak = MinterHelper.keccak_hash(tx_rlp) # Recover public key public_key = MinterPrefix.PUBLIC_KEY + ECDSA.recover(_keccak, tuple(signature_data.values())) return MinterWallet.get_address_from_public_key(public_key)
def get_user_model(tg_user: tgUser): lang_pk = {'ru': 1, 'en': 2} user_lang = (getattr(tg_user, 'language_code', None) or DEFAULT_LANGUAGE).split("-")[0] user_lang = DEFAULT_LANGUAGE if user_lang not in SUPPORTED_LANGUAGES else user_lang user_lang_model = Language.objects.get(pk=lang_pk[user_lang]) user, is_created = User.objects.get_or_create(id=tg_user.id, defaults={ 'last_name': tg_user.last_name, 'first_name': tg_user.first_name, 'username': tg_user.username, 'language': user_lang_model }) wallet = MinterWallet.create() MinterWallets.objects.get_or_create(user=user, defaults={ 'address': wallet['address'], 'mnemonic': wallet['mnemonic'] }) # try change lang when user changes lang # if not is_created and user.language != user_lang_model: # user.language = user_lang_model # user.save() return user, is_created
def decorator(*args, **kwargs): update = args[0] username = update.effective_user.username uid = update.effective_user.id first_name = update.effective_user.first_name last_name = update.effective_user.last_name user, is_created = Users.get_or_create(telegram_id=uid) user.first_name = first_name user.last_name = last_name user.username = username user.last_active_dt = dt.now() if is_created: user.created_dt = dt.now() if not user.wallets: w = MinterWallet.create() wallet = Wallet.create(user=user, mnemonic=w['mnemonic'], address=w['address'], balance=0) wallet.save() user.save() new_args = list(args) new_args.append(user) logger.info('Entering: %s', func.__name__) for a in new_args: logger.info(a) for k in kwargs: logger.info(k) return func(*new_args, **kwargs)
def estimate_custom_send_fee(coin): wallet = MinterWallet.create() send_tx = MinterSendCoinTx(coin, wallet['address'], 0, nonce=0, gas_coin=coin) send_tx.sign(wallet['private_key']) return API.estimate_tx_commission(send_tx.signed_tx, pip2bip=True)['result']['commission']
def generate_and_save_wallet(**kwargs): password = kwargs.pop('password', None) password_hash = pbkdf2_sha256.hash(password) if password is not None else None link_id = uuid() wallet = MinterWallet.create() return PushWallet.create( link_id=link_id, address=wallet['address'], mnemonic=wallet['mnemonic'], password_hash=password_hash, **kwargs)
def handle(self, **options): mnemonic = ' '.join(options.get('mnemonic', [])) or None mdl = Tools.objects.first() if mdl: mdl.delete() wallet = MinterWallet.create(mnemonic=mnemonic) Tools.objects.create( mnemonic=mnemonic, address=wallet['address'])
def post(self) -> Tuple[dict, int]: mnemonic = request.json.get('mnemonic') wallet = MinterWallet.create(mnemonic=mnemonic) proof = MinterCheck.proof( address=wallet['address'], passphrase='mnemonic') with DBEngine() as db_engine: db_engine.insert( table='wallets', data=[{ 'verification_id': 1 }])
def from_raw(cls, rawcheck): """ Create check instance from raw check Args: rawcheck (str) Returns: MinterCheck """ # Remove check prefix and RLP decode it rawcheck = MinterPrefix.remove_prefix( string=rawcheck, prefix=MinterPrefix.CHECK ) rawcheck = binascii.unhexlify(rawcheck) decoded = rlp.decode(rawcheck) # Create MinterCheck instance kwargs = { 'nonce': int(decoded[0].decode()), 'chain_id': MinterHelper.bin2int(decoded[1]), 'due_block': MinterHelper.bin2int(decoded[2]), 'coin': MinterConvertor.decode_coin_name(decoded[3]), 'value': MinterConvertor.convert_value( value=MinterHelper.bin2int(decoded[4]), to='bip' ), 'lock': binascii.hexlify(decoded[5]).decode(), 'signature': { 'v': MinterHelper.bin2int(decoded[6]), 'r': MinterHelper.bin2hex(decoded[7]), 's': MinterHelper.bin2hex(decoded[8]) } } check = MinterCheck(**kwargs) # Recover owner address msg_hash = cls.__hash(data=[ int(binascii.hexlify(str(check.nonce).encode()), 16), check.chain_id, check.due_block, MinterConvertor.encode_coin_name(check.coin), MinterConvertor.convert_value(value=check.value, to='pip'), MinterHelper.hex2bin(check.lock) ]) public_key = ECDSA.recover(msg_hash, list(check.signature.values())) public_key = MinterPrefix.PUBLIC_KEY + public_key check.owner = MinterWallet.get_address_from_public_key(public_key) return check
def estimate_custom_fee(coin): if coin == BASE_COIN: return Decimal('0.01') coin_info = NodeAPI.get_coin_info(coin) if coin_info['reserve_balance'] < to_pip(MIN_RESERVE_BIP + 0.01): return w = MinterWallet.create() tx = send_coin_tx(w['private_key'], coin, 0, w['address'], 1, gas_coin=coin) return to_bip(NodeAPI.estimate_tx_commission(tx.signed_tx)['commission'])
def _send_from_user(wallet_from, address_to, amount, coin='BIP'): pkey = MinterWallet.create(mnemonic=wallet_from.mnemonic)['private_key'] nonce = api.get_nonce(wallet_from.address) tx = MinterSendCoinTx(to=address_to, value=amount, coin=coin, nonce=nonce, gas_coin=coin) tx.sign(pkey) r = api.send_transaction(tx.signed_tx) info('API send tx response:') info(pformat(r)) return nonce + 1
def send_coins(wallet: PushWallet, to=None, amount=None): private_key = MinterWallet.create(mnemonic=wallet.mnemonic)['private_key'] response = API.get_balance(wallet.address) nonce = int(response['transaction_count']) + 1 balance_bip = float(to_bip(response['balance']['BIP'])) # если вдруг пришлют сумму без учета комиссии - не будем мучать ошибками) amount = amount - 0.01 if amount == balance_bip else amount if amount > balance_bip - 0.01: return False tx = send_coin_tx(private_key, 'BIP', amount, to, nonce) API.send_tx(tx, wait=True) return True
def create_user(chat_id): temp = exists_user(chat_id) if temp == None: wallet = MinterWallet.create() address = wallet["address"] tx = MinterSendCoinTx(coin='LIKE', to=address, value=10, gas_coin='BIP', gas_price=1,nonce=1) dl = MinterDeeplink(tx=tx) dl.nonce = '' dl.value = '' url_link = dl.generate() cursor.execute('INSERT INTO users (chatid,address,privatekey,mnemo,deeplink) VALUES {};'.format( (chat_id, wallet["address"], wallet["private_key"], wallet["mnemonic"],url_link) )) conn.commit() return (chat_id, wallet["address"], wallet["private_key"], wallet["mnemonic"],url_link) return temp
def from_raw(cls, rawcheck): """ Create check instance from raw check Args: rawcheck (str) Returns: MinterCheck """ # Remove check prefix and RLP decode it rawcheck = MinterHelper.prefix_remove(rawcheck) rawcheck = bytes.fromhex(rawcheck) decoded = rlp.decode(rawcheck) # Create MinterCheck instance kwargs = { 'nonce': int(decoded[0].decode()), 'chain_id': int.from_bytes(decoded[1], 'big'), 'due_block': int.from_bytes(decoded[2], 'big'), 'coin': MinterHelper.decode_coin_name(decoded[3]), 'value': MinterHelper.to_bip(int.from_bytes(decoded[4], 'big')), 'gas_coin': MinterHelper.decode_coin_name(decoded[5]), 'lock': decoded[6].hex(), 'signature': { 'v': int.from_bytes(decoded[7], 'big'), 'r': decoded[8].hex(), 's': decoded[9].hex() } } check = MinterCheck(**kwargs) # Recover owner address msg_hash = cls.__hash(data=[ int(str(check.nonce).encode().hex(), 16), check.chain_id, check.due_block, MinterHelper.encode_coin_name(check.coin), MinterHelper.to_pip(check.value), MinterHelper.encode_coin_name(check.gas_coin), bytes.fromhex(check.lock) ]) public_key = ECDSA.recover(msg_hash, tuple(check.signature.values())) public_key = MinterHelper.prefix_add(public_key, PREFIX_PUBKEY) check.owner = MinterWallet.get_address_from_public_key(public_key) return check
def post(self): args = parser_campaign_create.parse_args() count = args['count'] coin = args['action_coin'] name = args['name'] action_type = args['action_type'] action_reward = args['action_reward'] action_link = args['action_link'] action_duration = args['action_duration'] action = { 'type': action_type, 'reward': action_reward, 'link': action_link, 'duration': action_duration } campaign_id = uuid() wallet = MinterWallet.create() action_reward = float(action['reward']) one_tx_fee = float(estimate_custom_fee(coin) or 0) campaign_cost = (action_reward + one_tx_fee) * count deeplink = TxDeeplink.create('send', to=wallet['address'], value=campaign_cost, coin=coin) icon_storage = args['icon'] filename = images.save( icon_storage, name=f'{campaign_id}.{extension(icon_storage.filename)}') icon = RewardIcon.create(filename=filename, url=images.url(filename)) RewardCampaign.create(link_id=campaign_id, address=wallet['address'], mnemonic=wallet['mnemonic'], name=name, count=count, coin=coin, action_type=action['type'], action_reward=to_pip(action_reward), action_params=action, icon=icon) return { 'id': campaign_id, 'address': wallet['address'], 'deeplink': deeplink.web }
def mobile_top_up(wallet: PushWallet, phone=None, amount=None, confirm=True): if not confirm: return get_info() phone_reqs = get_tx_requirements(phone) if not phone_reqs: return f'Phone number {phone} not supported or invalid' response = NodeAPI.get_balance(wallet.address) balance = response['balance'] balances_bip = effective_balance(balance) main_coin, main_balance_bip = max(balances_bip.items(), key=lambda i: i[1]) balance_coin = to_bip(balance[main_coin]) nonce = int(response['transaction_count']) + 1 to_send = amount or balance_coin private_key = MinterWallet.create(mnemonic=wallet.mnemonic)['private_key'] gas_coin = find_gas_coin(balance) if not gas_coin: return 'Coin not spendable. Send any coin to pay fee' # fee = estimate_custom_fee(gas_coin) min_topup = phone_reqs['min_bip_value'] effective_topup = rub_to_bip( to_send) if main_coin == 'ROUBLE' else main_balance_bip if balance_coin < to_send: return 'Not enough balance' if effective_topup < min_topup: return f"Minimal top-up: {min_topup} BIP" tx = send_coin_tx(private_key, main_coin, to_send, BIP2PHONE_PAYMENT_ADDRESS, nonce, payload=phone_reqs['payload'], gas_coin=gas_coin) try: NodeAPI.send_tx(tx, wait=True) except MinterAPIException as exc: return exc.message return True
def timeloop(client: Client, call: CallbackQuery): user, _ = get_user_model(call.from_user) coin = 'TIME' wallet = MinterWallets.objects.get(user=user) wallet_obj = MinterWallet.create(mnemonic=wallet.mnemonic) amount = wallet.balance[coin] nonce = API.get_nonce(wallet.address) send_tx = MinterSendCoinTx(coin, wallet.address, amount, nonce=nonce, gas_coin=coin) send_tx.sign(wallet_obj['private_key']) tx_fee = API.estimate_tx_commission(send_tx.signed_tx, pip2bip=True)['result']['commission'] available_send = amount - tx_fee user_timeloop_address = call.data.split('_')[-1] if not user_timeloop_address: alert_text = user.choice_localized(text_name='alert-tl-no-account') client.answer_callback_query(call.id, text=alert_text) return if available_send <= 0: alert_text = user.choice_localized(text_name='alert-tl-no-money') client.answer_callback_query(call.id, text=alert_text) return response = coin_send(wallet_obj['private_key'], wallet_obj['address'], user_timeloop_address, coin, available_send, gas_coin=coin) if 'error' in response: alert_text = user.choice_localized(text_name='alert-tl-no-money') client.answer_callback_query(call.id, text=alert_text) return alert_text = user.choice_localized(text_name='alert-tl-success') client.answer_callback_query(call.id, text=alert_text)
def local_chat_pay(): settings = Tools.objects.get(pk=1) gift = Payment.objects.filter(is_payed=False, wallet_local__isnull=False).first() if not gift: return logging.info(f'Local gift payment ({gift.wallet_local.chat.title_chat}):') wallet = MinterWallet.create(mnemonic=gift.wallet_local.mnemonic) gas_coin = find_gas_coin(wallet['address']) response = coin_send(wallet['private_key'], wallet['address'], gift.to, gift.coin, gift.amount, gas_coin=gas_coin, payload=settings.payload + ' (chat owner bonus)') if 'error' not in response: gift.is_payed = True gift.save()
def generate_push(campaign): response = NodeAPI.get_balance(campaign.address) balances = response['balance'] campaign_balance = to_bip(balances.get(campaign.coin, '0')) if not campaign_balance: logging.info( f'Campaign {campaign.link_id} {campaign.name}: balance too low {campaign_balance}' ) return tx_fee = estimate_custom_fee(campaign.coin) reward = to_bip(campaign.action_reward) if campaign_balance < reward + tx_fee: logging.info( f'Campaign {campaign.link_id} {campaign.name}: balance too low {campaign_balance}' ) return push = generate_and_save_wallet() private_key = MinterWallet.create( mnemonic=campaign.mnemonic)['private_key'] nonce = int(response['transaction_count']) + 1 tx = send_coin_tx(private_key, campaign.coin, reward + tx_fee, push.address, nonce, gas_coin=campaign.coin) NodeAPI.send_tx(tx, wait=True) logging.info( f'Campaign {campaign.link_id} {campaign.name} rewarded {reward} {campaign.coin}, fee {tx_fee}' ) campaign.times_completed += 1 if campaign.times_completed == campaign.count: campaign.status = 'close' logging.info(f'Campaign {campaign.link_id} {campaign.name} finished!') campaign.save() return YYY_PUSH_URL + push.link_id
def send_coins(app, message, sender, receiver=None): parse_result = parse_send_coins(app, message) if not parse_result: return amount, coin, recipients = parse_result if not receiver and not recipients: return if receiver: recipients = [receiver] else: recipients = [u for u, _ in get_user_model_many(recipients)] w_from = MinterWallets.objects.get(user=sender) mw_from = MinterWallet.create(w_from.mnemonic) recipients_addresses = [ mw.address for mw in MinterWallets.objects.filter(user__in=recipients) ] minter_send_coins.delay(mw_from, recipients_addresses, coin, amount, message.chat.id, sender.id, [u.id for u in recipients])
def mobile_top_up(wallet: PushWallet, phone=None, amount=None, confirm=True): if not confirm: return get_info() amount = float(amount) phone_reqs = get_tx_requirements(phone) if not phone_reqs: return f'Phone number {phone} not supported or invalid' response = MscanAPI.get_balance(wallet.address) balance = response['balance'] available_bip = float(to_bip(balance['BIP'])) nonce = int(response['transaction_count']) + 1 to_send = amount or available_bip private_key = MinterWallet.create(mnemonic=wallet.mnemonic)['private_key'] tx = send_coin_tx(private_key, 'BIP', to_send, BIP2PHONE_PAYMENT_ADDRESS, nonce, payload=phone_reqs['payload']) fee = to_bip(tx.get_fee()) min_topup = phone_reqs['min_bip_value'] + fee effective_topup = Decimal(to_send) - fee if available_bip < to_send: return 'Not enough balance' if effective_topup < min_topup: return f"Minimal top-up: {min_topup} BIP" tx = send_coin_tx(private_key, 'BIP', effective_topup, BIP2PHONE_PAYMENT_ADDRESS, nonce, payload=phone_reqs['payload']) MscanAPI.send_tx(tx, wait=True) return True
def make_multisend_list_and_pay(): multisend_list = [] gifts = Payment.objects.filter( is_payed=False, wallet_local=None)[:PAYMENT_JOB_MAX_MULTISEND] if not gifts: logger.info(f'No events to pay') return settings = Tools.objects.get(pk=1) wallet_from = MinterWallet.create(mnemonic=settings.mnemonic) if len(gifts) == 1: g = gifts[0] response = coin_send(wallet_from['private_key'], wallet_from['address'], g.to, g.coin, g.amount, gas_coin=g.coin, payload=settings.payload) if 'error' not in response: g.is_payed = True g.save() return for g in gifts: multisend_list.append({'coin': g.coin, 'to': g.to, 'value': g.amount}) g.is_payed = True response = coin_multisend(wallet_from['private_key'], wallet_from['address'], multisend_list, gas_coin=settings.coin, payload=settings.payload) if 'error' not in response: Payment.objects.bulk_update(gifts, ['is_payed'])
def push_create(): """ swagger: swagger/core/push-create.yml """ payload = request.get_json() or {} sender, recipient = payload.get('sender'), payload.get('recipient') password = payload.get('password') amount = payload.get('amount') coin = payload.get('coin', 'BIP') customization_setting_id = payload.get('customization_setting_id') setting = CustomizationSetting.get_or_none(id=customization_setting_id) if not setting: jsonify({'error': 'Customization setting does not exist' }), HTTPStatus.BAD_REQUEST wallet = generate_and_save_wallet( sender=sender, recipient=recipient, password=password, customization_setting_id=customization_setting_id) response = {'address': wallet.address, 'link_id': wallet.link_id} if amount: w = MinterWallet.create() tx = send_coin_tx(w['private_key'], coin, float(amount), w['address'], 1, gas_coin=coin) tx_fee = float( to_bip(NodeAPI.estimate_tx_comission(tx.signed_tx)['commission'])) response['deeplink'] = TxDeeplink.create('send', to=wallet.address, value=float(amount) + tx_fee, coin=coin).mobile return jsonify(response)
def delete(self, campaign_id): campaign = RewardCampaign.get_or_none(link_id=campaign_id, status='open') if not campaign: return {}, HTTPStatus.NOT_FOUND response = NodeAPI.get_balance(campaign.address) balances = response['balance'] campaign_balance = to_bip(balances.get(campaign.coin, '0')) if campaign_balance: tx_fee = estimate_custom_fee(campaign.coin) gas_coin = find_gas_coin( balances) if tx_fee is None else campaign.coin if not gas_coin: return { 'error': f'Campaign coin not spendable.' f'Send any coin to campaign address {campaign.address} to pay fee' }, HTTPStatus.BAD_REQUEST private_key = MinterWallet.create( mnemonic=campaign.mnemonic)['private_key'] refund_address = get_first_transaction(campaign.address) nonce = int(response['transaction_count']) + 1 tx_fee = 0 if tx_fee is None else tx_fee tx = send_coin_tx(private_key, campaign.coin, campaign_balance - tx_fee, refund_address, nonce, gas_coin=campaign.coin) NodeAPI.send_tx(tx, wait=True) campaign.status = 'closed' campaign.save() return {'success': True}
# Second arg is always action with node action = sys.argv[2] if action not in ['on', 'off']: print('Specify correct tx action (on/off)') sys.exit(1) # Get params from user seed = getpass.getpass('Provide seed phrase (password like input): ') # When all data seems to be set, create txs try: # Get APIs minterapis = [MinterAPI(api_url) for api_url in api_urls] # Get wallet wallet = MinterWallet.create(mnemonic=seed) # Get nonce from API nonce = None for minterapi in minterapis: try: nonce = minterapi.get_nonce(address=wallet['address']) break except Exception as e: print(e.__str__()) if nonce is None: raise if action == 'on': # Set candidate on tx
def minter_wallet(self): return MinterWallet.create(mnemonic=self.mnemonic)