Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backend): add local payment #2857

Open
wants to merge 77 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
bb77152
feat(backend): add local payment quote migration
BlairCurrey Aug 10, 2024
fc06e24
feat(backend): WIP seperate ILPModels, LocalQuote, BaseQuote models
BlairCurrey Aug 12, 2024
257fd01
refactor(backend): change model/services to reflect optional ilp quot…
BlairCurrey Aug 13, 2024
d9fa20e
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Aug 14, 2024
2e76ee2
feat(backend): WIP local payment method with getQuote
BlairCurrey Aug 15, 2024
4fab5d8
feat(backend): add local payment method to payment method handler
BlairCurrey Aug 15, 2024
b17db75
chore(backend): fix format
BlairCurrey Aug 15, 2024
6e37420
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Aug 15, 2024
9ef7f94
feat(backend): stub in control payment handler service with receiver …
BlairCurrey Aug 16, 2024
320ee21
feat(backend): local payment .pay
BlairCurrey Aug 20, 2024
07569a7
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Aug 20, 2024
f3d5f5d
chore: rm comment
BlairCurrey Aug 20, 2024
d795ce2
chore: WIP debugging wrong sentAmount
BlairCurrey Aug 21, 2024
251c60a
chore: rm comment
BlairCurrey Aug 21, 2024
8f0bcb8
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Aug 21, 2024
eca01f1
feat(backend): use receiver.isLocal to control payment method in quot…
BlairCurrey Aug 21, 2024
770d7ea
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Aug 23, 2024
3849db7
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Sep 10, 2024
170bcc3
fix(backend): added source amount
BlairCurrey Sep 13, 2024
88618ce
fix(backend): p2p case (cross currency, local, fixed send)
BlairCurrey Sep 16, 2024
823c512
fix: lint error
BlairCurrey Sep 16, 2024
2e9f043
chore: rm logs
BlairCurrey Sep 16, 2024
3fb02e5
fix: quote service test
BlairCurrey Sep 16, 2024
569f029
fix: lint errors
BlairCurrey Sep 16, 2024
dae1de1
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Sep 16, 2024
2016469
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Sep 18, 2024
3182944
refactor(backend): split migrations
BlairCurrey Sep 18, 2024
3665188
refactor(backend): rm migration that was split into many
BlairCurrey Sep 18, 2024
5b8bad3
WIP bruno requests for testing
BlairCurrey Sep 18, 2024
b49e08e
feat(backend): start rm ilpQuoteDetail join on op where not used
BlairCurrey Sep 18, 2024
eedacb5
fix(backend): rm unecessary ilpQuoteDetail join
BlairCurrey Sep 18, 2024
27a64b2
chore(backend): format
BlairCurrey Sep 18, 2024
26d0539
fix(backend): dont join op on quote.ilpQuoteDetails on get
BlairCurrey Sep 18, 2024
2723961
fix(backend): rm ilpQuoteDetails join on op cancel
BlairCurrey Sep 18, 2024
08126c5
fix(backend): rm unecessary join in op validate grant amount
BlairCurrey Sep 18, 2024
205447d
fix(backend): rm join from fundPayment
BlairCurrey Sep 18, 2024
0471d84
fix(backend): rm unecessary join, unused method
BlairCurrey Sep 18, 2024
7b5142d
fix(backend): fetch ilpQuoteDetails where used instead of joining
BlairCurrey Sep 18, 2024
773e4f2
chore(backend): move ilpquotedetails dir
BlairCurrey Sep 18, 2024
0a3adf4
chore(backend): rm console.log
BlairCurrey Sep 18, 2024
347f9b0
fix(backend): rm ilpQuoteDetails joins from quote service
BlairCurrey Sep 19, 2024
37d399e
chore(backend): rm console.log
BlairCurrey Sep 19, 2024
78d42b6
refactor(backend): rename sourceAmount to debitAmountMinusFees
BlairCurrey Sep 26, 2024
a96d654
chore(backend): cleanup, rm unused fee method
BlairCurrey Sep 30, 2024
7941f05
test(backend): add local payment tests
BlairCurrey Oct 1, 2024
753a57b
chore: format
BlairCurrey Oct 1, 2024
ed30066
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Oct 1, 2024
8476615
fix(bruno): local open payments requests
BlairCurrey Oct 2, 2024
f8a979c
test(backend): add integration tests for local payments
BlairCurrey Oct 2, 2024
5cee618
chore(backend): cleanup
BlairCurrey Oct 2, 2024
d41777e
chore: restore old version of date definition in test
BlairCurrey Oct 2, 2024
e0f988d
chore: cleanup
BlairCurrey Oct 2, 2024
5d631bd
fix: rm unused import
BlairCurrey Oct 2, 2024
ececad2
test(integration): new case - p2p, fixed-send, local
BlairCurrey Oct 3, 2024
63011ae
chore(integration): rename test for consistency
BlairCurrey Oct 3, 2024
bd12e30
fix(backend): throw error in pay if incoming payment is not pending
BlairCurrey Oct 16, 2024
b0eaf8d
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Oct 22, 2024
0d69a3d
feat(backend): simplify migrations
BlairCurrey Oct 23, 2024
31e6cc7
chore(backend): clarify comment
BlairCurrey Oct 23, 2024
bb9d334
chore(auth): format
BlairCurrey Oct 23, 2024
b0897d9
refactor(backend): use IlpQuoteDetails model directly in ilp payment …
BlairCurrey Oct 23, 2024
2d8048a
refactor(backend): rm ilpQuoteDetails service
BlairCurrey Oct 23, 2024
15d8929
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Oct 29, 2024
c40db9e
fix(integration): wa typo
BlairCurrey Oct 30, 2024
0dbb2d3
chore: rm bruno test examples
BlairCurrey Oct 30, 2024
61b1010
refactor: mv debitAmountMinusFees to fee calc and clarify TODO
BlairCurrey Oct 30, 2024
0dea97d
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Oct 30, 2024
6c995d9
Update bruno/collections/Rafiki/Examples/Admin API - only locally/Pe…
BlairCurrey Oct 31, 2024
86f6db6
fix: make timeout required again
BlairCurrey Oct 31, 2024
3fc6924
feat: error when post fails in local pay
BlairCurrey Oct 31, 2024
6634b8f
refactor(backend): add optional quoteId to getQuote args
BlairCurrey Nov 1, 2024
6706557
refactor: rm ilp quote details out of quote service
BlairCurrey Nov 1, 2024
998ee25
refactor: insert ilp quote details in ilp getQuote
BlairCurrey Nov 1, 2024
a4cf57a
fix(backend): payment handler test
BlairCurrey Nov 1, 2024
1835bc4
chore(bruno): rename request
BlairCurrey Nov 5, 2024
7db833b
chore(integration): rm erroneous todo comment
BlairCurrey Nov 5, 2024
4437438
Merge branch 'main' into bc/2834/non-ilp-local-payments
BlairCurrey Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function (knex) {
return (
knex.schema
// Create new table with columns from "quotes" to migrate
.createTable('ilpQuoteDetails', function (table) {
table.uuid('id').notNullable().primary()
table.uuid('quoteId').notNullable().unique()
table.foreign('quoteId').references('quotes.id')

table.bigInteger('maxPacketAmount').notNullable()
table.decimal('minExchangeRateNumerator', 64, 0).notNullable()
table.decimal('minExchangeRateDenominator', 64, 0).notNullable()
table.decimal('lowEstimatedExchangeRateNumerator', 64, 0).notNullable()
table
.decimal('lowEstimatedExchangeRateDenominator', 64, 0)
.notNullable()
table.decimal('highEstimatedExchangeRateNumerator', 64, 0).notNullable()
table
.decimal('highEstimatedExchangeRateDenominator', 64, 0)
.notNullable()

table.timestamp('createdAt').defaultTo(knex.fn.now())
table.timestamp('updatedAt').defaultTo(knex.fn.now())
})
.then(() => {
// Enable uuid_generate_v4
return knex.raw(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`)
})
.then(() => {
// Migrate data from quotes to ilpQuoteDetails.
return knex.raw(`
INSERT INTO "ilpQuoteDetails" (
id,
"quoteId",
"maxPacketAmount",
"minExchangeRateNumerator",
"minExchangeRateDenominator",
"lowEstimatedExchangeRateNumerator",
"lowEstimatedExchangeRateDenominator",
"highEstimatedExchangeRateNumerator",
"highEstimatedExchangeRateDenominator"
)
SELECT
uuid_generate_v4(),
id AS "quoteId",
"maxPacketAmount",
"minExchangeRateNumerator",
"minExchangeRateDenominator",
"lowEstimatedExchangeRateNumerator",
"lowEstimatedExchangeRateDenominator",
"highEstimatedExchangeRateNumerator",
"highEstimatedExchangeRateDenominator"
FROM "quotes";
`)
})
.then(() => {
// TODO: test this more thoroughly.
// Might need to seed in migration preceeding this?
// Cant simply withold htis migration. Application code will fail when trying
// to insert ...
return knex('quotes')
.whereNull('estimatedExchangeRate')
.update({
estimatedExchangeRate: knex.raw('?? / ??', [
'lowEstimatedExchangeRateNumerator',
'lowEstimatedExchangeRateDenominator'
])
})
})
.then(() => {
return knex.schema.alterTable('quotes', function (table) {
table.dropColumn('maxPacketAmount')
table.dropColumn('minExchangeRateNumerator')
table.dropColumn('minExchangeRateDenominator')
table.dropColumn('lowEstimatedExchangeRateNumerator')
table.dropColumn('lowEstimatedExchangeRateDenominator')
table.dropColumn('highEstimatedExchangeRateNumerator')
table.dropColumn('highEstimatedExchangeRateDenominator')
})
})
)
}

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex.schema
.alterTable('quotes', function (table) {
// restore columns without not null constraint
table.bigInteger('maxPacketAmount')
table.decimal('minExchangeRateNumerator', 64, 0)
table.decimal('minExchangeRateDenominator', 64, 0)
table.decimal('lowEstimatedExchangeRateNumerator', 64, 0)
table.decimal('lowEstimatedExchangeRateDenominator', 64, 0)
table.decimal('highEstimatedExchangeRateNumerator', 64, 0)
table.decimal('highEstimatedExchangeRateDenominator', 64, 0)
})
.then(() => {
// Migrate data back to quotes table from ilpQuote
return knex.raw(`
UPDATE "quotes"
SET
"maxPacketAmount" = "ilpQuoteDetails"."maxPacketAmount",
"minExchangeRateNumerator" = "ilpQuoteDetails"."minExchangeRateNumerator",
"minExchangeRateDenominator" = "ilpQuoteDetails"."minExchangeRateDenominator",
"lowEstimatedExchangeRateNumerator" = "ilpQuoteDetails"."lowEstimatedExchangeRateNumerator",
"lowEstimatedExchangeRateDenominator" = "ilpQuoteDetails"."lowEstimatedExchangeRateDenominator",
"highEstimatedExchangeRateNumerator" = "ilpQuoteDetails"."highEstimatedExchangeRateNumerator",
"highEstimatedExchangeRateDenominator" = "ilpQuoteDetails"."highEstimatedExchangeRateDenominator"
FROM "ilpQuoteDetails"
WHERE "quotes"."id" = "ilpQuoteDetails"."quoteId"
`)
})
.then(() => {
// Apply the not null constraints after data insertion
return knex.schema.alterTable('quotes', function (table) {
table.bigInteger('maxPacketAmount').notNullable().alter()
table.decimal('minExchangeRateNumerator', 64, 0).notNullable().alter()
table.decimal('minExchangeRateDenominator', 64, 0).notNullable().alter()
table
.decimal('lowEstimatedExchangeRateNumerator', 64, 0)
.notNullable()
.alter()
table
.decimal('lowEstimatedExchangeRateDenominator', 64, 0)
.notNullable()
.alter()
table
.decimal('highEstimatedExchangeRateNumerator', 64, 0)
.notNullable()
.alter()
table
.decimal('highEstimatedExchangeRateDenominator', 64, 0)
.notNullable()
.alter()
})
})
Copy link
Contributor Author

@BlairCurrey BlairCurrey Aug 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this down will fail if local quotes are added before migration is rolled back run because they dont have these non null columns. We are setting back to null because that was the original state before the migration. What should we do?

  • leave them as nullable in the down. Doesnt fully restore the original state but not sure we can, short of losing the new quotes that dont fit in the previous model.
  • keep nullable and set to sensible(ish) defaults (derive from exchange rate)?
  • lose the new quotes
  • do nothing and require manual remediation

IDK, not sure any of these options are great, but its also kind of an edge case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's split this up into multiple migrations, something like:

  • First one will backfill estimatedExchangeRate, and mark the field as required
  • second one will create ilpQuoteDetails
  • third one will backfill ilpQuoteDetails

Then we deploy the code changes to start reading from ilpQuoteDetails

  • last one will drop ilp fields from quotes

this way, we dont run into the risk of losing data

Copy link
Contributor Author

@BlairCurrey BlairCurrey Aug 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's split this up into multiple migrations, something like:

  • First one will backfill estimatedExchangeRate, and mark the field as required
  • second one will create ilpQuoteDetails
  • third one will backfill ilpQuoteDetails

Then we deploy the code changes to start reading from ilpQuoteDetails

  • last one will drop ilp fields from quotes

this way, we dont run into the risk of losing data

yeah I suppose multiple migrations make sense. More control over up/down if needed without downside.

In terms of this part:

  • third one will backfill ilpQuoteDetails

Then we deploy the code changes to start reading from ilpQuoteDetails

  • last one will drop ilp fields from quotes

Is the idea that we put the drop ilp fields from quotes in another release and communicate as much in patch notes? I mean I dont see a way to ensure integrators arent just upgrading multiple releases and running them all at once in that case. I guess this is still better and if some integrator does run into an issue we can fix it before we release the migration that will lose the data.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this all will go in one release, I was just thinking of how to make the changes safely (or in separate PRs).

If you want, we can have this:

Then we deploy the code changes to start reading from ilpQuoteDetails

released the same time as we backfill ilpQuoteDetails (and drop ilp fields from quotes for that matter)

Copy link
Contributor Author

@BlairCurrey BlairCurrey Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thinking about it more, i dont think we can split the create ilpQuoteDetails table and the migration to backfill it.

if migrations are run through create ilpQuoteDetails (but not backfilled), and then quotes are created in the application with ilpQuoteDetails, then they are backfilled, then the quotes created via the application will try to be inserted again in the ilpQuoteDetails (and it will fail because the quoteId has a unique constraint). I think we need to enforce they are run together by keeping them in the same migration. I think splitting the other ones as described are still fine.

.then(() => {
return knex.schema.dropTableIfExists('ilpQuoteDetails')
})
}
12 changes: 6 additions & 6 deletions packages/backend/src/graphql/resolvers/outgoing_payment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,12 @@ describe('OutgoingPayment Resolvers', (): void => {
metadata,
quote: {
id: payment.quote.id,
maxPacketAmount: payment.quote.maxPacketAmount.toString(),
minExchangeRate: payment.quote.minExchangeRate.valueOf(),
lowEstimatedExchangeRate:
payment.quote.lowEstimatedExchangeRate.valueOf(),
highEstimatedExchangeRate:
payment.quote.highEstimatedExchangeRate.valueOf(),
// maxPacketAmount: payment.quote.maxPacketAmount.toString(),
// minExchangeRate: payment.quote.minExchangeRate.valueOf(),
// lowEstimatedExchangeRate:
// payment.quote.lowEstimatedExchangeRate.valueOf(),
// highEstimatedExchangeRate:
// payment.quote.highEstimatedExchangeRate.valueOf(),
createdAt: payment.quote.createdAt.toISOString(),
expiresAt: payment.quote.expiresAt.toISOString(),
__typename: 'Quote'
Expand Down
8 changes: 4 additions & 4 deletions packages/backend/src/graphql/resolvers/quote.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ describe('Quote Resolvers', (): void => {
assetScale: quote.receiveAmount.assetScale,
__typename: 'Amount'
},
maxPacketAmount: quote.maxPacketAmount.toString(),
minExchangeRate: quote.minExchangeRate.valueOf(),
lowEstimatedExchangeRate: quote.lowEstimatedExchangeRate.valueOf(),
highEstimatedExchangeRate: quote.highEstimatedExchangeRate.valueOf(),
// maxPacketAmount: quote.maxPacketAmount.toString(),
// minExchangeRate: quote.minExchangeRate.valueOf(),
// lowEstimatedExchangeRate: quote.lowEstimatedExchangeRate.valueOf(),
// highEstimatedExchangeRate: quote.highEstimatedExchangeRate.valueOf(),
createdAt: quote.createdAt.toISOString(),
expiresAt: quote.expiresAt.toISOString(),
__typename: 'Quote'
Expand Down
9 changes: 5 additions & 4 deletions packages/backend/src/graphql/resolvers/quote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,18 @@ export const getWalletAddressQuotes: WalletAddressResolvers<ApolloContext>['quot
}
}

// TODO: update gql types (there is a pr pending for this)
export function quoteToGraphql(quote: Quote): SchemaQuote {
return {
id: quote.id,
walletAddressId: quote.walletAddressId,
receiver: quote.receiver,
debitAmount: quote.debitAmount,
receiveAmount: quote.receiveAmount,
maxPacketAmount: quote.maxPacketAmount,
minExchangeRate: quote.minExchangeRate.valueOf(),
lowEstimatedExchangeRate: quote.lowEstimatedExchangeRate.valueOf(),
highEstimatedExchangeRate: quote.highEstimatedExchangeRate.valueOf(),
maxPacketAmount: 0n, //quote.maxPacketAmount,
minExchangeRate: 0, //quote.minExchangeRate.valueOf(),
lowEstimatedExchangeRate: 0, //quote.lowEstimatedExchangeRate.valueOf(),
highEstimatedExchangeRate: 0, //quote.highEstimatedExchangeRate.valueOf(),
createdAt: new Date(+quote.createdAt).toISOString(),
expiresAt: new Date(+quote.expiresAt).toISOString()
}
Expand Down
18 changes: 17 additions & 1 deletion packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ import {
createIlpPaymentService,
ServiceDependencies as IlpPaymentServiceDependencies
} from './payment-method/ilp/service'
import {
createLocalPaymentService,
ServiceDependencies as LocalPaymentServiceDependencies
} from './payment-method/local/service'
import { createSPSPRoutes } from './payment-method/ilp/spsp/routes'
import { createStreamCredentialsService } from './payment-method/ilp/stream-credentials/service'
import { createRatesService } from './rates/service'
Expand Down Expand Up @@ -444,11 +448,23 @@ export function initIocContainer(
return createIlpPaymentService(serviceDependencies)
})

container.singleton('localPaymentService', async (deps) => {
const serviceDependencies: LocalPaymentServiceDependencies = {
logger: await deps.use('logger'),
knex: await deps.use('knex'),
config: await deps.use('config'),
ratesService: await deps.use('ratesService')
}

return createLocalPaymentService(serviceDependencies)
})

container.singleton('paymentMethodHandlerService', async (deps) => {
return createPaymentMethodHandlerService({
logger: await deps.use('logger'),
knex: await deps.use('knex'),
ilpPaymentService: await deps.use('ilpPaymentService')
ilpPaymentService: await deps.use('ilpPaymentService'),
localPaymentService: await deps.use('localPaymentService')
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,7 @@ function getAdjustedAmounts(
// This is only an approximation of the true amount delivered due to exchange rate variance. Due to connection failures there isn't a reliable way to track that in sync with the amount sent (particularly within ILP payments)
// eslint-disable-next-line no-case-declarations
const amountDelivered = BigInt(
Math.ceil(
Number(alreadySentAmount) *
(payment.quote.estimatedExchangeRate ||
payment.quote.lowEstimatedExchangeRate.valueOf())
)
Math.ceil(Number(alreadySentAmount) * payment.quote.estimatedExchangeRate)
Copy link
Contributor Author

@BlairCurrey BlairCurrey Aug 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wont have the low lowEstimatedExchangeRate to fall back on anymore (it will be optional) so I ensured estimatedExchangeRate is always set in the migration. Set it to be lowEstimatedExchangeRate where null, just like we're setting it in the ilp getQuote method.

)
let maxReceiveAmount = payment.receiveAmount.value - amountDelivered

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -785,8 +785,10 @@ describe('OutgoingPaymentService', (): void => {
validDestination: false,
method: 'ilp'
})
const pastDate = new Date()
pastDate.setMinutes(pastDate.getMinutes() - 5)
await quote.$query(knex).patch({
expiresAt: new Date()
expiresAt: pastDate
})
await expect(
outgoingPaymentService.create({
Expand Down
12 changes: 6 additions & 6 deletions packages/backend/src/open_payments/payment/outgoing/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async function getOutgoingPayment(
): Promise<OutgoingPayment | undefined> {
const outgoingPayment = await OutgoingPayment.query(deps.knex)
.get(options)
.withGraphFetched('[quote.asset, walletAddress]')
.withGraphFetched('[quote.[asset, ilpQuoteDetails], walletAddress]')
BlairCurrey marked this conversation as resolved.
Show resolved Hide resolved

if (outgoingPayment) {
return addSentAmount(deps, outgoingPayment)
Expand Down Expand Up @@ -150,7 +150,7 @@ async function cancelOutgoingPayment(
...(options.reason ? { cancellationReason: options.reason } : {})
}
})
.withGraphFetched('[quote.asset, walletAddress]')
.withGraphFetched('[quote.[asset, ilpQuoteDetails], walletAddress]')

return addSentAmount(deps, payment)
})
Expand Down Expand Up @@ -208,7 +208,7 @@ async function createOutgoingPayment(
state: OutgoingPaymentState.Funding,
grantId
})
.withGraphFetched('[quote.asset, walletAddress]')
.withGraphFetched('[quote.[asset, ilpQuoteDetails], walletAddress]')

if (
payment.walletAddressId !== payment.quote.walletAddressId ||
Expand Down Expand Up @@ -372,7 +372,7 @@ async function validateGrantAndAddSpentAmountsToPayment(
.andWhereNot({
id: payment.id
})
.withGraphFetched('[quote.asset]')
.withGraphFetched('[quote.[asset, ilpQuoteDetails]]')

if (grantPayments.length === 0) {
return true
Expand Down Expand Up @@ -449,7 +449,7 @@ async function fundPayment(
const payment = await OutgoingPayment.query(trx)
.findById(id)
.forUpdate()
.withGraphFetched('[quote.asset]')
.withGraphFetched('[quote.[asset, ilpQuoteDetails]]')
if (!payment) return FundingError.UnknownPayment
if (payment.state !== OutgoingPaymentState.Funding) {
return FundingError.WrongState
Expand Down Expand Up @@ -493,7 +493,7 @@ async function getWalletAddressPage(
): Promise<OutgoingPayment[]> {
const page = await OutgoingPayment.query(deps.knex)
.list(options)
.withGraphFetched('[quote.asset, walletAddress]')
.withGraphFetched('[quote.[asset, ilpQuoteDetails], walletAddress]')
const amounts = await deps.accountingService.getAccountsTotalSent(
page.map((payment: OutgoingPayment) => payment.id)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async function getPendingPayment(
[RETRY_BACKOFF_SECONDS, now]
)
})
.withGraphFetched('[walletAddress, quote.asset]')
.withGraphFetched('[walletAddress, quote.[asset, ilpQuoteDetails]]')
return payments[0]
}

Expand Down
Loading
Loading