-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import {AuthenticatedLnd} from '../../lnd_grpc'; | ||
import { | ||
AuthenticatedLightningArgs, | ||
AuthenticatedLightningMethod | ||
} from '../../typescript'; | ||
|
||
export type GetRoutingFeeEstimateRequest = AuthenticatedLightningArgs<{ | ||
lnd: AuthenticatedLnd; | ||
/** BOLT 11 Encoded Payment Request */ | ||
request: string; | ||
/** Optional Timeout in Milliseconds */ | ||
timeout: number; | ||
}>; | ||
|
||
export type GetRoutingFeeEstimateResponse = { | ||
/** Sats (Routing Fee Sats) */ | ||
fee: number; | ||
/** Timeout (Time Lock Delay) */ | ||
timeout: string; | ||
}; | ||
|
||
/** | ||
* Estimate routing fees based on an invoice. | ||
* | ||
* Requires `offchain:read` permission | ||
* | ||
* This method is not supported before LND 0.18.4 | ||
*/ | ||
export const getRoutingFeeEstimate: AuthenticatedLightningMethod< | ||
GetRoutingFeeEstimateRequest, | ||
GetRoutingFeeEstimateResponse | ||
>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
const asyncAuto = require('async/auto'); | ||
const {returnResult} = require('asyncjs-util'); | ||
|
||
/** | ||
* Estimate routing fees based on an invoice. | ||
* | ||
* Requires `offchain:read` permission | ||
* | ||
* This method is not supported before LND 0.18.4 | ||
* | ||
@argument | ||
{ | ||
lnd: <Authenticated LND API Object> | ||
request: <BOLT 11 Payment Request String> | ||
timeout: <Optional Timeout in Milliseconds Number> | ||
} | ||
@returns via cbk or Promise | ||
{ | ||
fee: <Route Fee Sats Number> | ||
timeout: <Time Lock Block Height Delay String> | ||
} | ||
*/ | ||
module.exports = ({lnd, request, timeout}, cbk) => { | ||
return new Promise((resolve, reject) => { | ||
return asyncAuto({ | ||
// Check arguments | ||
validate: cbk => { | ||
if (!lnd || !lnd.router) { | ||
return cbk([400, 'ExpectedAuthenticatedLndForGetRoutingFeeEstimate']); | ||
} | ||
|
||
if (!request) { | ||
return cbk([400, 'ExpectedPaymentRequestStringForGetRoutingFeeEstimate']); | ||
} | ||
|
||
if (timeout > 86400000) { | ||
return cbk([400, 'ExpectedTimeoutLessThanOneDayForGetRoutingFeeEstimate']); | ||
} | ||
|
||
if (timeout < 1) { | ||
return cbk([400, 'ExpectedTimeoutGreaterThanZeroForGetRoutingFeeEstimate']); | ||
} | ||
|
||
timeout = !timeout ? 60 : timeout / 1000; | ||
|
||
return cbk(); | ||
}, | ||
|
||
// Estimate route fee and return a successful routing fee and timeout or failure reason | ||
getEstimate: ['validate', ({}, cbk) => { | ||
return lnd.router.estimateRouteFee({request, timeout}, | ||
(err, res) => { | ||
if (err) { | ||
return cbk([503, 'UnexpectedGetRoutingFeeEstimateError', {err}]); | ||
} | ||
|
||
if (!res) { | ||
return cbk([503, 'ExpectedGetRoutingFeeEstimateResponse']); | ||
} | ||
|
||
const mtokenFee = Number(res.fee); | ||
if (!mtokenFee) { | ||
return cbk([503, 'ExpectedFeeInGetRoutingFeeEstimateResponse']); | ||
} | ||
|
||
if (isNaN(mtokenFee)) { | ||
return cbk([503, 'ExpectedFeeInGetRoutingFeeEstimateResponseToBeNumber']); | ||
} | ||
|
||
if (!isFinite(mtokenFee)) { | ||
return cbk([503, 'ExpectedFeeInGetRoutingFeeEstimateResponseToBeFinite']); | ||
} | ||
|
||
if (!res.timeout) { | ||
return cbk([503, 'ExpectedTimeoutInGetRoutingFeeEstimateResponse']); | ||
} | ||
|
||
if (res.failure_reason !== 'FAILURE_REASON_NONE') { | ||
return cbk([404, 'GetRoutingFeeEstimateFailed', {failure: res.failure_reason}]) | ||
} | ||
|
||
const fee = mtokenFee > 0 ? mtokenFee / 1000 : mtokenFee; | ||
return cbk(null, {fee, timeout: res.timeout}); | ||
}); | ||
}], | ||
}, | ||
returnResult({reject, resolve, of: 'getEstimate'}, cbk)); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
test/lnd_methods/offchain/test_get_routing_fee_estimate.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
const {rejects, deepStrictEqual} = require('node:assert').strict; | ||
const test = require('node:test'); | ||
const getRoutingFeeEstimate = require('../../../lnd_methods/offchain/get_routing_fee_estimate'); | ||
|
||
const request = 'lnbcrt500u1pnh3r5dpp57cppte59jvmxnaunh03ecy6wchq8e0zh70n0nzsamaxztqxevcusdqqcqzzsxqyz5vqsp587ua488ttsts8cs97ekt9axdla3jmq4mj2h7xj7g6rw37fu65yqs9qxpqysgql27u5p9m2xv0r0pjykzvcgs88azzfkywzw2xw5q6u86qnwzrut94mks86zxelhltdtn6vnqgd8hay433wwq7uvple709gp7pmwmtzwcqakyevc'; | ||
|
||
/** Function */ | ||
const makeLnd = ({err, res}) => { | ||
const response = { | ||
fee: 1050, | ||
timeout: '3520', | ||
failure_reason: 'FAILURE_REASON_NONE' | ||
}; | ||
return { | ||
router: { | ||
estimateRouteFee: ({}, cbk) => cbk(err, res !== undefined ? res : response), | ||
} | ||
}; | ||
}; | ||
|
||
const makeArgs = override => { | ||
const args = {request, timeout: 60000, lnd: makeLnd({})}; | ||
Object.keys(override || {}).forEach(key => args[key] = override[key]); | ||
return args; | ||
}; | ||
|
||
const tests = [ | ||
{ | ||
args: makeArgs({lnd: undefined}), | ||
description: 'LND is required', | ||
error: [400, 'ExpectedAuthenticatedLndForGetRoutingFeeEstimate'], | ||
}, | ||
{ | ||
args: makeArgs({request: undefined}), | ||
description: 'Request is required', | ||
error: [400, 'ExpectedPaymentRequestStringForGetRoutingFeeEstimate'], | ||
}, | ||
{ | ||
args: makeArgs({timeout: 86400001}), | ||
description: 'Timeout must be less than or equal to 86400000 milliseconds', | ||
error: [400, 'ExpectedTimeoutLessThanOneDayForGetRoutingFeeEstimate'], | ||
}, | ||
{ | ||
args: makeArgs({timeout: 0}), | ||
description: 'Timeout must be greater than 0 milliseconds', | ||
error: [400, 'ExpectedTimeoutGreaterThanZeroForGetRoutingFeeEstimate'], | ||
}, | ||
{ | ||
args: makeArgs({request, lnd: makeLnd({})}), | ||
description: 'A route fee number in sats is expected for default timeout 60000 milliseconds', | ||
expected: {fee: 1.05, timeout: '3520'} | ||
}, | ||
{ | ||
args: makeArgs({request, timeout: 86400000, lnd: makeLnd({})}), | ||
description: 'A route fee number in sats is expected for timeout 86400000 milliseconds', | ||
expected: {fee: 1.05, timeout: '3520'} | ||
} | ||
]; | ||
|
||
tests.forEach(({args, description, error, expected}) => { | ||
return test(description, async () => { | ||
if (!!error) { | ||
await rejects(getRoutingFeeEstimate(args), error, 'Got expected error'); | ||
} else { | ||
deepStrictEqual(await getRoutingFeeEstimate(args), expected, 'Got result'); | ||
} | ||
|
||
return; | ||
}); | ||
}); |