Skip to content

Commit

Permalink
implement TxBuilder, BoxSelection and SimpleBoxSelector
Browse files Browse the repository at this point in the history
  • Loading branch information
Alesfatalis committed Apr 7, 2024
1 parent c7de203 commit 56742f2
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 0 deletions.
10 changes: 10 additions & 0 deletions box.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ type BoxAssetsDataList interface {
Get(index uint32) (BoxAssetsData, error)
// Add adds provided BoxAssetsData to the end of the collection
Add(boxAssetsData BoxAssetsData)
pointer() C.ErgoBoxAssetsDataListPtr
}

type boxAssetsDataList struct {
Expand Down Expand Up @@ -515,6 +516,10 @@ func (b *boxAssetsDataList) Add(boxAssetsData BoxAssetsData) {
C.ergo_lib_ergo_box_assets_data_list_add(boxAssetsData.pointer(), b.p)
}

func (b *boxAssetsDataList) pointer() C.ErgoBoxAssetsDataListPtr {
return b.p
}

func finalizeBoxAssetsDataList(b *boxAssetsDataList) {
C.ergo_lib_ergo_box_assets_data_list_delete(b.p)
}
Expand All @@ -527,6 +532,7 @@ type BoxCandidates interface {
Get(index uint32) (BoxCandidate, error)
// Add adds provided BoxCandidate to the end of the collection
Add(boxCandidate BoxCandidate)
pointer() C.ErgoBoxCandidatesPtr
}

type boxCandidates struct {
Expand Down Expand Up @@ -574,6 +580,10 @@ func (b *boxCandidates) Add(boxCandidate BoxCandidate) {
C.ergo_lib_ergo_box_candidates_add(boxCandidate.pointer(), b.p)
}

func (b *boxCandidates) pointer() C.ErgoBoxCandidatesPtr {
return b.p
}

func finalizeBoxCandidates(b *boxCandidates) {
C.ergo_lib_ergo_box_candidates_delete(b.p)
}
Expand Down
100 changes: 100 additions & 0 deletions boxselector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package ergo

/*
#include "ergo.h"
*/
import "C"
import "runtime"

// BoxSelection represents selected boxes with change boxes. Instance are created by SimpleBoxSelector
type BoxSelection interface {
// Boxes returns selected boxes to spend as transaction inputs
Boxes() Boxes
// ChangeBoxes returns selected boxes to use as change
ChangeBoxes() BoxAssetsDataList
pointer() C.BoxSelectionPtr
}

type boxSelection struct {
p C.BoxSelectionPtr
}

func newBoxSelection(b *boxSelection) BoxSelection {
runtime.SetFinalizer(b, finalizeBoxSelection)
return b
}

// NewBoxSelection creates a selection to easily inject custom selection algorithms
func NewBoxSelection(ergoBoxes Boxes, changeErgoBoxes BoxAssetsDataList) BoxSelection {
var p C.BoxSelectionPtr
C.ergo_lib_box_selection_new(ergoBoxes.pointer(), changeErgoBoxes.pointer(), &p)
bs := &boxSelection{p: p}
return newBoxSelection(bs)
}

func (b *boxSelection) Boxes() Boxes {
var p C.ErgoBoxesPtr
C.ergo_lib_box_selection_boxes(b.p, &p)
bo := &boxes{p: p}
return newBoxes(bo)
}

func (b *boxSelection) ChangeBoxes() BoxAssetsDataList {
var p C.ErgoBoxAssetsDataListPtr
C.ergo_lib_box_selection_change(b.p, &p)
ba := &boxAssetsDataList{p: p}
return newBoxAssetsDataList(ba)
}

func (b *boxSelection) pointer() C.BoxSelectionPtr {
return b.p
}

func finalizeBoxSelection(b *boxSelection) {
C.ergo_lib_box_selection_delete(b.p)
}

// SimpleBoxSelector is a naive box selector, collects inputs until target balance is reached
type SimpleBoxSelector interface {
// Select selects inputs to satisfy target balance and tokens
// Parameters:
// inputs - available inputs (returns an error, if empty)
// targetBalance - coins (in nanoERGs) needed
// targetTokens - amount of tokens needed
// Returns: selected inputs and box assets(value+tokens) with change
Select(inputs Boxes, targetBalance BoxValue, targetTokens Tokens) (BoxSelection, error)
}

type simpleBoxSelector struct {
p C.SimpleBoxSelectorPtr
}

func newSimpleBoxSelector(s *simpleBoxSelector) SimpleBoxSelector {
runtime.SetFinalizer(s, finalizeSimpleBoxSelector)
return s
}

// NewSimpleBoxSelector creates a new SimpleBoxSelector
func NewSimpleBoxSelector() SimpleBoxSelector {
var p C.SimpleBoxSelectorPtr
C.ergo_lib_simple_box_selector_new(&p)
s := &simpleBoxSelector{p: p}
return newSimpleBoxSelector(s)
}

func (b *simpleBoxSelector) Select(inputs Boxes, targetBalance BoxValue, targetTokens Tokens) (BoxSelection, error) {
var p C.BoxSelectionPtr
errPtr := C.ergo_lib_simple_box_selector_select(b.p, inputs.pointer(), targetBalance.pointer(), targetTokens.pointer(), &p)
err := newError(errPtr)

if err.isError() {
return nil, err.error()
}

bs := &boxSelection{p: p}
return newBoxSelection(bs), nil
}

func finalizeSimpleBoxSelector(s *simpleBoxSelector) {
C.ergo_lib_simple_box_selector_delete(s.p)
}
5 changes: 5 additions & 0 deletions contextextension.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
type ContextExtension interface {
// Keys returns all keys in the map
Keys() []byte
pointer() C.ContextExtensionPtr
}

type contextExtension struct {
Expand All @@ -37,6 +38,10 @@ func (c *contextExtension) Keys() []byte {
return result
}

func (c *contextExtension) pointer() C.ContextExtensionPtr {
return c.p
}

func finalizeContextExtension(c *contextExtension) {
C.ergo_lib_context_extension_delete(c.p)
}
5 changes: 5 additions & 0 deletions datainput.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type DataInputs interface {
Get(index uint32) (DataInput, error)
// Add adds provided DataInput to the end of the collection
Add(dataInput DataInput)
pointer() C.DataInputsPtr
}

type dataInputs struct {
Expand Down Expand Up @@ -98,6 +99,10 @@ func (d *dataInputs) Add(dataInput DataInput) {
C.ergo_lib_data_inputs_add(dataInput.pointer(), d.p)
}

func (d *dataInputs) pointer() C.DataInputsPtr {
return d.p
}

func finalizeDataInputs(d *dataInputs) {
C.ergo_lib_data_inputs_delete(d.p)
}
143 changes: 143 additions & 0 deletions txbuilder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package ergo

/*
#include "ergo.h"
*/
import "C"
import "runtime"

// TxBuilder builds UnsignedTransaction
type TxBuilder interface {
// SetDataInputs set data inputs for transaction
SetDataInputs(dataInputs DataInputs)
// SetContextExtension sets context extension for a given input
SetContextExtension(boxId BoxId, contextExtension ContextExtension)
// SetTokenBurnPermit permits the burn of the given token amount, i.e. allows this token amount to be omitted in the outputs
SetTokenBurnPermit(tokens Tokens)
// DataInputs returns DataInputs of the TxBuilder
DataInputs() DataInputs
// BoxSelection returns BoxSelection of the TxBuilder
BoxSelection() BoxSelection
// OutputCandidates returns BoxCandidates of the TxBuilder
OutputCandidates() BoxCandidates
// CurrentHeight returns the current height
CurrentHeight() uint32
// FeeAmount returns the fee amount of the TxBuilder
FeeAmount() BoxValue
// ChangeAddress returns the change address of the TxBuilder
ChangeAddress() Address
// Build builds the UnsignedTransaction
Build() (UnsignedTransaction, error)
}

type txBuilder struct {
p C.TxBuilderPtr
}

func newTxBuilder(t *txBuilder) TxBuilder {
runtime.SetFinalizer(t, finalizeTxBuilder)
return t
}

// NewTxBuilder creates a new TxBuilder
// Parameters
// boxSelection - selected input boxes
// outputCandidates - output boxes to be "created" in this transaction
// currentHeight - chain height that will be used in additionally created boxes (change, miner's fee, etc.)
// feeAmount - miner's fee
// changeAddress - change (inputs - outputs) will be sent to this address
func NewTxBuilder(
boxSelection BoxSelection,
outputCandidates BoxCandidates,
currentHeight uint32,
feeAmount BoxValue,
changeAddress Address) TxBuilder {
var p C.TxBuilderPtr
C.ergo_lib_tx_builder_new(
boxSelection.pointer(),
outputCandidates.pointer(),
C.uint(currentHeight),
feeAmount.pointer(),
changeAddress.pointer(),
&p)
tb := &txBuilder{p: p}
return newTxBuilder(tb)
}

func (t *txBuilder) SetDataInputs(dataInputs DataInputs) {
C.ergo_lib_tx_builder_set_data_inputs(t.p, dataInputs.pointer())
}

func (t *txBuilder) SetContextExtension(boxId BoxId, contextExtension ContextExtension) {
C.ergo_lib_tx_builder_set_context_extension(t.p, boxId.pointer(), contextExtension.pointer())
}

func (t *txBuilder) SetTokenBurnPermit(tokens Tokens) {
C.ergo_lib_tx_builder_set_token_burn_permit(t.p, tokens.pointer())
}

func (t *txBuilder) DataInputs() DataInputs {
var p C.DataInputsPtr
C.ergo_lib_tx_builder_data_inputs(t.p, &p)
di := &dataInputs{p: p}
return newDataInputs(di)
}

func (t *txBuilder) BoxSelection() BoxSelection {
var p C.BoxSelectionPtr
C.ergo_lib_tx_builder_box_selection(t.p, &p)
bs := &boxSelection{p: p}
return newBoxSelection(bs)
}

func (t *txBuilder) OutputCandidates() BoxCandidates {
var p C.ErgoBoxCandidatesPtr
C.ergo_lib_tx_builder_output_candidates(t.p, &p)
bc := &boxCandidates{p: p}
return newBoxCandidates(bc)
}

func (t *txBuilder) CurrentHeight() uint32 {
res := C.ergo_lib_tx_builder_current_height(t.p)
return uint32(res)
}

func (t *txBuilder) FeeAmount() BoxValue {
var p C.BoxValuePtr
C.ergo_lib_tx_builder_fee_amount(t.p, &p)
bv := &boxValue{p: p}
return newBoxValue(bv)
}

func (t *txBuilder) ChangeAddress() Address {
var p C.AddressPtr
C.ergo_lib_tx_builder_change_address(t.p, &p)
a := &address{p: p}
return newAddress(a)
}

func (t *txBuilder) Build() (UnsignedTransaction, error) {
var p C.UnsignedTransactionPtr

errPtr := C.ergo_lib_tx_builder_build(t.p, &p)
err := newError(errPtr)

if err.isError() {
return nil, err.error()
}

ut := &unsignedTransaction{p: p}
return newUnsignedTransaction(ut), nil
}

func finalizeTxBuilder(t *txBuilder) {
C.ergo_lib_tx_builder_delete(t.p)
}

// SuggestedTxFee returns the suggested transaction fee (semi-default value used across wallets and dApp as of Oct 2020)
func SuggestedTxFee() BoxValue {
var p C.BoxValuePtr
C.ergo_lib_tx_builder_suggested_tx_fee(&p)
bv := &boxValue{p: p}
return newBoxValue(bv)
}

0 comments on commit 56742f2

Please sign in to comment.