Skip to content

Instantly share code, notes, and snippets.

@whiteyhat
Last active October 23, 2019 02:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save whiteyhat/85048e46db618c697e1e9a9f8b49426b to your computer and use it in GitHub Desktop.
Save whiteyhat/85048e46db618c697e1e9a9f8b49426b to your computer and use it in GitHub Desktop.
Backend implementation using adonis.js framework for Lightning Network withdrawals straight to wallet using LNURL
const Logger = use('Logger')
const bech32 = require('bech32')
const Hash = use('Hash')
const lnService = require('ln-service')
const NonceHashMap = {};
const k1HashMap = {};
async requestWithdrawal ({auth, response}) {
try{
if (auth.user.unique_id){
// create random nonce for the user
const nonce = Math.floor(Math.random() * 1000000) // TODO: stronger source of randomness
// add item to hashmap
NonceHashMap[Hash.make(nonce)] = auth.user.id
return response.json({
data: bech32.encode('LNURL', "https://satoshis.games/withdrawal/confirmation?q="+nonce).toLocaleUpperCase()
})
}
}catch(error){
Logger.error(error)
return response.json({error})
}
}
async confirmWithdrawal ({response, request}) {
const { q } = request.all()
if (Hash.make(q) in NonceHashMap){
const existingUserId = NonceHashMap[Hash.make(q)]
delete NonceHashMap[Hash.make(q)]; // Invalidate a QR
const secondLevelNonce = Math.floor(Math.random() * 1000000) // TODO: stronger source of randomness
// k1HashMap[Hash.make(k1)] = Hash.make(auth.user.id)
k1HashMap[Hash.make(secondLevelNonce)] = existingUserId
return response.json({
callback = "https://satoshis.games/withdrawal/execute",
k1 = secondLevelNonce,
maxWithdrawable = 2000, // msat
defaultDescription = "withdraw from satoshis.games",
tag = "withdrawRequest",
})
}
}
async executeWithrawal ({request}) {
const { k1 } = request.all()
const { pr } = request.all()
if (Hash.make(k1) in k1HashMap){
const existingUserId = k1HashMap[Hash.make(k1)]
delete k1HashMap[Hash.make(k1)];
this.makePayment({pr})
response.ok()
} else {
return json({ status: "ERROR", reason: "Second level nonce not found" })
}
}
async makePayment ({pr}) {
try {
const lnd = await LndService.getLndInstance()
// Payment to encoded invoice request
await lnService.pay({
lnd,
request: pr
}, (error, result) => {
Logger.info(result)
Logger.error('Error:', error)
})
}catch(error){
Logger.error(error)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment