Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 49 additions & 20 deletions src/HavenoClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1644,20 +1644,24 @@ test("Can post, deactivate, activate, edit, and remove an offer (Test, CI, sanit
ctx.extraInfo = "My edited extra info";
ctx.price = undefined;
ctx.marketPriceMarginPct = 0.15;
const editedAssetCode = "BCH";
let paymentAccountId = (await createPaymentAccount(user1, editedAssetCode)).getId();
offer = await user1.editOffer({
offerId: offer.getId(),
price: ctx.price,
marketPriceMarginPct: ctx.marketPriceMarginPct,
extraInfo: ctx.extraInfo
extraInfo: ctx.extraInfo,
paymentAccountId: paymentAccountId
});
assert.equal(offer.getState(), "AVAILABLE");
assert.equal(offer.getCounterCurrencyCode(), editedAssetCode);
if (ctx.marketPriceMarginPct) assert.equal(offer.getMarketPriceMarginPct(), ctx.marketPriceMarginPct);
if (ctx.price) expect(parseFloat(offer.getPrice())).toEqual(ctx.price);
expect(offer.getExtraInfo()).toContain("My edited extra info");

// peer sees edited offer
await wait(TestConfig.trade.maxTimePeerNoticeMs);
peerOffer = getOffer(await user2.getOffers(assetCode, TestConfig.trade.direction), offer.getId());
peerOffer = getOffer(await user2.getOffers(editedAssetCode, TestConfig.trade.direction), offer.getId());
if (!peerOffer) throw new Error("Offer " + offer.getId() + " was not found in peer's offers after edited");
testOffer(peerOffer, ctx, false);
expect(peerOffer.getExtraInfo()).toContain("My edited extra info");
Expand Down Expand Up @@ -1687,29 +1691,46 @@ test("Can clone offers (Test, CI, sanity check)", async () => {
const availableBalanceBefore = BigInt((await user1.getBalances()).getAvailableBalance());

// post offer
let assetCode = "BCH";
let ctx: Partial<TradeContext> = {maker: {havenod: user1}, direction: OfferDirection.SELL, isPrivateOffer: true, buyerAsTakerWithoutDeposit: true, assetCode: assetCode, extraInfo: "My extra info"};
let assetCode = "USD";
let ctx: Partial<TradeContext> = {maker: {havenod: user1}, direction: OfferDirection.SELL, assetCode: assetCode, extraInfo: "My extra info"};
let offer: OfferInfo = await makeOffer(ctx);
assert.equal(offer.getState(), "AVAILABLE");

// clone offer
const clonedOffer = await makeOffer({
// clone offer with same fiat account
const clonedOffer1 = await user1.postOffer({
sourceOfferId: offer.getId(),
});
assert.notEqual(clonedOffer1.getId(), offer.getId());
assert.equal(clonedOffer1.getState(), "DEACTIVATED"); // deactivated if same payment method and currency
assert.equal(clonedOffer1.getCounterCurrencyCode(), assetCode);
assert.equal(clonedOffer1.getBaseCurrencyCode(), "XMR");
assert.equal(clonedOffer1.getAmount(), offer.getAmount());
assert.equal(clonedOffer1.getMinAmount(), offer.getMinAmount());
assert.equal(clonedOffer1.getIsPrivateOffer(), offer.getIsPrivateOffer());

// clone offer with crypto account
const cryptoAssetCode = "BCH";
let paymentAccountId = (await createPaymentAccount(user1, cryptoAssetCode)).getId();
const clonedOffer2 = await user1.postOffer({
sourceOfferId: offer.getId(),
assetCode: "BCH"
paymentAccountId: paymentAccountId
});
assert.notEqual(clonedOffer.getId(), offer.getId());
assert.equal(clonedOffer.getState(), "DEACTIVATED"); // deactivated if same payment method and currency
assert.equal(clonedOffer.getCounterCurrencyCode(), assetCode);
assert.equal(clonedOffer.getBaseCurrencyCode(), "XMR");
assert.equal(clonedOffer.getAmount(), offer.getAmount());
assert.equal(clonedOffer.getMinAmount(), offer.getMinAmount());
assert.equal(clonedOffer.getIsPrivateOffer(), offer.getIsPrivateOffer());
assert.notEqual(clonedOffer2.getId(), offer.getId());
assert.equal(clonedOffer2.getState(), "AVAILABLE");
assert.equal(clonedOffer2.getCounterCurrencyCode(), cryptoAssetCode);
assert.equal(clonedOffer2.getBaseCurrencyCode(), "XMR");
assert.equal(clonedOffer2.getAmount(), offer.getAmount());
assert.equal(clonedOffer2.getMinAmount(), offer.getMinAmount());
assert.equal(clonedOffer2.getIsPrivateOffer(), offer.getIsPrivateOffer());

// TODO: test edited fields on clone, etc
// TODO: test edited fields on clone

// TODO: test peer seeing cloned offers

// remove offers
await user1.removeOffer(offer.getId());
await user1.removeOffer(clonedOffer.getId());
await user1.removeOffer(clonedOffer1.getId());
await user1.removeOffer(clonedOffer2.getId());
});

// TODO: provide number of confirmations in offer status
Expand Down Expand Up @@ -2275,18 +2296,26 @@ test("Cannot make or take offer with insufficient funds (Test, CI, sanity check)
assert.equal(errTyped.code, 2);
}

// user1 gets or posts offer
// user1 gets or posts available offer
let offer: OfferInfo | undefined = undefined;
const offers: OfferInfo[] = await user1.getMyOffers(TestConfig.trade.assetCode);
let offer: OfferInfo;
if (offers.length) offer = offers[0];
else {
for (const anOffer of offers) {
if (anOffer.getState() === "AVAILABLE") {
offer = anOffer;
break;
}
}
if (offer === undefined) {
const tradeAmount = 250000000000n;
await waitForAvailableBalance(tradeAmount * 2n, user1);
offer = await makeOffer({maker: {havenod: user1}, offerAmount: tradeAmount, awaitFundsToMakeOffer: false});
assert.equal(offer.getState(), "AVAILABLE");
await wait(TestConfig.trade.walletSyncPeriodMs * 2);
}

// user3 sees offer
if (!getOffer(await user3.getOffers(offer.getCounterCurrencyCode()), offer.getId())) throw new Error("Offer " + offer.getId() + " was not found in user3's offers");

// user3 cannot take offer with insufficient funds
try {
await user3.takeOffer(offer.getId(), paymentAccount.getId());
Expand Down
33 changes: 17 additions & 16 deletions src/HavenoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1134,23 +1134,24 @@ export default class HavenoClient {
*/
async postOffer(config: PostOfferConfig): Promise<OfferInfo> {
console.log("Posting offer with security deposit %: " + config.securityDepositPct)
const request = new PostOfferRequest();
if (config.direction) request.setDirection(config.direction === OfferDirection.BUY ? "buy" : "sell");
if (config.amount) request.setAmount(config.amount.toString());
if (config.minAmount) request.setMinAmount(config.minAmount.toString());
else if (config.amount) request.setMinAmount(config.amount.toString());
if (config.assetCode) request.setCurrencyCode(config.assetCode);
if (config.paymentAccountId) request.setPaymentAccountId(config.paymentAccountId);
if (config.securityDepositPct) request.setSecurityDepositPct(config.securityDepositPct);
request.setUseMarketBasedPrice(config.price === undefined);
if (config.price) request.setPrice(config.price?.toString())
if (config.marketPriceMarginPct) request.setMarketPriceMarginPct(config.marketPriceMarginPct);
if (config.triggerPrice) request.setTriggerPrice(config.triggerPrice.toString());
if (config.reserveExactAmount) request.setReserveExactAmount(true);
if (config.isPrivateOffer) request.setIsPrivateOffer(true);
if (config.buyerAsTakerWithoutDeposit) request.setBuyerAsTakerWithoutDeposit(true);
if (config.extraInfo) request.setExtraInfo(config.extraInfo);
if (config.sourceOfferId) request.setSourceOfferId(config.sourceOfferId);
try {
const request = new PostOfferRequest();
if (config.direction) request.setDirection(config.direction === OfferDirection.BUY ? "buy" : "sell");
if (config.amount) request.setAmount(config.amount.toString());
request.setMinAmount(config.minAmount ? config.minAmount.toString() : config.amount!.toString());
if (config.assetCode) request.setCurrencyCode(config.assetCode);
if (config.paymentAccountId) request.setPaymentAccountId(config.paymentAccountId);
if (config.securityDepositPct) request.setSecurityDepositPct(config.securityDepositPct);
request.setUseMarketBasedPrice(config.price === undefined);
if (config.price) request.setPrice(config.price?.toString())
if (config.marketPriceMarginPct) request.setMarketPriceMarginPct(config.marketPriceMarginPct);
if (config.triggerPrice) request.setTriggerPrice(config.triggerPrice.toString());
if (config.reserveExactAmount) request.setReserveExactAmount(true);
if (config.isPrivateOffer) request.setIsPrivateOffer(true);
if (config.buyerAsTakerWithoutDeposit) request.setBuyerAsTakerWithoutDeposit(true);
if (config.extraInfo) request.setExtraInfo(config.extraInfo);
if (config.sourceOfferId) request.setSourceOfferId(config.sourceOfferId);
return (await this._offersClient.postOffer(request, {password: this._password})).getOffer()!;
} catch (e: any) {
throw new HavenoError(e.message, e.code);
Expand Down