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 all 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,72 @@
meta {
name: Create Outgoing Payment
type: graphql
seq: 3
}

post {
url: {{RafikiGraphqlHost}}/graphql
body: graphql
auth: none
}

body:graphql {
mutation CreateOutgoingPayment($input: CreateOutgoingPaymentInput!) {
createOutgoingPayment(input: $input) {
payment {
createdAt
error
metadata
id
walletAddressId
receiveAmount {
assetCode
assetScale
value
}
receiver
debitAmount {
assetCode
assetScale
value
}
sentAmount {
assetCode
assetScale
value
}
state
stateAttempts
}
}
}
}

body:graphql:vars {
{
"input": {
"walletAddressId": "{{gfranklinWalletAddressId}}",
"quoteId": "{{quoteId}}"
}
}
}

script:pre-request {
const scripts = require('./scripts');

scripts.addApiSignatureHeader();
}

script:post-response {
const body = res.getBody();

if (body?.data) {
bru.setEnvVar("outgoingPaymentId", body.data.createOutgoingPayment.payment.id);
}
}

tests {
test("Outgoing Payment id is string", function() {
expect(bru.getEnvVar("outgoingPaymentId")).to.be.a("string");
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
meta {
name: Create Quote
type: graphql
seq: 2
}

post {
url: {{RafikiGraphqlHost}}/graphql
body: graphql
auth: none
}

body:graphql {
mutation CreateQuote($input: CreateQuoteInput!) {
createQuote(input: $input) {
quote {
createdAt
expiresAt
id
walletAddressId
receiveAmount {
assetCode
assetScale
value
}
receiver
debitAmount {
assetCode
assetScale
value
}
}
}
}
}

body:graphql:vars {
{
"input": {
"walletAddressId": "{{gfranklinWalletAddressId}}",
"receiver": "{{receiverId}}"
}
}
}

script:pre-request {
const scripts = require('./scripts');

await scripts.loadWalletAddressIdsIntoVariables();

scripts.addApiSignatureHeader();
}

script:post-response {
const body = res.getBody();

if (body?.data) {
bru.setEnvVar("quoteId", body.data.createQuote.quote.id);
}
}

tests {
test("Quote id is string", function() {
expect(bru.getEnvVar("quoteId")).to.be.a("string");
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
meta {
name: Create Receiver -local Incoming Payment-
type: graphql
seq: 1
}

post {
url: {{RafikiGraphqlHost}}/graphql
body: graphql
auth: none
}

body:graphql {
mutation CreateReceiver($input: CreateReceiverInput!) {
createReceiver(input: $input) {
receiver {
completed
createdAt
expiresAt
metadata
id
incomingAmount {
assetCode
assetScale
value
}
walletAddressUrl
receivedAmount {
assetCode
assetScale
value
}
updatedAt
}
}
}
}

body:graphql:vars {
{
"input": {
"metadata": {
"description": "For lunch!"
},
"incomingAmount": {
"assetCode": "USD",
"assetScale": 2,
"value": 500
},
"walletAddressUrl": "https://cloud-nine-wallet-backend/accounts/bhamchest"
}
}
}

script:pre-request {
const scripts = require('./scripts');

scripts.addApiSignatureHeader();
}

script:post-response {
const body = res.getBody();

if (body?.data) {
bru.setEnvVar("receiverId", body.data.createReceiver.receiver.id);
}
}

tests {
test("Receiver id is string", function() {
expect(bru.getEnvVar("receiverId")).to.be.a("string");
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
meta {
name: Get Outgoing Payment
type: graphql
seq: 4
}

post {
url: {{RafikiGraphqlHost}}/graphql
body: graphql
auth: none
}

body:graphql {
query GetOutgoingPayment($id: String!) {
outgoingPayment(id: $id) {
createdAt
error
metadata
id
grantId
walletAddressId
quote {
id
}
receiveAmount {
assetCode
assetScale
value
}
receiver
debitAmount {
assetCode
assetScale
value
}
sentAmount {
assetCode
assetScale
value
}
state
stateAttempts
}
}
}

body:graphql:vars {
{
"id": "{{outgoingPaymentId}}"
}
}

script:pre-request {
const scripts = require('./scripts');

scripts.addApiSignatureHeader();
}
6 changes: 6 additions & 0 deletions localenv/cloud-nine-wallet/seed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ accounts:
path: accounts/broke
brunoEnvVar: brokeWalletAddress
assetCode: USD
- name: "Luca Rossi"
id: 63dcc665-d946-4263-ac27-d0da1eb08a83
initialBalance: 50
path: accounts/lrossi
brunoEnvVar: lrossiWalletAddressId
assetCode: EUR
rates:
EUR:
MXN: 18.78
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/

exports.up = function (knex) {
return knex('quotes')
.whereNull('estimatedExchangeRate')
Copy link
Member

Choose a reason for hiding this comment

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

In which cases the estimatedExchangeRate was null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I dont know of any specific cases where it would be null, but since it's nullable we should handle that possibility.

.update({
estimatedExchangeRate: knex.raw('?? / ??', [
'lowEstimatedExchangeRateNumerator',
'lowEstimatedExchangeRateDenominator'
])
})
.then(() => {
return knex.schema.table('quotes', (table) => {
table.decimal('estimatedExchangeRate', 20, 10).notNullable().alter()
})
})
}

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex.schema.table('quotes', (table) => {
table.decimal('estimatedExchangeRate', 20, 10).nullable().alter()
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @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()

// quoteId is purposefully not a FK referencing quote.id
// this allows us to create ilpQuoteDetail before quotes in service of
// fully decoupling payment method/quote services.
// https://github.com/interledger/rafiki/pull/2857#discussion_r1825891327
table.uuid('quoteId').notNullable().unique().index()

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(() => {
return knex.raw(`
INSERT INTO "ilpQuoteDetails" (
id,
"quoteId",
"maxPacketAmount",
"minExchangeRateNumerator",
"minExchangeRateDenominator",
"lowEstimatedExchangeRateNumerator",
"lowEstimatedExchangeRateDenominator",
"highEstimatedExchangeRateNumerator",
"highEstimatedExchangeRateDenominator"
)
SELECT
gen_random_uuid(),
id AS "quoteId",
"maxPacketAmount",
"minExchangeRateNumerator",
"minExchangeRateDenominator",
"lowEstimatedExchangeRateNumerator",
"lowEstimatedExchangeRateDenominator",
"highEstimatedExchangeRateNumerator",
"highEstimatedExchangeRateDenominator"
FROM "quotes";
`)
})
)
}

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex.schema.dropTableIfExists('ilpQuoteDetails')
}
Loading
Loading