Last active
September 28, 2022 12:29
-
-
Save vindard/f7b89a05f5639467987e692072b58326 to your computer and use it in GitHub Desktop.
A test to demonstrate an arb opportunity we discovered
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
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