mirror of
https://github.com/haveno-dex/haveno-ts.git
synced 2024-12-25 23:39:38 -05:00
test basic end-to-end trade completion
add methods to take offer and indicate payment to haveno daemon add getNewDepositSubaddress() to haveno daemon automatically fund haveno wallets and await unlocked funds run tests sequentially update protobuf definition
This commit is contained in:
parent
e35f8c5e95
commit
a268b26784
@ -431,6 +431,8 @@ message TxInfo {
|
||||
service Wallets {
|
||||
rpc GetBalances (GetBalancesRequest) returns (GetBalancesReply) {
|
||||
}
|
||||
rpc GetNewDepositSubaddress (GetNewDepositSubaddressRequest) returns (GetNewDepositSubaddressReply) {
|
||||
}
|
||||
rpc GetAddressBalance (GetAddressBalanceRequest) returns (GetAddressBalanceReply) {
|
||||
}
|
||||
rpc GetUnusedBsqAddress (GetUnusedBsqAddressRequest) returns (GetUnusedBsqAddressReply) {
|
||||
@ -469,6 +471,13 @@ message GetBalancesReply {
|
||||
BalancesInfo balances = 1;
|
||||
}
|
||||
|
||||
message GetNewDepositSubaddressRequest {
|
||||
}
|
||||
|
||||
message GetNewDepositSubaddressReply {
|
||||
string subaddress = 1;
|
||||
}
|
||||
|
||||
message GetAddressBalanceRequest {
|
||||
string address = 1;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"test": "react-scripts test --runInBand",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
@ -1,23 +1,26 @@
|
||||
// import haveno types
|
||||
import {HavenoDaemon} from "./HavenoDaemon";
|
||||
import {XmrBalanceInfo, OfferInfo} from './protobuf/grpc_pb'; // TODO (woodser): better names; haveno_grpc_pb, haveno_pb
|
||||
import {XmrBalanceInfo, OfferInfo, TradeInfo} from './protobuf/grpc_pb'; // TODO (woodser): better names; haveno_grpc_pb, haveno_pb
|
||||
import {PaymentAccount} from './protobuf/pb_pb';
|
||||
|
||||
// import monero-javascript
|
||||
const monerojs = require("monero-javascript"); // TODO (woodser): support typescript and `npm install @types/monero-javascript` in monero-javascript
|
||||
const MoneroDaemonRpc = monerojs.MoneroDaemonRpc;
|
||||
const MoneroWalletRpc = monerojs.MoneroWalletRpc;
|
||||
const MoneroTxConfig = monerojs.MoneroTxConfig;
|
||||
const TaskLooper = monerojs.TaskLooper;
|
||||
|
||||
// import console because jest swallows messages in real time
|
||||
const console = require('console');
|
||||
|
||||
// alice config
|
||||
const havenoVersion = "1.6.2";
|
||||
const aliceDaemonUrl = "http://localhost:8080";
|
||||
const aliceDaemonPassword = "apitest";
|
||||
const alice: HavenoDaemon = new HavenoDaemon(aliceDaemonUrl, aliceDaemonPassword);
|
||||
const aliceWalletUrl = "http://127.0.0.1:51743"; // alice's internal haveno wallet for direct testing // TODO (woodser): make configurable rather than randomly generated
|
||||
const aliceWalletUrl = "http://127.0.0.1:57983"; // alice's internal haveno wallet for direct testing // TODO (woodser): make configurable rather than randomly generated
|
||||
const aliceWalletUsername = "rpc_user";
|
||||
const aliceWalletPassword = "abc123";
|
||||
const aliceWallet = new MoneroWalletRpc(aliceWalletUrl, aliceWalletUsername, aliceWalletPassword);
|
||||
const aliceWalletSyncPeriod = 5000;
|
||||
let aliceWallet: any;
|
||||
|
||||
// bob config
|
||||
const bobDaemonUrl = "http://localhost:8081";
|
||||
@ -27,15 +30,35 @@ const bob: HavenoDaemon = new HavenoDaemon(bobDaemonUrl, bobDaemonPassword);
|
||||
// monero daemon config
|
||||
const moneroDaemonUrl = "http://localhost:38081"
|
||||
const moneroDaemonUsername = "superuser";
|
||||
const moneroDaemonPassword = "abctesting123";
|
||||
const moneroDaemonPassword = "abctesting123";
|
||||
const miningAddress = "59M2dSSmrKiimFavjWQ8zFGWe6ziHr9XUjhHcMVEj9ut4EdkcmcqawfgMrtEERipUJA8iNzU65eaELoFYcor1c4jK4FRj1N";
|
||||
let monerod: any;
|
||||
|
||||
// source funding wallet
|
||||
const fundingWalletUrl = "http://localhost:38084";
|
||||
const fundingWalletUsername = "rpc_user";
|
||||
const fundingWalletPassword = "abc123";
|
||||
let fundingWallet: any;
|
||||
|
||||
// other test config
|
||||
const MAX_TIME_PEER_NOTICE = 3000;
|
||||
|
||||
beforeAll(async () => {
|
||||
await monerojs.LibraryUtils.setWorkerDistPath("./node_modules/monero-javascript/src/main/js/common/MoneroWebWorker.js"); // TODO (woodser): remove this when update to monero-javascript-v0.5.6 which correctly detects node environment
|
||||
|
||||
// TODO (woodser): remove this when update to monero-javascript-v0.5.6 which correctly detects node environment
|
||||
await monerojs.LibraryUtils.setWorkerDistPath("./node_modules/monero-javascript/src/main/js/common/MoneroWebWorker.js");
|
||||
|
||||
// initialize clients of wallet and daemon rpc
|
||||
aliceWallet = await monerojs.connectToWalletRpc(aliceWalletUrl, aliceWalletUsername, aliceWalletPassword);
|
||||
fundingWallet = await monerojs.connectToWalletRpc(fundingWalletUrl, fundingWalletUsername, fundingWalletPassword);
|
||||
monerod = await monerojs.connectToDaemonRpc(moneroDaemonUrl, moneroDaemonUsername, moneroDaemonPassword);
|
||||
|
||||
// debug tools
|
||||
//for (let offer of await alice.getMyOffers("BUY")) await alice.removeOffer(offer.getId());
|
||||
//for (let offer of await alice.getMyOffers("SELL")) await alice.removeOffer(offer.getId());
|
||||
//for (let frozenOutput of await aliceWallet.getOutputs({isFrozen: true})) await aliceWallet.thawOutput(frozenOutput.getKeyImage().getHex());
|
||||
//console.log((await alice.getBalances()).getUnlockedBalance() + ", " + (await alice.getBalances()).getLockedBalance());
|
||||
//console.log((await bob.getBalances()).getUnlockedBalance() + ", " + (await bob.getBalances()).getLockedBalance());
|
||||
});
|
||||
|
||||
test("Can get the version", async () => {
|
||||
@ -119,7 +142,7 @@ test("Invalidates offers when reserved funds are spent", async () => {
|
||||
}
|
||||
|
||||
// offer is available to peers
|
||||
await wait(3000);
|
||||
await wait(MAX_TIME_PEER_NOTICE);
|
||||
if (!getOffer(await bob.getOffers("buy"), offer.getId())) throw new Error("Offer " + offer.getId() + " was not found in peer's offers after posting");
|
||||
|
||||
// spend one of offer's reserved outputs
|
||||
@ -149,18 +172,86 @@ test("Invalidates offers when reserved funds are spent", async () => {
|
||||
await monerod.flushTxPool(tx.getHash());
|
||||
});
|
||||
|
||||
jest.setTimeout(120000);
|
||||
test("Can complete a trade", async () => {
|
||||
|
||||
|
||||
console.log("Alice balances: " + getBalancesStr(await alice.getBalances()));
|
||||
|
||||
// wait for alice and bob to have unlocked balance for trade
|
||||
let tradeAmount: bigint = BigInt("250000000000");
|
||||
await waitForUnlockedBalance(tradeAmount, alice, bob);
|
||||
|
||||
// TODO: finish this test
|
||||
// alice posts offer to buy xmr
|
||||
console.log("Alice posting offer");
|
||||
let offer: OfferInfo = await postOffer();
|
||||
console.log("Alice done posting offer");
|
||||
|
||||
// bob sees offer
|
||||
await wait(MAX_TIME_PEER_NOTICE);
|
||||
|
||||
// get bob's ethereum payment account
|
||||
let ethPaymentAccount: PaymentAccount | undefined;
|
||||
for (let paymentAccount of await bob.getPaymentAccounts()) {
|
||||
if (paymentAccount.getSelectedTradeCurrency()?.getCode() === "ETH") {
|
||||
ethPaymentAccount = paymentAccount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ethPaymentAccount) throw new Error("Bob must have ethereum payment account to take offer");
|
||||
|
||||
// bob takes offer
|
||||
let startTime = Date.now();
|
||||
let bobBalancesBefore: XmrBalanceInfo = await bob.getBalances();
|
||||
console.log("Bob taking offer");
|
||||
let trade: TradeInfo = await bob.takeOffer(offer.getId(), ethPaymentAccount.getId()); // TODO (woodser): this returns before trade is fully initialized
|
||||
console.log("Bob done taking offer in " + (Date.now() - startTime) + " ms");
|
||||
|
||||
// bob can get trade
|
||||
let fetchedTrade: TradeInfo = await bob.getTrade(trade.getTradeId());
|
||||
// TODO: test fetched trade
|
||||
|
||||
// test bob's balances after taking trade
|
||||
let bobBalancesAfter: XmrBalanceInfo = await bob.getBalances();
|
||||
expect(BigInt(bobBalancesAfter.getUnlockedBalance())).toBeLessThan(BigInt(bobBalancesBefore.getUnlockedBalance()));
|
||||
expect(BigInt(bobBalancesAfter.getReservedOfferBalance()) + BigInt(bobBalancesAfter.getReservedTradeBalance())).toBeGreaterThan(BigInt(bobBalancesBefore.getReservedOfferBalance()) + BigInt(bobBalancesBefore.getReservedTradeBalance()));
|
||||
|
||||
// bob is notified of balance change
|
||||
|
||||
// alice notified of balance changes and that offer is taken
|
||||
await wait(MAX_TIME_PEER_NOTICE);
|
||||
|
||||
// alice can get trade
|
||||
fetchedTrade = await alice.getTrade(trade.getTradeId());
|
||||
|
||||
// mine until deposit txs unlock
|
||||
console.log("Mining to unlock deposit txs");
|
||||
await waitForUnlockedTxs(fetchedTrade.getMakerDepositTxId(), fetchedTrade.getTakerDepositTxId());
|
||||
console.log("Done mining to unlock deposit txs");
|
||||
|
||||
// alice notified to send payment
|
||||
await wait(5000);
|
||||
|
||||
// alice indicates payment is sent
|
||||
await alice.confirmPaymentStarted(trade.getTradeId());
|
||||
|
||||
// bob notified payment is sent
|
||||
await wait(MAX_TIME_PEER_NOTICE);
|
||||
|
||||
// bob confirms payment is received
|
||||
await bob.confirmPaymentReceived(trade.getTradeId());
|
||||
|
||||
// bob notified trade is complete
|
||||
fetchedTrade = await bob.getTrade(trade.getTradeId());
|
||||
console.log(fetchedTrade.getState()); // TODO (woodser): this should be complete state
|
||||
|
||||
// test bob's balances after confirming payment
|
||||
|
||||
// alice notified trade is complete and of balance changes
|
||||
});
|
||||
|
||||
// ------------------------------- HELPERS ------------------------------------
|
||||
|
||||
async function postOffer() {
|
||||
async function postOffer() { // TODO (woodser): postOffer(maker, peer)
|
||||
|
||||
// test requires ethereum payment account
|
||||
let ethPaymentAccount: PaymentAccount | undefined;
|
||||
@ -177,7 +268,7 @@ async function postOffer() {
|
||||
|
||||
// post offer
|
||||
// TODO: don't define variables, just document in comments
|
||||
let amount: bigint = BigInt("250000000000");
|
||||
let amount: bigint = BigInt("200000000000");
|
||||
let minAmount: bigint = BigInt("150000000000");
|
||||
let price: number = 12.378981; // TODO: price is optional? price string gets converted to long?
|
||||
let useMarketBasedPrice: boolean = true;
|
||||
@ -208,8 +299,8 @@ async function postOffer() {
|
||||
return offer;
|
||||
}
|
||||
|
||||
async function waitForUnlockedBalance(amount: bigint, ...clients: HavenoDaemon[]) {
|
||||
throw new Error("waitForUnlockedFunds() not implemented"); // TODO: implement
|
||||
function getBalancesStr(balances: XmrBalanceInfo) {
|
||||
return "[unlocked balance=" + balances.getUnlockedBalance() + ", locked balance=" + balances.getLockedBalance() + ", reserved offer balance=" + balances.getReservedOfferBalance() + ", reserved trade balance: " + balances.getReservedTradeBalance() + "]";
|
||||
}
|
||||
|
||||
function getOffer(offers: OfferInfo[], id: string): OfferInfo | undefined {
|
||||
@ -228,4 +319,71 @@ function testOffer(offer: OfferInfo) {
|
||||
|
||||
async function wait(durationMs: number) {
|
||||
return new Promise(function(resolve) { setTimeout(resolve, durationMs); });
|
||||
}
|
||||
|
||||
async function startMining() {
|
||||
try {
|
||||
await monerod.startMining(miningAddress, 1);
|
||||
} catch (err) {
|
||||
if (err.message !== "Already mining") throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForUnlockedBalance(amount: bigint, ...clients: HavenoDaemon[]) {
|
||||
|
||||
// fund haveno clients with insufficient balance
|
||||
let miningNeeded = false;
|
||||
let fundConfig = new MoneroTxConfig().setAccountIndex(0).setRelay(true);
|
||||
for (let client of clients) {
|
||||
let balances = await client.getBalances();
|
||||
if (BigInt(balances.getUnlockedBalance()) < amount) miningNeeded = true;
|
||||
let depositNeeded: BigInt = amount - BigInt(balances.getUnlockedBalance()) - BigInt(balances.getLockedBalance());
|
||||
if (depositNeeded > BigInt("0")) fundConfig.addDestination(await client.getNewDepositSubaddress(), depositNeeded);
|
||||
}
|
||||
if (fundConfig.getDestinations()) {
|
||||
try { await fundingWallet.createTx(fundConfig); }
|
||||
catch (err) { throw new Error("Error funding haveno daemons: " + err.message); }
|
||||
}
|
||||
|
||||
// done if all clients have sufficient unlocked balance
|
||||
if (!miningNeeded) return;
|
||||
|
||||
// wait for funds to unlock
|
||||
console.log("Mining for unlocked trader balances")
|
||||
await startMining();
|
||||
let promises: Promise<void>[] = []
|
||||
for (let client of clients) {
|
||||
promises.push(new Promise(async function(resolve, reject) {
|
||||
let taskLooper: any = new TaskLooper(async function() {
|
||||
let balances: XmrBalanceInfo = await client.getBalances();
|
||||
if (BigInt(balances.getUnlockedBalance()) >= amount) {
|
||||
taskLooper.stop();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
taskLooper.start(5000);
|
||||
}));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
await monerod.stopMining();
|
||||
console.log("Funds unlocked, done mining");
|
||||
};
|
||||
|
||||
async function waitForUnlockedTxs(...txHashes: string[]) {
|
||||
await startMining();
|
||||
let promises: Promise<void>[] = []
|
||||
for (let txHash of txHashes) {
|
||||
promises.push(new Promise(async function(resolve, reject) {
|
||||
let taskLooper: any = new TaskLooper(async function() {
|
||||
let tx = await monerod.getTx(txHash);
|
||||
if (tx.isConfirmed() && tx.getBlock().getHeight() <= await monerod.getHeight() - 10) {
|
||||
taskLooper.stop();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
taskLooper.start(5000);
|
||||
}));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
await monerod.stopMining();
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import * as grpcWeb from 'grpc-web';
|
||||
import {GetVersionClient, WalletsClient, OffersClient, PaymentAccountsClient} from './protobuf/GrpcServiceClientPb';
|
||||
import {GetVersionRequest, GetVersionReply, GetBalancesRequest, GetBalancesReply, XmrBalanceInfo, GetOffersRequest, GetOffersReply, OfferInfo, GetPaymentAccountsRequest, GetPaymentAccountsReply, CreateCryptoCurrencyPaymentAccountRequest, CreateCryptoCurrencyPaymentAccountReply, CreateOfferRequest, CreateOfferReply, CancelOfferRequest} from './protobuf/grpc_pb';
|
||||
import {PaymentAccount} from './protobuf/pb_pb';
|
||||
import {GetVersionClient, WalletsClient, OffersClient, PaymentAccountsClient, TradesClient} from './protobuf/GrpcServiceClientPb';
|
||||
import {GetVersionRequest, GetVersionReply, GetBalancesRequest, GetBalancesReply, XmrBalanceInfo, GetOffersRequest, GetOffersReply, OfferInfo, GetPaymentAccountsRequest, GetPaymentAccountsReply, CreateCryptoCurrencyPaymentAccountRequest, CreateCryptoCurrencyPaymentAccountReply, CreateOfferRequest, CreateOfferReply, CancelOfferRequest, TakeOfferRequest, TakeOfferReply, TradeInfo, GetTradeRequest, GetTradeReply, GetNewDepositSubaddressRequest, GetNewDepositSubaddressReply, ConfirmPaymentStartedRequest, ConfirmPaymentReceivedRequest} from './protobuf/grpc_pb';
|
||||
import {PaymentAccount, AvailabilityResult} from './protobuf/pb_pb';
|
||||
|
||||
/**
|
||||
* Haveno daemon client using gRPC.
|
||||
@ -13,8 +13,9 @@ class HavenoDaemon {
|
||||
_password: string;
|
||||
_getVersionClient: GetVersionClient;
|
||||
_walletsClient: WalletsClient;
|
||||
_offersClient: OffersClient;
|
||||
_paymentAccountsClient: PaymentAccountsClient;
|
||||
_offersClient: OffersClient;
|
||||
_tradesClient: TradesClient;
|
||||
|
||||
/**
|
||||
* Construct a client connected to a Haveno daemon.
|
||||
@ -27,8 +28,9 @@ class HavenoDaemon {
|
||||
this._password = password;
|
||||
this._getVersionClient = new GetVersionClient(this._url);
|
||||
this._walletsClient = new WalletsClient(this._url);
|
||||
this._offersClient = new OffersClient(this._url);
|
||||
this._paymentAccountsClient = new PaymentAccountsClient(this._url);
|
||||
this._offersClient = new OffersClient(this._url);
|
||||
this._tradesClient = new TradesClient(this._url);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -38,9 +40,8 @@ class HavenoDaemon {
|
||||
*/
|
||||
async getVersion(): Promise<string> {
|
||||
let that = this;
|
||||
let request = new GetVersionRequest();
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._getVersionClient.getVersion(request, {password: that._password}, function(err: grpcWeb.Error, response: GetVersionReply) {
|
||||
that._getVersionClient.getVersion(new GetVersionRequest(), {password: that._password}, function(err: grpcWeb.Error, response: GetVersionReply) {
|
||||
if (err) reject(err);
|
||||
else resolve(response.getVersion());
|
||||
});
|
||||
@ -54,9 +55,8 @@ class HavenoDaemon {
|
||||
*/
|
||||
async getBalances(): Promise<XmrBalanceInfo> {
|
||||
let that = this;
|
||||
let request = new GetBalancesRequest();
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._walletsClient.getBalances(request, {password: that._password}, function(err: grpcWeb.Error, response: GetBalancesReply) {
|
||||
that._walletsClient.getBalances(new GetBalancesRequest(), {password: that._password}, function(err: grpcWeb.Error, response: GetBalancesReply) {
|
||||
if (err) reject(err);
|
||||
else resolve(response.getBalances()!.getXmr()!);
|
||||
});
|
||||
@ -64,41 +64,16 @@ class HavenoDaemon {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available offers to buy or sell XMR.
|
||||
* Get a new subaddress in the Haveno wallet to receive deposits.
|
||||
*
|
||||
* @param {string} direction - one of "BUY" or "SELL"
|
||||
*
|
||||
* @return {OfferInfo[]} available offers
|
||||
* @return {string} the deposit address (a subaddress in the Haveno wallet)
|
||||
*/
|
||||
async getOffers(direction: string): Promise<OfferInfo[]> {
|
||||
let request = new GetOffersRequest()
|
||||
.setDirection(direction)
|
||||
.setCurrencyCode("XMR");
|
||||
async getNewDepositSubaddress(): Promise<string> {
|
||||
let that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._offersClient.getOffers(request, {password: that._password}, function(err: grpcWeb.Error, response: GetOffersReply) {
|
||||
that._walletsClient.getNewDepositSubaddress(new GetNewDepositSubaddressRequest(), {password: that._password}, function(err: grpcWeb.Error, response: GetNewDepositSubaddressReply) {
|
||||
if (err) reject(err);
|
||||
else resolve(response.getOffersList());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's created offers to buy or sell XMR.
|
||||
*
|
||||
* @param {string} direction - one of "BUY" or "SELL"
|
||||
*
|
||||
* @return {OfferInfo[]} the user's created offers
|
||||
*/
|
||||
async getMyOffers(direction: string): Promise<OfferInfo[]> {
|
||||
let that = this;
|
||||
let request = new GetOffersRequest()
|
||||
.setDirection(direction)
|
||||
.setCurrencyCode("XMR");
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._offersClient.getMyOffers(request, {password: that._password}, function(err: grpcWeb.Error, response: GetOffersReply) {
|
||||
if (err) reject(err);
|
||||
else resolve(response.getOffersList());
|
||||
else resolve(response.getSubaddress());
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -145,6 +120,40 @@ class HavenoDaemon {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available offers to buy or sell XMR.
|
||||
*
|
||||
* @param {string} direction - one of "BUY" or "SELL"
|
||||
*
|
||||
* @return {OfferInfo[]} available offers
|
||||
*/
|
||||
async getOffers(direction: string): Promise<OfferInfo[]> {
|
||||
let that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._offersClient.getOffers(new GetOffersRequest().setDirection(direction).setCurrencyCode("XMR"), {password: that._password}, function(err: grpcWeb.Error, response: GetOffersReply) {
|
||||
if (err) reject(err);
|
||||
else resolve(response.getOffersList());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's created offers to buy or sell XMR.
|
||||
*
|
||||
* @param {string} direction - one of "BUY" or "SELL"
|
||||
*
|
||||
* @return {OfferInfo[]} the user's created offers
|
||||
*/
|
||||
async getMyOffers(direction: string): Promise<OfferInfo[]> {
|
||||
let that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._offersClient.getMyOffers(new GetOffersRequest().setDirection(direction).setCurrencyCode("XMR"), {password: that._password}, function(err: grpcWeb.Error, response: GetOffersReply) {
|
||||
if (err) reject(err);
|
||||
else resolve(response.getOffersList());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Post an offer.
|
||||
*
|
||||
@ -158,7 +167,7 @@ class HavenoDaemon {
|
||||
* @param {number} buyerSecurityDeposit - buyer security deposit as % of trade amount
|
||||
* @param {string} paymentAccountId - payment account id
|
||||
* @param {number} triggerPrice - price to remove offer
|
||||
* @return {HavenoOffer[]} created offers
|
||||
* @return {OfferInfo} the created offer
|
||||
*/
|
||||
async postOffer(currencyCode: string,
|
||||
direction: string,
|
||||
@ -194,12 +203,80 @@ class HavenoDaemon {
|
||||
/**
|
||||
* Remove a posted offer, releasing its reserved funds.
|
||||
*
|
||||
* @param {string} id - the offer id to cancel
|
||||
* @param {string} offerId - the offer id to cancel
|
||||
*/
|
||||
async removeOffer(id: string): Promise<void> {
|
||||
async removeOffer(offerId: string): Promise<void> {
|
||||
let that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._offersClient.cancelOffer(new CancelOfferRequest().setId(id), {password: that._password}, function(err: grpcWeb.Error) {
|
||||
that._offersClient.cancelOffer(new CancelOfferRequest().setId(offerId), {password: that._password}, function(err: grpcWeb.Error) {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Take an offer.
|
||||
*
|
||||
* @param {string} offerId - id of the offer to take
|
||||
* @param {string} paymentAccountId - id of the payment account
|
||||
* @return {TradeInfo} the initialized trade
|
||||
*/
|
||||
async takeOffer(offerId: string, paymentAccountId: string): Promise<TradeInfo> {
|
||||
let that = this;
|
||||
let request = new TakeOfferRequest()
|
||||
.setOfferId(offerId)
|
||||
.setPaymentAccountId(paymentAccountId)
|
||||
.setTakerFeeCurrencyCode("XMR");
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._tradesClient.takeOffer(request, {password: that._password}, function(err: grpcWeb.Error, response: TakeOfferReply) {
|
||||
if (err) reject(err);
|
||||
else if (response.getFailureReason() && response.getFailureReason()!.getAvailabilityResult() !== AvailabilityResult.AVAILABLE) reject(response.getFailureReason()!.getDescription());
|
||||
else resolve(response.getTrade());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a trade by id.
|
||||
*
|
||||
* @param {string} tradeId - the id of the trade and its offer
|
||||
* @return {TradeInfo} the trade with the given id
|
||||
*/
|
||||
async getTrade(tradeId: string): Promise<TradeInfo> {
|
||||
let that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._tradesClient.getTrade(new GetTradeRequest().setTradeId(tradeId), {password: that._password}, function(err: grpcWeb.Error, response: GetTradeReply) {
|
||||
if (err) reject(err);
|
||||
else resolve(response.getTrade());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm a payment is started.
|
||||
*
|
||||
* @param {string} tradeId - the id of the trade
|
||||
*/
|
||||
async confirmPaymentStarted(tradeId: string): Promise<void> {
|
||||
let that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._tradesClient.confirmPaymentStarted(new ConfirmPaymentStartedRequest().setTradeId(tradeId), {password: that._password}, function(err: grpcWeb.Error) {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm a payment is received.
|
||||
*
|
||||
* @param {string} tradeId - the id of the trade
|
||||
*/
|
||||
async confirmPaymentReceived(tradeId: string): Promise<void> {
|
||||
let that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
that._tradesClient.confirmPaymentReceived(new ConfirmPaymentReceivedRequest().setTradeId(tradeId), {password: that._password}, function(err: grpcWeb.Error) {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
|
@ -1163,6 +1163,46 @@ export class WalletsClient {
|
||||
this.methodInfoGetBalances);
|
||||
}
|
||||
|
||||
methodInfoGetNewDepositSubaddress = new grpcWeb.AbstractClientBase.MethodInfo(
|
||||
grpc_pb.GetNewDepositSubaddressReply,
|
||||
(request: grpc_pb.GetNewDepositSubaddressRequest) => {
|
||||
return request.serializeBinary();
|
||||
},
|
||||
grpc_pb.GetNewDepositSubaddressReply.deserializeBinary
|
||||
);
|
||||
|
||||
getNewDepositSubaddress(
|
||||
request: grpc_pb.GetNewDepositSubaddressRequest,
|
||||
metadata: grpcWeb.Metadata | null): Promise<grpc_pb.GetNewDepositSubaddressReply>;
|
||||
|
||||
getNewDepositSubaddress(
|
||||
request: grpc_pb.GetNewDepositSubaddressRequest,
|
||||
metadata: grpcWeb.Metadata | null,
|
||||
callback: (err: grpcWeb.Error,
|
||||
response: grpc_pb.GetNewDepositSubaddressReply) => void): grpcWeb.ClientReadableStream<grpc_pb.GetNewDepositSubaddressReply>;
|
||||
|
||||
getNewDepositSubaddress(
|
||||
request: grpc_pb.GetNewDepositSubaddressRequest,
|
||||
metadata: grpcWeb.Metadata | null,
|
||||
callback?: (err: grpcWeb.Error,
|
||||
response: grpc_pb.GetNewDepositSubaddressReply) => void) {
|
||||
if (callback !== undefined) {
|
||||
return this.client_.rpcCall(
|
||||
this.hostname_ +
|
||||
'/io.bisq.protobuffer.Wallets/GetNewDepositSubaddress',
|
||||
request,
|
||||
metadata || {},
|
||||
this.methodInfoGetNewDepositSubaddress,
|
||||
callback);
|
||||
}
|
||||
return this.client_.unaryCall(
|
||||
this.hostname_ +
|
||||
'/io.bisq.protobuffer.Wallets/GetNewDepositSubaddress',
|
||||
request,
|
||||
metadata || {},
|
||||
this.methodInfoGetNewDepositSubaddress);
|
||||
}
|
||||
|
||||
methodInfoGetAddressBalance = new grpcWeb.AbstractClientBase.MethodInfo(
|
||||
grpc_pb.GetAddressBalanceReply,
|
||||
(request: grpc_pb.GetAddressBalanceRequest) => {
|
||||
|
32
src/protobuf/grpc_pb.d.ts
vendored
32
src/protobuf/grpc_pb.d.ts
vendored
@ -1343,6 +1343,38 @@ export namespace GetBalancesReply {
|
||||
}
|
||||
}
|
||||
|
||||
export class GetNewDepositSubaddressRequest extends jspb.Message {
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): GetNewDepositSubaddressRequest.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: GetNewDepositSubaddressRequest): GetNewDepositSubaddressRequest.AsObject;
|
||||
static serializeBinaryToWriter(message: GetNewDepositSubaddressRequest, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): GetNewDepositSubaddressRequest;
|
||||
static deserializeBinaryFromReader(message: GetNewDepositSubaddressRequest, reader: jspb.BinaryReader): GetNewDepositSubaddressRequest;
|
||||
}
|
||||
|
||||
export namespace GetNewDepositSubaddressRequest {
|
||||
export type AsObject = {
|
||||
}
|
||||
}
|
||||
|
||||
export class GetNewDepositSubaddressReply extends jspb.Message {
|
||||
getSubaddress(): string;
|
||||
setSubaddress(value: string): GetNewDepositSubaddressReply;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): GetNewDepositSubaddressReply.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: GetNewDepositSubaddressReply): GetNewDepositSubaddressReply.AsObject;
|
||||
static serializeBinaryToWriter(message: GetNewDepositSubaddressReply, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): GetNewDepositSubaddressReply;
|
||||
static deserializeBinaryFromReader(message: GetNewDepositSubaddressReply, reader: jspb.BinaryReader): GetNewDepositSubaddressReply;
|
||||
}
|
||||
|
||||
export namespace GetNewDepositSubaddressReply {
|
||||
export type AsObject = {
|
||||
subaddress: string,
|
||||
}
|
||||
}
|
||||
|
||||
export class GetAddressBalanceRequest extends jspb.Message {
|
||||
getAddress(): string;
|
||||
setAddress(value: string): GetAddressBalanceRequest;
|
||||
|
@ -49,6 +49,8 @@ goog.exportSymbol('proto.io.bisq.protobuffer.GetMyOfferReply', null, global);
|
||||
goog.exportSymbol('proto.io.bisq.protobuffer.GetMyOfferRequest', null, global);
|
||||
goog.exportSymbol('proto.io.bisq.protobuffer.GetMyOffersReply', null, global);
|
||||
goog.exportSymbol('proto.io.bisq.protobuffer.GetMyOffersRequest', null, global);
|
||||
goog.exportSymbol('proto.io.bisq.protobuffer.GetNewDepositSubaddressReply', null, global);
|
||||
goog.exportSymbol('proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest', null, global);
|
||||
goog.exportSymbol('proto.io.bisq.protobuffer.GetOfferReply', null, global);
|
||||
goog.exportSymbol('proto.io.bisq.protobuffer.GetOfferRequest', null, global);
|
||||
goog.exportSymbol('proto.io.bisq.protobuffer.GetOffersReply', null, global);
|
||||
@ -1262,6 +1264,48 @@ if (goog.DEBUG && !COMPILED) {
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetBalancesReply.displayName = 'proto.io.bisq.protobuffer.GetBalancesReply';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.displayName = 'proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.io.bisq.protobuffer.GetNewDepositSubaddressReply, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.displayName = 'proto.io.bisq.protobuffer.GetNewDepositSubaddressReply';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
@ -11955,6 +11999,237 @@ proto.io.bisq.protobuffer.GetBalancesReply.prototype.hasBalances = function() {
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest;
|
||||
return proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressRequest.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.io.bisq.protobuffer.GetNewDepositSubaddressReply} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
subaddress: jspb.Message.getFieldWithDefault(msg, 1, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.io.bisq.protobuffer.GetNewDepositSubaddressReply}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.io.bisq.protobuffer.GetNewDepositSubaddressReply;
|
||||
return proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.io.bisq.protobuffer.GetNewDepositSubaddressReply} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.io.bisq.protobuffer.GetNewDepositSubaddressReply}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setSubaddress(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.io.bisq.protobuffer.GetNewDepositSubaddressReply} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getSubaddress();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string subaddress = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.prototype.getSubaddress = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.io.bisq.protobuffer.GetNewDepositSubaddressReply} returns this
|
||||
*/
|
||||
proto.io.bisq.protobuffer.GetNewDepositSubaddressReply.prototype.setSubaddress = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
|
Loading…
Reference in New Issue
Block a user