Skip to content

Commit

Permalink
Feature: FromUTXOs (#45)
Browse files Browse the repository at this point in the history
* Added utility AutoFund func to abstract funding flow

* updated doc string

* fixed error in autofund example

* added context to fund iteration func

* renamed funditeration to fund

* renamed funditeratorfunc to fundgetterfunc

* fundgetterfunc now returns an error instead of a bool

* fixed doc string

* fixed doc string

* fixed linter and added test

* fund getter replaced with input getter. added utility input builder func

* removed all mention of funds

* updated example in doc string

* fixed type in error string

* Added utxo data type. changed tx.From signature. updated tests

* fixed deficit error and added tests

* removed println from tests

* fixed doc string typos

* fixed more typos in docs

* fixed tests

* added comment explaining precalculating prevTxID

* added FromUTXOs func. renamed old one to Fund

* fixed doc string

* updated doc string to explain UTXOGetterFunc param
  • Loading branch information
tigh-latte authored Sep 22, 2021
1 parent 6e0ed1a commit 695c030
Show file tree
Hide file tree
Showing 7 changed files with 734 additions and 50 deletions.
3 changes: 2 additions & 1 deletion examples/create_tx/create_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ func main() {
"11b476ad8e0a48fcd40807a111a050af51114877e09283bfa7f3505081a1819d",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac6a0568656c6c6f",
1500)
1500,
)

_ = tx.PayToAddress("1NRoySJ9Lvby6DuE2UQYnyT67AASwNZxGb", 1000)

Expand Down
3 changes: 2 additions & 1 deletion examples/create_tx_with_opreturn/create_tx_with_opreturn.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ func main() {
"b7b0650a7c3a1bd4716369783876348b59f5404784970192cec1996e86950576",
0,
"76a9149cbe9f5e72fa286ac8a38052d1d5337aa363ea7f88ac",
1000)
1000,
)

_ = tx.PayToAddress("1C8bzHM8XFBHZ2ZZVvFy2NSoAZbwCXAicL", 900)

Expand Down
17 changes: 17 additions & 0 deletions tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,4 +476,21 @@ func (tx *Tx) feesPaid(size *TxSize, fees *FeeQuote) (*TxFees, error) {
}
resp.TotalFeePaid = resp.StdFeePaid + resp.DataFeePaid
return resp, nil

}

func (tx *Tx) estimateDeficit(fees *FeeQuote) (uint64, error) {
totalInputSatoshis := tx.TotalInputSatoshis()
totalOutputSatoshis := tx.TotalOutputSatoshis()

expFeesPaid, err := tx.EstimateFeesPaid(fees)
if err != nil {
return 0, err
}

if totalInputSatoshis > totalOutputSatoshis+expFeesPaid.TotalFeePaid {
return 0, nil
}

return totalOutputSatoshis + expFeesPaid.TotalFeePaid - totalInputSatoshis, nil
}
105 changes: 69 additions & 36 deletions tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ func TestTx_CreateTx(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000)
2000000,
)
assert.NoError(t, err)

err = tx.PayToAddress("n2wmGVP89x3DsLNqk3NvctfQy9m9pvt7mk", 1999942)
Expand All @@ -227,7 +228,8 @@ func TestTx_HasDataOutputs(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000)
2000000,
)
assert.NoError(t, err)

err = tx.PayToAddress("n2wmGVP89x3DsLNqk3NvctfQy9m9pvt7mk", 1999942)
Expand Down Expand Up @@ -259,7 +261,8 @@ func TestTx_HasDataOutputs(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000)
2000000,
)
assert.NoError(t, err)

err = tx.PayToAddress("n2wmGVP89x3DsLNqk3NvctfQy9m9pvt7mk", 1999942)
Expand All @@ -280,9 +283,8 @@ func TestTx_HasDataOutputs(t *testing.T) {
func TestTx_ToJson(t *testing.T) {
tx, _ := bt.NewTxFromString("0100000001abad53d72f342dd3f338e5e3346b492440f8ea821f8b8800e318f461cc5ea5a2010000006a4730440220042edc1302c5463e8397120a56b28ea381c8f7f6d9bdc1fee5ebca00c84a76e2022077069bbdb7ed701c4977b7db0aba80d41d4e693112256660bb5d674599e390cf41210294639d6e4249ea381c2e077e95c78fc97afe47a52eb24e1b1595cd3fdd0afdf8ffffffff02000000000000000008006a0548656c6c6f7f030000000000001976a914b85524abf8202a961b847a3bd0bc89d3d4d41cc588ac00000000")

bb, err := json.MarshalIndent(tx, "", "\t")
_, err := json.MarshalIndent(tx, "", "\t")
assert.NoError(t, err)
fmt.Println(string(bb))
}

func TestTx_JSON(t *testing.T) {
Expand All @@ -297,7 +299,8 @@ func TestTx_JSON(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000))
2000000,
))
assert.NoError(t, tx.PayToAddress("n2wmGVP89x3DsLNqk3NvctfQy9m9pvt7mk", 1000))
var wif *WIF
wif, err := DecodeWIF("KznvCNc6Yf4iztSThoMH6oHWzH9EgjfodKxmeuUGPq5DEX5maspS")
Expand All @@ -315,7 +318,8 @@ func TestTx_JSON(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000))
2000000,
))
assert.NoError(t, tx.PayToAddress("n2wmGVP89x3DsLNqk3NvctfQy9m9pvt7mk", 1000))
var wif *WIF
wif, err := DecodeWIF("KznvCNc6Yf4iztSThoMH6oHWzH9EgjfodKxmeuUGPq5DEX5maspS")
Expand Down Expand Up @@ -406,17 +410,20 @@ func TestTx_MarshallJSON(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
10000))
10000,
))
assert.NoError(t, tx.From(
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
2,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
10000))
10000,
))
assert.NoError(t, tx.From(
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
114,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
10000))
10000,
))
assert.NoError(t, tx.PayToAddress("n2wmGVP89x3DsLNqk3NvctfQy9m9pvt7mk", 1000))
var w *wif.WIF
w, err := wif.DecodeWIF("KznvCNc6Yf4iztSThoMH6oHWzH9EgjfodKxmeuUGPq5DEX5maspS")
Expand Down Expand Up @@ -731,17 +738,20 @@ func TestTx_InputIdx(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
1000))
1000,
))
assert.NoError(t, tx.From(
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000))
2000000,
))
assert.NoError(t, tx.From(
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000))
2000000,
))
return tx
}(),
idx: 0,
Expand All @@ -766,17 +776,20 @@ func TestTx_InputIdx(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
1000))
1000,
))
assert.NoError(t, tx.From(
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000))
2000000,
))
assert.NoError(t, tx.From(
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdac4",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
999))
999,
))
return tx
}(),
idx: 2,
Expand All @@ -801,17 +814,20 @@ func TestTx_InputIdx(t *testing.T) {
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
1000))
1000,
))
assert.NoError(t, tx.From(
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
2000000))
2000000,
))
assert.NoError(t, tx.From(
"3c8edde27cb9a9132c22038dac4391496be9db16fd21351565cc1006966fdad5",
0,
"76a914eb0bd5edba389198e73f8efabddfc61666969ff788ac",
999))
999,
))
return tx
}(),
idx: 5,
Expand Down Expand Up @@ -911,8 +927,10 @@ func Test_EstimateIsFeePaidEnough(t *testing.T) {
"unsigned transaction (1 input 1 P2PKHOutput + no change) paying less by 1 satoshi": {
tx: func() *bt.Tx {
tx := bt.NewTx()
assert.NoError(t, tx.From("a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a91455b61be43392125d127f1780fb038437cd67ef9c88ac", 1000))
assert.NoError(t, tx.From(
"a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a91455b61be43392125d127f1780fb038437cd67ef9c88ac", 1000,
))

assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 905))
return tx
Expand All @@ -925,8 +943,10 @@ func Test_EstimateIsFeePaidEnough(t *testing.T) {
}, "unsigned transaction (1 input 1 P2PKHOutput + change) should pay exact amount": {
tx: func() *bt.Tx {
tx := bt.NewTx()
assert.NoError(t, tx.From("a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a91455b61be43392125d127f1780fb038437cd67ef9c88ac", 834709))
assert.NoError(t, tx.From(
"a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a91455b61be43392125d127f1780fb038437cd67ef9c88ac", 834709,
))

assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 256559))
assert.NoError(t, tx.ChangeToAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", bt.NewFeeQuote()))
Expand Down Expand Up @@ -954,8 +974,10 @@ func Test_EstimateIsFeePaidEnough(t *testing.T) {
}, "unsigned transaction (1 input 2 P2PKHOutputs) should pay exact amount": {
tx: func() *bt.Tx {
tx := bt.NewTx()
assert.NoError(t, tx.From("a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a91455b61be43392125d127f1780fb038437cd67ef9c88ac", 834763))
assert.NoError(t, tx.From(
"a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a91455b61be43392125d127f1780fb038437cd67ef9c88ac", 834763,
))

assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 256559))
assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 578091))
Expand All @@ -970,8 +992,10 @@ func Test_EstimateIsFeePaidEnough(t *testing.T) {
}, "unsigned transaction (1 input 2 P2PKHOutputs) should fail paying less by 1 sat": {
tx: func() *bt.Tx {
tx := bt.NewTx()
assert.NoError(t, tx.From("a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a91455b61be43392125d127f1780fb038437cd67ef9c88ac", 834763))
assert.NoError(t, tx.From(
"a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a91455b61be43392125d127f1780fb038437cd67ef9c88ac", 834763,
))

assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 256560))
assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 578091))
Expand All @@ -990,8 +1014,10 @@ func Test_EstimateIsFeePaidEnough(t *testing.T) {
if err != nil {
log.Fatal(err)
}
assert.NoError(t, tx.From("a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a914ff8c9344d4e76c0580420142f697e5fc2ce5c98e88ac", 834709))
assert.NoError(t, tx.From(
"a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a914ff8c9344d4e76c0580420142f697e5fc2ce5c98e88ac", 834709,
))

assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 256559))
assert.NoError(t, tx.ChangeToAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", bt.NewFeeQuote()))
Expand All @@ -1010,8 +1036,10 @@ func Test_EstimateIsFeePaidEnough(t *testing.T) {
if err != nil {
log.Fatal(err)
}
assert.NoError(t, tx.From("a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a914ff8c9344d4e76c0580420142f697e5fc2ce5c98e88ac", 1000))
assert.NoError(t, tx.From(
"a4c76f8a7c05a91dcf5699b95b54e856298e50c1ceca9a8a5569c8532c500c11",
0, "76a914ff8c9344d4e76c0580420142f697e5fc2ce5c98e88ac", 1000,
))

assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 904))
tx.SignAuto(context.Background(), &bt.LocalSigner{PrivateKey: w.PrivKey})
Expand All @@ -1029,8 +1057,10 @@ func Test_EstimateIsFeePaidEnough(t *testing.T) {
log.Fatal(err)
}
tx := bt.NewTx()
assert.NoError(t, tx.From("160f06232540dcb0e9b6db9b36a27f01da1e7e473989df67859742cf098d498f",
0, "76a914ff8c9344d4e76c0580420142f697e5fc2ce5c98e88ac", 1000))
assert.NoError(t, tx.From(
"160f06232540dcb0e9b6db9b36a27f01da1e7e473989df67859742cf098d498f",
0, "76a914ff8c9344d4e76c0580420142f697e5fc2ce5c98e88ac", 1000,
))
assert.NoError(t, tx.AddOpReturnOutput([]byte("hellohello")))
assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 894))
is, err := tx.SignAuto(context.Background(), &bt.LocalSigner{PrivateKey: w.PrivKey})
Expand All @@ -1051,8 +1081,10 @@ func Test_EstimateIsFeePaidEnough(t *testing.T) {
log.Fatal(err)
}
tx := bt.NewTx()
assert.NoError(t, tx.From("160f06232540dcb0e9b6db9b36a27f01da1e7e473989df67859742cf098d498f",
0, "76a914ff8c9344d4e76c0580420142f697e5fc2ce5c98e88ac", 1000))
assert.NoError(t, tx.From(
"160f06232540dcb0e9b6db9b36a27f01da1e7e473989df67859742cf098d498f",
0, "76a914ff8c9344d4e76c0580420142f697e5fc2ce5c98e88ac", 1000,
))
assert.NoError(t, tx.AddOpReturnOutput([]byte("hellohello")))
assert.NoError(t, tx.AddP2PKHOutputFromAddress("mtestD3vRB7AoYWK2n6kLdZmAMLbLhDsLr", 895))
is, err := tx.SignAuto(context.Background(), &bt.LocalSigner{PrivateKey: w.PrivKey})
Expand Down Expand Up @@ -1445,7 +1477,8 @@ func TestTx_EstimateFeesPaidTotal(t *testing.T) {
"07912972e42095fe58daaf09161c5a5da57be47c2054dc2aaa52b30fefa1940b",
0,
"76a914af2590a45ae401651fdbdf59a76ad43d1862534088ac",
2500))
2500,
))
assert.NoError(t, tx.PayToAddress("mxAoAyZFXX6LZBWhoam3vjm6xt9NxPQ15f", 500))
assert.NoError(t, tx.PayToAddress("mxAoAyZFXX6LZBWhoam3vjm6xt9NxPQ15f", 500))
assert.NoError(t, tx.PayToAddress("mxAoAyZFXX6LZBWhoam3vjm6xt9NxPQ15f", 500))
Expand Down
Loading

0 comments on commit 695c030

Please sign in to comment.