Merge pull request #10158 from f321x/command_fetch_swap_providers
commands: add command to fetch nostr swap providers
This commit is contained in:
@@ -46,6 +46,7 @@ from . import util
|
|||||||
from .lnmsg import OnionWireSerializer
|
from .lnmsg import OnionWireSerializer
|
||||||
from .logging import Logger
|
from .logging import Logger
|
||||||
from .onion_message import create_blinded_path, send_onion_message_to
|
from .onion_message import create_blinded_path, send_onion_message_to
|
||||||
|
from .submarine_swaps import NostrTransport
|
||||||
from .util import (
|
from .util import (
|
||||||
bfh, json_decode, json_normalize, is_hash256_str, is_hex_str, to_bytes, parse_max_spend, to_decimal,
|
bfh, json_decode, json_normalize, is_hash256_str, is_hex_str, to_bytes, parse_max_spend, to_decimal,
|
||||||
UserFacingException, InvalidPassword
|
UserFacingException, InvalidPassword
|
||||||
@@ -1966,6 +1967,32 @@ class Commands(Logger):
|
|||||||
'log': [x.formatted_tuple() for x in log]
|
'log': [x.formatted_tuple() for x in log]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@command('wnl')
|
||||||
|
async def get_submarine_swap_providers(self, query_time=15, wallet: Abstract_Wallet = None):
|
||||||
|
"""
|
||||||
|
Queries nostr relays for available submarine swap providers.
|
||||||
|
|
||||||
|
To configure one of the providers use:
|
||||||
|
setconfig swapserver_npub 'npub...'
|
||||||
|
|
||||||
|
arg:int:query_time:Optional timeout how long the relays should be queried for provider announcements. Default: 15 sec
|
||||||
|
"""
|
||||||
|
sm = wallet.lnworker.swap_manager
|
||||||
|
async with sm.create_transport() as transport:
|
||||||
|
assert isinstance(transport, NostrTransport)
|
||||||
|
await asyncio.sleep(query_time)
|
||||||
|
offers = transport.get_recent_offers()
|
||||||
|
result = {}
|
||||||
|
for offer in offers:
|
||||||
|
result[offer.server_npub] = {
|
||||||
|
"percentage_fee": offer.pairs.percentage,
|
||||||
|
"max_forward_sat": offer.pairs.max_forward,
|
||||||
|
"max_reverse_sat": offer.pairs.max_reverse,
|
||||||
|
"min_amount_sat": offer.pairs.min_amount,
|
||||||
|
"provider_mining_fee": offer.pairs.mining_fee,
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
@command('wnpl')
|
@command('wnpl')
|
||||||
async def normal_swap(self, onchain_amount, lightning_amount, password=None, wallet: Abstract_Wallet = None):
|
async def normal_swap(self, onchain_amount, lightning_amount, password=None, wallet: Abstract_Wallet = None):
|
||||||
"""
|
"""
|
||||||
@@ -1975,8 +2002,13 @@ class Commands(Logger):
|
|||||||
arg:decimal_or_dryrun:onchain_amount:Amount to be sent, in BTC. Set it to 'dryrun' to receive a value
|
arg:decimal_or_dryrun:onchain_amount:Amount to be sent, in BTC. Set it to 'dryrun' to receive a value
|
||||||
"""
|
"""
|
||||||
sm = wallet.lnworker.swap_manager
|
sm = wallet.lnworker.swap_manager
|
||||||
|
assert self.config.SWAPSERVER_NPUB or self.config.SWAPSERVER_URL, \
|
||||||
|
"Configure swap provider first. See 'get_submarine_swap_providers'."
|
||||||
async with sm.create_transport() as transport:
|
async with sm.create_transport() as transport:
|
||||||
await sm.is_initialized.wait()
|
try:
|
||||||
|
await asyncio.wait_for(sm.is_initialized.wait(), timeout=15)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
raise TimeoutError("Could not find configured swap provider. Setup another one. See 'get_submarine_swap_providers'")
|
||||||
if lightning_amount == 'dryrun':
|
if lightning_amount == 'dryrun':
|
||||||
onchain_amount_sat = satoshis(onchain_amount)
|
onchain_amount_sat = satoshis(onchain_amount)
|
||||||
lightning_amount_sat = sm.get_recv_amount(onchain_amount_sat, is_reverse=False)
|
lightning_amount_sat = sm.get_recv_amount(onchain_amount_sat, is_reverse=False)
|
||||||
@@ -2013,8 +2045,13 @@ class Commands(Logger):
|
|||||||
arg:decimal_or_dryrun:provider_mining_fee:Mining fee required by the swap provider, in BTC. Set it to 'dryrun' to receive a value
|
arg:decimal_or_dryrun:provider_mining_fee:Mining fee required by the swap provider, in BTC. Set it to 'dryrun' to receive a value
|
||||||
"""
|
"""
|
||||||
sm = wallet.lnworker.swap_manager
|
sm = wallet.lnworker.swap_manager
|
||||||
|
assert self.config.SWAPSERVER_NPUB or self.config.SWAPSERVER_URL, \
|
||||||
|
"Configure swap provider first. See 'get_submarine_swap_providers'."
|
||||||
async with sm.create_transport() as transport:
|
async with sm.create_transport() as transport:
|
||||||
await sm.is_initialized.wait()
|
try:
|
||||||
|
await asyncio.wait_for(sm.is_initialized.wait(), timeout=15)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
raise TimeoutError("Could not find configured swap provider. Setup another one. See 'get_submarine_swap_providers'")
|
||||||
if onchain_amount == 'dryrun':
|
if onchain_amount == 'dryrun':
|
||||||
lightning_amount_sat = satoshis(lightning_amount)
|
lightning_amount_sat = satoshis(lightning_amount)
|
||||||
onchain_amount_sat = sm.get_recv_amount(lightning_amount_sat, is_reverse=True)
|
onchain_amount_sat = sm.get_recv_amount(lightning_amount_sat, is_reverse=True)
|
||||||
|
|||||||
@@ -248,7 +248,8 @@ if [[ $1 == "swapserver_success" ]]; then
|
|||||||
echo "alice initiates swap"
|
echo "alice initiates swap"
|
||||||
dryrun=$($alice reverse_swap 0.02 dryrun)
|
dryrun=$($alice reverse_swap 0.02 dryrun)
|
||||||
onchain_amount=$(echo $dryrun| jq -r ".onchain_amount")
|
onchain_amount=$(echo $dryrun| jq -r ".onchain_amount")
|
||||||
swap=$($alice reverse_swap 0.02 $onchain_amount)
|
swapserver_mining_fee=$(echo $dryrun| jq -r ".provider_mining_fee")
|
||||||
|
swap=$($alice reverse_swap 0.02 $onchain_amount --provider_mining_fee $swapserver_mining_fee)
|
||||||
echo $swap | jq
|
echo $swap | jq
|
||||||
funding_txid=$(echo $swap| jq -r ".funding_txid")
|
funding_txid=$(echo $swap| jq -r ".funding_txid")
|
||||||
new_blocks 1
|
new_blocks 1
|
||||||
@@ -272,7 +273,8 @@ if [[ $1 == "swapserver_forceclose" ]]; then
|
|||||||
echo "alice initiates swap"
|
echo "alice initiates swap"
|
||||||
dryrun=$($alice reverse_swap 0.02 dryrun)
|
dryrun=$($alice reverse_swap 0.02 dryrun)
|
||||||
onchain_amount=$(echo $dryrun| jq -r ".onchain_amount")
|
onchain_amount=$(echo $dryrun| jq -r ".onchain_amount")
|
||||||
swap=$($alice reverse_swap 0.02 $onchain_amount)
|
swapserver_mining_fee=$(echo $dryrun| jq -r ".provider_mining_fee")
|
||||||
|
swap=$($alice reverse_swap 0.02 $onchain_amount --provider_mining_fee $swapserver_mining_fee)
|
||||||
echo $swap | jq
|
echo $swap | jq
|
||||||
funding_txid=$(echo $swap| jq -r ".funding_txid")
|
funding_txid=$(echo $swap| jq -r ".funding_txid")
|
||||||
ctx_id=$($bob close_channel --force $channel)
|
ctx_id=$($bob close_channel --force $channel)
|
||||||
@@ -307,7 +309,8 @@ if [[ $1 == "swapserver_refund" ]]; then
|
|||||||
echo "alice initiates swap"
|
echo "alice initiates swap"
|
||||||
dryrun=$($alice reverse_swap 0.02 dryrun)
|
dryrun=$($alice reverse_swap 0.02 dryrun)
|
||||||
onchain_amount=$(echo $dryrun| jq -r ".onchain_amount")
|
onchain_amount=$(echo $dryrun| jq -r ".onchain_amount")
|
||||||
swap=$($alice reverse_swap 0.02 $onchain_amount)
|
swapserver_mining_fee=$(echo $dryrun| jq -r ".provider_mining_fee")
|
||||||
|
swap=$($alice reverse_swap 0.02 $onchain_amount --provider_mining_fee $swapserver_mining_fee)
|
||||||
echo $swap | jq
|
echo $swap | jq
|
||||||
funding_txid=$(echo $swap| jq -r ".funding_txid")
|
funding_txid=$(echo $swap| jq -r ".funding_txid")
|
||||||
new_blocks 140
|
new_blocks 140
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from electrum.lnworker import RecvMPPResolution
|
|||||||
from electrum.wallet import Abstract_Wallet
|
from electrum.wallet import Abstract_Wallet
|
||||||
from electrum.address_synchronizer import TX_HEIGHT_UNCONFIRMED
|
from electrum.address_synchronizer import TX_HEIGHT_UNCONFIRMED
|
||||||
from electrum.simple_config import SimpleConfig
|
from electrum.simple_config import SimpleConfig
|
||||||
|
from electrum.submarine_swaps import SwapOffer, SwapFees, NostrTransport
|
||||||
from electrum.transaction import Transaction, TxOutput, tx_from_any
|
from electrum.transaction import Transaction, TxOutput, tx_from_any
|
||||||
from electrum.util import UserFacingException, NotEnoughFunds
|
from electrum.util import UserFacingException, NotEnoughFunds
|
||||||
from electrum.crypto import sha256
|
from electrum.crypto import sha256
|
||||||
@@ -640,3 +641,69 @@ class TestCommandsTestnet(ElectrumTestCase):
|
|||||||
"fiat_value": "-40.51",
|
"fiat_value": "-40.51",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(wallet.Abstract_Wallet, 'save_db')
|
||||||
|
async def test_get_submarine_swap_providers(self, *mock_args):
|
||||||
|
wallet = restore_wallet_from_text__for_unittest(
|
||||||
|
'disagree rug lemon bean unaware square alone beach tennis exhibit fix mimic',
|
||||||
|
path='if_this_exists_mocking_failed_648151893',
|
||||||
|
config=self.config)['wallet']
|
||||||
|
|
||||||
|
cmds = Commands(config=self.config)
|
||||||
|
|
||||||
|
offer1 = SwapOffer(
|
||||||
|
pairs=SwapFees(
|
||||||
|
percentage=0.5,
|
||||||
|
mining_fee=2000,
|
||||||
|
min_amount=10000,
|
||||||
|
max_forward=1000000,
|
||||||
|
max_reverse=500000
|
||||||
|
),
|
||||||
|
relays=["wss://relay1.example.com", "wss://relay2.example.com"],
|
||||||
|
timestamp=1640995200,
|
||||||
|
server_pubkey="a8cffad54f59e2c50a1d40ec0d57f1fc32df9cd2101fad8000215eb4a75b334d",
|
||||||
|
pow_bits=10
|
||||||
|
)
|
||||||
|
|
||||||
|
offer2 = SwapOffer(
|
||||||
|
pairs=SwapFees(
|
||||||
|
percentage=1.0,
|
||||||
|
mining_fee=3000,
|
||||||
|
min_amount=20000,
|
||||||
|
max_forward=2000000,
|
||||||
|
max_reverse=1000000
|
||||||
|
),
|
||||||
|
relays=["ws://relay3.example.onion", "wss://relay4.example.com"],
|
||||||
|
timestamp=1640995300,
|
||||||
|
server_pubkey="7a483b6546be900481f6be2d2cc1b47c779ee89b4b66d1a066a8dc81c63ad1f0",
|
||||||
|
pow_bits=12
|
||||||
|
)
|
||||||
|
mock_offers = [offer1, offer2]
|
||||||
|
mock_transport = mock.Mock(NostrTransport)
|
||||||
|
mock_transport.get_recent_offers.return_value = mock_offers
|
||||||
|
|
||||||
|
with mock.patch.object(
|
||||||
|
wallet.lnworker.swap_manager,
|
||||||
|
'create_transport'
|
||||||
|
) as mock_create_transport:
|
||||||
|
mock_create_transport.return_value.__aenter__.return_value = mock_transport
|
||||||
|
|
||||||
|
result = await cmds.get_submarine_swap_providers(query_time=1, wallet=wallet)
|
||||||
|
|
||||||
|
expected_result = {
|
||||||
|
offer1.server_npub: {
|
||||||
|
"percentage_fee": offer1.pairs.percentage,
|
||||||
|
"max_forward_sat": offer1.pairs.max_forward,
|
||||||
|
"max_reverse_sat": offer1.pairs.max_reverse,
|
||||||
|
"min_amount_sat": offer1.pairs.min_amount,
|
||||||
|
"provider_mining_fee": offer1.pairs.mining_fee,
|
||||||
|
},
|
||||||
|
offer2.server_npub: {
|
||||||
|
"percentage_fee": offer2.pairs.percentage,
|
||||||
|
"max_forward_sat": offer2.pairs.max_forward,
|
||||||
|
"max_reverse_sat": offer2.pairs.max_reverse,
|
||||||
|
"min_amount_sat": offer2.pairs.min_amount,
|
||||||
|
"provider_mining_fee": offer2.pairs.mining_fee,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.assertEqual(result, expected_result)
|
||||||
|
|||||||
Reference in New Issue
Block a user