Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions x/btcbridge/keeper/keeper_withdraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,29 @@ func (k Keeper) IncrementRequestSequence(ctx sdk.Context) uint64 {

// NewWithdrawRequest creates a new withdrawal request
func (k Keeper) NewWithdrawRequest(ctx sdk.Context, sender string, amount sdk.Coin, feeRate int64) (*types.BitcoinWithdrawRequest, error) {
sequence := k.IncrementRequestSequence(ctx)

p := k.GetParams(ctx)
btcVault := types.SelectVaultByAssetType(p.Vaults, types.AssetType_ASSET_TYPE_BTC)

switch types.AssetTypeFromDenom(amount.Denom, p) {
case types.AssetType_ASSET_TYPE_BTC:
return k.NewBtcWithdrawRequest(ctx, sender, amount, feeRate, btcVault.Address)
return k.NewBtcWithdrawRequest(ctx, sender, amount, feeRate, btcVault.Address, sequence)

case types.AssetType_ASSET_TYPE_RUNE:
runesVault := types.SelectVaultByAssetType(p.Vaults, types.AssetType_ASSET_TYPE_RUNE)
return k.NewRunesWithdrawRequest(ctx, sender, amount, feeRate, runesVault.Address, btcVault.Address)
return k.NewRunesWithdrawRequest(ctx, sender, amount, feeRate, runesVault.Address, btcVault.Address, sequence)

default:
return nil, types.ErrAssetNotSupported
}
}

// NewBtcWithdrawRequest creates the request for btc withdrawal
func (k Keeper) NewBtcWithdrawRequest(ctx sdk.Context, sender string, amount sdk.Coin, feeRate int64, vault string) (*types.BitcoinWithdrawRequest, error) {
func (k Keeper) NewBtcWithdrawRequest(ctx sdk.Context, sender string, amount sdk.Coin, feeRate int64, vault string, sequence uint64) (*types.BitcoinWithdrawRequest, error) {
utxoIterator := k.GetUTXOIteratorByAddr(ctx, vault)

psbt, selectedUTXOs, _, err := types.BuildPsbt(utxoIterator, sender, amount.Amount.Int64(), feeRate, vault)
psbt, selectedUTXOs, _, err := types.BuildPsbt(utxoIterator, sender, amount.Amount.Int64(), feeRate, vault, sequence)
if err != nil {
return nil, err
}
Expand All @@ -77,7 +79,7 @@ func (k Keeper) NewBtcWithdrawRequest(ctx sdk.Context, sender string, amount sdk

withdrawRequest := &types.BitcoinWithdrawRequest{
Address: sender,
Sequence: k.IncrementRequestSequence(ctx),
Sequence: sequence,
Txid: psbt.UnsignedTx.TxHash().String(),
Psbt: psbtB64,
Status: types.WithdrawStatus_WITHDRAW_STATUS_CREATED,
Expand All @@ -89,7 +91,7 @@ func (k Keeper) NewBtcWithdrawRequest(ctx sdk.Context, sender string, amount sdk
}

// NewRunesWithdrawRequest creates the request for runes withdrawal
func (k Keeper) NewRunesWithdrawRequest(ctx sdk.Context, sender string, amount sdk.Coin, feeRate int64, vault string, btcVault string) (*types.BitcoinWithdrawRequest, error) {
func (k Keeper) NewRunesWithdrawRequest(ctx sdk.Context, sender string, amount sdk.Coin, feeRate int64, vault string, btcVault string, sequence uint64) (*types.BitcoinWithdrawRequest, error) {
var runeId types.RuneId
runeId.FromDenom(amount.Denom)

Expand All @@ -102,7 +104,7 @@ func (k Keeper) NewRunesWithdrawRequest(ctx sdk.Context, sender string, amount s

paymentUTXOIterator := k.GetUTXOIteratorByAddr(ctx, btcVault)

psbt, selectedUTXOs, changeUTXO, runesChangeUTXO, err := types.BuildRunesPsbt(runesUTXOs, paymentUTXOIterator, sender, runeId.ToString(), runeAmount, feeRate, amountDelta, vault, btcVault)
psbt, selectedUTXOs, changeUTXO, runesChangeUTXO, err := types.BuildRunesPsbt(runesUTXOs, paymentUTXOIterator, sender, runeId.ToString(), runeAmount, feeRate, amountDelta, vault, btcVault, sequence)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -134,7 +136,7 @@ func (k Keeper) NewRunesWithdrawRequest(ctx sdk.Context, sender string, amount s

withdrawRequest := &types.BitcoinWithdrawRequest{
Address: sender,
Sequence: k.IncrementRequestSequence(ctx),
Sequence: sequence,
Txid: psbt.UnsignedTx.TxHash().String(),
Psbt: psbtB64,
Status: types.WithdrawStatus_WITHDRAW_STATUS_CREATED,
Expand Down
10 changes: 6 additions & 4 deletions x/btcbridge/types/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (

// BuildPsbt builds a bitcoin psbt from the given params.
// Assume that the utxo script type is witness.
func BuildPsbt(utxoIterator UTXOIterator, recipient string, amount int64, feeRate int64, change string) (*psbt.Packet, []*UTXO, *UTXO, error) {
func BuildPsbt(utxoIterator UTXOIterator, recipient string, amount int64, feeRate int64, change string, sequence uint64) (*psbt.Packet, []*UTXO, *UTXO, error) {
chaincfg := sdk.GetConfig().GetBtcChainCfg()

recipientAddr, err := btcutil.DecodeAddress(recipient, chaincfg)
Expand All @@ -45,6 +45,7 @@ func BuildPsbt(utxoIterator UTXOIterator, recipient string, amount int64, feeRat
}

txOuts := make([]*wire.TxOut, 0)
txOuts = append(txOuts, wire.NewTxOut(0, BuildWithdrawScript(sequence)))
txOuts = append(txOuts, wire.NewTxOut(amount, recipientPkScript))

unsignedTx, selectedUTXOs, changeUTXO, err := BuildUnsignedTransaction([]*UTXO{}, txOuts, utxoIterator, feeRate, changeAddr)
Expand All @@ -67,7 +68,7 @@ func BuildPsbt(utxoIterator UTXOIterator, recipient string, amount int64, feeRat

// BuildRunesPsbt builds a bitcoin psbt for runes edict from the given params.
// Assume that the utxo script type is witness.
func BuildRunesPsbt(utxos []*UTXO, paymentUTXOIterator UTXOIterator, recipient string, runeId string, amount uint128.Uint128, feeRate int64, runesChangeAmount uint128.Uint128, runesChange string, change string) (*psbt.Packet, []*UTXO, *UTXO, *UTXO, error) {
func BuildRunesPsbt(utxos []*UTXO, paymentUTXOIterator UTXOIterator, recipient string, runeId string, amount uint128.Uint128, feeRate int64, runesChangeAmount uint128.Uint128, runesChange string, change string, sequence uint64) (*psbt.Packet, []*UTXO, *UTXO, *UTXO, error) {
chaincfg := sdk.GetConfig().GetBtcChainCfg()

recipientAddr, err := btcutil.DecodeAddress(recipient, chaincfg)
Expand Down Expand Up @@ -96,16 +97,17 @@ func BuildRunesPsbt(utxos []*UTXO, paymentUTXOIterator UTXOIterator, recipient s
}

txOuts := make([]*wire.TxOut, 0)
txOuts = append(txOuts, wire.NewTxOut(0, BuildWithdrawScript(sequence)))

// fill the runes protocol script with empty output script first
txOuts = append(txOuts, wire.NewTxOut(0, []byte{}))

var runesChangeUTXO *UTXO
edictOutputIndex := uint32(1)
edictOutputIndex := uint32(len(txOuts))

if runesChangeAmount.Cmp64(0) > 0 {
// we can guarantee that every runes UTXO only includes a single rune by the deposit policy
runesChangeUTXO = GetRunesChangeUTXO(runeId, runesChangeAmount, runesChange, runesChangePkScript, 1)
runesChangeUTXO = GetRunesChangeUTXO(runeId, runesChangeAmount, runesChange, runesChangePkScript, uint32(len(txOuts)))

// allocate the remaining runes to the first non-OP_RETURN output by default
txOuts = append(txOuts, wire.NewTxOut(RunesOutValue, runesChangePkScript))
Expand Down
28 changes: 14 additions & 14 deletions x/btcbridge/types/policy.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package types

import (
"bytes"
"math/big"

"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"

sdk "github.com/cosmos/cosmos-sdk/types"
)

const (
Expand Down Expand Up @@ -158,18 +157,19 @@ func CheckRunesDepositTransaction(tx *wire.MsgTx, vaults []*Vault) (*Edict, erro
return edicts[0], nil
}

// ParseSequence parses the sequence from the given tx
// make sure the tx is valid
func ParseSequence(tx *wire.MsgTx) (uint64, error) {
scriptBuilder := txscript.MakeScriptTokenizer(0, tx.TxOut[0].PkScript)
// BuildWithdrawScript builds the OP_RETURN script using the withdrawal sequence
// Panic if any error occurred (not expected)
func BuildWithdrawScript(sequence uint64) []byte {
scriptBuilder := txscript.NewScriptBuilder()

if scriptBuilder.Next() && scriptBuilder.Opcode() == txscript.OP_RETURN {
if scriptBuilder.Next() && bytes.Equal(scriptBuilder.Data(), WithdrawIdentifier) {
if scriptBuilder.Next() {
return new(big.Int).SetBytes(scriptBuilder.Data()).Uint64(), nil
}
}
scriptBuilder.AddOp(txscript.OP_RETURN)
scriptBuilder.AddData(WithdrawIdentifier)
scriptBuilder.AddData(sdk.Uint64ToBigEndian(sequence))

script, err := scriptBuilder.Script()
if err != nil {
panic(err)
}

return 0, ErrInvalidSequence
return script
}