can post and remove an offer

implement createCryptoPaymentAccount() (unsupported on server)
This commit is contained in:
woodser 2021-09-14 08:30:22 -04:00
parent f83fcb0d84
commit febe4d7526
2 changed files with 158 additions and 1 deletions

View File

@ -42,6 +42,75 @@ test("Can get payment accounts", async () => {
} }
}); });
test("Can create crypto payment account", async () => {
let ethPaymentAccount: PaymentAccount = await daemon.createCryptoPaymentAccount(
"my eth account",
"eth",
"0xdBdAb835Acd6fC84cF5F9aDD3c0B5a1E25fbd99f",
true);
testPaymentAccount(ethPaymentAccount);
});
test("Can post and remove an offer", async () => {
// test requires ethereum payment account
let ethPaymentAccount: PaymentAccount | undefined;
for (let paymentAccount of await daemon.getPaymentAccounts()) {
if (paymentAccount.getSelectedTradeCurrency()?.getCode() === "ETH") {
ethPaymentAccount = paymentAccount;
break;
}
}
if (!ethPaymentAccount) throw new Error("Test requires ethereum payment account to post offer");
// get unlocked balance before reserving offer
let unlockedBalanceBefore: bigint = BigInt((await daemon.getBalances()).getUnlockedbalance()); // TODO: correct camelcase
// post offer
let amount: bigint = BigInt("250000000000");
let minAmount: bigint = BigInt("150000000000");
let price: number = 12.378981; // TODO: price is optional? price string gets converted to long?
let useMarketBasedPrice: boolean = true;
let marketPriceMargin: number = 0.02; // within 2%
let buyerSecurityDeposit: number = 0.15; // 15%
let triggerPrice: number = 12; // TODO: fails if there is decimal, gets converted to long?
let paymentAccountId: string = ethPaymentAccount.getId();
let offer: OfferInfo = await daemon.postOffer("eth",
"buy", // buy xmr for eth
price,
useMarketBasedPrice,
marketPriceMargin,
amount,
minAmount,
buyerSecurityDeposit,
paymentAccountId,
triggerPrice);
testOffer(offer);
// unlocked balance has decreased
let unlockedBalanceAfter: bigint = BigInt((await daemon.getBalances()).getUnlockedbalance());
expect(unlockedBalanceAfter).toBeLessThan(unlockedBalanceBefore);
// offer is included in my offers only
if (!getOffer(await daemon.getMyOffers("buy"), offer.getId())) throw new Error("Offer " + offer.getId() + " was not found in my offers");
if (getOffer(await daemon.getOffers("buy"), offer.getId())) throw new Error("My offer " + offer.getId() + " should not appear in available offers");
// cancel the offer
await daemon.cancelOffer(offer.getId());
// offer is removed from my offers
if (getOffer(await daemon.getOffers("buy"), offer.getId())) throw new Error("Offer " + offer.getId() + " was found in my offers after removal");
// reserved balance restored
expect(unlockedBalanceBefore).toEqual(BigInt((await daemon.getBalances()).getUnlockedbalance()));
});
// ------------------------------- HELPERS ------------------------------------
function getOffer(offers: OfferInfo[], id: string): OfferInfo | undefined {
return offers.find(offer => offer.getId() === id);
}
function testPaymentAccount(paymentAccount: PaymentAccount) { function testPaymentAccount(paymentAccount: PaymentAccount) {
expect(paymentAccount.getId()).toHaveLength; expect(paymentAccount.getId()).toHaveLength;
// TODO: test rest of offer // TODO: test rest of offer

View File

@ -1,6 +1,6 @@
import * as grpcWeb from 'grpc-web'; import * as grpcWeb from 'grpc-web';
import {GetVersionClient, WalletsClient, OffersClient, PaymentAccountsClient} from './protobuf/GrpcServiceClientPb'; import {GetVersionClient, WalletsClient, OffersClient, PaymentAccountsClient} from './protobuf/GrpcServiceClientPb';
import {GetVersionRequest, GetVersionReply, GetBalancesRequest, GetBalancesReply, XmrBalanceInfo, GetOffersRequest, GetOffersReply, OfferInfo, GetPaymentAccountsRequest, GetPaymentAccountsReply} from './protobuf/grpc_pb'; 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 {PaymentAccount} from './protobuf/pb_pb';
/** /**
@ -117,6 +117,94 @@ class HavenoDaemon {
}); });
}); });
} }
/**
* Create a crypto payment account.
*
* @param {string} accountName - description of the account
* @param {string} currencyCode - currency code of the account
* @param {string} address - payment address of the account
* @param {boolean} tradeInstant - whether or not trade can be completed quickly
* @return {PaymentAccount} the created payment account
*/
async createCryptoPaymentAccount(accountName: string,
currencyCode: string,
address: string,
tradeInstant: boolean): Promise<PaymentAccount> {
let that = this;
let request = new CreateCryptoCurrencyPaymentAccountRequest()
.setAccountname(accountName)
.setCurrencycode(currencyCode)
.setAddress(address)
.setTradeinstant(tradeInstant);
return new Promise(function(resolve, reject) {
that._paymentAccountsClient.createCryptoCurrencyPaymentAccount(request, {password: that._password}, function(err: grpcWeb.Error, response: CreateCryptoCurrencyPaymentAccountReply) {
if (err) reject(err);
else resolve(response.getPaymentaccount());
});
});
}
/**
* Post an offer.
*
* @param {string} currencyCode - currency code of traded pair
* @param {string} direction - one of "BUY" or "SELL"
* @param {number} price - trade price
* @param {bool} useMarketBasedPrice - base trade on market price
* @param {number} marketPriceMargin - % from market price to tolerate
* @param {bigint} amount - amount to trade
* @param {bigint} minAmount - minimum amount to trade
* @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
*/
async postOffer(currencyCode: string,
direction: string,
price: number,
useMarketBasedPrice: boolean,
marketPriceMargin: number,
amount: bigint,
minAmount: bigint,
buyerSecurityDeposit: number,
paymentAccountId: string,
triggerPrice?: number): Promise<OfferInfo> {
let that = this;
let request = new CreateOfferRequest()
.setCurrencycode(currencyCode)
.setDirection(direction)
.setPrice(price.toString())
.setUsemarketbasedprice(useMarketBasedPrice)
.setMarketpricemargin(marketPriceMargin)
.setAmount(amount.toString())
.setMinamount(minAmount.toString())
.setBuyersecuritydeposit(buyerSecurityDeposit)
.setPaymentaccountid(paymentAccountId)
.setMakerfeecurrencycode("XMR");
if (triggerPrice) request.setTriggerprice(BigInt(triggerPrice.toString()).toString());
return new Promise(function(resolve, reject) {
that._offersClient.createOffer(request, {password: that._password}, function(err: grpcWeb.Error, response: CreateOfferReply) {
if (err) reject(err);
else resolve(response.getOffer());
});
});
}
/**
* Remove a posted offer, unreserving its funds.
*
* @param {string} id - the offer id to cancel
*/
async cancelOffer(id: string) {
let that = this;
return new Promise(function(resolve, reject) {
that._offersClient.cancelOffer(new CancelOfferRequest().setId(id), {password: that._password}, function(err: grpcWeb.Error) {
if (err) reject(err);
else resolve();
});
});
}
} }
export {HavenoDaemon}; export {HavenoDaemon};