mirror of
https://github.com/haveno-dex/haveno-ts.git
synced 2024-10-01 01:35:42 -04:00
test trade account payloads over grpc, support crypto account forms
This commit is contained in:
parent
2fe2b1f492
commit
768c2158b3
@ -957,7 +957,7 @@ test("Can get payment accounts", async () => {
|
|||||||
test("Can validate payment account forms", async () => {
|
test("Can validate payment account forms", async () => {
|
||||||
|
|
||||||
// supported payment methods
|
// supported payment methods
|
||||||
const expectedPaymentMethods = ["REVOLUT", "SEPA", "SEPA_INSTANT", "TRANSFERWISE", "CLEAR_X_CHANGE", "SWIFT", "F2F", "STRIKE", "MONEY_GRAM", "FASTER_PAYMENTS", "UPHOLD", "PAXUM"];
|
const expectedPaymentMethods = ["BLOCK_CHAINS", "REVOLUT", "SEPA", "SEPA_INSTANT", "TRANSFERWISE", "CLEAR_X_CHANGE", "SWIFT", "F2F", "STRIKE", "MONEY_GRAM", "FASTER_PAYMENTS", "UPHOLD", "PAXUM"];
|
||||||
|
|
||||||
// get payment methods
|
// get payment methods
|
||||||
const paymentMethods = await user1.getPaymentMethods();
|
const paymentMethods = await user1.getPaymentMethods();
|
||||||
@ -992,12 +992,12 @@ test("Can validate payment account forms", async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create payment account
|
// create payment account
|
||||||
const fiatAccount = await user1.createPaymentAccount(accountForm);
|
const paymentAccount = await user1.createPaymentAccount(accountForm);
|
||||||
|
|
||||||
// payment account added
|
// payment account added
|
||||||
let found = false;
|
let found = false;
|
||||||
for (const paymentAccount of await user1.getPaymentAccounts()) {
|
for (const userAccount of await user1.getPaymentAccounts()) {
|
||||||
if (paymentAccount.getId() === fiatAccount.getId()) {
|
if (paymentAccount.getId() === userAccount.getId()) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1005,8 +1005,8 @@ test("Can validate payment account forms", async () => {
|
|||||||
assert(found, "Payment account not found after adding");
|
assert(found, "Payment account not found after adding");
|
||||||
|
|
||||||
// test payment account
|
// test payment account
|
||||||
expect(fiatAccount.getPaymentMethod()!.getId()).toEqual(paymentMethod.getId());
|
expect(paymentAccount.getPaymentMethod()!.getId()).toEqual(paymentMethod.getId());
|
||||||
testFiatAccount(fiatAccount, accountForm);
|
testPaymentAccount(paymentAccount, accountForm);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1023,12 +1023,12 @@ test("Can create fiat payment accounts", async () => {
|
|||||||
|
|
||||||
// create payment account
|
// create payment account
|
||||||
const fiatAccount = await user1.createPaymentAccount(accountForm);
|
const fiatAccount = await user1.createPaymentAccount(accountForm);
|
||||||
expect(fiatAccount.getAccountName()).toEqual(HavenoUtils.getFormValue(PaymentAccountFormField.FieldId.ACCOUNT_NAME, accountForm));
|
expect(fiatAccount.getAccountName()).toEqual(HavenoUtils.getFormValue(accountForm, PaymentAccountFormField.FieldId.ACCOUNT_NAME));
|
||||||
expect(fiatAccount.getSelectedTradeCurrency()!.getCode()).toEqual("USD");
|
expect(fiatAccount.getSelectedTradeCurrency()!.getCode()).toEqual("USD");
|
||||||
expect(fiatAccount.getTradeCurrenciesList().length).toBeGreaterThan(0);
|
expect(fiatAccount.getTradeCurrenciesList().length).toBeGreaterThan(0);
|
||||||
expect(fiatAccount.getPaymentAccountPayload()!.getPaymentMethodId()).toEqual(paymentMethodId);
|
expect(fiatAccount.getPaymentAccountPayload()!.getPaymentMethodId()).toEqual(paymentMethodId);
|
||||||
expect(fiatAccount.getPaymentAccountPayload()!.getRevolutAccountPayload()!.getAccountId()).toEqual(HavenoUtils.getFormValue(PaymentAccountFormField.FieldId.USER_NAME, accountForm)); // TODO: payment payload account id is username?
|
expect(fiatAccount.getPaymentAccountPayload()!.getRevolutAccountPayload()!.getAccountId()).toEqual(HavenoUtils.getFormValue(accountForm, PaymentAccountFormField.FieldId.USER_NAME)); // TODO: payment payload account id is username?
|
||||||
expect(fiatAccount.getPaymentAccountPayload()!.getRevolutAccountPayload()!.getUserName()).toEqual(HavenoUtils.getFormValue(PaymentAccountFormField.FieldId.USER_NAME, accountForm));
|
expect(fiatAccount.getPaymentAccountPayload()!.getRevolutAccountPayload()!.getUserName()).toEqual(HavenoUtils.getFormValue(accountForm, PaymentAccountFormField.FieldId.USER_NAME));
|
||||||
|
|
||||||
// payment account added
|
// payment account added
|
||||||
let found = false;
|
let found = false;
|
||||||
@ -1324,13 +1324,13 @@ test("Can go offline while completing a trade", async () => {
|
|||||||
test("Can resolve disputes", async () => {
|
test("Can resolve disputes", async () => {
|
||||||
|
|
||||||
// take trades but stop before sending payment
|
// take trades but stop before sending payment
|
||||||
const ctxs = getTradeContexts(5);
|
const ctxs = getTradeContexts(4);
|
||||||
for (const config of ctxs) config.buyerSendsPayment = false;
|
for (const config of ctxs) config.buyerSendsPayment = false;
|
||||||
const tradeIds = await executeTrades(ctxs);
|
const tradeIds = await executeTrades(ctxs);
|
||||||
|
|
||||||
// open disputes at same time but do not resolve
|
// open disputes at same time but do not resolve
|
||||||
|
const trade1 = await user1.getTrade(tradeIds[1]);
|
||||||
const trade2 = await user1.getTrade(tradeIds[2]);
|
const trade2 = await user1.getTrade(tradeIds[2]);
|
||||||
const trade3 = await user1.getTrade(tradeIds[3]);
|
|
||||||
Object.assign(ctxs[0], {
|
Object.assign(ctxs[0], {
|
||||||
resolveDispute: false,
|
resolveDispute: false,
|
||||||
sellerDisputeContext: DisputeContext.OPEN_AFTER_DEPOSITS_UNLOCK,
|
sellerDisputeContext: DisputeContext.OPEN_AFTER_DEPOSITS_UNLOCK,
|
||||||
@ -1343,25 +1343,18 @@ test("Can resolve disputes", async () => {
|
|||||||
buyerDisputeContext: DisputeContext.OPEN_AFTER_DEPOSITS_UNLOCK,
|
buyerDisputeContext: DisputeContext.OPEN_AFTER_DEPOSITS_UNLOCK,
|
||||||
disputeWinner: DisputeResult.Winner.BUYER,
|
disputeWinner: DisputeResult.Winner.BUYER,
|
||||||
disputeReason: DisputeResult.Reason.SELLER_NOT_RESPONDING,
|
disputeReason: DisputeResult.Reason.SELLER_NOT_RESPONDING,
|
||||||
disputeSummary: "Buyer is winner"
|
disputeSummary: "Split trade amount",
|
||||||
|
disputeWinnerAmount: BigInt(trade1.getAmountAsLong()) / BigInt(2) + HavenoUtils.centinerosToAtomicUnits(trade1.getOffer()!.getBuyerSecurityDeposit())
|
||||||
});
|
});
|
||||||
Object.assign(ctxs[2], {
|
Object.assign(ctxs[2], {
|
||||||
resolveDispute: false,
|
|
||||||
sellerDisputeContext: DisputeContext.OPEN_AFTER_DEPOSITS_UNLOCK,
|
|
||||||
disputeWinner: DisputeResult.Winner.BUYER,
|
|
||||||
disputeReason: DisputeResult.Reason.WRONG_SENDER_ACCOUNT,
|
|
||||||
disputeSummary: "Split trade amount",
|
|
||||||
disputeWinnerAmount: BigInt(trade2.getAmountAsLong()) / BigInt(2) + HavenoUtils.centinerosToAtomicUnits(trade2.getOffer()!.getBuyerSecurityDeposit())
|
|
||||||
});
|
|
||||||
Object.assign(ctxs[3], {
|
|
||||||
resolveDispute: false,
|
resolveDispute: false,
|
||||||
buyerDisputeContext: DisputeContext.OPEN_AFTER_DEPOSITS_UNLOCK,
|
buyerDisputeContext: DisputeContext.OPEN_AFTER_DEPOSITS_UNLOCK,
|
||||||
disputeWinner: DisputeResult.Winner.SELLER,
|
disputeWinner: DisputeResult.Winner.SELLER,
|
||||||
disputeReason: DisputeResult.Reason.TRADE_ALREADY_SETTLED,
|
disputeReason: DisputeResult.Reason.TRADE_ALREADY_SETTLED,
|
||||||
disputeSummary: "Seller gets everything",
|
disputeSummary: "Seller gets everything",
|
||||||
disputeWinnerAmount: BigInt(trade3.getAmountAsLong()) + HavenoUtils.centinerosToAtomicUnits(trade3.getOffer()!.getBuyerSecurityDeposit() + trade3.getOffer()!.getSellerSecurityDeposit())
|
disputeWinnerAmount: BigInt(trade2.getAmountAsLong()) + HavenoUtils.centinerosToAtomicUnits(trade2.getOffer()!.getBuyerSecurityDeposit() + trade2.getOffer()!.getSellerSecurityDeposit())
|
||||||
});
|
});
|
||||||
Object.assign(ctxs[4], {
|
Object.assign(ctxs[3], {
|
||||||
resolveDispute: false,
|
resolveDispute: false,
|
||||||
buyerSendsPayment: true,
|
buyerSendsPayment: true,
|
||||||
sellerDisputeContext: DisputeContext.OPEN_AFTER_PAYMENT_SENT,
|
sellerDisputeContext: DisputeContext.OPEN_AFTER_PAYMENT_SENT,
|
||||||
@ -1628,7 +1621,7 @@ test("Selects arbitrators which are online, registered, and least used", async (
|
|||||||
|
|
||||||
// complete a trade which uses arbitrator2 since it's least used
|
// complete a trade which uses arbitrator2 since it's least used
|
||||||
HavenoUtils.log(1, "Completing trade using arbitrator2");
|
HavenoUtils.log(1, "Completing trade using arbitrator2");
|
||||||
await executeTrade({maker: user1, taker: user2, offerId: offers[0].getId(), arbitrator: arbitrator2});
|
await executeTrade({maker: user1, taker: user2, arbitrator: arbitrator2, offerId: offers[0].getId(), makerPaymentAccountId: offers[0].getPaymentAccountId()});
|
||||||
let trade = await user1.getTrade(offers[0].getId());
|
let trade = await user1.getTrade(offers[0].getId());
|
||||||
assert.equal(trade.getArbitratorNodeAddress(), arbitrator2ApiUrl);
|
assert.equal(trade.getArbitratorNodeAddress(), arbitrator2ApiUrl);
|
||||||
|
|
||||||
@ -1644,7 +1637,7 @@ test("Selects arbitrators which are online, registered, and least used", async (
|
|||||||
|
|
||||||
// complete a trade which uses main arbitrator since signer/least used is offline
|
// complete a trade which uses main arbitrator since signer/least used is offline
|
||||||
HavenoUtils.log(1, "Completing trade using main arbitrator since signer/least used is offline");
|
HavenoUtils.log(1, "Completing trade using main arbitrator since signer/least used is offline");
|
||||||
await executeTrade({maker: user1, taker: user2, offerId: offers[1].getId()});
|
await executeTrade({maker: user1, taker: user2, offerId: offers[1].getId(), makerPaymentAccountId: offers[1].getPaymentAccountId()});
|
||||||
trade = await user1.getTrade(offers[1].getId());
|
trade = await user1.getTrade(offers[1].getId());
|
||||||
assert.equal(trade.getArbitratorNodeAddress(), arbitratorApiUrl);
|
assert.equal(trade.getArbitratorNodeAddress(), arbitratorApiUrl);
|
||||||
|
|
||||||
@ -1672,7 +1665,7 @@ test("Selects arbitrators which are online, registered, and least used", async (
|
|||||||
|
|
||||||
// complete a trade which uses main arbitrator since least used is unregistered
|
// complete a trade which uses main arbitrator since least used is unregistered
|
||||||
HavenoUtils.log(1, "Completing trade with main arbitrator since least used is unregistered");
|
HavenoUtils.log(1, "Completing trade with main arbitrator since least used is unregistered");
|
||||||
await executeTrade({maker: user1, taker: user2, offerId: offer.getId()});
|
await executeTrade({maker: user1, taker: user2, offerId: offer.getId(), makerPaymentAccountId: offer.getPaymentAccountId()});
|
||||||
HavenoUtils.log(1, "Done completing trade with main arbitrator since least used is unregistered");
|
HavenoUtils.log(1, "Done completing trade with main arbitrator since least used is unregistered");
|
||||||
trade = await user2.getTrade(offer.getId());
|
trade = await user2.getTrade(offer.getId());
|
||||||
HavenoUtils.log(1, "Done getting trade");
|
HavenoUtils.log(1, "Done getting trade");
|
||||||
@ -1824,7 +1817,7 @@ async function executeTrade(ctx?: TradeContext): Promise<string> {
|
|||||||
offer = await makeOffer(ctx);
|
offer = await makeOffer(ctx);
|
||||||
expect(offer.getState()).toEqual("AVAILABLE");
|
expect(offer.getState()).toEqual("AVAILABLE");
|
||||||
ctx.offerId = offer.getId();
|
ctx.offerId = offer.getId();
|
||||||
await wait(TestConfig.walletSyncPeriodMs * 2);
|
await wait(TestConfig.maxTimePeerNoticeMs + TestConfig.walletSyncPeriodMs * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (woodser): test error message taking offer before posted
|
// TODO (woodser): test error message taking offer before posted
|
||||||
@ -1840,6 +1833,17 @@ async function executeTrade(ctx?: TradeContext): Promise<string> {
|
|||||||
|
|
||||||
// test trader chat
|
// test trader chat
|
||||||
if (ctx.testTraderChat) await testTradeChat(trade.getTradeId(), ctx.maker!, ctx.taker!);
|
if (ctx.testTraderChat) await testTradeChat(trade.getTradeId(), ctx.maker!, ctx.taker!);
|
||||||
|
|
||||||
|
// get expected payment account payloads
|
||||||
|
let expectedBuyerPaymentAccountPayload = (await ctx.buyer?.getPaymentAccount(ctx.maker == ctx.buyer ? ctx.makerPaymentAccountId! : ctx.takerPaymentAccountId!))?.getPaymentAccountPayload();
|
||||||
|
let expectedSellerPaymentAccountPayload = (await ctx.seller?.getPaymentAccount(ctx.maker == ctx.buyer ? ctx.takerPaymentAccountId! : ctx.makerPaymentAccountId!))?.getPaymentAccountPayload();
|
||||||
|
|
||||||
|
// seller does not have buyer's payment account payload until payment sent
|
||||||
|
let fetchedTrade = await ctx.seller!.getTrade(ctx.offerId!);
|
||||||
|
let contract = fetchedTrade.getContract()!;
|
||||||
|
let buyerPaymentAccountPayload = contract.getIsBuyerMakerAndSellerTaker() ? contract.getMakerPaymentAccountPayload() : contract.getTakerPaymentAccountPayload();
|
||||||
|
if (ctx.isPaymentSent) expect(buyerPaymentAccountPayload).toEqual(expectedBuyerPaymentAccountPayload);
|
||||||
|
else expect(buyerPaymentAccountPayload).toBeUndefined();
|
||||||
|
|
||||||
// shut down buyer and seller if configured
|
// shut down buyer and seller if configured
|
||||||
const promises: Promise<void>[] = [];
|
const promises: Promise<void>[] = [];
|
||||||
@ -1873,7 +1877,7 @@ async function executeTrade(ctx?: TradeContext): Promise<string> {
|
|||||||
await wait(TestConfig.maxWalletStartupMs + TestConfig.walletSyncPeriodMs * 2);
|
await wait(TestConfig.maxWalletStartupMs + TestConfig.walletSyncPeriodMs * 2);
|
||||||
const expectedState = ctx.isPaymentSent ? "PAYMENT_SENT" : "DEPOSITS_UNLOCKED" // TODO: test COMPLETED, PAYMENT_RECEIVED states?
|
const expectedState = ctx.isPaymentSent ? "PAYMENT_SENT" : "DEPOSITS_UNLOCKED" // TODO: test COMPLETED, PAYMENT_RECEIVED states?
|
||||||
expect((await ctx.buyer!.getTrade(offer!.getId())).getPhase()).toEqual(expectedState);
|
expect((await ctx.buyer!.getTrade(offer!.getId())).getPhase()).toEqual(expectedState);
|
||||||
let fetchedTrade = await ctx.buyer!.getTrade(ctx.offerId!);
|
fetchedTrade = await ctx.buyer!.getTrade(ctx.offerId!);
|
||||||
expect(fetchedTrade.getIsDepositUnlocked()).toBe(true);
|
expect(fetchedTrade.getIsDepositUnlocked()).toBe(true);
|
||||||
expect(fetchedTrade.getPhase()).toEqual(expectedState);
|
expect(fetchedTrade.getPhase()).toEqual(expectedState);
|
||||||
if (!ctx.sellerOfflineAfterTake) {
|
if (!ctx.sellerOfflineAfterTake) {
|
||||||
@ -1881,7 +1885,16 @@ async function executeTrade(ctx?: TradeContext): Promise<string> {
|
|||||||
expect(fetchedTrade.getIsDepositUnlocked()).toBe(true);
|
expect(fetchedTrade.getIsDepositUnlocked()).toBe(true);
|
||||||
expect(fetchedTrade.getPhase()).toEqual(expectedState);
|
expect(fetchedTrade.getPhase()).toEqual(expectedState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buyer has seller's payment account payload after first confirmation
|
||||||
|
fetchedTrade = await ctx.buyer!.getTrade(ctx.offerId!);
|
||||||
|
contract = fetchedTrade.getContract()!;
|
||||||
|
let sellerPaymentAccountPayload = contract.getIsBuyerMakerAndSellerTaker() ? contract.getTakerPaymentAccountPayload() : contract.getMakerPaymentAccountPayload();
|
||||||
|
expect(sellerPaymentAccountPayload).toEqual(expectedSellerPaymentAccountPayload);
|
||||||
|
let form = await ctx.buyer!.getPaymentAccountPayloadForm(sellerPaymentAccountPayload!);
|
||||||
|
let expectedForm = await ctx.buyer!.getPaymentAccountPayloadForm(expectedSellerPaymentAccountPayload!);
|
||||||
|
expect(HavenoUtils.formToString(form)).toEqual(HavenoUtils.formToString(expectedForm));
|
||||||
|
|
||||||
// buyer notified to send payment TODO
|
// buyer notified to send payment TODO
|
||||||
|
|
||||||
// open dispute(s) if configured
|
// open dispute(s) if configured
|
||||||
@ -1938,6 +1951,15 @@ async function executeTrade(ctx?: TradeContext): Promise<string> {
|
|||||||
expect(fetchedTrade.getPhase()).toEqual("PAYMENT_SENT");
|
expect(fetchedTrade.getPhase()).toEqual("PAYMENT_SENT");
|
||||||
expect(fetchedTrade.getPayoutState()).toEqual("PAYOUT_UNPUBLISHED");
|
expect(fetchedTrade.getPayoutState()).toEqual("PAYOUT_UNPUBLISHED");
|
||||||
|
|
||||||
|
// seller has buyer's payment account payload after payment sent
|
||||||
|
fetchedTrade = await ctx.seller!.getTrade(ctx.offerId!);
|
||||||
|
contract = fetchedTrade.getContract()!;
|
||||||
|
buyerPaymentAccountPayload = contract.getIsBuyerMakerAndSellerTaker() ? contract.getMakerPaymentAccountPayload() : contract.getTakerPaymentAccountPayload();
|
||||||
|
expect(buyerPaymentAccountPayload).toEqual(expectedBuyerPaymentAccountPayload);
|
||||||
|
form = await ctx.seller!.getPaymentAccountPayloadForm(sellerPaymentAccountPayload!);
|
||||||
|
expectedForm = await ctx.seller!.getPaymentAccountPayloadForm(expectedSellerPaymentAccountPayload!);
|
||||||
|
expect(HavenoUtils.formToString(form)).toEqual(HavenoUtils.formToString(expectedForm));
|
||||||
|
|
||||||
// open dispute(s) if configured
|
// open dispute(s) if configured
|
||||||
if (ctx.buyerDisputeContext === DisputeContext.OPEN_AFTER_PAYMENT_SENT && !ctx.buyerOpenedDispute) {
|
if (ctx.buyerDisputeContext === DisputeContext.OPEN_AFTER_PAYMENT_SENT && !ctx.buyerOpenedDispute) {
|
||||||
await ctx.buyer!.openDispute(ctx.offerId!);
|
await ctx.buyer!.openDispute(ctx.offerId!);
|
||||||
@ -2054,9 +2076,15 @@ async function makeOffer(ctx?: TradeContext): Promise<OfferInfo> {
|
|||||||
|
|
||||||
// create payment account if not given // TODO: re-use existing payment account
|
// create payment account if not given // TODO: re-use existing payment account
|
||||||
if (!ctx.makerPaymentAccountId) ctx.makerPaymentAccountId = (await createPaymentAccount(ctx.maker!, ctx.assetCode!)).getId();
|
if (!ctx.makerPaymentAccountId) ctx.makerPaymentAccountId = (await createPaymentAccount(ctx.maker!, ctx.assetCode!)).getId();
|
||||||
|
|
||||||
// get unlocked balance before reserving offer
|
// get unlocked balance before reserving offer
|
||||||
const unlockedBalanceBefore = BigInt((await ctx.maker!.getBalances()).getAvailableBalance());
|
let unlockedBalanceBefore = BigInt((await ctx.maker!.getBalances()).getAvailableBalance());
|
||||||
|
if (ctx.awaitFundsToMakeOffer && unlockedBalanceBefore === BigInt(0)) {
|
||||||
|
HavenoUtils.log(0, "WARNING: unlocked balance before posting offer is 0, waiting...");
|
||||||
|
await wait(5000);
|
||||||
|
unlockedBalanceBefore = BigInt((await ctx.maker!.getBalances()).getAvailableBalance());
|
||||||
|
if (unlockedBalanceBefore === BigInt(0)) throw new Error("Unlocked balance before posting offer was 0, even after waiting");
|
||||||
|
}
|
||||||
|
|
||||||
// post offer
|
// post offer
|
||||||
const offer: OfferInfo = await ctx.maker!.postOffer(
|
const offer: OfferInfo = await ctx.maker!.postOffer(
|
||||||
@ -2101,7 +2129,7 @@ async function takeOffer(ctx: TradeContext): Promise<TradeInfo> {
|
|||||||
// taker sees offer
|
// taker sees offer
|
||||||
if (!ctx.offerId) throw new Error("Must provide offer id");
|
if (!ctx.offerId) throw new Error("Must provide offer id");
|
||||||
const takerOffer = getOffer(await ctx.taker!.getOffers(ctx.assetCode!, ctx.direction), ctx.offerId);
|
const takerOffer = getOffer(await ctx.taker!.getOffers(ctx.assetCode!, ctx.direction), ctx.offerId);
|
||||||
if (!takerOffer) throw new Error("Offer " + ctx.offerId + " was not found in taker's offers after posting");
|
if (!takerOffer) throw new Error("Offer " + ctx.offerId + " was not found in taker's offers");
|
||||||
expect(takerOffer.getState()).toEqual("UNKNOWN"); // TODO: offer state should be known
|
expect(takerOffer.getState()).toEqual("UNKNOWN"); // TODO: offer state should be known
|
||||||
|
|
||||||
// wait for unlocked balance
|
// wait for unlocked balance
|
||||||
@ -2182,6 +2210,31 @@ async function testOpenDispute(ctx: TradeContext) {
|
|||||||
assert(arbDisputePeer);
|
assert(arbDisputePeer);
|
||||||
const arbDisputeOpener = disputes.find(d => d.getId() === openerDispute.getId());
|
const arbDisputeOpener = disputes.find(d => d.getId() === openerDispute.getId());
|
||||||
assert(arbDisputeOpener);
|
assert(arbDisputeOpener);
|
||||||
|
|
||||||
|
// arbitrator has seller's payment account info
|
||||||
|
let sellerPaymentAccountPayload = arbDisputeOpener.getContract()!.getIsBuyerMakerAndSellerTaker() ? arbDisputeOpener.getTakerPaymentAccountPayload() : arbDisputeOpener.getMakerPaymentAccountPayload();
|
||||||
|
let expectedSellerPaymentAccountPayload = (await ctx.seller?.getPaymentAccount(sellerPaymentAccountPayload?.getId()!))?.getPaymentAccountPayload();
|
||||||
|
expect(sellerPaymentAccountPayload).toEqual(expectedSellerPaymentAccountPayload);
|
||||||
|
expect(await ctx.arbitrator?.getPaymentAccountPayloadForm(sellerPaymentAccountPayload!)).toEqual(await ctx.arbitrator?.getPaymentAccountPayloadForm(expectedSellerPaymentAccountPayload!));
|
||||||
|
sellerPaymentAccountPayload = arbDisputePeer.getContract()!.getIsBuyerMakerAndSellerTaker() ? arbDisputePeer.getTakerPaymentAccountPayload() : arbDisputeOpener.getMakerPaymentAccountPayload();
|
||||||
|
expect(sellerPaymentAccountPayload).toEqual(expectedSellerPaymentAccountPayload);
|
||||||
|
expect(await ctx.arbitrator?.getPaymentAccountPayloadForm(sellerPaymentAccountPayload!)).toEqual(await ctx.arbitrator?.getPaymentAccountPayloadForm(expectedSellerPaymentAccountPayload!));
|
||||||
|
|
||||||
|
// arbitrator has buyer's payment account info unless opener is seller and payment not sent
|
||||||
|
let buyerPaymentAccountPayload = arbDisputeOpener.getContract()!.getIsBuyerMakerAndSellerTaker() ? arbDisputeOpener.getMakerPaymentAccountPayload() : arbDisputeOpener.getTakerPaymentAccountPayload();
|
||||||
|
if (ctx.disputeOpener === ctx.seller && !ctx.isPaymentSent) expect(buyerPaymentAccountPayload).toBeUndefined();
|
||||||
|
else {
|
||||||
|
let expectedBuyerPaymentAccountPayload = (await ctx.buyer?.getPaymentAccount(buyerPaymentAccountPayload?.getId()!))?.getPaymentAccountPayload();
|
||||||
|
expect(buyerPaymentAccountPayload).toEqual(expectedBuyerPaymentAccountPayload);
|
||||||
|
expect(await ctx.arbitrator?.getPaymentAccountPayloadForm(buyerPaymentAccountPayload!)).toEqual(await ctx.arbitrator?.getPaymentAccountPayloadForm(expectedBuyerPaymentAccountPayload!));
|
||||||
|
}
|
||||||
|
buyerPaymentAccountPayload = arbDisputePeer.getContract()!.getIsBuyerMakerAndSellerTaker() ? arbDisputePeer.getMakerPaymentAccountPayload() : arbDisputePeer.getTakerPaymentAccountPayload();
|
||||||
|
if (ctx.disputeOpener === ctx.seller && !ctx.isPaymentSent) expect(buyerPaymentAccountPayload).toBeUndefined();
|
||||||
|
else {
|
||||||
|
let expectedBuyerPaymentAccountPayload = (await ctx.buyer?.getPaymentAccount(buyerPaymentAccountPayload?.getId()!))?.getPaymentAccountPayload();
|
||||||
|
expect(buyerPaymentAccountPayload).toEqual(expectedBuyerPaymentAccountPayload);
|
||||||
|
expect(await ctx.arbitrator?.getPaymentAccountPayloadForm(buyerPaymentAccountPayload!)).toEqual(await ctx.arbitrator?.getPaymentAccountPayloadForm(expectedBuyerPaymentAccountPayload!));
|
||||||
|
}
|
||||||
|
|
||||||
// register to receive notifications
|
// register to receive notifications
|
||||||
const disputeOpenerNotifications: NotificationMessage[] = [];
|
const disputeOpenerNotifications: NotificationMessage[] = [];
|
||||||
@ -3101,16 +3154,20 @@ function getValidFormInput(fieldId: PaymentAccountFormField.FieldId, form: Payme
|
|||||||
return "123456";
|
return "123456";
|
||||||
case PaymentAccountFormField.FieldId.SPECIAL_INSTRUCTIONS:
|
case PaymentAccountFormField.FieldId.SPECIAL_INSTRUCTIONS:
|
||||||
return "asap plz";
|
return "asap plz";
|
||||||
case PaymentAccountFormField.FieldId.STATE: {
|
case PaymentAccountFormField.FieldId.STATE:
|
||||||
const country = HavenoUtils.getFormValue(PaymentAccountFormField.FieldId.COUNTRY, form);
|
const country = HavenoUtils.getFormValue(form, PaymentAccountFormField.FieldId.COUNTRY);
|
||||||
return GenUtils.arrayContains(field.getRequiredForCountriesList(), country) ? "My state" : "";
|
return GenUtils.arrayContains(field.getRequiredForCountriesList(), country) ? "My state" : "";
|
||||||
}
|
|
||||||
case PaymentAccountFormField.FieldId.TRADE_CURRENCIES:
|
case PaymentAccountFormField.FieldId.TRADE_CURRENCIES:
|
||||||
return field.getSupportedCurrenciesList().map(currency => currency.getCode()).join(',');
|
if (field.getComponent() === PaymentAccountFormField.Component.SELECT_ONE) return field.getSupportedCurrenciesList().at(0)!.getCode(); // TODO: randomly select?
|
||||||
|
else return field.getSupportedCurrenciesList().map(currency => currency.getCode()).join(',');
|
||||||
case PaymentAccountFormField.FieldId.USER_NAME:
|
case PaymentAccountFormField.FieldId.USER_NAME:
|
||||||
return "user123";
|
return "user123";
|
||||||
case PaymentAccountFormField.FieldId.VIRTUAL_PAYMENT_ADDRESS:
|
case PaymentAccountFormField.FieldId.ADDRESS:
|
||||||
throw new Error("Not implemented");
|
const currencyCode = HavenoUtils.getFormValue(form, PaymentAccountFormField.FieldId.TRADE_CURRENCIES);
|
||||||
|
for (let cryptoAddress of TestConfig.cryptoAddresses) {
|
||||||
|
if (cryptoAddress.currencyCode.toLowerCase() === currencyCode.toLowerCase()) return cryptoAddress.address;
|
||||||
|
}
|
||||||
|
throw new Error("Unsupported blockchain currency code: " + currencyCode);
|
||||||
default:
|
default:
|
||||||
throw new Error("Unhandled form field: " + fieldId);
|
throw new Error("Unhandled form field: " + fieldId);
|
||||||
}
|
}
|
||||||
@ -3229,26 +3286,31 @@ function getInvalidFormInput(form: PaymentAccountForm, fieldId: PaymentAccountFo
|
|||||||
case PaymentAccountFormField.FieldId.SPECIAL_INSTRUCTIONS:
|
case PaymentAccountFormField.FieldId.SPECIAL_INSTRUCTIONS:
|
||||||
throw new Error("Special instructions have no invalid input");
|
throw new Error("Special instructions have no invalid input");
|
||||||
case PaymentAccountFormField.FieldId.STATE: {
|
case PaymentAccountFormField.FieldId.STATE: {
|
||||||
const country = HavenoUtils.getFormValue(PaymentAccountFormField.FieldId.COUNTRY, form);
|
const country = HavenoUtils.getFormValue(form, PaymentAccountFormField.FieldId.COUNTRY);
|
||||||
return GenUtils.arrayContains(field.getRequiredForCountriesList(), country) ? "" : "My state";
|
return GenUtils.arrayContains(field.getRequiredForCountriesList(), country) ? "" : "My state";
|
||||||
}
|
}
|
||||||
case PaymentAccountFormField.FieldId.TRADE_CURRENCIES:
|
case PaymentAccountFormField.FieldId.TRADE_CURRENCIES:
|
||||||
return "abc,def";
|
return "abc,def";
|
||||||
case PaymentAccountFormField.FieldId.USER_NAME:
|
case PaymentAccountFormField.FieldId.USER_NAME:
|
||||||
return "A";
|
return "A";
|
||||||
case PaymentAccountFormField.FieldId.VIRTUAL_PAYMENT_ADDRESS:
|
case PaymentAccountFormField.FieldId.ADDRESS:
|
||||||
throw new Error("Not implemented");
|
return "A123";
|
||||||
default:
|
default:
|
||||||
throw new Error("Unhandled form field: " + fieldId);
|
throw new Error("Unhandled form field: " + fieldId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testFiatAccount(account: PaymentAccount, form: PaymentAccountForm) {
|
function testPaymentAccount(account: PaymentAccount, form: PaymentAccountForm) {
|
||||||
|
if (account.getPaymentAccountPayload()?.getCryptoCurrencyAccountPayload()) testCryptoPaymentAccount(account); // TODO: test non-crypto
|
||||||
expect(account.getAccountName()).toEqual(getFormField(form, PaymentAccountFormField.FieldId.ACCOUNT_NAME).getValue()); // TODO: using number as payment method, account payload's account name = user name
|
expect(account.getAccountName()).toEqual(getFormField(form, PaymentAccountFormField.FieldId.ACCOUNT_NAME).getValue()); // TODO: using number as payment method, account payload's account name = user name
|
||||||
const isCountryBased = account.getPaymentAccountPayload()!.getCountryBasedPaymentAccountPayload() !== undefined;
|
const isCountryBased = account.getPaymentAccountPayload()!.getCountryBasedPaymentAccountPayload() !== undefined;
|
||||||
if (isCountryBased) expect(account.getPaymentAccountPayload()!.getCountryBasedPaymentAccountPayload()!.getCountryCode()).toEqual(getFormField(form, PaymentAccountFormField.FieldId.COUNTRY).getValue());
|
if (isCountryBased) expect(account.getPaymentAccountPayload()!.getCountryBasedPaymentAccountPayload()!.getCountryCode()).toEqual(getFormField(form, PaymentAccountFormField.FieldId.COUNTRY).getValue());
|
||||||
switch (form.getId()) {
|
switch (form.getId()) {
|
||||||
case PaymentAccountForm.FormId.REVOLUT:
|
case PaymentAccountForm.FormId.BLOCK_CHAINS:
|
||||||
|
expect(account.getPaymentAccountPayload()!.getCryptoCurrencyAccountPayload()!.getAddress()).toEqual(getFormField(form, PaymentAccountFormField.FieldId.ADDRESS).getValue());
|
||||||
|
expect(account.getTradeCurrenciesList().map(currency => currency.getCode()).join(",")).toEqual(getFormField(form, PaymentAccountFormField.FieldId.TRADE_CURRENCIES).getValue());
|
||||||
|
break;
|
||||||
|
case PaymentAccountForm.FormId.REVOLUT:
|
||||||
expect(account.getPaymentAccountPayload()!.getRevolutAccountPayload()!.getUserName()).toEqual(getFormField(form, PaymentAccountFormField.FieldId.USER_NAME).getValue());
|
expect(account.getPaymentAccountPayload()!.getRevolutAccountPayload()!.getUserName()).toEqual(getFormField(form, PaymentAccountFormField.FieldId.USER_NAME).getValue());
|
||||||
expect(account.getTradeCurrenciesList().map(currency => currency.getCode()).join(",")).toEqual(getFormField(form, PaymentAccountFormField.FieldId.TRADE_CURRENCIES).getValue());
|
expect(account.getTradeCurrenciesList().map(currency => currency.getCode()).join(",")).toEqual(getFormField(form, PaymentAccountFormField.FieldId.TRADE_CURRENCIES).getValue());
|
||||||
break;
|
break;
|
||||||
|
@ -5,7 +5,7 @@ import TaskLooper from "./utils/TaskLooper";
|
|||||||
import type * as grpcWeb from "grpc-web";
|
import type * as grpcWeb from "grpc-web";
|
||||||
import { GetVersionClient, AccountClient, MoneroConnectionsClient, DisputesClient, DisputeAgentsClient, NotificationsClient, WalletsClient, PriceClient, OffersClient, PaymentAccountsClient, TradesClient, ShutdownServerClient, MoneroNodeClient } from './protobuf/GrpcServiceClientPb';
|
import { GetVersionClient, AccountClient, MoneroConnectionsClient, DisputesClient, DisputeAgentsClient, NotificationsClient, WalletsClient, PriceClient, OffersClient, PaymentAccountsClient, TradesClient, ShutdownServerClient, MoneroNodeClient } from './protobuf/GrpcServiceClientPb';
|
||||||
import { GetVersionRequest, GetVersionReply, IsAppInitializedRequest, IsAppInitializedReply, RegisterDisputeAgentRequest, UnregisterDisputeAgentRequest, MarketPriceRequest, MarketPriceReply, MarketPricesRequest, MarketPricesReply, MarketPriceInfo, MarketDepthRequest, MarketDepthReply, MarketDepthInfo, GetBalancesRequest, GetBalancesReply, XmrBalanceInfo, GetMyOfferRequest, GetMyOfferReply, GetOffersRequest, GetOffersReply, OfferInfo, GetPaymentMethodsRequest, GetPaymentMethodsReply, GetPaymentAccountFormRequest, CreatePaymentAccountRequest, ValidateFormFieldRequest, CreatePaymentAccountReply, GetPaymentAccountFormReply, GetPaymentAccountsRequest, GetPaymentAccountsReply, CreateCryptoCurrencyPaymentAccountRequest, CreateCryptoCurrencyPaymentAccountReply, CreateOfferRequest, CreateOfferReply, CancelOfferRequest, TakeOfferRequest, TakeOfferReply, TradeInfo, GetTradeRequest, GetTradeReply, GetTradesRequest, GetTradesReply, GetXmrSeedRequest, GetXmrSeedReply, GetXmrPrimaryAddressRequest, GetXmrPrimaryAddressReply, GetXmrNewSubaddressRequest, GetXmrNewSubaddressReply, ConfirmPaymentStartedRequest, ConfirmPaymentReceivedRequest, CompleteTradeRequest, XmrTx, GetXmrTxsRequest, GetXmrTxsReply, XmrDestination, CreateXmrTxRequest, CreateXmrTxReply, RelayXmrTxRequest, RelayXmrTxReply, CreateAccountRequest, AccountExistsRequest, AccountExistsReply, DeleteAccountRequest, OpenAccountRequest, IsAccountOpenRequest, IsAccountOpenReply, CloseAccountRequest, ChangePasswordRequest, BackupAccountRequest, BackupAccountReply, RestoreAccountRequest, StopRequest, NotificationMessage, RegisterNotificationListenerRequest, SendNotificationRequest, UrlConnection, AddConnectionRequest, RemoveConnectionRequest, GetConnectionRequest, GetConnectionsRequest, SetConnectionRequest, CheckConnectionRequest, CheckConnectionsReply, CheckConnectionsRequest, StartCheckingConnectionsRequest, StopCheckingConnectionsRequest, GetBestAvailableConnectionRequest, SetAutoSwitchRequest, CheckConnectionReply, GetConnectionsReply, GetConnectionReply, GetBestAvailableConnectionReply, GetDisputeRequest, GetDisputeReply, GetDisputesRequest, GetDisputesReply, OpenDisputeRequest, ResolveDisputeRequest, SendDisputeChatMessageRequest, SendChatMessageRequest, GetChatMessagesRequest, GetChatMessagesReply, StartMoneroNodeRequest, StopMoneroNodeRequest, IsMoneroNodeOnlineRequest, IsMoneroNodeOnlineReply, GetMoneroNodeSettingsRequest, GetMoneroNodeSettingsReply } from "./protobuf/grpc_pb";
|
import { GetVersionRequest, GetVersionReply, IsAppInitializedRequest, IsAppInitializedReply, RegisterDisputeAgentRequest, UnregisterDisputeAgentRequest, MarketPriceRequest, MarketPriceReply, MarketPricesRequest, MarketPricesReply, MarketPriceInfo, MarketDepthRequest, MarketDepthReply, MarketDepthInfo, GetBalancesRequest, GetBalancesReply, XmrBalanceInfo, GetMyOfferRequest, GetMyOfferReply, GetOffersRequest, GetOffersReply, OfferInfo, GetPaymentMethodsRequest, GetPaymentMethodsReply, GetPaymentAccountFormRequest, CreatePaymentAccountRequest, ValidateFormFieldRequest, CreatePaymentAccountReply, GetPaymentAccountFormReply, GetPaymentAccountsRequest, GetPaymentAccountsReply, CreateCryptoCurrencyPaymentAccountRequest, CreateCryptoCurrencyPaymentAccountReply, CreateOfferRequest, CreateOfferReply, CancelOfferRequest, TakeOfferRequest, TakeOfferReply, TradeInfo, GetTradeRequest, GetTradeReply, GetTradesRequest, GetTradesReply, GetXmrSeedRequest, GetXmrSeedReply, GetXmrPrimaryAddressRequest, GetXmrPrimaryAddressReply, GetXmrNewSubaddressRequest, GetXmrNewSubaddressReply, ConfirmPaymentStartedRequest, ConfirmPaymentReceivedRequest, CompleteTradeRequest, XmrTx, GetXmrTxsRequest, GetXmrTxsReply, XmrDestination, CreateXmrTxRequest, CreateXmrTxReply, RelayXmrTxRequest, RelayXmrTxReply, CreateAccountRequest, AccountExistsRequest, AccountExistsReply, DeleteAccountRequest, OpenAccountRequest, IsAccountOpenRequest, IsAccountOpenReply, CloseAccountRequest, ChangePasswordRequest, BackupAccountRequest, BackupAccountReply, RestoreAccountRequest, StopRequest, NotificationMessage, RegisterNotificationListenerRequest, SendNotificationRequest, UrlConnection, AddConnectionRequest, RemoveConnectionRequest, GetConnectionRequest, GetConnectionsRequest, SetConnectionRequest, CheckConnectionRequest, CheckConnectionsReply, CheckConnectionsRequest, StartCheckingConnectionsRequest, StopCheckingConnectionsRequest, GetBestAvailableConnectionRequest, SetAutoSwitchRequest, CheckConnectionReply, GetConnectionsReply, GetConnectionReply, GetBestAvailableConnectionReply, GetDisputeRequest, GetDisputeReply, GetDisputesRequest, GetDisputesReply, OpenDisputeRequest, ResolveDisputeRequest, SendDisputeChatMessageRequest, SendChatMessageRequest, GetChatMessagesRequest, GetChatMessagesReply, StartMoneroNodeRequest, StopMoneroNodeRequest, IsMoneroNodeOnlineRequest, IsMoneroNodeOnlineReply, GetMoneroNodeSettingsRequest, GetMoneroNodeSettingsReply } from "./protobuf/grpc_pb";
|
||||||
import { PaymentMethod, PaymentAccountForm, PaymentAccountFormField, PaymentAccount, AvailabilityResult, Attachment, DisputeResult, Dispute, ChatMessage, MoneroNodeSettings } from "./protobuf/pb_pb";
|
import { PaymentMethod, PaymentAccountForm, PaymentAccountFormField, PaymentAccount, PaymentAccountPayload, AvailabilityResult, Attachment, DisputeResult, Dispute, ChatMessage, MoneroNodeSettings } from "./protobuf/pb_pb";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Haveno daemon client.
|
* Haveno daemon client.
|
||||||
@ -1057,6 +1057,25 @@ export default class HavenoClient {
|
|||||||
throw new HavenoError(e.message, e.code);
|
throw new HavenoError(e.message, e.code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a form from the given payment account payload.
|
||||||
|
*
|
||||||
|
* @param {PaymentAccountPayload} paymentAccountPayload - payload to get as a form
|
||||||
|
* @return {PaymentAccountForm} the payment account form
|
||||||
|
*/
|
||||||
|
async getPaymentAccountPayloadForm(paymentAccountPayload: PaymentAccountPayload): Promise<PaymentAccountForm> {
|
||||||
|
try {
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
this._paymentAccountsClient.getPaymentAccountForm(new GetPaymentAccountFormRequest().setPaymentAccountPayload(paymentAccountPayload), {password: this._password}, function(err: grpcWeb.RpcError, response: GetPaymentAccountFormReply) {
|
||||||
|
if (err) reject(err);
|
||||||
|
else resolve(response.getPaymentAccountForm()!);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (e: any) {
|
||||||
|
throw new HavenoError(e.message, e.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validate a form field.
|
* Validate a form field.
|
||||||
|
@ -83,16 +83,30 @@ export default class HavenoUtils {
|
|||||||
static centinerosToAtomicUnits(centineros: number): bigint {
|
static centinerosToAtomicUnits(centineros: number): bigint {
|
||||||
return BigInt(centineros) * BigInt(HavenoUtils.centinerosToAUMultiplier);
|
return BigInt(centineros) * BigInt(HavenoUtils.centinerosToAUMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stringify a payment account form.
|
||||||
|
*
|
||||||
|
* @param form - form to stringify
|
||||||
|
* @return {string} the stringified form
|
||||||
|
*/
|
||||||
|
static formToString(form: PaymentAccountForm): string {
|
||||||
|
let str = "";
|
||||||
|
for (const field of form.getFieldsList()) {
|
||||||
|
str += field.getId() + ": " + this.getFormValue(form, field.getId()) + "\n";
|
||||||
|
}
|
||||||
|
return str.trim();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a form field value.
|
* Get a form field value.
|
||||||
*
|
*
|
||||||
* @param {PaymentAccountFormField.FieldId} fieldId - id of the field to get the value from
|
|
||||||
* @param {PaymentAccountForm} form - form to get the field value from
|
* @param {PaymentAccountForm} form - form to get the field value from
|
||||||
|
* @param {PaymentAccountFormField.FieldId} fieldId - id of the field to get the value from
|
||||||
* @return {string} the form field value
|
* @return {string} the form field value
|
||||||
*/
|
*/
|
||||||
// TODO: attach getter and setter to PaymentAccountForm prototype in typescript?
|
// TODO: attach getter and setter to PaymentAccountForm prototype in typescript?
|
||||||
static getFormValue(fieldId: PaymentAccountFormField.FieldId, form: PaymentAccountForm): string {
|
static getFormValue(form: PaymentAccountForm, fieldId: PaymentAccountFormField.FieldId): string {
|
||||||
for (const field of form.getFieldsList()) {
|
for (const field of form.getFieldsList()) {
|
||||||
if (field.getId() === fieldId) return field.getValue();
|
if (field.getId() === fieldId) return field.getValue();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user