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

Added additional system test scenario #654

Merged
merged 8 commits into from
Aug 23, 2023
276 changes: 275 additions & 1 deletion system-tests/test/deposit-redemption.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe("System Test - Deposit and redemption", () => {
let systemTestsContext: SystemTestsContext
let electrumClient: ElectrumClient
let bridgeAddress: string
let vaultAddress: string
let maintainerBridgeHandle: EthereumBridge
let depositorBridgeHandle: EthereumBridge
let bank: Contract
Expand Down Expand Up @@ -77,6 +78,7 @@ describe("System Test - Deposit and redemption", () => {
)

bridgeAddress = deployedContracts.Bridge.address
vaultAddress = deployedContracts.TBTCVault.address

maintainerBridgeHandle = new EthereumBridge({
address: bridgeAddress,
Expand All @@ -103,7 +105,7 @@ describe("System Test - Deposit and redemption", () => {
)
})

context("when deposit is made and revealed", () => {
context("when deposit is made and revealed without a vault", () => {
before("make and reveal deposit", async () => {
deposit = generateDeposit(
systemTestsContext.depositor.address,
Expand Down Expand Up @@ -372,4 +374,276 @@ describe("System Test - Deposit and redemption", () => {
})
})
})

context("when deposit is made and revealed with a vault", () => {
before("make and reveal deposit", async () => {
deposit = generateDeposit(
systemTestsContext.depositor.address,
depositAmount,
systemTestsContext.walletBitcoinKeyPair.publicKey.compressed,
vaultAddress,
)

console.log(`
Generated deposit data:
${JSON.stringify(deposit)}
`)
;({ depositUtxo } = await submitDepositTransaction(
deposit,
systemTestsContext.depositorBitcoinKeyPair.wif,
electrumClient,
true
))

console.log(`
Deposit made on BTC chain:
- Transaction hash: ${depositUtxo.transactionHash}
- Output index: ${depositUtxo.outputIndex}
`)

// Since the reveal deposit logic does not perform SPV proof, we
// can reveal the deposit transaction immediately without waiting
// for confirmations.
await TBTC.revealDeposit(
depositUtxo,
deposit,
electrumClient,
depositorBridgeHandle,
deposit.vault,
)

console.log(`
Deposit revealed on Ethereum chain
`)
})

it("should broadcast the deposit transaction on the Bitcoin network", async () => {
expect(
(await electrumClient.getRawTransaction(depositUtxo.transactionHash))
.transactionHex.length
).to.be.greaterThan(0)
})

it("should reveal the deposit to the bridge", async () => {
const { revealedAt } = await TBTC.getRevealedDeposit(
depositUtxo,
maintainerBridgeHandle
)
expect(revealedAt).to.be.greaterThan(0)
})

context("when deposit is swept and sweep proof submitted", () => {
before("sweep the deposit and submit sweep proof", async () => {
;({ newMainUtxo: sweepUtxo } = await submitDepositSweepTransaction(
electrumClient,
depositSweepTxFee,
systemTestsContext.walletBitcoinKeyPair.wif,
true,
[depositUtxo],
[deposit]
))

console.log(`
Deposit swept on Bitcoin chain:
- Transaction hash: ${sweepUtxo.transactionHash}
`)

// Unlike in the deposit transaction case, we must wait for the sweep
// transaction to have an enough number of confirmations. This is
// because the bridge performs the SPV proof of that transaction.
await waitTransactionConfirmed(
electrumClient,
sweepUtxo.transactionHash
)

await fakeRelayDifficulty(
relay,
electrumClient,
sweepUtxo.transactionHash
)

// TODO: Consider fetching the current wallet main UTXO and passing it
// here. This will allow running this test scenario multiple
// times for the same wallet.
await SpvMaintainer.submitDepositSweepProof(
sweepUtxo.transactionHash,
// This is the first sweep of the given wallet so there is no main UTXO.
{
// The function expects an unprefixed hash.
transactionHash: BitcoinTransactionHash.from(constants.HashZero),
outputIndex: 0,
value: BigNumber.from(0),
},
maintainerBridgeHandle,
electrumClient
)

console.log(`
Deposit sweep proved on the bridge
`)
})

it("should broadcast the sweep transaction on the Bitcoin network", async () => {
expect(
(await electrumClient.getRawTransaction(sweepUtxo.transactionHash))
.transactionHex.length
).to.be.greaterThan(0)
})

it("should sweep the deposit on the bridge", async () => {
const { sweptAt } = await TBTC.getRevealedDeposit(
depositUtxo,
maintainerBridgeHandle
)
expect(sweptAt).to.be.greaterThan(0)
})

it("should increase depositor's balance in the bank", async () => {
const { treasuryFee } = await TBTC.getRevealedDeposit(
depositUtxo,
maintainerBridgeHandle
)

const expectedBalance = depositAmount
.sub(treasuryFee)
.sub(depositSweepTxFee)

const actualBalance = await bank.balanceOf(
systemTestsContext.depositor.address
)
r-czajkowski marked this conversation as resolved.
Show resolved Hide resolved

expect(actualBalance).to.be.equal(expectedBalance)
})

context("when redemption is requested", () => {
let requestedAmount: BigNumber
let redeemerOutputScript: string
let redemptionRequest: RedemptionRequest

before("request the redemption", async () => {
// Redeem the full depositor's balance.
requestedAmount = await bank.balanceOf(
systemTestsContext.depositor.address
)

// Allow the bridge to take the redeemed bank balance.
await bank
.connect(systemTestsContext.depositor)
.approveBalance(bridgeAddress, requestedAmount)
r-czajkowski marked this conversation as resolved.
Show resolved Hide resolved

// Request redemption to depositor's address.
redeemerOutputScript = `0014${computeHash160(
systemTestsContext.depositorBitcoinKeyPair.publicKey.compressed
)}`

await depositorBridgeHandle.requestRedemption(
systemTestsContext.walletBitcoinKeyPair.publicKey.compressed,
sweepUtxo,
redeemerOutputScript,
requestedAmount,
)
r-czajkowski marked this conversation as resolved.
Show resolved Hide resolved

console.log(
`Requested redemption of amount ${requestedAmount} to script ${redeemerOutputScript} on the bridge`
)

redemptionRequest = await TBTC.getRedemptionRequest(
systemTestsContext.walletBitcoinKeyPair.publicKey.compressed,
redeemerOutputScript,
"pending",
maintainerBridgeHandle
)
})

it("should transfer depositor's bank balance to the Bridge", async () => {
expect(
await bank.balanceOf(systemTestsContext.depositor.address)
).to.be.equal(0)

expect(await bank.balanceOf(bridgeAddress)).to.be.equal(
requestedAmount
)
})

it("should register the redemption request on the bridge", async () => {
expect(redemptionRequest.requestedAt).to.be.greaterThan(0)
expect(redemptionRequest.requestedAmount).to.be.equal(requestedAmount)
expect(redemptionRequest.redeemerOutputScript).to.be.equal(
redeemerOutputScript
)
})

context(
"when redemption is made and redemption proof submitted",
() => {
let redemptionTxHash: BitcoinTransactionHash

before(
"make the redemption and submit redemption proof",
async () => {
;({ transactionHash: redemptionTxHash } =
await submitRedemptionTransaction(
electrumClient,
maintainerBridgeHandle,
systemTestsContext.walletBitcoinKeyPair.wif,
sweepUtxo,
[redemptionRequest.redeemerOutputScript],
true
))

console.log(
"Redemption made on Bitcoin chain:\n" +
`- Transaction hash: ${redemptionTxHash}`
)

await waitTransactionConfirmed(electrumClient, redemptionTxHash)

await fakeRelayDifficulty(
relay,
electrumClient,
redemptionTxHash
)

await SpvMaintainer.submitRedemptionProof(
redemptionTxHash,
sweepUtxo,
systemTestsContext.walletBitcoinKeyPair.publicKey.compressed,
maintainerBridgeHandle,
electrumClient
)

console.log("Redemption proved on the bridge")
}
)

it("should broadcast the redemption transaction on the Bitcoin network", async () => {
expect(
(await electrumClient.getRawTransaction(redemptionTxHash))
.transactionHex.length
).to.be.greaterThan(0)
})

it("should close the redemption request on the bridge", async () => {
await expect(
TBTC.getRedemptionRequest(
systemTestsContext.walletBitcoinKeyPair.publicKey.compressed,
redemptionRequest.redeemerOutputScript,
"pending",
maintainerBridgeHandle
)
).to.be.rejectedWith(
"Provided redeemer output script and wallet public key do not identify a redemption request"
)
})

it("should decrease Bridge's balance in the bank", async () => {
const actualBalance = await bank.balanceOf(bridgeAddress)

expect(actualBalance).to.be.equal(0)
})
}
)
})
})
})
})