Skip to content
This repository was archived by the owner on Nov 15, 2021. It is now read-only.

Adds sendmany feature to Prompt.py #610

Merged
merged 46 commits into from
Oct 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
af4604d
Update CHANGELOG.rst
jseagrave21 Sep 14, 2018
6afb312
Add get_outgoing and get_change_addr
jseagrave21 Sep 14, 2018
ba461b5
Add support for sendmany
jseagrave21 Sep 14, 2018
76a78b1
Add construct_and_send_many
jseagrave21 Sep 14, 2018
c44e3c6
Add tests for sendmany
jseagrave21 Sep 14, 2018
ac62558
Update CHANGELOG.rst
jseagrave21 Sep 14, 2018
84be107
Add tests for sendmany
jseagrave21 Sep 14, 2018
d896786
Add construct_and_send_many
jseagrave21 Sep 14, 2018
d597d9a
Add more tests for sendmany
jseagrave21 Sep 14, 2018
6f7dd84
Add a couple more tests for sendmany
jseagrave21 Sep 14, 2018
96f86db
Update CHANGELOG.rst
jseagrave21 Oct 5, 2018
a790241
Update test_send_command.py
jseagrave21 Oct 5, 2018
76df6e2
Merge pull request #33 from CityOfZion/development
jseagrave21 Oct 5, 2018
1946f31
Update CHANGELOG.rst
jseagrave21 Oct 5, 2018
84a44eb
Update Send.py
jseagrave21 Oct 5, 2018
bcbfd90
Update test_send_command.py
jseagrave21 Oct 5, 2018
f57ee4f
Update prompt.py
jseagrave21 Oct 5, 2018
0ef8620
Add provision if outgoing is None
jseagrave21 Oct 5, 2018
fdc3aef
Update test_send_command.py
jseagrave21 Oct 5, 2018
e3dfed5
Update CHANGELOG.rst
jseagrave21 Oct 9, 2018
17fdc3a
Update Send.py
jseagrave21 Oct 9, 2018
c808041
Update Send.py
jseagrave21 Oct 9, 2018
baeca78
Update Send.py
jseagrave21 Oct 9, 2018
d46593d
Update Send.py
jseagrave21 Oct 9, 2018
5479bbb
Update prompt.py
jseagrave21 Oct 9, 2018
4631795
Merge pull request #37 from CityOfZion/development
jseagrave21 Oct 9, 2018
d8c1432
Update CHANGELOG.rst
jseagrave21 Oct 9, 2018
8561376
Update Utils.py
jseagrave21 Oct 9, 2018
59efd25
Update Send.py
jseagrave21 Oct 9, 2018
dd4667c
Update test_send_command.py
jseagrave21 Oct 9, 2018
5cacbbd
Update prompt.py
jseagrave21 Oct 9, 2018
ee6c37c
Update Send.py
jseagrave21 Oct 9, 2018
6e35e68
Improve `sendmany` description
jseagrave21 Oct 9, 2018
2dd0c29
Remove unused `prompter` argument
jseagrave21 Oct 9, 2018
047db6c
Update test_send_command.py
jseagrave21 Oct 9, 2018
4117b85
Update prompt.py
jseagrave21 Oct 9, 2018
6a59681
Simplify `sendmany` description further
jseagrave21 Oct 9, 2018
984c9b3
Remove `get_outgoing`
jseagrave21 Oct 9, 2018
a54e3ce
Update Send.py
jseagrave21 Oct 9, 2018
b528e23
Update test_send_command.py
jseagrave21 Oct 9, 2018
72255f1
Update Send.py
jseagrave21 Oct 9, 2018
9e33cfd
Update CHANGELOG.rst
jseagrave21 Oct 10, 2018
5a7eb9a
Merge pull request #39 from CityOfZion/development
jseagrave21 Oct 10, 2018
295ee3a
Update CHANGELOG.rst
jseagrave21 Oct 10, 2018
ed6e3a1
Update Send.py
jseagrave21 Oct 10, 2018
25b9e71
Update test_send_command.py
jseagrave21 Oct 10, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project are documented in this file.
- Add ExtendedJsonRpcApi, Add ``getnodestate`` RPC extended method, Add ``gettxhistory`` RPC extended method
- Fix return types of ``claimGas`` function.
- Update compiler version ``v0.5.4``
- Adds ``sendmany`` feature to prompt.py, integrates with ``send`` feature, and adds provisions for sending with a negative fee and bad from_address

[0.8.1] 2018-10-06
------------------
Expand Down
196 changes: 136 additions & 60 deletions neo/Prompt/Commands/Send.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from neo.Core.TX.TransactionAttribute import TransactionAttribute, TransactionAttributeUsage
from neo.SmartContract.ContractParameterContext import ContractParametersContext
from neo.Network.NodeLeader import NodeLeader
from neo.Prompt.Utils import get_arg, get_from_addr, get_asset_id, lookup_addr_str, get_tx_attr_from_args, get_owners_from_params, get_fee
from neo.Prompt.Utils import get_arg, get_from_addr, get_asset_id, lookup_addr_str, get_tx_attr_from_args, \
get_owners_from_params, get_fee, get_change_addr, get_asset_amount
from neo.Prompt.Commands.Tokens import do_token_transfer, amount_from_string
from neo.Prompt.Commands.Invoke import gather_signatures
from neo.Wallets.NEP5Token import NEP5Token
Expand All @@ -12,87 +13,160 @@
import json
from prompt_toolkit import prompt
import traceback


def construct_and_send(prompter, wallet, arguments, prompt_password=True):
try:
if not wallet:
print("please open a wallet")
return False
if len(arguments) < 3:
print("Not enough arguments")
from logzero import logger


def construct_send_basic(wallet, arguments):
if not wallet:
print("please open a wallet")
return False
if len(arguments) < 3:
print("Not enough arguments")
return False

arguments, from_address = get_from_addr(arguments)
arguments, priority_fee = get_fee(arguments)
arguments, user_tx_attributes = get_tx_attr_from_args(arguments)
arguments, owners = get_owners_from_params(arguments)
to_send = get_arg(arguments)
address_to = get_arg(arguments, 1)
amount = get_arg(arguments, 2)

assetId = get_asset_id(wallet, to_send)
if assetId is None:
print("Asset id not found")
return False

scripthash_to = lookup_addr_str(wallet, address_to)
if scripthash_to is None:
logger.debug("invalid address")
return False

scripthash_from = None
if from_address is not None:
scripthash_from = lookup_addr_str(wallet, from_address)
if scripthash_from is None:
logger.debug("invalid address")
return False

arguments, from_address = get_from_addr(arguments)
arguments, user_tx_attributes = get_tx_attr_from_args(arguments)
arguments, owners = get_owners_from_params(arguments)
arguments, priority_fee = get_fee(arguments)
to_send = get_arg(arguments)
address_to = get_arg(arguments, 1)
amount = get_arg(arguments, 2)

try:
if float(amount) == 0:
print("amount cannot be 0")
return False
except ValueError:
# float parse error
# if this is a token, we will use a different
# transfer mechanism
if type(assetId) is NEP5Token:
return do_token_transfer(assetId, wallet, from_address, address_to, amount_from_string(assetId, amount), tx_attributes=user_tx_attributes)

f8amount = get_asset_amount(amount, assetId)
if f8amount is False:
logger.debug("invalid amount")
return False
if float(amount) == 0:
print("amount cannot be 0")
return False

fee = Fixed8.Zero()
if priority_fee is not None:
fee = priority_fee
if fee is False:
logger.debug("invalid fee")
return False

output = TransactionOutput(AssetId=assetId, Value=f8amount, script_hash=scripthash_to)
contract_tx = ContractTransaction(outputs=[output])
return [contract_tx, scripthash_from, fee, owners, user_tx_attributes]


def construct_send_many(wallet, arguments):
if not wallet:
print("please open a wallet")
return False
if len(arguments) is 0:
print("Not enough arguments")
return False

outgoing = get_arg(arguments, convert_to_int=True)
if outgoing is None:
print("invalid outgoing number")
return False
if outgoing < 1:
print("outgoing number must be >= 1")
return False

arguments, from_address = get_from_addr(arguments)
arguments, change_address = get_change_addr(arguments)
arguments, priority_fee = get_fee(arguments)
arguments, owners = get_owners_from_params(arguments)
arguments, user_tx_attributes = get_tx_attr_from_args(arguments)

output = []
for i in range(outgoing):
print('Outgoing Number ', i + 1)
to_send = prompt("Asset to send: ")
assetId = get_asset_id(wallet, to_send)

if assetId is None:
print("Asset id not found")
return False

if type(assetId) is NEP5Token:
print('Sendmany does not support NEP5 tokens')
return False
address_to = prompt("Address to: ")
scripthash_to = lookup_addr_str(wallet, address_to)
if scripthash_to is None:
print("invalid address")
logger.debug("invalid address")
return False
amount = prompt("Amount to send: ")
f8amount = get_asset_amount(amount, assetId)
if f8amount is False:
logger.debug("invalid amount")
return False
if float(amount) == 0:
print("amount cannot be 0")
return False
tx_output = TransactionOutput(AssetId=assetId, Value=f8amount, script_hash=scripthash_to)
output.append(tx_output)
contract_tx = ContractTransaction(outputs=output)

scripthash_from = None
scripthash_from = None

if from_address is not None:
scripthash_from = lookup_addr_str(wallet, from_address)
if from_address is not None:
scripthash_from = lookup_addr_str(wallet, from_address)
if scripthash_from is None:
logger.debug("invalid address")
return False

# if this is a token, we will use a different
# transfer mechanism
if type(assetId) is NEP5Token:
return do_token_transfer(assetId, wallet, from_address, address_to, amount_from_string(assetId, amount), prompt_passwd=prompt_password, tx_attributes=user_tx_attributes)
scripthash_change = None

f8amount = Fixed8.TryParse(amount, require_positive=True)
if f8amount is None:
print("invalid amount format")
if change_address is not None:
scripthash_change = lookup_addr_str(wallet, change_address)
if scripthash_change is None:
logger.debug("invalid address")
return False

if type(assetId) is UInt256 and f8amount.value % pow(10, 8 - Blockchain.Default().GetAssetState(assetId.ToBytes()).Precision) != 0:
print("incorrect amount precision")
fee = Fixed8.Zero()
if priority_fee is not None:
fee = priority_fee
if fee is False:
logger.debug("invalid fee")
return False

fee = Fixed8.Zero()
if priority_fee is not None:
fee = priority_fee
print("sending with fee: %s " % fee.ToString())
return [contract_tx, scripthash_from, scripthash_change, fee, owners, user_tx_attributes]

print("sending with fee: %s " % fee.ToString())

output = TransactionOutput(AssetId=assetId, Value=f8amount, script_hash=scripthash_to)
tx = ContractTransaction(outputs=[output])

ttx = wallet.MakeTransaction(tx=tx,
change_address=None,
fee=fee,
from_addr=scripthash_from)
def process_transaction(wallet, contract_tx, scripthash_from=None, scripthash_change=None, fee=None, owners=None, user_tx_attributes=None):
try:
tx = wallet.MakeTransaction(tx=contract_tx,
change_address=scripthash_change,
fee=fee,
from_addr=scripthash_from)

if ttx is None:
print("insufficient funds")
if tx is None:
logger.debug("insufficient funds")
return False

if prompt_password:
passwd = prompt("[Password]> ", is_password=True)

if not wallet.ValidatePassword(passwd):
print("incorrect password")
return False
# password prompt
passwd = prompt("[Password]> ", is_password=True)
if not wallet.ValidatePassword(passwd):
print("incorrect password")
return False

standard_contract = wallet.GetStandardAddress()

Expand All @@ -102,6 +176,7 @@ def construct_and_send(prompter, wallet, arguments, prompt_password=True):
signer_contract = wallet.GetContract(standard_contract)

if not signer_contract.IsMultiSigContract and owners is None:

data = standard_contract.Data
tx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script,
data=data)]
Expand All @@ -126,7 +201,7 @@ def construct_and_send(prompter, wallet, arguments, prompt_password=True):

tx.scripts = context.GetScripts()

# print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4))
# print("will send tx: %s " % json.dumps(tx.ToJson(),indent=4))

relayed = NodeLeader.Instance().Relay(tx)

Expand All @@ -152,7 +227,8 @@ def construct_and_send(prompter, wallet, arguments, prompt_password=True):
return False


def parse_and_sign(prompter, wallet, jsn):
def parse_and_sign(wallet, jsn):

try:
context = ContractParametersContext.FromJson(jsn)
if context is None:
Expand Down
Loading