Skip to content

Instantly share code, notes, and snippets.

@vindard
Last active September 28, 2022 12:29
Show Gist options
  • Save vindard/f7b89a05f5639467987e692072b58326 to your computer and use it in GitHub Desktop.
Save vindard/f7b89a05f5639467987e692072b58326 to your computer and use it in GitHub Desktop.
A test to demonstrate an arb opportunity we discovered
it.only("arbitrage BTC/USD with $0.01 strategy", async () => {
const ONE_CENT = { amount: 1n, currency: WalletCurrency.Usd } as UsdPaymentAmount
const ONE_SAT = { amount: 1n, currency: WalletCurrency.Btc } as BtcPaymentAmount
const getUsdForBtcEquivalent = async (
btcAmount: BtcPaymentAmount,
): Promise<CurrencyBaseAmount> => {
// console.log({ btcAmount })
const lnInvoice = await Wallets.addInvoiceForSelf({
walletId: walletIdB,
amount: toSats(btcAmount.amount),
})
if (lnInvoice instanceof Error) throw lnInvoice
const beforeUsd = await getBalanceHelper(walletIdUsdB)
const result = await Payments.payInvoiceByWalletId({
paymentRequest: lnInvoice.paymentRequest,
memo: null,
senderWalletId: walletIdUsdB,
senderAccount: accountB,
})
if (result instanceof Error) throw result
const afterUsd = await getBalanceHelper(walletIdUsdB)
const diff = (beforeUsd - afterUsd) as CurrencyBaseAmount
// console.log({ beforeUsd, afterUsd, diff })
return diff
}
const midPriceRatio = await getMidPriceRatio(usdHedgeEnabled)
if (midPriceRatio instanceof Error) throw midPriceRatio
const startingBtcAmount = midPriceRatio.convertFromUsd(ONE_CENT)
console.log({ startingBtcAmount })
// Validate btc starting amount for max btc discovery
let maxBtcAmountToEarn = startingBtcAmount
let diff = 2 as CurrencyBaseAmount
while (diff > 1) {
diff = await getUsdForBtcEquivalent(maxBtcAmountToEarn)
if (diff > 1) {
maxBtcAmountToEarn = calc.sub(maxBtcAmountToEarn, ONE_SAT)
}
}
expect(diff).toEqual(1)
console.log("Start:", { maxBtcAmountToEarn })
// Discover max BTC amount to buy for $0.01
while (diff === 1) {
maxBtcAmountToEarn = calc.add(maxBtcAmountToEarn, ONE_SAT)
diff = await getUsdForBtcEquivalent(maxBtcAmountToEarn)
}
maxBtcAmountToEarn = calc.sub(maxBtcAmountToEarn, ONE_SAT)
console.log("Discovered:", { maxBtcAmountToEarn })
// Validate btc starting amount for min btc discovery
let minBtcAmountToSpend = startingBtcAmount
let paid: Error | PaymentSendStatus = PaymentSendStatus.Success
while (!(paid instanceof ZeroAmountForUsdRecipientError)) {
paid = await Payments.intraledgerPaymentSendWalletId({
recipientWalletId: walletIdUsdB,
memo: null,
amount: toSats(minBtcAmountToSpend.amount),
senderWalletId: walletIdB,
senderAccount: accountB,
})
if (paid instanceof Error && !(paid instanceof ZeroAmountForUsdRecipientError)) {
throw paid
}
// console.log(paid, minBtcAmountToSpend)
if (!(paid instanceof ZeroAmountForUsdRecipientError)) {
minBtcAmountToSpend = calc.sub(minBtcAmountToSpend, ONE_SAT)
}
}
console.log("Start:", { minBtcAmountToSpend })
// Discover min BTC amount to sell for $0.01
while (paid instanceof ZeroAmountForUsdRecipientError) {
minBtcAmountToSpend = calc.add(minBtcAmountToSpend, ONE_SAT)
paid = await Payments.intraledgerPaymentSendWalletId({
recipientWalletId: walletIdUsdB,
memo: null,
amount: toSats(minBtcAmountToSpend.amount),
senderWalletId: walletIdB,
senderAccount: accountB,
})
if (paid instanceof Error && !(paid instanceof ZeroAmountForUsdRecipientError)) {
throw paid
}
console.log(paid, minBtcAmountToSpend)
}
console.log("Discovered:", { minBtcAmountToSpend })
console.log({
maxBtcAmountToEarn,
minBtcAmountToSpend,
arb: maxBtcAmountToEarn.amount - minBtcAmountToSpend.amount,
})
// Execute arbitrage
const arbBeforeBtc = await getBalanceHelper(walletIdB)
const arbBeforeUsd = await getBalanceHelper(walletIdUsdB)
// Step 1: Create invoice from BTC Wallet
const lnInvoice = await Wallets.addInvoiceForSelf({
walletId: walletIdB,
amount: toSats(maxBtcAmountToEarn.amount),
})
if (lnInvoice instanceof Error) throw lnInvoice
// Step 2: Pay invoice from USD wallet at favourable rate
await Payments.payInvoiceByWalletId({
paymentRequest: lnInvoice.paymentRequest,
memo: null,
senderWalletId: walletIdUsdB,
senderAccount: accountB,
})
// Step 3: Replenish USD from BTC wallet at lower rate
await Payments.intraledgerPaymentSendWalletId({
recipientWalletId: walletIdUsdB,
memo: null,
amount: toSats(minBtcAmountToSpend.amount),
senderWalletId: walletIdB,
senderAccount: accountB,
})
if (paid instanceof Error && !(paid instanceof ZeroAmountForUsdRecipientError)) {
throw paid
}
const arbAfterBtc = await getBalanceHelper(walletIdB)
const arbAfterUsd = await getBalanceHelper(walletIdUsdB)
const diffBtc = arbAfterBtc - arbBeforeBtc
const diffUsd = arbAfterUsd - arbBeforeUsd
console.log({ diffBtc, diffUsd })
console.log({
arbPercentage: `${Math.round(
(diffBtc / Number(minBtcAmountToSpend.amount)) * 100,
)}%`,
})
expect(diffBtc).toBeLessThanOrEqual(0)
expect(diffUsd).toBeLessThanOrEqual(0)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment