more fixies
This commit is contained in:
parent
c5ea8c899d
commit
6ae03e520c
19 changed files with 2330 additions and 1880 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -66,10 +66,10 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
||||||
})
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.SetMockInvoiceAsPaid) throw new Error('method: SetMockInvoiceAsPaid is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.SetMockInvoiceAsPaid) throw new Error('method: SetMockInvoiceAsPaid is not implemented')
|
||||||
app.post('/api/admin/lnd/mock/invoice/paid', async (req, res) => {
|
app.post('/api/lnd/mock/invoice/paid', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
if (!methods.SetMockInvoiceAsPaid) throw new Error('method: SetMockInvoiceAsPaid is not implemented')
|
if (!methods.SetMockInvoiceAsPaid) throw new Error('method: SetMockInvoiceAsPaid is not implemented')
|
||||||
const authContext = await opts.AdminAuthGuard(req.headers['authorization'])
|
const authContext = await opts.GuestAuthGuard(req.headers['authorization'])
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.SetMockInvoiceAsPaidRequestValidate(request)
|
const error = Types.SetMockInvoiceAsPaidRequestValidate(request)
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger)
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger)
|
||||||
|
|
@ -93,6 +93,17 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
res.json({status: 'OK', ...response})
|
res.json({status: 'OK', ...response})
|
||||||
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
||||||
})
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.GetApp) throw new Error('method: GetApp is not implemented')
|
||||||
|
app.post('/api/app/get', async (req, res) => {
|
||||||
|
try {
|
||||||
|
if (!methods.GetApp) throw new Error('method: GetApp is not implemented')
|
||||||
|
const authContext = await opts.AppAuthGuard(req.headers['authorization'])
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
const response = await methods.GetApp({ ...authContext, ...query, ...params })
|
||||||
|
res.json({status: 'OK', ...response})
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.AddAppUser) throw new Error('method: AddAppUser is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.AddAppUser) throw new Error('method: AddAppUser is not implemented')
|
||||||
app.post('/api/app/user/add', async (req, res) => {
|
app.post('/api/app/user/add', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -205,6 +216,34 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
res.json({status: 'OK', ...response})
|
res.json({status: 'OK', ...response})
|
||||||
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
||||||
})
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.SetMockAppUserBalance) throw new Error('method: SetMockAppUserBalance is not implemented')
|
||||||
|
app.post('/api/app/mock/user/blance/set', async (req, res) => {
|
||||||
|
try {
|
||||||
|
if (!methods.SetMockAppUserBalance) throw new Error('method: SetMockAppUserBalance is not implemented')
|
||||||
|
const authContext = await opts.AppAuthGuard(req.headers['authorization'])
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.SetMockAppUserBalanceRequestValidate(request)
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger)
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
await methods.SetMockAppUserBalance({ ...authContext, ...query, ...params }, request)
|
||||||
|
res.json({status: 'OK'})
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
|
if (!opts.allowNotImplementedMethods && !methods.SetMockAppBalance) throw new Error('method: SetMockAppBalance is not implemented')
|
||||||
|
app.post('/api/app/mock/blance/set', async (req, res) => {
|
||||||
|
try {
|
||||||
|
if (!methods.SetMockAppBalance) throw new Error('method: SetMockAppBalance is not implemented')
|
||||||
|
const authContext = await opts.AppAuthGuard(req.headers['authorization'])
|
||||||
|
const request = req.body
|
||||||
|
const error = Types.SetMockAppBalanceRequestValidate(request)
|
||||||
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger)
|
||||||
|
const query = req.query
|
||||||
|
const params = req.params
|
||||||
|
await methods.SetMockAppBalance({ ...authContext, ...query, ...params }, request)
|
||||||
|
res.json({status: 'OK'})
|
||||||
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger); if (opts.throwErrors) throw e }
|
||||||
|
})
|
||||||
if (!opts.allowNotImplementedMethods && !methods.AddUser) throw new Error('method: AddUser is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.AddUser) throw new Error('method: AddUser is not implemented')
|
||||||
app.post('/api/user/add', async (req, res) => {
|
app.post('/api/user/add', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,9 @@ export default (params: ClientParams) => ({
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
SetMockInvoiceAsPaid: async (request: Types.SetMockInvoiceAsPaidRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
SetMockInvoiceAsPaid: async (request: Types.SetMockInvoiceAsPaidRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
const auth = await params.retrieveAdminAuth()
|
const auth = await params.retrieveGuestAuth()
|
||||||
if (auth === null) throw new Error('retrieveAdminAuth() returned null')
|
if (auth === null) throw new Error('retrieveGuestAuth() returned null')
|
||||||
let finalRoute = '/api/admin/lnd/mock/invoice/paid'
|
let finalRoute = '/api/lnd/mock/invoice/paid'
|
||||||
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
if (data.status === 'OK') {
|
if (data.status === 'OK') {
|
||||||
|
|
@ -76,6 +76,20 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
GetApp: async (): Promise<ResultError | ({ status: 'OK' }& Types.Application)> => {
|
||||||
|
const auth = await params.retrieveAppAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
||||||
|
let finalRoute = '/api/app/get'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, {}, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
const result = data
|
||||||
|
if(!params.checkResult) return { status: 'OK', ...result }
|
||||||
|
const error = Types.ApplicationValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
AddAppUser: async (request: Types.AddAppUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.AppUser)> => {
|
AddAppUser: async (request: Types.AddAppUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.AppUser)> => {
|
||||||
const auth = await params.retrieveAppAuth()
|
const auth = await params.retrieveAppAuth()
|
||||||
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
||||||
|
|
@ -182,6 +196,28 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
|
SetMockAppUserBalance: async (request: Types.SetMockAppUserBalanceRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveAppAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
||||||
|
let finalRoute = '/api/app/mock/user/blance/set'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
|
SetMockAppBalance: async (request: Types.SetMockAppBalanceRequest): Promise<ResultError | ({ status: 'OK' })> => {
|
||||||
|
const auth = await params.retrieveAppAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveAppAuth() returned null')
|
||||||
|
let finalRoute = '/api/app/mock/blance/set'
|
||||||
|
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
|
||||||
|
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
|
||||||
|
if (data.status === 'OK') {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
AddUser: async (request: Types.AddUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.AddUserResponse)> => {
|
AddUser: async (request: Types.AddUserRequest): Promise<ResultError | ({ status: 'OK' }& Types.AddUserResponse)> => {
|
||||||
const auth = await params.retrieveGuestAuth()
|
const auth = await params.retrieveGuestAuth()
|
||||||
if (auth === null) throw new Error('retrieveGuestAuth() returned null')
|
if (auth === null) throw new Error('retrieveGuestAuth() returned null')
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -89,9 +89,9 @@ service LightningPub {
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc SetMockInvoiceAsPaid(structs.SetMockInvoiceAsPaidRequest) returns (structs.Empty) {
|
rpc SetMockInvoiceAsPaid(structs.SetMockInvoiceAsPaidRequest) returns (structs.Empty) {
|
||||||
option (auth_type) = "Admin";
|
option (auth_type) = "Guest";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/admin/lnd/mock/invoice/paid";
|
option (http_route) = "/api/lnd/mock/invoice/paid";
|
||||||
}
|
}
|
||||||
|
|
||||||
// <App>
|
// <App>
|
||||||
|
|
@ -101,6 +101,12 @@ service LightningPub {
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/admin/app/add";
|
option (http_route) = "/api/admin/app/add";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rpc GetApp(structs.Empty) returns (structs.Application) {
|
||||||
|
option (auth_type) = "App";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/app/get";
|
||||||
|
}
|
||||||
|
|
||||||
rpc AddAppUser(structs.AddAppUserRequest)returns (structs.AppUser) {
|
rpc AddAppUser(structs.AddAppUserRequest)returns (structs.AppUser) {
|
||||||
option (auth_type) = "App";
|
option (auth_type) = "App";
|
||||||
|
|
@ -149,6 +155,16 @@ service LightningPub {
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/app/user/lnurl/pay/info";
|
option (http_route) = "/api/app/user/lnurl/pay/info";
|
||||||
}
|
}
|
||||||
|
rpc SetMockAppUserBalance(structs.SetMockAppUserBalanceRequest) returns (structs.Empty) {
|
||||||
|
option (auth_type) = "App";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/app/mock/user/blance/set";
|
||||||
|
}
|
||||||
|
rpc SetMockAppBalance(structs.SetMockAppBalanceRequest) returns (structs.Empty) {
|
||||||
|
option (auth_type) = "App";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/app/mock/blance/set";
|
||||||
|
}
|
||||||
|
|
||||||
// </App>
|
// </App>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,16 @@ message AddAppRequest {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddAppResponse {
|
message Application {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
string id = 2;
|
string id = 2;
|
||||||
string auth_token = 3;
|
int64 balance = 3;
|
||||||
}
|
}
|
||||||
|
message AddAppResponse {
|
||||||
|
Application app = 1;
|
||||||
|
string auth_token = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
message AddAppUserRequest {
|
message AddAppUserRequest {
|
||||||
string identifier = 1;
|
string identifier = 1;
|
||||||
|
|
@ -91,6 +96,15 @@ message GetAppUserLNURLInfoRequest {
|
||||||
string user_identifier = 1;
|
string user_identifier = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SetMockAppUserBalanceRequest {
|
||||||
|
string user_identifier = 1;
|
||||||
|
int64 amount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetMockAppBalanceRequest {
|
||||||
|
int64 amount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
enum AddressType {
|
enum AddressType {
|
||||||
WITNESS_PUBKEY_HASH = 0;
|
WITNESS_PUBKEY_HASH = 0;
|
||||||
NESTED_PUBKEY_HASH = 1;
|
NESTED_PUBKEY_HASH = 1;
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,10 @@ export interface LightningHandler {
|
||||||
|
|
||||||
export default (settings: LndSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb): LightningHandler => {
|
export default (settings: LndSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb): LightningHandler => {
|
||||||
if (settings.mockLnd) {
|
if (settings.mockLnd) {
|
||||||
|
console.log("registering mock lnd handler")
|
||||||
return new MockLnd(settings, addressPaidCb, invoicePaidCb)
|
return new MockLnd(settings, addressPaidCb, invoicePaidCb)
|
||||||
} else {
|
} else {
|
||||||
|
console.log("registering prod lnd handler")
|
||||||
return new LND(settings, addressPaidCb, invoicePaidCb)
|
return new LND(settings, addressPaidCb, invoicePaidCb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,7 +157,6 @@ export default class {
|
||||||
this.checkReady()
|
this.checkReady()
|
||||||
const abortController = new AbortController()
|
const abortController = new AbortController()
|
||||||
const req = PayInvoiceReq(invoice, amount, feeLimit)
|
const req = PayInvoiceReq(invoice, amount, feeLimit)
|
||||||
console.log(req)
|
|
||||||
const stream = this.router.sendPaymentV2(req, { abort: abortController.signal })
|
const stream = this.router.sendPaymentV2(req, { abort: abortController.signal })
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
stream.responses.onError(error => {
|
stream.responses.onError(error => {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import { SendCoinsReq } from './sendCoinsReq.js';
|
||||||
import { LndSettings, AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice } from './settings.js';
|
import { LndSettings, AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice } from './settings.js';
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
invoicesAwaiting: Record<string /* invoice */, { value: number, memo: string, expiryUnix: number }>
|
invoicesAwaiting: Record<string /* invoice */, { value: number, memo: string, expiryUnix: number }> = {}
|
||||||
settings: LndSettings
|
settings: LndSettings
|
||||||
abortController = new AbortController()
|
abortController = new AbortController()
|
||||||
addressPaidCb: AddressPaidCb
|
addressPaidCb: AddressPaidCb
|
||||||
|
|
@ -49,12 +49,16 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async NewInvoice(value: number, memo: string, expiry: number): Promise<Invoice> {
|
async NewInvoice(value: number, memo: string, expiry: number): Promise<Invoice> {
|
||||||
const mockInvoice = "lnbcrtmock" + crypto.randomBytes(32).toString('hex')
|
const mockInvoice = "lnbcrtmockin" + crypto.randomBytes(32).toString('hex')
|
||||||
this.invoicesAwaiting[mockInvoice] = { value, memo, expiryUnix: expiry + Date.now() / 1000 }
|
this.invoicesAwaiting[mockInvoice] = { value, memo, expiryUnix: expiry + Date.now() / 1000 }
|
||||||
return { payRequest: mockInvoice }
|
return { payRequest: mockInvoice }
|
||||||
}
|
}
|
||||||
|
|
||||||
async DecodeInvoice(paymentRequest: string): Promise<DecodedInvoice> {
|
async DecodeInvoice(paymentRequest: string): Promise<DecodedInvoice> {
|
||||||
|
if (paymentRequest.startsWith('lnbcrtmockout')) {
|
||||||
|
const amt = this.decodeOutboundInvoice(paymentRequest)
|
||||||
|
return { numSatoshis: amt }
|
||||||
|
}
|
||||||
const i = this.invoicesAwaiting[paymentRequest]
|
const i = this.invoicesAwaiting[paymentRequest]
|
||||||
if (!i) {
|
if (!i) {
|
||||||
throw new Error("invoice not found")
|
throw new Error("invoice not found")
|
||||||
|
|
@ -70,15 +74,23 @@ export default class {
|
||||||
return Math.max(0, Math.floor(amount * (1 - this.settings.feeRateLimit) - this.settings.feeFixedLimit))
|
return Math.max(0, Math.floor(amount * (1 - this.settings.feeRateLimit) - this.settings.feeFixedLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
async PayInvoice(invoice: string, amount: number, feeLimit: number): Promise<PaidInvoice> {
|
decodeOutboundInvoice(invoice: string): number {
|
||||||
if (!invoice.startsWith('lnbcrtmock')) {
|
if (!invoice.startsWith('lnbcrtmockout')) {
|
||||||
throw new Error("invalid mock invoice provided for payment")
|
throw new Error("invalid mock invoice provided for payment")
|
||||||
}
|
}
|
||||||
const amt = invoice.substring('lnbcrtmock'.length)
|
const amt = invoice.substring('lnbcrtmockout'.length).split("__")[0]
|
||||||
if (isNaN(+amt)) {
|
if (isNaN(+amt)) {
|
||||||
throw new Error("invalid mock invoice provided for payment")
|
throw new Error("invalid mock invoice provided for payment")
|
||||||
}
|
}
|
||||||
return { feeSat: 0, paymentPreimage: "all_good", valueSat: +amt || amount }
|
return +amt
|
||||||
|
}
|
||||||
|
|
||||||
|
async PayInvoice(invoice: string, amount: number, feeLimit: number): Promise<PaidInvoice> {
|
||||||
|
console.log('payng', invoice)
|
||||||
|
await new Promise(res => setTimeout(res, 200))
|
||||||
|
const amt = this.decodeOutboundInvoice(invoice)
|
||||||
|
console.log('paid', invoice)
|
||||||
|
return { feeSat: 1, paymentPreimage: "all_good", valueSat: amt || amount }
|
||||||
}
|
}
|
||||||
|
|
||||||
async EstimateChainFees(address: string, amount: number, targetConf: number): Promise<EstimateFeeResponse> {
|
async EstimateChainFees(address: string, amount: number, targetConf: number): Promise<EstimateFeeResponse> {
|
||||||
|
|
|
||||||
|
|
@ -27,19 +27,45 @@ export default class {
|
||||||
t = token.substring("Bearer ".length)
|
t = token.substring("Bearer ".length)
|
||||||
}
|
}
|
||||||
if (!t) throw new Error("no app token provided")
|
if (!t) throw new Error("no app token provided")
|
||||||
return (jwt.verify(token, this.settings.jwtSecret) as { appId: string }).appId
|
const decoded = jwt.verify(token, this.settings.jwtSecret) as { appId?: string }
|
||||||
|
if (!decoded.appId) {
|
||||||
|
throw new Error("the provided token is not an app token")
|
||||||
|
}
|
||||||
|
return decoded.appId
|
||||||
|
}
|
||||||
|
|
||||||
|
async SetMockAppUserBalance(appId: string, req: Types.SetMockAppUserBalanceRequest) {
|
||||||
|
const user = await this.storage.applicationStorage.GetOrCreateApplicationUser(appId, req.user_identifier, 0)
|
||||||
|
await this.paymentManager.SetMockUserBalance(user.user.user_id, req.amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
async SetMockAppBalance(appId: string, req: Types.SetMockAppBalanceRequest) {
|
||||||
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
await this.paymentManager.SetMockUserBalance(app.owner.user_id, req.amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async AddApp(req: Types.AddAppRequest): Promise<Types.AddAppResponse> {
|
async AddApp(req: Types.AddAppRequest): Promise<Types.AddAppResponse> {
|
||||||
const app = await this.storage.applicationStorage.AddApplication(req.name)
|
const app = await this.storage.applicationStorage.AddApplication(req.name)
|
||||||
return {
|
return {
|
||||||
id: app.app_id,
|
app: {
|
||||||
name: app.name,
|
id: app.app_id,
|
||||||
|
name: app.name,
|
||||||
|
balance: 0
|
||||||
|
},
|
||||||
auth_token: this.SignAppToken(app.app_id)
|
auth_token: this.SignAppToken(app.app_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async GetApp(appId: string): Promise<Types.Application> {
|
||||||
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
return {
|
||||||
|
name: app.name,
|
||||||
|
id: app.app_id,
|
||||||
|
balance: app.owner.balance_sats
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async AddAppUser(appId: string, req: Types.AddAppUserRequest): Promise<Types.AppUser> {
|
async AddAppUser(appId: string, req: Types.AddAppUserRequest): Promise<Types.AppUser> {
|
||||||
let u: ApplicationUser
|
let u: ApplicationUser
|
||||||
if (req.fail_if_exists) {
|
if (req.fail_if_exists) {
|
||||||
|
|
@ -60,7 +86,7 @@ export default class {
|
||||||
async AddAppInvoice(appId: string, req: Types.AddAppInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
async AddAppInvoice(appId: string, req: Types.AddAppInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const payer = await this.storage.applicationStorage.GetOrCreateApplicationUser(appId, req.payer_identifier, 0)
|
const payer = await this.storage.applicationStorage.GetOrCreateApplicationUser(appId, req.payer_identifier, 0)
|
||||||
const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user }
|
const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
|
||||||
return this.paymentManager.NewInvoice(app.owner.user_id, req.invoice_req, opts)
|
return this.paymentManager.NewInvoice(app.owner.user_id, req.invoice_req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,6 +103,7 @@ export default class {
|
||||||
async GetAppUser(appId: string, req: Types.GetAppUserRequest): Promise<Types.AppUser> {
|
async GetAppUser(appId: string, req: Types.GetAppUserRequest): Promise<Types.AppUser> {
|
||||||
const user = await this.storage.applicationStorage.GetApplicationUser(appId, req.user_identifier)
|
const user = await this.storage.applicationStorage.GetApplicationUser(appId, req.user_identifier)
|
||||||
const max = this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats)
|
const max = this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats)
|
||||||
|
console.log(max, user.user.balance_sats)
|
||||||
return {
|
return {
|
||||||
max_withdrawable: max, identifier: req.user_identifier, info: {
|
max_withdrawable: max, identifier: req.user_identifier, info: {
|
||||||
userId: user.user.user_id, balance: user.user.balance_sats
|
userId: user.user.user_id, balance: user.user.balance_sats
|
||||||
|
|
@ -85,14 +112,16 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async PayAppUserInvoice(appId: string, req: Types.PayAppUserInvoiceRequest): Promise<Types.PayAppUserInvoiceResponse> {
|
async PayAppUserInvoice(appId: string, req: Types.PayAppUserInvoiceRequest): Promise<Types.PayAppUserInvoiceResponse> {
|
||||||
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const appUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.user_identifier)
|
const appUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.user_identifier)
|
||||||
return this.paymentManager.PayInvoice(appUser.user.user_id, req)
|
return this.paymentManager.PayInvoice(appUser.user.user_id, req, app)
|
||||||
}
|
}
|
||||||
|
|
||||||
async SendAppUserToAppUserPayment(appId: string, req: Types.SendAppUserToAppUserPaymentRequest): Promise<void> {
|
async SendAppUserToAppUserPayment(appId: string, req: Types.SendAppUserToAppUserPaymentRequest): Promise<void> {
|
||||||
const fromUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.from_user_identifier)
|
const fromUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.from_user_identifier)
|
||||||
const toUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.to_user_identifier)
|
const toUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.to_user_identifier)
|
||||||
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, toUser.user.user_id, req.amount)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, toUser.user.user_id, req.amount, app)
|
||||||
}
|
}
|
||||||
|
|
||||||
async SendAppUserToAppPayment(appId: string, req: Types.SendAppUserToAppPaymentRequest): Promise<void> {
|
async SendAppUserToAppPayment(appId: string, req: Types.SendAppUserToAppPaymentRequest): Promise<void> {
|
||||||
|
|
|
||||||
|
|
@ -73,11 +73,13 @@ export default class {
|
||||||
const userInvoice = await this.storage.paymentStorage.GetInvoiceOwner(paymentRequest, tx)
|
const userInvoice = await this.storage.paymentStorage.GetInvoiceOwner(paymentRequest, tx)
|
||||||
if (!userInvoice || userInvoice.paid_at_unix > 0) { return }
|
if (!userInvoice || userInvoice.paid_at_unix > 0) { return }
|
||||||
const fee = this.paymentManager.getServiceFee(Types.UserOperationType.INCOMING_INVOICE, amount)
|
const fee = this.paymentManager.getServiceFee(Types.UserOperationType.INCOMING_INVOICE, amount)
|
||||||
const maybeApp = await this.storage.applicationStorage.IsApplicationUser(userInvoice.user.user_id)
|
|
||||||
try {
|
try {
|
||||||
// This call will fail if the invoice is already registered
|
// This call will fail if the invoice is already registered
|
||||||
await this.storage.paymentStorage.FlagInvoiceAsPaid(userInvoice, amount, fee, tx)
|
await this.storage.paymentStorage.FlagInvoiceAsPaid(userInvoice, amount, fee, tx)
|
||||||
await this.storage.userStorage.IncrementUserBalance(userInvoice.user.user_id, amount - fee, tx)
|
await this.storage.userStorage.IncrementUserBalance(userInvoice.user.user_id, amount - fee, tx)
|
||||||
|
if (userInvoice.linkedApplication) {
|
||||||
|
await this.storage.userStorage.IncrementUserBalance(userInvoice.linkedApplication.owner.user_id, fee, tx)
|
||||||
|
}
|
||||||
await this.triggerPaidCallback(userInvoice.callbackUrl)
|
await this.triggerPaidCallback(userInvoice.callbackUrl)
|
||||||
} catch {
|
} catch {
|
||||||
//TODO
|
//TODO
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||||
import { MainSettings } from './settings.js'
|
import { MainSettings } from './settings.js'
|
||||||
import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
||||||
import { LightningHandler } from '../lnd/index.js'
|
import { LightningHandler } from '../lnd/index.js'
|
||||||
|
import { Application } from '../storage/entity/Application.js'
|
||||||
interface UserOperationInfo {
|
interface UserOperationInfo {
|
||||||
serial_id: number
|
serial_id: number
|
||||||
paid_amount: number
|
paid_amount: number
|
||||||
|
|
@ -39,9 +40,20 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async SetMockInvoiceAsPaid(req: Types.SetMockInvoiceAsPaidRequest) {
|
async SetMockInvoiceAsPaid(req: Types.SetMockInvoiceAsPaidRequest) {
|
||||||
|
if (!this.settings.lndSettings.mockLnd) {
|
||||||
|
throw new Error("mock disabled, cannot set invoice as paid")
|
||||||
|
}
|
||||||
await this.lnd.SetMockInvoiceAsPaid(req.invoice, req.amount)
|
await this.lnd.SetMockInvoiceAsPaid(req.invoice, req.amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async SetMockUserBalance(userId: string, balance: number) {
|
||||||
|
if (!this.settings.lndSettings.mockLnd) {
|
||||||
|
throw new Error("mock disabled, cannot set invoice as paid")
|
||||||
|
}
|
||||||
|
console.log("setting mock balance...")
|
||||||
|
await this.storage.userStorage.UpdateUser(userId, { balance_sats: balance })
|
||||||
|
}
|
||||||
|
|
||||||
async NewAddress(userId: string, req: Types.NewAddressRequest): Promise<Types.NewAddressResponse> {
|
async NewAddress(userId: string, req: Types.NewAddressRequest): Promise<Types.NewAddressResponse> {
|
||||||
const res = await this.lnd.NewAddress(req.addressType)
|
const res = await this.lnd.NewAddress(req.addressType)
|
||||||
const userAddress = await this.storage.paymentStorage.AddUserAddress(userId, res.address)
|
const userAddress = await this.storage.paymentStorage.AddUserAddress(userId, res.address)
|
||||||
|
|
@ -60,8 +72,12 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async lockUserWithMinBalance(userId: string, minBalance: number) {
|
async lockUserWithMinBalance(userId: string, minBalance: number) {
|
||||||
|
console.log("locking", userId)
|
||||||
return this.storage.StartTransaction(async tx => {
|
return this.storage.StartTransaction(async tx => {
|
||||||
const user = await this.storage.userStorage.GetUser(userId, tx)
|
const user = await this.storage.userStorage.GetUser(userId, tx)
|
||||||
|
if (user.locked) {
|
||||||
|
throw new Error("user is already withdrawing")
|
||||||
|
}
|
||||||
if (user.balance_sats < minBalance) {
|
if (user.balance_sats < minBalance) {
|
||||||
throw new Error("insufficient balance")
|
throw new Error("insufficient balance")
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +96,7 @@ export default class {
|
||||||
amount: Number(decoded.numSatoshis)
|
amount: Number(decoded.numSatoshis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async PayInvoice(userId: string, req: Types.PayInvoiceRequest): Promise<Types.PayInvoiceResponse> {
|
async PayInvoice(userId: string, req: Types.PayInvoiceRequest, linkedApplication?: Application): Promise<Types.PayInvoiceResponse> {
|
||||||
const decoded = await this.lnd.DecodeInvoice(req.invoice)
|
const decoded = await this.lnd.DecodeInvoice(req.invoice)
|
||||||
if (decoded.numSatoshis !== 0 && req.amount !== 0) {
|
if (decoded.numSatoshis !== 0 && req.amount !== 0) {
|
||||||
throw new Error("invoice has value, do not provide amount the the request")
|
throw new Error("invoice has value, do not provide amount the the request")
|
||||||
|
|
@ -92,11 +108,15 @@ export default class {
|
||||||
const serviceFee = this.getServiceFee(Types.UserOperationType.OUTGOING_INVOICE, payAmount)
|
const serviceFee = this.getServiceFee(Types.UserOperationType.OUTGOING_INVOICE, payAmount)
|
||||||
const totalAmountToDecrement = payAmount + serviceFee
|
const totalAmountToDecrement = payAmount + serviceFee
|
||||||
|
|
||||||
|
|
||||||
const routingFeeLimit = this.lnd.GetFeeLimitAmount(payAmount)
|
const routingFeeLimit = this.lnd.GetFeeLimitAmount(payAmount)
|
||||||
await this.lockUserWithMinBalance(userId, totalAmountToDecrement + routingFeeLimit)
|
await this.lockUserWithMinBalance(userId, totalAmountToDecrement + routingFeeLimit)
|
||||||
const payment = await this.lnd.PayInvoice(req.invoice, req.amount, routingFeeLimit)
|
const payment = await this.lnd.PayInvoice(req.invoice, req.amount, routingFeeLimit)
|
||||||
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + Number(payment.feeSat))
|
await this.storage.userStorage.DecrementUserBalance(userId, totalAmountToDecrement + Number(payment.feeSat))
|
||||||
|
if (linkedApplication) {
|
||||||
|
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, serviceFee)
|
||||||
|
} else {
|
||||||
|
//const appOwner = await this.storage.applicationStorage.IsApplicationOwner(userId)
|
||||||
|
}
|
||||||
await this.storage.userStorage.UnlockUser(userId)
|
await this.storage.userStorage.UnlockUser(userId)
|
||||||
await this.storage.paymentStorage.AddUserInvoicePayment(userId, req.invoice, payAmount, Number(payment.feeSat), serviceFee)
|
await this.storage.paymentStorage.AddUserInvoicePayment(userId, req.invoice, payAmount, Number(payment.feeSat), serviceFee)
|
||||||
return {
|
return {
|
||||||
|
|
@ -241,7 +261,7 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async SendUserToUserPayment(fromUserId: string, toUserId: string, amount: number) {
|
async SendUserToUserPayment(fromUserId: string, toUserId: string, amount: number, linkedApplication?: Application) {
|
||||||
await this.storage.StartTransaction(async tx => {
|
await this.storage.StartTransaction(async tx => {
|
||||||
const fromUser = await this.storage.userStorage.GetUser(fromUserId, tx)
|
const fromUser = await this.storage.userStorage.GetUser(fromUserId, tx)
|
||||||
const toUser = await this.storage.userStorage.GetUser(toUserId, tx)
|
const toUser = await this.storage.userStorage.GetUser(toUserId, tx)
|
||||||
|
|
@ -253,6 +273,9 @@ export default class {
|
||||||
await this.storage.userStorage.DecrementUserBalance(fromUser.user_id, amount, tx)
|
await this.storage.userStorage.DecrementUserBalance(fromUser.user_id, amount, tx)
|
||||||
await this.storage.userStorage.IncrementUserBalance(toUser.user_id, toIncrement, tx)
|
await this.storage.userStorage.IncrementUserBalance(toUser.user_id, toIncrement, tx)
|
||||||
await this.storage.paymentStorage.AddUserToUserPayment(fromUserId, toUserId, amount, fee)
|
await this.storage.paymentStorage.AddUserToUserPayment(fromUserId, toUserId, amount, fee)
|
||||||
|
if (linkedApplication) {
|
||||||
|
await this.storage.userStorage.IncrementUserBalance(linkedApplication.owner.user_id, fee)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,18 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeUserToken(token?: string): string {
|
DecodeUserToken(token?: string): string {
|
||||||
if (!token) throw new Error("empty user token provided")
|
throw new Error("users methods temporarely disabled")
|
||||||
|
/*if (!token) throw new Error("empty user token provided")
|
||||||
let t = token
|
let t = token
|
||||||
if (token.startsWith("Bearer ")) {
|
if (token.startsWith("Bearer ")) {
|
||||||
t = token.substring("Bearer ".length)
|
t = token.substring("Bearer ".length)
|
||||||
}
|
}
|
||||||
if (!t) throw new Error("no user token provided")
|
if (!t) throw new Error("no user token provided")
|
||||||
return (jwt.verify(token, this.settings.jwtSecret) as { userId: string }).userId
|
const decoded = jwt.verify(token, this.settings.jwtSecret) as { userId?: string }
|
||||||
|
if (!decoded.userId) {
|
||||||
|
throw new Error("the provided token is not an app token")
|
||||||
|
}
|
||||||
|
return decoded.userId*/
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddBasicUser(req: Types.AddUserRequest): Promise<Types.AddUserResponse> {
|
async AddBasicUser(req: Types.AddUserRequest): Promise<Types.AddUserResponse> {
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,9 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.AddApp(req)
|
return mainHandler.applicationManager.AddApp(req)
|
||||||
},
|
},
|
||||||
|
GetApp: async (ctx) => {
|
||||||
|
return mainHandler.applicationManager.GetApp(ctx.app_id)
|
||||||
|
},
|
||||||
AddAppUser: async (ctx, req) => {
|
AddAppUser: async (ctx, req) => {
|
||||||
const err = Types.AddAppUserRequestValidate(req, {
|
const err = Types.AddAppUserRequestValidate(req, {
|
||||||
identifier_CustomCheck: id => id !== ''
|
identifier_CustomCheck: id => id !== ''
|
||||||
|
|
@ -176,6 +179,16 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.applicationManager.GetAppUserLNURLInfo(ctx.app_id, req)
|
return mainHandler.applicationManager.GetAppUserLNURLInfo(ctx.app_id, req)
|
||||||
|
},
|
||||||
|
SetMockAppUserBalance: async (ctx, req) => {
|
||||||
|
const err = Types.SetMockAppUserBalanceRequestValidate(req, {
|
||||||
|
user_identifier_CustomCheck: id => id !== ''
|
||||||
|
})
|
||||||
|
if (err != null) throw new Error(err.message)
|
||||||
|
await mainHandler.applicationManager.SetMockAppUserBalance(ctx.app_id, req)
|
||||||
|
},
|
||||||
|
SetMockAppBalance: async (ctx, req) => {
|
||||||
|
await mainHandler.applicationManager.SetMockAppBalance(ctx.app_id, req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,6 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found.application.app_id !== appId) {
|
if (found.application.app_id !== appId) {
|
||||||
console.log(found, appId)
|
|
||||||
throw new Error("requested user does not belong to requestor application")
|
throw new Error("requested user does not belong to requestor application")
|
||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
|
|
@ -75,4 +74,8 @@ export default class {
|
||||||
async IsApplicationUser(userId: string, entityManager = this.DB): Promise<ApplicationUser | null> {
|
async IsApplicationUser(userId: string, entityManager = this.DB): Promise<ApplicationUser | null> {
|
||||||
return await entityManager.getRepository(ApplicationUser).findOne({ where: { user: { user_id: userId } } })
|
return await entityManager.getRepository(ApplicationUser).findOne({ where: { user: { user_id: userId } } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async IsApplicationOwner(userId: string, entityManager = this.DB) {
|
||||||
|
return entityManager.getRepository(Application).findOne({ where: { owner: { user_id: userId } } })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
import { Entity, PrimaryGeneratedColumn, Column, Index, Check, ManyToOne, JoinColumn, CreateDateColumn, UpdateDateColumn } from "typeorm"
|
||||||
import { Product } from "./Product.js"
|
import { Product } from "./Product.js"
|
||||||
import { User } from "./User.js"
|
import { User } from "./User.js"
|
||||||
|
import { Application } from "./Application.js"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class UserReceivingInvoice {
|
export class UserReceivingInvoice {
|
||||||
|
|
@ -37,6 +38,9 @@ export class UserReceivingInvoice {
|
||||||
@ManyToOne(type => User, { eager: true })
|
@ManyToOne(type => User, { eager: true })
|
||||||
payer: User | null
|
payer: User | null
|
||||||
|
|
||||||
|
@ManyToOne(type => Application, { eager: true })
|
||||||
|
linkedApplication: Application | null
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { DataSource, EntityManager, MoreThan, MoreThanOrEqual } from "typeorm"
|
import { DataSource, EntityManager, MoreThan, MoreThanOrEqual, TransactionAlreadyStartedError } from "typeorm"
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import NewDB, { DbSettings, LoadDbSettingsFromEnv } from "./db.js"
|
import NewDB, { DbSettings, LoadDbSettingsFromEnv } from "./db.js"
|
||||||
import { User } from "./entity/User.js"
|
import { User } from "./entity/User.js"
|
||||||
|
|
@ -29,6 +29,7 @@ export default class {
|
||||||
applicationStorage: ApplicationStorage
|
applicationStorage: ApplicationStorage
|
||||||
userStorage: UserStorage
|
userStorage: UserStorage
|
||||||
paymentStorage: PaymentStorage
|
paymentStorage: PaymentStorage
|
||||||
|
pendingTx: boolean
|
||||||
constructor(settings: StorageSettings) {
|
constructor(settings: StorageSettings) {
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +41,24 @@ export default class {
|
||||||
this.paymentStorage = new PaymentStorage(this.DB, this.userStorage)
|
this.paymentStorage = new PaymentStorage(this.DB, this.userStorage)
|
||||||
}
|
}
|
||||||
StartTransaction(exec: (entityManager: EntityManager) => Promise<void>) {
|
StartTransaction(exec: (entityManager: EntityManager) => Promise<void>) {
|
||||||
return this.DB.transaction(exec)
|
if (this.pendingTx) {
|
||||||
|
throw new Error("cannot start transaction")
|
||||||
|
}
|
||||||
|
this.pendingTx = true
|
||||||
|
console.log("starting tx")
|
||||||
|
return this.DB.transaction(async tx => {
|
||||||
|
try {
|
||||||
|
await exec(tx)
|
||||||
|
console.log("tx done")
|
||||||
|
this.pendingTx = false
|
||||||
|
} catch (err) {
|
||||||
|
console.log("tx err")
|
||||||
|
this.pendingTx = false
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12,7 +12,8 @@ import UserStorage from './userStorage.js';
|
||||||
import { AddressReceivingTransaction } from './entity/AddressReceivingTransaction.js';
|
import { AddressReceivingTransaction } from './entity/AddressReceivingTransaction.js';
|
||||||
import { UserInvoicePayment } from './entity/UserInvoicePayment.js';
|
import { UserInvoicePayment } from './entity/UserInvoicePayment.js';
|
||||||
import { UserToUserPayment } from './entity/UserToUserPayment.js';
|
import { UserToUserPayment } from './entity/UserToUserPayment.js';
|
||||||
export type InboundOptionals = { product?: Product, callbackUrl?: string, expiry: number, expectedPayer?: User }
|
import { Application } from './entity/Application.js';
|
||||||
|
export type InboundOptionals = { product?: Product, callbackUrl?: string, expiry: number, expectedPayer?: User, linkedApplication?: Application }
|
||||||
export const defaultInvoiceExpiry = 60 * 60
|
export const defaultInvoiceExpiry = 60 * 60
|
||||||
export default class {
|
export default class {
|
||||||
DB: DataSource | EntityManager
|
DB: DataSource | EntityManager
|
||||||
|
|
@ -83,7 +84,8 @@ export default class {
|
||||||
user: user,
|
user: user,
|
||||||
product: options.product,
|
product: options.product,
|
||||||
expires_at_unix: Math.floor(Date.now() / 1000) + options.expiry,
|
expires_at_unix: Math.floor(Date.now() / 1000) + options.expiry,
|
||||||
payer: options.expectedPayer
|
payer: options.expectedPayer,
|
||||||
|
linkedApplication: options.linkedApplication
|
||||||
})
|
})
|
||||||
return entityManager.getRepository(UserReceivingInvoice).save(newUserInvoice)
|
return entityManager.getRepository(UserReceivingInvoice).save(newUserInvoice)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async UnlockUser(userId: string, entityManager = this.DB) {
|
async UnlockUser(userId: string, entityManager = this.DB) {
|
||||||
|
console.log("unlocking", userId)
|
||||||
const res = await entityManager.getRepository(User).update({
|
const res = await entityManager.getRepository(User).update({
|
||||||
user_id: userId
|
user_id: userId
|
||||||
}, { locked: false })
|
}, { locked: false })
|
||||||
|
|
@ -102,4 +103,9 @@ export default class {
|
||||||
throw new Error("unaffected balance decrement for " + userId) // TODO: fix logs doxing
|
throw new Error("unaffected balance decrement for " + userId) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async UpdateUser(userId: string, update: Partial<User>, entityManager = this.DB) {
|
||||||
|
const user = await this.GetUser(userId, entityManager)
|
||||||
|
await entityManager.getRepository(User).update(user.serial_id, update)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue