fix u2u
This commit is contained in:
parent
229cfa7a95
commit
0b08fde708
14 changed files with 95 additions and 83 deletions
|
|
@ -4,14 +4,14 @@
|
|||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": " tsc && node build/src/tests/testRunner.js",
|
||||
"start": "tsc && node build/src/index.js",
|
||||
"clean": "rimraf build",
|
||||
"test": "npm run clean && tsc && node build/src/tests/testRunner.js",
|
||||
"start": "npm run clean && tsc && node build/src/index.js",
|
||||
"start:ci": "git reset --hard && git pull && npm run start",
|
||||
"build_autogenerated": "cd proto && rimraf autogenerated && protoc -I ./service --pub_out=. service/*",
|
||||
"build_lnd_client_1": "cd proto && protoc -I ./others --plugin=.\\node_modules\\.bin\\protoc-gen-ts_proto.cmd --ts_proto_out=./lnd --ts_proto_opt=esModuleInterop=true others/* ",
|
||||
"build_lnd_client": "cd proto && rimraf lnd/* && npx protoc --ts_out ./lnd --ts_opt long_type_string --proto_path others others/* ",
|
||||
"typeorm": "typeorm-ts-node-commonjs",
|
||||
"aa": "tsc && cd build && node src/services/nostr/index.js"
|
||||
"typeorm": "typeorm-ts-node-commonjs"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
|
|
@ -30,46 +30,4 @@ export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSett
|
|||
}, event.startAtNano, event.startAtMs)
|
||||
})
|
||||
return { Stop: () => nostr.Stop, Send: (...args) => nostr.Send(...args) }
|
||||
}
|
||||
|
||||
/*
|
||||
export default (serverMethods: Types.ServerMethods, mainHandler: Main, nostrSettings: NostrSettings): Nostr => {
|
||||
// TODO: - move to codegen
|
||||
const nostr = new Nostr(nostrSettings,
|
||||
async (event) => {
|
||||
if (!nostrSettings.allowedPubs.includes(event.pub)) {
|
||||
console.log("nostr pub not allowed")
|
||||
return
|
||||
}
|
||||
let nostrUser = await mainHandler.storage.FindNostrUser(event.pub)
|
||||
if (!nostrUser) {
|
||||
nostrUser = await mainHandler.storage.AddNostrUser(event.pub)
|
||||
}
|
||||
let j: EventRequest
|
||||
try {
|
||||
j = JSON.parse(event.content)
|
||||
} catch {
|
||||
console.error("invalid json event received", event.content)
|
||||
return
|
||||
}
|
||||
if (handledRequests.includes(j.requestId)) {
|
||||
console.log("request already handled")
|
||||
return
|
||||
}
|
||||
handledRequests.push(j.requestId)
|
||||
switch (j.method) {
|
||||
case '/api/user/chain/new':
|
||||
const error = Types.NewAddressRequestValidate(j.body)
|
||||
if (error !== null) {
|
||||
console.error("invalid request from", event.pub, j)// TODO: dont dox
|
||||
return // TODO: respond
|
||||
}
|
||||
if (!serverMethods.NewAddress) {
|
||||
throw new Error("unimplemented NewInvoice")
|
||||
}
|
||||
const res = await serverMethods.NewAddress({ user_id: nostrUser.user.user_id }, j.body)
|
||||
nostr.Send(event.pub, JSON.stringify({ ...res, requestId: j.requestId }))
|
||||
}
|
||||
})
|
||||
return nostr
|
||||
}*/
|
||||
}
|
||||
|
|
@ -189,7 +189,6 @@ export default class {
|
|||
this.log("paying external invoice", invoice)
|
||||
const routingFeeLimit = this.lnd.GetFeeLimitAmount(payAmount)
|
||||
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + routingFeeLimit, invoice)
|
||||
console.log("decremented")
|
||||
const pendingPayment = await this.storage.paymentStorage.AddPendingExternalPayment(userId, invoice, payAmount, linkedApplication)
|
||||
try {
|
||||
const payment = await this.lnd.PayInvoice(invoice, amountForLnd, routingFeeLimit)
|
||||
|
|
@ -523,9 +522,8 @@ export default class {
|
|||
}
|
||||
}
|
||||
|
||||
async SendUserToUserPayment(fromUserId: string, toUserId: string, amount: number, linkedApplication: Application): Promise<number> {
|
||||
let sentAmount = 0
|
||||
await this.storage.StartTransaction(async tx => {
|
||||
async SendUserToUserPayment(fromUserId: string, toUserId: string, amount: number, linkedApplication: Application): Promise<{ amount: number, fees: number }> {
|
||||
const payment = await this.storage.StartTransaction(async tx => {
|
||||
const fromUser = await this.storage.userStorage.GetUser(fromUserId, tx)
|
||||
const toUser = await this.storage.userStorage.GetUser(toUserId, tx)
|
||||
if (fromUser.locked || toUser.locked) {
|
||||
|
|
@ -536,21 +534,21 @@ export default class {
|
|||
}
|
||||
const isAppUserPayment = fromUser.user_id !== linkedApplication.owner.user_id
|
||||
let fee = this.getServiceFee(Types.UserOperationType.OUTGOING_USER_TO_USER, amount, isAppUserPayment)
|
||||
const toIncrement = amount - fee
|
||||
const paymentEntry = await this.storage.paymentStorage.CreateUserToUserPayment(fromUserId, toUserId, amount, fee, linkedApplication, tx)
|
||||
await this.storage.userStorage.DecrementUserBalance(fromUser.user_id, amount, `${toUserId}:${paymentEntry.serial_id}`, tx)
|
||||
await this.storage.userStorage.IncrementUserBalance(toUser.user_id, toIncrement, `${fromUserId}:${paymentEntry.serial_id}`, tx)
|
||||
await this.storage.paymentStorage.SaveUserToUserPayment(paymentEntry, tx)
|
||||
const toDecrement = amount + fee
|
||||
const paymentEntry = await this.storage.paymentStorage.AddPendingUserToUserPayment(fromUserId, toUserId, amount, fee, linkedApplication, tx)
|
||||
await this.storage.userStorage.DecrementUserBalance(fromUser.user_id, toDecrement, `${toUserId}:${paymentEntry.serial_id}`, tx)
|
||||
await this.storage.userStorage.IncrementUserBalance(toUser.user_id, amount, `${fromUserId}:${paymentEntry.serial_id}`, tx)
|
||||
await this.storage.paymentStorage.SetPendingUserToUserPaymentAsPaid(paymentEntry.serial_id, tx)
|
||||
if (isAppUserPayment && fee > 0) {
|
||||
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, fee, 'fees', tx)
|
||||
}
|
||||
sentAmount = toIncrement
|
||||
return paymentEntry
|
||||
})
|
||||
const fromUser = await this.storage.userStorage.GetUser(fromUserId)
|
||||
const toUser = await this.storage.userStorage.GetUser(toUserId)
|
||||
this.storage.eventsLog.LogEvent({ type: 'u2u_sender', userId: fromUserId, appId: linkedApplication.app_id, appUserId: "", balance: fromUser.balance_sats, data: toUserId, amount: amount })
|
||||
this.storage.eventsLog.LogEvent({ type: 'u2u_sender', userId: fromUserId, appId: linkedApplication.app_id, appUserId: "", balance: fromUser.balance_sats, data: toUserId, amount: payment.paid_amount + payment.service_fees })
|
||||
this.storage.eventsLog.LogEvent({ type: 'u2u_receiver', userId: toUserId, appId: linkedApplication.app_id, appUserId: "", balance: toUser.balance_sats, data: fromUserId, amount: amount })
|
||||
return sentAmount
|
||||
return { amount: payment.paid_amount, fees: payment.service_fees }
|
||||
}
|
||||
|
||||
async CheckNewlyConfirmedTxs(height: number) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import Storage from '../storage/index.js'
|
|||
import { LightningHandler } from "../lnd/index.js"
|
||||
import { LoggedEvent } from '../storage/eventsLog.js'
|
||||
import { Invoice, Payment } from '../../../proto/lnd/lightning';
|
||||
import { getLogger } from '../helpers/logger.js';
|
||||
const LN_INVOICE_REGEX = /^(lightning:)?(lnbc|lntb)[0-9a-zA-Z]+$/;
|
||||
const BITCOIN_ADDRESS_REGEX = /^(bitcoin:)?([13][a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-zA-HJ-NP-Z0-9]{39,59})$/;
|
||||
type UniqueDecrementReasons = 'ban'
|
||||
|
|
@ -19,6 +20,7 @@ export default class SanityChecker {
|
|||
incrementSources: Record<string, boolean> = {}
|
||||
decrementSources: Record<string, boolean> = {}
|
||||
decrementEvents: Record<string, { userId: string, refund: number, failure: boolean }> = {}
|
||||
log = getLogger({ appName: "SanityChecker" })
|
||||
users: Record<string, { ts: number, updatedBalance: number }> = {}
|
||||
constructor(storage: Storage, lnd: LightningHandler) {
|
||||
this.storage = storage
|
||||
|
|
@ -201,7 +203,6 @@ export default class SanityChecker {
|
|||
throw new Error("payment failled, should not refund routing fees " + invoice)
|
||||
}
|
||||
if (entry.refund !== amt) {
|
||||
console.log(entry.refund, amt)
|
||||
throw new Error("refund amount mismatch for routing fee refund " + invoice)
|
||||
}
|
||||
}
|
||||
|
|
@ -251,9 +252,8 @@ export default class SanityChecker {
|
|||
|
||||
checkUserEntry(e: LoggedEvent, u: { ts: number, updatedBalance: number } | undefined) {
|
||||
const newEntry = { ts: e.timestampMs, updatedBalance: e.balance + e.amount * (e.type === 'balance_decrement' ? -1 : 1) }
|
||||
console.log(e)
|
||||
if (!u) {
|
||||
console.log(e.userId, "balance starts at", e.balance, "sats and moves by", e.amount * (e.type === 'balance_decrement' ? -1 : 1), "sats, resulting in", newEntry.updatedBalance, "sats")
|
||||
this.log(e.userId, "balance starts at", e.balance, "sats and moves by", e.amount * (e.type === 'balance_decrement' ? -1 : 1), "sats, resulting in", newEntry.updatedBalance, "sats")
|
||||
return newEntry
|
||||
}
|
||||
if (e.timestampMs < u.ts) {
|
||||
|
|
@ -262,7 +262,7 @@ export default class SanityChecker {
|
|||
if (e.balance !== u.updatedBalance) {
|
||||
throw new Error("inconsistent balance update got: " + e.balance + " expected " + u.updatedBalance)
|
||||
}
|
||||
console.log(e.userId, "balance updates from", e.balance, "sats and moves by", e.amount * (e.type === 'balance_decrement' ? -1 : 1), "sats, resulting in", newEntry.updatedBalance, "sats")
|
||||
this.log(e.userId, "balance updates from", e.balance, "sats and moves by", e.amount * (e.type === 'balance_decrement' ? -1 : 1), "sats, resulting in", newEntry.updatedBalance, "sats")
|
||||
return newEntry
|
||||
}
|
||||
}
|
||||
|
|
@ -56,13 +56,13 @@ process.on("message", (message: ChildProcessRequest) => {
|
|||
sendToNostr(message.appId, message.data, message.relays)
|
||||
break
|
||||
default:
|
||||
console.error("unknown nostr request", message)
|
||||
getLogger({ appName: "nostrMiddleware" })("ERROR", "unknown nostr request", message)
|
||||
break
|
||||
}
|
||||
})
|
||||
const initSubprocessHandler = (settings: NostrSettings) => {
|
||||
if (subProcessHandler) {
|
||||
console.error("nostr settings ignored since handler already exists")
|
||||
getLogger({ appName: "nostrMiddleware" })("ERROR", "nostr settings ignored since handler already exists")
|
||||
return
|
||||
}
|
||||
subProcessHandler = new Handler(settings, event => {
|
||||
|
|
@ -74,7 +74,7 @@ const initSubprocessHandler = (settings: NostrSettings) => {
|
|||
}
|
||||
const sendToNostr: NostrSend = (appId, data, relays) => {
|
||||
if (!subProcessHandler) {
|
||||
console.error("nostr was not initialized")
|
||||
getLogger({ appName: "nostrMiddleware" })("ERROR", "nostr was not initialized")
|
||||
return
|
||||
}
|
||||
subProcessHandler.Send(appId, data, relays)
|
||||
|
|
@ -87,9 +87,10 @@ export default class Handler {
|
|||
subs: Sub[] = []
|
||||
apps: Record<string, AppInfo> = {}
|
||||
eventCallback: (event: NostrEvent) => void
|
||||
log = getLogger({ appName: "nostrMiddleware" })
|
||||
constructor(settings: NostrSettings, eventCallback: (event: NostrEvent) => void) {
|
||||
this.settings = settings
|
||||
console.log(
|
||||
this.log(
|
||||
{
|
||||
...settings,
|
||||
apps: settings.apps.map(app => {
|
||||
|
|
@ -151,7 +152,7 @@ export default class Handler {
|
|||
}
|
||||
const eventId = e.id
|
||||
if (handledEvents.includes(eventId)) {
|
||||
console.log("event already handled")
|
||||
this.log("event already handled")
|
||||
return
|
||||
}
|
||||
handledEvents.push(eventId)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export default class {
|
|||
return { executedMigrations, executedMetricsMigrations };
|
||||
}
|
||||
|
||||
StartTransaction(exec: TX<void>, description?: string) {
|
||||
StartTransaction<T>(exec: TX<T>, description?: string) {
|
||||
return this.txQueue.PushToQueue({ exec, dbTx: true, description })
|
||||
}
|
||||
}
|
||||
|
|
@ -283,18 +283,19 @@ export default class {
|
|||
return found
|
||||
}
|
||||
|
||||
async CreateUserToUserPayment(fromUserId: string, toUserId: string, amount: number, fee: number, linkedApplication: Application, dbTx: DataSource | EntityManager) {
|
||||
return dbTx.getRepository(UserToUserPayment).create({
|
||||
async AddPendingUserToUserPayment(fromUserId: string, toUserId: string, amount: number, fee: number, linkedApplication: Application, dbTx: DataSource | EntityManager) {
|
||||
const entry = dbTx.getRepository(UserToUserPayment).create({
|
||||
from_user: await this.userStorage.GetUser(fromUserId, dbTx),
|
||||
to_user: await this.userStorage.GetUser(toUserId, dbTx),
|
||||
paid_at_unix: Math.floor(Date.now() / 1000),
|
||||
paid_at_unix: 0,
|
||||
paid_amount: amount,
|
||||
service_fees: fee,
|
||||
linkedApplication
|
||||
})
|
||||
return dbTx.getRepository(UserToUserPayment).save(entry)
|
||||
}
|
||||
async SaveUserToUserPayment(payment: UserToUserPayment, dbTx: DataSource | EntityManager) {
|
||||
return dbTx.getRepository(UserToUserPayment).save(payment)
|
||||
async SetPendingUserToUserPaymentAsPaid(serialId: number, dbTx: DataSource | EntityManager) {
|
||||
dbTx.getRepository(UserToUserPayment).update(serialId, { paid_at_unix: Math.floor(Date.now() / 1000) })
|
||||
}
|
||||
|
||||
GetUserToUserReceivedPayments(userId: string, fromIndex: number, take = 50, entityManager = this.DB) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
||||
export const ignore = false
|
||||
|
||||
export const dev = false
|
||||
export default async (T: TestBase) => {
|
||||
await safelySetUserBalance(T, T.user1, 2000)
|
||||
await testSuccessfulExternalPayment(T)
|
||||
await testFailedExternalPayment(T)
|
||||
await runSanityCheck(T)
|
||||
}
|
||||
|
||||
|
||||
const testSuccessfulExternalPayment = async (T: TestBase) => {
|
||||
T.d("starting testSuccessfulExternalPayment")
|
||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||
const invoice = await T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry)
|
||||
expect(invoice.payRequest).to.startWith("lnbcrt5u")
|
||||
|
|
@ -27,3 +29,19 @@ const testSuccessfulExternalPayment = async (T: TestBase) => {
|
|||
|
||||
}
|
||||
|
||||
const testFailedExternalPayment = async (T: TestBase) => {
|
||||
T.d("starting testFailedExternalPayment")
|
||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||
const invoice = await T.externalAccessToOtherLnd.NewInvoice(1500, "test", defaultInvoiceExpiry)
|
||||
expect(invoice.payRequest).to.startWith("lnbcrt15u")
|
||||
T.d("generated 1500 sats invoice for external node")
|
||||
|
||||
await expectThrowsAsync(T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.payRequest, amount: 0 }, application), "not enough balance to decrement")
|
||||
T.d("payment failed as expected, with the expected error message")
|
||||
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
||||
expect(u1.balance_sats).to.be.equal(1496)
|
||||
T.d("user1 balance is still 1496")
|
||||
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
||||
expect(owner.balance_sats).to.be.equal(3)
|
||||
T.d("app balance is still 3 sats")
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ export default async (T: TestBase) => {
|
|||
}
|
||||
|
||||
const testSuccessfulInternalPayment = async (T: TestBase) => {
|
||||
T.d("starting testSuccessfulInternalPayment")
|
||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||
const invoice = await T.main.paymentManager.NewInvoice(T.user2.userId, { amountSats: 1000, memo: "test" }, { linkedApplication: application, expiry: defaultInvoiceExpiry })
|
||||
expect(invoice.invoice).to.startWith("lnbcrt10u")
|
||||
|
|
@ -29,6 +30,7 @@ const testSuccessfulInternalPayment = async (T: TestBase) => {
|
|||
}
|
||||
|
||||
const testFailedInternalPayment = async (T: TestBase) => {
|
||||
T.d("starting testFailedInternalPayment")
|
||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||
const invoice = await T.main.paymentManager.NewInvoice(T.user2.userId, { amountSats: 1000, memo: "test" }, { linkedApplication: application, expiry: defaultInvoiceExpiry })
|
||||
expect(invoice.invoice).to.startWith("lnbcrt10u")
|
||||
|
|
|
|||
|
|
@ -12,18 +12,15 @@ export default async (T: TestBase) => {
|
|||
|
||||
|
||||
const testSpamExternalPayment = async (T: TestBase) => {
|
||||
T.d("starting testSpamExternalPayment")
|
||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||
const invoices = await Promise.all(new Array(10).fill(0).map(() => T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry)))
|
||||
T.d("generated 10 500 sats invoices for external node")
|
||||
const res = await Promise.all(invoices.map(async (invoice, i) => {
|
||||
try {
|
||||
T.d("trying to pay invoice " + i)
|
||||
const result = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice.payRequest, amount: 0 }, application)
|
||||
T.d("payment succeeded " + i)
|
||||
return { success: true, result }
|
||||
} catch (e: any) {
|
||||
T.d("payment failed " + i)
|
||||
console.log(e, i)
|
||||
return { success: false, err: e }
|
||||
}
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export default async (T: TestBase) => {
|
|||
|
||||
|
||||
const testSpamExternalPayment = async (T: TestBase) => {
|
||||
T.d("starting testSpamExternalPayment")
|
||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||
const invoicesForExternal = await Promise.all(new Array(5).fill(0).map(() => T.externalAccessToOtherLnd.NewInvoice(500, "test", defaultInvoiceExpiry)))
|
||||
const invoicesForUser2 = await Promise.all(new Array(5).fill(0).map(() => T.main.paymentManager.NewInvoice(T.user2.userId, { amountSats: 500, memo: "test" }, { linkedApplication: application, expiry: defaultInvoiceExpiry })))
|
||||
|
|
@ -20,13 +21,9 @@ const testSpamExternalPayment = async (T: TestBase) => {
|
|||
T.d("generated 10 500 sats mixed invoices between external node and user 2")
|
||||
const res = await Promise.all(invoices.map(async (invoice, i) => {
|
||||
try {
|
||||
T.d("trying to pay invoice " + i)
|
||||
const result = await T.main.paymentManager.PayInvoice(T.user1.userId, { invoice: invoice, amount: 0 }, application)
|
||||
T.d("payment succeeded " + i)
|
||||
return { success: true, result }
|
||||
} catch (e: any) {
|
||||
T.d("payment failed " + i)
|
||||
console.log(e, i)
|
||||
return { success: false, err: e }
|
||||
}
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ export const teardown = async (T: TestBase) => {
|
|||
T.main.lnd.Stop()
|
||||
T.externalAccessToMainLnd.Stop()
|
||||
T.externalAccessToOtherLnd.Stop()
|
||||
T.externalAccessToThirdLnd.Stop()
|
||||
console.log("teardown")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ const start = async () => {
|
|||
const module = await import(`./${file.slice("build/src/tests/".length)}`) as TestModule
|
||||
modules.push({ module, file })
|
||||
if (module.dev) {
|
||||
console.log("dev module found", file)
|
||||
if (devModule !== -1) {
|
||||
console.error(redConsole, "there are multiple dev modules", resetConsole)
|
||||
return
|
||||
|
|
@ -63,6 +64,9 @@ const runTestFile = async (fileName: string, mod: TestModule) => {
|
|||
d(e, true)
|
||||
await teardown(T)
|
||||
}
|
||||
if (mod.dev) {
|
||||
d("dev mod is not allowed to in CI, failing for precaution", true)
|
||||
}
|
||||
}
|
||||
|
||||
const getDescribe = (fileName: string): Describe => {
|
||||
|
|
|
|||
35
src/tests/userToUserPayment.spec.ts
Normal file
35
src/tests/userToUserPayment.spec.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
||||
export const ignore = false
|
||||
export const dev = true
|
||||
export default async (T: TestBase) => {
|
||||
await safelySetUserBalance(T, T.user1, 2000)
|
||||
await testSuccessfulU2UPayment(T)
|
||||
await testFailedInternalPayment(T)
|
||||
await runSanityCheck(T)
|
||||
}
|
||||
|
||||
const testSuccessfulU2UPayment = async (T: TestBase) => {
|
||||
T.d("starting testSuccessfulU2UPayment")
|
||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||
const sentAmt = await T.main.paymentManager.SendUserToUserPayment(T.user1.userId, T.user2.userId, 1000, application)
|
||||
expect(sentAmt.amount).to.be.equal(1000)
|
||||
T.d("paid 1000 sats u2u from user1 to user2")
|
||||
const u1 = await T.main.storage.userStorage.GetUser(T.user1.userId)
|
||||
const u2 = await T.main.storage.userStorage.GetUser(T.user2.userId)
|
||||
const owner = await T.main.storage.userStorage.GetUser(application.owner.user_id)
|
||||
expect(u2.balance_sats).to.be.equal(1000)
|
||||
T.d("user2 balance is 1000")
|
||||
expect(u1.balance_sats).to.be.equal(994)
|
||||
T.d("user1 balance is 994 cuz he paid 6 sats fee")
|
||||
expect(owner.balance_sats).to.be.equal(6)
|
||||
T.d("app balance is 6 sats")
|
||||
}
|
||||
|
||||
const testFailedInternalPayment = async (T: TestBase) => {
|
||||
T.d("starting testFailedInternalPayment")
|
||||
const application = await T.main.storage.applicationStorage.GetApplication(T.app.appId)
|
||||
await expectThrowsAsync(T.main.paymentManager.SendUserToUserPayment(T.user1.userId, T.user2.userId, 1000, application), "not enough balance to send payment")
|
||||
T.d("payment failed as expected, with the expected error message")
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue