create offer and zero coin automatically
This commit is contained in:
parent
8c3cf2617d
commit
3752d466e8
|
@ -734,13 +734,17 @@ class CCWallet:
|
|||
full_spend = SpendBundle.aggregate([spend_bundle, eve_spend])
|
||||
return full_spend
|
||||
|
||||
async def create_spend_bundle_relative_amount(self, cc_amount):
|
||||
async def create_spend_bundle_relative_amount(self, cc_amount, zero_coin: Coin = None):
|
||||
# If we're losing value then get coloured coins with at least that much value
|
||||
# If we're gaining value then our amount doesn't matter
|
||||
if cc_amount < 0:
|
||||
cc_spends = await self.select_coins(abs(cc_amount))
|
||||
else:
|
||||
cc_spends = await self.select_coins(0)
|
||||
if zero_coin is None:
|
||||
return None
|
||||
cc_spends = set()
|
||||
cc_spends.add(zero_coin)
|
||||
|
||||
if cc_spends is None:
|
||||
return None
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import logging
|
|||
import clvm
|
||||
|
||||
from src.types.BLSSignature import BLSSignature
|
||||
from src.types.coin import Coin
|
||||
from src.types.coin_solution import CoinSolution
|
||||
from src.types.program import Program
|
||||
from src.types.sized_bytes import bytes32
|
||||
|
@ -52,13 +53,44 @@ class TradeManager:
|
|||
wallet_id = uint32(int(id))
|
||||
wallet = self.wallet_state_manager.wallets[wallet_id]
|
||||
if isinstance(wallet, CCWallet):
|
||||
new_spend_bundle = await wallet.create_spend_bundle_relative_amount(
|
||||
amount
|
||||
)
|
||||
balance = await wallet.get_confirmed_balance()
|
||||
if balance == 0:
|
||||
if spend_bundle is None:
|
||||
to_exclude = []
|
||||
else:
|
||||
to_exclude = spend_bundle.removals()
|
||||
zero_spend_bundle: SpendBundle = await wallet.generate_zero_val_coin(False, to_exclude)
|
||||
|
||||
if zero_spend_bundle is None:
|
||||
raise ValueError("Failed to generate offer. Zero value coin not created.")
|
||||
if spend_bundle is None:
|
||||
spend_bundle = zero_spend_bundle
|
||||
else:
|
||||
spend_bundle = SpendBundle.aggregate([spend_bundle, zero_spend_bundle])
|
||||
|
||||
additions = zero_spend_bundle.additions()
|
||||
removals = zero_spend_bundle.removals()
|
||||
zero_val_coin: Optional[Coin] = None
|
||||
for add in additions:
|
||||
if add not in removals and add.amount == 0:
|
||||
zero_val_coin = add
|
||||
|
||||
new_spend_bundle = await wallet.create_spend_bundle_relative_amount(
|
||||
amount, zero_val_coin
|
||||
)
|
||||
else:
|
||||
new_spend_bundle = await wallet.create_spend_bundle_relative_amount(
|
||||
amount
|
||||
)
|
||||
elif isinstance(wallet, Wallet):
|
||||
if spend_bundle is None:
|
||||
to_exclude = []
|
||||
else:
|
||||
to_exclude = spend_bundle.removals()
|
||||
new_spend_bundle = await wallet.create_spend_bundle_relative_chia(
|
||||
amount
|
||||
amount, to_exclude
|
||||
)
|
||||
self.log.info("1")
|
||||
else:
|
||||
return False, None
|
||||
if new_spend_bundle.removals() == [] or new_spend_bundle is None:
|
||||
|
@ -83,7 +115,6 @@ class TradeManager:
|
|||
try:
|
||||
self.log.info(f"trade offer: {file_path}")
|
||||
cc_discrepancies: Dict[bytes32, int] = dict()
|
||||
wallets: Dict[bytes32, Any] = dict()
|
||||
trade_offer_hex = file_path.read_text()
|
||||
trade_offer = SpendBundle.from_bytes(bytes.fromhex(trade_offer_hex))
|
||||
for coinsol in trade_offer.coin_solutions:
|
||||
|
@ -92,15 +123,6 @@ class TradeManager:
|
|||
|
||||
# work out the deficits between coin amount and expected output for each
|
||||
if cc_wallet_puzzles.check_is_cc_puzzle(puzzle):
|
||||
colour = cc_wallet_puzzles.get_genesis_from_puzzle(
|
||||
binutils.disassemble(puzzle)
|
||||
)
|
||||
if colour not in wallets:
|
||||
wallets[
|
||||
colour
|
||||
] = await self.wallet_state_manager.get_wallet_for_colour(
|
||||
colour
|
||||
)
|
||||
parent_info = binutils.disassemble(solution.rest().first()).split(
|
||||
" "
|
||||
)
|
||||
|
@ -121,20 +143,16 @@ class TradeManager:
|
|||
else:
|
||||
cc_discrepancies[colour] = coinsol.coin.amount - out_amount
|
||||
else: # standard chia coin
|
||||
if None in cc_discrepancies:
|
||||
cc_discrepancies["chia"] += (
|
||||
coinsol.coin.amount
|
||||
- cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution(
|
||||
puzzle, solution
|
||||
)
|
||||
coin_amount = coinsol.coin.amount
|
||||
out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution(
|
||||
puzzle, solution
|
||||
)
|
||||
diff = coin_amount - out_amount
|
||||
if "chia" in cc_discrepancies:
|
||||
cc_discrepancies["chia"] = cc_discrepancies["chia"] + diff
|
||||
else:
|
||||
cc_discrepancies["chia"] = (
|
||||
coinsol.coin.amount
|
||||
- cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution(
|
||||
puzzle, solution
|
||||
)
|
||||
)
|
||||
cc_discrepancies["chia"] = diff
|
||||
|
||||
return True, cc_discrepancies, None
|
||||
except Exception as e:
|
||||
return False, None, e
|
||||
|
@ -167,6 +185,7 @@ class TradeManager:
|
|||
# work out the deficits between coin amount and expected output for each
|
||||
if cc_wallet_puzzles.check_is_cc_puzzle(puzzle):
|
||||
parent_info = binutils.disassemble(solution.rest().first()).split(" ")
|
||||
|
||||
if len(parent_info) > 1:
|
||||
# Calculate output amounts
|
||||
colour = cc_wallet_puzzles.get_genesis_from_puzzle(
|
||||
|
@ -183,6 +202,7 @@ class TradeManager:
|
|||
out_amount = cc_wallet_puzzles.get_output_amount_for_puzzle_and_solution(
|
||||
innerpuzzlereveal, innersol
|
||||
)
|
||||
|
||||
if colour in cc_discrepancies:
|
||||
cc_discrepancies[colour] += coinsol.coin.amount - out_amount
|
||||
else:
|
||||
|
@ -212,6 +232,8 @@ class TradeManager:
|
|||
out_amount,
|
||||
)
|
||||
]
|
||||
else:
|
||||
coinsols.append(coinsol)
|
||||
else:
|
||||
# standard chia coin
|
||||
if chia_discrepancy is None:
|
||||
|
@ -227,7 +249,7 @@ class TradeManager:
|
|||
chia_spend_bundle: Optional[SpendBundle] = None
|
||||
if chia_discrepancy is not None:
|
||||
chia_spend_bundle = await self.wallet_state_manager.main_wallet.create_spend_bundle_relative_chia(
|
||||
chia_discrepancy
|
||||
chia_discrepancy, []
|
||||
)
|
||||
|
||||
zero_spend_list: List[SpendBundle] = []
|
||||
|
|
|
@ -362,16 +362,16 @@ class Wallet:
|
|||
# Create an offer spend bundle for chia given an amount of relative change (i.e -400 or 1000)
|
||||
|
||||
# This is to be aggregated together with a coloured coin offer to ensure that the trade happens
|
||||
async def create_spend_bundle_relative_chia(self, chia_amount: int):
|
||||
async def create_spend_bundle_relative_chia(self, chia_amount: int, exclude: List[Coin]):
|
||||
list_of_solutions = []
|
||||
utxos = None
|
||||
|
||||
# If we're losing value then get coins with at least that much value
|
||||
# If we're gaining value then our amount doesn't matter
|
||||
if chia_amount < 0:
|
||||
utxos = await self.select_coins(abs(chia_amount))
|
||||
utxos = await self.select_coins(abs(chia_amount), exclude)
|
||||
else:
|
||||
utxos = await self.select_coins(0)
|
||||
utxos = await self.select_coins(0, exclude)
|
||||
|
||||
if utxos is None:
|
||||
return None
|
||||
|
|
|
@ -582,3 +582,98 @@ class TestWalletSimulator:
|
|||
cc_2_unconfirmed_balance = await red_wallet.get_confirmed_balance()
|
||||
assert cc_2_confirmed_balance == 70
|
||||
assert cc_2_unconfirmed_balance == 70
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_offer_with_zero_val(self, two_wallet_nodes):
|
||||
num_blocks = 10
|
||||
full_nodes, wallets = two_wallet_nodes
|
||||
full_node_1, server_1 = full_nodes[0]
|
||||
wallet_node, server_2 = wallets[0]
|
||||
wallet_node_2, server_3 = wallets[1]
|
||||
wallet = wallet_node.wallet_state_manager.main_wallet
|
||||
wallet2 = wallet_node_2.wallet_state_manager.main_wallet
|
||||
|
||||
ph = await wallet.get_new_puzzlehash()
|
||||
ph2 = await wallet2.get_new_puzzlehash()
|
||||
|
||||
await server_2.start_client(PeerInfo("localhost", uint16(server_1._port)), None)
|
||||
await server_3.start_client(PeerInfo("localhost", uint16(server_1._port)), None)
|
||||
|
||||
for i in range(1, num_blocks):
|
||||
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
|
||||
|
||||
await asyncio.sleep(5)
|
||||
funds = sum(
|
||||
[
|
||||
calculate_base_fee(uint32(i)) + calculate_block_reward(uint32(i))
|
||||
for i in range(1, num_blocks - 2)
|
||||
]
|
||||
)
|
||||
|
||||
assert await wallet.get_confirmed_balance() == funds
|
||||
|
||||
cc_wallet: CCWallet = await CCWallet.create_new_cc(
|
||||
wallet_node.wallet_state_manager, wallet, uint64(100)
|
||||
)
|
||||
|
||||
for i in range(1, num_blocks):
|
||||
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
|
||||
|
||||
await asyncio.sleep(1)
|
||||
confirmed_balance = await cc_wallet.get_confirmed_balance()
|
||||
unconfirmed_balance = await cc_wallet.get_unconfirmed_balance()
|
||||
|
||||
assert confirmed_balance == 100
|
||||
assert unconfirmed_balance == 100
|
||||
|
||||
colour = cc_wallet_puzzles.get_genesis_from_core(cc_wallet.cc_info.my_core)
|
||||
|
||||
cc_wallet_2: CCWallet = await CCWallet.create_wallet_for_cc(
|
||||
wallet_node_2.wallet_state_manager, wallet2, colour
|
||||
)
|
||||
|
||||
assert cc_wallet.cc_info.my_core == cc_wallet_2.cc_info.my_core
|
||||
|
||||
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph2))
|
||||
for i in range(1, num_blocks):
|
||||
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
|
||||
|
||||
trade_manager_1 = await TradeManager.create(wallet_node.wallet_state_manager)
|
||||
trade_manager_2 = await TradeManager.create(wallet_node_2.wallet_state_manager)
|
||||
|
||||
file = "test_offer_file.offer"
|
||||
file_path = Path(file)
|
||||
|
||||
if file_path.exists():
|
||||
file_path.unlink()
|
||||
|
||||
offer_dict = {1: -10, 2: 30}
|
||||
|
||||
success, spend_bundle = await trade_manager_2.create_offer_for_ids(offer_dict)
|
||||
|
||||
assert success is True
|
||||
assert spend_bundle is not None
|
||||
trade_manager_2.write_offer_to_disk(file_path, spend_bundle)
|
||||
|
||||
success, offer, error = await trade_manager_1.get_discrepancies_for_offer(file_path)
|
||||
|
||||
assert error is None
|
||||
assert success is True
|
||||
assert offer is not None
|
||||
|
||||
assert offer["chia"] == 10
|
||||
assert offer[colour] == -30
|
||||
|
||||
success = await trade_manager_1.respond_to_offer(file_path)
|
||||
|
||||
assert success is True
|
||||
|
||||
for i in range(0, 4):
|
||||
await full_node_1.farm_new_block(FarmNewBlockProtocol(token_bytes()))
|
||||
|
||||
await asyncio.sleep(5)
|
||||
cc_2_confirmed_balance = await cc_wallet_2.get_confirmed_balance()
|
||||
cc_2_unconfirmed_balance = await cc_wallet_2.get_confirmed_balance()
|
||||
|
||||
assert cc_2_confirmed_balance == 30
|
||||
assert cc_2_unconfirmed_balance == 30
|
||||
|
|
Loading…
Reference in New Issue