feat(gui): Voluntary donations (#418)

* poc: monero receive pool with multiple redeem addresses for bob with given ratios

* fix: use new monero_receive_pool arg for buy_xmr

* update sweep/sweep_multi to return TxReceipt instead of String containing txid

* fix test (generate 1 block before checking balance after transfer)

* add move distribute function to rust, add property tests

* use rust distribute

* update sqlx cache/tempdb

* sqlx fix

* feat: update ui to display the monero address pool

* fix: remove unused functions, set dispatcher for tracing in wallet threads, use new subtract_fee wallet2 functionality

* Add patch system

* add wallet2_api_allow_subtract_from_fee patch

* apply git patches

* split monero-sys patches into chunks

* refactor

* .sqlx needs to be commited, revert unbound issue

* display pool on XmrRedeemInMempoolPage.tsx page, commit .sqlx folder

* fmt

* refactor

* assert MoneroAddressPool is on correct network, differntiate between stagenet and mainnet donaiton address

* looks ok

* re-add retry logic, database errors, ...

* add test

* add tests

* fmt comments, changelog

---------

Co-authored-by: Binarybaron <binarybaron@protonmail.com>
This commit is contained in:
Raphael 2025-06-25 16:37:47 +02:00 committed by GitHub
parent cd4aa5201a
commit 11b891f530
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 2091 additions and 380 deletions

View file

@ -27,6 +27,7 @@ import {
ResolveApprovalResponse,
RedactArgs,
RedactResponse,
LabeledMoneroAddress,
} from "models/tauriModel";
import { rpcSetBalance, rpcSetSwapInfo } from "store/features/rpcSlice";
import { store } from "./store/storeRenderer";
@ -36,14 +37,46 @@ import { MoneroRecoveryResponse } from "models/rpcModel";
import { ListSellersResponse } from "../models/tauriModel";
import logger from "utils/logger";
import { getNetwork, isTestnet } from "store/config";
import { Blockchain, Network } from "store/features/settingsSlice";
import {
Blockchain,
DonateToDevelopmentTip,
Network,
} from "store/features/settingsSlice";
import { setStatus } from "store/features/nodesSlice";
import { discoveredMakersByRendezvous } from "store/features/makersSlice";
import { CliLog } from "models/cliModel";
import { logsToRawString, parseLogsFromString } from "utils/parseUtils";
/// These are the official donation address for the UnstoppableSwap/core project
const DONATION_ADDRESS_MAINNET =
"49LEH26DJGuCyr8xzRAzWPUryzp7bpccC7Hie1DiwyfJEyUKvMFAethRLybDYrFdU1eHaMkKQpUPebY4WT3cSjEvThmpjPa";
const DONATION_ADDRESS_STAGENET =
"56E274CJxTyVuuFG651dLURKyneoJ5LsSA5jMq4By9z9GBNYQKG8y5ejTYkcvZxarZW6if14ve8xXav2byK4aRnvNdKyVxp";
/// Signature by binarybaron for the donation address
/// https://github.com/binarybaron/
///
/// Get the key from:
/// - https://github.com/UnstoppableSwap/core/blob/master/utils/gpg_keys/binarybaron.asc
/// - https://unstoppableswap.net/binarybaron.asc
const DONATION_ADDRESS_MAINNET_SIG = `
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
56E274CJxTyVuuFG651dLURKyneoJ5LsSA5jMq4By9z9GBNYQKG8y5ejTYkcvZxarZW6if14ve8xXav2byK4aRnvNdKyVxp is our donation address (signed by binarybaron)
-----BEGIN PGP SIGNATURE-----
iHUEARYKAB0WIQQ1qETX9LVbxE4YD/GZt10+FHaibgUCaFvzWQAKCRCZt10+FHai
bvC6APoCzCto6RsNYwUr7j1ou3xeVNiwMkUQbE0erKt70pT+tQD/fAvPxHtPyb56
XGFQ0pxL1PKzMd9npBGmGJhC4aTljQ4=
=OUK4
-----END PGP SIGNATURE-----
`;
export const PRESET_RENDEZVOUS_POINTS = [
"/dnsaddr/xxmr.cheap/p2p/12D3KooWMk3QyPS8D1d1vpHZoY7y2MnXdPE5yV6iyPvyuj4zcdxT",
"/dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE",
"/dns4/discover2.unstoppableswap.net/tcp/8888/p2p/12D3KooWGRvf7qVQDrNR5nfYD6rKrbgeTi9x8RrbdxbmsPvxL4mw",
"/dns4/darkness.su/tcp/8888/p2p/12D3KooWFQAgVVS9t9UgL6v1sLprJVM7am5hFK7vy9iBCCoCBYmU",
];
export async function fetchSellersAtPresetRendezvousPoints() {
@ -142,20 +175,39 @@ export async function buyXmr(
seller: Maker,
bitcoin_change_address: string | null,
monero_receive_address: string,
donation_percentage: DonateToDevelopmentTip,
) {
await invoke<BuyXmrArgs, BuyXmrResponse>(
"buy_xmr",
bitcoin_change_address == null
? {
seller: providerToConcatenatedMultiAddr(seller),
monero_receive_address,
}
: {
seller: providerToConcatenatedMultiAddr(seller),
monero_receive_address,
bitcoin_change_address,
},
);
const address_pool: LabeledMoneroAddress[] = [];
if (donation_percentage !== false) {
const donation_address = isTestnet()
? DONATION_ADDRESS_STAGENET
: DONATION_ADDRESS_MAINNET;
address_pool.push(
{
address: monero_receive_address,
percentage: 100 - donation_percentage * 100,
label: "Your wallet",
},
{
address: donation_address,
percentage: donation_percentage * 100,
label: "Tip to the developers",
},
);
} else {
address_pool.push({
address: monero_receive_address,
percentage: 100,
label: "Your wallet",
});
}
await invoke<BuyXmrArgs, BuyXmrResponse>("buy_xmr", {
seller: providerToConcatenatedMultiAddr(seller),
monero_receive_pool: address_pool,
bitcoin_change_address,
});
}
export async function resumeSwap(swapId: string) {