From a1f0f73a4090d63120b59ef9a87be6fe8f22bd5c Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Wed, 8 Jan 2025 17:33:12 -0500 Subject: [PATCH 01/40] xdrill for ledgerCloseMeta --- exp/xdrill/ledger.go | 248 ++++++++++++++++++++++++++++++++++++++ exp/xdrill/ledger_test.go | 168 ++++++++++++++++++++++++++ exp/xdrill/utils/utils.go | 92 ++++++++++++++ go.mod | 1 + go.sum | 2 + 5 files changed, 511 insertions(+) create mode 100644 exp/xdrill/ledger.go create mode 100644 exp/xdrill/ledger_test.go create mode 100644 exp/xdrill/utils/utils.go diff --git a/exp/xdrill/ledger.go b/exp/xdrill/ledger.go new file mode 100644 index 0000000000..3095094d85 --- /dev/null +++ b/exp/xdrill/ledger.go @@ -0,0 +1,248 @@ +package xdrill + +import ( + "encoding/base64" + "fmt" + "time" + + "github.com/stellar/go/exp/xdrill/utils" + "github.com/stellar/go/keypair" + "github.com/stellar/go/txnbuild" + "github.com/stellar/go/xdr" +) + +type Ledger struct { + ledger *xdr.LedgerCloseMeta +} + +func (l Ledger) Sequence() uint32 { + return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) +} + +func (l Ledger) ID() int64 { + return utils.NewID(int32(l.Sequence()), 0, 0).ToInt64() +} + +func (l Ledger) Hash() string { + return utils.HashToHexString(l.ledger.LedgerHeaderHistoryEntry().Hash) +} + +func (l Ledger) PreviousHash() string { + return utils.HashToHexString(l.ledger.PreviousLedgerHash()) +} + +func (l Ledger) CloseTime() int64 { + return l.ledger.LedgerCloseTime() +} + +func (l Ledger) ClosedAt() time.Time { + return time.Unix(l.CloseTime(), 0).UTC() +} + +func (l Ledger) TotalCoins() int64 { + return int64(l.ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) +} + +func (l Ledger) FeePool() int64 { + return int64(l.ledger.LedgerHeaderHistoryEntry().Header.FeePool) +} + +func (l Ledger) BaseFee() uint32 { + return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.BaseFee) +} + +func (l Ledger) BaseReserve() uint32 { + return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) +} + +func (l Ledger) MaxTxSetSize() uint32 { + return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) +} + +func (l Ledger) LedgerVersion() uint32 { + return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) +} + +func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { + lcmV1, ok := l.ledger.GetV1() + if !ok { + return 0, false + } + + extV1, ok := lcmV1.Ext.GetV1() + if !ok { + return 0, false + } + + return int64(extV1.SorobanFeeWrite1Kb), true +} + +func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { + lcmV1, ok := l.ledger.GetV1() + if !ok { + return 0, false + } + + return uint64(lcmV1.TotalByteSizeOfBucketList), true +} + +func (l Ledger) NodeID() (string, bool) { + LedgerCloseValueSignature, ok := l.ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() + if !ok { + return "", false + + } + nodeID, ok := utils.GetAddress(LedgerCloseValueSignature.NodeId) + if !ok { + return "", false + } + + return nodeID, true +} + +func (l Ledger) Signature() (string, bool) { + LedgerCloseValueSignature, ok := l.ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() + if !ok { + return "", false + } + + return base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature), true +} + +// Add docstring to larger, more complicated functions +func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) { + var results []xdr.TransactionResultMeta + + transactions := getTransactionSet(l) + switch l.ledger.V { + case 0: + results = l.ledger.V0.TxProcessing + case 1: + results = l.ledger.V1.TxProcessing + } + txCount := len(transactions) + if txCount != len(results) { + return 0, 0, false + } + + for i := 0; i < txCount; i++ { + if results[i].Result.Successful() { + successTxCount++ + } else { + failedTxCount++ + } + } + + return successTxCount, failedTxCount, true +} + +// Add docstring to larger, more complicated functions +func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) { + var results []xdr.TransactionResultMeta + + transactions := getTransactionSet(l) + switch l.ledger.V { + case 0: + results = l.ledger.V0.TxProcessing + case 1: + results = l.ledger.V1.TxProcessing + } + + txCount := len(transactions) + if txCount != len(results) { + return 0, 0, false + } + + for i := 0; i < txCount; i++ { + operations := transactions[i].Operations() + numberOfOps := int32(len(operations)) + txSetOperationCount += numberOfOps + + // for successful transactions, the operation count is based on the operations results slice + if results[i].Result.Successful() { + operationResults, ok := results[i].Result.OperationResults() + if !ok { + return 0, 0, false + } + + operationCount += int32(len(operationResults)) + } + + } + + return operationCount, txSetOperationCount, true +} + +func getTransactionSet(l Ledger) (transactionProcessing []xdr.TransactionEnvelope) { + switch l.ledger.V { + case 0: + return l.ledger.V0.TxSet.Txs + case 1: + switch l.ledger.V1.TxSet.V { + case 0: + return getTransactionPhase(l.ledger.V1.TxSet.V1TxSet.Phases) + default: + panic(fmt.Sprintf("unsupported LedgerCloseMeta.V1.TxSet.V: %d", l.ledger.V1.TxSet.V)) + } + default: + panic(fmt.Sprintf("unsupported LedgerCloseMeta.V: %d", l.ledger.V)) + } +} + +func getTransactionPhase(transactionPhase []xdr.TransactionPhase) (transactionEnvelope []xdr.TransactionEnvelope) { + transactionSlice := []xdr.TransactionEnvelope{} + for _, phase := range transactionPhase { + switch phase.V { + case 0: + components := phase.MustV0Components() + for _, component := range components { + switch component.Type { + case 0: + transactionSlice = append(transactionSlice, component.TxsMaybeDiscountedFee.Txs...) + + default: + panic(fmt.Sprintf("unsupported TxSetComponentType: %d", component.Type)) + } + + } + default: + panic(fmt.Sprintf("unsupported TransactionPhase.V: %d", phase.V)) + } + } + + return transactionSlice +} + +func CreateSampleTx(sequence int64, operationCount int) xdr.TransactionEnvelope { + kp, err := keypair.Random() + PanicOnError(err) + + operations := []txnbuild.Operation{} + operationType := &txnbuild.BumpSequence{ + BumpTo: 0, + } + for i := 0; i < operationCount; i++ { + operations = append(operations, operationType) + } + + sourceAccount := txnbuild.NewSimpleAccount(kp.Address(), int64(0)) + tx, err := txnbuild.NewTransaction( + txnbuild.TransactionParams{ + SourceAccount: &sourceAccount, + Operations: operations, + BaseFee: txnbuild.MinBaseFee, + Preconditions: txnbuild.Preconditions{TimeBounds: txnbuild.NewInfiniteTimeout()}, + }, + ) + PanicOnError(err) + + env := tx.ToXDR() + return env +} + +// PanicOnError is a function that panics if the provided error is not nil +func PanicOnError(err error) { + if err != nil { + panic(err) + } +} diff --git a/exp/xdrill/ledger_test.go b/exp/xdrill/ledger_test.go new file mode 100644 index 0000000000..febdf65d45 --- /dev/null +++ b/exp/xdrill/ledger_test.go @@ -0,0 +1,168 @@ +package xdrill + +import ( + "testing" + "time" + + "github.com/stellar/go/xdr" + "github.com/stretchr/testify/assert" +) + +func TestLedger(t *testing.T) { + ledger := Ledger{ + ledger: ledgerTestInput(), + } + + assert.Equal(t, uint32(30578981), ledger.Sequence()) + assert.Equal(t, int64(131335723340005376), ledger.ID()) + assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", ledger.Hash()) + assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", ledger.PreviousHash()) + assert.Equal(t, int64(1594584547), ledger.CloseTime()) + assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ledger.ClosedAt()) + assert.Equal(t, int64(1054439020873472865), ledger.TotalCoins()) + assert.Equal(t, int64(18153766209161), ledger.FeePool()) + assert.Equal(t, uint32(100), ledger.BaseFee()) + assert.Equal(t, uint32(5000000), ledger.BaseReserve()) + assert.Equal(t, uint32(1000), ledger.MaxTxSetSize()) + assert.Equal(t, uint32(13), ledger.LedgerVersion()) + + var ok bool + + var freeWrite int64 + freeWrite, ok = ledger.SorobanFeeWrite1Kb() + assert.Equal(t, true, ok) + assert.Equal(t, int64(12), freeWrite) + + var bucketSize uint64 + bucketSize, ok = ledger.TotalByteSizeOfBucketList() + assert.Equal(t, true, ok) + assert.Equal(t, uint64(56), bucketSize) + + var nodeID string + nodeID, ok = ledger.NodeID() + assert.Equal(t, true, ok) + assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) + + var signature string + signature, ok = ledger.Signature() + assert.Equal(t, true, ok) + assert.Equal(t, "", signature) + + var success int32 + var failed int32 + success, failed, ok = ledger.TransactionCounts() + assert.Equal(t, true, ok) + assert.Equal(t, int32(1), success) + assert.Equal(t, int32(1), failed) + + success, failed, ok = ledger.OperationCounts() + assert.Equal(t, true, ok) + assert.Equal(t, int32(1), success) + assert.Equal(t, int32(13), failed) + +} + +func ledgerTestInput() (lcm *xdr.LedgerCloseMeta) { + lcm = &xdr.LedgerCloseMeta{ + V: 1, + V1: &xdr.LedgerCloseMetaV1{ + Ext: xdr.LedgerCloseMetaExt{ + V: 1, + V1: &xdr.LedgerCloseMetaExtV1{ + SorobanFeeWrite1Kb: xdr.Int64(12), + }, + }, + LedgerHeader: xdr.LedgerHeaderHistoryEntry{ + Hash: xdr.Hash{0x26, 0x93, 0x2d, 0xc4, 0xd8, 0x4b, 0x5f, 0xab, 0xe9, 0xae, 0x74, 0x4c, 0xb4, 0x3c, 0xe4, 0xc6, 0xda, 0xcc, 0xf9, 0x8c, 0x86, 0xa9, 0x91, 0xb2, 0xa1, 0x49, 0x45, 0xb1, 0xad, 0xac, 0x4d, 0x59}, + Header: xdr.LedgerHeader{ + LedgerSeq: 30578981, + TotalCoins: 1054439020873472865, + FeePool: 18153766209161, + BaseFee: 100, + BaseReserve: 5000000, + MaxTxSetSize: 1000, + LedgerVersion: 13, + PreviousLedgerHash: xdr.Hash{0xf6, 0x3c, 0x15, 0xd0, 0xea, 0xf4, 0x8a, 0xfb, 0xd7, 0x51, 0xa4, 0xc4, 0xdf, 0xad, 0xe5, 0x4a, 0x34, 0x48, 0x5, 0x3c, 0x47, 0xc5, 0xa7, 0x1d, 0x62, 0x26, 0x68, 0xae, 0xc, 0xc2, 0xa2, 0x8}, + ScpValue: xdr.StellarValue{ + Ext: xdr.StellarValueExt{ + V: 1, + LcValueSignature: &xdr.LedgerCloseValueSignature{ + NodeId: xdr.NodeId{ + Type: 0, + Ed25519: &xdr.Uint256{34}, + }, + }, + }, + CloseTime: 1594584547, + }, + }, + }, + TotalByteSizeOfBucketList: xdr.Uint64(56), + TxSet: xdr.GeneralizedTransactionSet{ + V: 0, + V1TxSet: &xdr.TransactionSetV1{ + Phases: []xdr.TransactionPhase{ + { + V: 0, + V0Components: &[]xdr.TxSetComponent{ + { + Type: 0, + TxsMaybeDiscountedFee: &xdr.TxSetComponentTxsMaybeDiscountedFee{ + Txs: []xdr.TransactionEnvelope{ + CreateSampleTx(0, 3), + CreateSampleTx(1, 10), + }, + }, + }, + }, + }, + }, + }, + }, + TxProcessing: []xdr.TransactionResultMeta{ + { + Result: xdr.TransactionResultPair{ + Result: xdr.TransactionResult{ + Result: xdr.TransactionResultResult{ + Code: xdr.TransactionResultCodeTxSuccess, + Results: &[]xdr.OperationResult{ + { + Code: xdr.OperationResultCodeOpInner, + Tr: &xdr.OperationResultTr{ + Type: xdr.OperationTypeCreateAccount, + CreateAccountResult: &xdr.CreateAccountResult{ + Code: 0, + }, + }, + }, + }, + }, + }, + }, + }, + { + Result: xdr.TransactionResultPair{ + Result: xdr.TransactionResult{ + Result: xdr.TransactionResultResult{ + Code: xdr.TransactionResultCodeTxFailed, + Results: &[]xdr.OperationResult{ + { + Code: xdr.OperationResultCodeOpInner, + Tr: &xdr.OperationResultTr{ + Type: xdr.OperationTypeCreateAccount, + CreateAccountResult: &xdr.CreateAccountResult{ + Code: 0, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + return lcm +} diff --git a/exp/xdrill/utils/utils.go b/exp/xdrill/utils/utils.go new file mode 100644 index 0000000000..0bc8d30c3e --- /dev/null +++ b/exp/xdrill/utils/utils.go @@ -0,0 +1,92 @@ +package utils + +import ( + "encoding/hex" + + "github.com/stellar/go/strkey" + "github.com/stellar/go/xdr" +) + +// HashToHexString is utility function that converts and xdr.Hash type to a hex string +func HashToHexString(inputHash xdr.Hash) string { + sliceHash := inputHash[:] + hexString := hex.EncodeToString(sliceHash) + return hexString +} + +type ID struct { + LedgerSequence int32 + TransactionOrder int32 + OperationOrder int32 +} + +const ( + // LedgerMask is the bitmask to mask out ledger sequences in a + // TotalOrderID + LedgerMask = (1 << 32) - 1 + // TransactionMask is the bitmask to mask out transaction indexes + TransactionMask = (1 << 20) - 1 + // OperationMask is the bitmask to mask out operation indexes + OperationMask = (1 << 12) - 1 + + // LedgerShift is the number of bits to shift an int64 to target the + // ledger component + LedgerShift = 32 + // TransactionShift is the number of bits to shift an int64 to + // target the transaction component + TransactionShift = 12 + // OperationShift is the number of bits to shift an int64 to target + // the operation component + OperationShift = 0 +) + +// New creates a new total order ID +func NewID(ledger int32, tx int32, op int32) *ID { + return &ID{ + LedgerSequence: ledger, + TransactionOrder: tx, + OperationOrder: op, + } +} + +// ToInt64 converts this struct back into an int64 +func (id ID) ToInt64() (result int64) { + + if id.LedgerSequence < 0 { + panic("invalid ledger sequence") + } + + if id.TransactionOrder > TransactionMask { + panic("transaction order overflow") + } + + if id.OperationOrder > OperationMask { + panic("operation order overflow") + } + + result = result | ((int64(id.LedgerSequence) & LedgerMask) << LedgerShift) + result = result | ((int64(id.TransactionOrder) & TransactionMask) << TransactionShift) + result = result | ((int64(id.OperationOrder) & OperationMask) << OperationShift) + return +} + +// TODO: This should be moved into the go monorepo xdr functions +// Or nodeID should just be an xdr.AccountId but the error message would be incorrect +func GetAddress(nodeID xdr.NodeId) (string, bool) { + switch nodeID.Type { + case xdr.PublicKeyTypePublicKeyTypeEd25519: + ed, ok := nodeID.GetEd25519() + if !ok { + return "", false + } + raw := make([]byte, 32) + copy(raw, ed[:]) + encodedAddress, err := strkey.Encode(strkey.VersionByteAccountID, raw) + if err != nil { + return "", false + } + return encodedAddress, true + default: + return "", false + } +} diff --git a/go.mod b/go.mod index 341c85543e..6d7e5fab5d 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( require ( github.com/cenkalti/backoff/v4 v4.3.0 + github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fsouza/fake-gcs-server v1.49.2 diff --git a/go.sum b/go.sum index a3c8ce08fa..b071601459 100644 --- a/go.sum +++ b/go.sum @@ -116,6 +116,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/djherbis/fscache v0.10.1 h1:hDv+RGyvD+UDKyRYuLoVNbuRTnf2SrA2K3VyR1br9lk= From f1f97a9ec38c132461a187763c03f24d8f30e0a8 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Wed, 8 Jan 2025 17:41:04 -0500 Subject: [PATCH 02/40] go mod tidy --- go.mod | 1 - go.sum | 2 -- 2 files changed, 3 deletions(-) diff --git a/go.mod b/go.mod index 6d7e5fab5d..341c85543e 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,6 @@ require ( require ( github.com/cenkalti/backoff/v4 v4.3.0 - github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fsouza/fake-gcs-server v1.49.2 diff --git a/go.sum b/go.sum index b071601459..a3c8ce08fa 100644 --- a/go.sum +++ b/go.sum @@ -116,8 +116,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= -github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/djherbis/fscache v0.10.1 h1:hDv+RGyvD+UDKyRYuLoVNbuRTnf2SrA2K3VyR1br9lk= From 36cfcbc9afa0590c7d1a067c5214dfe70496d61c Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 9 Jan 2025 00:55:01 -0500 Subject: [PATCH 03/40] Move util functions from ledger.go to utils.go --- exp/xdrill/ledger.go | 36 ------------------------------------ exp/xdrill/ledger_test.go | 5 +++-- exp/xdrill/utils/utils.go | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/exp/xdrill/ledger.go b/exp/xdrill/ledger.go index 3095094d85..e904009d52 100644 --- a/exp/xdrill/ledger.go +++ b/exp/xdrill/ledger.go @@ -6,8 +6,6 @@ import ( "time" "github.com/stellar/go/exp/xdrill/utils" - "github.com/stellar/go/keypair" - "github.com/stellar/go/txnbuild" "github.com/stellar/go/xdr" ) @@ -212,37 +210,3 @@ func getTransactionPhase(transactionPhase []xdr.TransactionPhase) (transactionEn return transactionSlice } - -func CreateSampleTx(sequence int64, operationCount int) xdr.TransactionEnvelope { - kp, err := keypair.Random() - PanicOnError(err) - - operations := []txnbuild.Operation{} - operationType := &txnbuild.BumpSequence{ - BumpTo: 0, - } - for i := 0; i < operationCount; i++ { - operations = append(operations, operationType) - } - - sourceAccount := txnbuild.NewSimpleAccount(kp.Address(), int64(0)) - tx, err := txnbuild.NewTransaction( - txnbuild.TransactionParams{ - SourceAccount: &sourceAccount, - Operations: operations, - BaseFee: txnbuild.MinBaseFee, - Preconditions: txnbuild.Preconditions{TimeBounds: txnbuild.NewInfiniteTimeout()}, - }, - ) - PanicOnError(err) - - env := tx.ToXDR() - return env -} - -// PanicOnError is a function that panics if the provided error is not nil -func PanicOnError(err error) { - if err != nil { - panic(err) - } -} diff --git a/exp/xdrill/ledger_test.go b/exp/xdrill/ledger_test.go index febdf65d45..7626895abe 100644 --- a/exp/xdrill/ledger_test.go +++ b/exp/xdrill/ledger_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/stellar/go/exp/xdrill/utils" "github.com/stellar/go/xdr" "github.com/stretchr/testify/assert" ) @@ -109,8 +110,8 @@ func ledgerTestInput() (lcm *xdr.LedgerCloseMeta) { Type: 0, TxsMaybeDiscountedFee: &xdr.TxSetComponentTxsMaybeDiscountedFee{ Txs: []xdr.TransactionEnvelope{ - CreateSampleTx(0, 3), - CreateSampleTx(1, 10), + utils.CreateSampleTx(0, 3), + utils.CreateSampleTx(1, 10), }, }, }, diff --git a/exp/xdrill/utils/utils.go b/exp/xdrill/utils/utils.go index 0bc8d30c3e..645967679e 100644 --- a/exp/xdrill/utils/utils.go +++ b/exp/xdrill/utils/utils.go @@ -3,7 +3,9 @@ package utils import ( "encoding/hex" + "github.com/stellar/go/keypair" "github.com/stellar/go/strkey" + "github.com/stellar/go/txnbuild" "github.com/stellar/go/xdr" ) @@ -90,3 +92,37 @@ func GetAddress(nodeID xdr.NodeId) (string, bool) { return "", false } } + +func CreateSampleTx(sequence int64, operationCount int) xdr.TransactionEnvelope { + kp, err := keypair.Random() + PanicOnError(err) + + operations := []txnbuild.Operation{} + operationType := &txnbuild.BumpSequence{ + BumpTo: 0, + } + for i := 0; i < operationCount; i++ { + operations = append(operations, operationType) + } + + sourceAccount := txnbuild.NewSimpleAccount(kp.Address(), int64(0)) + tx, err := txnbuild.NewTransaction( + txnbuild.TransactionParams{ + SourceAccount: &sourceAccount, + Operations: operations, + BaseFee: txnbuild.MinBaseFee, + Preconditions: txnbuild.Preconditions{TimeBounds: txnbuild.NewInfiniteTimeout()}, + }, + ) + PanicOnError(err) + + env := tx.ToXDR() + return env +} + +// PanicOnError is a function that panics if the provided error is not nil +func PanicOnError(err error) { + if err != nil { + panic(err) + } +} From d064296aa0ece071cd1b873d55e346fe97713f4e Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 9 Jan 2025 01:10:10 -0500 Subject: [PATCH 04/40] change some return values to pointers --- exp/xdrill/ledger.go | 48 ++++++++++++++++++--------------------- exp/xdrill/ledger_test.go | 25 ++++++++------------ xdr/ledger_close_meta.go | 12 ++++++++++ 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/exp/xdrill/ledger.go b/exp/xdrill/ledger.go index e904009d52..88eebde1c6 100644 --- a/exp/xdrill/ledger.go +++ b/exp/xdrill/ledger.go @@ -61,50 +61,56 @@ func (l Ledger) LedgerVersion() uint32 { return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) } -func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { +func (l Ledger) SorobanFeeWrite1Kb() *int64 { lcmV1, ok := l.ledger.GetV1() if !ok { - return 0, false + return nil } extV1, ok := lcmV1.Ext.GetV1() if !ok { - return 0, false + return nil } - return int64(extV1.SorobanFeeWrite1Kb), true + result := int64(extV1.SorobanFeeWrite1Kb) + + return &result } -func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { +func (l Ledger) TotalByteSizeOfBucketList() *uint64 { lcmV1, ok := l.ledger.GetV1() if !ok { - return 0, false + return nil } - return uint64(lcmV1.TotalByteSizeOfBucketList), true + result := uint64(lcmV1.TotalByteSizeOfBucketList) + + return &result } -func (l Ledger) NodeID() (string, bool) { +func (l Ledger) NodeID() *string { LedgerCloseValueSignature, ok := l.ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { - return "", false + return nil } nodeID, ok := utils.GetAddress(LedgerCloseValueSignature.NodeId) if !ok { - return "", false + return nil } - return nodeID, true + return &nodeID } -func (l Ledger) Signature() (string, bool) { +func (l Ledger) Signature() *string { LedgerCloseValueSignature, ok := l.ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { - return "", false + return nil } - return base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature), true + result := base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature) + + return &result } // Add docstring to larger, more complicated functions @@ -112,12 +118,7 @@ func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok boo var results []xdr.TransactionResultMeta transactions := getTransactionSet(l) - switch l.ledger.V { - case 0: - results = l.ledger.V0.TxProcessing - case 1: - results = l.ledger.V1.TxProcessing - } + results = l.ledger.TxProcessing() txCount := len(transactions) if txCount != len(results) { return 0, 0, false @@ -139,12 +140,7 @@ func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok var results []xdr.TransactionResultMeta transactions := getTransactionSet(l) - switch l.ledger.V { - case 0: - results = l.ledger.V0.TxProcessing - case 1: - results = l.ledger.V1.TxProcessing - } + results = l.ledger.TxProcessing() txCount := len(transactions) if txCount != len(results) { diff --git a/exp/xdrill/ledger_test.go b/exp/xdrill/ledger_test.go index 7626895abe..b5ca0377a1 100644 --- a/exp/xdrill/ledger_test.go +++ b/exp/xdrill/ledger_test.go @@ -29,25 +29,17 @@ func TestLedger(t *testing.T) { var ok bool - var freeWrite int64 - freeWrite, ok = ledger.SorobanFeeWrite1Kb() - assert.Equal(t, true, ok) - assert.Equal(t, int64(12), freeWrite) + freeWrite := ledger.SorobanFeeWrite1Kb() + assert.Equal(t, int64(12), *freeWrite) - var bucketSize uint64 - bucketSize, ok = ledger.TotalByteSizeOfBucketList() - assert.Equal(t, true, ok) - assert.Equal(t, uint64(56), bucketSize) + bucketSize := ledger.TotalByteSizeOfBucketList() + assert.Equal(t, uint64(56), *bucketSize) - var nodeID string - nodeID, ok = ledger.NodeID() - assert.Equal(t, true, ok) - assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) + nodeID := ledger.NodeID() + assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", *nodeID) - var signature string - signature, ok = ledger.Signature() - assert.Equal(t, true, ok) - assert.Equal(t, "", signature) + signature := ledger.Signature() + assert.Equal(t, "9g==", *signature) var success int32 var failed int32 @@ -92,6 +84,7 @@ func ledgerTestInput() (lcm *xdr.LedgerCloseMeta) { Type: 0, Ed25519: &xdr.Uint256{34}, }, + Signature: []byte{0xf6}, }, }, CloseTime: 1594584547, diff --git a/xdr/ledger_close_meta.go b/xdr/ledger_close_meta.go index 30e80b2e38..bcb4fd9645 100644 --- a/xdr/ledger_close_meta.go +++ b/xdr/ledger_close_meta.go @@ -156,3 +156,15 @@ func (l LedgerCloseMeta) EvictedPersistentLedgerEntries() ([]LedgerEntry, error) panic(fmt.Sprintf("Unsupported LedgerCloseMeta.V: %d", l.V)) } } + +// TxProcessing returns the TransactionResultMeta in this ledger +func (l LedgerCloseMeta) TxProcessing() []TransactionResultMeta { + switch l.V { + case 0: + return l.MustV0().TxProcessing + case 1: + return l.MustV1().TxProcessing + default: + panic(fmt.Sprintf("Unsupported LedgerCloseMeta.V: %d", l.V)) + } +} From 15fe1e574f47cd9a0d42dc7b86094200db12e9ca Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 9 Jan 2025 17:01:08 -0500 Subject: [PATCH 05/40] Change ledger to Ledger --- exp/xdrill/ledger.go | 46 +++++++++++++++++++-------------------- exp/xdrill/ledger_test.go | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/exp/xdrill/ledger.go b/exp/xdrill/ledger.go index 88eebde1c6..d794fce04a 100644 --- a/exp/xdrill/ledger.go +++ b/exp/xdrill/ledger.go @@ -10,11 +10,11 @@ import ( ) type Ledger struct { - ledger *xdr.LedgerCloseMeta + Ledger *xdr.LedgerCloseMeta } func (l Ledger) Sequence() uint32 { - return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) } func (l Ledger) ID() int64 { @@ -22,15 +22,15 @@ func (l Ledger) ID() int64 { } func (l Ledger) Hash() string { - return utils.HashToHexString(l.ledger.LedgerHeaderHistoryEntry().Hash) + return utils.HashToHexString(l.Ledger.LedgerHeaderHistoryEntry().Hash) } func (l Ledger) PreviousHash() string { - return utils.HashToHexString(l.ledger.PreviousLedgerHash()) + return utils.HashToHexString(l.Ledger.PreviousLedgerHash()) } func (l Ledger) CloseTime() int64 { - return l.ledger.LedgerCloseTime() + return l.Ledger.LedgerCloseTime() } func (l Ledger) ClosedAt() time.Time { @@ -38,31 +38,31 @@ func (l Ledger) ClosedAt() time.Time { } func (l Ledger) TotalCoins() int64 { - return int64(l.ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) + return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) } func (l Ledger) FeePool() int64 { - return int64(l.ledger.LedgerHeaderHistoryEntry().Header.FeePool) + return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.FeePool) } func (l Ledger) BaseFee() uint32 { - return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.BaseFee) + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseFee) } func (l Ledger) BaseReserve() uint32 { - return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) } func (l Ledger) MaxTxSetSize() uint32 { - return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) } func (l Ledger) LedgerVersion() uint32 { - return uint32(l.ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) } func (l Ledger) SorobanFeeWrite1Kb() *int64 { - lcmV1, ok := l.ledger.GetV1() + lcmV1, ok := l.Ledger.GetV1() if !ok { return nil } @@ -78,7 +78,7 @@ func (l Ledger) SorobanFeeWrite1Kb() *int64 { } func (l Ledger) TotalByteSizeOfBucketList() *uint64 { - lcmV1, ok := l.ledger.GetV1() + lcmV1, ok := l.Ledger.GetV1() if !ok { return nil } @@ -89,7 +89,7 @@ func (l Ledger) TotalByteSizeOfBucketList() *uint64 { } func (l Ledger) NodeID() *string { - LedgerCloseValueSignature, ok := l.ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() + LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { return nil @@ -103,7 +103,7 @@ func (l Ledger) NodeID() *string { } func (l Ledger) Signature() *string { - LedgerCloseValueSignature, ok := l.ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() + LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { return nil } @@ -118,7 +118,7 @@ func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok boo var results []xdr.TransactionResultMeta transactions := getTransactionSet(l) - results = l.ledger.TxProcessing() + results = l.Ledger.TxProcessing() txCount := len(transactions) if txCount != len(results) { return 0, 0, false @@ -140,7 +140,7 @@ func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok var results []xdr.TransactionResultMeta transactions := getTransactionSet(l) - results = l.ledger.TxProcessing() + results = l.Ledger.TxProcessing() txCount := len(transactions) if txCount != len(results) { @@ -168,18 +168,18 @@ func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok } func getTransactionSet(l Ledger) (transactionProcessing []xdr.TransactionEnvelope) { - switch l.ledger.V { + switch l.Ledger.V { case 0: - return l.ledger.V0.TxSet.Txs + return l.Ledger.V0.TxSet.Txs case 1: - switch l.ledger.V1.TxSet.V { + switch l.Ledger.V1.TxSet.V { case 0: - return getTransactionPhase(l.ledger.V1.TxSet.V1TxSet.Phases) + return getTransactionPhase(l.Ledger.V1.TxSet.V1TxSet.Phases) default: - panic(fmt.Sprintf("unsupported LedgerCloseMeta.V1.TxSet.V: %d", l.ledger.V1.TxSet.V)) + panic(fmt.Sprintf("unsupported LedgerCloseMeta.V1.TxSet.V: %d", l.Ledger.V1.TxSet.V)) } default: - panic(fmt.Sprintf("unsupported LedgerCloseMeta.V: %d", l.ledger.V)) + panic(fmt.Sprintf("unsupported LedgerCloseMeta.V: %d", l.Ledger.V)) } } diff --git a/exp/xdrill/ledger_test.go b/exp/xdrill/ledger_test.go index b5ca0377a1..9c135dd21d 100644 --- a/exp/xdrill/ledger_test.go +++ b/exp/xdrill/ledger_test.go @@ -11,7 +11,7 @@ import ( func TestLedger(t *testing.T) { ledger := Ledger{ - ledger: ledgerTestInput(), + Ledger: ledgerTestInput(), } assert.Equal(t, uint32(30578981), ledger.Sequence()) From d45b0fd0b35943076ea44efa733dd95c65d0a61c Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 9 Jan 2025 19:58:42 -0500 Subject: [PATCH 06/40] Remove Ledger struct; pass lcm as param --- exp/xdrill/{ => ledger}/ledger.go | 92 ++++++++++++-------------- exp/xdrill/{ => ledger}/ledger_test.go | 49 +++++++------- 2 files changed, 67 insertions(+), 74 deletions(-) rename exp/xdrill/{ => ledger}/ledger.go (53%) rename exp/xdrill/{ => ledger}/ledger_test.go (78%) diff --git a/exp/xdrill/ledger.go b/exp/xdrill/ledger/ledger.go similarity index 53% rename from exp/xdrill/ledger.go rename to exp/xdrill/ledger/ledger.go index d794fce04a..b6cb9f9d48 100644 --- a/exp/xdrill/ledger.go +++ b/exp/xdrill/ledger/ledger.go @@ -1,4 +1,4 @@ -package xdrill +package ledger import ( "encoding/base64" @@ -9,60 +9,56 @@ import ( "github.com/stellar/go/xdr" ) -type Ledger struct { - Ledger *xdr.LedgerCloseMeta +func Sequence(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq) } -func (l Ledger) Sequence() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) +func ID(l xdr.LedgerCloseMeta) int64 { + return utils.NewID(int32(l.LedgerSequence()), 0, 0).ToInt64() } -func (l Ledger) ID() int64 { - return utils.NewID(int32(l.Sequence()), 0, 0).ToInt64() +func Hash(l xdr.LedgerCloseMeta) string { + return utils.HashToHexString(l.LedgerHeaderHistoryEntry().Hash) } -func (l Ledger) Hash() string { - return utils.HashToHexString(l.Ledger.LedgerHeaderHistoryEntry().Hash) +func PreviousHash(l xdr.LedgerCloseMeta) string { + return utils.HashToHexString(l.PreviousLedgerHash()) } -func (l Ledger) PreviousHash() string { - return utils.HashToHexString(l.Ledger.PreviousLedgerHash()) +func CloseTime(l xdr.LedgerCloseMeta) int64 { + return l.LedgerCloseTime() } -func (l Ledger) CloseTime() int64 { - return l.Ledger.LedgerCloseTime() +func ClosedAt(l xdr.LedgerCloseMeta) time.Time { + return time.Unix(l.LedgerCloseTime(), 0).UTC() } -func (l Ledger) ClosedAt() time.Time { - return time.Unix(l.CloseTime(), 0).UTC() +func TotalCoins(l xdr.LedgerCloseMeta) int64 { + return int64(l.LedgerHeaderHistoryEntry().Header.TotalCoins) } -func (l Ledger) TotalCoins() int64 { - return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) +func FeePool(l xdr.LedgerCloseMeta) int64 { + return int64(l.LedgerHeaderHistoryEntry().Header.FeePool) } -func (l Ledger) FeePool() int64 { - return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.FeePool) +func BaseFee(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.BaseFee) } -func (l Ledger) BaseFee() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseFee) +func BaseReserve(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.BaseReserve) } -func (l Ledger) BaseReserve() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) +func MaxTxSetSize(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) } -func (l Ledger) MaxTxSetSize() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) +func LedgerVersion(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerVersion) } -func (l Ledger) LedgerVersion() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) -} - -func (l Ledger) SorobanFeeWrite1Kb() *int64 { - lcmV1, ok := l.Ledger.GetV1() +func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) *int64 { + lcmV1, ok := l.GetV1() if !ok { return nil } @@ -77,8 +73,8 @@ func (l Ledger) SorobanFeeWrite1Kb() *int64 { return &result } -func (l Ledger) TotalByteSizeOfBucketList() *uint64 { - lcmV1, ok := l.Ledger.GetV1() +func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) *uint64 { + lcmV1, ok := l.GetV1() if !ok { return nil } @@ -88,8 +84,8 @@ func (l Ledger) TotalByteSizeOfBucketList() *uint64 { return &result } -func (l Ledger) NodeID() *string { - LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +func NodeID(l xdr.LedgerCloseMeta) *string { + LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { return nil @@ -102,8 +98,8 @@ func (l Ledger) NodeID() *string { return &nodeID } -func (l Ledger) Signature() *string { - LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +func Signature(l xdr.LedgerCloseMeta) *string { + LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { return nil } @@ -114,11 +110,11 @@ func (l Ledger) Signature() *string { } // Add docstring to larger, more complicated functions -func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) { +func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32, ok bool) { var results []xdr.TransactionResultMeta transactions := getTransactionSet(l) - results = l.Ledger.TxProcessing() + results = l.TxProcessing() txCount := len(transactions) if txCount != len(results) { return 0, 0, false @@ -136,11 +132,11 @@ func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok boo } // Add docstring to larger, more complicated functions -func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) { +func OperationCounts(l xdr.LedgerCloseMeta) (operationCount, txSetOperationCount int32, ok bool) { var results []xdr.TransactionResultMeta transactions := getTransactionSet(l) - results = l.Ledger.TxProcessing() + results = l.TxProcessing() txCount := len(transactions) if txCount != len(results) { @@ -167,19 +163,19 @@ func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok return operationCount, txSetOperationCount, true } -func getTransactionSet(l Ledger) (transactionProcessing []xdr.TransactionEnvelope) { - switch l.Ledger.V { +func getTransactionSet(l xdr.LedgerCloseMeta) (transactionProcessing []xdr.TransactionEnvelope) { + switch l.V { case 0: - return l.Ledger.V0.TxSet.Txs + return l.V0.TxSet.Txs case 1: - switch l.Ledger.V1.TxSet.V { + switch l.V1.TxSet.V { case 0: - return getTransactionPhase(l.Ledger.V1.TxSet.V1TxSet.Phases) + return getTransactionPhase(l.V1.TxSet.V1TxSet.Phases) default: - panic(fmt.Sprintf("unsupported LedgerCloseMeta.V1.TxSet.V: %d", l.Ledger.V1.TxSet.V)) + panic(fmt.Sprintf("unsupported LedgerCloseMeta.V1.TxSet.V: %d", l.V1.TxSet.V)) } default: - panic(fmt.Sprintf("unsupported LedgerCloseMeta.V: %d", l.Ledger.V)) + panic(fmt.Sprintf("unsupported LedgerCloseMeta.V: %d", l.V)) } } diff --git a/exp/xdrill/ledger_test.go b/exp/xdrill/ledger/ledger_test.go similarity index 78% rename from exp/xdrill/ledger_test.go rename to exp/xdrill/ledger/ledger_test.go index 9c135dd21d..7adac0a4cb 100644 --- a/exp/xdrill/ledger_test.go +++ b/exp/xdrill/ledger/ledger_test.go @@ -1,4 +1,4 @@ -package xdrill +package ledger import ( "testing" @@ -10,53 +10,50 @@ import ( ) func TestLedger(t *testing.T) { - ledger := Ledger{ - Ledger: ledgerTestInput(), - } - - assert.Equal(t, uint32(30578981), ledger.Sequence()) - assert.Equal(t, int64(131335723340005376), ledger.ID()) - assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", ledger.Hash()) - assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", ledger.PreviousHash()) - assert.Equal(t, int64(1594584547), ledger.CloseTime()) - assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ledger.ClosedAt()) - assert.Equal(t, int64(1054439020873472865), ledger.TotalCoins()) - assert.Equal(t, int64(18153766209161), ledger.FeePool()) - assert.Equal(t, uint32(100), ledger.BaseFee()) - assert.Equal(t, uint32(5000000), ledger.BaseReserve()) - assert.Equal(t, uint32(1000), ledger.MaxTxSetSize()) - assert.Equal(t, uint32(13), ledger.LedgerVersion()) + ledger := ledgerTestInput() - var ok bool + assert.Equal(t, uint32(30578981), Sequence(ledger)) + assert.Equal(t, int64(131335723340005376), ID(ledger)) + assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger)) + assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", PreviousHash(ledger)) + assert.Equal(t, int64(1594584547), CloseTime(ledger)) + assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ClosedAt(ledger)) + assert.Equal(t, int64(1054439020873472865), TotalCoins(ledger)) + assert.Equal(t, int64(18153766209161), FeePool(ledger)) + assert.Equal(t, uint32(100), BaseFee(ledger)) + assert.Equal(t, uint32(5000000), BaseReserve(ledger)) + assert.Equal(t, uint32(1000), MaxTxSetSize(ledger)) + assert.Equal(t, uint32(13), LedgerVersion(ledger)) - freeWrite := ledger.SorobanFeeWrite1Kb() + freeWrite := SorobanFeeWrite1Kb(ledger) assert.Equal(t, int64(12), *freeWrite) - bucketSize := ledger.TotalByteSizeOfBucketList() + bucketSize := TotalByteSizeOfBucketList(ledger) assert.Equal(t, uint64(56), *bucketSize) - nodeID := ledger.NodeID() + nodeID := NodeID(ledger) assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", *nodeID) - signature := ledger.Signature() + signature := Signature(ledger) assert.Equal(t, "9g==", *signature) + var ok bool var success int32 var failed int32 - success, failed, ok = ledger.TransactionCounts() + success, failed, ok = TransactionCounts(ledger) assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) - success, failed, ok = ledger.OperationCounts() + success, failed, ok = OperationCounts(ledger) assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(13), failed) } -func ledgerTestInput() (lcm *xdr.LedgerCloseMeta) { - lcm = &xdr.LedgerCloseMeta{ +func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { + lcm = xdr.LedgerCloseMeta{ V: 1, V1: &xdr.LedgerCloseMetaV1{ Ext: xdr.LedgerCloseMetaExt{ From e9de99c352853a1043800b3a9a66fbf45649ee7e Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 9 Jan 2025 16:59:20 -0500 Subject: [PATCH 07/40] xdrill transaction helper functions --- exp/xdrill/transaction/transaction.go | 359 +++++++++++++++++++++ exp/xdrill/transaction/transaction_test.go | 242 ++++++++++++++ exp/xdrill/utils/utils.go | 51 +++ 3 files changed, 652 insertions(+) create mode 100644 exp/xdrill/transaction/transaction.go create mode 100644 exp/xdrill/transaction/transaction_test.go diff --git a/exp/xdrill/transaction/transaction.go b/exp/xdrill/transaction/transaction.go new file mode 100644 index 0000000000..15c1f1a664 --- /dev/null +++ b/exp/xdrill/transaction/transaction.go @@ -0,0 +1,359 @@ +package transaction + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + "strconv" + + "github.com/stellar/go/exp/xdrill/ledger" + "github.com/stellar/go/exp/xdrill/utils" + "github.com/stellar/go/ingest" + "github.com/stellar/go/toid" + "github.com/stellar/go/xdr" +) + +func Hash(t ingest.LedgerTransaction) string { + return utils.HashToHexString(t.Result.TransactionHash) +} + +func Index(t ingest.LedgerTransaction) uint32 { + return uint32(t.Index) +} + +func ID(t ingest.LedgerTransaction, l xdr.LedgerCloseMeta) int64 { + return toid.New(int32(ledger.Sequence(l)), int32(t.Index), 0).ToInt64() +} + +func Account(t ingest.LedgerTransaction) (string, error) { + return utils.GetAccountAddressFromMuxedAccount(t.Envelope.SourceAccount()) +} + +func AccountSequence(t ingest.LedgerTransaction) int64 { + return t.Envelope.SeqNum() +} + +func MaxFee(t ingest.LedgerTransaction) uint32 { + return t.Envelope.Fee() +} + +func FeeCharged(t ingest.LedgerTransaction, l xdr.LedgerCloseMeta) *int64 { + // Any Soroban Fee Bump transactions before P21 will need the below logic to calculate the correct feeCharged + // Protocol 20 contained a bug where the feeCharged was incorrectly calculated but was fixed for + // Protocol 21 with https://github.com/stellar/stellar-core/issues/4188 + var result int64 + _, ok := getSorobanData(t) + if ok { + if ledger.LedgerVersion(l) < 21 && t.Envelope.Type == xdr.EnvelopeTypeEnvelopeTypeTxFeeBump { + resourceFeeRefund := SorobanResourceFeeRefund(t) + inclusionFeeCharged := SorobanInclusionFeeCharged(t) + result = int64(t.Result.Result.FeeCharged) - *resourceFeeRefund + *inclusionFeeCharged + return &result + } + } + + result = int64(t.Result.Result.FeeCharged) + + return &result +} + +func OperationCount(t ingest.LedgerTransaction) uint32 { + return uint32(len(t.Envelope.Operations())) +} + +func Memo(t ingest.LedgerTransaction) string { + memoObject := t.Envelope.Memo() + memoContents := "" + switch xdr.MemoType(memoObject.Type) { + case xdr.MemoTypeMemoText: + memoContents = memoObject.MustText() + case xdr.MemoTypeMemoId: + memoContents = strconv.FormatUint(uint64(memoObject.MustId()), 10) + case xdr.MemoTypeMemoHash: + hash := memoObject.MustHash() + memoContents = base64.StdEncoding.EncodeToString(hash[:]) + case xdr.MemoTypeMemoReturn: + hash := memoObject.MustRetHash() + memoContents = base64.StdEncoding.EncodeToString(hash[:]) + } + + return memoContents +} + +func MemoType(t ingest.LedgerTransaction) string { + memoObject := t.Envelope.Memo() + return memoObject.Type.String() +} + +func TimeBounds(t ingest.LedgerTransaction) (*string, error) { + timeBounds := t.Envelope.TimeBounds() + if timeBounds == nil { + return nil, nil + } + + if timeBounds.MaxTime < timeBounds.MinTime && timeBounds.MaxTime != 0 { + return nil, fmt.Errorf("the max time is earlier than the min time") + } + + var result string + if timeBounds.MaxTime == 0 { + result = fmt.Sprintf("[%d,)", timeBounds.MinTime) + return &result, nil + } + + result = fmt.Sprintf("[%d,%d)", timeBounds.MinTime, timeBounds.MaxTime) + + return &result, nil +} + +func LedgerBounds(t ingest.LedgerTransaction) *string { + ledgerBounds := t.Envelope.LedgerBounds() + if ledgerBounds == nil { + return nil + } + + result := fmt.Sprintf("[%d,%d)", int64(ledgerBounds.MinLedger), int64(ledgerBounds.MaxLedger)) + + return &result +} + +func MinSequence(t ingest.LedgerTransaction) *int64 { + return t.Envelope.MinSeqNum() +} + +func MinSequenceAge(t ingest.LedgerTransaction) *int64 { + minSequenceAge := t.Envelope.MinSeqAge() + if minSequenceAge == nil { + return nil + } + + minSequenceAgeInt64 := int64(*minSequenceAge) + return &minSequenceAgeInt64 +} + +func MinSequenceLedgerGap(t ingest.LedgerTransaction) *int64 { + minSequenceLedgerGap := t.Envelope.MinSeqLedgerGap() + result := int64(*minSequenceLedgerGap) + return &result +} + +func getSorobanData(t ingest.LedgerTransaction) (sorobanData xdr.SorobanTransactionData, ok bool) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + return t.Envelope.V1.Tx.Ext.GetSorobanData() + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + return t.Envelope.FeeBump.Tx.InnerTx.V1.Tx.Ext.GetSorobanData() + } + + return +} + +func SorobanResourceFee(t ingest.LedgerTransaction) *int64 { + sorobanData, ok := getSorobanData(t) + if !ok { + return nil + } + + result := int64(sorobanData.ResourceFee) + return &result +} + +func SorobanResourcesInstructions(t ingest.LedgerTransaction) *uint32 { + sorobanData, ok := getSorobanData(t) + if !ok { + return nil + } + + result := uint32(sorobanData.Resources.Instructions) + return &result +} + +func SorobanResourcesReadBytes(t ingest.LedgerTransaction) *uint32 { + sorobanData, ok := getSorobanData(t) + if !ok { + return nil + } + + result := uint32(sorobanData.Resources.ReadBytes) + return &result +} + +func SorobanResourcesWriteBytes(t ingest.LedgerTransaction) *uint32 { + sorobanData, ok := getSorobanData(t) + if !ok { + return nil + } + + result := uint32(sorobanData.Resources.WriteBytes) + return &result +} + +func InclusionFeeBid(t ingest.LedgerTransaction) *int64 { + resourceFee := SorobanResourceFee(t) + if resourceFee == nil { + return nil + } + + result := int64(t.Envelope.Fee()) - *resourceFee + return &result +} + +func getFeeAccountAddress(t ingest.LedgerTransaction) (feeAccountAddress string) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + sourceAccount := t.Envelope.SourceAccount() + feeAccountAddress = sourceAccount.Address() + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + feeBumpAccount := t.Envelope.FeeBumpAccount() + feeAccountAddress = feeBumpAccount.Address() + } + + return +} + +func SorobanInclusionFeeCharged(t ingest.LedgerTransaction) *int64 { + resourceFee := SorobanResourceFee(t) + if resourceFee == nil { + return nil + } + + accountBalanceStart, accountBalanceEnd := utils.GetAccountBalanceFromLedgerEntryChanges(t.FeeChanges, getFeeAccountAddress(t)) + initialFeeCharged := accountBalanceStart - accountBalanceEnd + result := initialFeeCharged - *resourceFee + + return &result +} + +func SorobanResourceFeeRefund(t ingest.LedgerTransaction) *int64 { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return nil + } + + accountBalanceStart, accountBalanceEnd := utils.GetAccountBalanceFromLedgerEntryChanges(meta.TxChangesAfter, getFeeAccountAddress(t)) + result := accountBalanceEnd - accountBalanceStart + + return &result +} + +func SorobanTotalNonRefundableResourceFeeCharged(t ingest.LedgerTransaction) *int64 { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return nil + } + + switch meta.SorobanMeta.Ext.V { + case 1: + result := int64(meta.SorobanMeta.Ext.V1.TotalNonRefundableResourceFeeCharged) + return &result + } + + return nil +} + +func SorobanTotalRefundableResourceFeeCharged(t ingest.LedgerTransaction) *int64 { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return nil + } + + switch meta.SorobanMeta.Ext.V { + case 1: + result := int64(meta.SorobanMeta.Ext.V1.TotalRefundableResourceFeeCharged) + return &result + } + + return nil +} + +func SorobanRentFeeCharged(t ingest.LedgerTransaction) *int64 { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return nil + } + + switch meta.SorobanMeta.Ext.V { + case 1: + result := int64(meta.SorobanMeta.Ext.V1.RentFeeCharged) + return &result + } + + return nil +} + +func ResultCode(t ingest.LedgerTransaction) string { + return t.Result.Result.Result.Code.String() +} + +func Signers(t ingest.LedgerTransaction) (signers []string) { + if t.Envelope.IsFeeBump() { + signers, _ = utils.GetTxSigners(t.Envelope.FeeBump.Signatures) + return + } + + signers, _ = utils.GetTxSigners(t.Envelope.Signatures()) + + return +} + +func AccountMuxed(t ingest.LedgerTransaction) *string { + sourceAccount := t.Envelope.SourceAccount() + if sourceAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return nil + } + + result := sourceAccount.Address() + + return &result +} + +func FeeAccount(t ingest.LedgerTransaction) *string { + if !t.Envelope.IsFeeBump() { + return nil + } + + feeBumpAccount := t.Envelope.FeeBumpAccount() + feeAccount := feeBumpAccount.ToAccountId() + result := feeAccount.Address() + + return &result +} + +func FeeAccountMuxed(t ingest.LedgerTransaction) *string { + if !t.Envelope.IsFeeBump() { + return nil + } + + feeBumpAccount := t.Envelope.FeeBumpAccount() + if feeBumpAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return nil + } + + result := feeBumpAccount.Address() + + return &result +} + +func InnerTransactionHash(t ingest.LedgerTransaction) *string { + if !t.Envelope.IsFeeBump() { + return nil + } + + innerHash := t.Result.InnerHash() + result := hex.EncodeToString(innerHash[:]) + + return &result +} + +func NewMaxFee(t ingest.LedgerTransaction) *uint32 { + if !t.Envelope.IsFeeBump() { + return nil + } + + newMaxFee := uint32(t.Envelope.FeeBumpFee()) + return &newMaxFee +} + +func Successful(t ingest.LedgerTransaction) bool { + return t.Result.Successful() +} diff --git a/exp/xdrill/transaction/transaction_test.go b/exp/xdrill/transaction/transaction_test.go new file mode 100644 index 0000000000..9dc36aa9ef --- /dev/null +++ b/exp/xdrill/transaction/transaction_test.go @@ -0,0 +1,242 @@ +package transaction + +import ( + "testing" + + "github.com/stellar/go/ingest" + "github.com/stellar/go/xdr" + "github.com/stretchr/testify/assert" +) + +func TestTransaction(t *testing.T) { + ledger := ledgerTestInput() + transaction := transactionTestInput() + + assert.Equal(t, "1122330000000000000000000000000000000000000000000000000000000000", Hash(transaction)) + assert.Equal(t, uint32(1), Index(transaction)) + assert.Equal(t, int64(131335723340009472), ID(transaction, ledger)) + + var err error + var account string + account, err = Account(transaction) + assert.Equal(t, nil, err) + assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", account) + + assert.Equal(t, int64(30578981), AccountSequence(transaction)) + assert.Equal(t, uint32(4560), MaxFee(transaction)) + + feeCharged := FeeCharged(transaction, ledger) + assert.Equal(t, int64(789), *feeCharged) + + assert.Equal(t, uint32(3), OperationCount(transaction)) + assert.Equal(t, "test memo", Memo(transaction)) + assert.Equal(t, "MemoTypeMemoText", MemoType(transaction)) + + var timeBounds *string + timeBounds, err = TimeBounds(transaction) + assert.Equal(t, nil, err) + assert.Equal(t, "[1,10)", *timeBounds) + + ledgerBounds := LedgerBounds(transaction) + assert.Equal(t, "[2,20)", *ledgerBounds) + + minSequence := MinSequence(transaction) + assert.Equal(t, int64(123), *minSequence) + + minSequenceAge := MinSequenceAge(transaction) + assert.Equal(t, int64(456), *minSequenceAge) + + minSequenceLedgerGap := MinSequenceLedgerGap(transaction) + assert.Equal(t, int64(789), *minSequenceLedgerGap) + + sorobanResourceFee := SorobanResourceFee(transaction) + assert.Equal(t, int64(1234), *sorobanResourceFee) + + sorobanResourcesInstructions := SorobanResourcesInstructions(transaction) + assert.Equal(t, uint32(123), *sorobanResourcesInstructions) + + sorobanResourcesReadBytes := SorobanResourcesReadBytes(transaction) + assert.Equal(t, uint32(456), *sorobanResourcesReadBytes) + + sorobanResourcesWriteBytes := SorobanResourcesWriteBytes(transaction) + assert.Equal(t, uint32(789), *sorobanResourcesWriteBytes) + + inclusionFeeBid := InclusionFeeBid(transaction) + assert.Equal(t, int64(3326), *inclusionFeeBid) + + sorobanInclusionFeeCharged := SorobanInclusionFeeCharged(transaction) + assert.Equal(t, int64(-1234), *sorobanInclusionFeeCharged) + + sorobanResourceFeeRefund := SorobanResourceFeeRefund(transaction) + assert.Equal(t, int64(0), *sorobanResourceFeeRefund) + + sorobanTotalNonRefundableResourceFeeCharged := SorobanTotalNonRefundableResourceFeeCharged(transaction) + assert.Equal(t, int64(321), *sorobanTotalNonRefundableResourceFeeCharged) + + sorobanTotalRefundableResourceFeeCharged := SorobanTotalRefundableResourceFeeCharged(transaction) + assert.Equal(t, int64(123), *sorobanTotalRefundableResourceFeeCharged) + + sorobanRentFeeCharged := SorobanRentFeeCharged(transaction) + assert.Equal(t, int64(456), *sorobanRentFeeCharged) + + assert.Equal(t, "TransactionResultCodeTxSuccess", ResultCode(transaction)) + assert.Equal(t, []string{"GAISFR7R"}, Signers(transaction)) + + accountMuxed := AccountMuxed(transaction) + assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", *accountMuxed) + + feeAccount := FeeAccount(transaction) + assert.Equal(t, (*string)(nil), feeAccount) + + feeAccountMuxed := FeeAccountMuxed(transaction) + assert.Equal(t, (*string)(nil), feeAccountMuxed) + + innerTransactionHash := InnerTransactionHash(transaction) + assert.Equal(t, (*string)(nil), innerTransactionHash) + + assert.Equal(t, (*uint32)(nil), NewMaxFee(transaction)) + assert.Equal(t, true, Successful(transaction)) +} + +func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { + lcm = xdr.LedgerCloseMeta{ + V: 1, + V1: &xdr.LedgerCloseMetaV1{ + LedgerHeader: xdr.LedgerHeaderHistoryEntry{ + Header: xdr.LedgerHeader{ + LedgerSeq: 30578981, + LedgerVersion: 22, + }, + }, + }, + } + + return lcm +} + +func transactionTestInput() ingest.LedgerTransaction { + ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) + muxedAccount := xdr.MuxedAccount{ + Type: 256, + Ed25519: &ed25519, + Med25519: &xdr.MuxedAccountMed25519{ + Id: xdr.Uint64(123), + Ed25519: ed25519, + }, + } + + memoText := "test memo" + minSeqNum := xdr.SequenceNumber(123) + + transaction := ingest.LedgerTransaction{ + Index: 1, + Envelope: xdr.TransactionEnvelope{ + Type: xdr.EnvelopeTypeEnvelopeTypeTx, + V1: &xdr.TransactionV1Envelope{ + Signatures: []xdr.DecoratedSignature{ + { + Signature: []byte{0x11, 0x22}, + }, + }, + Tx: xdr.Transaction{ + SourceAccount: muxedAccount, + SeqNum: xdr.SequenceNumber(30578981), + Fee: xdr.Uint32(4560), + Operations: []xdr.Operation{ + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + }, + Memo: xdr.Memo{ + Type: xdr.MemoTypeMemoText, + Text: &memoText, + }, + Cond: xdr.Preconditions{ + Type: 2, + V2: &xdr.PreconditionsV2{ + TimeBounds: &xdr.TimeBounds{ + MinTime: xdr.TimePoint(1), + MaxTime: xdr.TimePoint(10), + }, + LedgerBounds: &xdr.LedgerBounds{ + MinLedger: 2, + MaxLedger: 20, + }, + MinSeqNum: &minSeqNum, + MinSeqAge: 456, + MinSeqLedgerGap: 789, + }, + }, + Ext: xdr.TransactionExt{ + V: 1, + SorobanData: &xdr.SorobanTransactionData{ + Resources: xdr.SorobanResources{ + Instructions: 123, + ReadBytes: 456, + WriteBytes: 789, + }, + ResourceFee: 1234, + }, + }, + }, + }, + }, + Result: xdr.TransactionResultPair{ + TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, + Result: xdr.TransactionResult{ + FeeCharged: xdr.Int64(789), + Result: xdr.TransactionResultResult{ + Code: 0, + }, + }, + }, + FeeChanges: xdr.LedgerEntryChanges{ + { + Type: xdr.LedgerEntryChangeTypeLedgerEntryState, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: xdr.LedgerEntryTypeAccount, + Account: &xdr.AccountEntry{ + AccountId: xdr.AccountId{ + Type: 0, + Ed25519: &ed25519, + }, + Balance: 1000, + }, + }, + }, + }, + {}, + }, + UnsafeMeta: xdr.TransactionMeta{ + V: 3, + V3: &xdr.TransactionMetaV3{ + TxChangesAfter: xdr.LedgerEntryChanges{}, + SorobanMeta: &xdr.SorobanTransactionMeta{ + Ext: xdr.SorobanTransactionMetaExt{ + V: 1, + V1: &xdr.SorobanTransactionMetaExtV1{ + TotalNonRefundableResourceFeeCharged: 321, + TotalRefundableResourceFeeCharged: 123, + RentFeeCharged: 456, + }, + }, + }, + }, + }, + LedgerVersion: 22, + Ledger: xdr.LedgerCloseMeta{}, + Hash: xdr.Hash{}, + } + + return transaction +} diff --git a/exp/xdrill/utils/utils.go b/exp/xdrill/utils/utils.go index 645967679e..b5fc44329e 100644 --- a/exp/xdrill/utils/utils.go +++ b/exp/xdrill/utils/utils.go @@ -126,3 +126,54 @@ func PanicOnError(err error) { panic(err) } } + +// GetAccountAddressFromMuxedAccount takes in a muxed account and returns the address of the account +func GetAccountAddressFromMuxedAccount(account xdr.MuxedAccount) (string, error) { + providedID := account.ToAccountId() + pointerToID := &providedID + return pointerToID.GetAddress() +} + +func GetAccountBalanceFromLedgerEntryChanges(changes xdr.LedgerEntryChanges, sourceAccountAddress string) (int64, int64) { + var accountBalanceStart int64 + var accountBalanceEnd int64 + + for _, change := range changes { + switch change.Type { + case xdr.LedgerEntryChangeTypeLedgerEntryUpdated: + accountEntry, ok := change.Updated.Data.GetAccount() + if !ok { + continue + } + + if accountEntry.AccountId.Address() == sourceAccountAddress { + accountBalanceEnd = int64(accountEntry.Balance) + } + case xdr.LedgerEntryChangeTypeLedgerEntryState: + accountEntry, ok := change.State.Data.GetAccount() + if !ok { + continue + } + + if accountEntry.AccountId.Address() == sourceAccountAddress { + accountBalanceStart = int64(accountEntry.Balance) + } + } + } + + return accountBalanceStart, accountBalanceEnd +} + +func GetTxSigners(xdrSignatures []xdr.DecoratedSignature) ([]string, error) { + signers := make([]string, len(xdrSignatures)) + + for i, sig := range xdrSignatures { + signerAccount, err := strkey.Encode(strkey.VersionByteAccountID, sig.Signature) + if err != nil { + return nil, err + } + signers[i] = signerAccount + } + + return signers, nil +} From 40d505759d70f72b5937f53447da774105c3bff6 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 14:42:51 -0700 Subject: [PATCH 08/40] Move xdrill ledger functions to ingest as subpackage --- exp/xdrill/ledger/ledger.go | 204 ------------------- exp/xdrill/utils/utils.go | 128 ------------ ingest/ledger/ledger.go | 150 ++++++++++++++ {exp/xdrill => ingest}/ledger/ledger_test.go | 99 ++++++--- xdr/node_id.go | 22 ++ 5 files changed, 244 insertions(+), 359 deletions(-) delete mode 100644 exp/xdrill/ledger/ledger.go delete mode 100644 exp/xdrill/utils/utils.go create mode 100644 ingest/ledger/ledger.go rename {exp/xdrill => ingest}/ledger/ledger_test.go (61%) create mode 100644 xdr/node_id.go diff --git a/exp/xdrill/ledger/ledger.go b/exp/xdrill/ledger/ledger.go deleted file mode 100644 index b6cb9f9d48..0000000000 --- a/exp/xdrill/ledger/ledger.go +++ /dev/null @@ -1,204 +0,0 @@ -package ledger - -import ( - "encoding/base64" - "fmt" - "time" - - "github.com/stellar/go/exp/xdrill/utils" - "github.com/stellar/go/xdr" -) - -func Sequence(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq) -} - -func ID(l xdr.LedgerCloseMeta) int64 { - return utils.NewID(int32(l.LedgerSequence()), 0, 0).ToInt64() -} - -func Hash(l xdr.LedgerCloseMeta) string { - return utils.HashToHexString(l.LedgerHeaderHistoryEntry().Hash) -} - -func PreviousHash(l xdr.LedgerCloseMeta) string { - return utils.HashToHexString(l.PreviousLedgerHash()) -} - -func CloseTime(l xdr.LedgerCloseMeta) int64 { - return l.LedgerCloseTime() -} - -func ClosedAt(l xdr.LedgerCloseMeta) time.Time { - return time.Unix(l.LedgerCloseTime(), 0).UTC() -} - -func TotalCoins(l xdr.LedgerCloseMeta) int64 { - return int64(l.LedgerHeaderHistoryEntry().Header.TotalCoins) -} - -func FeePool(l xdr.LedgerCloseMeta) int64 { - return int64(l.LedgerHeaderHistoryEntry().Header.FeePool) -} - -func BaseFee(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.BaseFee) -} - -func BaseReserve(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.BaseReserve) -} - -func MaxTxSetSize(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) -} - -func LedgerVersion(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerVersion) -} - -func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) *int64 { - lcmV1, ok := l.GetV1() - if !ok { - return nil - } - - extV1, ok := lcmV1.Ext.GetV1() - if !ok { - return nil - } - - result := int64(extV1.SorobanFeeWrite1Kb) - - return &result -} - -func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) *uint64 { - lcmV1, ok := l.GetV1() - if !ok { - return nil - } - - result := uint64(lcmV1.TotalByteSizeOfBucketList) - - return &result -} - -func NodeID(l xdr.LedgerCloseMeta) *string { - LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() - if !ok { - return nil - - } - nodeID, ok := utils.GetAddress(LedgerCloseValueSignature.NodeId) - if !ok { - return nil - } - - return &nodeID -} - -func Signature(l xdr.LedgerCloseMeta) *string { - LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() - if !ok { - return nil - } - - result := base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature) - - return &result -} - -// Add docstring to larger, more complicated functions -func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32, ok bool) { - var results []xdr.TransactionResultMeta - - transactions := getTransactionSet(l) - results = l.TxProcessing() - txCount := len(transactions) - if txCount != len(results) { - return 0, 0, false - } - - for i := 0; i < txCount; i++ { - if results[i].Result.Successful() { - successTxCount++ - } else { - failedTxCount++ - } - } - - return successTxCount, failedTxCount, true -} - -// Add docstring to larger, more complicated functions -func OperationCounts(l xdr.LedgerCloseMeta) (operationCount, txSetOperationCount int32, ok bool) { - var results []xdr.TransactionResultMeta - - transactions := getTransactionSet(l) - results = l.TxProcessing() - - txCount := len(transactions) - if txCount != len(results) { - return 0, 0, false - } - - for i := 0; i < txCount; i++ { - operations := transactions[i].Operations() - numberOfOps := int32(len(operations)) - txSetOperationCount += numberOfOps - - // for successful transactions, the operation count is based on the operations results slice - if results[i].Result.Successful() { - operationResults, ok := results[i].Result.OperationResults() - if !ok { - return 0, 0, false - } - - operationCount += int32(len(operationResults)) - } - - } - - return operationCount, txSetOperationCount, true -} - -func getTransactionSet(l xdr.LedgerCloseMeta) (transactionProcessing []xdr.TransactionEnvelope) { - switch l.V { - case 0: - return l.V0.TxSet.Txs - case 1: - switch l.V1.TxSet.V { - case 0: - return getTransactionPhase(l.V1.TxSet.V1TxSet.Phases) - default: - panic(fmt.Sprintf("unsupported LedgerCloseMeta.V1.TxSet.V: %d", l.V1.TxSet.V)) - } - default: - panic(fmt.Sprintf("unsupported LedgerCloseMeta.V: %d", l.V)) - } -} - -func getTransactionPhase(transactionPhase []xdr.TransactionPhase) (transactionEnvelope []xdr.TransactionEnvelope) { - transactionSlice := []xdr.TransactionEnvelope{} - for _, phase := range transactionPhase { - switch phase.V { - case 0: - components := phase.MustV0Components() - for _, component := range components { - switch component.Type { - case 0: - transactionSlice = append(transactionSlice, component.TxsMaybeDiscountedFee.Txs...) - - default: - panic(fmt.Sprintf("unsupported TxSetComponentType: %d", component.Type)) - } - - } - default: - panic(fmt.Sprintf("unsupported TransactionPhase.V: %d", phase.V)) - } - } - - return transactionSlice -} diff --git a/exp/xdrill/utils/utils.go b/exp/xdrill/utils/utils.go deleted file mode 100644 index 645967679e..0000000000 --- a/exp/xdrill/utils/utils.go +++ /dev/null @@ -1,128 +0,0 @@ -package utils - -import ( - "encoding/hex" - - "github.com/stellar/go/keypair" - "github.com/stellar/go/strkey" - "github.com/stellar/go/txnbuild" - "github.com/stellar/go/xdr" -) - -// HashToHexString is utility function that converts and xdr.Hash type to a hex string -func HashToHexString(inputHash xdr.Hash) string { - sliceHash := inputHash[:] - hexString := hex.EncodeToString(sliceHash) - return hexString -} - -type ID struct { - LedgerSequence int32 - TransactionOrder int32 - OperationOrder int32 -} - -const ( - // LedgerMask is the bitmask to mask out ledger sequences in a - // TotalOrderID - LedgerMask = (1 << 32) - 1 - // TransactionMask is the bitmask to mask out transaction indexes - TransactionMask = (1 << 20) - 1 - // OperationMask is the bitmask to mask out operation indexes - OperationMask = (1 << 12) - 1 - - // LedgerShift is the number of bits to shift an int64 to target the - // ledger component - LedgerShift = 32 - // TransactionShift is the number of bits to shift an int64 to - // target the transaction component - TransactionShift = 12 - // OperationShift is the number of bits to shift an int64 to target - // the operation component - OperationShift = 0 -) - -// New creates a new total order ID -func NewID(ledger int32, tx int32, op int32) *ID { - return &ID{ - LedgerSequence: ledger, - TransactionOrder: tx, - OperationOrder: op, - } -} - -// ToInt64 converts this struct back into an int64 -func (id ID) ToInt64() (result int64) { - - if id.LedgerSequence < 0 { - panic("invalid ledger sequence") - } - - if id.TransactionOrder > TransactionMask { - panic("transaction order overflow") - } - - if id.OperationOrder > OperationMask { - panic("operation order overflow") - } - - result = result | ((int64(id.LedgerSequence) & LedgerMask) << LedgerShift) - result = result | ((int64(id.TransactionOrder) & TransactionMask) << TransactionShift) - result = result | ((int64(id.OperationOrder) & OperationMask) << OperationShift) - return -} - -// TODO: This should be moved into the go monorepo xdr functions -// Or nodeID should just be an xdr.AccountId but the error message would be incorrect -func GetAddress(nodeID xdr.NodeId) (string, bool) { - switch nodeID.Type { - case xdr.PublicKeyTypePublicKeyTypeEd25519: - ed, ok := nodeID.GetEd25519() - if !ok { - return "", false - } - raw := make([]byte, 32) - copy(raw, ed[:]) - encodedAddress, err := strkey.Encode(strkey.VersionByteAccountID, raw) - if err != nil { - return "", false - } - return encodedAddress, true - default: - return "", false - } -} - -func CreateSampleTx(sequence int64, operationCount int) xdr.TransactionEnvelope { - kp, err := keypair.Random() - PanicOnError(err) - - operations := []txnbuild.Operation{} - operationType := &txnbuild.BumpSequence{ - BumpTo: 0, - } - for i := 0; i < operationCount; i++ { - operations = append(operations, operationType) - } - - sourceAccount := txnbuild.NewSimpleAccount(kp.Address(), int64(0)) - tx, err := txnbuild.NewTransaction( - txnbuild.TransactionParams{ - SourceAccount: &sourceAccount, - Operations: operations, - BaseFee: txnbuild.MinBaseFee, - Preconditions: txnbuild.Preconditions{TimeBounds: txnbuild.NewInfiniteTimeout()}, - }, - ) - PanicOnError(err) - - env := tx.ToXDR() - return env -} - -// PanicOnError is a function that panics if the provided error is not nil -func PanicOnError(err error) { - if err != nil { - panic(err) - } -} diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go new file mode 100644 index 0000000000..fb58dbd9a5 --- /dev/null +++ b/ingest/ledger/ledger.go @@ -0,0 +1,150 @@ +package ledger + +import ( + "encoding/base64" + "time" + + "github.com/stellar/go/toid" + "github.com/stellar/go/xdr" +) + +type Ledger struct { + Ledger xdr.LedgerCloseMeta +} + +func (l Ledger) Sequence() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) +} + +func (l Ledger) ID() int64 { + return toid.New(int32(l.Ledger.LedgerSequence()), 0, 0).ToInt64() +} + +func (l Ledger) Hash() string { + return l.Ledger.LedgerHeaderHistoryEntry().Hash.HexString() +} + +func (l Ledger) PreviousHash() string { + return l.Ledger.PreviousLedgerHash().HexString() +} + +func (l Ledger) CloseTime() int64 { + return l.Ledger.LedgerCloseTime() +} + +func (l Ledger) ClosedAt() time.Time { + return time.Unix(l.Ledger.LedgerCloseTime(), 0).UTC() +} + +func (l Ledger) TotalCoins() int64 { + return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) +} + +func (l Ledger) FeePool() int64 { + return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.FeePool) +} + +func (l Ledger) BaseFee() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseFee) +} + +func (l Ledger) BaseReserve() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) +} + +func (l Ledger) MaxTxSetSize() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) +} + +func (l Ledger) LedgerVersion() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) +} + +func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { + lcmV1, ok := l.Ledger.GetV1() + if !ok { + return 0, false + } + + extV1, ok := lcmV1.Ext.GetV1() + if !ok { + return 0, false + } + + return int64(extV1.SorobanFeeWrite1Kb), true +} + +func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { + lcmV1, ok := l.Ledger.GetV1() + if !ok { + return 0, false + } + + return uint64(lcmV1.TotalByteSizeOfBucketList), true +} + +func (l Ledger) NodeID() (string, bool) { + LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() + if !ok { + return "", false + + } + return LedgerCloseValueSignature.NodeId.GetAddress() +} + +func (l Ledger) Signature() (string, bool) { + LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() + if !ok { + return "", false + } + + return base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature), true +} + +// Add docstring to larger, more complicated functions +func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) { + var results []xdr.TransactionResultMeta + + transactions := l.Ledger.TransactionEnvelopes() + results = l.Ledger.TxProcessing() + txCount := len(transactions) + if txCount != len(results) { + return 0, 0, false + } + + for i := 0; i < txCount; i++ { + if results[i].Result.Successful() { + successTxCount++ + } else { + failedTxCount++ + } + } + + return successTxCount, failedTxCount, true +} + +// Add docstring to larger, more complicated functions +func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) { + var results []xdr.TransactionResultMeta + + transactions := l.Ledger.TransactionEnvelopes() + results = l.Ledger.TxProcessing() + + for i, result := range results { + operations := transactions[i].Operations() + numberOfOps := int32(len(operations)) + txSetOperationCount += numberOfOps + + // for successful transactions, the operation count is based on the operations results slice + if result.Result.Successful() { + operationResults, ok := result.Result.OperationResults() + if !ok { + return 0, 0, false + } + + operationCount += int32(len(operationResults)) + } + } + + return operationCount, txSetOperationCount, true +} diff --git a/exp/xdrill/ledger/ledger_test.go b/ingest/ledger/ledger_test.go similarity index 61% rename from exp/xdrill/ledger/ledger_test.go rename to ingest/ledger/ledger_test.go index 7adac0a4cb..3c4b388ec8 100644 --- a/exp/xdrill/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -4,48 +4,59 @@ import ( "testing" "time" - "github.com/stellar/go/exp/xdrill/utils" + "github.com/stellar/go/keypair" + "github.com/stellar/go/txnbuild" "github.com/stellar/go/xdr" "github.com/stretchr/testify/assert" ) func TestLedger(t *testing.T) { - ledger := ledgerTestInput() + ledger := Ledger{ + Ledger: ledgerTestInput(), + } - assert.Equal(t, uint32(30578981), Sequence(ledger)) - assert.Equal(t, int64(131335723340005376), ID(ledger)) - assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger)) - assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", PreviousHash(ledger)) - assert.Equal(t, int64(1594584547), CloseTime(ledger)) - assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ClosedAt(ledger)) - assert.Equal(t, int64(1054439020873472865), TotalCoins(ledger)) - assert.Equal(t, int64(18153766209161), FeePool(ledger)) - assert.Equal(t, uint32(100), BaseFee(ledger)) - assert.Equal(t, uint32(5000000), BaseReserve(ledger)) - assert.Equal(t, uint32(1000), MaxTxSetSize(ledger)) - assert.Equal(t, uint32(13), LedgerVersion(ledger)) + assert.Equal(t, uint32(30578981), ledger.Sequence()) + assert.Equal(t, int64(131335723340005376), ledger.ID()) + assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", ledger.Hash()) + assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", ledger.PreviousHash()) + assert.Equal(t, int64(1594584547), ledger.CloseTime()) + assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ledger.ClosedAt()) + assert.Equal(t, int64(1054439020873472865), ledger.TotalCoins()) + assert.Equal(t, int64(18153766209161), ledger.FeePool()) + assert.Equal(t, uint32(100), ledger.BaseFee()) + assert.Equal(t, uint32(5000000), ledger.BaseReserve()) + assert.Equal(t, uint32(1000), ledger.MaxTxSetSize()) + assert.Equal(t, uint32(13), ledger.LedgerVersion()) - freeWrite := SorobanFeeWrite1Kb(ledger) - assert.Equal(t, int64(12), *freeWrite) + var ok bool + var freeWrite int64 + freeWrite, ok = ledger.SorobanFeeWrite1Kb() + assert.Equal(t, true, ok) + assert.Equal(t, int64(12), freeWrite) - bucketSize := TotalByteSizeOfBucketList(ledger) - assert.Equal(t, uint64(56), *bucketSize) + var bucketSize uint64 + bucketSize, ok = ledger.TotalByteSizeOfBucketList() + assert.Equal(t, true, ok) + assert.Equal(t, uint64(56), bucketSize) - nodeID := NodeID(ledger) - assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", *nodeID) + var nodeID string + nodeID, ok = ledger.NodeID() + assert.Equal(t, true, ok) + assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) - signature := Signature(ledger) - assert.Equal(t, "9g==", *signature) + var signature string + signature, ok = ledger.Signature() + assert.Equal(t, true, ok) + assert.Equal(t, "9g==", signature) - var ok bool var success int32 var failed int32 - success, failed, ok = TransactionCounts(ledger) + success, failed, ok = ledger.TransactionCounts() assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) - success, failed, ok = OperationCounts(ledger) + success, failed, ok = ledger.OperationCounts() assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(13), failed) @@ -100,8 +111,8 @@ func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { Type: 0, TxsMaybeDiscountedFee: &xdr.TxSetComponentTxsMaybeDiscountedFee{ Txs: []xdr.TransactionEnvelope{ - utils.CreateSampleTx(0, 3), - utils.CreateSampleTx(1, 10), + createSampleTx(3), + createSampleTx(10), }, }, }, @@ -157,3 +168,37 @@ func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { return lcm } + +func createSampleTx(operationCount int) xdr.TransactionEnvelope { + kp, err := keypair.Random() + panicOnError(err) + + operations := []txnbuild.Operation{} + operationType := &txnbuild.BumpSequence{ + BumpTo: 0, + } + for i := 0; i < operationCount; i++ { + operations = append(operations, operationType) + } + + sourceAccount := txnbuild.NewSimpleAccount(kp.Address(), int64(0)) + tx, err := txnbuild.NewTransaction( + txnbuild.TransactionParams{ + SourceAccount: &sourceAccount, + Operations: operations, + BaseFee: txnbuild.MinBaseFee, + Preconditions: txnbuild.Preconditions{TimeBounds: txnbuild.NewInfiniteTimeout()}, + }, + ) + panicOnError(err) + + env := tx.ToXDR() + return env +} + +// PanicOnError is a function that panics if the provided error is not nil +func panicOnError(err error) { + if err != nil { + panic(err) + } +} diff --git a/xdr/node_id.go b/xdr/node_id.go new file mode 100644 index 0000000000..b3f9c77eb8 --- /dev/null +++ b/xdr/node_id.go @@ -0,0 +1,22 @@ +package xdr + +import "github.com/stellar/go/strkey" + +func (n NodeId) GetAddress() (string, bool) { + switch n.Type { + case PublicKeyTypePublicKeyTypeEd25519: + ed, ok := n.GetEd25519() + if !ok { + return "", false + } + raw := make([]byte, 32) + copy(raw, ed[:]) + encodedAddress, err := strkey.Encode(strkey.VersionByteAccountID, raw) + if err != nil { + return "", false + } + return encodedAddress, true + default: + return "", false + } +} From 89421684c4efea72386c74203e1dcbc79c5413e6 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 15:29:16 -0700 Subject: [PATCH 09/40] Change Ledger to use lcm as param instead --- ingest/ledger/ledger.go | 80 +++++++++++++++++------------------- ingest/ledger/ledger_test.go | 43 +++++++++---------- 2 files changed, 58 insertions(+), 65 deletions(-) diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go index fb58dbd9a5..c37cb50b3b 100644 --- a/ingest/ledger/ledger.go +++ b/ingest/ledger/ledger.go @@ -8,60 +8,56 @@ import ( "github.com/stellar/go/xdr" ) -type Ledger struct { - Ledger xdr.LedgerCloseMeta +func Sequence(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq) } -func (l Ledger) Sequence() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) +func ID(l xdr.LedgerCloseMeta) int64 { + return toid.New(int32(l.LedgerSequence()), 0, 0).ToInt64() } -func (l Ledger) ID() int64 { - return toid.New(int32(l.Ledger.LedgerSequence()), 0, 0).ToInt64() +func Hash(l xdr.LedgerCloseMeta) string { + return l.LedgerHeaderHistoryEntry().Hash.HexString() } -func (l Ledger) Hash() string { - return l.Ledger.LedgerHeaderHistoryEntry().Hash.HexString() +func PreviousHash(l xdr.LedgerCloseMeta) string { + return l.PreviousLedgerHash().HexString() } -func (l Ledger) PreviousHash() string { - return l.Ledger.PreviousLedgerHash().HexString() +func CloseTime(l xdr.LedgerCloseMeta) int64 { + return l.LedgerCloseTime() } -func (l Ledger) CloseTime() int64 { - return l.Ledger.LedgerCloseTime() +func ClosedAt(l xdr.LedgerCloseMeta) time.Time { + return time.Unix(l.LedgerCloseTime(), 0).UTC() } -func (l Ledger) ClosedAt() time.Time { - return time.Unix(l.Ledger.LedgerCloseTime(), 0).UTC() +func TotalCoins(l xdr.LedgerCloseMeta) int64 { + return int64(l.LedgerHeaderHistoryEntry().Header.TotalCoins) } -func (l Ledger) TotalCoins() int64 { - return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) +func FeePool(l xdr.LedgerCloseMeta) int64 { + return int64(l.LedgerHeaderHistoryEntry().Header.FeePool) } -func (l Ledger) FeePool() int64 { - return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.FeePool) +func BaseFee(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.BaseFee) } -func (l Ledger) BaseFee() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseFee) +func BaseReserve(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.BaseReserve) } -func (l Ledger) BaseReserve() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) +func MaxTxSetSize(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) } -func (l Ledger) MaxTxSetSize() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) +func LedgerVersion(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerVersion) } -func (l Ledger) LedgerVersion() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) -} - -func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { - lcmV1, ok := l.Ledger.GetV1() +func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) (int64, bool) { + lcmV1, ok := l.GetV1() if !ok { return 0, false } @@ -74,8 +70,8 @@ func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { return int64(extV1.SorobanFeeWrite1Kb), true } -func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { - lcmV1, ok := l.Ledger.GetV1() +func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) { + lcmV1, ok := l.GetV1() if !ok { return 0, false } @@ -83,8 +79,8 @@ func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { return uint64(lcmV1.TotalByteSizeOfBucketList), true } -func (l Ledger) NodeID() (string, bool) { - LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +func NodeID(l xdr.LedgerCloseMeta) (string, bool) { + LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { return "", false @@ -92,8 +88,8 @@ func (l Ledger) NodeID() (string, bool) { return LedgerCloseValueSignature.NodeId.GetAddress() } -func (l Ledger) Signature() (string, bool) { - LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +func Signature(l xdr.LedgerCloseMeta) (string, bool) { + LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { return "", false } @@ -102,11 +98,11 @@ func (l Ledger) Signature() (string, bool) { } // Add docstring to larger, more complicated functions -func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) { +func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32, ok bool) { var results []xdr.TransactionResultMeta - transactions := l.Ledger.TransactionEnvelopes() - results = l.Ledger.TxProcessing() + transactions := l.TransactionEnvelopes() + results = l.TxProcessing() txCount := len(transactions) if txCount != len(results) { return 0, 0, false @@ -124,11 +120,11 @@ func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok boo } // Add docstring to larger, more complicated functions -func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) { +func OperationCounts(l xdr.LedgerCloseMeta) (operationCount, txSetOperationCount int32, ok bool) { var results []xdr.TransactionResultMeta - transactions := l.Ledger.TransactionEnvelopes() - results = l.Ledger.TxProcessing() + transactions := l.TransactionEnvelopes() + results = l.TxProcessing() for i, result := range results { operations := transactions[i].Operations() diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index 3c4b388ec8..2345d46792 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -11,56 +11,53 @@ import ( ) func TestLedger(t *testing.T) { - ledger := Ledger{ - Ledger: ledgerTestInput(), - } - - assert.Equal(t, uint32(30578981), ledger.Sequence()) - assert.Equal(t, int64(131335723340005376), ledger.ID()) - assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", ledger.Hash()) - assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", ledger.PreviousHash()) - assert.Equal(t, int64(1594584547), ledger.CloseTime()) - assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ledger.ClosedAt()) - assert.Equal(t, int64(1054439020873472865), ledger.TotalCoins()) - assert.Equal(t, int64(18153766209161), ledger.FeePool()) - assert.Equal(t, uint32(100), ledger.BaseFee()) - assert.Equal(t, uint32(5000000), ledger.BaseReserve()) - assert.Equal(t, uint32(1000), ledger.MaxTxSetSize()) - assert.Equal(t, uint32(13), ledger.LedgerVersion()) + ledger := ledgerTestInput() + + assert.Equal(t, uint32(30578981), Sequence(ledger)) + assert.Equal(t, int64(131335723340005376), ID(ledger)) + assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger)) + assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", PreviousHash(ledger)) + assert.Equal(t, int64(1594584547), CloseTime(ledger)) + assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ClosedAt(ledger)) + assert.Equal(t, int64(1054439020873472865), TotalCoins(ledger)) + assert.Equal(t, int64(18153766209161), FeePool(ledger)) + assert.Equal(t, uint32(100), BaseFee(ledger)) + assert.Equal(t, uint32(5000000), BaseReserve(ledger)) + assert.Equal(t, uint32(1000), MaxTxSetSize(ledger)) + assert.Equal(t, uint32(13), LedgerVersion(ledger)) var ok bool var freeWrite int64 - freeWrite, ok = ledger.SorobanFeeWrite1Kb() + freeWrite, ok = SorobanFeeWrite1Kb(ledger) assert.Equal(t, true, ok) assert.Equal(t, int64(12), freeWrite) var bucketSize uint64 - bucketSize, ok = ledger.TotalByteSizeOfBucketList() + bucketSize, ok = TotalByteSizeOfBucketList(ledger) assert.Equal(t, true, ok) assert.Equal(t, uint64(56), bucketSize) var nodeID string - nodeID, ok = ledger.NodeID() + nodeID, ok = NodeID(ledger) assert.Equal(t, true, ok) assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) var signature string - signature, ok = ledger.Signature() + signature, ok = Signature(ledger) assert.Equal(t, true, ok) assert.Equal(t, "9g==", signature) var success int32 var failed int32 - success, failed, ok = ledger.TransactionCounts() + success, failed, ok = TransactionCounts(ledger) assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) - success, failed, ok = ledger.OperationCounts() + success, failed, ok = OperationCounts(ledger) assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(13), failed) - } func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { From b5feb2c8300e7ad44da807b0f317eb32b701c55f Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 14:42:51 -0700 Subject: [PATCH 10/40] Move xdrill ledger functions to ingest as subpackage --- exp/xdrill/ledger/ledger.go | 204 ------------------- exp/xdrill/utils/utils.go | 179 ---------------- ingest/ledger/ledger.go | 150 ++++++++++++++ {exp/xdrill => ingest}/ledger/ledger_test.go | 99 ++++++--- xdr/node_id.go | 22 ++ 5 files changed, 244 insertions(+), 410 deletions(-) delete mode 100644 exp/xdrill/ledger/ledger.go delete mode 100644 exp/xdrill/utils/utils.go create mode 100644 ingest/ledger/ledger.go rename {exp/xdrill => ingest}/ledger/ledger_test.go (61%) create mode 100644 xdr/node_id.go diff --git a/exp/xdrill/ledger/ledger.go b/exp/xdrill/ledger/ledger.go deleted file mode 100644 index b6cb9f9d48..0000000000 --- a/exp/xdrill/ledger/ledger.go +++ /dev/null @@ -1,204 +0,0 @@ -package ledger - -import ( - "encoding/base64" - "fmt" - "time" - - "github.com/stellar/go/exp/xdrill/utils" - "github.com/stellar/go/xdr" -) - -func Sequence(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq) -} - -func ID(l xdr.LedgerCloseMeta) int64 { - return utils.NewID(int32(l.LedgerSequence()), 0, 0).ToInt64() -} - -func Hash(l xdr.LedgerCloseMeta) string { - return utils.HashToHexString(l.LedgerHeaderHistoryEntry().Hash) -} - -func PreviousHash(l xdr.LedgerCloseMeta) string { - return utils.HashToHexString(l.PreviousLedgerHash()) -} - -func CloseTime(l xdr.LedgerCloseMeta) int64 { - return l.LedgerCloseTime() -} - -func ClosedAt(l xdr.LedgerCloseMeta) time.Time { - return time.Unix(l.LedgerCloseTime(), 0).UTC() -} - -func TotalCoins(l xdr.LedgerCloseMeta) int64 { - return int64(l.LedgerHeaderHistoryEntry().Header.TotalCoins) -} - -func FeePool(l xdr.LedgerCloseMeta) int64 { - return int64(l.LedgerHeaderHistoryEntry().Header.FeePool) -} - -func BaseFee(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.BaseFee) -} - -func BaseReserve(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.BaseReserve) -} - -func MaxTxSetSize(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) -} - -func LedgerVersion(l xdr.LedgerCloseMeta) uint32 { - return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerVersion) -} - -func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) *int64 { - lcmV1, ok := l.GetV1() - if !ok { - return nil - } - - extV1, ok := lcmV1.Ext.GetV1() - if !ok { - return nil - } - - result := int64(extV1.SorobanFeeWrite1Kb) - - return &result -} - -func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) *uint64 { - lcmV1, ok := l.GetV1() - if !ok { - return nil - } - - result := uint64(lcmV1.TotalByteSizeOfBucketList) - - return &result -} - -func NodeID(l xdr.LedgerCloseMeta) *string { - LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() - if !ok { - return nil - - } - nodeID, ok := utils.GetAddress(LedgerCloseValueSignature.NodeId) - if !ok { - return nil - } - - return &nodeID -} - -func Signature(l xdr.LedgerCloseMeta) *string { - LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() - if !ok { - return nil - } - - result := base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature) - - return &result -} - -// Add docstring to larger, more complicated functions -func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32, ok bool) { - var results []xdr.TransactionResultMeta - - transactions := getTransactionSet(l) - results = l.TxProcessing() - txCount := len(transactions) - if txCount != len(results) { - return 0, 0, false - } - - for i := 0; i < txCount; i++ { - if results[i].Result.Successful() { - successTxCount++ - } else { - failedTxCount++ - } - } - - return successTxCount, failedTxCount, true -} - -// Add docstring to larger, more complicated functions -func OperationCounts(l xdr.LedgerCloseMeta) (operationCount, txSetOperationCount int32, ok bool) { - var results []xdr.TransactionResultMeta - - transactions := getTransactionSet(l) - results = l.TxProcessing() - - txCount := len(transactions) - if txCount != len(results) { - return 0, 0, false - } - - for i := 0; i < txCount; i++ { - operations := transactions[i].Operations() - numberOfOps := int32(len(operations)) - txSetOperationCount += numberOfOps - - // for successful transactions, the operation count is based on the operations results slice - if results[i].Result.Successful() { - operationResults, ok := results[i].Result.OperationResults() - if !ok { - return 0, 0, false - } - - operationCount += int32(len(operationResults)) - } - - } - - return operationCount, txSetOperationCount, true -} - -func getTransactionSet(l xdr.LedgerCloseMeta) (transactionProcessing []xdr.TransactionEnvelope) { - switch l.V { - case 0: - return l.V0.TxSet.Txs - case 1: - switch l.V1.TxSet.V { - case 0: - return getTransactionPhase(l.V1.TxSet.V1TxSet.Phases) - default: - panic(fmt.Sprintf("unsupported LedgerCloseMeta.V1.TxSet.V: %d", l.V1.TxSet.V)) - } - default: - panic(fmt.Sprintf("unsupported LedgerCloseMeta.V: %d", l.V)) - } -} - -func getTransactionPhase(transactionPhase []xdr.TransactionPhase) (transactionEnvelope []xdr.TransactionEnvelope) { - transactionSlice := []xdr.TransactionEnvelope{} - for _, phase := range transactionPhase { - switch phase.V { - case 0: - components := phase.MustV0Components() - for _, component := range components { - switch component.Type { - case 0: - transactionSlice = append(transactionSlice, component.TxsMaybeDiscountedFee.Txs...) - - default: - panic(fmt.Sprintf("unsupported TxSetComponentType: %d", component.Type)) - } - - } - default: - panic(fmt.Sprintf("unsupported TransactionPhase.V: %d", phase.V)) - } - } - - return transactionSlice -} diff --git a/exp/xdrill/utils/utils.go b/exp/xdrill/utils/utils.go deleted file mode 100644 index b5fc44329e..0000000000 --- a/exp/xdrill/utils/utils.go +++ /dev/null @@ -1,179 +0,0 @@ -package utils - -import ( - "encoding/hex" - - "github.com/stellar/go/keypair" - "github.com/stellar/go/strkey" - "github.com/stellar/go/txnbuild" - "github.com/stellar/go/xdr" -) - -// HashToHexString is utility function that converts and xdr.Hash type to a hex string -func HashToHexString(inputHash xdr.Hash) string { - sliceHash := inputHash[:] - hexString := hex.EncodeToString(sliceHash) - return hexString -} - -type ID struct { - LedgerSequence int32 - TransactionOrder int32 - OperationOrder int32 -} - -const ( - // LedgerMask is the bitmask to mask out ledger sequences in a - // TotalOrderID - LedgerMask = (1 << 32) - 1 - // TransactionMask is the bitmask to mask out transaction indexes - TransactionMask = (1 << 20) - 1 - // OperationMask is the bitmask to mask out operation indexes - OperationMask = (1 << 12) - 1 - - // LedgerShift is the number of bits to shift an int64 to target the - // ledger component - LedgerShift = 32 - // TransactionShift is the number of bits to shift an int64 to - // target the transaction component - TransactionShift = 12 - // OperationShift is the number of bits to shift an int64 to target - // the operation component - OperationShift = 0 -) - -// New creates a new total order ID -func NewID(ledger int32, tx int32, op int32) *ID { - return &ID{ - LedgerSequence: ledger, - TransactionOrder: tx, - OperationOrder: op, - } -} - -// ToInt64 converts this struct back into an int64 -func (id ID) ToInt64() (result int64) { - - if id.LedgerSequence < 0 { - panic("invalid ledger sequence") - } - - if id.TransactionOrder > TransactionMask { - panic("transaction order overflow") - } - - if id.OperationOrder > OperationMask { - panic("operation order overflow") - } - - result = result | ((int64(id.LedgerSequence) & LedgerMask) << LedgerShift) - result = result | ((int64(id.TransactionOrder) & TransactionMask) << TransactionShift) - result = result | ((int64(id.OperationOrder) & OperationMask) << OperationShift) - return -} - -// TODO: This should be moved into the go monorepo xdr functions -// Or nodeID should just be an xdr.AccountId but the error message would be incorrect -func GetAddress(nodeID xdr.NodeId) (string, bool) { - switch nodeID.Type { - case xdr.PublicKeyTypePublicKeyTypeEd25519: - ed, ok := nodeID.GetEd25519() - if !ok { - return "", false - } - raw := make([]byte, 32) - copy(raw, ed[:]) - encodedAddress, err := strkey.Encode(strkey.VersionByteAccountID, raw) - if err != nil { - return "", false - } - return encodedAddress, true - default: - return "", false - } -} - -func CreateSampleTx(sequence int64, operationCount int) xdr.TransactionEnvelope { - kp, err := keypair.Random() - PanicOnError(err) - - operations := []txnbuild.Operation{} - operationType := &txnbuild.BumpSequence{ - BumpTo: 0, - } - for i := 0; i < operationCount; i++ { - operations = append(operations, operationType) - } - - sourceAccount := txnbuild.NewSimpleAccount(kp.Address(), int64(0)) - tx, err := txnbuild.NewTransaction( - txnbuild.TransactionParams{ - SourceAccount: &sourceAccount, - Operations: operations, - BaseFee: txnbuild.MinBaseFee, - Preconditions: txnbuild.Preconditions{TimeBounds: txnbuild.NewInfiniteTimeout()}, - }, - ) - PanicOnError(err) - - env := tx.ToXDR() - return env -} - -// PanicOnError is a function that panics if the provided error is not nil -func PanicOnError(err error) { - if err != nil { - panic(err) - } -} - -// GetAccountAddressFromMuxedAccount takes in a muxed account and returns the address of the account -func GetAccountAddressFromMuxedAccount(account xdr.MuxedAccount) (string, error) { - providedID := account.ToAccountId() - pointerToID := &providedID - return pointerToID.GetAddress() -} - -func GetAccountBalanceFromLedgerEntryChanges(changes xdr.LedgerEntryChanges, sourceAccountAddress string) (int64, int64) { - var accountBalanceStart int64 - var accountBalanceEnd int64 - - for _, change := range changes { - switch change.Type { - case xdr.LedgerEntryChangeTypeLedgerEntryUpdated: - accountEntry, ok := change.Updated.Data.GetAccount() - if !ok { - continue - } - - if accountEntry.AccountId.Address() == sourceAccountAddress { - accountBalanceEnd = int64(accountEntry.Balance) - } - case xdr.LedgerEntryChangeTypeLedgerEntryState: - accountEntry, ok := change.State.Data.GetAccount() - if !ok { - continue - } - - if accountEntry.AccountId.Address() == sourceAccountAddress { - accountBalanceStart = int64(accountEntry.Balance) - } - } - } - - return accountBalanceStart, accountBalanceEnd -} - -func GetTxSigners(xdrSignatures []xdr.DecoratedSignature) ([]string, error) { - signers := make([]string, len(xdrSignatures)) - - for i, sig := range xdrSignatures { - signerAccount, err := strkey.Encode(strkey.VersionByteAccountID, sig.Signature) - if err != nil { - return nil, err - } - signers[i] = signerAccount - } - - return signers, nil -} diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go new file mode 100644 index 0000000000..fb58dbd9a5 --- /dev/null +++ b/ingest/ledger/ledger.go @@ -0,0 +1,150 @@ +package ledger + +import ( + "encoding/base64" + "time" + + "github.com/stellar/go/toid" + "github.com/stellar/go/xdr" +) + +type Ledger struct { + Ledger xdr.LedgerCloseMeta +} + +func (l Ledger) Sequence() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) +} + +func (l Ledger) ID() int64 { + return toid.New(int32(l.Ledger.LedgerSequence()), 0, 0).ToInt64() +} + +func (l Ledger) Hash() string { + return l.Ledger.LedgerHeaderHistoryEntry().Hash.HexString() +} + +func (l Ledger) PreviousHash() string { + return l.Ledger.PreviousLedgerHash().HexString() +} + +func (l Ledger) CloseTime() int64 { + return l.Ledger.LedgerCloseTime() +} + +func (l Ledger) ClosedAt() time.Time { + return time.Unix(l.Ledger.LedgerCloseTime(), 0).UTC() +} + +func (l Ledger) TotalCoins() int64 { + return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) +} + +func (l Ledger) FeePool() int64 { + return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.FeePool) +} + +func (l Ledger) BaseFee() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseFee) +} + +func (l Ledger) BaseReserve() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) +} + +func (l Ledger) MaxTxSetSize() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) +} + +func (l Ledger) LedgerVersion() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) +} + +func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { + lcmV1, ok := l.Ledger.GetV1() + if !ok { + return 0, false + } + + extV1, ok := lcmV1.Ext.GetV1() + if !ok { + return 0, false + } + + return int64(extV1.SorobanFeeWrite1Kb), true +} + +func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { + lcmV1, ok := l.Ledger.GetV1() + if !ok { + return 0, false + } + + return uint64(lcmV1.TotalByteSizeOfBucketList), true +} + +func (l Ledger) NodeID() (string, bool) { + LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() + if !ok { + return "", false + + } + return LedgerCloseValueSignature.NodeId.GetAddress() +} + +func (l Ledger) Signature() (string, bool) { + LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() + if !ok { + return "", false + } + + return base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature), true +} + +// Add docstring to larger, more complicated functions +func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) { + var results []xdr.TransactionResultMeta + + transactions := l.Ledger.TransactionEnvelopes() + results = l.Ledger.TxProcessing() + txCount := len(transactions) + if txCount != len(results) { + return 0, 0, false + } + + for i := 0; i < txCount; i++ { + if results[i].Result.Successful() { + successTxCount++ + } else { + failedTxCount++ + } + } + + return successTxCount, failedTxCount, true +} + +// Add docstring to larger, more complicated functions +func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) { + var results []xdr.TransactionResultMeta + + transactions := l.Ledger.TransactionEnvelopes() + results = l.Ledger.TxProcessing() + + for i, result := range results { + operations := transactions[i].Operations() + numberOfOps := int32(len(operations)) + txSetOperationCount += numberOfOps + + // for successful transactions, the operation count is based on the operations results slice + if result.Result.Successful() { + operationResults, ok := result.Result.OperationResults() + if !ok { + return 0, 0, false + } + + operationCount += int32(len(operationResults)) + } + } + + return operationCount, txSetOperationCount, true +} diff --git a/exp/xdrill/ledger/ledger_test.go b/ingest/ledger/ledger_test.go similarity index 61% rename from exp/xdrill/ledger/ledger_test.go rename to ingest/ledger/ledger_test.go index 7adac0a4cb..3c4b388ec8 100644 --- a/exp/xdrill/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -4,48 +4,59 @@ import ( "testing" "time" - "github.com/stellar/go/exp/xdrill/utils" + "github.com/stellar/go/keypair" + "github.com/stellar/go/txnbuild" "github.com/stellar/go/xdr" "github.com/stretchr/testify/assert" ) func TestLedger(t *testing.T) { - ledger := ledgerTestInput() + ledger := Ledger{ + Ledger: ledgerTestInput(), + } - assert.Equal(t, uint32(30578981), Sequence(ledger)) - assert.Equal(t, int64(131335723340005376), ID(ledger)) - assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger)) - assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", PreviousHash(ledger)) - assert.Equal(t, int64(1594584547), CloseTime(ledger)) - assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ClosedAt(ledger)) - assert.Equal(t, int64(1054439020873472865), TotalCoins(ledger)) - assert.Equal(t, int64(18153766209161), FeePool(ledger)) - assert.Equal(t, uint32(100), BaseFee(ledger)) - assert.Equal(t, uint32(5000000), BaseReserve(ledger)) - assert.Equal(t, uint32(1000), MaxTxSetSize(ledger)) - assert.Equal(t, uint32(13), LedgerVersion(ledger)) + assert.Equal(t, uint32(30578981), ledger.Sequence()) + assert.Equal(t, int64(131335723340005376), ledger.ID()) + assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", ledger.Hash()) + assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", ledger.PreviousHash()) + assert.Equal(t, int64(1594584547), ledger.CloseTime()) + assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ledger.ClosedAt()) + assert.Equal(t, int64(1054439020873472865), ledger.TotalCoins()) + assert.Equal(t, int64(18153766209161), ledger.FeePool()) + assert.Equal(t, uint32(100), ledger.BaseFee()) + assert.Equal(t, uint32(5000000), ledger.BaseReserve()) + assert.Equal(t, uint32(1000), ledger.MaxTxSetSize()) + assert.Equal(t, uint32(13), ledger.LedgerVersion()) - freeWrite := SorobanFeeWrite1Kb(ledger) - assert.Equal(t, int64(12), *freeWrite) + var ok bool + var freeWrite int64 + freeWrite, ok = ledger.SorobanFeeWrite1Kb() + assert.Equal(t, true, ok) + assert.Equal(t, int64(12), freeWrite) - bucketSize := TotalByteSizeOfBucketList(ledger) - assert.Equal(t, uint64(56), *bucketSize) + var bucketSize uint64 + bucketSize, ok = ledger.TotalByteSizeOfBucketList() + assert.Equal(t, true, ok) + assert.Equal(t, uint64(56), bucketSize) - nodeID := NodeID(ledger) - assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", *nodeID) + var nodeID string + nodeID, ok = ledger.NodeID() + assert.Equal(t, true, ok) + assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) - signature := Signature(ledger) - assert.Equal(t, "9g==", *signature) + var signature string + signature, ok = ledger.Signature() + assert.Equal(t, true, ok) + assert.Equal(t, "9g==", signature) - var ok bool var success int32 var failed int32 - success, failed, ok = TransactionCounts(ledger) + success, failed, ok = ledger.TransactionCounts() assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) - success, failed, ok = OperationCounts(ledger) + success, failed, ok = ledger.OperationCounts() assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(13), failed) @@ -100,8 +111,8 @@ func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { Type: 0, TxsMaybeDiscountedFee: &xdr.TxSetComponentTxsMaybeDiscountedFee{ Txs: []xdr.TransactionEnvelope{ - utils.CreateSampleTx(0, 3), - utils.CreateSampleTx(1, 10), + createSampleTx(3), + createSampleTx(10), }, }, }, @@ -157,3 +168,37 @@ func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { return lcm } + +func createSampleTx(operationCount int) xdr.TransactionEnvelope { + kp, err := keypair.Random() + panicOnError(err) + + operations := []txnbuild.Operation{} + operationType := &txnbuild.BumpSequence{ + BumpTo: 0, + } + for i := 0; i < operationCount; i++ { + operations = append(operations, operationType) + } + + sourceAccount := txnbuild.NewSimpleAccount(kp.Address(), int64(0)) + tx, err := txnbuild.NewTransaction( + txnbuild.TransactionParams{ + SourceAccount: &sourceAccount, + Operations: operations, + BaseFee: txnbuild.MinBaseFee, + Preconditions: txnbuild.Preconditions{TimeBounds: txnbuild.NewInfiniteTimeout()}, + }, + ) + panicOnError(err) + + env := tx.ToXDR() + return env +} + +// PanicOnError is a function that panics if the provided error is not nil +func panicOnError(err error) { + if err != nil { + panic(err) + } +} diff --git a/xdr/node_id.go b/xdr/node_id.go new file mode 100644 index 0000000000..b3f9c77eb8 --- /dev/null +++ b/xdr/node_id.go @@ -0,0 +1,22 @@ +package xdr + +import "github.com/stellar/go/strkey" + +func (n NodeId) GetAddress() (string, bool) { + switch n.Type { + case PublicKeyTypePublicKeyTypeEd25519: + ed, ok := n.GetEd25519() + if !ok { + return "", false + } + raw := make([]byte, 32) + copy(raw, ed[:]) + encodedAddress, err := strkey.Encode(strkey.VersionByteAccountID, raw) + if err != nil { + return "", false + } + return encodedAddress, true + default: + return "", false + } +} From 4aedfdbbc65cd41dabadd0e78ad4cee92c778710 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 15:29:16 -0700 Subject: [PATCH 11/40] Change Ledger to use lcm as param instead --- ingest/ledger/ledger.go | 80 +++++++++++++++++------------------- ingest/ledger/ledger_test.go | 43 +++++++++---------- 2 files changed, 58 insertions(+), 65 deletions(-) diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go index fb58dbd9a5..c37cb50b3b 100644 --- a/ingest/ledger/ledger.go +++ b/ingest/ledger/ledger.go @@ -8,60 +8,56 @@ import ( "github.com/stellar/go/xdr" ) -type Ledger struct { - Ledger xdr.LedgerCloseMeta +func Sequence(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq) } -func (l Ledger) Sequence() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) +func ID(l xdr.LedgerCloseMeta) int64 { + return toid.New(int32(l.LedgerSequence()), 0, 0).ToInt64() } -func (l Ledger) ID() int64 { - return toid.New(int32(l.Ledger.LedgerSequence()), 0, 0).ToInt64() +func Hash(l xdr.LedgerCloseMeta) string { + return l.LedgerHeaderHistoryEntry().Hash.HexString() } -func (l Ledger) Hash() string { - return l.Ledger.LedgerHeaderHistoryEntry().Hash.HexString() +func PreviousHash(l xdr.LedgerCloseMeta) string { + return l.PreviousLedgerHash().HexString() } -func (l Ledger) PreviousHash() string { - return l.Ledger.PreviousLedgerHash().HexString() +func CloseTime(l xdr.LedgerCloseMeta) int64 { + return l.LedgerCloseTime() } -func (l Ledger) CloseTime() int64 { - return l.Ledger.LedgerCloseTime() +func ClosedAt(l xdr.LedgerCloseMeta) time.Time { + return time.Unix(l.LedgerCloseTime(), 0).UTC() } -func (l Ledger) ClosedAt() time.Time { - return time.Unix(l.Ledger.LedgerCloseTime(), 0).UTC() +func TotalCoins(l xdr.LedgerCloseMeta) int64 { + return int64(l.LedgerHeaderHistoryEntry().Header.TotalCoins) } -func (l Ledger) TotalCoins() int64 { - return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) +func FeePool(l xdr.LedgerCloseMeta) int64 { + return int64(l.LedgerHeaderHistoryEntry().Header.FeePool) } -func (l Ledger) FeePool() int64 { - return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.FeePool) +func BaseFee(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.BaseFee) } -func (l Ledger) BaseFee() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseFee) +func BaseReserve(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.BaseReserve) } -func (l Ledger) BaseReserve() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) +func MaxTxSetSize(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) } -func (l Ledger) MaxTxSetSize() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) +func LedgerVersion(l xdr.LedgerCloseMeta) uint32 { + return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerVersion) } -func (l Ledger) LedgerVersion() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) -} - -func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { - lcmV1, ok := l.Ledger.GetV1() +func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) (int64, bool) { + lcmV1, ok := l.GetV1() if !ok { return 0, false } @@ -74,8 +70,8 @@ func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { return int64(extV1.SorobanFeeWrite1Kb), true } -func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { - lcmV1, ok := l.Ledger.GetV1() +func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) { + lcmV1, ok := l.GetV1() if !ok { return 0, false } @@ -83,8 +79,8 @@ func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { return uint64(lcmV1.TotalByteSizeOfBucketList), true } -func (l Ledger) NodeID() (string, bool) { - LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +func NodeID(l xdr.LedgerCloseMeta) (string, bool) { + LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { return "", false @@ -92,8 +88,8 @@ func (l Ledger) NodeID() (string, bool) { return LedgerCloseValueSignature.NodeId.GetAddress() } -func (l Ledger) Signature() (string, bool) { - LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +func Signature(l xdr.LedgerCloseMeta) (string, bool) { + LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { return "", false } @@ -102,11 +98,11 @@ func (l Ledger) Signature() (string, bool) { } // Add docstring to larger, more complicated functions -func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) { +func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32, ok bool) { var results []xdr.TransactionResultMeta - transactions := l.Ledger.TransactionEnvelopes() - results = l.Ledger.TxProcessing() + transactions := l.TransactionEnvelopes() + results = l.TxProcessing() txCount := len(transactions) if txCount != len(results) { return 0, 0, false @@ -124,11 +120,11 @@ func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok boo } // Add docstring to larger, more complicated functions -func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) { +func OperationCounts(l xdr.LedgerCloseMeta) (operationCount, txSetOperationCount int32, ok bool) { var results []xdr.TransactionResultMeta - transactions := l.Ledger.TransactionEnvelopes() - results = l.Ledger.TxProcessing() + transactions := l.TransactionEnvelopes() + results = l.TxProcessing() for i, result := range results { operations := transactions[i].Operations() diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index 3c4b388ec8..2345d46792 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -11,56 +11,53 @@ import ( ) func TestLedger(t *testing.T) { - ledger := Ledger{ - Ledger: ledgerTestInput(), - } - - assert.Equal(t, uint32(30578981), ledger.Sequence()) - assert.Equal(t, int64(131335723340005376), ledger.ID()) - assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", ledger.Hash()) - assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", ledger.PreviousHash()) - assert.Equal(t, int64(1594584547), ledger.CloseTime()) - assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ledger.ClosedAt()) - assert.Equal(t, int64(1054439020873472865), ledger.TotalCoins()) - assert.Equal(t, int64(18153766209161), ledger.FeePool()) - assert.Equal(t, uint32(100), ledger.BaseFee()) - assert.Equal(t, uint32(5000000), ledger.BaseReserve()) - assert.Equal(t, uint32(1000), ledger.MaxTxSetSize()) - assert.Equal(t, uint32(13), ledger.LedgerVersion()) + ledger := ledgerTestInput() + + assert.Equal(t, uint32(30578981), Sequence(ledger)) + assert.Equal(t, int64(131335723340005376), ID(ledger)) + assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger)) + assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", PreviousHash(ledger)) + assert.Equal(t, int64(1594584547), CloseTime(ledger)) + assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ClosedAt(ledger)) + assert.Equal(t, int64(1054439020873472865), TotalCoins(ledger)) + assert.Equal(t, int64(18153766209161), FeePool(ledger)) + assert.Equal(t, uint32(100), BaseFee(ledger)) + assert.Equal(t, uint32(5000000), BaseReserve(ledger)) + assert.Equal(t, uint32(1000), MaxTxSetSize(ledger)) + assert.Equal(t, uint32(13), LedgerVersion(ledger)) var ok bool var freeWrite int64 - freeWrite, ok = ledger.SorobanFeeWrite1Kb() + freeWrite, ok = SorobanFeeWrite1Kb(ledger) assert.Equal(t, true, ok) assert.Equal(t, int64(12), freeWrite) var bucketSize uint64 - bucketSize, ok = ledger.TotalByteSizeOfBucketList() + bucketSize, ok = TotalByteSizeOfBucketList(ledger) assert.Equal(t, true, ok) assert.Equal(t, uint64(56), bucketSize) var nodeID string - nodeID, ok = ledger.NodeID() + nodeID, ok = NodeID(ledger) assert.Equal(t, true, ok) assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) var signature string - signature, ok = ledger.Signature() + signature, ok = Signature(ledger) assert.Equal(t, true, ok) assert.Equal(t, "9g==", signature) var success int32 var failed int32 - success, failed, ok = ledger.TransactionCounts() + success, failed, ok = TransactionCounts(ledger) assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) - success, failed, ok = ledger.OperationCounts() + success, failed, ok = OperationCounts(ledger) assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(13), failed) - } func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { From a5bd9273179d216e4a4b3723ac8baec287762caa Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 15:24:27 -0700 Subject: [PATCH 12/40] Move transaction helper functions to ingest --- exp/xdrill/transaction/transaction.go | 359 ------------------- exp/xdrill/transaction/transaction_test.go | 242 ------------- ingest/ledger_transaction.go | 398 +++++++++++++++++++++ ingest/ledger_transaction_test.go | 271 ++++++++++++++ 4 files changed, 669 insertions(+), 601 deletions(-) delete mode 100644 exp/xdrill/transaction/transaction.go delete mode 100644 exp/xdrill/transaction/transaction_test.go diff --git a/exp/xdrill/transaction/transaction.go b/exp/xdrill/transaction/transaction.go deleted file mode 100644 index 15c1f1a664..0000000000 --- a/exp/xdrill/transaction/transaction.go +++ /dev/null @@ -1,359 +0,0 @@ -package transaction - -import ( - "encoding/base64" - "encoding/hex" - "fmt" - "strconv" - - "github.com/stellar/go/exp/xdrill/ledger" - "github.com/stellar/go/exp/xdrill/utils" - "github.com/stellar/go/ingest" - "github.com/stellar/go/toid" - "github.com/stellar/go/xdr" -) - -func Hash(t ingest.LedgerTransaction) string { - return utils.HashToHexString(t.Result.TransactionHash) -} - -func Index(t ingest.LedgerTransaction) uint32 { - return uint32(t.Index) -} - -func ID(t ingest.LedgerTransaction, l xdr.LedgerCloseMeta) int64 { - return toid.New(int32(ledger.Sequence(l)), int32(t.Index), 0).ToInt64() -} - -func Account(t ingest.LedgerTransaction) (string, error) { - return utils.GetAccountAddressFromMuxedAccount(t.Envelope.SourceAccount()) -} - -func AccountSequence(t ingest.LedgerTransaction) int64 { - return t.Envelope.SeqNum() -} - -func MaxFee(t ingest.LedgerTransaction) uint32 { - return t.Envelope.Fee() -} - -func FeeCharged(t ingest.LedgerTransaction, l xdr.LedgerCloseMeta) *int64 { - // Any Soroban Fee Bump transactions before P21 will need the below logic to calculate the correct feeCharged - // Protocol 20 contained a bug where the feeCharged was incorrectly calculated but was fixed for - // Protocol 21 with https://github.com/stellar/stellar-core/issues/4188 - var result int64 - _, ok := getSorobanData(t) - if ok { - if ledger.LedgerVersion(l) < 21 && t.Envelope.Type == xdr.EnvelopeTypeEnvelopeTypeTxFeeBump { - resourceFeeRefund := SorobanResourceFeeRefund(t) - inclusionFeeCharged := SorobanInclusionFeeCharged(t) - result = int64(t.Result.Result.FeeCharged) - *resourceFeeRefund + *inclusionFeeCharged - return &result - } - } - - result = int64(t.Result.Result.FeeCharged) - - return &result -} - -func OperationCount(t ingest.LedgerTransaction) uint32 { - return uint32(len(t.Envelope.Operations())) -} - -func Memo(t ingest.LedgerTransaction) string { - memoObject := t.Envelope.Memo() - memoContents := "" - switch xdr.MemoType(memoObject.Type) { - case xdr.MemoTypeMemoText: - memoContents = memoObject.MustText() - case xdr.MemoTypeMemoId: - memoContents = strconv.FormatUint(uint64(memoObject.MustId()), 10) - case xdr.MemoTypeMemoHash: - hash := memoObject.MustHash() - memoContents = base64.StdEncoding.EncodeToString(hash[:]) - case xdr.MemoTypeMemoReturn: - hash := memoObject.MustRetHash() - memoContents = base64.StdEncoding.EncodeToString(hash[:]) - } - - return memoContents -} - -func MemoType(t ingest.LedgerTransaction) string { - memoObject := t.Envelope.Memo() - return memoObject.Type.String() -} - -func TimeBounds(t ingest.LedgerTransaction) (*string, error) { - timeBounds := t.Envelope.TimeBounds() - if timeBounds == nil { - return nil, nil - } - - if timeBounds.MaxTime < timeBounds.MinTime && timeBounds.MaxTime != 0 { - return nil, fmt.Errorf("the max time is earlier than the min time") - } - - var result string - if timeBounds.MaxTime == 0 { - result = fmt.Sprintf("[%d,)", timeBounds.MinTime) - return &result, nil - } - - result = fmt.Sprintf("[%d,%d)", timeBounds.MinTime, timeBounds.MaxTime) - - return &result, nil -} - -func LedgerBounds(t ingest.LedgerTransaction) *string { - ledgerBounds := t.Envelope.LedgerBounds() - if ledgerBounds == nil { - return nil - } - - result := fmt.Sprintf("[%d,%d)", int64(ledgerBounds.MinLedger), int64(ledgerBounds.MaxLedger)) - - return &result -} - -func MinSequence(t ingest.LedgerTransaction) *int64 { - return t.Envelope.MinSeqNum() -} - -func MinSequenceAge(t ingest.LedgerTransaction) *int64 { - minSequenceAge := t.Envelope.MinSeqAge() - if minSequenceAge == nil { - return nil - } - - minSequenceAgeInt64 := int64(*minSequenceAge) - return &minSequenceAgeInt64 -} - -func MinSequenceLedgerGap(t ingest.LedgerTransaction) *int64 { - minSequenceLedgerGap := t.Envelope.MinSeqLedgerGap() - result := int64(*minSequenceLedgerGap) - return &result -} - -func getSorobanData(t ingest.LedgerTransaction) (sorobanData xdr.SorobanTransactionData, ok bool) { - switch t.Envelope.Type { - case xdr.EnvelopeTypeEnvelopeTypeTx: - return t.Envelope.V1.Tx.Ext.GetSorobanData() - case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: - return t.Envelope.FeeBump.Tx.InnerTx.V1.Tx.Ext.GetSorobanData() - } - - return -} - -func SorobanResourceFee(t ingest.LedgerTransaction) *int64 { - sorobanData, ok := getSorobanData(t) - if !ok { - return nil - } - - result := int64(sorobanData.ResourceFee) - return &result -} - -func SorobanResourcesInstructions(t ingest.LedgerTransaction) *uint32 { - sorobanData, ok := getSorobanData(t) - if !ok { - return nil - } - - result := uint32(sorobanData.Resources.Instructions) - return &result -} - -func SorobanResourcesReadBytes(t ingest.LedgerTransaction) *uint32 { - sorobanData, ok := getSorobanData(t) - if !ok { - return nil - } - - result := uint32(sorobanData.Resources.ReadBytes) - return &result -} - -func SorobanResourcesWriteBytes(t ingest.LedgerTransaction) *uint32 { - sorobanData, ok := getSorobanData(t) - if !ok { - return nil - } - - result := uint32(sorobanData.Resources.WriteBytes) - return &result -} - -func InclusionFeeBid(t ingest.LedgerTransaction) *int64 { - resourceFee := SorobanResourceFee(t) - if resourceFee == nil { - return nil - } - - result := int64(t.Envelope.Fee()) - *resourceFee - return &result -} - -func getFeeAccountAddress(t ingest.LedgerTransaction) (feeAccountAddress string) { - switch t.Envelope.Type { - case xdr.EnvelopeTypeEnvelopeTypeTx: - sourceAccount := t.Envelope.SourceAccount() - feeAccountAddress = sourceAccount.Address() - case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: - feeBumpAccount := t.Envelope.FeeBumpAccount() - feeAccountAddress = feeBumpAccount.Address() - } - - return -} - -func SorobanInclusionFeeCharged(t ingest.LedgerTransaction) *int64 { - resourceFee := SorobanResourceFee(t) - if resourceFee == nil { - return nil - } - - accountBalanceStart, accountBalanceEnd := utils.GetAccountBalanceFromLedgerEntryChanges(t.FeeChanges, getFeeAccountAddress(t)) - initialFeeCharged := accountBalanceStart - accountBalanceEnd - result := initialFeeCharged - *resourceFee - - return &result -} - -func SorobanResourceFeeRefund(t ingest.LedgerTransaction) *int64 { - meta, ok := t.UnsafeMeta.GetV3() - if !ok { - return nil - } - - accountBalanceStart, accountBalanceEnd := utils.GetAccountBalanceFromLedgerEntryChanges(meta.TxChangesAfter, getFeeAccountAddress(t)) - result := accountBalanceEnd - accountBalanceStart - - return &result -} - -func SorobanTotalNonRefundableResourceFeeCharged(t ingest.LedgerTransaction) *int64 { - meta, ok := t.UnsafeMeta.GetV3() - if !ok { - return nil - } - - switch meta.SorobanMeta.Ext.V { - case 1: - result := int64(meta.SorobanMeta.Ext.V1.TotalNonRefundableResourceFeeCharged) - return &result - } - - return nil -} - -func SorobanTotalRefundableResourceFeeCharged(t ingest.LedgerTransaction) *int64 { - meta, ok := t.UnsafeMeta.GetV3() - if !ok { - return nil - } - - switch meta.SorobanMeta.Ext.V { - case 1: - result := int64(meta.SorobanMeta.Ext.V1.TotalRefundableResourceFeeCharged) - return &result - } - - return nil -} - -func SorobanRentFeeCharged(t ingest.LedgerTransaction) *int64 { - meta, ok := t.UnsafeMeta.GetV3() - if !ok { - return nil - } - - switch meta.SorobanMeta.Ext.V { - case 1: - result := int64(meta.SorobanMeta.Ext.V1.RentFeeCharged) - return &result - } - - return nil -} - -func ResultCode(t ingest.LedgerTransaction) string { - return t.Result.Result.Result.Code.String() -} - -func Signers(t ingest.LedgerTransaction) (signers []string) { - if t.Envelope.IsFeeBump() { - signers, _ = utils.GetTxSigners(t.Envelope.FeeBump.Signatures) - return - } - - signers, _ = utils.GetTxSigners(t.Envelope.Signatures()) - - return -} - -func AccountMuxed(t ingest.LedgerTransaction) *string { - sourceAccount := t.Envelope.SourceAccount() - if sourceAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { - return nil - } - - result := sourceAccount.Address() - - return &result -} - -func FeeAccount(t ingest.LedgerTransaction) *string { - if !t.Envelope.IsFeeBump() { - return nil - } - - feeBumpAccount := t.Envelope.FeeBumpAccount() - feeAccount := feeBumpAccount.ToAccountId() - result := feeAccount.Address() - - return &result -} - -func FeeAccountMuxed(t ingest.LedgerTransaction) *string { - if !t.Envelope.IsFeeBump() { - return nil - } - - feeBumpAccount := t.Envelope.FeeBumpAccount() - if feeBumpAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { - return nil - } - - result := feeBumpAccount.Address() - - return &result -} - -func InnerTransactionHash(t ingest.LedgerTransaction) *string { - if !t.Envelope.IsFeeBump() { - return nil - } - - innerHash := t.Result.InnerHash() - result := hex.EncodeToString(innerHash[:]) - - return &result -} - -func NewMaxFee(t ingest.LedgerTransaction) *uint32 { - if !t.Envelope.IsFeeBump() { - return nil - } - - newMaxFee := uint32(t.Envelope.FeeBumpFee()) - return &newMaxFee -} - -func Successful(t ingest.LedgerTransaction) bool { - return t.Result.Successful() -} diff --git a/exp/xdrill/transaction/transaction_test.go b/exp/xdrill/transaction/transaction_test.go deleted file mode 100644 index 9dc36aa9ef..0000000000 --- a/exp/xdrill/transaction/transaction_test.go +++ /dev/null @@ -1,242 +0,0 @@ -package transaction - -import ( - "testing" - - "github.com/stellar/go/ingest" - "github.com/stellar/go/xdr" - "github.com/stretchr/testify/assert" -) - -func TestTransaction(t *testing.T) { - ledger := ledgerTestInput() - transaction := transactionTestInput() - - assert.Equal(t, "1122330000000000000000000000000000000000000000000000000000000000", Hash(transaction)) - assert.Equal(t, uint32(1), Index(transaction)) - assert.Equal(t, int64(131335723340009472), ID(transaction, ledger)) - - var err error - var account string - account, err = Account(transaction) - assert.Equal(t, nil, err) - assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", account) - - assert.Equal(t, int64(30578981), AccountSequence(transaction)) - assert.Equal(t, uint32(4560), MaxFee(transaction)) - - feeCharged := FeeCharged(transaction, ledger) - assert.Equal(t, int64(789), *feeCharged) - - assert.Equal(t, uint32(3), OperationCount(transaction)) - assert.Equal(t, "test memo", Memo(transaction)) - assert.Equal(t, "MemoTypeMemoText", MemoType(transaction)) - - var timeBounds *string - timeBounds, err = TimeBounds(transaction) - assert.Equal(t, nil, err) - assert.Equal(t, "[1,10)", *timeBounds) - - ledgerBounds := LedgerBounds(transaction) - assert.Equal(t, "[2,20)", *ledgerBounds) - - minSequence := MinSequence(transaction) - assert.Equal(t, int64(123), *minSequence) - - minSequenceAge := MinSequenceAge(transaction) - assert.Equal(t, int64(456), *minSequenceAge) - - minSequenceLedgerGap := MinSequenceLedgerGap(transaction) - assert.Equal(t, int64(789), *minSequenceLedgerGap) - - sorobanResourceFee := SorobanResourceFee(transaction) - assert.Equal(t, int64(1234), *sorobanResourceFee) - - sorobanResourcesInstructions := SorobanResourcesInstructions(transaction) - assert.Equal(t, uint32(123), *sorobanResourcesInstructions) - - sorobanResourcesReadBytes := SorobanResourcesReadBytes(transaction) - assert.Equal(t, uint32(456), *sorobanResourcesReadBytes) - - sorobanResourcesWriteBytes := SorobanResourcesWriteBytes(transaction) - assert.Equal(t, uint32(789), *sorobanResourcesWriteBytes) - - inclusionFeeBid := InclusionFeeBid(transaction) - assert.Equal(t, int64(3326), *inclusionFeeBid) - - sorobanInclusionFeeCharged := SorobanInclusionFeeCharged(transaction) - assert.Equal(t, int64(-1234), *sorobanInclusionFeeCharged) - - sorobanResourceFeeRefund := SorobanResourceFeeRefund(transaction) - assert.Equal(t, int64(0), *sorobanResourceFeeRefund) - - sorobanTotalNonRefundableResourceFeeCharged := SorobanTotalNonRefundableResourceFeeCharged(transaction) - assert.Equal(t, int64(321), *sorobanTotalNonRefundableResourceFeeCharged) - - sorobanTotalRefundableResourceFeeCharged := SorobanTotalRefundableResourceFeeCharged(transaction) - assert.Equal(t, int64(123), *sorobanTotalRefundableResourceFeeCharged) - - sorobanRentFeeCharged := SorobanRentFeeCharged(transaction) - assert.Equal(t, int64(456), *sorobanRentFeeCharged) - - assert.Equal(t, "TransactionResultCodeTxSuccess", ResultCode(transaction)) - assert.Equal(t, []string{"GAISFR7R"}, Signers(transaction)) - - accountMuxed := AccountMuxed(transaction) - assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", *accountMuxed) - - feeAccount := FeeAccount(transaction) - assert.Equal(t, (*string)(nil), feeAccount) - - feeAccountMuxed := FeeAccountMuxed(transaction) - assert.Equal(t, (*string)(nil), feeAccountMuxed) - - innerTransactionHash := InnerTransactionHash(transaction) - assert.Equal(t, (*string)(nil), innerTransactionHash) - - assert.Equal(t, (*uint32)(nil), NewMaxFee(transaction)) - assert.Equal(t, true, Successful(transaction)) -} - -func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { - lcm = xdr.LedgerCloseMeta{ - V: 1, - V1: &xdr.LedgerCloseMetaV1{ - LedgerHeader: xdr.LedgerHeaderHistoryEntry{ - Header: xdr.LedgerHeader{ - LedgerSeq: 30578981, - LedgerVersion: 22, - }, - }, - }, - } - - return lcm -} - -func transactionTestInput() ingest.LedgerTransaction { - ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) - muxedAccount := xdr.MuxedAccount{ - Type: 256, - Ed25519: &ed25519, - Med25519: &xdr.MuxedAccountMed25519{ - Id: xdr.Uint64(123), - Ed25519: ed25519, - }, - } - - memoText := "test memo" - minSeqNum := xdr.SequenceNumber(123) - - transaction := ingest.LedgerTransaction{ - Index: 1, - Envelope: xdr.TransactionEnvelope{ - Type: xdr.EnvelopeTypeEnvelopeTypeTx, - V1: &xdr.TransactionV1Envelope{ - Signatures: []xdr.DecoratedSignature{ - { - Signature: []byte{0x11, 0x22}, - }, - }, - Tx: xdr.Transaction{ - SourceAccount: muxedAccount, - SeqNum: xdr.SequenceNumber(30578981), - Fee: xdr.Uint32(4560), - Operations: []xdr.Operation{ - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - }, - Memo: xdr.Memo{ - Type: xdr.MemoTypeMemoText, - Text: &memoText, - }, - Cond: xdr.Preconditions{ - Type: 2, - V2: &xdr.PreconditionsV2{ - TimeBounds: &xdr.TimeBounds{ - MinTime: xdr.TimePoint(1), - MaxTime: xdr.TimePoint(10), - }, - LedgerBounds: &xdr.LedgerBounds{ - MinLedger: 2, - MaxLedger: 20, - }, - MinSeqNum: &minSeqNum, - MinSeqAge: 456, - MinSeqLedgerGap: 789, - }, - }, - Ext: xdr.TransactionExt{ - V: 1, - SorobanData: &xdr.SorobanTransactionData{ - Resources: xdr.SorobanResources{ - Instructions: 123, - ReadBytes: 456, - WriteBytes: 789, - }, - ResourceFee: 1234, - }, - }, - }, - }, - }, - Result: xdr.TransactionResultPair{ - TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, - Result: xdr.TransactionResult{ - FeeCharged: xdr.Int64(789), - Result: xdr.TransactionResultResult{ - Code: 0, - }, - }, - }, - FeeChanges: xdr.LedgerEntryChanges{ - { - Type: xdr.LedgerEntryChangeTypeLedgerEntryState, - State: &xdr.LedgerEntry{ - Data: xdr.LedgerEntryData{ - Type: xdr.LedgerEntryTypeAccount, - Account: &xdr.AccountEntry{ - AccountId: xdr.AccountId{ - Type: 0, - Ed25519: &ed25519, - }, - Balance: 1000, - }, - }, - }, - }, - {}, - }, - UnsafeMeta: xdr.TransactionMeta{ - V: 3, - V3: &xdr.TransactionMetaV3{ - TxChangesAfter: xdr.LedgerEntryChanges{}, - SorobanMeta: &xdr.SorobanTransactionMeta{ - Ext: xdr.SorobanTransactionMetaExt{ - V: 1, - V1: &xdr.SorobanTransactionMetaExtV1{ - TotalNonRefundableResourceFeeCharged: 321, - TotalRefundableResourceFeeCharged: 123, - RentFeeCharged: 456, - }, - }, - }, - }, - }, - LedgerVersion: 22, - Ledger: xdr.LedgerCloseMeta{}, - Hash: xdr.Hash{}, - } - - return transaction -} diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index 046cff3782..36f82b952f 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -1,7 +1,14 @@ package ingest import ( + "encoding/base64" + "encoding/hex" + "fmt" + "strconv" + + "github.com/stellar/go/strkey" "github.com/stellar/go/support/errors" + "github.com/stellar/go/toid" "github.com/stellar/go/xdr" ) @@ -181,3 +188,394 @@ func (t *LedgerTransaction) operationChanges(ops []xdr.OperationMeta, index uint func (t *LedgerTransaction) GetDiagnosticEvents() ([]xdr.DiagnosticEvent, error) { return t.UnsafeMeta.GetDiagnosticEvents() } + +func (t *LedgerTransaction) ID() int64 { + return toid.New(int32(t.Ledger.LedgerSequence()), int32(t.Index), 0).ToInt64() +} + +func (t *LedgerTransaction) Account() (string, error) { + sourceAccount := t.Envelope.SourceAccount() + providedID := sourceAccount.ToAccountId() + pointerToID := &providedID + + return pointerToID.GetAddress() +} + +func (t *LedgerTransaction) AccountSequence() int64 { + return t.Envelope.SeqNum() +} + +func (t *LedgerTransaction) MaxFee() uint32 { + return t.Envelope.Fee() +} + +func (t *LedgerTransaction) FeeCharged() (int64, bool) { + // Any Soroban Fee Bump transactions before P21 will need the below logic to calculate the correct feeCharged + // Protocol 20 contained a bug where the feeCharged was incorrectly calculated but was fixed for + // Protocol 21 with https://github.com/stellar/stellar-core/issues/4188 + var ok bool + _, ok = t.GetSorobanData() + if ok { + if uint32(t.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) < 21 && t.Envelope.Type == xdr.EnvelopeTypeEnvelopeTypeTxFeeBump { + var resourceFeeRefund int64 + var inclusionFeeCharged int64 + + resourceFeeRefund, ok = t.SorobanResourceFeeRefund() + if !ok { + return 0, false + } + + inclusionFeeCharged, ok = t.SorobanInclusionFeeCharged() + if !ok { + return 0, false + } + + return int64(t.Result.Result.FeeCharged) - resourceFeeRefund + inclusionFeeCharged, true + } + } + + return int64(t.Result.Result.FeeCharged), true + +} + +func (t *LedgerTransaction) OperationCount() uint32 { + return uint32(len(t.Envelope.Operations())) +} + +func (t *LedgerTransaction) Memo() string { + memoObject := t.Envelope.Memo() + memoContents := "" + switch xdr.MemoType(memoObject.Type) { + case xdr.MemoTypeMemoText: + memoContents = memoObject.MustText() + case xdr.MemoTypeMemoId: + memoContents = strconv.FormatUint(uint64(memoObject.MustId()), 10) + case xdr.MemoTypeMemoHash: + hash := memoObject.MustHash() + memoContents = base64.StdEncoding.EncodeToString(hash[:]) + case xdr.MemoTypeMemoReturn: + hash := memoObject.MustRetHash() + memoContents = base64.StdEncoding.EncodeToString(hash[:]) + } + + return memoContents +} + +func (t *LedgerTransaction) MemoType() string { + memoObject := t.Envelope.Memo() + return memoObject.Type.String() +} + +func (t *LedgerTransaction) TimeBounds() (string, error) { + timeBounds := t.Envelope.TimeBounds() + if timeBounds == nil { + return "", nil + } + + if timeBounds.MaxTime < timeBounds.MinTime && timeBounds.MaxTime != 0 { + return "", fmt.Errorf("the max time is earlier than the min time") + } + + if timeBounds.MaxTime == 0 { + return fmt.Sprintf("[%d,)", timeBounds.MinTime), nil + } + + return fmt.Sprintf("[%d,%d)", timeBounds.MinTime, timeBounds.MaxTime), nil +} + +func (t *LedgerTransaction) LedgerBounds() (string, bool) { + ledgerBounds := t.Envelope.LedgerBounds() + if ledgerBounds == nil { + return "", false + } + + return fmt.Sprintf("[%d,%d)", int64(ledgerBounds.MinLedger), int64(ledgerBounds.MaxLedger)), true + +} + +func (t *LedgerTransaction) MinSequence() (int64, bool) { + minSeqNum := t.Envelope.MinSeqNum() + if minSeqNum == nil { + return 0, false + } + + return *minSeqNum, true +} + +func (t *LedgerTransaction) MinSequenceAge() (int64, bool) { + minSequenceAge := t.Envelope.MinSeqAge() + if minSequenceAge == nil { + return 0, false + } + + return int64(*minSequenceAge), true +} + +func (t *LedgerTransaction) MinSequenceLedgerGap() (int64, bool) { + minSequenceLedgerGap := t.Envelope.MinSeqLedgerGap() + if minSequenceLedgerGap == nil { + return 0, false + } + + return int64(*minSequenceLedgerGap), true +} + +func (t *LedgerTransaction) GetSorobanData() (xdr.SorobanTransactionData, bool) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + return t.Envelope.V1.Tx.Ext.GetSorobanData() + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + return t.Envelope.FeeBump.Tx.InnerTx.V1.Tx.Ext.GetSorobanData() + default: + return xdr.SorobanTransactionData{}, false + } +} + +func (t *LedgerTransaction) SorobanResourceFee() (int64, bool) { + sorobanData, ok := t.GetSorobanData() + if !ok { + return 0, false + } + + return int64(sorobanData.ResourceFee), true +} + +func (t *LedgerTransaction) SorobanResourcesInstructions() (uint32, bool) { + sorobanData, ok := t.GetSorobanData() + if !ok { + return 0, false + } + + return uint32(sorobanData.Resources.Instructions), true +} + +func (t *LedgerTransaction) SorobanResourcesReadBytes() (uint32, bool) { + sorobanData, ok := t.GetSorobanData() + if !ok { + return 0, false + } + + return uint32(sorobanData.Resources.ReadBytes), true +} + +func (t *LedgerTransaction) SorobanResourcesWriteBytes() (uint32, bool) { + sorobanData, ok := t.GetSorobanData() + if !ok { + return 0, false + } + + return uint32(sorobanData.Resources.WriteBytes), true +} + +func (t *LedgerTransaction) InclusionFeeBid() (int64, bool) { + resourceFee, ok := t.SorobanResourceFee() + if !ok { + return 0, false + } + + return int64(t.Envelope.Fee()) - resourceFee, true +} + +func (t *LedgerTransaction) FeeAccountAddress() (string, bool) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + sourceAccount := t.Envelope.SourceAccount() + feeAccountAddress := sourceAccount.Address() + return feeAccountAddress, true + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + feeBumpAccount := t.Envelope.FeeBumpAccount() + feeAccountAddress := feeBumpAccount.Address() + return feeAccountAddress, true + default: + return "", false + } +} + +func (t *LedgerTransaction) SorobanInclusionFeeCharged() (int64, bool) { + resourceFee, ok := t.SorobanResourceFee() + if !ok { + return 0, false + } + + feeAccountAddress, ok := t.FeeAccountAddress() + if !ok { + return 0, false + } + + accountBalanceStart, accountBalanceEnd := getAccountBalanceFromLedgerEntryChanges(t.FeeChanges, feeAccountAddress) + initialFeeCharged := accountBalanceStart - accountBalanceEnd + + return initialFeeCharged - resourceFee, true +} + +func getAccountBalanceFromLedgerEntryChanges(changes xdr.LedgerEntryChanges, sourceAccountAddress string) (int64, int64) { + var accountBalanceStart int64 + var accountBalanceEnd int64 + + for _, change := range changes { + switch change.Type { + case xdr.LedgerEntryChangeTypeLedgerEntryUpdated: + accountEntry, ok := change.Updated.Data.GetAccount() + if !ok { + continue + } + + if accountEntry.AccountId.Address() == sourceAccountAddress { + accountBalanceEnd = int64(accountEntry.Balance) + } + case xdr.LedgerEntryChangeTypeLedgerEntryState: + accountEntry, ok := change.State.Data.GetAccount() + if !ok { + continue + } + + if accountEntry.AccountId.Address() == sourceAccountAddress { + accountBalanceStart = int64(accountEntry.Balance) + } + } + } + + return accountBalanceStart, accountBalanceEnd +} + +func (t *LedgerTransaction) SorobanResourceFeeRefund() (int64, bool) { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return 0, false + } + + feeAccountAddress, ok := t.FeeAccountAddress() + if !ok { + return 0, false + } + + accountBalanceStart, accountBalanceEnd := getAccountBalanceFromLedgerEntryChanges(meta.TxChangesAfter, feeAccountAddress) + + return accountBalanceEnd - accountBalanceStart, true + +} + +func (t *LedgerTransaction) SorobanTotalNonRefundableResourceFeeCharged() (int64, bool) { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return 0, false + } + + switch meta.SorobanMeta.Ext.V { + case 1: + return int64(meta.SorobanMeta.Ext.V1.TotalNonRefundableResourceFeeCharged), true + default: + return 0, false + } +} + +func (t *LedgerTransaction) SorobanTotalRefundableResourceFeeCharged() (int64, bool) { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return 0, false + } + + switch meta.SorobanMeta.Ext.V { + case 1: + return int64(meta.SorobanMeta.Ext.V1.TotalRefundableResourceFeeCharged), true + default: + return 0, false + } +} + +func (t *LedgerTransaction) SorobanRentFeeCharged() (int64, bool) { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return 0, false + } + + switch meta.SorobanMeta.Ext.V { + case 1: + return int64(meta.SorobanMeta.Ext.V1.RentFeeCharged), true + default: + return 0, false + } +} + +func (t *LedgerTransaction) ResultCode() string { + return t.Result.Result.Result.Code.String() +} + +func (t *LedgerTransaction) Signers() (signers []string, err error) { + if t.Envelope.IsFeeBump() { + return getTxSigners(t.Envelope.FeeBump.Signatures) + } + + return getTxSigners(t.Envelope.Signatures()) +} + +func getTxSigners(xdrSignatures []xdr.DecoratedSignature) ([]string, error) { + signers := make([]string, len(xdrSignatures)) + + for i, sig := range xdrSignatures { + signerAccount, err := strkey.Encode(strkey.VersionByteAccountID, sig.Signature) + if err != nil { + return nil, err + } + signers[i] = signerAccount + } + + return signers, nil +} + +func (t *LedgerTransaction) AccountMuxed() (string, bool) { + sourceAccount := t.Envelope.SourceAccount() + if sourceAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return "", false + } + + return sourceAccount.Address(), true + +} + +func (t *LedgerTransaction) FeeAccount() (string, bool) { + if !t.Envelope.IsFeeBump() { + return "", false + } + + feeBumpAccount := t.Envelope.FeeBumpAccount() + feeAccount := feeBumpAccount.ToAccountId() + + return feeAccount.Address(), true + +} + +func (t *LedgerTransaction) FeeAccountMuxed() (string, bool) { + if !t.Envelope.IsFeeBump() { + return "", false + } + + feeBumpAccount := t.Envelope.FeeBumpAccount() + if feeBumpAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return "", false + } + + return feeBumpAccount.Address(), true +} + +func (t *LedgerTransaction) InnerTransactionHash() (string, bool) { + if !t.Envelope.IsFeeBump() { + return "", false + } + + innerHash := t.Result.InnerHash() + + return hex.EncodeToString(innerHash[:]), true +} + +func (t *LedgerTransaction) NewMaxFee() (uint32, bool) { + if !t.Envelope.IsFeeBump() { + return 0, false + } + + return uint32(t.Envelope.FeeBumpFee()), true +} + +func (t *LedgerTransaction) Successful() bool { + return t.Result.Successful() +} diff --git a/ingest/ledger_transaction_test.go b/ingest/ledger_transaction_test.go index ced92e6918..3a2773fa88 100644 --- a/ingest/ledger_transaction_test.go +++ b/ingest/ledger_transaction_test.go @@ -811,3 +811,274 @@ func TestChangeAccountChangedExceptSignersNoChanges(t *testing.T) { assert.NotNil(t, change.Post.Data.Account.Signers) assert.Len(t, change.Post.Data.Account.Signers, 1) } + +func TestTransactionHelperFunctions(t *testing.T) { + transaction := transactionHelperFunctionsTestInput() + + assert.Equal(t, int64(131335723340009472), transaction.ID()) + + var err error + var ok bool + var account string + account, err = transaction.Account() + assert.Equal(t, nil, err) + assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", account) + + assert.Equal(t, int64(30578981), transaction.AccountSequence()) + assert.Equal(t, uint32(4560), transaction.MaxFee()) + + var feeCharged int64 + feeCharged, ok = transaction.FeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(789), feeCharged) + + assert.Equal(t, uint32(3), transaction.OperationCount()) + assert.Equal(t, "test memo", transaction.Memo()) + assert.Equal(t, "MemoTypeMemoText", transaction.MemoType()) + + var timeBounds string + timeBounds, err = transaction.TimeBounds() + assert.Equal(t, nil, err) + assert.Equal(t, "[1,10)", timeBounds) + + var ledgerBounds string + ledgerBounds, ok = transaction.LedgerBounds() + assert.Equal(t, true, ok) + assert.Equal(t, "[2,20)", ledgerBounds) + + var minSequence int64 + minSequence, ok = transaction.MinSequence() + assert.Equal(t, true, ok) + assert.Equal(t, int64(123), minSequence) + + var minSequenceAge int64 + minSequenceAge, ok = transaction.MinSequenceAge() + assert.Equal(t, true, ok) + assert.Equal(t, int64(456), minSequenceAge) + + var minSequenceLedgerGap int64 + minSequenceLedgerGap, ok = transaction.MinSequenceLedgerGap() + assert.Equal(t, true, ok) + assert.Equal(t, int64(789), minSequenceLedgerGap) + + var sorobanResourceFee int64 + sorobanResourceFee, ok = transaction.SorobanResourceFee() + assert.Equal(t, true, ok) + assert.Equal(t, int64(1234), sorobanResourceFee) + + var sorobanResourcesInstructions uint32 + sorobanResourcesInstructions, ok = transaction.SorobanResourcesInstructions() + assert.Equal(t, true, ok) + assert.Equal(t, uint32(123), sorobanResourcesInstructions) + + var sorobanResourcesReadBytes uint32 + sorobanResourcesReadBytes, ok = transaction.SorobanResourcesReadBytes() + assert.Equal(t, true, ok) + assert.Equal(t, uint32(456), sorobanResourcesReadBytes) + + var sorobanResourcesWriteBytes uint32 + sorobanResourcesWriteBytes, ok = transaction.SorobanResourcesWriteBytes() + assert.Equal(t, true, ok) + assert.Equal(t, uint32(789), sorobanResourcesWriteBytes) + + var inclusionFeeBid int64 + inclusionFeeBid, ok = transaction.InclusionFeeBid() + assert.Equal(t, true, ok) + assert.Equal(t, int64(3326), inclusionFeeBid) + + var sorobanInclusionFeeCharged int64 + sorobanInclusionFeeCharged, ok = transaction.SorobanInclusionFeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(-1234), sorobanInclusionFeeCharged) + + var sorobanResourceFeeRefund int64 + sorobanResourceFeeRefund, ok = transaction.SorobanResourceFeeRefund() + assert.Equal(t, true, ok) + assert.Equal(t, int64(0), sorobanResourceFeeRefund) + + var sorobanTotalNonRefundableResourceFeeCharged int64 + sorobanTotalNonRefundableResourceFeeCharged, ok = transaction.SorobanTotalNonRefundableResourceFeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(321), sorobanTotalNonRefundableResourceFeeCharged) + + var sorobanTotalRefundableResourceFeeCharged int64 + sorobanTotalRefundableResourceFeeCharged, ok = transaction.SorobanTotalRefundableResourceFeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(123), sorobanTotalRefundableResourceFeeCharged) + + var sorobanRentFeeCharged int64 + sorobanRentFeeCharged, ok = transaction.SorobanRentFeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(456), sorobanRentFeeCharged) + + assert.Equal(t, "TransactionResultCodeTxSuccess", transaction.ResultCode()) + + var signers []string + signers, err = transaction.Signers() + assert.Equal(t, nil, err) + assert.Equal(t, []string{"GAISFR7R"}, signers) + + var accountMuxed string + accountMuxed, ok = transaction.AccountMuxed() + assert.Equal(t, true, ok) + assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", accountMuxed) + + var feeAccount string + feeAccount, ok = transaction.FeeAccount() + assert.Equal(t, false, ok) + assert.Equal(t, "", feeAccount) + + var feeAccountMuxed string + feeAccountMuxed, ok = transaction.FeeAccountMuxed() + assert.Equal(t, false, ok) + assert.Equal(t, "", feeAccountMuxed) + + var innerTransactionHash string + innerTransactionHash, ok = transaction.InnerTransactionHash() + assert.Equal(t, false, ok) + assert.Equal(t, "", innerTransactionHash) + + var newMaxFee uint32 + newMaxFee, ok = transaction.NewMaxFee() + assert.Equal(t, false, ok) + assert.Equal(t, uint32(0), newMaxFee) + + assert.Equal(t, true, transaction.Successful()) +} + +func transactionHelperFunctionsTestInput() LedgerTransaction { + ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) + muxedAccount := xdr.MuxedAccount{ + Type: 256, + Ed25519: &ed25519, + Med25519: &xdr.MuxedAccountMed25519{ + Id: xdr.Uint64(123), + Ed25519: ed25519, + }, + } + + memoText := "test memo" + minSeqNum := xdr.SequenceNumber(123) + + transaction := LedgerTransaction{ + Index: 1, + Envelope: xdr.TransactionEnvelope{ + Type: xdr.EnvelopeTypeEnvelopeTypeTx, + V1: &xdr.TransactionV1Envelope{ + Signatures: []xdr.DecoratedSignature{ + { + Signature: []byte{0x11, 0x22}, + }, + }, + Tx: xdr.Transaction{ + SourceAccount: muxedAccount, + SeqNum: xdr.SequenceNumber(30578981), + Fee: xdr.Uint32(4560), + Operations: []xdr.Operation{ + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + }, + Memo: xdr.Memo{ + Type: xdr.MemoTypeMemoText, + Text: &memoText, + }, + Cond: xdr.Preconditions{ + Type: 2, + V2: &xdr.PreconditionsV2{ + TimeBounds: &xdr.TimeBounds{ + MinTime: xdr.TimePoint(1), + MaxTime: xdr.TimePoint(10), + }, + LedgerBounds: &xdr.LedgerBounds{ + MinLedger: 2, + MaxLedger: 20, + }, + MinSeqNum: &minSeqNum, + MinSeqAge: 456, + MinSeqLedgerGap: 789, + }, + }, + Ext: xdr.TransactionExt{ + V: 1, + SorobanData: &xdr.SorobanTransactionData{ + Resources: xdr.SorobanResources{ + Instructions: 123, + ReadBytes: 456, + WriteBytes: 789, + }, + ResourceFee: 1234, + }, + }, + }, + }, + }, + Result: xdr.TransactionResultPair{ + TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, + Result: xdr.TransactionResult{ + FeeCharged: xdr.Int64(789), + Result: xdr.TransactionResultResult{ + Code: 0, + }, + }, + }, + FeeChanges: xdr.LedgerEntryChanges{ + { + Type: xdr.LedgerEntryChangeTypeLedgerEntryState, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: xdr.LedgerEntryTypeAccount, + Account: &xdr.AccountEntry{ + AccountId: xdr.AccountId{ + Type: 0, + Ed25519: &ed25519, + }, + Balance: 1000, + }, + }, + }, + }, + {}, + }, + UnsafeMeta: xdr.TransactionMeta{ + V: 3, + V3: &xdr.TransactionMetaV3{ + TxChangesAfter: xdr.LedgerEntryChanges{}, + SorobanMeta: &xdr.SorobanTransactionMeta{ + Ext: xdr.SorobanTransactionMetaExt{ + V: 1, + V1: &xdr.SorobanTransactionMetaExtV1{ + TotalNonRefundableResourceFeeCharged: 321, + TotalRefundableResourceFeeCharged: 123, + RentFeeCharged: 456, + }, + }, + }, + }, + }, + LedgerVersion: 22, + Ledger: xdr.LedgerCloseMeta{ + V: 1, + V1: &xdr.LedgerCloseMetaV1{ + LedgerHeader: xdr.LedgerHeaderHistoryEntry{ + Header: xdr.LedgerHeader{ + LedgerSeq: 30578981, + LedgerVersion: 22, + }, + }, + }, + }, + Hash: xdr.Hash{}, + } + + return transaction +} From 0b62fe227b9119873d255fed72ad1757049f7417 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 9 Jan 2025 16:59:20 -0500 Subject: [PATCH 13/40] xdrill transaction helper functions --- exp/xdrill/transaction/transaction.go | 359 +++++++++++++++++++++ exp/xdrill/transaction/transaction_test.go | 242 ++++++++++++++ 2 files changed, 601 insertions(+) create mode 100644 exp/xdrill/transaction/transaction.go create mode 100644 exp/xdrill/transaction/transaction_test.go diff --git a/exp/xdrill/transaction/transaction.go b/exp/xdrill/transaction/transaction.go new file mode 100644 index 0000000000..15c1f1a664 --- /dev/null +++ b/exp/xdrill/transaction/transaction.go @@ -0,0 +1,359 @@ +package transaction + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + "strconv" + + "github.com/stellar/go/exp/xdrill/ledger" + "github.com/stellar/go/exp/xdrill/utils" + "github.com/stellar/go/ingest" + "github.com/stellar/go/toid" + "github.com/stellar/go/xdr" +) + +func Hash(t ingest.LedgerTransaction) string { + return utils.HashToHexString(t.Result.TransactionHash) +} + +func Index(t ingest.LedgerTransaction) uint32 { + return uint32(t.Index) +} + +func ID(t ingest.LedgerTransaction, l xdr.LedgerCloseMeta) int64 { + return toid.New(int32(ledger.Sequence(l)), int32(t.Index), 0).ToInt64() +} + +func Account(t ingest.LedgerTransaction) (string, error) { + return utils.GetAccountAddressFromMuxedAccount(t.Envelope.SourceAccount()) +} + +func AccountSequence(t ingest.LedgerTransaction) int64 { + return t.Envelope.SeqNum() +} + +func MaxFee(t ingest.LedgerTransaction) uint32 { + return t.Envelope.Fee() +} + +func FeeCharged(t ingest.LedgerTransaction, l xdr.LedgerCloseMeta) *int64 { + // Any Soroban Fee Bump transactions before P21 will need the below logic to calculate the correct feeCharged + // Protocol 20 contained a bug where the feeCharged was incorrectly calculated but was fixed for + // Protocol 21 with https://github.com/stellar/stellar-core/issues/4188 + var result int64 + _, ok := getSorobanData(t) + if ok { + if ledger.LedgerVersion(l) < 21 && t.Envelope.Type == xdr.EnvelopeTypeEnvelopeTypeTxFeeBump { + resourceFeeRefund := SorobanResourceFeeRefund(t) + inclusionFeeCharged := SorobanInclusionFeeCharged(t) + result = int64(t.Result.Result.FeeCharged) - *resourceFeeRefund + *inclusionFeeCharged + return &result + } + } + + result = int64(t.Result.Result.FeeCharged) + + return &result +} + +func OperationCount(t ingest.LedgerTransaction) uint32 { + return uint32(len(t.Envelope.Operations())) +} + +func Memo(t ingest.LedgerTransaction) string { + memoObject := t.Envelope.Memo() + memoContents := "" + switch xdr.MemoType(memoObject.Type) { + case xdr.MemoTypeMemoText: + memoContents = memoObject.MustText() + case xdr.MemoTypeMemoId: + memoContents = strconv.FormatUint(uint64(memoObject.MustId()), 10) + case xdr.MemoTypeMemoHash: + hash := memoObject.MustHash() + memoContents = base64.StdEncoding.EncodeToString(hash[:]) + case xdr.MemoTypeMemoReturn: + hash := memoObject.MustRetHash() + memoContents = base64.StdEncoding.EncodeToString(hash[:]) + } + + return memoContents +} + +func MemoType(t ingest.LedgerTransaction) string { + memoObject := t.Envelope.Memo() + return memoObject.Type.String() +} + +func TimeBounds(t ingest.LedgerTransaction) (*string, error) { + timeBounds := t.Envelope.TimeBounds() + if timeBounds == nil { + return nil, nil + } + + if timeBounds.MaxTime < timeBounds.MinTime && timeBounds.MaxTime != 0 { + return nil, fmt.Errorf("the max time is earlier than the min time") + } + + var result string + if timeBounds.MaxTime == 0 { + result = fmt.Sprintf("[%d,)", timeBounds.MinTime) + return &result, nil + } + + result = fmt.Sprintf("[%d,%d)", timeBounds.MinTime, timeBounds.MaxTime) + + return &result, nil +} + +func LedgerBounds(t ingest.LedgerTransaction) *string { + ledgerBounds := t.Envelope.LedgerBounds() + if ledgerBounds == nil { + return nil + } + + result := fmt.Sprintf("[%d,%d)", int64(ledgerBounds.MinLedger), int64(ledgerBounds.MaxLedger)) + + return &result +} + +func MinSequence(t ingest.LedgerTransaction) *int64 { + return t.Envelope.MinSeqNum() +} + +func MinSequenceAge(t ingest.LedgerTransaction) *int64 { + minSequenceAge := t.Envelope.MinSeqAge() + if minSequenceAge == nil { + return nil + } + + minSequenceAgeInt64 := int64(*minSequenceAge) + return &minSequenceAgeInt64 +} + +func MinSequenceLedgerGap(t ingest.LedgerTransaction) *int64 { + minSequenceLedgerGap := t.Envelope.MinSeqLedgerGap() + result := int64(*minSequenceLedgerGap) + return &result +} + +func getSorobanData(t ingest.LedgerTransaction) (sorobanData xdr.SorobanTransactionData, ok bool) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + return t.Envelope.V1.Tx.Ext.GetSorobanData() + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + return t.Envelope.FeeBump.Tx.InnerTx.V1.Tx.Ext.GetSorobanData() + } + + return +} + +func SorobanResourceFee(t ingest.LedgerTransaction) *int64 { + sorobanData, ok := getSorobanData(t) + if !ok { + return nil + } + + result := int64(sorobanData.ResourceFee) + return &result +} + +func SorobanResourcesInstructions(t ingest.LedgerTransaction) *uint32 { + sorobanData, ok := getSorobanData(t) + if !ok { + return nil + } + + result := uint32(sorobanData.Resources.Instructions) + return &result +} + +func SorobanResourcesReadBytes(t ingest.LedgerTransaction) *uint32 { + sorobanData, ok := getSorobanData(t) + if !ok { + return nil + } + + result := uint32(sorobanData.Resources.ReadBytes) + return &result +} + +func SorobanResourcesWriteBytes(t ingest.LedgerTransaction) *uint32 { + sorobanData, ok := getSorobanData(t) + if !ok { + return nil + } + + result := uint32(sorobanData.Resources.WriteBytes) + return &result +} + +func InclusionFeeBid(t ingest.LedgerTransaction) *int64 { + resourceFee := SorobanResourceFee(t) + if resourceFee == nil { + return nil + } + + result := int64(t.Envelope.Fee()) - *resourceFee + return &result +} + +func getFeeAccountAddress(t ingest.LedgerTransaction) (feeAccountAddress string) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + sourceAccount := t.Envelope.SourceAccount() + feeAccountAddress = sourceAccount.Address() + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + feeBumpAccount := t.Envelope.FeeBumpAccount() + feeAccountAddress = feeBumpAccount.Address() + } + + return +} + +func SorobanInclusionFeeCharged(t ingest.LedgerTransaction) *int64 { + resourceFee := SorobanResourceFee(t) + if resourceFee == nil { + return nil + } + + accountBalanceStart, accountBalanceEnd := utils.GetAccountBalanceFromLedgerEntryChanges(t.FeeChanges, getFeeAccountAddress(t)) + initialFeeCharged := accountBalanceStart - accountBalanceEnd + result := initialFeeCharged - *resourceFee + + return &result +} + +func SorobanResourceFeeRefund(t ingest.LedgerTransaction) *int64 { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return nil + } + + accountBalanceStart, accountBalanceEnd := utils.GetAccountBalanceFromLedgerEntryChanges(meta.TxChangesAfter, getFeeAccountAddress(t)) + result := accountBalanceEnd - accountBalanceStart + + return &result +} + +func SorobanTotalNonRefundableResourceFeeCharged(t ingest.LedgerTransaction) *int64 { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return nil + } + + switch meta.SorobanMeta.Ext.V { + case 1: + result := int64(meta.SorobanMeta.Ext.V1.TotalNonRefundableResourceFeeCharged) + return &result + } + + return nil +} + +func SorobanTotalRefundableResourceFeeCharged(t ingest.LedgerTransaction) *int64 { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return nil + } + + switch meta.SorobanMeta.Ext.V { + case 1: + result := int64(meta.SorobanMeta.Ext.V1.TotalRefundableResourceFeeCharged) + return &result + } + + return nil +} + +func SorobanRentFeeCharged(t ingest.LedgerTransaction) *int64 { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return nil + } + + switch meta.SorobanMeta.Ext.V { + case 1: + result := int64(meta.SorobanMeta.Ext.V1.RentFeeCharged) + return &result + } + + return nil +} + +func ResultCode(t ingest.LedgerTransaction) string { + return t.Result.Result.Result.Code.String() +} + +func Signers(t ingest.LedgerTransaction) (signers []string) { + if t.Envelope.IsFeeBump() { + signers, _ = utils.GetTxSigners(t.Envelope.FeeBump.Signatures) + return + } + + signers, _ = utils.GetTxSigners(t.Envelope.Signatures()) + + return +} + +func AccountMuxed(t ingest.LedgerTransaction) *string { + sourceAccount := t.Envelope.SourceAccount() + if sourceAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return nil + } + + result := sourceAccount.Address() + + return &result +} + +func FeeAccount(t ingest.LedgerTransaction) *string { + if !t.Envelope.IsFeeBump() { + return nil + } + + feeBumpAccount := t.Envelope.FeeBumpAccount() + feeAccount := feeBumpAccount.ToAccountId() + result := feeAccount.Address() + + return &result +} + +func FeeAccountMuxed(t ingest.LedgerTransaction) *string { + if !t.Envelope.IsFeeBump() { + return nil + } + + feeBumpAccount := t.Envelope.FeeBumpAccount() + if feeBumpAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return nil + } + + result := feeBumpAccount.Address() + + return &result +} + +func InnerTransactionHash(t ingest.LedgerTransaction) *string { + if !t.Envelope.IsFeeBump() { + return nil + } + + innerHash := t.Result.InnerHash() + result := hex.EncodeToString(innerHash[:]) + + return &result +} + +func NewMaxFee(t ingest.LedgerTransaction) *uint32 { + if !t.Envelope.IsFeeBump() { + return nil + } + + newMaxFee := uint32(t.Envelope.FeeBumpFee()) + return &newMaxFee +} + +func Successful(t ingest.LedgerTransaction) bool { + return t.Result.Successful() +} diff --git a/exp/xdrill/transaction/transaction_test.go b/exp/xdrill/transaction/transaction_test.go new file mode 100644 index 0000000000..9dc36aa9ef --- /dev/null +++ b/exp/xdrill/transaction/transaction_test.go @@ -0,0 +1,242 @@ +package transaction + +import ( + "testing" + + "github.com/stellar/go/ingest" + "github.com/stellar/go/xdr" + "github.com/stretchr/testify/assert" +) + +func TestTransaction(t *testing.T) { + ledger := ledgerTestInput() + transaction := transactionTestInput() + + assert.Equal(t, "1122330000000000000000000000000000000000000000000000000000000000", Hash(transaction)) + assert.Equal(t, uint32(1), Index(transaction)) + assert.Equal(t, int64(131335723340009472), ID(transaction, ledger)) + + var err error + var account string + account, err = Account(transaction) + assert.Equal(t, nil, err) + assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", account) + + assert.Equal(t, int64(30578981), AccountSequence(transaction)) + assert.Equal(t, uint32(4560), MaxFee(transaction)) + + feeCharged := FeeCharged(transaction, ledger) + assert.Equal(t, int64(789), *feeCharged) + + assert.Equal(t, uint32(3), OperationCount(transaction)) + assert.Equal(t, "test memo", Memo(transaction)) + assert.Equal(t, "MemoTypeMemoText", MemoType(transaction)) + + var timeBounds *string + timeBounds, err = TimeBounds(transaction) + assert.Equal(t, nil, err) + assert.Equal(t, "[1,10)", *timeBounds) + + ledgerBounds := LedgerBounds(transaction) + assert.Equal(t, "[2,20)", *ledgerBounds) + + minSequence := MinSequence(transaction) + assert.Equal(t, int64(123), *minSequence) + + minSequenceAge := MinSequenceAge(transaction) + assert.Equal(t, int64(456), *minSequenceAge) + + minSequenceLedgerGap := MinSequenceLedgerGap(transaction) + assert.Equal(t, int64(789), *minSequenceLedgerGap) + + sorobanResourceFee := SorobanResourceFee(transaction) + assert.Equal(t, int64(1234), *sorobanResourceFee) + + sorobanResourcesInstructions := SorobanResourcesInstructions(transaction) + assert.Equal(t, uint32(123), *sorobanResourcesInstructions) + + sorobanResourcesReadBytes := SorobanResourcesReadBytes(transaction) + assert.Equal(t, uint32(456), *sorobanResourcesReadBytes) + + sorobanResourcesWriteBytes := SorobanResourcesWriteBytes(transaction) + assert.Equal(t, uint32(789), *sorobanResourcesWriteBytes) + + inclusionFeeBid := InclusionFeeBid(transaction) + assert.Equal(t, int64(3326), *inclusionFeeBid) + + sorobanInclusionFeeCharged := SorobanInclusionFeeCharged(transaction) + assert.Equal(t, int64(-1234), *sorobanInclusionFeeCharged) + + sorobanResourceFeeRefund := SorobanResourceFeeRefund(transaction) + assert.Equal(t, int64(0), *sorobanResourceFeeRefund) + + sorobanTotalNonRefundableResourceFeeCharged := SorobanTotalNonRefundableResourceFeeCharged(transaction) + assert.Equal(t, int64(321), *sorobanTotalNonRefundableResourceFeeCharged) + + sorobanTotalRefundableResourceFeeCharged := SorobanTotalRefundableResourceFeeCharged(transaction) + assert.Equal(t, int64(123), *sorobanTotalRefundableResourceFeeCharged) + + sorobanRentFeeCharged := SorobanRentFeeCharged(transaction) + assert.Equal(t, int64(456), *sorobanRentFeeCharged) + + assert.Equal(t, "TransactionResultCodeTxSuccess", ResultCode(transaction)) + assert.Equal(t, []string{"GAISFR7R"}, Signers(transaction)) + + accountMuxed := AccountMuxed(transaction) + assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", *accountMuxed) + + feeAccount := FeeAccount(transaction) + assert.Equal(t, (*string)(nil), feeAccount) + + feeAccountMuxed := FeeAccountMuxed(transaction) + assert.Equal(t, (*string)(nil), feeAccountMuxed) + + innerTransactionHash := InnerTransactionHash(transaction) + assert.Equal(t, (*string)(nil), innerTransactionHash) + + assert.Equal(t, (*uint32)(nil), NewMaxFee(transaction)) + assert.Equal(t, true, Successful(transaction)) +} + +func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { + lcm = xdr.LedgerCloseMeta{ + V: 1, + V1: &xdr.LedgerCloseMetaV1{ + LedgerHeader: xdr.LedgerHeaderHistoryEntry{ + Header: xdr.LedgerHeader{ + LedgerSeq: 30578981, + LedgerVersion: 22, + }, + }, + }, + } + + return lcm +} + +func transactionTestInput() ingest.LedgerTransaction { + ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) + muxedAccount := xdr.MuxedAccount{ + Type: 256, + Ed25519: &ed25519, + Med25519: &xdr.MuxedAccountMed25519{ + Id: xdr.Uint64(123), + Ed25519: ed25519, + }, + } + + memoText := "test memo" + minSeqNum := xdr.SequenceNumber(123) + + transaction := ingest.LedgerTransaction{ + Index: 1, + Envelope: xdr.TransactionEnvelope{ + Type: xdr.EnvelopeTypeEnvelopeTypeTx, + V1: &xdr.TransactionV1Envelope{ + Signatures: []xdr.DecoratedSignature{ + { + Signature: []byte{0x11, 0x22}, + }, + }, + Tx: xdr.Transaction{ + SourceAccount: muxedAccount, + SeqNum: xdr.SequenceNumber(30578981), + Fee: xdr.Uint32(4560), + Operations: []xdr.Operation{ + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + }, + Memo: xdr.Memo{ + Type: xdr.MemoTypeMemoText, + Text: &memoText, + }, + Cond: xdr.Preconditions{ + Type: 2, + V2: &xdr.PreconditionsV2{ + TimeBounds: &xdr.TimeBounds{ + MinTime: xdr.TimePoint(1), + MaxTime: xdr.TimePoint(10), + }, + LedgerBounds: &xdr.LedgerBounds{ + MinLedger: 2, + MaxLedger: 20, + }, + MinSeqNum: &minSeqNum, + MinSeqAge: 456, + MinSeqLedgerGap: 789, + }, + }, + Ext: xdr.TransactionExt{ + V: 1, + SorobanData: &xdr.SorobanTransactionData{ + Resources: xdr.SorobanResources{ + Instructions: 123, + ReadBytes: 456, + WriteBytes: 789, + }, + ResourceFee: 1234, + }, + }, + }, + }, + }, + Result: xdr.TransactionResultPair{ + TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, + Result: xdr.TransactionResult{ + FeeCharged: xdr.Int64(789), + Result: xdr.TransactionResultResult{ + Code: 0, + }, + }, + }, + FeeChanges: xdr.LedgerEntryChanges{ + { + Type: xdr.LedgerEntryChangeTypeLedgerEntryState, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: xdr.LedgerEntryTypeAccount, + Account: &xdr.AccountEntry{ + AccountId: xdr.AccountId{ + Type: 0, + Ed25519: &ed25519, + }, + Balance: 1000, + }, + }, + }, + }, + {}, + }, + UnsafeMeta: xdr.TransactionMeta{ + V: 3, + V3: &xdr.TransactionMetaV3{ + TxChangesAfter: xdr.LedgerEntryChanges{}, + SorobanMeta: &xdr.SorobanTransactionMeta{ + Ext: xdr.SorobanTransactionMetaExt{ + V: 1, + V1: &xdr.SorobanTransactionMetaExtV1{ + TotalNonRefundableResourceFeeCharged: 321, + TotalRefundableResourceFeeCharged: 123, + RentFeeCharged: 456, + }, + }, + }, + }, + }, + LedgerVersion: 22, + Ledger: xdr.LedgerCloseMeta{}, + Hash: xdr.Hash{}, + } + + return transaction +} From cce0cfe25ab0eb263a3802de826e33661c70b08b Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 14:42:51 -0700 Subject: [PATCH 14/40] Move xdrill ledger functions to ingest as subpackage --- ingest/ledger/ledger.go | 88 ++++++++++++++++++++++++++++++++++++ ingest/ledger/ledger_test.go | 39 ++++++++++++++-- 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go index c37cb50b3b..07f5e8c59d 100644 --- a/ingest/ledger/ledger.go +++ b/ingest/ledger/ledger.go @@ -8,6 +8,7 @@ import ( "github.com/stellar/go/xdr" ) +<<<<<<< HEAD func Sequence(l xdr.LedgerCloseMeta) uint32 { return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq) } @@ -58,6 +59,62 @@ func LedgerVersion(l xdr.LedgerCloseMeta) uint32 { func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) (int64, bool) { lcmV1, ok := l.GetV1() +======= +type Ledger struct { + Ledger xdr.LedgerCloseMeta +} + +func (l Ledger) Sequence() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) +} + +func (l Ledger) ID() int64 { + return toid.New(int32(l.Ledger.LedgerSequence()), 0, 0).ToInt64() +} + +func (l Ledger) Hash() string { + return l.Ledger.LedgerHeaderHistoryEntry().Hash.HexString() +} + +func (l Ledger) PreviousHash() string { + return l.Ledger.PreviousLedgerHash().HexString() +} + +func (l Ledger) CloseTime() int64 { + return l.Ledger.LedgerCloseTime() +} + +func (l Ledger) ClosedAt() time.Time { + return time.Unix(l.Ledger.LedgerCloseTime(), 0).UTC() +} + +func (l Ledger) TotalCoins() int64 { + return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) +} + +func (l Ledger) FeePool() int64 { + return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.FeePool) +} + +func (l Ledger) BaseFee() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseFee) +} + +func (l Ledger) BaseReserve() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) +} + +func (l Ledger) MaxTxSetSize() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) +} + +func (l Ledger) LedgerVersion() uint32 { + return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) +} + +func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { + lcmV1, ok := l.Ledger.GetV1() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) if !ok { return 0, false } @@ -70,8 +127,13 @@ func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) (int64, bool) { return int64(extV1.SorobanFeeWrite1Kb), true } +<<<<<<< HEAD func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) { lcmV1, ok := l.GetV1() +======= +func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { + lcmV1, ok := l.Ledger.GetV1() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) if !ok { return 0, false } @@ -79,8 +141,13 @@ func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) { return uint64(lcmV1.TotalByteSizeOfBucketList), true } +<<<<<<< HEAD func NodeID(l xdr.LedgerCloseMeta) (string, bool) { LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +======= +func (l Ledger) NodeID() (string, bool) { + LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) if !ok { return "", false @@ -88,8 +155,13 @@ func NodeID(l xdr.LedgerCloseMeta) (string, bool) { return LedgerCloseValueSignature.NodeId.GetAddress() } +<<<<<<< HEAD func Signature(l xdr.LedgerCloseMeta) (string, bool) { LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +======= +func (l Ledger) Signature() (string, bool) { + LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) if !ok { return "", false } @@ -98,11 +170,19 @@ func Signature(l xdr.LedgerCloseMeta) (string, bool) { } // Add docstring to larger, more complicated functions +<<<<<<< HEAD func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32, ok bool) { var results []xdr.TransactionResultMeta transactions := l.TransactionEnvelopes() results = l.TxProcessing() +======= +func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) { + var results []xdr.TransactionResultMeta + + transactions := l.Ledger.TransactionEnvelopes() + results = l.Ledger.TxProcessing() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) txCount := len(transactions) if txCount != len(results) { return 0, 0, false @@ -120,11 +200,19 @@ func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int } // Add docstring to larger, more complicated functions +<<<<<<< HEAD func OperationCounts(l xdr.LedgerCloseMeta) (operationCount, txSetOperationCount int32, ok bool) { var results []xdr.TransactionResultMeta transactions := l.TransactionEnvelopes() results = l.TxProcessing() +======= +func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) { + var results []xdr.TransactionResultMeta + + transactions := l.Ledger.TransactionEnvelopes() + results = l.Ledger.TxProcessing() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) for i, result := range results { operations := transactions[i].Operations() diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index 2345d46792..50e6eea12f 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -11,8 +11,11 @@ import ( ) func TestLedger(t *testing.T) { - ledger := ledgerTestInput() + ledger := Ledger{ + Ledger: ledgerTestInput(), + } +<<<<<<< HEAD assert.Equal(t, uint32(30578981), Sequence(ledger)) assert.Equal(t, int64(131335723340005376), ID(ledger)) assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger)) @@ -29,32 +32,62 @@ func TestLedger(t *testing.T) { var ok bool var freeWrite int64 freeWrite, ok = SorobanFeeWrite1Kb(ledger) +======= + assert.Equal(t, uint32(30578981), ledger.Sequence()) + assert.Equal(t, int64(131335723340005376), ledger.ID()) + assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", ledger.Hash()) + assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", ledger.PreviousHash()) + assert.Equal(t, int64(1594584547), ledger.CloseTime()) + assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ledger.ClosedAt()) + assert.Equal(t, int64(1054439020873472865), ledger.TotalCoins()) + assert.Equal(t, int64(18153766209161), ledger.FeePool()) + assert.Equal(t, uint32(100), ledger.BaseFee()) + assert.Equal(t, uint32(5000000), ledger.BaseReserve()) + assert.Equal(t, uint32(1000), ledger.MaxTxSetSize()) + assert.Equal(t, uint32(13), ledger.LedgerVersion()) + + var ok bool + var freeWrite int64 + freeWrite, ok = ledger.SorobanFeeWrite1Kb() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) assert.Equal(t, true, ok) assert.Equal(t, int64(12), freeWrite) var bucketSize uint64 +<<<<<<< HEAD bucketSize, ok = TotalByteSizeOfBucketList(ledger) +======= + bucketSize, ok = ledger.TotalByteSizeOfBucketList() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) assert.Equal(t, true, ok) assert.Equal(t, uint64(56), bucketSize) var nodeID string +<<<<<<< HEAD nodeID, ok = NodeID(ledger) +======= + nodeID, ok = ledger.NodeID() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) assert.Equal(t, true, ok) assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) var signature string +<<<<<<< HEAD signature, ok = Signature(ledger) +======= + signature, ok = ledger.Signature() +>>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) assert.Equal(t, true, ok) assert.Equal(t, "9g==", signature) var success int32 var failed int32 - success, failed, ok = TransactionCounts(ledger) + success, failed, ok = ledger.TransactionCounts() assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) - success, failed, ok = OperationCounts(ledger) + success, failed, ok = ledger.OperationCounts() assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(13), failed) From dab3bd90a686702edc818c82a9c47dabd610d218 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 15:24:27 -0700 Subject: [PATCH 15/40] Move transaction helper functions to ingest --- exp/xdrill/transaction/transaction.go | 359 ------------------- exp/xdrill/transaction/transaction_test.go | 242 ------------- ingest/ledger_transaction.go | 398 +++++++++++++++++++++ ingest/ledger_transaction_test.go | 271 ++++++++++++++ 4 files changed, 669 insertions(+), 601 deletions(-) delete mode 100644 exp/xdrill/transaction/transaction.go delete mode 100644 exp/xdrill/transaction/transaction_test.go diff --git a/exp/xdrill/transaction/transaction.go b/exp/xdrill/transaction/transaction.go deleted file mode 100644 index 15c1f1a664..0000000000 --- a/exp/xdrill/transaction/transaction.go +++ /dev/null @@ -1,359 +0,0 @@ -package transaction - -import ( - "encoding/base64" - "encoding/hex" - "fmt" - "strconv" - - "github.com/stellar/go/exp/xdrill/ledger" - "github.com/stellar/go/exp/xdrill/utils" - "github.com/stellar/go/ingest" - "github.com/stellar/go/toid" - "github.com/stellar/go/xdr" -) - -func Hash(t ingest.LedgerTransaction) string { - return utils.HashToHexString(t.Result.TransactionHash) -} - -func Index(t ingest.LedgerTransaction) uint32 { - return uint32(t.Index) -} - -func ID(t ingest.LedgerTransaction, l xdr.LedgerCloseMeta) int64 { - return toid.New(int32(ledger.Sequence(l)), int32(t.Index), 0).ToInt64() -} - -func Account(t ingest.LedgerTransaction) (string, error) { - return utils.GetAccountAddressFromMuxedAccount(t.Envelope.SourceAccount()) -} - -func AccountSequence(t ingest.LedgerTransaction) int64 { - return t.Envelope.SeqNum() -} - -func MaxFee(t ingest.LedgerTransaction) uint32 { - return t.Envelope.Fee() -} - -func FeeCharged(t ingest.LedgerTransaction, l xdr.LedgerCloseMeta) *int64 { - // Any Soroban Fee Bump transactions before P21 will need the below logic to calculate the correct feeCharged - // Protocol 20 contained a bug where the feeCharged was incorrectly calculated but was fixed for - // Protocol 21 with https://github.com/stellar/stellar-core/issues/4188 - var result int64 - _, ok := getSorobanData(t) - if ok { - if ledger.LedgerVersion(l) < 21 && t.Envelope.Type == xdr.EnvelopeTypeEnvelopeTypeTxFeeBump { - resourceFeeRefund := SorobanResourceFeeRefund(t) - inclusionFeeCharged := SorobanInclusionFeeCharged(t) - result = int64(t.Result.Result.FeeCharged) - *resourceFeeRefund + *inclusionFeeCharged - return &result - } - } - - result = int64(t.Result.Result.FeeCharged) - - return &result -} - -func OperationCount(t ingest.LedgerTransaction) uint32 { - return uint32(len(t.Envelope.Operations())) -} - -func Memo(t ingest.LedgerTransaction) string { - memoObject := t.Envelope.Memo() - memoContents := "" - switch xdr.MemoType(memoObject.Type) { - case xdr.MemoTypeMemoText: - memoContents = memoObject.MustText() - case xdr.MemoTypeMemoId: - memoContents = strconv.FormatUint(uint64(memoObject.MustId()), 10) - case xdr.MemoTypeMemoHash: - hash := memoObject.MustHash() - memoContents = base64.StdEncoding.EncodeToString(hash[:]) - case xdr.MemoTypeMemoReturn: - hash := memoObject.MustRetHash() - memoContents = base64.StdEncoding.EncodeToString(hash[:]) - } - - return memoContents -} - -func MemoType(t ingest.LedgerTransaction) string { - memoObject := t.Envelope.Memo() - return memoObject.Type.String() -} - -func TimeBounds(t ingest.LedgerTransaction) (*string, error) { - timeBounds := t.Envelope.TimeBounds() - if timeBounds == nil { - return nil, nil - } - - if timeBounds.MaxTime < timeBounds.MinTime && timeBounds.MaxTime != 0 { - return nil, fmt.Errorf("the max time is earlier than the min time") - } - - var result string - if timeBounds.MaxTime == 0 { - result = fmt.Sprintf("[%d,)", timeBounds.MinTime) - return &result, nil - } - - result = fmt.Sprintf("[%d,%d)", timeBounds.MinTime, timeBounds.MaxTime) - - return &result, nil -} - -func LedgerBounds(t ingest.LedgerTransaction) *string { - ledgerBounds := t.Envelope.LedgerBounds() - if ledgerBounds == nil { - return nil - } - - result := fmt.Sprintf("[%d,%d)", int64(ledgerBounds.MinLedger), int64(ledgerBounds.MaxLedger)) - - return &result -} - -func MinSequence(t ingest.LedgerTransaction) *int64 { - return t.Envelope.MinSeqNum() -} - -func MinSequenceAge(t ingest.LedgerTransaction) *int64 { - minSequenceAge := t.Envelope.MinSeqAge() - if minSequenceAge == nil { - return nil - } - - minSequenceAgeInt64 := int64(*minSequenceAge) - return &minSequenceAgeInt64 -} - -func MinSequenceLedgerGap(t ingest.LedgerTransaction) *int64 { - minSequenceLedgerGap := t.Envelope.MinSeqLedgerGap() - result := int64(*minSequenceLedgerGap) - return &result -} - -func getSorobanData(t ingest.LedgerTransaction) (sorobanData xdr.SorobanTransactionData, ok bool) { - switch t.Envelope.Type { - case xdr.EnvelopeTypeEnvelopeTypeTx: - return t.Envelope.V1.Tx.Ext.GetSorobanData() - case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: - return t.Envelope.FeeBump.Tx.InnerTx.V1.Tx.Ext.GetSorobanData() - } - - return -} - -func SorobanResourceFee(t ingest.LedgerTransaction) *int64 { - sorobanData, ok := getSorobanData(t) - if !ok { - return nil - } - - result := int64(sorobanData.ResourceFee) - return &result -} - -func SorobanResourcesInstructions(t ingest.LedgerTransaction) *uint32 { - sorobanData, ok := getSorobanData(t) - if !ok { - return nil - } - - result := uint32(sorobanData.Resources.Instructions) - return &result -} - -func SorobanResourcesReadBytes(t ingest.LedgerTransaction) *uint32 { - sorobanData, ok := getSorobanData(t) - if !ok { - return nil - } - - result := uint32(sorobanData.Resources.ReadBytes) - return &result -} - -func SorobanResourcesWriteBytes(t ingest.LedgerTransaction) *uint32 { - sorobanData, ok := getSorobanData(t) - if !ok { - return nil - } - - result := uint32(sorobanData.Resources.WriteBytes) - return &result -} - -func InclusionFeeBid(t ingest.LedgerTransaction) *int64 { - resourceFee := SorobanResourceFee(t) - if resourceFee == nil { - return nil - } - - result := int64(t.Envelope.Fee()) - *resourceFee - return &result -} - -func getFeeAccountAddress(t ingest.LedgerTransaction) (feeAccountAddress string) { - switch t.Envelope.Type { - case xdr.EnvelopeTypeEnvelopeTypeTx: - sourceAccount := t.Envelope.SourceAccount() - feeAccountAddress = sourceAccount.Address() - case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: - feeBumpAccount := t.Envelope.FeeBumpAccount() - feeAccountAddress = feeBumpAccount.Address() - } - - return -} - -func SorobanInclusionFeeCharged(t ingest.LedgerTransaction) *int64 { - resourceFee := SorobanResourceFee(t) - if resourceFee == nil { - return nil - } - - accountBalanceStart, accountBalanceEnd := utils.GetAccountBalanceFromLedgerEntryChanges(t.FeeChanges, getFeeAccountAddress(t)) - initialFeeCharged := accountBalanceStart - accountBalanceEnd - result := initialFeeCharged - *resourceFee - - return &result -} - -func SorobanResourceFeeRefund(t ingest.LedgerTransaction) *int64 { - meta, ok := t.UnsafeMeta.GetV3() - if !ok { - return nil - } - - accountBalanceStart, accountBalanceEnd := utils.GetAccountBalanceFromLedgerEntryChanges(meta.TxChangesAfter, getFeeAccountAddress(t)) - result := accountBalanceEnd - accountBalanceStart - - return &result -} - -func SorobanTotalNonRefundableResourceFeeCharged(t ingest.LedgerTransaction) *int64 { - meta, ok := t.UnsafeMeta.GetV3() - if !ok { - return nil - } - - switch meta.SorobanMeta.Ext.V { - case 1: - result := int64(meta.SorobanMeta.Ext.V1.TotalNonRefundableResourceFeeCharged) - return &result - } - - return nil -} - -func SorobanTotalRefundableResourceFeeCharged(t ingest.LedgerTransaction) *int64 { - meta, ok := t.UnsafeMeta.GetV3() - if !ok { - return nil - } - - switch meta.SorobanMeta.Ext.V { - case 1: - result := int64(meta.SorobanMeta.Ext.V1.TotalRefundableResourceFeeCharged) - return &result - } - - return nil -} - -func SorobanRentFeeCharged(t ingest.LedgerTransaction) *int64 { - meta, ok := t.UnsafeMeta.GetV3() - if !ok { - return nil - } - - switch meta.SorobanMeta.Ext.V { - case 1: - result := int64(meta.SorobanMeta.Ext.V1.RentFeeCharged) - return &result - } - - return nil -} - -func ResultCode(t ingest.LedgerTransaction) string { - return t.Result.Result.Result.Code.String() -} - -func Signers(t ingest.LedgerTransaction) (signers []string) { - if t.Envelope.IsFeeBump() { - signers, _ = utils.GetTxSigners(t.Envelope.FeeBump.Signatures) - return - } - - signers, _ = utils.GetTxSigners(t.Envelope.Signatures()) - - return -} - -func AccountMuxed(t ingest.LedgerTransaction) *string { - sourceAccount := t.Envelope.SourceAccount() - if sourceAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { - return nil - } - - result := sourceAccount.Address() - - return &result -} - -func FeeAccount(t ingest.LedgerTransaction) *string { - if !t.Envelope.IsFeeBump() { - return nil - } - - feeBumpAccount := t.Envelope.FeeBumpAccount() - feeAccount := feeBumpAccount.ToAccountId() - result := feeAccount.Address() - - return &result -} - -func FeeAccountMuxed(t ingest.LedgerTransaction) *string { - if !t.Envelope.IsFeeBump() { - return nil - } - - feeBumpAccount := t.Envelope.FeeBumpAccount() - if feeBumpAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { - return nil - } - - result := feeBumpAccount.Address() - - return &result -} - -func InnerTransactionHash(t ingest.LedgerTransaction) *string { - if !t.Envelope.IsFeeBump() { - return nil - } - - innerHash := t.Result.InnerHash() - result := hex.EncodeToString(innerHash[:]) - - return &result -} - -func NewMaxFee(t ingest.LedgerTransaction) *uint32 { - if !t.Envelope.IsFeeBump() { - return nil - } - - newMaxFee := uint32(t.Envelope.FeeBumpFee()) - return &newMaxFee -} - -func Successful(t ingest.LedgerTransaction) bool { - return t.Result.Successful() -} diff --git a/exp/xdrill/transaction/transaction_test.go b/exp/xdrill/transaction/transaction_test.go deleted file mode 100644 index 9dc36aa9ef..0000000000 --- a/exp/xdrill/transaction/transaction_test.go +++ /dev/null @@ -1,242 +0,0 @@ -package transaction - -import ( - "testing" - - "github.com/stellar/go/ingest" - "github.com/stellar/go/xdr" - "github.com/stretchr/testify/assert" -) - -func TestTransaction(t *testing.T) { - ledger := ledgerTestInput() - transaction := transactionTestInput() - - assert.Equal(t, "1122330000000000000000000000000000000000000000000000000000000000", Hash(transaction)) - assert.Equal(t, uint32(1), Index(transaction)) - assert.Equal(t, int64(131335723340009472), ID(transaction, ledger)) - - var err error - var account string - account, err = Account(transaction) - assert.Equal(t, nil, err) - assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", account) - - assert.Equal(t, int64(30578981), AccountSequence(transaction)) - assert.Equal(t, uint32(4560), MaxFee(transaction)) - - feeCharged := FeeCharged(transaction, ledger) - assert.Equal(t, int64(789), *feeCharged) - - assert.Equal(t, uint32(3), OperationCount(transaction)) - assert.Equal(t, "test memo", Memo(transaction)) - assert.Equal(t, "MemoTypeMemoText", MemoType(transaction)) - - var timeBounds *string - timeBounds, err = TimeBounds(transaction) - assert.Equal(t, nil, err) - assert.Equal(t, "[1,10)", *timeBounds) - - ledgerBounds := LedgerBounds(transaction) - assert.Equal(t, "[2,20)", *ledgerBounds) - - minSequence := MinSequence(transaction) - assert.Equal(t, int64(123), *minSequence) - - minSequenceAge := MinSequenceAge(transaction) - assert.Equal(t, int64(456), *minSequenceAge) - - minSequenceLedgerGap := MinSequenceLedgerGap(transaction) - assert.Equal(t, int64(789), *minSequenceLedgerGap) - - sorobanResourceFee := SorobanResourceFee(transaction) - assert.Equal(t, int64(1234), *sorobanResourceFee) - - sorobanResourcesInstructions := SorobanResourcesInstructions(transaction) - assert.Equal(t, uint32(123), *sorobanResourcesInstructions) - - sorobanResourcesReadBytes := SorobanResourcesReadBytes(transaction) - assert.Equal(t, uint32(456), *sorobanResourcesReadBytes) - - sorobanResourcesWriteBytes := SorobanResourcesWriteBytes(transaction) - assert.Equal(t, uint32(789), *sorobanResourcesWriteBytes) - - inclusionFeeBid := InclusionFeeBid(transaction) - assert.Equal(t, int64(3326), *inclusionFeeBid) - - sorobanInclusionFeeCharged := SorobanInclusionFeeCharged(transaction) - assert.Equal(t, int64(-1234), *sorobanInclusionFeeCharged) - - sorobanResourceFeeRefund := SorobanResourceFeeRefund(transaction) - assert.Equal(t, int64(0), *sorobanResourceFeeRefund) - - sorobanTotalNonRefundableResourceFeeCharged := SorobanTotalNonRefundableResourceFeeCharged(transaction) - assert.Equal(t, int64(321), *sorobanTotalNonRefundableResourceFeeCharged) - - sorobanTotalRefundableResourceFeeCharged := SorobanTotalRefundableResourceFeeCharged(transaction) - assert.Equal(t, int64(123), *sorobanTotalRefundableResourceFeeCharged) - - sorobanRentFeeCharged := SorobanRentFeeCharged(transaction) - assert.Equal(t, int64(456), *sorobanRentFeeCharged) - - assert.Equal(t, "TransactionResultCodeTxSuccess", ResultCode(transaction)) - assert.Equal(t, []string{"GAISFR7R"}, Signers(transaction)) - - accountMuxed := AccountMuxed(transaction) - assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", *accountMuxed) - - feeAccount := FeeAccount(transaction) - assert.Equal(t, (*string)(nil), feeAccount) - - feeAccountMuxed := FeeAccountMuxed(transaction) - assert.Equal(t, (*string)(nil), feeAccountMuxed) - - innerTransactionHash := InnerTransactionHash(transaction) - assert.Equal(t, (*string)(nil), innerTransactionHash) - - assert.Equal(t, (*uint32)(nil), NewMaxFee(transaction)) - assert.Equal(t, true, Successful(transaction)) -} - -func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { - lcm = xdr.LedgerCloseMeta{ - V: 1, - V1: &xdr.LedgerCloseMetaV1{ - LedgerHeader: xdr.LedgerHeaderHistoryEntry{ - Header: xdr.LedgerHeader{ - LedgerSeq: 30578981, - LedgerVersion: 22, - }, - }, - }, - } - - return lcm -} - -func transactionTestInput() ingest.LedgerTransaction { - ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) - muxedAccount := xdr.MuxedAccount{ - Type: 256, - Ed25519: &ed25519, - Med25519: &xdr.MuxedAccountMed25519{ - Id: xdr.Uint64(123), - Ed25519: ed25519, - }, - } - - memoText := "test memo" - minSeqNum := xdr.SequenceNumber(123) - - transaction := ingest.LedgerTransaction{ - Index: 1, - Envelope: xdr.TransactionEnvelope{ - Type: xdr.EnvelopeTypeEnvelopeTypeTx, - V1: &xdr.TransactionV1Envelope{ - Signatures: []xdr.DecoratedSignature{ - { - Signature: []byte{0x11, 0x22}, - }, - }, - Tx: xdr.Transaction{ - SourceAccount: muxedAccount, - SeqNum: xdr.SequenceNumber(30578981), - Fee: xdr.Uint32(4560), - Operations: []xdr.Operation{ - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - }, - Memo: xdr.Memo{ - Type: xdr.MemoTypeMemoText, - Text: &memoText, - }, - Cond: xdr.Preconditions{ - Type: 2, - V2: &xdr.PreconditionsV2{ - TimeBounds: &xdr.TimeBounds{ - MinTime: xdr.TimePoint(1), - MaxTime: xdr.TimePoint(10), - }, - LedgerBounds: &xdr.LedgerBounds{ - MinLedger: 2, - MaxLedger: 20, - }, - MinSeqNum: &minSeqNum, - MinSeqAge: 456, - MinSeqLedgerGap: 789, - }, - }, - Ext: xdr.TransactionExt{ - V: 1, - SorobanData: &xdr.SorobanTransactionData{ - Resources: xdr.SorobanResources{ - Instructions: 123, - ReadBytes: 456, - WriteBytes: 789, - }, - ResourceFee: 1234, - }, - }, - }, - }, - }, - Result: xdr.TransactionResultPair{ - TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, - Result: xdr.TransactionResult{ - FeeCharged: xdr.Int64(789), - Result: xdr.TransactionResultResult{ - Code: 0, - }, - }, - }, - FeeChanges: xdr.LedgerEntryChanges{ - { - Type: xdr.LedgerEntryChangeTypeLedgerEntryState, - State: &xdr.LedgerEntry{ - Data: xdr.LedgerEntryData{ - Type: xdr.LedgerEntryTypeAccount, - Account: &xdr.AccountEntry{ - AccountId: xdr.AccountId{ - Type: 0, - Ed25519: &ed25519, - }, - Balance: 1000, - }, - }, - }, - }, - {}, - }, - UnsafeMeta: xdr.TransactionMeta{ - V: 3, - V3: &xdr.TransactionMetaV3{ - TxChangesAfter: xdr.LedgerEntryChanges{}, - SorobanMeta: &xdr.SorobanTransactionMeta{ - Ext: xdr.SorobanTransactionMetaExt{ - V: 1, - V1: &xdr.SorobanTransactionMetaExtV1{ - TotalNonRefundableResourceFeeCharged: 321, - TotalRefundableResourceFeeCharged: 123, - RentFeeCharged: 456, - }, - }, - }, - }, - }, - LedgerVersion: 22, - Ledger: xdr.LedgerCloseMeta{}, - Hash: xdr.Hash{}, - } - - return transaction -} diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index 046cff3782..36f82b952f 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -1,7 +1,14 @@ package ingest import ( + "encoding/base64" + "encoding/hex" + "fmt" + "strconv" + + "github.com/stellar/go/strkey" "github.com/stellar/go/support/errors" + "github.com/stellar/go/toid" "github.com/stellar/go/xdr" ) @@ -181,3 +188,394 @@ func (t *LedgerTransaction) operationChanges(ops []xdr.OperationMeta, index uint func (t *LedgerTransaction) GetDiagnosticEvents() ([]xdr.DiagnosticEvent, error) { return t.UnsafeMeta.GetDiagnosticEvents() } + +func (t *LedgerTransaction) ID() int64 { + return toid.New(int32(t.Ledger.LedgerSequence()), int32(t.Index), 0).ToInt64() +} + +func (t *LedgerTransaction) Account() (string, error) { + sourceAccount := t.Envelope.SourceAccount() + providedID := sourceAccount.ToAccountId() + pointerToID := &providedID + + return pointerToID.GetAddress() +} + +func (t *LedgerTransaction) AccountSequence() int64 { + return t.Envelope.SeqNum() +} + +func (t *LedgerTransaction) MaxFee() uint32 { + return t.Envelope.Fee() +} + +func (t *LedgerTransaction) FeeCharged() (int64, bool) { + // Any Soroban Fee Bump transactions before P21 will need the below logic to calculate the correct feeCharged + // Protocol 20 contained a bug where the feeCharged was incorrectly calculated but was fixed for + // Protocol 21 with https://github.com/stellar/stellar-core/issues/4188 + var ok bool + _, ok = t.GetSorobanData() + if ok { + if uint32(t.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) < 21 && t.Envelope.Type == xdr.EnvelopeTypeEnvelopeTypeTxFeeBump { + var resourceFeeRefund int64 + var inclusionFeeCharged int64 + + resourceFeeRefund, ok = t.SorobanResourceFeeRefund() + if !ok { + return 0, false + } + + inclusionFeeCharged, ok = t.SorobanInclusionFeeCharged() + if !ok { + return 0, false + } + + return int64(t.Result.Result.FeeCharged) - resourceFeeRefund + inclusionFeeCharged, true + } + } + + return int64(t.Result.Result.FeeCharged), true + +} + +func (t *LedgerTransaction) OperationCount() uint32 { + return uint32(len(t.Envelope.Operations())) +} + +func (t *LedgerTransaction) Memo() string { + memoObject := t.Envelope.Memo() + memoContents := "" + switch xdr.MemoType(memoObject.Type) { + case xdr.MemoTypeMemoText: + memoContents = memoObject.MustText() + case xdr.MemoTypeMemoId: + memoContents = strconv.FormatUint(uint64(memoObject.MustId()), 10) + case xdr.MemoTypeMemoHash: + hash := memoObject.MustHash() + memoContents = base64.StdEncoding.EncodeToString(hash[:]) + case xdr.MemoTypeMemoReturn: + hash := memoObject.MustRetHash() + memoContents = base64.StdEncoding.EncodeToString(hash[:]) + } + + return memoContents +} + +func (t *LedgerTransaction) MemoType() string { + memoObject := t.Envelope.Memo() + return memoObject.Type.String() +} + +func (t *LedgerTransaction) TimeBounds() (string, error) { + timeBounds := t.Envelope.TimeBounds() + if timeBounds == nil { + return "", nil + } + + if timeBounds.MaxTime < timeBounds.MinTime && timeBounds.MaxTime != 0 { + return "", fmt.Errorf("the max time is earlier than the min time") + } + + if timeBounds.MaxTime == 0 { + return fmt.Sprintf("[%d,)", timeBounds.MinTime), nil + } + + return fmt.Sprintf("[%d,%d)", timeBounds.MinTime, timeBounds.MaxTime), nil +} + +func (t *LedgerTransaction) LedgerBounds() (string, bool) { + ledgerBounds := t.Envelope.LedgerBounds() + if ledgerBounds == nil { + return "", false + } + + return fmt.Sprintf("[%d,%d)", int64(ledgerBounds.MinLedger), int64(ledgerBounds.MaxLedger)), true + +} + +func (t *LedgerTransaction) MinSequence() (int64, bool) { + minSeqNum := t.Envelope.MinSeqNum() + if minSeqNum == nil { + return 0, false + } + + return *minSeqNum, true +} + +func (t *LedgerTransaction) MinSequenceAge() (int64, bool) { + minSequenceAge := t.Envelope.MinSeqAge() + if minSequenceAge == nil { + return 0, false + } + + return int64(*minSequenceAge), true +} + +func (t *LedgerTransaction) MinSequenceLedgerGap() (int64, bool) { + minSequenceLedgerGap := t.Envelope.MinSeqLedgerGap() + if minSequenceLedgerGap == nil { + return 0, false + } + + return int64(*minSequenceLedgerGap), true +} + +func (t *LedgerTransaction) GetSorobanData() (xdr.SorobanTransactionData, bool) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + return t.Envelope.V1.Tx.Ext.GetSorobanData() + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + return t.Envelope.FeeBump.Tx.InnerTx.V1.Tx.Ext.GetSorobanData() + default: + return xdr.SorobanTransactionData{}, false + } +} + +func (t *LedgerTransaction) SorobanResourceFee() (int64, bool) { + sorobanData, ok := t.GetSorobanData() + if !ok { + return 0, false + } + + return int64(sorobanData.ResourceFee), true +} + +func (t *LedgerTransaction) SorobanResourcesInstructions() (uint32, bool) { + sorobanData, ok := t.GetSorobanData() + if !ok { + return 0, false + } + + return uint32(sorobanData.Resources.Instructions), true +} + +func (t *LedgerTransaction) SorobanResourcesReadBytes() (uint32, bool) { + sorobanData, ok := t.GetSorobanData() + if !ok { + return 0, false + } + + return uint32(sorobanData.Resources.ReadBytes), true +} + +func (t *LedgerTransaction) SorobanResourcesWriteBytes() (uint32, bool) { + sorobanData, ok := t.GetSorobanData() + if !ok { + return 0, false + } + + return uint32(sorobanData.Resources.WriteBytes), true +} + +func (t *LedgerTransaction) InclusionFeeBid() (int64, bool) { + resourceFee, ok := t.SorobanResourceFee() + if !ok { + return 0, false + } + + return int64(t.Envelope.Fee()) - resourceFee, true +} + +func (t *LedgerTransaction) FeeAccountAddress() (string, bool) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + sourceAccount := t.Envelope.SourceAccount() + feeAccountAddress := sourceAccount.Address() + return feeAccountAddress, true + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + feeBumpAccount := t.Envelope.FeeBumpAccount() + feeAccountAddress := feeBumpAccount.Address() + return feeAccountAddress, true + default: + return "", false + } +} + +func (t *LedgerTransaction) SorobanInclusionFeeCharged() (int64, bool) { + resourceFee, ok := t.SorobanResourceFee() + if !ok { + return 0, false + } + + feeAccountAddress, ok := t.FeeAccountAddress() + if !ok { + return 0, false + } + + accountBalanceStart, accountBalanceEnd := getAccountBalanceFromLedgerEntryChanges(t.FeeChanges, feeAccountAddress) + initialFeeCharged := accountBalanceStart - accountBalanceEnd + + return initialFeeCharged - resourceFee, true +} + +func getAccountBalanceFromLedgerEntryChanges(changes xdr.LedgerEntryChanges, sourceAccountAddress string) (int64, int64) { + var accountBalanceStart int64 + var accountBalanceEnd int64 + + for _, change := range changes { + switch change.Type { + case xdr.LedgerEntryChangeTypeLedgerEntryUpdated: + accountEntry, ok := change.Updated.Data.GetAccount() + if !ok { + continue + } + + if accountEntry.AccountId.Address() == sourceAccountAddress { + accountBalanceEnd = int64(accountEntry.Balance) + } + case xdr.LedgerEntryChangeTypeLedgerEntryState: + accountEntry, ok := change.State.Data.GetAccount() + if !ok { + continue + } + + if accountEntry.AccountId.Address() == sourceAccountAddress { + accountBalanceStart = int64(accountEntry.Balance) + } + } + } + + return accountBalanceStart, accountBalanceEnd +} + +func (t *LedgerTransaction) SorobanResourceFeeRefund() (int64, bool) { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return 0, false + } + + feeAccountAddress, ok := t.FeeAccountAddress() + if !ok { + return 0, false + } + + accountBalanceStart, accountBalanceEnd := getAccountBalanceFromLedgerEntryChanges(meta.TxChangesAfter, feeAccountAddress) + + return accountBalanceEnd - accountBalanceStart, true + +} + +func (t *LedgerTransaction) SorobanTotalNonRefundableResourceFeeCharged() (int64, bool) { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return 0, false + } + + switch meta.SorobanMeta.Ext.V { + case 1: + return int64(meta.SorobanMeta.Ext.V1.TotalNonRefundableResourceFeeCharged), true + default: + return 0, false + } +} + +func (t *LedgerTransaction) SorobanTotalRefundableResourceFeeCharged() (int64, bool) { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return 0, false + } + + switch meta.SorobanMeta.Ext.V { + case 1: + return int64(meta.SorobanMeta.Ext.V1.TotalRefundableResourceFeeCharged), true + default: + return 0, false + } +} + +func (t *LedgerTransaction) SorobanRentFeeCharged() (int64, bool) { + meta, ok := t.UnsafeMeta.GetV3() + if !ok { + return 0, false + } + + switch meta.SorobanMeta.Ext.V { + case 1: + return int64(meta.SorobanMeta.Ext.V1.RentFeeCharged), true + default: + return 0, false + } +} + +func (t *LedgerTransaction) ResultCode() string { + return t.Result.Result.Result.Code.String() +} + +func (t *LedgerTransaction) Signers() (signers []string, err error) { + if t.Envelope.IsFeeBump() { + return getTxSigners(t.Envelope.FeeBump.Signatures) + } + + return getTxSigners(t.Envelope.Signatures()) +} + +func getTxSigners(xdrSignatures []xdr.DecoratedSignature) ([]string, error) { + signers := make([]string, len(xdrSignatures)) + + for i, sig := range xdrSignatures { + signerAccount, err := strkey.Encode(strkey.VersionByteAccountID, sig.Signature) + if err != nil { + return nil, err + } + signers[i] = signerAccount + } + + return signers, nil +} + +func (t *LedgerTransaction) AccountMuxed() (string, bool) { + sourceAccount := t.Envelope.SourceAccount() + if sourceAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return "", false + } + + return sourceAccount.Address(), true + +} + +func (t *LedgerTransaction) FeeAccount() (string, bool) { + if !t.Envelope.IsFeeBump() { + return "", false + } + + feeBumpAccount := t.Envelope.FeeBumpAccount() + feeAccount := feeBumpAccount.ToAccountId() + + return feeAccount.Address(), true + +} + +func (t *LedgerTransaction) FeeAccountMuxed() (string, bool) { + if !t.Envelope.IsFeeBump() { + return "", false + } + + feeBumpAccount := t.Envelope.FeeBumpAccount() + if feeBumpAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return "", false + } + + return feeBumpAccount.Address(), true +} + +func (t *LedgerTransaction) InnerTransactionHash() (string, bool) { + if !t.Envelope.IsFeeBump() { + return "", false + } + + innerHash := t.Result.InnerHash() + + return hex.EncodeToString(innerHash[:]), true +} + +func (t *LedgerTransaction) NewMaxFee() (uint32, bool) { + if !t.Envelope.IsFeeBump() { + return 0, false + } + + return uint32(t.Envelope.FeeBumpFee()), true +} + +func (t *LedgerTransaction) Successful() bool { + return t.Result.Successful() +} diff --git a/ingest/ledger_transaction_test.go b/ingest/ledger_transaction_test.go index ced92e6918..3a2773fa88 100644 --- a/ingest/ledger_transaction_test.go +++ b/ingest/ledger_transaction_test.go @@ -811,3 +811,274 @@ func TestChangeAccountChangedExceptSignersNoChanges(t *testing.T) { assert.NotNil(t, change.Post.Data.Account.Signers) assert.Len(t, change.Post.Data.Account.Signers, 1) } + +func TestTransactionHelperFunctions(t *testing.T) { + transaction := transactionHelperFunctionsTestInput() + + assert.Equal(t, int64(131335723340009472), transaction.ID()) + + var err error + var ok bool + var account string + account, err = transaction.Account() + assert.Equal(t, nil, err) + assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", account) + + assert.Equal(t, int64(30578981), transaction.AccountSequence()) + assert.Equal(t, uint32(4560), transaction.MaxFee()) + + var feeCharged int64 + feeCharged, ok = transaction.FeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(789), feeCharged) + + assert.Equal(t, uint32(3), transaction.OperationCount()) + assert.Equal(t, "test memo", transaction.Memo()) + assert.Equal(t, "MemoTypeMemoText", transaction.MemoType()) + + var timeBounds string + timeBounds, err = transaction.TimeBounds() + assert.Equal(t, nil, err) + assert.Equal(t, "[1,10)", timeBounds) + + var ledgerBounds string + ledgerBounds, ok = transaction.LedgerBounds() + assert.Equal(t, true, ok) + assert.Equal(t, "[2,20)", ledgerBounds) + + var minSequence int64 + minSequence, ok = transaction.MinSequence() + assert.Equal(t, true, ok) + assert.Equal(t, int64(123), minSequence) + + var minSequenceAge int64 + minSequenceAge, ok = transaction.MinSequenceAge() + assert.Equal(t, true, ok) + assert.Equal(t, int64(456), minSequenceAge) + + var minSequenceLedgerGap int64 + minSequenceLedgerGap, ok = transaction.MinSequenceLedgerGap() + assert.Equal(t, true, ok) + assert.Equal(t, int64(789), minSequenceLedgerGap) + + var sorobanResourceFee int64 + sorobanResourceFee, ok = transaction.SorobanResourceFee() + assert.Equal(t, true, ok) + assert.Equal(t, int64(1234), sorobanResourceFee) + + var sorobanResourcesInstructions uint32 + sorobanResourcesInstructions, ok = transaction.SorobanResourcesInstructions() + assert.Equal(t, true, ok) + assert.Equal(t, uint32(123), sorobanResourcesInstructions) + + var sorobanResourcesReadBytes uint32 + sorobanResourcesReadBytes, ok = transaction.SorobanResourcesReadBytes() + assert.Equal(t, true, ok) + assert.Equal(t, uint32(456), sorobanResourcesReadBytes) + + var sorobanResourcesWriteBytes uint32 + sorobanResourcesWriteBytes, ok = transaction.SorobanResourcesWriteBytes() + assert.Equal(t, true, ok) + assert.Equal(t, uint32(789), sorobanResourcesWriteBytes) + + var inclusionFeeBid int64 + inclusionFeeBid, ok = transaction.InclusionFeeBid() + assert.Equal(t, true, ok) + assert.Equal(t, int64(3326), inclusionFeeBid) + + var sorobanInclusionFeeCharged int64 + sorobanInclusionFeeCharged, ok = transaction.SorobanInclusionFeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(-1234), sorobanInclusionFeeCharged) + + var sorobanResourceFeeRefund int64 + sorobanResourceFeeRefund, ok = transaction.SorobanResourceFeeRefund() + assert.Equal(t, true, ok) + assert.Equal(t, int64(0), sorobanResourceFeeRefund) + + var sorobanTotalNonRefundableResourceFeeCharged int64 + sorobanTotalNonRefundableResourceFeeCharged, ok = transaction.SorobanTotalNonRefundableResourceFeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(321), sorobanTotalNonRefundableResourceFeeCharged) + + var sorobanTotalRefundableResourceFeeCharged int64 + sorobanTotalRefundableResourceFeeCharged, ok = transaction.SorobanTotalRefundableResourceFeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(123), sorobanTotalRefundableResourceFeeCharged) + + var sorobanRentFeeCharged int64 + sorobanRentFeeCharged, ok = transaction.SorobanRentFeeCharged() + assert.Equal(t, true, ok) + assert.Equal(t, int64(456), sorobanRentFeeCharged) + + assert.Equal(t, "TransactionResultCodeTxSuccess", transaction.ResultCode()) + + var signers []string + signers, err = transaction.Signers() + assert.Equal(t, nil, err) + assert.Equal(t, []string{"GAISFR7R"}, signers) + + var accountMuxed string + accountMuxed, ok = transaction.AccountMuxed() + assert.Equal(t, true, ok) + assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", accountMuxed) + + var feeAccount string + feeAccount, ok = transaction.FeeAccount() + assert.Equal(t, false, ok) + assert.Equal(t, "", feeAccount) + + var feeAccountMuxed string + feeAccountMuxed, ok = transaction.FeeAccountMuxed() + assert.Equal(t, false, ok) + assert.Equal(t, "", feeAccountMuxed) + + var innerTransactionHash string + innerTransactionHash, ok = transaction.InnerTransactionHash() + assert.Equal(t, false, ok) + assert.Equal(t, "", innerTransactionHash) + + var newMaxFee uint32 + newMaxFee, ok = transaction.NewMaxFee() + assert.Equal(t, false, ok) + assert.Equal(t, uint32(0), newMaxFee) + + assert.Equal(t, true, transaction.Successful()) +} + +func transactionHelperFunctionsTestInput() LedgerTransaction { + ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) + muxedAccount := xdr.MuxedAccount{ + Type: 256, + Ed25519: &ed25519, + Med25519: &xdr.MuxedAccountMed25519{ + Id: xdr.Uint64(123), + Ed25519: ed25519, + }, + } + + memoText := "test memo" + minSeqNum := xdr.SequenceNumber(123) + + transaction := LedgerTransaction{ + Index: 1, + Envelope: xdr.TransactionEnvelope{ + Type: xdr.EnvelopeTypeEnvelopeTypeTx, + V1: &xdr.TransactionV1Envelope{ + Signatures: []xdr.DecoratedSignature{ + { + Signature: []byte{0x11, 0x22}, + }, + }, + Tx: xdr.Transaction{ + SourceAccount: muxedAccount, + SeqNum: xdr.SequenceNumber(30578981), + Fee: xdr.Uint32(4560), + Operations: []xdr.Operation{ + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + }, + Memo: xdr.Memo{ + Type: xdr.MemoTypeMemoText, + Text: &memoText, + }, + Cond: xdr.Preconditions{ + Type: 2, + V2: &xdr.PreconditionsV2{ + TimeBounds: &xdr.TimeBounds{ + MinTime: xdr.TimePoint(1), + MaxTime: xdr.TimePoint(10), + }, + LedgerBounds: &xdr.LedgerBounds{ + MinLedger: 2, + MaxLedger: 20, + }, + MinSeqNum: &minSeqNum, + MinSeqAge: 456, + MinSeqLedgerGap: 789, + }, + }, + Ext: xdr.TransactionExt{ + V: 1, + SorobanData: &xdr.SorobanTransactionData{ + Resources: xdr.SorobanResources{ + Instructions: 123, + ReadBytes: 456, + WriteBytes: 789, + }, + ResourceFee: 1234, + }, + }, + }, + }, + }, + Result: xdr.TransactionResultPair{ + TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, + Result: xdr.TransactionResult{ + FeeCharged: xdr.Int64(789), + Result: xdr.TransactionResultResult{ + Code: 0, + }, + }, + }, + FeeChanges: xdr.LedgerEntryChanges{ + { + Type: xdr.LedgerEntryChangeTypeLedgerEntryState, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: xdr.LedgerEntryTypeAccount, + Account: &xdr.AccountEntry{ + AccountId: xdr.AccountId{ + Type: 0, + Ed25519: &ed25519, + }, + Balance: 1000, + }, + }, + }, + }, + {}, + }, + UnsafeMeta: xdr.TransactionMeta{ + V: 3, + V3: &xdr.TransactionMetaV3{ + TxChangesAfter: xdr.LedgerEntryChanges{}, + SorobanMeta: &xdr.SorobanTransactionMeta{ + Ext: xdr.SorobanTransactionMetaExt{ + V: 1, + V1: &xdr.SorobanTransactionMetaExtV1{ + TotalNonRefundableResourceFeeCharged: 321, + TotalRefundableResourceFeeCharged: 123, + RentFeeCharged: 456, + }, + }, + }, + }, + }, + LedgerVersion: 22, + Ledger: xdr.LedgerCloseMeta{ + V: 1, + V1: &xdr.LedgerCloseMetaV1{ + LedgerHeader: xdr.LedgerHeaderHistoryEntry{ + Header: xdr.LedgerHeader{ + LedgerSeq: 30578981, + LedgerVersion: 22, + }, + }, + }, + }, + Hash: xdr.Hash{}, + } + + return transaction +} From 58fcfe2bbeee71f2990bc332982a03d54d0c7cd9 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 16:13:43 -0700 Subject: [PATCH 16/40] fix merge issues --- ingest/ledger/ledger.go | 121 ----------------------------------- ingest/ledger/ledger_test.go | 48 -------------- 2 files changed, 169 deletions(-) diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go index 3da14c867c..c37cb50b3b 100644 --- a/ingest/ledger/ledger.go +++ b/ingest/ledger/ledger.go @@ -8,10 +8,6 @@ import ( "github.com/stellar/go/xdr" ) -<<<<<<< HEAD -<<<<<<< HEAD -======= ->>>>>>> origin/5550/xdrill-transactions func Sequence(l xdr.LedgerCloseMeta) uint32 { return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq) } @@ -62,65 +58,6 @@ func LedgerVersion(l xdr.LedgerCloseMeta) uint32 { func SorobanFeeWrite1Kb(l xdr.LedgerCloseMeta) (int64, bool) { lcmV1, ok := l.GetV1() -<<<<<<< HEAD -======= -type Ledger struct { - Ledger xdr.LedgerCloseMeta -} - -func (l Ledger) Sequence() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerSeq) -} - -func (l Ledger) ID() int64 { - return toid.New(int32(l.Ledger.LedgerSequence()), 0, 0).ToInt64() -} - -func (l Ledger) Hash() string { - return l.Ledger.LedgerHeaderHistoryEntry().Hash.HexString() -} - -func (l Ledger) PreviousHash() string { - return l.Ledger.PreviousLedgerHash().HexString() -} - -func (l Ledger) CloseTime() int64 { - return l.Ledger.LedgerCloseTime() -} - -func (l Ledger) ClosedAt() time.Time { - return time.Unix(l.Ledger.LedgerCloseTime(), 0).UTC() -} - -func (l Ledger) TotalCoins() int64 { - return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.TotalCoins) -} - -func (l Ledger) FeePool() int64 { - return int64(l.Ledger.LedgerHeaderHistoryEntry().Header.FeePool) -} - -func (l Ledger) BaseFee() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseFee) -} - -func (l Ledger) BaseReserve() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.BaseReserve) -} - -func (l Ledger) MaxTxSetSize() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.MaxTxSetSize) -} - -func (l Ledger) LedgerVersion() uint32 { - return uint32(l.Ledger.LedgerHeaderHistoryEntry().Header.LedgerVersion) -} - -func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { - lcmV1, ok := l.Ledger.GetV1() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= ->>>>>>> origin/5550/xdrill-transactions if !ok { return 0, false } @@ -133,18 +70,8 @@ func (l Ledger) SorobanFeeWrite1Kb() (int64, bool) { return int64(extV1.SorobanFeeWrite1Kb), true } -<<<<<<< HEAD -<<<<<<< HEAD -func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) { - lcmV1, ok := l.GetV1() -======= -func (l Ledger) TotalByteSizeOfBucketList() (uint64, bool) { - lcmV1, ok := l.Ledger.GetV1() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) { lcmV1, ok := l.GetV1() ->>>>>>> origin/5550/xdrill-transactions if !ok { return 0, false } @@ -152,18 +79,8 @@ func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) { return uint64(lcmV1.TotalByteSizeOfBucketList), true } -<<<<<<< HEAD -<<<<<<< HEAD -func NodeID(l xdr.LedgerCloseMeta) (string, bool) { - LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() -======= -func (l Ledger) NodeID() (string, bool) { - LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= func NodeID(l xdr.LedgerCloseMeta) (string, bool) { LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() ->>>>>>> origin/5550/xdrill-transactions if !ok { return "", false @@ -171,18 +88,8 @@ func NodeID(l xdr.LedgerCloseMeta) (string, bool) { return LedgerCloseValueSignature.NodeId.GetAddress() } -<<<<<<< HEAD -<<<<<<< HEAD -func Signature(l xdr.LedgerCloseMeta) (string, bool) { - LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() -======= -func (l Ledger) Signature() (string, bool) { - LedgerCloseValueSignature, ok := l.Ledger.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= func Signature(l xdr.LedgerCloseMeta) (string, bool) { LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() ->>>>>>> origin/5550/xdrill-transactions if !ok { return "", false } @@ -191,25 +98,11 @@ func Signature(l xdr.LedgerCloseMeta) (string, bool) { } // Add docstring to larger, more complicated functions -<<<<<<< HEAD -<<<<<<< HEAD -======= ->>>>>>> origin/5550/xdrill-transactions func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32, ok bool) { var results []xdr.TransactionResultMeta transactions := l.TransactionEnvelopes() results = l.TxProcessing() -<<<<<<< HEAD -======= -func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok bool) { - var results []xdr.TransactionResultMeta - - transactions := l.Ledger.TransactionEnvelopes() - results = l.Ledger.TxProcessing() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= ->>>>>>> origin/5550/xdrill-transactions txCount := len(transactions) if txCount != len(results) { return 0, 0, false @@ -227,25 +120,11 @@ func (l Ledger) TransactionCounts() (successTxCount, failedTxCount int32, ok boo } // Add docstring to larger, more complicated functions -<<<<<<< HEAD -<<<<<<< HEAD -======= ->>>>>>> origin/5550/xdrill-transactions func OperationCounts(l xdr.LedgerCloseMeta) (operationCount, txSetOperationCount int32, ok bool) { var results []xdr.TransactionResultMeta transactions := l.TransactionEnvelopes() results = l.TxProcessing() -<<<<<<< HEAD -======= -func (l Ledger) OperationCounts() (operationCount, txSetOperationCount int32, ok bool) { - var results []xdr.TransactionResultMeta - - transactions := l.Ledger.TransactionEnvelopes() - results = l.Ledger.TxProcessing() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= ->>>>>>> origin/5550/xdrill-transactions for i, result := range results { operations := transactions[i].Operations() diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index 22651f68e3..3e5409dc8e 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -15,7 +15,6 @@ func TestLedger(t *testing.T) { Ledger: ledgerTestInput(), } -<<<<<<< HEAD assert.Equal(t, uint32(30578981), Sequence(ledger)) assert.Equal(t, int64(131335723340005376), ID(ledger)) assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger)) @@ -29,72 +28,25 @@ func TestLedger(t *testing.T) { assert.Equal(t, uint32(1000), MaxTxSetSize(ledger)) assert.Equal(t, uint32(13), LedgerVersion(ledger)) -<<<<<<< HEAD var ok bool var freeWrite int64 freeWrite, ok = SorobanFeeWrite1Kb(ledger) -======= - assert.Equal(t, uint32(30578981), ledger.Sequence()) - assert.Equal(t, int64(131335723340005376), ledger.ID()) - assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", ledger.Hash()) - assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", ledger.PreviousHash()) - assert.Equal(t, int64(1594584547), ledger.CloseTime()) - assert.Equal(t, time.Time(time.Date(2020, time.July, 12, 20, 9, 7, 0, time.UTC)), ledger.ClosedAt()) - assert.Equal(t, int64(1054439020873472865), ledger.TotalCoins()) - assert.Equal(t, int64(18153766209161), ledger.FeePool()) - assert.Equal(t, uint32(100), ledger.BaseFee()) - assert.Equal(t, uint32(5000000), ledger.BaseReserve()) - assert.Equal(t, uint32(1000), ledger.MaxTxSetSize()) - assert.Equal(t, uint32(13), ledger.LedgerVersion()) - - var ok bool - var freeWrite int64 - freeWrite, ok = ledger.SorobanFeeWrite1Kb() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= - var ok bool - var freeWrite int64 - freeWrite, ok = SorobanFeeWrite1Kb(ledger) ->>>>>>> origin/5550/xdrill-transactions assert.Equal(t, true, ok) assert.Equal(t, int64(12), freeWrite) var bucketSize uint64 -<<<<<<< HEAD -<<<<<<< HEAD bucketSize, ok = TotalByteSizeOfBucketList(ledger) -======= - bucketSize, ok = ledger.TotalByteSizeOfBucketList() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= - bucketSize, ok = TotalByteSizeOfBucketList(ledger) ->>>>>>> origin/5550/xdrill-transactions assert.Equal(t, true, ok) assert.Equal(t, uint64(56), bucketSize) var nodeID string -<<<<<<< HEAD -<<<<<<< HEAD - nodeID, ok = NodeID(ledger) -======= - nodeID, ok = ledger.NodeID() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= nodeID, ok = NodeID(ledger) ->>>>>>> origin/5550/xdrill-transactions assert.Equal(t, true, ok) assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) var signature string -<<<<<<< HEAD -<<<<<<< HEAD signature, ok = Signature(ledger) -======= - signature, ok = ledger.Signature() ->>>>>>> b5feb2c8 (Move xdrill ledger functions to ingest as subpackage) -======= signature, ok = Signature(ledger) ->>>>>>> origin/5550/xdrill-transactions assert.Equal(t, true, ok) assert.Equal(t, "9g==", signature) From 18dd712a0f24bf99f7015870df6c33f7e2dc9cca Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 16:15:41 -0700 Subject: [PATCH 17/40] fix merge errors --- ingest/ledger/ledger_test.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index 3e5409dc8e..2345d46792 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -11,9 +11,7 @@ import ( ) func TestLedger(t *testing.T) { - ledger := Ledger{ - Ledger: ledgerTestInput(), - } + ledger := ledgerTestInput() assert.Equal(t, uint32(30578981), Sequence(ledger)) assert.Equal(t, int64(131335723340005376), ID(ledger)) @@ -46,18 +44,17 @@ func TestLedger(t *testing.T) { var signature string signature, ok = Signature(ledger) - signature, ok = Signature(ledger) assert.Equal(t, true, ok) assert.Equal(t, "9g==", signature) var success int32 var failed int32 - success, failed, ok = ledger.TransactionCounts() + success, failed, ok = TransactionCounts(ledger) assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) - success, failed, ok = ledger.OperationCounts() + success, failed, ok = OperationCounts(ledger) assert.Equal(t, true, ok) assert.Equal(t, int32(1), success) assert.Equal(t, int32(13), failed) From 314b605e87aecae83f999a3b9daa54859265b6d1 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Fri, 10 Jan 2025 12:59:28 -0700 Subject: [PATCH 18/40] xdrill for operations --- go.mod | 1 + go.sum | 2 + ingest/ledger_operation.go | 1431 ++++++++++++++++++++++++++++++ ingest/ledger_operation_test.go | 1474 +++++++++++++++++++++++++++++++ ingest/ledger_transaction.go | 160 ++++ xdr/hash.go | 16 +- xdr/operation_trace_result.go | 68 ++ 7 files changed, 3151 insertions(+), 1 deletion(-) create mode 100644 ingest/ledger_operation.go create mode 100644 ingest/ledger_operation_test.go create mode 100644 xdr/operation_trace_result.go diff --git a/go.mod b/go.mod index 341c85543e..6d7e5fab5d 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( require ( github.com/cenkalti/backoff/v4 v4.3.0 + github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fsouza/fake-gcs-server v1.49.2 diff --git a/go.sum b/go.sum index a3c8ce08fa..b071601459 100644 --- a/go.sum +++ b/go.sum @@ -116,6 +116,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/djherbis/fscache v0.10.1 h1:hDv+RGyvD+UDKyRYuLoVNbuRTnf2SrA2K3VyR1br9lk= diff --git a/ingest/ledger_operation.go b/ingest/ledger_operation.go new file mode 100644 index 0000000000..f59add11e2 --- /dev/null +++ b/ingest/ledger_operation.go @@ -0,0 +1,1431 @@ +package ingest + +import ( + "encoding/base64" + "fmt" + "math/big" + "strconv" + + "github.com/dgryski/go-farm" + "github.com/stellar/go/amount" + "github.com/stellar/go/support/contractevents" + "github.com/stellar/go/toid" + "github.com/stellar/go/xdr" +) + +type LedgerOperation struct { + OperationIndex int32 + Operation xdr.Operation + Transaction *LedgerTransaction + NetworkPassphrase string +} + +func (o *LedgerOperation) sourceAccountXDR() xdr.MuxedAccount { + sourceAccount := o.Operation.SourceAccount + if sourceAccount != nil { + return *sourceAccount + } + + return o.Transaction.Envelope.SourceAccount() +} + +func (o *LedgerOperation) SourceAccount() string { + muxedAccount := o.sourceAccountXDR() + providedID := muxedAccount.ToAccountId() + pointerToID := &providedID + + return pointerToID.Address() +} + +func (o *LedgerOperation) Type() int32 { + return int32(o.Operation.Body.Type) +} + +func (o *LedgerOperation) TypeString() string { + return xdr.OperationTypeToStringMap[o.Type()] +} + +func (o *LedgerOperation) ID() int64 { + //operationIndex needs +1 increment to stay in sync with ingest package + return toid.New(int32(o.Transaction.Ledger.LedgerSequence()), int32(o.Transaction.Index), o.OperationIndex+1).ToInt64() +} + +func (o *LedgerOperation) SourceAccountMuxed() (string, bool) { + muxedAccount := o.sourceAccountXDR() + if muxedAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return "", false + } + + return muxedAccount.Address(), true +} + +func (o *LedgerOperation) OperationResultCode() string { + var operationResultCode string + operationResults, ok := o.Transaction.Result.Result.OperationResults() + if ok { + operationResultCode = operationResults[o.OperationIndex].Code.String() + } + + return operationResultCode +} + +func (o *LedgerOperation) OperationTraceCode() (string, error) { + var operationTraceCode string + + operationResults, ok := o.Transaction.Result.Result.OperationResults() + if ok { + operationResultTr, ok := operationResults[o.OperationIndex].GetTr() + if ok { + operationTraceCode, err := operationResultTr.MapOperationResultTr() + if err != nil { + return "", err + } + return operationTraceCode, nil + } + } + + return operationTraceCode, nil +} + +func (o *LedgerOperation) OperationDetails() (map[string]interface{}, error) { + var err error + details := map[string]interface{}{} + + switch o.Operation.Body.Type { + case xdr.OperationTypeCreateAccount: + details, err = o.CreateAccountDetails() + if err != nil { + return details, err + } + case xdr.OperationTypePayment: + details, err = o.PaymentDetails() + if err != nil { + return details, err + } + case xdr.OperationTypePathPaymentStrictReceive: + details, err = o.PathPaymentStrictReceiveDetails() + if err != nil { + return details, err + } + case xdr.OperationTypePathPaymentStrictSend: + details, err = o.PathPaymentStrictSendDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeManageBuyOffer: + details, err = o.ManageBuyOfferDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeManageSellOffer: + details, err = o.ManageSellOfferDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeCreatePassiveSellOffer: + details, err = o.CreatePassiveSellOfferDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeSetOptions: + details, err = o.SetOptionsDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeChangeTrust: + details, err = o.ChangeTrustDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeAllowTrust: + details, err = o.AllowTrustDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeAccountMerge: + details, err = o.AccountMergeDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeInflation: + details, err = o.InflationDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeManageData: + details, err = o.ManageDataDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeBumpSequence: + details, err = o.BumpSequenceDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeCreateClaimableBalance: + details, err = o.CreateClaimableBalanceDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeClaimClaimableBalance: + details, err = o.ClaimClaimableBalanceDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeBeginSponsoringFutureReserves: + details, err = o.BeginSponsoringFutureReservesDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeEndSponsoringFutureReserves: + details, err = o.EndSponsoringFutureReserveDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeRevokeSponsorship: + details, err = o.RevokeSponsorshipDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeClawback: + details, err = o.ClawbackDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeClawbackClaimableBalance: + details, err = o.ClawbackClaimableBalanceDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeSetTrustLineFlags: + details, err = o.SetTrustLineFlagsDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeLiquidityPoolDeposit: + details, err = o.LiquidityPoolDepositDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeLiquidityPoolWithdraw: + details, err = o.LiquidityPoolWithdrawDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeInvokeHostFunction: + details, err = o.InvokeHostFunctionDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeExtendFootprintTtl: + details, err = o.ExtendFootprintTtlDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeRestoreFootprint: + details, err = o.RestoreFootprintDetails() + if err != nil { + return details, err + } + default: + return details, fmt.Errorf("unknown operation type: %s", o.Operation.Body.Type.String()) + } + + return details, nil +} + +func (o *LedgerOperation) CreateAccountDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetCreateAccountOp() + if !ok { + return details, fmt.Errorf("could not access CreateAccount info for this operation (index %d)", o.OperationIndex) + } + + if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "funder"); err != nil { + return details, err + } + details["account"] = op.Destination.Address() + details["starting_balance"] = o.ConvertStroopValueToReal(op.StartingBalance) + + return details, nil +} + +func (o *LedgerOperation) addAccountAndMuxedAccountDetails(result map[string]interface{}, a xdr.MuxedAccount, prefix string) error { + account_id := a.ToAccountId() + result[prefix] = account_id.Address() + prefix = o.FormatPrefix(prefix) + if a.Type == xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + muxedAccountAddress, err := a.GetAddress() + if err != nil { + return err + } + result[prefix+"muxed"] = muxedAccountAddress + muxedAccountId, err := a.GetId() + if err != nil { + return err + } + result[prefix+"muxed_id"] = muxedAccountId + } + return nil +} + +func (o *LedgerOperation) PaymentDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetPaymentOp() + if !ok { + return details, fmt.Errorf("could not access Payment info for this operation (index %d)", o.OperationIndex) + } + + if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "from"); err != nil { + return details, err + } + if err := o.addAccountAndMuxedAccountDetails(details, op.Destination, "to"); err != nil { + return details, err + } + details["amount"] = o.ConvertStroopValueToReal(op.Amount) + if err := o.addAssetDetailsToOperationDetails(details, op.Asset, ""); err != nil { + return details, err + } + + return details, nil +} + +func (o *LedgerOperation) addAssetDetailsToOperationDetails(result map[string]interface{}, asset xdr.Asset, prefix string) error { + var assetType, code, issuer string + err := asset.Extract(&assetType, &code, &issuer) + if err != nil { + return err + } + + prefix = o.FormatPrefix(prefix) + result[prefix+"asset_type"] = assetType + + if asset.Type == xdr.AssetTypeAssetTypeNative { + result[prefix+"asset_id"] = int64(-5706705804583548011) + return nil + } + + result[prefix+"asset_code"] = code + result[prefix+"asset_issuer"] = issuer + result[prefix+"asset_id"] = o.FarmHashAsset(code, issuer, assetType) + + return nil +} + +func (o *LedgerOperation) PathPaymentStrictReceiveDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetPathPaymentStrictReceiveOp() + if !ok { + return details, fmt.Errorf("could not access PathPaymentStrictReceive info for this operation (index %d)", o.OperationIndex) + } + + if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "from"); err != nil { + return details, err + } + if err := o.addAccountAndMuxedAccountDetails(details, op.Destination, "to"); err != nil { + return details, err + } + details["amount"] = o.ConvertStroopValueToReal(op.DestAmount) + details["source_amount"] = amount.String(0) + details["source_max"] = o.ConvertStroopValueToReal(op.SendMax) + if err := o.addAssetDetailsToOperationDetails(details, op.DestAsset, ""); err != nil { + return details, err + } + if err := o.addAssetDetailsToOperationDetails(details, op.SendAsset, "source"); err != nil { + return details, err + } + + if o.Transaction.Successful() { + allOperationResults, ok := o.Transaction.Result.OperationResults() + if !ok { + return details, fmt.Errorf("could not access any results for this transaction") + } + currentOperationResult := allOperationResults[o.OperationIndex] + resultBody, ok := currentOperationResult.GetTr() + if !ok { + return details, fmt.Errorf("could not access result body for this operation (index %d)", o.OperationIndex) + } + result, ok := resultBody.GetPathPaymentStrictReceiveResult() + if !ok { + return details, fmt.Errorf("could not access PathPaymentStrictReceive result info for this operation (index %d)", o.OperationIndex) + } + details["source_amount"] = o.ConvertStroopValueToReal(result.SendAmount()) + } + + details["path"] = o.TransformPath(op.Path) + return details, nil +} + +func (o *LedgerOperation) PathPaymentStrictSendDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetPathPaymentStrictSendOp() + if !ok { + return details, fmt.Errorf("could not access PathPaymentStrictSend info for this operation (index %d)", o.OperationIndex) + } + + if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "from"); err != nil { + return details, err + } + if err := o.addAccountAndMuxedAccountDetails(details, op.Destination, "to"); err != nil { + return details, err + } + details["amount"] = float64(0) + details["source_amount"] = o.ConvertStroopValueToReal(op.SendAmount) + details["destination_min"] = amount.String(op.DestMin) + if err := o.addAssetDetailsToOperationDetails(details, op.DestAsset, ""); err != nil { + return details, err + } + if err := o.addAssetDetailsToOperationDetails(details, op.SendAsset, "source"); err != nil { + return details, err + } + + if o.Transaction.Successful() { + allOperationResults, ok := o.Transaction.Result.OperationResults() + if !ok { + return details, fmt.Errorf("could not access any results for this transaction") + } + currentOperationResult := allOperationResults[o.OperationIndex] + resultBody, ok := currentOperationResult.GetTr() + if !ok { + return details, fmt.Errorf("could not access result body for this operation (index %d)", o.OperationIndex) + } + result, ok := resultBody.GetPathPaymentStrictSendResult() + if !ok { + return details, fmt.Errorf("could not access GetPathPaymentStrictSendResult result info for this operation (index %d)", o.OperationIndex) + } + details["amount"] = o.ConvertStroopValueToReal(result.DestAmount()) + } + + details["path"] = o.TransformPath(op.Path) + + return details, nil +} +func (o *LedgerOperation) ManageBuyOfferDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetManageBuyOfferOp() + if !ok { + return details, fmt.Errorf("could not access ManageBuyOffer info for this operation (index %d)", o.OperationIndex) + } + + details["offer_id"] = int64(op.OfferId) + details["amount"] = o.ConvertStroopValueToReal(op.BuyAmount) + if err := o.addPriceDetails(details, op.Price, ""); err != nil { + return details, err + } + + if err := o.addAssetDetailsToOperationDetails(details, op.Buying, "buying"); err != nil { + return details, err + } + if err := o.addAssetDetailsToOperationDetails(details, op.Selling, "selling"); err != nil { + return details, err + } + + return details, nil +} + +func (o *LedgerOperation) addPriceDetails(result map[string]interface{}, price xdr.Price, prefix string) error { + prefix = o.FormatPrefix(prefix) + parsedPrice, err := strconv.ParseFloat(price.String(), 64) + if err != nil { + return err + } + result[prefix+"price"] = parsedPrice + result[prefix+"price_r"] = Price{ + Numerator: int32(price.N), + Denominator: int32(price.D), + } + return nil +} + +func (o *LedgerOperation) ManageSellOfferDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetManageSellOfferOp() + if !ok { + return details, fmt.Errorf("could not access ManageSellOffer info for this operation (index %d)", o.OperationIndex) + } + + details["offer_id"] = int64(op.OfferId) + details["amount"] = o.ConvertStroopValueToReal(op.Amount) + if err := o.addPriceDetails(details, op.Price, ""); err != nil { + return details, err + } + + if err := o.addAssetDetailsToOperationDetails(details, op.Buying, "buying"); err != nil { + return details, err + } + if err := o.addAssetDetailsToOperationDetails(details, op.Selling, "selling"); err != nil { + return details, err + } + + return details, nil +} +func (o *LedgerOperation) CreatePassiveSellOfferDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetCreatePassiveSellOfferOp() + if !ok { + return details, fmt.Errorf("could not access CreatePassiveSellOffer info for this operation (index %d)", o.OperationIndex) + } + + details["amount"] = o.ConvertStroopValueToReal(op.Amount) + if err := o.addPriceDetails(details, op.Price, ""); err != nil { + return details, err + } + + if err := o.addAssetDetailsToOperationDetails(details, op.Buying, "buying"); err != nil { + return details, err + } + if err := o.addAssetDetailsToOperationDetails(details, op.Selling, "selling"); err != nil { + return details, err + } + + return details, nil +} +func (o *LedgerOperation) SetOptionsDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetSetOptionsOp() + if !ok { + return details, fmt.Errorf("could not access GetSetOptions info for this operation (index %d)", o.OperationIndex) + } + + if op.InflationDest != nil { + details["inflation_dest"] = op.InflationDest.Address() + } + + if op.SetFlags != nil && *op.SetFlags > 0 { + o.addOperationFlagToOperationDetails(details, uint32(*op.SetFlags), "set") + } + + if op.ClearFlags != nil && *op.ClearFlags > 0 { + o.addOperationFlagToOperationDetails(details, uint32(*op.ClearFlags), "clear") + } + + if op.MasterWeight != nil { + details["master_key_weight"] = uint32(*op.MasterWeight) + } + + if op.LowThreshold != nil { + details["low_threshold"] = uint32(*op.LowThreshold) + } + + if op.MedThreshold != nil { + details["med_threshold"] = uint32(*op.MedThreshold) + } + + if op.HighThreshold != nil { + details["high_threshold"] = uint32(*op.HighThreshold) + } + + if op.HomeDomain != nil { + details["home_domain"] = string(*op.HomeDomain) + } + + if op.Signer != nil { + details["signer_key"] = op.Signer.Key.Address() + details["signer_weight"] = uint32(op.Signer.Weight) + } + + return details, nil +} + +func (o *LedgerOperation) addOperationFlagToOperationDetails(result map[string]interface{}, flag uint32, prefix string) { + intFlags := make([]int32, 0) + stringFlags := make([]string, 0) + + if (int64(flag) & int64(xdr.AccountFlagsAuthRequiredFlag)) > 0 { + intFlags = append(intFlags, int32(xdr.AccountFlagsAuthRequiredFlag)) + stringFlags = append(stringFlags, "auth_required") + } + + if (int64(flag) & int64(xdr.AccountFlagsAuthRevocableFlag)) > 0 { + intFlags = append(intFlags, int32(xdr.AccountFlagsAuthRevocableFlag)) + stringFlags = append(stringFlags, "auth_revocable") + } + + if (int64(flag) & int64(xdr.AccountFlagsAuthImmutableFlag)) > 0 { + intFlags = append(intFlags, int32(xdr.AccountFlagsAuthImmutableFlag)) + stringFlags = append(stringFlags, "auth_immutable") + } + + if (int64(flag) & int64(xdr.AccountFlagsAuthClawbackEnabledFlag)) > 0 { + intFlags = append(intFlags, int32(xdr.AccountFlagsAuthClawbackEnabledFlag)) + stringFlags = append(stringFlags, "auth_clawback_enabled") + } + + prefix = o.FormatPrefix(prefix) + result[prefix+"flags"] = intFlags + result[prefix+"flags_s"] = stringFlags +} + +func (o *LedgerOperation) ChangeTrustDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetChangeTrustOp() + if !ok { + return details, fmt.Errorf("could not access GetChangeTrust info for this operation (index %d)", o.OperationIndex) + } + + if op.Line.Type == xdr.AssetTypeAssetTypePoolShare { + if err := o.addLiquidityPoolAssetDetails(details, *op.Line.LiquidityPool); err != nil { + return details, err + } + } else { + if err := o.addAssetDetailsToOperationDetails(details, op.Line.ToAsset(), ""); err != nil { + return details, err + } + details["trustee"] = details["asset_issuer"] + } + + if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "trustor"); err != nil { + return details, err + } + + details["limit"] = o.ConvertStroopValueToReal(op.Limit) + + return details, nil +} + +func (o *LedgerOperation) addLiquidityPoolAssetDetails(result map[string]interface{}, lpp xdr.LiquidityPoolParameters) error { + result["asset_type"] = "liquidity_pool_shares" + if lpp.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { + return fmt.Errorf("unknown liquidity pool type %d", lpp.Type) + } + cp := lpp.ConstantProduct + poolID, err := xdr.NewPoolId(cp.AssetA, cp.AssetB, cp.Fee) + if err != nil { + return err + } + + result["liquidity_pool_id"] = o.PoolIDToString(poolID) + + return nil +} + +func (o *LedgerOperation) AllowTrustDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetAllowTrustOp() + if !ok { + return details, fmt.Errorf("could not access AllowTrust info for this operation (index %d)", o.OperationIndex) + } + + if err := o.addAssetDetailsToOperationDetails(details, op.Asset.ToAsset(o.sourceAccountXDR().ToAccountId()), ""); err != nil { + return details, err + } + if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "trustee"); err != nil { + return details, err + } + details["trustor"] = op.Trustor.Address() + shouldAuth := xdr.TrustLineFlags(op.Authorize).IsAuthorized() + details["authorize"] = shouldAuth + shouldAuthLiabilities := xdr.TrustLineFlags(op.Authorize).IsAuthorizedToMaintainLiabilitiesFlag() + if shouldAuthLiabilities { + details["authorize_to_maintain_liabilities"] = shouldAuthLiabilities + } + shouldClawbackEnabled := xdr.TrustLineFlags(op.Authorize).IsClawbackEnabledFlag() + if shouldClawbackEnabled { + details["clawback_enabled"] = shouldClawbackEnabled + } + + return details, nil +} + +func (o *LedgerOperation) AccountMergeDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + destinationAccount, ok := o.Operation.Body.GetDestination() + if !ok { + return details, fmt.Errorf("could not access Destination info for this operation (index %d)", o.OperationIndex) + } + + if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "account"); err != nil { + return details, err + } + if err := o.addAccountAndMuxedAccountDetails(details, destinationAccount, "into"); err != nil { + return details, err + } + + return details, nil +} + +// Inflation operations don't have information that affects the details struct +func (o *LedgerOperation) InflationDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + return details, nil +} + +func (o *LedgerOperation) ManageDataDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetManageDataOp() + if !ok { + return details, fmt.Errorf("could not access GetManageData info for this operation (index %d)", o.OperationIndex) + } + + details["name"] = string(op.DataName) + if op.DataValue != nil { + details["value"] = base64.StdEncoding.EncodeToString(*op.DataValue) + } else { + details["value"] = nil + } + + return details, nil +} + +func (o *LedgerOperation) BumpSequenceDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetBumpSequenceOp() + if !ok { + return details, fmt.Errorf("could not access BumpSequence info for this operation (index %d)", o.OperationIndex) + } + + details["bump_to"] = fmt.Sprintf("%d", op.BumpTo) + + return details, nil +} +func (o *LedgerOperation) CreateClaimableBalanceDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetCreateClaimableBalanceOp() + if !ok { + return details, fmt.Errorf("could not access CreateClaimableBalance info for this operation (index %d)", o.OperationIndex) + } + + details["asset"] = op.Asset.StringCanonical() + details["amount"] = o.ConvertStroopValueToReal(op.Amount) + details["claimants"] = o.TransformClaimants(op.Claimants) + + return details, nil +} + +func (o *LedgerOperation) ClaimClaimableBalanceDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetClaimClaimableBalanceOp() + if !ok { + return details, fmt.Errorf("could not access ClaimClaimableBalance info for this operation (index %d)", o.OperationIndex) + } + + balanceID, err := xdr.MarshalHex(op.BalanceId) + if err != nil { + return details, fmt.Errorf("invalid balanceId in op: %d", o.OperationIndex) + } + details["balance_id"] = balanceID + if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "claimant"); err != nil { + return details, err + } + + return details, nil +} + +func (o *LedgerOperation) BeginSponsoringFutureReservesDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetBeginSponsoringFutureReservesOp() + if !ok { + return details, fmt.Errorf("could not access BeginSponsoringFutureReserves info for this operation (index %d)", o.OperationIndex) + } + + details["sponsored_id"] = op.SponsoredId.Address() + + return details, nil +} + +func (o *LedgerOperation) EndSponsoringFutureReserveDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + beginSponsorOp := o.findInitatingBeginSponsoringOp() + if beginSponsorOp != nil { + beginSponsorshipSource := o.sourceAccountXDR() + if err := o.addAccountAndMuxedAccountDetails(details, beginSponsorshipSource, "begin_sponsor"); err != nil { + return details, err + } + } + + return details, nil +} + +func (o *LedgerOperation) findInitatingBeginSponsoringOp() *SponsorshipOutput { + if !o.Transaction.Successful() { + // Failed transactions may not have a compliant sandwich structure + // we can rely on (e.g. invalid nesting or a being operation with the wrong sponsoree ID) + // and thus we bail out since we could return incorrect information. + return nil + } + sponsoree := o.sourceAccountXDR().ToAccountId() + operations := o.Transaction.Envelope.Operations() + for i := int(o.OperationIndex) - 1; i >= 0; i-- { + if beginOp, ok := operations[i].Body.GetBeginSponsoringFutureReservesOp(); ok && + beginOp.SponsoredId.Address() == sponsoree.Address() { + result := SponsorshipOutput{ + Operation: operations[i], + OperationIndex: uint32(i), + } + return &result + } + } + return nil +} + +func (o *LedgerOperation) RevokeSponsorshipDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetRevokeSponsorshipOp() + if !ok { + return details, fmt.Errorf("could not access RevokeSponsorship info for this operation (index %d)", o.OperationIndex) + } + + switch op.Type { + case xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry: + if err := o.addLedgerKeyToDetails(details, *op.LedgerKey); err != nil { + return details, err + } + case xdr.RevokeSponsorshipTypeRevokeSponsorshipSigner: + details["signer_account_id"] = op.Signer.AccountId.Address() + details["signer_key"] = op.Signer.SignerKey.Address() + } + + return details, nil +} + +func (o *LedgerOperation) addLedgerKeyToDetails(result map[string]interface{}, ledgerKey xdr.LedgerKey) error { + switch ledgerKey.Type { + case xdr.LedgerEntryTypeAccount: + result["account_id"] = ledgerKey.Account.AccountId.Address() + case xdr.LedgerEntryTypeClaimableBalance: + marshalHex, err := xdr.MarshalHex(ledgerKey.ClaimableBalance.BalanceId) + if err != nil { + return fmt.Errorf("in claimable balance: %w", err) + } + result["claimable_balance_id"] = marshalHex + case xdr.LedgerEntryTypeData: + result["data_account_id"] = ledgerKey.Data.AccountId.Address() + result["data_name"] = string(ledgerKey.Data.DataName) + case xdr.LedgerEntryTypeOffer: + result["offer_id"] = int64(ledgerKey.Offer.OfferId) + case xdr.LedgerEntryTypeTrustline: + result["trustline_account_id"] = ledgerKey.TrustLine.AccountId.Address() + if ledgerKey.TrustLine.Asset.Type == xdr.AssetTypeAssetTypePoolShare { + result["trustline_liquidity_pool_id"] = o.PoolIDToString(*ledgerKey.TrustLine.Asset.LiquidityPoolId) + } else { + result["trustline_asset"] = ledgerKey.TrustLine.Asset.ToAsset().StringCanonical() + } + case xdr.LedgerEntryTypeLiquidityPool: + result["liquidity_pool_id"] = o.PoolIDToString(ledgerKey.LiquidityPool.LiquidityPoolId) + } + return nil +} + +func (o *LedgerOperation) ClawbackDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetClawbackOp() + if !ok { + return details, fmt.Errorf("could not access Clawback info for this operation (index %d)", o.OperationIndex) + } + + if err := o.addAssetDetailsToOperationDetails(details, op.Asset, ""); err != nil { + return details, err + } + if err := o.addAccountAndMuxedAccountDetails(details, op.From, "from"); err != nil { + return details, err + } + details["amount"] = o.ConvertStroopValueToReal(op.Amount) + + return details, nil +} +func (o *LedgerOperation) ClawbackClaimableBalanceDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetClawbackClaimableBalanceOp() + if !ok { + return details, fmt.Errorf("could not access ClawbackClaimableBalance info for this operation (index %d)", o.OperationIndex) + } + + balanceID, err := xdr.MarshalHex(op.BalanceId) + if err != nil { + return details, fmt.Errorf("invalid balanceId in op: %d", o.OperationIndex) + } + details["balance_id"] = balanceID + + return details, nil +} +func (o *LedgerOperation) SetTrustLineFlagsDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetSetTrustLineFlagsOp() + if !ok { + return details, fmt.Errorf("could not access SetTrustLineFlags info for this operation (index %d)", o.OperationIndex) + } + + details["trustor"] = op.Trustor.Address() + if err := o.addAssetDetailsToOperationDetails(details, op.Asset, ""); err != nil { + return details, err + } + if op.SetFlags > 0 { + o.addTrustLineFlagToDetails(details, xdr.TrustLineFlags(op.SetFlags), "set") + + } + if op.ClearFlags > 0 { + o.addTrustLineFlagToDetails(details, xdr.TrustLineFlags(op.ClearFlags), "clear") + } + + return details, nil +} + +func (o *LedgerOperation) addTrustLineFlagToDetails(result map[string]interface{}, f xdr.TrustLineFlags, prefix string) { + var ( + n []int32 + s []string + ) + + if f.IsAuthorized() { + n = append(n, int32(xdr.TrustLineFlagsAuthorizedFlag)) + s = append(s, "authorized") + } + + if f.IsAuthorizedToMaintainLiabilitiesFlag() { + n = append(n, int32(xdr.TrustLineFlagsAuthorizedToMaintainLiabilitiesFlag)) + s = append(s, "authorized_to_maintain_liabilities") + } + + if f.IsClawbackEnabledFlag() { + n = append(n, int32(xdr.TrustLineFlagsTrustlineClawbackEnabledFlag)) + s = append(s, "clawback_enabled") + } + + prefix = o.FormatPrefix(prefix) + result[prefix+"flags"] = n + result[prefix+"flags_s"] = s +} + +func (o *LedgerOperation) LiquidityPoolDepositDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetLiquidityPoolDepositOp() + if !ok { + return details, fmt.Errorf("could not access LiquidityPoolDeposit info for this operation (index %d)", o.OperationIndex) + } + + details["liquidity_pool_id"] = o.PoolIDToString(op.LiquidityPoolId) + var ( + assetA, assetB xdr.Asset + depositedA, depositedB xdr.Int64 + sharesReceived xdr.Int64 + ) + if o.Transaction.Successful() { + // we will use the defaults (omitted asset and 0 amounts) if the transaction failed + lp, delta, err := o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) + if err != nil { + return nil, err + } + params := lp.Body.ConstantProduct.Params + assetA, assetB = params.AssetA, params.AssetB + depositedA, depositedB = delta.ReserveA, delta.ReserveB + sharesReceived = delta.TotalPoolShares + } + + // Process ReserveA Details + if err := o.addAssetDetailsToOperationDetails(details, assetA, "reserve_a"); err != nil { + return details, err + } + details["reserve_a_max_amount"] = o.ConvertStroopValueToReal(op.MaxAmountA) + depositA, err := strconv.ParseFloat(amount.String(depositedA), 64) + if err != nil { + return details, err + } + details["reserve_a_deposit_amount"] = depositA + + //Process ReserveB Details + if err := o.addAssetDetailsToOperationDetails(details, assetB, "reserve_b"); err != nil { + return details, err + } + details["reserve_b_max_amount"] = o.ConvertStroopValueToReal(op.MaxAmountB) + depositB, err := strconv.ParseFloat(amount.String(depositedB), 64) + if err != nil { + return details, err + } + details["reserve_b_deposit_amount"] = depositB + + if err := o.addPriceDetails(details, op.MinPrice, "min"); err != nil { + return details, err + } + if err := o.addPriceDetails(details, op.MaxPrice, "max"); err != nil { + return details, err + } + + sharesToFloat, err := strconv.ParseFloat(amount.String(sharesReceived), 64) + if err != nil { + return details, err + } + details["shares_received"] = sharesToFloat + + return details, nil +} + +// operation xdr.Operation, operationIndex int32, transaction LedgerTransaction, ledgerSeq int32 +func (o *LedgerOperation) getLiquidityPoolAndProductDelta(lpID *xdr.PoolId) (*xdr.LiquidityPoolEntry, *LiquidityPoolDelta, error) { + changes, err := o.Transaction.GetOperationChanges(uint32(o.OperationIndex)) + if err != nil { + return nil, nil, err + } + + for _, c := range changes { + if c.Type != xdr.LedgerEntryTypeLiquidityPool { + continue + } + // The delta can be caused by a full removal or full creation of the liquidity pool + var lp *xdr.LiquidityPoolEntry + var preA, preB, preShares xdr.Int64 + if c.Pre != nil { + if lpID != nil && c.Pre.Data.LiquidityPool.LiquidityPoolId != *lpID { + // if we were looking for specific pool id, then check on it + continue + } + lp = c.Pre.Data.LiquidityPool + if c.Pre.Data.LiquidityPool.Body.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { + return nil, nil, fmt.Errorf("unexpected liquity pool body type %d", c.Pre.Data.LiquidityPool.Body.Type) + } + cpPre := c.Pre.Data.LiquidityPool.Body.ConstantProduct + preA, preB, preShares = cpPre.ReserveA, cpPre.ReserveB, cpPre.TotalPoolShares + } + var postA, postB, postShares xdr.Int64 + if c.Post != nil { + if lpID != nil && c.Post.Data.LiquidityPool.LiquidityPoolId != *lpID { + // if we were looking for specific pool id, then check on it + continue + } + lp = c.Post.Data.LiquidityPool + if c.Post.Data.LiquidityPool.Body.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { + return nil, nil, fmt.Errorf("unexpected liquity pool body type %d", c.Post.Data.LiquidityPool.Body.Type) + } + cpPost := c.Post.Data.LiquidityPool.Body.ConstantProduct + postA, postB, postShares = cpPost.ReserveA, cpPost.ReserveB, cpPost.TotalPoolShares + } + delta := &LiquidityPoolDelta{ + ReserveA: postA - preA, + ReserveB: postB - preB, + TotalPoolShares: postShares - preShares, + } + return lp, delta, nil + } + + return nil, nil, fmt.Errorf("liquidity pool change not found") +} + +func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetLiquidityPoolWithdrawOp() + if !ok { + return details, fmt.Errorf("could not access LiquidityPoolWithdraw info for this operation (index %d)", o.OperationIndex) + } + + details["liquidity_pool_id"] = o.PoolIDToString(op.LiquidityPoolId) + var ( + assetA, assetB xdr.Asset + receivedA, receivedB xdr.Int64 + ) + if o.Transaction.Successful() { + // we will use the defaults (omitted asset and 0 amounts) if the transaction failed + lp, delta, err := o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) + if err != nil { + return nil, err + } + params := lp.Body.ConstantProduct.Params + assetA, assetB = params.AssetA, params.AssetB + receivedA, receivedB = -delta.ReserveA, -delta.ReserveB + } + // Process AssetA Details + if err := o.addAssetDetailsToOperationDetails(details, assetA, "reserve_a"); err != nil { + return details, err + } + details["reserve_a_min_amount"] = o.ConvertStroopValueToReal(op.MinAmountA) + details["reserve_a_withdraw_amount"] = o.ConvertStroopValueToReal(receivedA) + + // Process AssetB Details + if err := o.addAssetDetailsToOperationDetails(details, assetB, "reserve_b"); err != nil { + return details, err + } + details["reserve_b_min_amount"] = o.ConvertStroopValueToReal(op.MinAmountB) + details["reserve_b_withdraw_amount"] = o.ConvertStroopValueToReal(receivedB) + + details["shares"] = o.ConvertStroopValueToReal(op.Amount) + + return details, nil +} + +func (o *LedgerOperation) InvokeHostFunctionDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetInvokeHostFunctionOp() + if !ok { + return details, fmt.Errorf("could not access InvokeHostFunction info for this operation (index %d)", o.OperationIndex) + } + + details["function"] = op.HostFunction.Type.String() + + switch op.HostFunction.Type { + case xdr.HostFunctionTypeHostFunctionTypeInvokeContract: + invokeArgs := op.HostFunction.MustInvokeContract() + args := make([]xdr.ScVal, 0, len(invokeArgs.Args)+2) + args = append(args, xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &invokeArgs.ContractAddress}) + args = append(args, xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &invokeArgs.FunctionName}) + args = append(args, invokeArgs.Args...) + + details["type"] = "invoke_contract" + + contractId, err := invokeArgs.ContractAddress.String() + if err != nil { + return nil, err + } + + details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() + details["contract_id"] = contractId + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + details["contract_code_hash"] = contractCodeHash + } + + details["parameters"], details["parameters_decoded"] = o.serializeParameters(args) + + if balanceChanges, err := o.parseAssetBalanceChangesFromContractEvents(); err != nil { + return nil, err + } else { + details["asset_balance_changes"] = balanceChanges + } + + case xdr.HostFunctionTypeHostFunctionTypeCreateContract: + args := op.HostFunction.MustCreateContract() + details["type"] = "create_contract" + + details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + details["contract_id"] = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + details["contract_code_hash"] = contractCodeHash + } + + preimageTypeMap := o.switchContractIdPreimageType(args.ContractIdPreimage) + for key, val := range preimageTypeMap { + if _, ok := preimageTypeMap[key]; ok { + details[key] = val + } + } + case xdr.HostFunctionTypeHostFunctionTypeUploadContractWasm: + details["type"] = "upload_wasm" + details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + details["contract_code_hash"] = contractCodeHash + } + case xdr.HostFunctionTypeHostFunctionTypeCreateContractV2: + args := op.HostFunction.MustCreateContractV2() + details["type"] = "create_contract_v2" + + details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + details["contract_id"] = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + details["contract_code_hash"] = contractCodeHash + } + + // ConstructorArgs is a list of ScVals + // This will initially be handled the same as InvokeContractParams until a different + // model is found necessary. + constructorArgs := args.ConstructorArgs + details["parameters"], details["parameters_decoded"] = o.serializeParameters(constructorArgs) + + preimageTypeMap := o.switchContractIdPreimageType(args.ContractIdPreimage) + for key, val := range preimageTypeMap { + if _, ok := preimageTypeMap[key]; ok { + details[key] = val + } + } + default: + panic(fmt.Errorf("unknown host function type: %s", op.HostFunction.Type)) + } + + return details, nil +} + +func (o *LedgerOperation) ExtendFootprintTtlDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + op, ok := o.Operation.Body.GetExtendFootprintTtlOp() + if !ok { + return details, fmt.Errorf("could not access ExtendFootprintTtl info for this operation (index %d)", o.OperationIndex) + } + + details["type"] = "extend_footprint_ttl" + details["extend_to"] = int32(op.ExtendTo) + + details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + details["contract_id"] = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + details["contract_code_hash"] = contractCodeHash + } + + return details, nil +} +func (o *LedgerOperation) RestoreFootprintDetails() (map[string]interface{}, error) { + details := map[string]interface{}{} + _, ok := o.Operation.Body.GetRestoreFootprintOp() + if !ok { + return details, fmt.Errorf("could not access InvokeHostFunction info for this operation (index %d)", o.OperationIndex) + } + + details["type"] = "restore_footprint" + + details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + details["contract_id"] = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + details["contract_code_hash"] = contractCodeHash + } + + return details, nil +} + +func (o *LedgerOperation) serializeParameters(args []xdr.ScVal) ([]map[string]string, []map[string]string) { + params := make([]map[string]string, 0, len(args)) + paramsDecoded := make([]map[string]string, 0, len(args)) + + for _, param := range args { + serializedParam := map[string]string{} + serializedParam["value"] = "n/a" + serializedParam["type"] = "n/a" + + serializedParamDecoded := map[string]string{} + serializedParamDecoded["value"] = "n/a" + serializedParamDecoded["type"] = "n/a" + + if scValTypeName, ok := param.ArmForSwitch(int32(param.Type)); ok { + serializedParam["type"] = scValTypeName + serializedParamDecoded["type"] = scValTypeName + if raw, err := param.MarshalBinary(); err == nil { + serializedParam["value"] = base64.StdEncoding.EncodeToString(raw) + serializedParamDecoded["value"] = param.String() + } + } + params = append(params, serializedParam) + paramsDecoded = append(paramsDecoded, serializedParamDecoded) + } + + return params, paramsDecoded +} + +func (o *LedgerOperation) parseAssetBalanceChangesFromContractEvents() ([]map[string]interface{}, error) { + balanceChanges := []map[string]interface{}{} + + diagnosticEvents, err := o.Transaction.GetDiagnosticEvents() + if err != nil { + // this operation in this context must be an InvokeHostFunctionOp, therefore V3Meta should be present + // as it's in same soroban model, so if any err, it's real, + return nil, err + } + + for _, contractEvent := range o.filterEvents(diagnosticEvents) { + // Parse the xdr contract event to contractevents.StellarAssetContractEvent model + + // has some convenience like to/from attributes are expressed in strkey format for accounts(G...) and contracts(C...) + if sacEvent, err := contractevents.NewStellarAssetContractEvent(&contractEvent, o.NetworkPassphrase); err == nil { + switch sacEvent.GetType() { + case contractevents.EventTypeTransfer: + transferEvt := sacEvent.(*contractevents.TransferEvent) + balanceChanges = append(balanceChanges, o.createSACBalanceChangeEntry(transferEvt.From, transferEvt.To, transferEvt.Amount, transferEvt.Asset, "transfer")) + case contractevents.EventTypeMint: + mintEvt := sacEvent.(*contractevents.MintEvent) + balanceChanges = append(balanceChanges, o.createSACBalanceChangeEntry("", mintEvt.To, mintEvt.Amount, mintEvt.Asset, "mint")) + case contractevents.EventTypeClawback: + clawbackEvt := sacEvent.(*contractevents.ClawbackEvent) + balanceChanges = append(balanceChanges, o.createSACBalanceChangeEntry(clawbackEvt.From, "", clawbackEvt.Amount, clawbackEvt.Asset, "clawback")) + case contractevents.EventTypeBurn: + burnEvt := sacEvent.(*contractevents.BurnEvent) + balanceChanges = append(balanceChanges, o.createSACBalanceChangeEntry(burnEvt.From, "", burnEvt.Amount, burnEvt.Asset, "burn")) + } + } + } + + return balanceChanges, nil +} + +func (o *LedgerOperation) filterEvents(diagnosticEvents []xdr.DiagnosticEvent) []xdr.ContractEvent { + var filtered []xdr.ContractEvent + for _, diagnosticEvent := range diagnosticEvents { + if !diagnosticEvent.InSuccessfulContractCall || diagnosticEvent.Event.Type != xdr.ContractEventTypeContract { + continue + } + filtered = append(filtered, diagnosticEvent.Event) + } + return filtered +} + +// fromAccount - strkey format of contract or address +// toAccount - strkey format of contract or address, or nillable +// amountChanged - absolute value that asset balance changed +// asset - the fully qualified issuer:code for asset that had balance change +// changeType - the type of source sac event that triggered this change +// +// return - a balance changed record expressed as map of key/value's +func (o *LedgerOperation) createSACBalanceChangeEntry(fromAccount string, toAccount string, amountChanged xdr.Int128Parts, asset xdr.Asset, changeType string) map[string]interface{} { + balanceChange := map[string]interface{}{} + + if fromAccount != "" { + balanceChange["from"] = fromAccount + } + if toAccount != "" { + balanceChange["to"] = toAccount + } + + balanceChange["type"] = changeType + balanceChange["amount"] = amount.String128(amountChanged) + o.addAssetDetails(balanceChange, asset, "") + return balanceChange +} + +// addAssetDetails sets the details for `a` on `result` using keys with `prefix` +func (o *LedgerOperation) addAssetDetails(result map[string]interface{}, a xdr.Asset, prefix string) error { + var ( + assetType string + code string + issuer string + ) + err := a.Extract(&assetType, &code, &issuer) + if err != nil { + err = fmt.Errorf("xdr.Asset.Extract error: %w", err) + return err + } + result[prefix+"asset_type"] = assetType + + if a.Type == xdr.AssetTypeAssetTypeNative { + return nil + } + + result[prefix+"asset_code"] = code + result[prefix+"asset_issuer"] = issuer + return nil +} + +func (o *LedgerOperation) switchContractIdPreimageType(contractIdPreimage xdr.ContractIdPreimage) map[string]interface{} { + details := map[string]interface{}{} + + switch contractIdPreimage.Type { + case xdr.ContractIdPreimageTypeContractIdPreimageFromAddress: + fromAddress := contractIdPreimage.MustFromAddress() + address, err := fromAddress.Address.String() + if err != nil { + panic(fmt.Errorf("error obtaining address for: %s", contractIdPreimage.Type)) + } + details["from"] = "address" + details["address"] = address + case xdr.ContractIdPreimageTypeContractIdPreimageFromAsset: + details["from"] = "asset" + details["asset"] = contractIdPreimage.MustFromAsset().StringCanonical() + default: + panic(fmt.Errorf("unknown contract id type: %s", contractIdPreimage.Type)) + } + + return details +} + +func (o *LedgerOperation) ConvertStroopValueToReal(input xdr.Int64) float64 { + output, _ := big.NewRat(int64(input), int64(10000000)).Float64() + return output +} + +func (o *LedgerOperation) FormatPrefix(p string) string { + if p != "" { + p += "_" + } + return p +} + +func (o *LedgerOperation) FarmHashAsset(assetCode, assetIssuer, assetType string) int64 { + asset := fmt.Sprintf("%s%s%s", assetCode, assetIssuer, assetType) + hash := farm.Fingerprint64([]byte(asset)) + + return int64(hash) +} + +// Path is a representation of an asset without an ID that forms part of a path in a path payment +type Path struct { + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` +} + +func (o *LedgerOperation) TransformPath(initialPath []xdr.Asset) []Path { + if len(initialPath) == 0 { + return nil + } + var path = make([]Path, 0) + for _, pathAsset := range initialPath { + var assetType, code, issuer string + err := pathAsset.Extract(&assetType, &code, &issuer) + if err != nil { + return nil + } + + path = append(path, Path{ + AssetType: assetType, + AssetIssuer: issuer, + AssetCode: code, + }) + } + return path +} + +type Price struct { + Numerator int32 `json:"n"` + Denominator int32 `json:"d"` +} + +func (o *LedgerOperation) PoolIDToString(id xdr.PoolId) string { + return xdr.Hash(id).HexString() +} + +type Claimant struct { + Destination string `json:"destination"` + Predicate xdr.ClaimPredicate `json:"predicate"` +} + +func (o *LedgerOperation) TransformClaimants(claimants []xdr.Claimant) []Claimant { + var transformed []Claimant + for _, c := range claimants { + switch c.Type { + case 0: + transformed = append(transformed, Claimant{ + Destination: c.V0.Destination.Address(), + Predicate: c.V0.Predicate, + }) + } + } + return transformed +} + +type SponsorshipOutput struct { + Operation xdr.Operation + OperationIndex uint32 +} + +type LiquidityPoolDelta struct { + ReserveA xdr.Int64 + ReserveB xdr.Int64 + TotalPoolShares xdr.Int64 +} diff --git a/ingest/ledger_operation_test.go b/ingest/ledger_operation_test.go new file mode 100644 index 0000000000..18c4760219 --- /dev/null +++ b/ingest/ledger_operation_test.go @@ -0,0 +1,1474 @@ +package ingest + +import ( + "testing" + + "github.com/stellar/go/xdr" + "github.com/stretchr/testify/assert" +) + +func TestOperation(t *testing.T) { + testOutput := resultTestOutput() + for i, op := range operationTestInput() { + ledgerOperation := LedgerOperation{ + OperationIndex: int32(i), + Operation: op, + Transaction: transactionTestInput(), + NetworkPassphrase: "", + } + + result, err := ledgerOperation.OperationDetails() + assert.Equal(t, testOutput[i].err, err) + assert.Equal(t, testOutput[i].result, result) + } +} + +func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { + lcm = xdr.LedgerCloseMeta{ + V: 1, + V1: &xdr.LedgerCloseMetaV1{ + LedgerHeader: xdr.LedgerHeaderHistoryEntry{ + Header: xdr.LedgerHeader{ + LedgerSeq: 30578981, + LedgerVersion: 22, + }, + }, + }, + } + + return lcm +} + +func transactionTestInput() *LedgerTransaction { + testAccountAddress := "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA" + testAccountID, _ := xdr.AddressToAccountId(testAccountAddress) + dummyBool := true + + ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) + muxedAccount := xdr.MuxedAccount{ + Type: 256, + Ed25519: &ed25519, + Med25519: &xdr.MuxedAccountMed25519{ + Id: xdr.Uint64(123), + Ed25519: ed25519, + }, + } + + memoText := "test memo" + minSeqNum := xdr.SequenceNumber(123) + + transaction := &LedgerTransaction{ + Index: 1, + Envelope: xdr.TransactionEnvelope{ + Type: xdr.EnvelopeTypeEnvelopeTypeTx, + V1: &xdr.TransactionV1Envelope{ + Signatures: []xdr.DecoratedSignature{ + { + Signature: []byte{0x11, 0x22}, + }, + }, + Tx: xdr.Transaction{ + SourceAccount: muxedAccount, + SeqNum: xdr.SequenceNumber(30578981), + Fee: xdr.Uint32(4560), + Operations: []xdr.Operation{ + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + }, + Memo: xdr.Memo{ + Type: xdr.MemoTypeMemoText, + Text: &memoText, + }, + Cond: xdr.Preconditions{ + Type: 2, + V2: &xdr.PreconditionsV2{ + TimeBounds: &xdr.TimeBounds{ + MinTime: xdr.TimePoint(1), + MaxTime: xdr.TimePoint(10), + }, + LedgerBounds: &xdr.LedgerBounds{ + MinLedger: 2, + MaxLedger: 20, + }, + MinSeqNum: &minSeqNum, + MinSeqAge: 456, + MinSeqLedgerGap: 789, + }, + }, + Ext: xdr.TransactionExt{ + V: 1, + SorobanData: &xdr.SorobanTransactionData{ + Resources: xdr.SorobanResources{ + Instructions: 123, + ReadBytes: 456, + WriteBytes: 789, + Footprint: xdr.LedgerFootprint{ + ReadOnly: []xdr.LedgerKey{ + { + Type: 6, + ContractData: &xdr.LedgerKeyContractData{ + Contract: xdr.ScAddress{ + Type: 1, + ContractId: &xdr.Hash{0x12, 0x34}, + }, + Key: xdr.ScVal{ + Type: 0, + B: &dummyBool, + }, + }, + }, + }, + }, + }, + ResourceFee: 1234, + }, + }, + }, + }, + }, + Result: xdr.TransactionResultPair{ + TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, + Result: xdr.TransactionResult{ + FeeCharged: xdr.Int64(789), + Result: xdr.TransactionResultResult{ + Code: 0, + Results: &[]xdr.OperationResult{ + {}, + {}, + {}, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 2, + PathPaymentStrictReceiveResult: &xdr.PathPaymentStrictReceiveResult{ + Code: 0, + Success: &xdr.PathPaymentStrictReceiveResultSuccess{}, + NoIssuer: &xdr.Asset{}, + }, + }, + }, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 13, + PathPaymentStrictSendResult: &xdr.PathPaymentStrictSendResult{ + Code: 0, + Success: &xdr.PathPaymentStrictSendResultSuccess{ + Last: xdr.SimplePaymentResult{ + Amount: 640000000, + }, + }, + NoIssuer: &xdr.Asset{}, + }, + }, + }, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 22, + LiquidityPoolDepositResult: &xdr.LiquidityPoolDepositResult{ + Code: 0, + }, + }, + }, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 23, + LiquidityPoolWithdrawResult: &xdr.LiquidityPoolWithdrawResult{ + Code: 0, + }, + }, + }, + {}, + }, + }, + }, + }, + FeeChanges: xdr.LedgerEntryChanges{ + { + Type: xdr.LedgerEntryChangeTypeLedgerEntryState, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: xdr.LedgerEntryTypeAccount, + Account: &xdr.AccountEntry{ + AccountId: xdr.AccountId{ + Type: 0, + Ed25519: &ed25519, + }, + Balance: 1000, + }, + }, + }, + }, + {}, + }, + UnsafeMeta: xdr.TransactionMeta{ + V: 3, + V3: &xdr.TransactionMetaV3{ + TxChangesAfter: xdr.LedgerEntryChanges{}, + SorobanMeta: &xdr.SorobanTransactionMeta{ + Ext: xdr.SorobanTransactionMetaExt{ + V: 1, + V1: &xdr.SorobanTransactionMetaExtV1{ + TotalNonRefundableResourceFeeCharged: 321, + TotalRefundableResourceFeeCharged: 123, + RentFeeCharged: 456, + }, + }, + }, + Operations: []xdr.OperationMeta{ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + { + Changes: []xdr.LedgerEntryChange{ + { + Type: 3, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: 5, + LiquidityPool: &xdr.LiquidityPoolEntry{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Body: xdr.LiquidityPoolEntryBody{ + Type: 0, + ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ + Params: xdr.LiquidityPoolConstantProductParameters{ + AssetA: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + AssetB: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + Fee: 1, + }, + ReserveA: 1, + ReserveB: 1, + TotalPoolShares: 1, + PoolSharesTrustLineCount: 1, + }, + }, + }, + }, + }, + }, + { + Type: 1, + Updated: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: 5, + LiquidityPool: &xdr.LiquidityPoolEntry{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Body: xdr.LiquidityPoolEntryBody{ + Type: 0, + ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ + Params: xdr.LiquidityPoolConstantProductParameters{ + AssetA: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + AssetB: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + Fee: 1, + }, + ReserveA: 2, + ReserveB: 2, + TotalPoolShares: 2, + PoolSharesTrustLineCount: 1, + }, + }, + }, + }, + }, + }, + }, + }, + { + Changes: []xdr.LedgerEntryChange{ + { + Type: 3, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: 5, + LiquidityPool: &xdr.LiquidityPoolEntry{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Body: xdr.LiquidityPoolEntryBody{ + Type: 0, + ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ + Params: xdr.LiquidityPoolConstantProductParameters{ + AssetA: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + AssetB: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + Fee: 1, + }, + ReserveA: 1, + ReserveB: 1, + TotalPoolShares: 1, + PoolSharesTrustLineCount: 1, + }, + }, + }, + }, + }, + }, + { + Type: 1, + Updated: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: 5, + LiquidityPool: &xdr.LiquidityPoolEntry{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Body: xdr.LiquidityPoolEntryBody{ + Type: 0, + ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ + Params: xdr.LiquidityPoolConstantProductParameters{ + AssetA: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + AssetB: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + Fee: 1, + }, + ReserveA: 2, + ReserveB: 2, + TotalPoolShares: 2, + PoolSharesTrustLineCount: 1, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + LedgerVersion: 22, + Ledger: ledgerTestInput(), + Hash: xdr.Hash{}, + } + + return transaction +} + +type testOutput struct { + err error + result map[string]interface{} +} + +func operationTestInput() []xdr.Operation { + testAccountAddress := "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA" + testAccountID, _ := xdr.AddressToAccountId(testAccountAddress) + testAccountMuxed := testAccountID.ToMuxedAccount() + + sourceAccountAddress := "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN" + sourceAccountID, _ := xdr.AddressToAccountId(sourceAccountAddress) + sourceAccountMuxed := sourceAccountID.ToMuxedAccount() + + usdtAsset := xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + } + assetCode, _ := usdtAsset.ToAssetCode("USDT") + nativeAsset := xdr.MustNewNativeAsset() + + clearFlags := xdr.Uint32(3) + setFlags := xdr.Uint32(4) + masterWeight := xdr.Uint32(3) + lowThresh := xdr.Uint32(1) + medThresh := xdr.Uint32(3) + highThresh := xdr.Uint32(5) + homeDomain := xdr.String32("2019=DRA;n-test") + signerKey, _ := xdr.NewSignerKey(xdr.SignerKeyTypeSignerKeyTypeEd25519, xdr.Uint256([32]byte{})) + signer := xdr.Signer{ + Key: signerKey, + Weight: xdr.Uint32(1), + } + + usdtChangeTrustAsset := xdr.ChangeTrustAsset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x53, 0x44}), + Issuer: testAccountID, + }, + } + + usdtLiquidityPoolShare := xdr.ChangeTrustAsset{ + Type: xdr.AssetTypeAssetTypePoolShare, + LiquidityPool: &xdr.LiquidityPoolParameters{ + Type: xdr.LiquidityPoolTypeLiquidityPoolConstantProduct, + ConstantProduct: &xdr.LiquidityPoolConstantProductParameters{ + AssetA: nativeAsset, + AssetB: usdtAsset, + Fee: 30, + }, + }, + } + + dataValue := xdr.DataValue([]byte{0x76, 0x61, 0x6c, 0x75, 0x65}) + + testClaimant := xdr.Claimant{ + Type: xdr.ClaimantTypeClaimantTypeV0, + V0: &xdr.ClaimantV0{ + Destination: testAccountID, + Predicate: xdr.ClaimPredicate{ + Type: xdr.ClaimPredicateTypeClaimPredicateUnconditional, + }, + }, + } + + claimableBalance := xdr.ClaimableBalanceId{ + Type: xdr.ClaimableBalanceIdTypeClaimableBalanceIdTypeV0, + V0: &xdr.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9}, + } + + contractHash := xdr.Hash{0x12, 0x34, 0x56, 0x78} + salt := [32]byte{0x12, 0x34, 0x56} + wasm := []byte{0x12, 0x34} + dummyBool := true + + operation := []xdr.Operation{ + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeCreateAccount, + CreateAccountOp: &xdr.CreateAccountOp{ + StartingBalance: 25000000, + Destination: testAccountID, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypePayment, + PaymentOp: &xdr.PaymentOp{ + Destination: testAccountMuxed, + Asset: usdtAsset, + Amount: 350000000, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypePayment, + PaymentOp: &xdr.PaymentOp{ + Destination: testAccountMuxed, + Asset: nativeAsset, + Amount: 350000000, + }, + }, + }, + { + SourceAccount: &sourceAccountMuxed, + Body: xdr.OperationBody{ + Type: xdr.OperationTypePathPaymentStrictReceive, + PathPaymentStrictReceiveOp: &xdr.PathPaymentStrictReceiveOp{ + SendAsset: nativeAsset, + SendMax: 8951495900, + Destination: testAccountMuxed, + DestAsset: nativeAsset, + DestAmount: 8951495900, + Path: []xdr.Asset{usdtAsset}, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeManageSellOffer, + ManageSellOfferOp: &xdr.ManageSellOfferOp{ + Selling: usdtAsset, + Buying: nativeAsset, + Amount: 765860000, + Price: xdr.Price{ + N: 128523, + D: 250000, + }, + OfferId: 0, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeCreatePassiveSellOffer, + CreatePassiveSellOfferOp: &xdr.CreatePassiveSellOfferOp{ + Selling: nativeAsset, + Buying: usdtAsset, + Amount: 631595000, + Price: xdr.Price{ + N: 99583200, + D: 1257990000, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeSetOptions, + SetOptionsOp: &xdr.SetOptionsOp{ + InflationDest: &testAccountID, + ClearFlags: &clearFlags, + SetFlags: &setFlags, + MasterWeight: &masterWeight, + LowThreshold: &lowThresh, + MedThreshold: &medThresh, + HighThreshold: &highThresh, + HomeDomain: &homeDomain, + Signer: &signer, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeChangeTrust, + ChangeTrustOp: &xdr.ChangeTrustOp{ + Line: usdtChangeTrustAsset, + Limit: xdr.Int64(500000000000000000), + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeChangeTrust, + ChangeTrustOp: &xdr.ChangeTrustOp{ + Line: usdtLiquidityPoolShare, + Limit: xdr.Int64(500000000000000000), + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeAllowTrust, + AllowTrustOp: &xdr.AllowTrustOp{ + Trustor: testAccountID, + Asset: assetCode, + Authorize: xdr.Uint32(1), + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeAccountMerge, + Destination: &testAccountMuxed, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInflation, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeManageData, + ManageDataOp: &xdr.ManageDataOp{ + DataName: "test", + DataValue: &dataValue, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeBumpSequence, + BumpSequenceOp: &xdr.BumpSequenceOp{ + BumpTo: xdr.SequenceNumber(100), + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeManageBuyOffer, + ManageBuyOfferOp: &xdr.ManageBuyOfferOp{ + Selling: usdtAsset, + Buying: nativeAsset, + BuyAmount: 7654501001, + Price: xdr.Price{ + N: 635863285, + D: 1818402817, + }, + OfferId: 100, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypePathPaymentStrictSend, + PathPaymentStrictSendOp: &xdr.PathPaymentStrictSendOp{ + SendAsset: nativeAsset, + SendAmount: 1598182, + Destination: testAccountMuxed, + DestAsset: nativeAsset, + DestMin: 4280460538, + Path: []xdr.Asset{usdtAsset}, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeCreateClaimableBalance, + CreateClaimableBalanceOp: &xdr.CreateClaimableBalanceOp{ + Asset: usdtAsset, + Amount: 1234567890000, + Claimants: []xdr.Claimant{testClaimant}, + }, + }, + }, + { + SourceAccount: &sourceAccountMuxed, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeClaimClaimableBalance, + ClaimClaimableBalanceOp: &xdr.ClaimClaimableBalanceOp{ + BalanceId: claimableBalance, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeBeginSponsoringFutureReserves, + BeginSponsoringFutureReservesOp: &xdr.BeginSponsoringFutureReservesOp{ + SponsoredId: testAccountID, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipSigner, + Signer: &xdr.RevokeSponsorshipOpSigner{ + AccountId: testAccountID, + SignerKey: signer.Key, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeAccount, + Account: &xdr.LedgerKeyAccount{ + AccountId: testAccountID, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeClaimableBalance, + ClaimableBalance: &xdr.LedgerKeyClaimableBalance{ + BalanceId: claimableBalance, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeData, + Data: &xdr.LedgerKeyData{ + AccountId: testAccountID, + DataName: "test", + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeOffer, + Offer: &xdr.LedgerKeyOffer{ + SellerId: testAccountID, + OfferId: 100, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeTrustline, + TrustLine: &xdr.LedgerKeyTrustLine{ + AccountId: testAccountID, + Asset: xdr.TrustLineAsset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x54, 0x54}), + Issuer: testAccountID, + }, + }, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeLiquidityPool, + LiquidityPool: &xdr.LedgerKeyLiquidityPool{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeClawback, + ClawbackOp: &xdr.ClawbackOp{ + Asset: usdtAsset, + From: testAccountMuxed, + Amount: 1598182, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeClawbackClaimableBalance, + ClawbackClaimableBalanceOp: &xdr.ClawbackClaimableBalanceOp{ + BalanceId: claimableBalance, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeSetTrustLineFlags, + SetTrustLineFlagsOp: &xdr.SetTrustLineFlagsOp{ + Trustor: testAccountID, + Asset: usdtAsset, + SetFlags: setFlags, + ClearFlags: clearFlags, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeLiquidityPoolDeposit, + LiquidityPoolDepositOp: &xdr.LiquidityPoolDepositOp{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + MaxAmountA: 1000, + MaxAmountB: 100, + MinPrice: xdr.Price{ + N: 1, + D: 1000000, + }, + MaxPrice: xdr.Price{ + N: 1000000, + D: 1, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeLiquidityPoolWithdraw, + LiquidityPoolWithdrawOp: &xdr.LiquidityPoolWithdrawOp{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Amount: 4, + MinAmountA: 1, + MinAmountB: 1, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeInvokeContract, + InvokeContract: &xdr.InvokeContractArgs{ + ContractAddress: xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeContract, + ContractId: &contractHash, + }, + FunctionName: "test", + Args: []xdr.ScVal{}, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeCreateContract, + CreateContract: &xdr.CreateContractArgs{ + ContractIdPreimage: xdr.ContractIdPreimage{ + Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAddress, + FromAddress: &xdr.ContractIdPreimageFromAddress{ + Address: xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeContract, + ContractId: &contractHash, + }, + Salt: salt, + }, + }, + Executable: xdr.ContractExecutable{}, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeCreateContract, + CreateContract: &xdr.CreateContractArgs{ + ContractIdPreimage: xdr.ContractIdPreimage{ + Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAsset, + FromAsset: &usdtAsset, + }, + Executable: xdr.ContractExecutable{}, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeCreateContractV2, + CreateContractV2: &xdr.CreateContractArgsV2{ + ContractIdPreimage: xdr.ContractIdPreimage{ + Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAsset, + FromAsset: &usdtAsset, + }, + Executable: xdr.ContractExecutable{}, + ConstructorArgs: []xdr.ScVal{ + { + Type: xdr.ScValTypeScvBool, + B: &dummyBool, + }, + }, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeUploadContractWasm, + Wasm: &wasm, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeExtendFootprintTtl, + ExtendFootprintTtlOp: &xdr.ExtendFootprintTtlOp{ + Ext: xdr.ExtensionPoint{ + V: 0, + }, + ExtendTo: 1234, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRestoreFootprint, + RestoreFootprintOp: &xdr.RestoreFootprintOp{ + Ext: xdr.ExtensionPoint{ + V: 0, + }, + }, + }, + }, + } + + return operation +} + +func resultTestOutput() []testOutput { + output := []testOutput{ + { + err: nil, + result: map[string]interface{}{ + "account": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "funder": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "funder_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + "funder_muxed_id": uint64(123), + "starting_balance": 2.5}, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": float64(35), + "asset_code": "USDT", + "asset_id": int64(-8205667356306085451), + "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_type": "credit_alphanum4", + "from": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "from_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + "from_muxed_id": uint64(123), + "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": float64(35), + "asset_id": int64(-5706705804583548011), + "asset_type": "native", + "from": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "from_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + "from_muxed_id": uint64(123), + "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": 895.14959, + "asset_id": int64(-5706705804583548011), + "asset_type": "native", + "from": "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", + "path": []Path{Path{AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4"}}, + "source_amount": float64(0), + "source_asset_id": int64(-5706705804583548011), + "source_asset_type": "native", + "source_max": 895.14959, + "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": float64(76.586), + "buying_asset_id": int64(-5706705804583548011), + "buying_asset_type": "native", + "offer_id": int64(0), + "price": 0.514092, + "price_r": Price{Numerator: 128523, + Denominator: 250000}, + "selling_asset_code": "USDT", + "selling_asset_id": int64(-8205667356306085451), + "selling_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "selling_asset_type": "credit_alphanum4"}, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": float64(63.1595), + "buying_asset_code": "USDT", + "buying_asset_id": int64(-8205667356306085451), + "buying_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "buying_asset_type": "credit_alphanum4", + "price": 0.0791606, + "price_r": Price{Numerator: 99583200, + Denominator: 1257990000}, + "selling_asset_id": int64(-5706705804583548011), + "selling_asset_type": "native"}, + }, + { + err: nil, + result: map[string]interface{}{ + "clear_flags": []int32{1, + 2}, + "clear_flags_s": []string{"auth_required", + "auth_revocable"}, + "high_threshold": uint32(5), + "home_domain": "2019=DRA;n-test", + "inflation_dest": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "low_threshold": uint32(1), + "master_key_weight": uint32(3), + "med_threshold": uint32(3), + "set_flags": []int32{4}, + "set_flags_s": []string{"auth_immutable"}, + "signer_key": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + "signer_weight": uint32(1)}, + }, + { + err: nil, + result: map[string]interface{}{ + "asset_code": "USSD", + "asset_id": int64(6690054458235693884), + "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_type": "credit_alphanum4", + "limit": 5e+10, + "trustee": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "trustor": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "trustor_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + "trustor_muxed_id": uint64(123)}, + }, + { + err: nil, + result: map[string]interface{}{ + "asset_type": "liquidity_pool_shares", + "limit": 5e+10, + "liquidity_pool_id": "1c261d6c75930204a73b480c3020ab525e9be48ce93de6194cf69fb06f07452d", + "trustor": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "trustor_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + "trustor_muxed_id": uint64(123)}, + }, + { + err: nil, + result: map[string]interface{}{ + "asset_code": "USDT", + "asset_id": int64(8181787832768848499), + "asset_issuer": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "asset_type": "credit_alphanum4", + "authorize": true, + "trustee": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "trustee_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + "trustee_muxed_id": uint64(123), + "trustor": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{ + "account": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "account_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + "account_muxed_id": uint64(123), + "into": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{}, + }, + { + err: nil, + result: map[string]interface{}{ + "name": "test", + "value": "dmFsdWU=", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "bump_to": "100", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": float64(765.4501001), + "buying_asset_id": int64(-5706705804583548011), + "buying_asset_type": "native", + "offer_id": int64(100), + "price": 0.3496823, + "price_r": Price{Numerator: 635863285, + Denominator: 1818402817}, + "selling_asset_code": "USDT", + "selling_asset_id": int64(-8205667356306085451), + "selling_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "selling_asset_type": "credit_alphanum4"}, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": float64(64), + "asset_id": int64(-5706705804583548011), + "asset_type": "native", + "destination_min": "428.0460538", + "from": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + "from_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + "from_muxed_id": uint64(123), + "path": []Path{{AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4"}}, + "source_amount": 0.1598182, + "source_asset_id": int64(-5706705804583548011), + "source_asset_type": "native", + "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": 123456.789, + "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "claimants": []Claimant{{Destination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + Predicate: xdr.ClaimPredicate{Type: 0, + AndPredicates: (*[]xdr.ClaimPredicate)(nil), + OrPredicates: (*[]xdr.ClaimPredicate)(nil), + NotPredicate: (**xdr.ClaimPredicate)(nil), + AbsBefore: (*xdr.Int64)(nil), + RelBefore: (*xdr.Int64)(nil)}}}}, + }, + { + err: nil, + result: map[string]interface{}{ + "balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000", + "claimant": "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN"}, + }, + { + err: nil, + result: map[string]interface{}{ + "sponsored_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "signer_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "signer_key": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"}, + }, + { + err: nil, + result: map[string]interface{}{ + "account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{ + "claimable_balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000"}, + }, + { + err: nil, + result: map[string]interface{}{ + "data_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "data_name": "test"}, + }, + { + err: nil, + result: map[string]interface{}{ + "offer_id": int64(100)}, + }, + { + err: nil, + result: map[string]interface{}{ + "trustline_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "trustline_asset": "USTT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{ + "liquidity_pool_id": "0102030405060708090000000000000000000000000000000000000000000000"}, + }, + { + err: nil, + result: map[string]interface{}{ + "amount": 0.1598182, + "asset_code": "USDT", + "asset_id": int64(-8205667356306085451), + "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_type": "credit_alphanum4", + "from": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: map[string]interface{}{ + "balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000"}, + }, + { + err: nil, + result: map[string]interface{}{ + "asset_code": "USDT", + "asset_id": int64(-8205667356306085451), + "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_type": "credit_alphanum4", + "clear_flags": []int32{1, 2}, + "clear_flags_s": []string{"authorized", "authorized_to_maintain_liabilities"}, + "set_flags": []int32{4}, + "set_flags_s": []string{"clawback_enabled"}, + "trustor": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}}, + { + err: nil, + result: map[string]interface{}{ + "liquidity_pool_id": "0102030405060708090000000000000000000000000000000000000000000000", + "max_price": 1e+06, + "max_price_r": Price{Numerator: 1000000, Denominator: 1}, + "min_price": 1e-06, + "min_price_r": Price{Numerator: 1, Denominator: 1000000}, + "reserve_a_asset_code": "USDT", + "reserve_a_asset_id": int64(-8205667356306085451), + "reserve_a_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "reserve_a_asset_type": "credit_alphanum4", + "reserve_a_deposit_amount": 1e-07, + "reserve_a_max_amount": 0.0001, + "reserve_b_asset_code": "USDT", + "reserve_b_asset_id": int64(-8205667356306085451), + "reserve_b_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "reserve_b_asset_type": "credit_alphanum4", + "reserve_b_deposit_amount": 1e-07, + "reserve_b_max_amount": 1e-05, + "shares_received": 1e-07, + }, + }, + { + err: nil, + result: map[string]interface{}{ + "liquidity_pool_id": "0102030405060708090000000000000000000000000000000000000000000000", + "reserve_a_asset_code": "USDT", + "reserve_a_asset_id": int64(-8205667356306085451), + "reserve_a_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "reserve_a_asset_type": "credit_alphanum4", + "reserve_a_min_amount": 1e-07, + "reserve_a_withdraw_amount": -1e-07, + "reserve_b_asset_code": "USDT", + "reserve_b_asset_id": int64(-8205667356306085451), + "reserve_b_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "reserve_b_asset_type": "credit_alphanum4", + "reserve_b_min_amount": 1e-07, + "reserve_b_withdraw_amount": -1e-07, + "shares": 4e-07, + }, + }, + { + err: nil, + result: map[string]interface{}{ + "asset_balance_changes": []map[string]interface{}{}, + "contract_id": "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", + "function": "HostFunctionTypeHostFunctionTypeInvokeContract", + "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + "parameters": []map[string]string{ + { + "type": "Address", + "value": "AAAAEgAAAAESNFZ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + }, + { + "type": "Sym", + "value": "AAAADwAAAAR0ZXN0", + }, + }, + "parameters_decoded": []map[string]string{ + { + "type": "Address", + "value": "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", + }, + { + "type": "Sym", + "value": "test", + }, + }, + "type": "invoke_contract", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "address": "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", + "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + "from": "address", + "function": "HostFunctionTypeHostFunctionTypeCreateContract", + "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + "type": "create_contract", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + "from": "asset", + "function": "HostFunctionTypeHostFunctionTypeCreateContract", + "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + "type": "create_contract", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + "from": "asset", + "function": "HostFunctionTypeHostFunctionTypeCreateContractV2", + "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + "parameters": []map[string]string{ + { + "type": "B", + "value": "AAAAAAAAAAE=", + }, + }, + "parameters_decoded": []map[string]string{ + { + "type": "B", + "value": "true", + }, + }, + "type": "create_contract_v2", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "function": "HostFunctionTypeHostFunctionTypeUploadContractWasm", + "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + "type": "upload_wasm", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "extend_to": int32(1234), + "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + "type": "extend_footprint_ttl", + }, + }, + { + err: nil, + result: map[string]interface{}{ + "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + "type": "restore_footprint", + }, + }, + } + + return output +} diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index 36f82b952f..8490163699 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -579,3 +579,163 @@ func (t *LedgerTransaction) NewMaxFee() (uint32, bool) { func (t *LedgerTransaction) Successful() bool { return t.Result.Successful() } + +func (t *LedgerTransaction) GetOperations(networkPassphrase string) []LedgerOperation { + var ledgerOperations []LedgerOperation + + for i, operation := range t.Envelope.Operations() { + ledgerOperation := LedgerOperation{ + OperationIndex: int32(i), + Operation: operation, + Transaction: t, + NetworkPassphrase: networkPassphrase, + } + ledgerOperations = append(ledgerOperations, ledgerOperation) + } + + return ledgerOperations +} + +func (t *LedgerTransaction) GetTransactionV1Envelope() (xdr.TransactionV1Envelope, bool) { + switch t.Envelope.Type { + case xdr.EnvelopeTypeEnvelopeTypeTx: + switch t.Envelope.Type { + case 2: + return *t.Envelope.V1, true + default: + return xdr.TransactionV1Envelope{}, false + } + case xdr.EnvelopeTypeEnvelopeTypeTxFeeBump: + return t.Envelope.MustFeeBump().Tx.InnerTx.MustV1(), true + default: + return xdr.TransactionV1Envelope{}, false + } +} + +func (t *LedgerTransaction) LedgerKeyHashFromTxEnvelope() []string { + var ledgerKeyHash []string + + v1Envelope, ok := t.GetTransactionV1Envelope() + if !ok { + return ledgerKeyHash + } + + for _, ledgerKey := range v1Envelope.Tx.Ext.SorobanData.Resources.Footprint.ReadOnly { + ledgerKeyBase64, err := ledgerKey.MarshalBinaryBase64() + if err != nil { + panic(err) + } + if ledgerKeyBase64 != "" { + ledgerKeyHash = append(ledgerKeyHash, ledgerKeyBase64) + } + } + + for _, ledgerKey := range v1Envelope.Tx.Ext.SorobanData.Resources.Footprint.ReadWrite { + ledgerKeyBase64, err := ledgerKey.MarshalBinaryBase64() + if err != nil { + panic(err) + } + if ledgerKeyBase64 != "" { + ledgerKeyHash = append(ledgerKeyHash, ledgerKeyBase64) + } + } + + return ledgerKeyHash +} + +func (t *LedgerTransaction) ContractCodeHashFromTxEnvelope() (string, bool) { + v1Envelope, ok := t.GetTransactionV1Envelope() + if !ok { + return "", false + } + for _, ledgerKey := range v1Envelope.Tx.Ext.SorobanData.Resources.Footprint.ReadOnly { + contractCode, ok := t.contractCodeFromContractData(ledgerKey) + if !ok { + return "", false + } + if contractCode != "" { + return contractCode, true + } + } + + for _, ledgerKey := range v1Envelope.Tx.Ext.SorobanData.Resources.Footprint.ReadWrite { + contractCode, ok := t.contractCodeFromContractData(ledgerKey) + if !ok { + return "", false + } + if contractCode != "" { + return contractCode, true + } + } + + return "", true +} + +func (t *LedgerTransaction) contractCodeFromContractData(ledgerKey xdr.LedgerKey) (string, bool) { + contractCode, ok := ledgerKey.GetContractCode() + if !ok { + return "", false + } + + codeHash, err := contractCode.Hash.MarshalBinaryBase64() + if err != nil { + panic(err) + } + + return codeHash, true +} + +func (t *LedgerTransaction) contractIdFromTxEnvelope() (string, bool) { + v1Envelope, ok := t.GetTransactionV1Envelope() + if !ok { + return "", false + } + for _, ledgerKey := range v1Envelope.Tx.Ext.SorobanData.Resources.Footprint.ReadWrite { + contractId, ok := t.contractIdFromContractData(ledgerKey) + if !ok { + return "", false + } + + if contractId != "" { + return contractId, true + } + } + + for _, ledgerKey := range v1Envelope.Tx.Ext.SorobanData.Resources.Footprint.ReadOnly { + contractId, ok := t.contractIdFromContractData(ledgerKey) + if !ok { + return "", false + } + + if contractId != "" { + return contractId, true + } + } + + return "", true +} + +func (t *LedgerTransaction) contractIdFromContractData(ledgerKey xdr.LedgerKey) (string, bool) { + contractData, ok := ledgerKey.GetContractData() + if !ok { + return "", false + } + contractIdHash, ok := contractData.Contract.GetContractId() + if !ok { + return "", false + } + + var contractIdByte []byte + var contractId string + var err error + contractIdByte, err = contractIdHash.MarshalBinary() + if err != nil { + panic(err) + } + contractId, err = strkey.Encode(strkey.VersionByteContract, contractIdByte) + if err != nil { + panic(err) + } + + return contractId, true +} diff --git a/xdr/hash.go b/xdr/hash.go index 2a15c18c9c..c0107163b6 100644 --- a/xdr/hash.go +++ b/xdr/hash.go @@ -1,6 +1,9 @@ package xdr -import "encoding/hex" +import ( + "encoding/base64" + "encoding/hex" +) func (h Hash) HexString() string { return hex.EncodeToString(h[:]) @@ -17,3 +20,14 @@ func (s Hash) Equals(o Hash) bool { } return true } + +// MarshalBinaryBase64 marshals XDR into a binary form and then encodes it +// using base64. +func (h Hash) MarshalBinaryBase64() (string, error) { + b, err := h.MarshalBinary() + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(b), nil +} diff --git a/xdr/operation_trace_result.go b/xdr/operation_trace_result.go new file mode 100644 index 0000000000..f5c68c7989 --- /dev/null +++ b/xdr/operation_trace_result.go @@ -0,0 +1,68 @@ +package xdr + +import "fmt" + +func (o OperationResultTr) MapOperationResultTr() (string, error) { + var operationTraceDescription string + operationType := o.Type + + switch operationType { + case OperationTypeCreateAccount: + operationTraceDescription = o.CreateAccountResult.Code.String() + case OperationTypePayment: + operationTraceDescription = o.PaymentResult.Code.String() + case OperationTypePathPaymentStrictReceive: + operationTraceDescription = o.PathPaymentStrictReceiveResult.Code.String() + case OperationTypePathPaymentStrictSend: + operationTraceDescription = o.PathPaymentStrictSendResult.Code.String() + case OperationTypeManageBuyOffer: + operationTraceDescription = o.ManageBuyOfferResult.Code.String() + case OperationTypeManageSellOffer: + operationTraceDescription = o.ManageSellOfferResult.Code.String() + case OperationTypeCreatePassiveSellOffer: + operationTraceDescription = o.CreatePassiveSellOfferResult.Code.String() + case OperationTypeSetOptions: + operationTraceDescription = o.SetOptionsResult.Code.String() + case OperationTypeChangeTrust: + operationTraceDescription = o.ChangeTrustResult.Code.String() + case OperationTypeAllowTrust: + operationTraceDescription = o.AllowTrustResult.Code.String() + case OperationTypeAccountMerge: + operationTraceDescription = o.AccountMergeResult.Code.String() + case OperationTypeInflation: + operationTraceDescription = o.InflationResult.Code.String() + case OperationTypeManageData: + operationTraceDescription = o.ManageDataResult.Code.String() + case OperationTypeBumpSequence: + operationTraceDescription = o.BumpSeqResult.Code.String() + case OperationTypeCreateClaimableBalance: + operationTraceDescription = o.CreateClaimableBalanceResult.Code.String() + case OperationTypeClaimClaimableBalance: + operationTraceDescription = o.ClaimClaimableBalanceResult.Code.String() + case OperationTypeBeginSponsoringFutureReserves: + operationTraceDescription = o.BeginSponsoringFutureReservesResult.Code.String() + case OperationTypeEndSponsoringFutureReserves: + operationTraceDescription = o.EndSponsoringFutureReservesResult.Code.String() + case OperationTypeRevokeSponsorship: + operationTraceDescription = o.RevokeSponsorshipResult.Code.String() + case OperationTypeClawback: + operationTraceDescription = o.ClawbackResult.Code.String() + case OperationTypeClawbackClaimableBalance: + operationTraceDescription = o.ClawbackClaimableBalanceResult.Code.String() + case OperationTypeSetTrustLineFlags: + operationTraceDescription = o.SetTrustLineFlagsResult.Code.String() + case OperationTypeLiquidityPoolDeposit: + operationTraceDescription = o.LiquidityPoolDepositResult.Code.String() + case OperationTypeLiquidityPoolWithdraw: + operationTraceDescription = o.LiquidityPoolWithdrawResult.Code.String() + case OperationTypeInvokeHostFunction: + operationTraceDescription = o.InvokeHostFunctionResult.Code.String() + case OperationTypeExtendFootprintTtl: + operationTraceDescription = o.ExtendFootprintTtlResult.Code.String() + case OperationTypeRestoreFootprint: + operationTraceDescription = o.RestoreFootprintResult.Code.String() + default: + return operationTraceDescription, fmt.Errorf("unknown operation type: %s", o.Type.String()) + } + return operationTraceDescription, nil +} From be020c9be95a0f4d7688409139b86b2fc3390642 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 11:24:09 -0500 Subject: [PATCH 19/40] address comments --- ingest/ledger/ledger.go | 46 ++++++++++++++++++------------------ ingest/ledger/ledger_test.go | 12 ++++------ xdr/ledger_close_meta.go | 8 +++---- xdr/node_id.go | 16 ++++++++----- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go index c37cb50b3b..c91400db73 100644 --- a/ingest/ledger/ledger.go +++ b/ingest/ledger/ledger.go @@ -2,9 +2,9 @@ package ledger import ( "encoding/base64" + "fmt" "time" - "github.com/stellar/go/toid" "github.com/stellar/go/xdr" ) @@ -12,10 +12,6 @@ func Sequence(l xdr.LedgerCloseMeta) uint32 { return uint32(l.LedgerHeaderHistoryEntry().Header.LedgerSeq) } -func ID(l xdr.LedgerCloseMeta) int64 { - return toid.New(int32(l.LedgerSequence()), 0, 0).ToInt64() -} - func Hash(l xdr.LedgerCloseMeta) string { return l.LedgerHeaderHistoryEntry().Hash.HexString() } @@ -79,10 +75,10 @@ func TotalByteSizeOfBucketList(l xdr.LedgerCloseMeta) (uint64, bool) { return uint64(lcmV1.TotalByteSizeOfBucketList), true } -func NodeID(l xdr.LedgerCloseMeta) (string, bool) { +func NodeID(l xdr.LedgerCloseMeta) (string, error) { LedgerCloseValueSignature, ok := l.LedgerHeaderHistoryEntry().Header.ScpValue.Ext.GetLcValueSignature() if !ok { - return "", false + return "", fmt.Errorf("could not get LedgerCloseValueSignature") } return LedgerCloseValueSignature.NodeId.GetAddress() @@ -97,15 +93,17 @@ func Signature(l xdr.LedgerCloseMeta) (string, bool) { return base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature), true } -// Add docstring to larger, more complicated functions -func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32, ok bool) { - var results []xdr.TransactionResultMeta - +// TransactionCounts calculates and returns the number of successful and failed transactions +func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32) { transactions := l.TransactionEnvelopes() - results = l.TxProcessing() + results, err := l.TxProcessing() + if err != nil { + panic(err) + } + txCount := len(transactions) if txCount != len(results) { - return 0, 0, false + panic("transaction count and number of TransactionResultMeta not equal") } for i := 0; i < txCount; i++ { @@ -116,31 +114,33 @@ func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int } } - return successTxCount, failedTxCount, true + return successTxCount, failedTxCount } -// Add docstring to larger, more complicated functions -func OperationCounts(l xdr.LedgerCloseMeta) (operationCount, txSetOperationCount int32, ok bool) { - var results []xdr.TransactionResultMeta - +// OperationCounts calculates and returns the number of successful operations and the total operations within +// a LedgerCloseMeta +func OperationCounts(l xdr.LedgerCloseMeta) (successfulOperationCount, totalOperationCount int32) { transactions := l.TransactionEnvelopes() - results = l.TxProcessing() + results, err := l.TxProcessing() + if err != nil { + panic(err) + } for i, result := range results { operations := transactions[i].Operations() numberOfOps := int32(len(operations)) - txSetOperationCount += numberOfOps + totalOperationCount += numberOfOps // for successful transactions, the operation count is based on the operations results slice if result.Result.Successful() { operationResults, ok := result.Result.OperationResults() if !ok { - return 0, 0, false + panic("could not get OperationResults") } - operationCount += int32(len(operationResults)) + successfulOperationCount += int32(len(operationResults)) } } - return operationCount, txSetOperationCount, true + return successfulOperationCount, totalOperationCount } diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index 2345d46792..017657c004 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -14,7 +14,6 @@ func TestLedger(t *testing.T) { ledger := ledgerTestInput() assert.Equal(t, uint32(30578981), Sequence(ledger)) - assert.Equal(t, int64(131335723340005376), ID(ledger)) assert.Equal(t, "26932dc4d84b5fabe9ae744cb43ce4c6daccf98c86a991b2a14945b1adac4d59", Hash(ledger)) assert.Equal(t, "f63c15d0eaf48afbd751a4c4dfade54a3448053c47c5a71d622668ae0cc2a208", PreviousHash(ledger)) assert.Equal(t, int64(1594584547), CloseTime(ledger)) @@ -38,8 +37,9 @@ func TestLedger(t *testing.T) { assert.Equal(t, uint64(56), bucketSize) var nodeID string - nodeID, ok = NodeID(ledger) - assert.Equal(t, true, ok) + var err error + nodeID, err = NodeID(ledger) + assert.Equal(t, nil, err) assert.Equal(t, "GARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA76O", nodeID) var signature string @@ -49,13 +49,11 @@ func TestLedger(t *testing.T) { var success int32 var failed int32 - success, failed, ok = TransactionCounts(ledger) - assert.Equal(t, true, ok) + success, failed = TransactionCounts(ledger) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) - success, failed, ok = OperationCounts(ledger) - assert.Equal(t, true, ok) + success, failed = OperationCounts(ledger) assert.Equal(t, int32(1), success) assert.Equal(t, int32(13), failed) } diff --git a/xdr/ledger_close_meta.go b/xdr/ledger_close_meta.go index bcb4fd9645..ace0a0f378 100644 --- a/xdr/ledger_close_meta.go +++ b/xdr/ledger_close_meta.go @@ -158,13 +158,13 @@ func (l LedgerCloseMeta) EvictedPersistentLedgerEntries() ([]LedgerEntry, error) } // TxProcessing returns the TransactionResultMeta in this ledger -func (l LedgerCloseMeta) TxProcessing() []TransactionResultMeta { +func (l LedgerCloseMeta) TxProcessing() ([]TransactionResultMeta, error) { switch l.V { case 0: - return l.MustV0().TxProcessing + return l.MustV0().TxProcessing, nil case 1: - return l.MustV1().TxProcessing + return l.MustV1().TxProcessing, nil default: - panic(fmt.Sprintf("Unsupported LedgerCloseMeta.V: %d", l.V)) + return []TransactionResultMeta{}, fmt.Errorf("Unsupported LedgerCloseMeta.V: %d", l.V) } } diff --git a/xdr/node_id.go b/xdr/node_id.go index b3f9c77eb8..7f7420fb76 100644 --- a/xdr/node_id.go +++ b/xdr/node_id.go @@ -1,22 +1,26 @@ package xdr -import "github.com/stellar/go/strkey" +import ( + "fmt" -func (n NodeId) GetAddress() (string, bool) { + "github.com/stellar/go/strkey" +) + +func (n NodeId) GetAddress() (string, error) { switch n.Type { case PublicKeyTypePublicKeyTypeEd25519: ed, ok := n.GetEd25519() if !ok { - return "", false + return "", fmt.Errorf("could not get NodeID.Ed25519") } raw := make([]byte, 32) copy(raw, ed[:]) encodedAddress, err := strkey.Encode(strkey.VersionByteAccountID, raw) if err != nil { - return "", false + return "", err } - return encodedAddress, true + return encodedAddress, nil default: - return "", false + return "", fmt.Errorf("unknown NodeId.PublicKeyType") } } From 69f9bf28d79dc09a4201c4a77b2ad53870e54e38 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 11:45:10 -0500 Subject: [PATCH 20/40] Change count to uint32 --- ingest/ledger/ledger.go | 11 +++++------ ingest/ledger/ledger_test.go | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go index c91400db73..b24f5e335a 100644 --- a/ingest/ledger/ledger.go +++ b/ingest/ledger/ledger.go @@ -94,7 +94,7 @@ func Signature(l xdr.LedgerCloseMeta) (string, bool) { } // TransactionCounts calculates and returns the number of successful and failed transactions -func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int32) { +func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount uint32) { transactions := l.TransactionEnvelopes() results, err := l.TxProcessing() if err != nil { @@ -119,7 +119,7 @@ func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount int // OperationCounts calculates and returns the number of successful operations and the total operations within // a LedgerCloseMeta -func OperationCounts(l xdr.LedgerCloseMeta) (successfulOperationCount, totalOperationCount int32) { +func OperationCounts(l xdr.LedgerCloseMeta) (successfulOperationCount, totalOperationCount uint32) { transactions := l.TransactionEnvelopes() results, err := l.TxProcessing() if err != nil { @@ -127,9 +127,8 @@ func OperationCounts(l xdr.LedgerCloseMeta) (successfulOperationCount, totalOper } for i, result := range results { - operations := transactions[i].Operations() - numberOfOps := int32(len(operations)) - totalOperationCount += numberOfOps + operations := uint32(len(transactions[i].Operations())) + totalOperationCount += operations // for successful transactions, the operation count is based on the operations results slice if result.Result.Successful() { @@ -138,7 +137,7 @@ func OperationCounts(l xdr.LedgerCloseMeta) (successfulOperationCount, totalOper panic("could not get OperationResults") } - successfulOperationCount += int32(len(operationResults)) + successfulOperationCount += uint32(len(operationResults)) } } diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index 017657c004..c87431b9e1 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -47,8 +47,8 @@ func TestLedger(t *testing.T) { assert.Equal(t, true, ok) assert.Equal(t, "9g==", signature) - var success int32 - var failed int32 + var success uint32 + var failed uint32 success, failed = TransactionCounts(ledger) assert.Equal(t, int32(1), success) assert.Equal(t, int32(1), failed) From 10b403113ac8b7e419a444d15153bfee5ea832a4 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 11:49:54 -0500 Subject: [PATCH 21/40] wip --- ingest/ledger_transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index 36f82b952f..bf9a9947bc 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -239,7 +239,7 @@ func (t *LedgerTransaction) FeeCharged() (int64, bool) { } func (t *LedgerTransaction) OperationCount() uint32 { - return uint32(len(t.Envelope.Operations())) + return t.Envelope.OperationsCount() } func (t *LedgerTransaction) Memo() string { From 93f96390d245f4051cb5bd4eeba3ce98c021f8cd Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 11:50:48 -0500 Subject: [PATCH 22/40] add txEnvelope OperationsCount() --- ingest/ledger/ledger.go | 2 +- xdr/transaction_envelope.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go index b24f5e335a..dd6517be7b 100644 --- a/ingest/ledger/ledger.go +++ b/ingest/ledger/ledger.go @@ -127,7 +127,7 @@ func OperationCounts(l xdr.LedgerCloseMeta) (successfulOperationCount, totalOper } for i, result := range results { - operations := uint32(len(transactions[i].Operations())) + operations := transactions[i].OperationsCount() totalOperationCount += operations // for successful transactions, the operation count is based on the operations results slice diff --git a/xdr/transaction_envelope.go b/xdr/transaction_envelope.go index 6d513ff342..2cde059e5a 100644 --- a/xdr/transaction_envelope.go +++ b/xdr/transaction_envelope.go @@ -242,3 +242,7 @@ func (e TransactionEnvelope) Memo() Memo { panic("unsupported transaction type: " + e.Type.String()) } } + +func (e TransactionEnvelope) OperationsCount() uint32 { + return uint32(len(e.Operations())) +} From 47ecec833a2f0c16b5f9f37d6bd6f8382a501cb9 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 12:41:42 -0500 Subject: [PATCH 23/40] update timebound --- ingest/ledger_transaction.go | 12 ++++-------- ingest/ledger_transaction_test.go | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index bf9a9947bc..85c2e6726f 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -266,21 +266,17 @@ func (t *LedgerTransaction) MemoType() string { return memoObject.Type.String() } -func (t *LedgerTransaction) TimeBounds() (string, error) { +func (t *LedgerTransaction) TimeBounds() (string, bool) { timeBounds := t.Envelope.TimeBounds() if timeBounds == nil { - return "", nil - } - - if timeBounds.MaxTime < timeBounds.MinTime && timeBounds.MaxTime != 0 { - return "", fmt.Errorf("the max time is earlier than the min time") + return "", false } if timeBounds.MaxTime == 0 { - return fmt.Sprintf("[%d,)", timeBounds.MinTime), nil + return fmt.Sprintf("[%d,)", timeBounds.MinTime), true } - return fmt.Sprintf("[%d,%d)", timeBounds.MinTime, timeBounds.MaxTime), nil + return fmt.Sprintf("[%d,%d)", timeBounds.MinTime, timeBounds.MaxTime), true } func (t *LedgerTransaction) LedgerBounds() (string, bool) { diff --git a/ingest/ledger_transaction_test.go b/ingest/ledger_transaction_test.go index 3a2773fa88..3644691a84 100644 --- a/ingest/ledger_transaction_test.go +++ b/ingest/ledger_transaction_test.go @@ -837,8 +837,8 @@ func TestTransactionHelperFunctions(t *testing.T) { assert.Equal(t, "MemoTypeMemoText", transaction.MemoType()) var timeBounds string - timeBounds, err = transaction.TimeBounds() - assert.Equal(t, nil, err) + timeBounds, ok = transaction.TimeBounds() + assert.Equal(t, true, ok) assert.Equal(t, "[1,10)", timeBounds) var ledgerBounds string From c2a3616b6b45c82651550259f4d56eb68b72ae78 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 13:00:03 -0500 Subject: [PATCH 24/40] add InclusionFee() --- ingest/ledger_transaction.go | 15 +++++++++++++++ ingest/ledger_transaction_test.go | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index 85c2e6726f..e635c0262f 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -404,6 +404,21 @@ func (t *LedgerTransaction) SorobanInclusionFeeCharged() (int64, bool) { return initialFeeCharged - resourceFee, true } +func (t *LedgerTransaction) InclusionFee() (int64, bool) { + inclusionFee, ok := t.SorobanInclusionFeeCharged() + if ok { + return inclusionFee, ok + } + + // Inclusion fee for classic is just the base 100 stroops + surge pricing if surging + inclusionFee, ok = t.FeeCharged() + if !ok { + return 0, false + } + + return inclusionFee, true +} + func getAccountBalanceFromLedgerEntryChanges(changes xdr.LedgerEntryChanges, sourceAccountAddress string) (int64, int64) { var accountBalanceStart int64 var accountBalanceEnd int64 diff --git a/ingest/ledger_transaction_test.go b/ingest/ledger_transaction_test.go index 3644691a84..5b4c7432b9 100644 --- a/ingest/ledger_transaction_test.go +++ b/ingest/ledger_transaction_test.go @@ -891,6 +891,11 @@ func TestTransactionHelperFunctions(t *testing.T) { assert.Equal(t, true, ok) assert.Equal(t, int64(-1234), sorobanInclusionFeeCharged) + var inclusionFee int64 + inclusionFee, ok = transaction.InclusionFee() + assert.Equal(t, true, ok) + assert.Equal(t, int64(-1234), inclusionFee) + var sorobanResourceFeeRefund int64 sorobanResourceFeeRefund, ok = transaction.SorobanResourceFeeRefund() assert.Equal(t, true, ok) From 019a3fd146298ef890863952862c2e69d40197a8 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 13:02:59 -0500 Subject: [PATCH 25/40] rename to InclusionFeeCharged --- ingest/ledger_transaction.go | 2 +- ingest/ledger_transaction_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index e635c0262f..07775cdae0 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -404,7 +404,7 @@ func (t *LedgerTransaction) SorobanInclusionFeeCharged() (int64, bool) { return initialFeeCharged - resourceFee, true } -func (t *LedgerTransaction) InclusionFee() (int64, bool) { +func (t *LedgerTransaction) InclusionFeeCharged() (int64, bool) { inclusionFee, ok := t.SorobanInclusionFeeCharged() if ok { return inclusionFee, ok diff --git a/ingest/ledger_transaction_test.go b/ingest/ledger_transaction_test.go index 5b4c7432b9..644c9af92b 100644 --- a/ingest/ledger_transaction_test.go +++ b/ingest/ledger_transaction_test.go @@ -892,7 +892,7 @@ func TestTransactionHelperFunctions(t *testing.T) { assert.Equal(t, int64(-1234), sorobanInclusionFeeCharged) var inclusionFee int64 - inclusionFee, ok = transaction.InclusionFee() + inclusionFee, ok = transaction.InclusionFeeCharged() assert.Equal(t, true, ok) assert.Equal(t, int64(-1234), inclusionFee) From ee153f87b95b5e4a97977abd628fd10175c78649 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 13:17:16 -0500 Subject: [PATCH 26/40] fix tests --- ingest/ledger/ledger_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index c87431b9e1..401ea2e150 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -50,12 +50,12 @@ func TestLedger(t *testing.T) { var success uint32 var failed uint32 success, failed = TransactionCounts(ledger) - assert.Equal(t, int32(1), success) - assert.Equal(t, int32(1), failed) + assert.Equal(t, uint32(1), success) + assert.Equal(t, uint32(1), failed) success, failed = OperationCounts(ledger) - assert.Equal(t, int32(1), success) - assert.Equal(t, int32(13), failed) + assert.Equal(t, uint32(1), success) + assert.Equal(t, uint32(13), failed) } func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { From 3bc82f44da9be4d41bf74f14fc2fa8a78f9925e9 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 13:50:01 -0500 Subject: [PATCH 27/40] update tests --- ingest/ledger_operation_test.go | 133 ++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 31 deletions(-) diff --git a/ingest/ledger_operation_test.go b/ingest/ledger_operation_test.go index 18c4760219..83978ee7fa 100644 --- a/ingest/ledger_operation_test.go +++ b/ingest/ledger_operation_test.go @@ -8,6 +8,34 @@ import ( ) func TestOperation(t *testing.T) { + o := LedgerOperation{ + OperationIndex: int32(0), + Operation: operationTestInput()[1], + Transaction: transactionTestInput(), + NetworkPassphrase: "", + } + + assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", o.SourceAccount()) + assert.Equal(t, int32(1), o.Type()) + assert.Equal(t, "OperationTypePayment", o.TypeString()) + assert.Equal(t, int64(131335723340009473), o.ID()) + + var ok bool + var sourceAccountMuxed string + sourceAccountMuxed, ok = o.SourceAccountMuxed() + assert.Equal(t, true, ok) + assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", sourceAccountMuxed) + + assert.Equal(t, "OperationResultCodeOpInner", o.OperationResultCode()) + + var err error + var operationTraceCode string + operationTraceCode, err = o.OperationTraceCode() + assert.Equal(t, nil, err) + assert.Equal(t, "PathPaymentStrictReceiveResultCodePathPaymentStrictReceiveSuccess", operationTraceCode) +} + +func TestOperationDetails(t *testing.T) { testOutput := resultTestOutput() for i, op := range operationTestInput() { ledgerOperation := LedgerOperation{ @@ -143,7 +171,17 @@ func transactionTestInput() *LedgerTransaction { Result: xdr.TransactionResultResult{ Code: 0, Results: &[]xdr.OperationResult{ - {}, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 2, + PathPaymentStrictReceiveResult: &xdr.PathPaymentStrictReceiveResult{ + Code: 0, + Success: &xdr.PathPaymentStrictReceiveResultSuccess{}, + NoIssuer: &xdr.Asset{}, + }, + }, + }, {}, {}, { @@ -1086,9 +1124,13 @@ func resultTestOutput() []testOutput { "asset_id": int64(-5706705804583548011), "asset_type": "native", "from": "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", - "path": []Path{Path{AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4"}}, + "path": []Path{ + { + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + }, + }, "source_amount": float64(0), "source_asset_id": int64(-5706705804583548011), "source_asset_type": "native", @@ -1103,8 +1145,10 @@ func resultTestOutput() []testOutput { "buying_asset_type": "native", "offer_id": int64(0), "price": 0.514092, - "price_r": Price{Numerator: 128523, - Denominator: 250000}, + "price_r": Price{ + Numerator: 128523, + Denominator: 250000, + }, "selling_asset_code": "USDT", "selling_asset_id": int64(-8205667356306085451), "selling_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", @@ -1119,8 +1163,10 @@ func resultTestOutput() []testOutput { "buying_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", "buying_asset_type": "credit_alphanum4", "price": 0.0791606, - "price_r": Price{Numerator: 99583200, - Denominator: 1257990000}, + "price_r": Price{ + Numerator: 99583200, + Denominator: 1257990000, + }, "selling_asset_id": int64(-5706705804583548011), "selling_asset_type": "native"}, }, @@ -1211,8 +1257,10 @@ func resultTestOutput() []testOutput { "buying_asset_type": "native", "offer_id": int64(100), "price": 0.3496823, - "price_r": Price{Numerator: 635863285, - Denominator: 1818402817}, + "price_r": Price{ + Numerator: 635863285, + Denominator: 1818402817, + }, "selling_asset_code": "USDT", "selling_asset_id": int64(-8205667356306085451), "selling_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", @@ -1228,9 +1276,13 @@ func resultTestOutput() []testOutput { "from": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", "from_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", "from_muxed_id": uint64(123), - "path": []Path{{AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4"}}, + "path": []Path{ + { + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + }, + }, "source_amount": 0.1598182, "source_asset_id": int64(-5706705804583548011), "source_asset_type": "native", @@ -1241,19 +1293,27 @@ func resultTestOutput() []testOutput { result: map[string]interface{}{ "amount": 123456.789, "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "claimants": []Claimant{{Destination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - Predicate: xdr.ClaimPredicate{Type: 0, - AndPredicates: (*[]xdr.ClaimPredicate)(nil), - OrPredicates: (*[]xdr.ClaimPredicate)(nil), - NotPredicate: (**xdr.ClaimPredicate)(nil), - AbsBefore: (*xdr.Int64)(nil), - RelBefore: (*xdr.Int64)(nil)}}}}, + "claimants": []Claimant{ + { + Destination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + Predicate: xdr.ClaimPredicate{ + Type: 0, + AndPredicates: (*[]xdr.ClaimPredicate)(nil), + OrPredicates: (*[]xdr.ClaimPredicate)(nil), + NotPredicate: (**xdr.ClaimPredicate)(nil), + AbsBefore: (*xdr.Int64)(nil), + RelBefore: (*xdr.Int64)(nil), + }, + }, + }, + }, }, { err: nil, result: map[string]interface{}{ "balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000", - "claimant": "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN"}, + "claimant": "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", + }, }, { err: nil, @@ -1265,39 +1325,46 @@ func resultTestOutput() []testOutput { err: nil, result: map[string]interface{}{ "signer_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "signer_key": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"}, + "signer_key": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + }, }, { err: nil, result: map[string]interface{}{ - "account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + "account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, }, { err: nil, result: map[string]interface{}{ - "claimable_balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000"}, + "claimable_balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000", + }, }, { err: nil, result: map[string]interface{}{ "data_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "data_name": "test"}, + "data_name": "test", + }, }, { err: nil, result: map[string]interface{}{ - "offer_id": int64(100)}, + "offer_id": int64(100), + }, }, { err: nil, result: map[string]interface{}{ "trustline_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "trustline_asset": "USTT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + "trustline_asset": "USTT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, }, { err: nil, result: map[string]interface{}{ - "liquidity_pool_id": "0102030405060708090000000000000000000000000000000000000000000000"}, + "liquidity_pool_id": "0102030405060708090000000000000000000000000000000000000000000000", + }, }, { err: nil, @@ -1307,12 +1374,14 @@ func resultTestOutput() []testOutput { "asset_id": int64(-8205667356306085451), "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", "asset_type": "credit_alphanum4", - "from": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + "from": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, }, { err: nil, result: map[string]interface{}{ - "balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000"}, + "balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000", + }, }, { err: nil, @@ -1325,7 +1394,9 @@ func resultTestOutput() []testOutput { "clear_flags_s": []string{"authorized", "authorized_to_maintain_liabilities"}, "set_flags": []int32{4}, "set_flags_s": []string{"clawback_enabled"}, - "trustor": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}}, + "trustor": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, + }, { err: nil, result: map[string]interface{}{ From 21dd54ee561185e3cf8f8f9ccc2e745e07f833fd Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Tue, 21 Jan 2025 15:43:53 -0500 Subject: [PATCH 28/40] address comments --- ingest/ledger/ledger.go | 8 +++----- ingest/ledger/ledger_test.go | 10 +++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/ingest/ledger/ledger.go b/ingest/ledger/ledger.go index dd6517be7b..3a6e0e966e 100644 --- a/ingest/ledger/ledger.go +++ b/ingest/ledger/ledger.go @@ -93,8 +93,8 @@ func Signature(l xdr.LedgerCloseMeta) (string, bool) { return base64.StdEncoding.EncodeToString(LedgerCloseValueSignature.Signature), true } -// TransactionCounts calculates and returns the number of successful and failed transactions -func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount uint32) { +// TransactionCounts calculates and returns the number of successful and total transactions +func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, totalTxCount uint32) { transactions := l.TransactionEnvelopes() results, err := l.TxProcessing() if err != nil { @@ -109,12 +109,10 @@ func TransactionCounts(l xdr.LedgerCloseMeta) (successTxCount, failedTxCount uin for i := 0; i < txCount; i++ { if results[i].Result.Successful() { successTxCount++ - } else { - failedTxCount++ } } - return successTxCount, failedTxCount + return successTxCount, uint32(txCount) } // OperationCounts calculates and returns the number of successful operations and the total operations within diff --git a/ingest/ledger/ledger_test.go b/ingest/ledger/ledger_test.go index 401ea2e150..70c2c75d01 100644 --- a/ingest/ledger/ledger_test.go +++ b/ingest/ledger/ledger_test.go @@ -48,14 +48,14 @@ func TestLedger(t *testing.T) { assert.Equal(t, "9g==", signature) var success uint32 - var failed uint32 - success, failed = TransactionCounts(ledger) + var total uint32 + success, total = TransactionCounts(ledger) assert.Equal(t, uint32(1), success) - assert.Equal(t, uint32(1), failed) + assert.Equal(t, uint32(2), total) - success, failed = OperationCounts(ledger) + success, total = OperationCounts(ledger) assert.Equal(t, uint32(1), success) - assert.Equal(t, uint32(13), failed) + assert.Equal(t, uint32(13), total) } func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { From c68cd9a766a4b492d6469ee3c119e2935eb72818 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 23 Jan 2025 13:37:20 -0500 Subject: [PATCH 29/40] updates from comments --- ingest/ledger_operation.go | 150 ++++++++++++++++---------------- ingest/ledger_operation_test.go | 58 +++++++----- 2 files changed, 112 insertions(+), 96 deletions(-) diff --git a/ingest/ledger_operation.go b/ingest/ledger_operation.go index f59add11e2..cf7f29f799 100644 --- a/ingest/ledger_operation.go +++ b/ingest/ledger_operation.go @@ -71,10 +71,13 @@ func (o *LedgerOperation) OperationResultCode() string { func (o *LedgerOperation) OperationTraceCode() (string, error) { var operationTraceCode string + var operationResults []xdr.OperationResult + var ok bool - operationResults, ok := o.Transaction.Result.Result.OperationResults() + operationResults, ok = o.Transaction.Result.Result.OperationResults() if ok { - operationResultTr, ok := operationResults[o.OperationIndex].GetTr() + var operationResultTr xdr.OperationResultTr + operationResultTr, ok = operationResults[o.OperationIndex].GetTr() if ok { operationTraceCode, err := operationResultTr.MapOperationResultTr() if err != nil { @@ -245,7 +248,7 @@ func (o *LedgerOperation) CreateAccountDetails() (map[string]interface{}, error) return details, err } details["account"] = op.Destination.Address() - details["starting_balance"] = o.ConvertStroopValueToReal(op.StartingBalance) + details["starting_balance"] = int64(op.StartingBalance) return details, nil } @@ -282,36 +285,14 @@ func (o *LedgerOperation) PaymentDetails() (map[string]interface{}, error) { if err := o.addAccountAndMuxedAccountDetails(details, op.Destination, "to"); err != nil { return details, err } - details["amount"] = o.ConvertStroopValueToReal(op.Amount) - if err := o.addAssetDetailsToOperationDetails(details, op.Asset, ""); err != nil { + details["amount"] = int64(op.Amount) + if err := o.addAssetDetails(details, op.Asset, ""); err != nil { return details, err } return details, nil } -func (o *LedgerOperation) addAssetDetailsToOperationDetails(result map[string]interface{}, asset xdr.Asset, prefix string) error { - var assetType, code, issuer string - err := asset.Extract(&assetType, &code, &issuer) - if err != nil { - return err - } - - prefix = o.FormatPrefix(prefix) - result[prefix+"asset_type"] = assetType - - if asset.Type == xdr.AssetTypeAssetTypeNative { - result[prefix+"asset_id"] = int64(-5706705804583548011) - return nil - } - - result[prefix+"asset_code"] = code - result[prefix+"asset_issuer"] = issuer - result[prefix+"asset_id"] = o.FarmHashAsset(code, issuer, assetType) - - return nil -} - func (o *LedgerOperation) PathPaymentStrictReceiveDetails() (map[string]interface{}, error) { details := map[string]interface{}{} op, ok := o.Operation.Body.GetPathPaymentStrictReceiveOp() @@ -325,13 +306,13 @@ func (o *LedgerOperation) PathPaymentStrictReceiveDetails() (map[string]interfac if err := o.addAccountAndMuxedAccountDetails(details, op.Destination, "to"); err != nil { return details, err } - details["amount"] = o.ConvertStroopValueToReal(op.DestAmount) + details["amount"] = int64(op.DestAmount) details["source_amount"] = amount.String(0) - details["source_max"] = o.ConvertStroopValueToReal(op.SendMax) - if err := o.addAssetDetailsToOperationDetails(details, op.DestAsset, ""); err != nil { + details["source_max"] = int64(op.SendMax) + if err := o.addAssetDetails(details, op.DestAsset, ""); err != nil { return details, err } - if err := o.addAssetDetailsToOperationDetails(details, op.SendAsset, "source"); err != nil { + if err := o.addAssetDetails(details, op.SendAsset, "source"); err != nil { return details, err } @@ -349,7 +330,7 @@ func (o *LedgerOperation) PathPaymentStrictReceiveDetails() (map[string]interfac if !ok { return details, fmt.Errorf("could not access PathPaymentStrictReceive result info for this operation (index %d)", o.OperationIndex) } - details["source_amount"] = o.ConvertStroopValueToReal(result.SendAmount()) + details["source_amount"] = int64(result.SendAmount()) } details["path"] = o.TransformPath(op.Path) @@ -370,12 +351,12 @@ func (o *LedgerOperation) PathPaymentStrictSendDetails() (map[string]interface{} return details, err } details["amount"] = float64(0) - details["source_amount"] = o.ConvertStroopValueToReal(op.SendAmount) + details["source_amount"] = int64(op.SendAmount) details["destination_min"] = amount.String(op.DestMin) - if err := o.addAssetDetailsToOperationDetails(details, op.DestAsset, ""); err != nil { + if err := o.addAssetDetails(details, op.DestAsset, ""); err != nil { return details, err } - if err := o.addAssetDetailsToOperationDetails(details, op.SendAsset, "source"); err != nil { + if err := o.addAssetDetails(details, op.SendAsset, "source"); err != nil { return details, err } @@ -393,7 +374,7 @@ func (o *LedgerOperation) PathPaymentStrictSendDetails() (map[string]interface{} if !ok { return details, fmt.Errorf("could not access GetPathPaymentStrictSendResult result info for this operation (index %d)", o.OperationIndex) } - details["amount"] = o.ConvertStroopValueToReal(result.DestAmount()) + details["amount"] = int64(result.DestAmount()) } details["path"] = o.TransformPath(op.Path) @@ -408,15 +389,15 @@ func (o *LedgerOperation) ManageBuyOfferDetails() (map[string]interface{}, error } details["offer_id"] = int64(op.OfferId) - details["amount"] = o.ConvertStroopValueToReal(op.BuyAmount) + details["amount"] = int64(op.BuyAmount) if err := o.addPriceDetails(details, op.Price, ""); err != nil { return details, err } - if err := o.addAssetDetailsToOperationDetails(details, op.Buying, "buying"); err != nil { + if err := o.addAssetDetails(details, op.Buying, "buying"); err != nil { return details, err } - if err := o.addAssetDetailsToOperationDetails(details, op.Selling, "selling"); err != nil { + if err := o.addAssetDetails(details, op.Selling, "selling"); err != nil { return details, err } @@ -445,15 +426,15 @@ func (o *LedgerOperation) ManageSellOfferDetails() (map[string]interface{}, erro } details["offer_id"] = int64(op.OfferId) - details["amount"] = o.ConvertStroopValueToReal(op.Amount) + details["amount"] = int64(op.Amount) if err := o.addPriceDetails(details, op.Price, ""); err != nil { return details, err } - if err := o.addAssetDetailsToOperationDetails(details, op.Buying, "buying"); err != nil { + if err := o.addAssetDetails(details, op.Buying, "buying"); err != nil { return details, err } - if err := o.addAssetDetailsToOperationDetails(details, op.Selling, "selling"); err != nil { + if err := o.addAssetDetails(details, op.Selling, "selling"); err != nil { return details, err } @@ -466,15 +447,15 @@ func (o *LedgerOperation) CreatePassiveSellOfferDetails() (map[string]interface{ return details, fmt.Errorf("could not access CreatePassiveSellOffer info for this operation (index %d)", o.OperationIndex) } - details["amount"] = o.ConvertStroopValueToReal(op.Amount) + details["amount"] = int64(op.Amount) if err := o.addPriceDetails(details, op.Price, ""); err != nil { return details, err } - if err := o.addAssetDetailsToOperationDetails(details, op.Buying, "buying"); err != nil { + if err := o.addAssetDetails(details, op.Buying, "buying"); err != nil { return details, err } - if err := o.addAssetDetailsToOperationDetails(details, op.Selling, "selling"); err != nil { + if err := o.addAssetDetails(details, op.Selling, "selling"); err != nil { return details, err } @@ -568,7 +549,7 @@ func (o *LedgerOperation) ChangeTrustDetails() (map[string]interface{}, error) { return details, err } } else { - if err := o.addAssetDetailsToOperationDetails(details, op.Line.ToAsset(), ""); err != nil { + if err := o.addAssetDetails(details, op.Line.ToAsset(), ""); err != nil { return details, err } details["trustee"] = details["asset_issuer"] @@ -578,7 +559,7 @@ func (o *LedgerOperation) ChangeTrustDetails() (map[string]interface{}, error) { return details, err } - details["limit"] = o.ConvertStroopValueToReal(op.Limit) + details["limit"] = int64(op.Limit) return details, nil } @@ -606,7 +587,7 @@ func (o *LedgerOperation) AllowTrustDetails() (map[string]interface{}, error) { return details, fmt.Errorf("could not access AllowTrust info for this operation (index %d)", o.OperationIndex) } - if err := o.addAssetDetailsToOperationDetails(details, op.Asset.ToAsset(o.sourceAccountXDR().ToAccountId()), ""); err != nil { + if err := o.addAssetDetails(details, op.Asset.ToAsset(o.sourceAccountXDR().ToAccountId()), ""); err != nil { return details, err } if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "trustee"); err != nil { @@ -686,7 +667,12 @@ func (o *LedgerOperation) CreateClaimableBalanceDetails() (map[string]interface{ } details["asset"] = op.Asset.StringCanonical() - details["amount"] = o.ConvertStroopValueToReal(op.Amount) + err := o.addAssetDetails(details, op.Asset, "") + if err != nil { + return details, err + } + + details["amount"] = int64(op.Amount) details["claimants"] = o.TransformClaimants(op.Claimants) return details, nil @@ -813,13 +799,13 @@ func (o *LedgerOperation) ClawbackDetails() (map[string]interface{}, error) { return details, fmt.Errorf("could not access Clawback info for this operation (index %d)", o.OperationIndex) } - if err := o.addAssetDetailsToOperationDetails(details, op.Asset, ""); err != nil { + if err := o.addAssetDetails(details, op.Asset, ""); err != nil { return details, err } if err := o.addAccountAndMuxedAccountDetails(details, op.From, "from"); err != nil { return details, err } - details["amount"] = o.ConvertStroopValueToReal(op.Amount) + details["amount"] = int64(op.Amount) return details, nil } @@ -846,7 +832,7 @@ func (o *LedgerOperation) SetTrustLineFlagsDetails() (map[string]interface{}, er } details["trustor"] = op.Trustor.Address() - if err := o.addAssetDetailsToOperationDetails(details, op.Asset, ""); err != nil { + if err := o.addAssetDetails(details, op.Asset, ""); err != nil { return details, err } if op.SetFlags > 0 { @@ -912,10 +898,10 @@ func (o *LedgerOperation) LiquidityPoolDepositDetails() (map[string]interface{}, } // Process ReserveA Details - if err := o.addAssetDetailsToOperationDetails(details, assetA, "reserve_a"); err != nil { + if err := o.addAssetDetails(details, assetA, "reserve_a"); err != nil { return details, err } - details["reserve_a_max_amount"] = o.ConvertStroopValueToReal(op.MaxAmountA) + details["reserve_a_max_amount"] = int64(op.MaxAmountA) depositA, err := strconv.ParseFloat(amount.String(depositedA), 64) if err != nil { return details, err @@ -923,10 +909,10 @@ func (o *LedgerOperation) LiquidityPoolDepositDetails() (map[string]interface{}, details["reserve_a_deposit_amount"] = depositA //Process ReserveB Details - if err := o.addAssetDetailsToOperationDetails(details, assetB, "reserve_b"); err != nil { + if err := o.addAssetDetails(details, assetB, "reserve_b"); err != nil { return details, err } - details["reserve_b_max_amount"] = o.ConvertStroopValueToReal(op.MaxAmountB) + details["reserve_b_max_amount"] = int64(op.MaxAmountB) depositB, err := strconv.ParseFloat(amount.String(depositedB), 64) if err != nil { return details, err @@ -1022,20 +1008,20 @@ func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (map[string]interface{} receivedA, receivedB = -delta.ReserveA, -delta.ReserveB } // Process AssetA Details - if err := o.addAssetDetailsToOperationDetails(details, assetA, "reserve_a"); err != nil { + if err := o.addAssetDetails(details, assetA, "reserve_a"); err != nil { return details, err } - details["reserve_a_min_amount"] = o.ConvertStroopValueToReal(op.MinAmountA) - details["reserve_a_withdraw_amount"] = o.ConvertStroopValueToReal(receivedA) + details["reserve_a_min_amount"] = int64(op.MinAmountA) + details["reserve_a_withdraw_amount"] = int64(receivedA) // Process AssetB Details - if err := o.addAssetDetailsToOperationDetails(details, assetB, "reserve_b"); err != nil { + if err := o.addAssetDetails(details, assetB, "reserve_b"); err != nil { return details, err } - details["reserve_b_min_amount"] = o.ConvertStroopValueToReal(op.MinAmountB) - details["reserve_b_withdraw_amount"] = o.ConvertStroopValueToReal(receivedB) + details["reserve_b_min_amount"] = int64(op.MinAmountB) + details["reserve_b_withdraw_amount"] = int64(receivedB) - details["shares"] = o.ConvertStroopValueToReal(op.Amount) + details["shares"] = int64(op.Amount) return details, nil } @@ -1074,12 +1060,13 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (map[string]interface{}, e details["parameters"], details["parameters_decoded"] = o.serializeParameters(args) - if balanceChanges, err := o.parseAssetBalanceChangesFromContractEvents(); err != nil { + balanceChanges, err := o.parseAssetBalanceChangesFromContractEvents() + if err != nil { return nil, err - } else { - details["asset_balance_changes"] = balanceChanges } + details["asset_balance_changes"] = balanceChanges + case xdr.HostFunctionTypeHostFunctionTypeCreateContract: args := op.HostFunction.MustCreateContract() details["type"] = "create_contract" @@ -1098,7 +1085,11 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (map[string]interface{}, e details["contract_code_hash"] = contractCodeHash } - preimageTypeMap := o.switchContractIdPreimageType(args.ContractIdPreimage) + preimageTypeMap, err := o.switchContractIdPreimageType(args.ContractIdPreimage) + if err != nil { + return details, nil + } + for key, val := range preimageTypeMap { if _, ok := preimageTypeMap[key]; ok { details[key] = val @@ -1137,7 +1128,11 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (map[string]interface{}, e constructorArgs := args.ConstructorArgs details["parameters"], details["parameters_decoded"] = o.serializeParameters(constructorArgs) - preimageTypeMap := o.switchContractIdPreimageType(args.ContractIdPreimage) + preimageTypeMap, err := o.switchContractIdPreimageType(args.ContractIdPreimage) + if err != nil { + return details, nil + } + for key, val := range preimageTypeMap { if _, ok := preimageTypeMap[key]; ok { details[key] = val @@ -1180,7 +1175,7 @@ func (o *LedgerOperation) RestoreFootprintDetails() (map[string]interface{}, err details := map[string]interface{}{} _, ok := o.Operation.Body.GetRestoreFootprintOp() if !ok { - return details, fmt.Errorf("could not access InvokeHostFunction info for this operation (index %d)", o.OperationIndex) + return details, fmt.Errorf("could not access RestoreFootprint info for this operation (index %d)", o.OperationIndex) } details["type"] = "restore_footprint" @@ -1311,18 +1306,23 @@ func (o *LedgerOperation) addAssetDetails(result map[string]interface{}, a xdr.A err = fmt.Errorf("xdr.Asset.Extract error: %w", err) return err } + + prefix = o.FormatPrefix(prefix) result[prefix+"asset_type"] = assetType if a.Type == xdr.AssetTypeAssetTypeNative { + result[prefix+"asset_id"] = int64(-5706705804583548011) return nil } result[prefix+"asset_code"] = code result[prefix+"asset_issuer"] = issuer + result[prefix+"asset_id"] = o.FarmHashAsset(code, issuer, assetType) + return nil } -func (o *LedgerOperation) switchContractIdPreimageType(contractIdPreimage xdr.ContractIdPreimage) map[string]interface{} { +func (o *LedgerOperation) switchContractIdPreimageType(contractIdPreimage xdr.ContractIdPreimage) (map[string]interface{}, error) { details := map[string]interface{}{} switch contractIdPreimage.Type { @@ -1330,21 +1330,25 @@ func (o *LedgerOperation) switchContractIdPreimageType(contractIdPreimage xdr.Co fromAddress := contractIdPreimage.MustFromAddress() address, err := fromAddress.Address.String() if err != nil { - panic(fmt.Errorf("error obtaining address for: %s", contractIdPreimage.Type)) + return details, err } details["from"] = "address" details["address"] = address case xdr.ContractIdPreimageTypeContractIdPreimageFromAsset: details["from"] = "asset" details["asset"] = contractIdPreimage.MustFromAsset().StringCanonical() + err := o.addAssetDetails(details, contractIdPreimage.MustFromAsset(), "") + if err != nil { + return details, err + } default: panic(fmt.Errorf("unknown contract id type: %s", contractIdPreimage.Type)) } - return details + return details, nil } -func (o *LedgerOperation) ConvertStroopValueToReal(input xdr.Int64) float64 { +func (o *LedgerOperation) ConvertStroopValueToReal(input int64) float64 { output, _ := big.NewRat(int64(input), int64(10000000)).Float64() return output } diff --git a/ingest/ledger_operation_test.go b/ingest/ledger_operation_test.go index 83978ee7fa..d7127104dc 100644 --- a/ingest/ledger_operation_test.go +++ b/ingest/ledger_operation_test.go @@ -1091,12 +1091,12 @@ func resultTestOutput() []testOutput { "funder": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", "funder_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", "funder_muxed_id": uint64(123), - "starting_balance": 2.5}, + "starting_balance": int64(25000000)}, }, { err: nil, result: map[string]interface{}{ - "amount": float64(35), + "amount": int64(350000000), "asset_code": "USDT", "asset_id": int64(-8205667356306085451), "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", @@ -1109,7 +1109,7 @@ func resultTestOutput() []testOutput { { err: nil, result: map[string]interface{}{ - "amount": float64(35), + "amount": int64(350000000), "asset_id": int64(-5706705804583548011), "asset_type": "native", "from": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", @@ -1120,7 +1120,7 @@ func resultTestOutput() []testOutput { { err: nil, result: map[string]interface{}{ - "amount": 895.14959, + "amount": int64(8951495900), "asset_id": int64(-5706705804583548011), "asset_type": "native", "from": "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", @@ -1131,16 +1131,16 @@ func resultTestOutput() []testOutput { AssetType: "credit_alphanum4", }, }, - "source_amount": float64(0), + "source_amount": int64(0), "source_asset_id": int64(-5706705804583548011), "source_asset_type": "native", - "source_max": 895.14959, + "source_max": int64(8951495900), "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, }, { err: nil, result: map[string]interface{}{ - "amount": float64(76.586), + "amount": int64(765860000), "buying_asset_id": int64(-5706705804583548011), "buying_asset_type": "native", "offer_id": int64(0), @@ -1157,7 +1157,7 @@ func resultTestOutput() []testOutput { { err: nil, result: map[string]interface{}{ - "amount": float64(63.1595), + "amount": int64(631595000), "buying_asset_code": "USDT", "buying_asset_id": int64(-8205667356306085451), "buying_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", @@ -1195,7 +1195,7 @@ func resultTestOutput() []testOutput { "asset_id": int64(6690054458235693884), "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", "asset_type": "credit_alphanum4", - "limit": 5e+10, + "limit": int64(500000000000000000), "trustee": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", "trustor": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", "trustor_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", @@ -1205,7 +1205,7 @@ func resultTestOutput() []testOutput { err: nil, result: map[string]interface{}{ "asset_type": "liquidity_pool_shares", - "limit": 5e+10, + "limit": int64(500000000000000000), "liquidity_pool_id": "1c261d6c75930204a73b480c3020ab525e9be48ce93de6194cf69fb06f07452d", "trustor": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", "trustor_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", @@ -1252,7 +1252,7 @@ func resultTestOutput() []testOutput { { err: nil, result: map[string]interface{}{ - "amount": float64(765.4501001), + "amount": int64(7654501001), "buying_asset_id": int64(-5706705804583548011), "buying_asset_type": "native", "offer_id": int64(100), @@ -1269,7 +1269,7 @@ func resultTestOutput() []testOutput { { err: nil, result: map[string]interface{}{ - "amount": float64(64), + "amount": int64(640000000), "asset_id": int64(-5706705804583548011), "asset_type": "native", "destination_min": "428.0460538", @@ -1283,7 +1283,7 @@ func resultTestOutput() []testOutput { AssetType: "credit_alphanum4", }, }, - "source_amount": 0.1598182, + "source_amount": int64(1598182), "source_asset_id": int64(-5706705804583548011), "source_asset_type": "native", "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, @@ -1291,8 +1291,12 @@ func resultTestOutput() []testOutput { { err: nil, result: map[string]interface{}{ - "amount": 123456.789, - "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "amount": int64(1234567890000), + "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_code": "USDT", + "asset_id": int64(-8205667356306085451), + "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_type": "credit_alphanum4", "claimants": []Claimant{ { Destination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", @@ -1369,7 +1373,7 @@ func resultTestOutput() []testOutput { { err: nil, result: map[string]interface{}{ - "amount": 0.1598182, + "amount": int64(1598182), "asset_code": "USDT", "asset_id": int64(-8205667356306085451), "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", @@ -1410,13 +1414,13 @@ func resultTestOutput() []testOutput { "reserve_a_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", "reserve_a_asset_type": "credit_alphanum4", "reserve_a_deposit_amount": 1e-07, - "reserve_a_max_amount": 0.0001, + "reserve_a_max_amount": int64(1000), "reserve_b_asset_code": "USDT", "reserve_b_asset_id": int64(-8205667356306085451), "reserve_b_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", "reserve_b_asset_type": "credit_alphanum4", "reserve_b_deposit_amount": 1e-07, - "reserve_b_max_amount": 1e-05, + "reserve_b_max_amount": int64(100), "shares_received": 1e-07, }, }, @@ -1428,15 +1432,15 @@ func resultTestOutput() []testOutput { "reserve_a_asset_id": int64(-8205667356306085451), "reserve_a_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", "reserve_a_asset_type": "credit_alphanum4", - "reserve_a_min_amount": 1e-07, - "reserve_a_withdraw_amount": -1e-07, + "reserve_a_min_amount": int64(1), + "reserve_a_withdraw_amount": int64(-1), "reserve_b_asset_code": "USDT", "reserve_b_asset_id": int64(-8205667356306085451), "reserve_b_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", "reserve_b_asset_type": "credit_alphanum4", - "reserve_b_min_amount": 1e-07, - "reserve_b_withdraw_amount": -1e-07, - "shares": 4e-07, + "reserve_b_min_amount": int64(1), + "reserve_b_withdraw_amount": int64(-1), + "shares": int64(4), }, }, { @@ -1484,6 +1488,10 @@ func resultTestOutput() []testOutput { err: nil, result: map[string]interface{}{ "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_code": "USDT", + "asset_id": int64(-8205667356306085451), + "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_type": "credit_alphanum4", "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", "from": "asset", "function": "HostFunctionTypeHostFunctionTypeCreateContract", @@ -1495,6 +1503,10 @@ func resultTestOutput() []testOutput { err: nil, result: map[string]interface{}{ "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_code": "USDT", + "asset_id": int64(-8205667356306085451), + "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + "asset_type": "credit_alphanum4", "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", "from": "asset", "function": "HostFunctionTypeHostFunctionTypeCreateContractV2", From 86d5d78136fd3088261b1834e223b621cae53675 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Mon, 3 Feb 2025 17:52:20 -0500 Subject: [PATCH 30/40] Add structs for each operation --- ingest/account_merge_details.go | 47 + ingest/allow_trust_details.go | 58 + ...begin_sponsoring_future_reserve_details.go | 18 + ingest/bump_sequence_details.go | 18 + ingest/change_trust_details.go | 85 ++ ingest/claim_claimable_balance_details.go | 46 + ingest/clawback_claimable_balance_details.go | 25 + ingest/clawback_details.go | 47 + ingest/create_account_details.go | 36 + ingest/create_claimable_balance_details.go | 38 + ingest/create_passive_sell_offer_details.go | 60 + .../end_sponsoring_future_reserve_details.go | 51 + ingest/extend_footprint_ttl_details.go | 38 + ingest/inflation_details.go | 7 + ingest/invoke_host_function_details.go | 144 +++ ingest/ledger_operation.go | 1077 ++--------------- ingest/liquidity_pool_deposit_details.go | 110 ++ ingest/liquidity_pool_withdraw_details.go | 85 ++ ingest/manage_buy_offer_details.go | 62 + ingest/manage_data_details.go | 28 + ingest/manage_sell_offer_details.go | 63 + ingest/path_payment_strict_receive_details.go | 100 ++ ingest/path_payment_strict_send_details.go | 100 ++ ingest/payment_details.go | 60 + ingest/restore_footprint_details.go | 36 + ingest/revoke_sponsorship_details.go | 37 + ingest/set_options_details.go | 97 ++ ingest/set_trustline_flags_details.go | 73 ++ 28 files changed, 1700 insertions(+), 946 deletions(-) create mode 100644 ingest/account_merge_details.go create mode 100644 ingest/allow_trust_details.go create mode 100644 ingest/begin_sponsoring_future_reserve_details.go create mode 100644 ingest/bump_sequence_details.go create mode 100644 ingest/change_trust_details.go create mode 100644 ingest/claim_claimable_balance_details.go create mode 100644 ingest/clawback_claimable_balance_details.go create mode 100644 ingest/clawback_details.go create mode 100644 ingest/create_account_details.go create mode 100644 ingest/create_claimable_balance_details.go create mode 100644 ingest/create_passive_sell_offer_details.go create mode 100644 ingest/end_sponsoring_future_reserve_details.go create mode 100644 ingest/extend_footprint_ttl_details.go create mode 100644 ingest/inflation_details.go create mode 100644 ingest/invoke_host_function_details.go create mode 100644 ingest/liquidity_pool_deposit_details.go create mode 100644 ingest/liquidity_pool_withdraw_details.go create mode 100644 ingest/manage_buy_offer_details.go create mode 100644 ingest/manage_data_details.go create mode 100644 ingest/manage_sell_offer_details.go create mode 100644 ingest/path_payment_strict_receive_details.go create mode 100644 ingest/path_payment_strict_send_details.go create mode 100644 ingest/payment_details.go create mode 100644 ingest/restore_footprint_details.go create mode 100644 ingest/revoke_sponsorship_details.go create mode 100644 ingest/set_options_details.go create mode 100644 ingest/set_trustline_flags_details.go diff --git a/ingest/account_merge_details.go b/ingest/account_merge_details.go new file mode 100644 index 0000000000..fc70291188 --- /dev/null +++ b/ingest/account_merge_details.go @@ -0,0 +1,47 @@ +package ingest + +import "fmt" + +type AccountMergeDetail struct { + Account string `json:"account"` + AccountMuxed string `json:"account_muxed"` + AccountMuxedID uint64 `json:"account_muxed_id"` + Into string `json:"into"` + IntoMuxed string `json:"into_muxed"` + IntoMuxedID uint64 `json:"into_muxed_id"` +} + +func (o *LedgerOperation) AccountMergeDetails() (AccountMergeDetail, error) { + destinationAccount, ok := o.Operation.Body.GetDestination() + if !ok { + return AccountMergeDetail{}, fmt.Errorf("could not access Destination info for this operation (index %d)", o.OperationIndex) + } + + accountMergeDetail := AccountMergeDetail{ + Account: o.SourceAccount(), + Into: destinationAccount.Address(), + } + + var err error + var accountMuxed string + var accountMuxedID uint64 + accountMuxed, accountMuxedID, err = getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return AccountMergeDetail{}, err + } + + accountMergeDetail.AccountMuxed = accountMuxed + accountMergeDetail.AccountMuxedID = accountMuxedID + + var intoMuxed string + var intoMuxedID uint64 + intoMuxed, intoMuxedID, err = getMuxedAccountDetails(destinationAccount) + if err != nil { + return AccountMergeDetail{}, err + } + + accountMergeDetail.IntoMuxed = intoMuxed + accountMergeDetail.IntoMuxedID = intoMuxedID + + return accountMergeDetail, nil +} diff --git a/ingest/allow_trust_details.go b/ingest/allow_trust_details.go new file mode 100644 index 0000000000..df06278738 --- /dev/null +++ b/ingest/allow_trust_details.go @@ -0,0 +1,58 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type AllowTrustDetail struct { + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + Trustor string `json:"trustor"` + Trustee string `json:"trustee"` + TrusteeMuxed string `json:"trustee_muxed"` + TrusteeMuxedID uint64 `json:"trustee_muxed_id"` + Authorize bool `json:"authorize"` + AuthorizeToMaintainLiabilities bool `json:"authorize_to_maintain_liabilities"` + ClawbackEnabled bool `json:"clawback_enabled"` +} + +func (o *LedgerOperation) AllowTrustDetails() (AllowTrustDetail, error) { + op, ok := o.Operation.Body.GetAllowTrustOp() + if !ok { + return AllowTrustDetail{}, fmt.Errorf("could not access AllowTrust info for this operation (index %d)", o.OperationIndex) + } + + allowTrustDetail := AllowTrustDetail{ + Trustor: op.Trustor.Address(), + Trustee: o.SourceAccount(), + Authorize: xdr.TrustLineFlags(op.Authorize).IsAuthorizedToMaintainLiabilitiesFlag(), + AuthorizeToMaintainLiabilities: xdr.TrustLineFlags(op.Authorize).IsAuthorizedToMaintainLiabilitiesFlag(), + ClawbackEnabled: xdr.TrustLineFlags(op.Authorize).IsClawbackEnabledFlag(), + } + + var err error + var assetCode, assetIssuer, assetType string + err = op.Asset.ToAsset(o.sourceAccountXDR().ToAccountId()).Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return AllowTrustDetail{}, err + } + + allowTrustDetail.AssetCode = assetCode + allowTrustDetail.AssetIssuer = assetIssuer + allowTrustDetail.AssetType = assetType + + var trusteeMuxed string + var trusteeMuxedID uint64 + trusteeMuxed, trusteeMuxedID, err = getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return AllowTrustDetail{}, err + } + + allowTrustDetail.TrusteeMuxed = trusteeMuxed + allowTrustDetail.TrusteeMuxedID = trusteeMuxedID + + return allowTrustDetail, nil +} diff --git a/ingest/begin_sponsoring_future_reserve_details.go b/ingest/begin_sponsoring_future_reserve_details.go new file mode 100644 index 0000000000..ea0c255468 --- /dev/null +++ b/ingest/begin_sponsoring_future_reserve_details.go @@ -0,0 +1,18 @@ +package ingest + +import "fmt" + +type BeginSponsoringFutureReservesDetail struct { + SponsoredID string `json:"sponsored_id"` +} + +func (o *LedgerOperation) BeginSponsoringFutureReservesDetails() (BeginSponsoringFutureReservesDetail, error) { + op, ok := o.Operation.Body.GetBeginSponsoringFutureReservesOp() + if !ok { + return BeginSponsoringFutureReservesDetail{}, fmt.Errorf("could not access BeginSponsoringFutureReserves info for this operation (index %d)", o.OperationIndex) + } + + return BeginSponsoringFutureReservesDetail{ + SponsoredID: op.SponsoredId.Address(), + }, nil +} diff --git a/ingest/bump_sequence_details.go b/ingest/bump_sequence_details.go new file mode 100644 index 0000000000..c3e3d2e86e --- /dev/null +++ b/ingest/bump_sequence_details.go @@ -0,0 +1,18 @@ +package ingest + +import "fmt" + +type BumpSequenceDetails struct { + BumpTo string `json:"bump_to"` +} + +func (o *LedgerOperation) BumpSequenceDetails() (BumpSequenceDetails, error) { + op, ok := o.Operation.Body.GetBumpSequenceOp() + if !ok { + return BumpSequenceDetails{}, fmt.Errorf("could not access BumpSequence info for this operation (index %d)", o.OperationIndex) + } + + return BumpSequenceDetails{ + BumpTo: fmt.Sprintf("%d", op.BumpTo), + }, nil +} diff --git a/ingest/change_trust_details.go b/ingest/change_trust_details.go new file mode 100644 index 0000000000..a3302146f7 --- /dev/null +++ b/ingest/change_trust_details.go @@ -0,0 +1,85 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type ChangeTrustDetail struct { + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + LiquidityPoolID string `json:"liquidity_pool_id"` + Limit int64 `json:"limit"` + Trustee string `json:"trustee"` + Trustor string `json:"trustor"` + TrustorMuxed string `json:"trustor_muxed"` + TrustorMuxedID uint64 `json:"trustor_muxed_id"` +} + +func (o *LedgerOperation) ChangeTrustDetails() (ChangeTrustDetail, error) { + op, ok := o.Operation.Body.GetChangeTrustOp() + if !ok { + return ChangeTrustDetail{}, fmt.Errorf("could not access GetChangeTrust info for this operation (index %d)", o.OperationIndex) + } + + var err error + changeTrustDetail := ChangeTrustDetail{ + Trustor: o.SourceAccount(), + Limit: int64(op.Limit), + } + + if op.Line.Type == xdr.AssetTypeAssetTypePoolShare { + changeTrustDetail.AssetType, changeTrustDetail.LiquidityPoolID, err = getLiquidityPoolAssetDetails(*op.Line.LiquidityPool) + if err != nil { + return ChangeTrustDetail{}, err + } + } else { + var assetCode, assetIssuer, assetType string + err = op.Line.ToAsset().Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return ChangeTrustDetail{}, err + } + + changeTrustDetail.AssetCode = assetCode + changeTrustDetail.AssetIssuer = assetIssuer + changeTrustDetail.AssetType = assetType + changeTrustDetail.Trustee = assetIssuer + } + + var trustorMuxed string + var trustorMuxedID uint64 + trustorMuxed, trustorMuxedID, err = getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return ChangeTrustDetail{}, err + } + + changeTrustDetail.TrustorMuxed = trustorMuxed + changeTrustDetail.TrustorMuxedID = trustorMuxedID + + return changeTrustDetail, nil +} + +func getLiquidityPoolAssetDetails(lpp xdr.LiquidityPoolParameters) (string, string, error) { + if lpp.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { + return "", "", fmt.Errorf("unknown liquidity pool type %d", lpp.Type) + } + + cp := lpp.ConstantProduct + + var err error + var poolID xdr.PoolId + var poolIDString string + poolID, err = xdr.NewPoolId(cp.AssetA, cp.AssetB, cp.Fee) + if err != nil { + return "", "", err + } + + poolIDString, err = PoolIDToString(poolID) + if err != nil { + return "", "", err + } + + return "liquidity_pool_shares", poolIDString, nil +} diff --git a/ingest/claim_claimable_balance_details.go b/ingest/claim_claimable_balance_details.go new file mode 100644 index 0000000000..2125d31e6b --- /dev/null +++ b/ingest/claim_claimable_balance_details.go @@ -0,0 +1,46 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type ClaimClaimableBalanceDetail struct { + BalanceID string `json:"balance_id"` + Claimant string `json:"claimant"` + ClaimantMuxed string `json:"claimant_muxed"` + ClaimantMuxedID uint64 `json:"claimant_muxed_id"` +} + +func (o *LedgerOperation) ClaimClaimableBalanceDetails() (ClaimClaimableBalanceDetail, error) { + op, ok := o.Operation.Body.GetClaimClaimableBalanceOp() + if !ok { + return ClaimClaimableBalanceDetail{}, fmt.Errorf("could not access ClaimClaimableBalance info for this operation (index %d)", o.OperationIndex) + } + + claimClaimableBalanceDetail := ClaimClaimableBalanceDetail{ + Claimant: o.SourceAccount(), + } + + var err error + var balanceID string + balanceID, err = xdr.MarshalBase64(op.BalanceId) + if err != nil { + return ClaimClaimableBalanceDetail{}, err + } + + claimClaimableBalanceDetail.BalanceID = balanceID + + var claimantMuxed string + var claimantMuxedID uint64 + claimantMuxed, claimantMuxedID, err = getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return ClaimClaimableBalanceDetail{}, err + } + + claimClaimableBalanceDetail.ClaimantMuxed = claimantMuxed + claimClaimableBalanceDetail.ClaimantMuxedID = claimantMuxedID + + return claimClaimableBalanceDetail, nil +} diff --git a/ingest/clawback_claimable_balance_details.go b/ingest/clawback_claimable_balance_details.go new file mode 100644 index 0000000000..5a8e19f796 --- /dev/null +++ b/ingest/clawback_claimable_balance_details.go @@ -0,0 +1,25 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type ClawbackClaimableBalanceDetail struct { + BalanceID string `json:"balance_id"` +} + +func (o *LedgerOperation) ClawbackClaimableBalanceDetails() (ClawbackClaimableBalanceDetail, error) { + op, ok := o.Operation.Body.GetClawbackClaimableBalanceOp() + if !ok { + return ClawbackClaimableBalanceDetail{}, fmt.Errorf("could not access ClawbackClaimableBalance info for this operation (index %d)", o.OperationIndex) + } + + balanceID, err := xdr.MarshalBase64(op.BalanceId) + if err != nil { + return ClawbackClaimableBalanceDetail{}, err + } + + return ClawbackClaimableBalanceDetail{BalanceID: balanceID}, nil +} diff --git a/ingest/clawback_details.go b/ingest/clawback_details.go new file mode 100644 index 0000000000..f9dc0f6fd4 --- /dev/null +++ b/ingest/clawback_details.go @@ -0,0 +1,47 @@ +package ingest + +import "fmt" + +type ClawbackDetail struct { + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + From string `json:"from"` + FromMuxed string `json:"from_muxed"` + FromMuxedID uint64 `json:"from_muxed_id"` + Amount int64 `json:"amount"` +} + +func (o *LedgerOperation) ClawbackDetails() (ClawbackDetail, error) { + op, ok := o.Operation.Body.GetClawbackOp() + if !ok { + return ClawbackDetail{}, fmt.Errorf("could not access Clawback info for this operation (index %d)", o.OperationIndex) + } + + clawbackDetail := ClawbackDetail{ + Amount: int64(op.Amount), + } + + var err error + var assetCode, assetIssuer, assetType string + err = op.Asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return ClawbackDetail{}, err + } + + clawbackDetail.AssetCode = assetCode + clawbackDetail.AssetIssuer = assetIssuer + clawbackDetail.AssetType = assetType + + var fromMuxed string + var fromMuxedID uint64 + fromMuxed, fromMuxedID, err = getMuxedAccountDetails(op.From) + if err != nil { + return ClawbackDetail{}, err + } + + clawbackDetail.FromMuxed = fromMuxed + clawbackDetail.FromMuxedID = fromMuxedID + + return clawbackDetail, nil +} diff --git a/ingest/create_account_details.go b/ingest/create_account_details.go new file mode 100644 index 0000000000..9a04de1be6 --- /dev/null +++ b/ingest/create_account_details.go @@ -0,0 +1,36 @@ +package ingest + +import ( + "fmt" +) + +type CreateAccountDetail struct { + Account string `json:"account"` + StartingBalance int64 `json:"starting_balance"` + Funder string `json:"funder"` + FunderMuxed string `json:"funder_muxed"` + FunderMuxedID uint64 `json:"funder_muxed_id"` +} + +func (o *LedgerOperation) CreateAccountDetails() (CreateAccountDetail, error) { + op, ok := o.Operation.Body.GetCreateAccountOp() + if !ok { + return CreateAccountDetail{}, fmt.Errorf("could not access CreateAccount info for this operation (index %d)", o.OperationIndex) + } + + createAccountDetail := CreateAccountDetail{ + Account: op.Destination.Address(), + StartingBalance: int64(op.StartingBalance), + Funder: o.SourceAccount(), + } + + funderMuxed, funderMuxedID, err := getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return CreateAccountDetail{}, err + } + + createAccountDetail.FunderMuxed = funderMuxed + createAccountDetail.FunderMuxedID = funderMuxedID + + return createAccountDetail, nil +} diff --git a/ingest/create_claimable_balance_details.go b/ingest/create_claimable_balance_details.go new file mode 100644 index 0000000000..795ed5edf0 --- /dev/null +++ b/ingest/create_claimable_balance_details.go @@ -0,0 +1,38 @@ +package ingest + +import ( + "fmt" +) + +type CreateClaimableBalanceDetail struct { + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + Amount int64 `json:"amount"` + Claimants []Claimant `json:"claimants"` +} + +func (o *LedgerOperation) CreateClaimableBalanceDetails() (CreateClaimableBalanceDetail, error) { + op, ok := o.Operation.Body.GetCreateClaimableBalanceOp() + if !ok { + return CreateClaimableBalanceDetail{}, fmt.Errorf("could not access CreateClaimableBalance info for this operation (index %d)", o.OperationIndex) + } + + createClaimableBalanceDetail := CreateClaimableBalanceDetail{ + Claimants: transformClaimants(op.Claimants), + Amount: int64(op.Amount), + } + + var err error + var assetCode, assetIssuer, assetType string + err = op.Asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return CreateClaimableBalanceDetail{}, err + } + + createClaimableBalanceDetail.AssetCode = assetCode + createClaimableBalanceDetail.AssetIssuer = assetIssuer + createClaimableBalanceDetail.AssetType = assetType + + return createClaimableBalanceDetail, nil +} diff --git a/ingest/create_passive_sell_offer_details.go b/ingest/create_passive_sell_offer_details.go new file mode 100644 index 0000000000..1532cb7d07 --- /dev/null +++ b/ingest/create_passive_sell_offer_details.go @@ -0,0 +1,60 @@ +package ingest + +import ( + "fmt" + "strconv" +) + +type CreatePassiveSellOfferDetail struct { + Amount int64 `json:"amount"` + PriceN int32 `json:"price_n"` + PriceD int32 `json:"price_d"` + Price float64 `json:"price"` + BuyingAssetCode string `json:"buying_asset_code"` + BuyingAssetIssuer string `json:"buying_asset_issuer"` + BuyingAssetType string `json:"buying_asset_type"` + SellingAssetCode string `json:"selling_asset_code"` + SellingAssetIssuer string `json:"selling_asset_issuer"` + SellingAssetType string `json:"selling_asset_type"` +} + +func (o *LedgerOperation) CreatePassiveSellOfferDetails() (CreatePassiveSellOfferDetail, error) { + op, ok := o.Operation.Body.GetCreatePassiveSellOfferOp() + if !ok { + return CreatePassiveSellOfferDetail{}, fmt.Errorf("could not access CreatePassiveSellOffer info for this operation (index %d)", o.OperationIndex) + } + + createPassiveSellOffer := CreatePassiveSellOfferDetail{ + Amount: int64(op.Amount), + PriceN: int32(op.Price.N), + PriceD: int32(op.Price.D), + } + + var err error + createPassiveSellOffer.Price, err = strconv.ParseFloat(op.Price.String(), 64) + if err != nil { + return CreatePassiveSellOfferDetail{}, err + } + + var buyingAssetCode, buyingAssetIssuer, buyingAssetType string + err = op.Buying.Extract(&buyingAssetType, &buyingAssetCode, &buyingAssetIssuer) + if err != nil { + return CreatePassiveSellOfferDetail{}, err + } + + createPassiveSellOffer.BuyingAssetCode = buyingAssetCode + createPassiveSellOffer.BuyingAssetIssuer = buyingAssetIssuer + createPassiveSellOffer.BuyingAssetType = buyingAssetType + + var sellingAssetCode, sellingAssetIssuer, sellingAssetType string + err = op.Selling.Extract(&sellingAssetType, &sellingAssetCode, &sellingAssetIssuer) + if err != nil { + return CreatePassiveSellOfferDetail{}, err + } + + createPassiveSellOffer.SellingAssetCode = sellingAssetCode + createPassiveSellOffer.SellingAssetIssuer = sellingAssetIssuer + createPassiveSellOffer.SellingAssetType = sellingAssetType + + return createPassiveSellOffer, nil +} diff --git a/ingest/end_sponsoring_future_reserve_details.go b/ingest/end_sponsoring_future_reserve_details.go new file mode 100644 index 0000000000..5a9b58df9e --- /dev/null +++ b/ingest/end_sponsoring_future_reserve_details.go @@ -0,0 +1,51 @@ +package ingest + +type EndSponsoringFutureReserveDetail struct { + BeginSponsor string `json:"begin_sponsor"` + BeginSponsorMuxed string `json:"begin_sponsor_muxed"` + BeginSponsorMuxedID uint64 `json:"begin_sponsor_muxed_id"` +} + +func (o *LedgerOperation) EndSponsoringFutureReserveDetails() (EndSponsoringFutureReserveDetail, error) { + var endSponsoringFutureReserveDetail EndSponsoringFutureReserveDetail + + beginSponsorOp := o.findInitatingBeginSponsoringOp() + if beginSponsorOp != nil { + endSponsoringFutureReserveDetail.BeginSponsor = o.SourceAccount() + + var err error + var beginSponsorMuxed string + var beginSponsorMuxedID uint64 + beginSponsorMuxed, beginSponsorMuxedID, err = getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return EndSponsoringFutureReserveDetail{}, err + } + + endSponsoringFutureReserveDetail.BeginSponsorMuxed = beginSponsorMuxed + endSponsoringFutureReserveDetail.BeginSponsorMuxedID = beginSponsorMuxedID + } + + return endSponsoringFutureReserveDetail, nil +} + +func (o *LedgerOperation) findInitatingBeginSponsoringOp() *SponsorshipOutput { + if !o.Transaction.Successful() { + // Failed transactions may not have a compliant sandwich structure + // we can rely on (e.g. invalid nesting or a being operation with the wrong sponsoree ID) + // and thus we bail out since we could return incorrect information. + return nil + } + sponsoree := o.sourceAccountXDR().ToAccountId() + operations := o.Transaction.Envelope.Operations() + for i := int(o.OperationIndex) - 1; i >= 0; i-- { + if beginOp, ok := operations[i].Body.GetBeginSponsoringFutureReservesOp(); ok && + beginOp.SponsoredId.Address() == sponsoree.Address() { + result := SponsorshipOutput{ + Operation: operations[i], + OperationIndex: uint32(i), + } + return &result + } + } + return nil +} diff --git a/ingest/extend_footprint_ttl_details.go b/ingest/extend_footprint_ttl_details.go new file mode 100644 index 0000000000..8889077e03 --- /dev/null +++ b/ingest/extend_footprint_ttl_details.go @@ -0,0 +1,38 @@ +package ingest + +import "fmt" + +type ExtendFootprintTtlDetail struct { + Type string `json:"type"` + ExtendTo uint32 `json:"extend_to"` + LedgerKeyHash []string `json:"ledger_key_hash"` + ContractID string `json:"contract_id"` + ContractCodeHash string `json:"contract_code_hash"` +} + +func (o *LedgerOperation) ExtendFootprintTtlDetails() (ExtendFootprintTtlDetail, error) { + op, ok := o.Operation.Body.GetExtendFootprintTtlOp() + if !ok { + return ExtendFootprintTtlDetail{}, fmt.Errorf("could not access ExtendFootprintTtl info for this operation (index %d)", o.OperationIndex) + } + + extendFootprintTtlDetail := ExtendFootprintTtlDetail{ + Type: "extend_footprint_ttl", + ExtendTo: uint32(op.ExtendTo), + LedgerKeyHash: o.Transaction.LedgerKeyHashFromTxEnvelope(), + } + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + extendFootprintTtlDetail.ContractID = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + extendFootprintTtlDetail.ContractCodeHash = contractCodeHash + } + + return extendFootprintTtlDetail, nil +} diff --git a/ingest/inflation_details.go b/ingest/inflation_details.go new file mode 100644 index 0000000000..6eda8adea1 --- /dev/null +++ b/ingest/inflation_details.go @@ -0,0 +1,7 @@ +package ingest + +type InflationDetail struct{} + +func (o *LedgerOperation) InflationDetails() (InflationDetail, error) { + return InflationDetail{}, nil +} diff --git a/ingest/invoke_host_function_details.go b/ingest/invoke_host_function_details.go new file mode 100644 index 0000000000..8a37365602 --- /dev/null +++ b/ingest/invoke_host_function_details.go @@ -0,0 +1,144 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type InvokeHostFunctionDetail struct { + Function string `json:"function"` + Type string `json:"type"` + LedgerKeyHash []string `json:"ledger_key_hash"` + ContractID string `json:"contract_id"` + ContractCodeHash string `json:"contract_code_hash"` + Parameters []map[string]string `json:"parameters"` + ParametersDecoded []map[string]string `json:"parameters_decoded"` + AssetBalanceChanges []BalanceChangeDetail `json:"asset_balance_changes"` + From string `json:"from"` + Address string `json:"address"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` +} + +func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, error) { + op, ok := o.Operation.Body.GetInvokeHostFunctionOp() + if !ok { + return InvokeHostFunctionDetail{}, fmt.Errorf("could not access InvokeHostFunction info for this operation (index %d)", o.OperationIndex) + } + + invokeHostFunctionDetail := InvokeHostFunctionDetail{ + Function: op.HostFunction.Type.String(), + } + + switch op.HostFunction.Type { + case xdr.HostFunctionTypeHostFunctionTypeInvokeContract: + invokeArgs := op.HostFunction.MustInvokeContract() + args := make([]xdr.ScVal, 0, len(invokeArgs.Args)+2) + args = append(args, xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &invokeArgs.ContractAddress}) + args = append(args, xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &invokeArgs.FunctionName}) + args = append(args, invokeArgs.Args...) + + invokeHostFunctionDetail.Type = "invoke_contract" + + contractId, err := invokeArgs.ContractAddress.String() + if err != nil { + return InvokeHostFunctionDetail{}, err + } + + invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() + invokeHostFunctionDetail.ContractID = contractId + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + invokeHostFunctionDetail.ContractCodeHash = contractCodeHash + } + + // TODO: Parameters should be processed with xdr2json + invokeHostFunctionDetail.Parameters, invokeHostFunctionDetail.ParametersDecoded = o.serializeParameters(args) + + balanceChanges, err := o.parseAssetBalanceChangesFromContractEvents() + if err != nil { + return InvokeHostFunctionDetail{}, err + } + + invokeHostFunctionDetail.AssetBalanceChanges = balanceChanges + + case xdr.HostFunctionTypeHostFunctionTypeCreateContract: + args := op.HostFunction.MustCreateContract() + + invokeHostFunctionDetail.Type = "create_contract" + invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + invokeHostFunctionDetail.ContractID = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + invokeHostFunctionDetail.ContractCodeHash = contractCodeHash + } + + preImageDetails, err := switchContractIdPreimageType(args.ContractIdPreimage) + if err != nil { + return InvokeHostFunctionDetail{}, nil + } + + invokeHostFunctionDetail.From = preImageDetails.From + invokeHostFunctionDetail.Address = preImageDetails.Address + invokeHostFunctionDetail.AssetCode = preImageDetails.AssetCode + invokeHostFunctionDetail.AssetIssuer = preImageDetails.AssetIssuer + invokeHostFunctionDetail.AssetType = preImageDetails.AssetType + case xdr.HostFunctionTypeHostFunctionTypeUploadContractWasm: + invokeHostFunctionDetail.Type = "upload_wasm" + invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + invokeHostFunctionDetail.ContractCodeHash = contractCodeHash + } + case xdr.HostFunctionTypeHostFunctionTypeCreateContractV2: + args := op.HostFunction.MustCreateContractV2() + + invokeHostFunctionDetail.Type = "create_contract_v2" + invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + invokeHostFunctionDetail.ContractID = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + invokeHostFunctionDetail.ContractCodeHash = contractCodeHash + } + + // ConstructorArgs is a list of ScVals + // This will initially be handled the same as InvokeContractParams until a different + // model is found necessary. + invokeHostFunctionDetail.Parameters, invokeHostFunctionDetail.ParametersDecoded = o.serializeParameters(args.ConstructorArgs) + + preImageDetails, err := switchContractIdPreimageType(args.ContractIdPreimage) + if err != nil { + return InvokeHostFunctionDetail{}, nil + } + + invokeHostFunctionDetail.From = preImageDetails.From + invokeHostFunctionDetail.Address = preImageDetails.Address + invokeHostFunctionDetail.AssetCode = preImageDetails.AssetCode + invokeHostFunctionDetail.AssetIssuer = preImageDetails.AssetIssuer + invokeHostFunctionDetail.AssetType = preImageDetails.AssetType + default: + return InvokeHostFunctionDetail{}, fmt.Errorf("unknown host function type: %s", op.HostFunction.Type) + } + + return invokeHostFunctionDetail, nil +} diff --git a/ingest/ledger_operation.go b/ingest/ledger_operation.go index cf7f29f799..77b831448d 100644 --- a/ingest/ledger_operation.go +++ b/ingest/ledger_operation.go @@ -4,7 +4,6 @@ import ( "encoding/base64" "fmt" "math/big" - "strconv" "github.com/dgryski/go-farm" "github.com/stellar/go/amount" @@ -31,10 +30,7 @@ func (o *LedgerOperation) sourceAccountXDR() xdr.MuxedAccount { func (o *LedgerOperation) SourceAccount() string { muxedAccount := o.sourceAccountXDR() - providedID := muxedAccount.ToAccountId() - pointerToID := &providedID - - return pointerToID.Address() + return muxedAccount.ToAccountId().Address() } func (o *LedgerOperation) Type() int32 { @@ -90,9 +86,9 @@ func (o *LedgerOperation) OperationTraceCode() (string, error) { return operationTraceCode, nil } -func (o *LedgerOperation) OperationDetails() (map[string]interface{}, error) { +func (o *LedgerOperation) OperationDetails() (interface{}, error) { var err error - details := map[string]interface{}{} + var details interface{} switch o.Operation.Body.Type { case xdr.OperationTypeCreateAccount: @@ -201,7 +197,7 @@ func (o *LedgerOperation) OperationDetails() (map[string]interface{}, error) { return details, err } case xdr.OperationTypeSetTrustLineFlags: - details, err = o.SetTrustLineFlagsDetails() + details, err = o.SetTrustlineFlagsDetails() if err != nil { return details, err } @@ -237,705 +233,85 @@ func (o *LedgerOperation) OperationDetails() (map[string]interface{}, error) { return details, nil } -func (o *LedgerOperation) CreateAccountDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetCreateAccountOp() - if !ok { - return details, fmt.Errorf("could not access CreateAccount info for this operation (index %d)", o.OperationIndex) - } - - if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "funder"); err != nil { - return details, err - } - details["account"] = op.Destination.Address() - details["starting_balance"] = int64(op.StartingBalance) - - return details, nil -} +func getMuxedAccountDetails(a xdr.MuxedAccount) (string, uint64, error) { + var err error + var muxedAccountAddress string + var muxedAccountID uint64 -func (o *LedgerOperation) addAccountAndMuxedAccountDetails(result map[string]interface{}, a xdr.MuxedAccount, prefix string) error { - account_id := a.ToAccountId() - result[prefix] = account_id.Address() - prefix = o.FormatPrefix(prefix) if a.Type == xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { - muxedAccountAddress, err := a.GetAddress() + muxedAccountAddress, err = a.GetAddress() if err != nil { - return err + return "", 0, err } - result[prefix+"muxed"] = muxedAccountAddress - muxedAccountId, err := a.GetId() + muxedAccountID, err = a.GetId() if err != nil { - return err - } - result[prefix+"muxed_id"] = muxedAccountId - } - return nil -} - -func (o *LedgerOperation) PaymentDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetPaymentOp() - if !ok { - return details, fmt.Errorf("could not access Payment info for this operation (index %d)", o.OperationIndex) - } - - if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "from"); err != nil { - return details, err - } - if err := o.addAccountAndMuxedAccountDetails(details, op.Destination, "to"); err != nil { - return details, err - } - details["amount"] = int64(op.Amount) - if err := o.addAssetDetails(details, op.Asset, ""); err != nil { - return details, err - } - - return details, nil -} - -func (o *LedgerOperation) PathPaymentStrictReceiveDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetPathPaymentStrictReceiveOp() - if !ok { - return details, fmt.Errorf("could not access PathPaymentStrictReceive info for this operation (index %d)", o.OperationIndex) - } - - if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "from"); err != nil { - return details, err - } - if err := o.addAccountAndMuxedAccountDetails(details, op.Destination, "to"); err != nil { - return details, err - } - details["amount"] = int64(op.DestAmount) - details["source_amount"] = amount.String(0) - details["source_max"] = int64(op.SendMax) - if err := o.addAssetDetails(details, op.DestAsset, ""); err != nil { - return details, err - } - if err := o.addAssetDetails(details, op.SendAsset, "source"); err != nil { - return details, err - } - - if o.Transaction.Successful() { - allOperationResults, ok := o.Transaction.Result.OperationResults() - if !ok { - return details, fmt.Errorf("could not access any results for this transaction") - } - currentOperationResult := allOperationResults[o.OperationIndex] - resultBody, ok := currentOperationResult.GetTr() - if !ok { - return details, fmt.Errorf("could not access result body for this operation (index %d)", o.OperationIndex) - } - result, ok := resultBody.GetPathPaymentStrictReceiveResult() - if !ok { - return details, fmt.Errorf("could not access PathPaymentStrictReceive result info for this operation (index %d)", o.OperationIndex) - } - details["source_amount"] = int64(result.SendAmount()) - } - - details["path"] = o.TransformPath(op.Path) - return details, nil -} - -func (o *LedgerOperation) PathPaymentStrictSendDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetPathPaymentStrictSendOp() - if !ok { - return details, fmt.Errorf("could not access PathPaymentStrictSend info for this operation (index %d)", o.OperationIndex) - } - - if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "from"); err != nil { - return details, err - } - if err := o.addAccountAndMuxedAccountDetails(details, op.Destination, "to"); err != nil { - return details, err - } - details["amount"] = float64(0) - details["source_amount"] = int64(op.SendAmount) - details["destination_min"] = amount.String(op.DestMin) - if err := o.addAssetDetails(details, op.DestAsset, ""); err != nil { - return details, err - } - if err := o.addAssetDetails(details, op.SendAsset, "source"); err != nil { - return details, err - } - - if o.Transaction.Successful() { - allOperationResults, ok := o.Transaction.Result.OperationResults() - if !ok { - return details, fmt.Errorf("could not access any results for this transaction") - } - currentOperationResult := allOperationResults[o.OperationIndex] - resultBody, ok := currentOperationResult.GetTr() - if !ok { - return details, fmt.Errorf("could not access result body for this operation (index %d)", o.OperationIndex) - } - result, ok := resultBody.GetPathPaymentStrictSendResult() - if !ok { - return details, fmt.Errorf("could not access GetPathPaymentStrictSendResult result info for this operation (index %d)", o.OperationIndex) - } - details["amount"] = int64(result.DestAmount()) - } - - details["path"] = o.TransformPath(op.Path) - - return details, nil -} -func (o *LedgerOperation) ManageBuyOfferDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetManageBuyOfferOp() - if !ok { - return details, fmt.Errorf("could not access ManageBuyOffer info for this operation (index %d)", o.OperationIndex) - } - - details["offer_id"] = int64(op.OfferId) - details["amount"] = int64(op.BuyAmount) - if err := o.addPriceDetails(details, op.Price, ""); err != nil { - return details, err - } - - if err := o.addAssetDetails(details, op.Buying, "buying"); err != nil { - return details, err - } - if err := o.addAssetDetails(details, op.Selling, "selling"); err != nil { - return details, err - } - - return details, nil -} - -func (o *LedgerOperation) addPriceDetails(result map[string]interface{}, price xdr.Price, prefix string) error { - prefix = o.FormatPrefix(prefix) - parsedPrice, err := strconv.ParseFloat(price.String(), 64) - if err != nil { - return err - } - result[prefix+"price"] = parsedPrice - result[prefix+"price_r"] = Price{ - Numerator: int32(price.N), - Denominator: int32(price.D), - } - return nil -} - -func (o *LedgerOperation) ManageSellOfferDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetManageSellOfferOp() - if !ok { - return details, fmt.Errorf("could not access ManageSellOffer info for this operation (index %d)", o.OperationIndex) - } - - details["offer_id"] = int64(op.OfferId) - details["amount"] = int64(op.Amount) - if err := o.addPriceDetails(details, op.Price, ""); err != nil { - return details, err - } - - if err := o.addAssetDetails(details, op.Buying, "buying"); err != nil { - return details, err - } - if err := o.addAssetDetails(details, op.Selling, "selling"); err != nil { - return details, err - } - - return details, nil -} -func (o *LedgerOperation) CreatePassiveSellOfferDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetCreatePassiveSellOfferOp() - if !ok { - return details, fmt.Errorf("could not access CreatePassiveSellOffer info for this operation (index %d)", o.OperationIndex) - } - - details["amount"] = int64(op.Amount) - if err := o.addPriceDetails(details, op.Price, ""); err != nil { - return details, err - } - - if err := o.addAssetDetails(details, op.Buying, "buying"); err != nil { - return details, err - } - if err := o.addAssetDetails(details, op.Selling, "selling"); err != nil { - return details, err - } - - return details, nil -} -func (o *LedgerOperation) SetOptionsDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetSetOptionsOp() - if !ok { - return details, fmt.Errorf("could not access GetSetOptions info for this operation (index %d)", o.OperationIndex) - } - - if op.InflationDest != nil { - details["inflation_dest"] = op.InflationDest.Address() - } - - if op.SetFlags != nil && *op.SetFlags > 0 { - o.addOperationFlagToOperationDetails(details, uint32(*op.SetFlags), "set") - } - - if op.ClearFlags != nil && *op.ClearFlags > 0 { - o.addOperationFlagToOperationDetails(details, uint32(*op.ClearFlags), "clear") - } - - if op.MasterWeight != nil { - details["master_key_weight"] = uint32(*op.MasterWeight) - } - - if op.LowThreshold != nil { - details["low_threshold"] = uint32(*op.LowThreshold) - } - - if op.MedThreshold != nil { - details["med_threshold"] = uint32(*op.MedThreshold) - } - - if op.HighThreshold != nil { - details["high_threshold"] = uint32(*op.HighThreshold) - } - - if op.HomeDomain != nil { - details["home_domain"] = string(*op.HomeDomain) - } - - if op.Signer != nil { - details["signer_key"] = op.Signer.Key.Address() - details["signer_weight"] = uint32(op.Signer.Weight) - } - - return details, nil -} - -func (o *LedgerOperation) addOperationFlagToOperationDetails(result map[string]interface{}, flag uint32, prefix string) { - intFlags := make([]int32, 0) - stringFlags := make([]string, 0) - - if (int64(flag) & int64(xdr.AccountFlagsAuthRequiredFlag)) > 0 { - intFlags = append(intFlags, int32(xdr.AccountFlagsAuthRequiredFlag)) - stringFlags = append(stringFlags, "auth_required") - } - - if (int64(flag) & int64(xdr.AccountFlagsAuthRevocableFlag)) > 0 { - intFlags = append(intFlags, int32(xdr.AccountFlagsAuthRevocableFlag)) - stringFlags = append(stringFlags, "auth_revocable") - } - - if (int64(flag) & int64(xdr.AccountFlagsAuthImmutableFlag)) > 0 { - intFlags = append(intFlags, int32(xdr.AccountFlagsAuthImmutableFlag)) - stringFlags = append(stringFlags, "auth_immutable") - } - - if (int64(flag) & int64(xdr.AccountFlagsAuthClawbackEnabledFlag)) > 0 { - intFlags = append(intFlags, int32(xdr.AccountFlagsAuthClawbackEnabledFlag)) - stringFlags = append(stringFlags, "auth_clawback_enabled") - } - - prefix = o.FormatPrefix(prefix) - result[prefix+"flags"] = intFlags - result[prefix+"flags_s"] = stringFlags -} - -func (o *LedgerOperation) ChangeTrustDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetChangeTrustOp() - if !ok { - return details, fmt.Errorf("could not access GetChangeTrust info for this operation (index %d)", o.OperationIndex) - } - - if op.Line.Type == xdr.AssetTypeAssetTypePoolShare { - if err := o.addLiquidityPoolAssetDetails(details, *op.Line.LiquidityPool); err != nil { - return details, err - } - } else { - if err := o.addAssetDetails(details, op.Line.ToAsset(), ""); err != nil { - return details, err + return "", 0, err } - details["trustee"] = details["asset_issuer"] - } - - if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "trustor"); err != nil { - return details, err - } - - details["limit"] = int64(op.Limit) - - return details, nil -} - -func (o *LedgerOperation) addLiquidityPoolAssetDetails(result map[string]interface{}, lpp xdr.LiquidityPoolParameters) error { - result["asset_type"] = "liquidity_pool_shares" - if lpp.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { - return fmt.Errorf("unknown liquidity pool type %d", lpp.Type) - } - cp := lpp.ConstantProduct - poolID, err := xdr.NewPoolId(cp.AssetA, cp.AssetB, cp.Fee) - if err != nil { - return err - } - - result["liquidity_pool_id"] = o.PoolIDToString(poolID) - - return nil -} - -func (o *LedgerOperation) AllowTrustDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetAllowTrustOp() - if !ok { - return details, fmt.Errorf("could not access AllowTrust info for this operation (index %d)", o.OperationIndex) - } - - if err := o.addAssetDetails(details, op.Asset.ToAsset(o.sourceAccountXDR().ToAccountId()), ""); err != nil { - return details, err - } - if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "trustee"); err != nil { - return details, err - } - details["trustor"] = op.Trustor.Address() - shouldAuth := xdr.TrustLineFlags(op.Authorize).IsAuthorized() - details["authorize"] = shouldAuth - shouldAuthLiabilities := xdr.TrustLineFlags(op.Authorize).IsAuthorizedToMaintainLiabilitiesFlag() - if shouldAuthLiabilities { - details["authorize_to_maintain_liabilities"] = shouldAuthLiabilities - } - shouldClawbackEnabled := xdr.TrustLineFlags(op.Authorize).IsClawbackEnabledFlag() - if shouldClawbackEnabled { - details["clawback_enabled"] = shouldClawbackEnabled - } - - return details, nil -} - -func (o *LedgerOperation) AccountMergeDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - destinationAccount, ok := o.Operation.Body.GetDestination() - if !ok { - return details, fmt.Errorf("could not access Destination info for this operation (index %d)", o.OperationIndex) - } - - if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "account"); err != nil { - return details, err - } - if err := o.addAccountAndMuxedAccountDetails(details, destinationAccount, "into"); err != nil { - return details, err } - - return details, nil + return muxedAccountAddress, muxedAccountID, nil } -// Inflation operations don't have information that affects the details struct -func (o *LedgerOperation) InflationDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - return details, nil +type LedgerKeyDetail struct { + AccountID string `json:"account_id"` + ClaimableBalanceID string `json:"claimable_balance_id"` + DataAccountID string `json:"data_account_id"` + DataName string `json:"data_name"` + OfferID int64 `json:"offer_id"` + TrustlineAccountID string `json:"trustline_account_id"` + TrustlineLiquidityPoolID string `json:"trustline_liquidity_pool_id"` + TrustlineAssetCode string `json:"trustline_asset_code"` + TrustlineAssetIssuer string `json:"trustline_asset_issuer"` + TrustlineAssetType string `json:"trustline_asset_type"` + LiquidityPoolID string `json:"liquidity_pool_id"` } -func (o *LedgerOperation) ManageDataDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetManageDataOp() - if !ok { - return details, fmt.Errorf("could not access GetManageData info for this operation (index %d)", o.OperationIndex) - } - - details["name"] = string(op.DataName) - if op.DataValue != nil { - details["value"] = base64.StdEncoding.EncodeToString(*op.DataValue) - } else { - details["value"] = nil - } - - return details, nil -} - -func (o *LedgerOperation) BumpSequenceDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetBumpSequenceOp() - if !ok { - return details, fmt.Errorf("could not access BumpSequence info for this operation (index %d)", o.OperationIndex) - } - - details["bump_to"] = fmt.Sprintf("%d", op.BumpTo) - - return details, nil -} -func (o *LedgerOperation) CreateClaimableBalanceDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetCreateClaimableBalanceOp() - if !ok { - return details, fmt.Errorf("could not access CreateClaimableBalance info for this operation (index %d)", o.OperationIndex) - } - - details["asset"] = op.Asset.StringCanonical() - err := o.addAssetDetails(details, op.Asset, "") - if err != nil { - return details, err - } - - details["amount"] = int64(op.Amount) - details["claimants"] = o.TransformClaimants(op.Claimants) - - return details, nil -} - -func (o *LedgerOperation) ClaimClaimableBalanceDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetClaimClaimableBalanceOp() - if !ok { - return details, fmt.Errorf("could not access ClaimClaimableBalance info for this operation (index %d)", o.OperationIndex) - } - - balanceID, err := xdr.MarshalHex(op.BalanceId) - if err != nil { - return details, fmt.Errorf("invalid balanceId in op: %d", o.OperationIndex) - } - details["balance_id"] = balanceID - if err := o.addAccountAndMuxedAccountDetails(details, o.sourceAccountXDR(), "claimant"); err != nil { - return details, err - } - - return details, nil -} - -func (o *LedgerOperation) BeginSponsoringFutureReservesDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetBeginSponsoringFutureReservesOp() - if !ok { - return details, fmt.Errorf("could not access BeginSponsoringFutureReserves info for this operation (index %d)", o.OperationIndex) - } - - details["sponsored_id"] = op.SponsoredId.Address() - - return details, nil -} - -func (o *LedgerOperation) EndSponsoringFutureReserveDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - beginSponsorOp := o.findInitatingBeginSponsoringOp() - if beginSponsorOp != nil { - beginSponsorshipSource := o.sourceAccountXDR() - if err := o.addAccountAndMuxedAccountDetails(details, beginSponsorshipSource, "begin_sponsor"); err != nil { - return details, err - } - } - - return details, nil -} - -func (o *LedgerOperation) findInitatingBeginSponsoringOp() *SponsorshipOutput { - if !o.Transaction.Successful() { - // Failed transactions may not have a compliant sandwich structure - // we can rely on (e.g. invalid nesting or a being operation with the wrong sponsoree ID) - // and thus we bail out since we could return incorrect information. - return nil - } - sponsoree := o.sourceAccountXDR().ToAccountId() - operations := o.Transaction.Envelope.Operations() - for i := int(o.OperationIndex) - 1; i >= 0; i-- { - if beginOp, ok := operations[i].Body.GetBeginSponsoringFutureReservesOp(); ok && - beginOp.SponsoredId.Address() == sponsoree.Address() { - result := SponsorshipOutput{ - Operation: operations[i], - OperationIndex: uint32(i), - } - return &result - } - } - return nil -} - -func (o *LedgerOperation) RevokeSponsorshipDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetRevokeSponsorshipOp() - if !ok { - return details, fmt.Errorf("could not access RevokeSponsorship info for this operation (index %d)", o.OperationIndex) - } - - switch op.Type { - case xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry: - if err := o.addLedgerKeyToDetails(details, *op.LedgerKey); err != nil { - return details, err - } - case xdr.RevokeSponsorshipTypeRevokeSponsorshipSigner: - details["signer_account_id"] = op.Signer.AccountId.Address() - details["signer_key"] = op.Signer.SignerKey.Address() - } - - return details, nil -} +func addLedgerKeyToDetails(ledgerKey xdr.LedgerKey) (LedgerKeyDetail, error) { + var err error + var ledgerKeyDetail LedgerKeyDetail -func (o *LedgerOperation) addLedgerKeyToDetails(result map[string]interface{}, ledgerKey xdr.LedgerKey) error { switch ledgerKey.Type { case xdr.LedgerEntryTypeAccount: - result["account_id"] = ledgerKey.Account.AccountId.Address() + ledgerKeyDetail.AccountID = ledgerKey.Account.AccountId.Address() case xdr.LedgerEntryTypeClaimableBalance: - marshalHex, err := xdr.MarshalHex(ledgerKey.ClaimableBalance.BalanceId) + var marshalHex string + marshalHex, err = xdr.MarshalHex(ledgerKey.ClaimableBalance.BalanceId) if err != nil { - return fmt.Errorf("in claimable balance: %w", err) + return LedgerKeyDetail{}, fmt.Errorf("in claimable balance: %w", err) } - result["claimable_balance_id"] = marshalHex + ledgerKeyDetail.ClaimableBalanceID = marshalHex case xdr.LedgerEntryTypeData: - result["data_account_id"] = ledgerKey.Data.AccountId.Address() - result["data_name"] = string(ledgerKey.Data.DataName) + ledgerKeyDetail.DataAccountID = ledgerKey.Data.AccountId.Address() + ledgerKeyDetail.DataName = string(ledgerKey.Data.DataName) case xdr.LedgerEntryTypeOffer: - result["offer_id"] = int64(ledgerKey.Offer.OfferId) + ledgerKeyDetail.OfferID = int64(ledgerKey.Offer.OfferId) case xdr.LedgerEntryTypeTrustline: - result["trustline_account_id"] = ledgerKey.TrustLine.AccountId.Address() + ledgerKeyDetail.TrustlineAccountID = ledgerKey.TrustLine.AccountId.Address() if ledgerKey.TrustLine.Asset.Type == xdr.AssetTypeAssetTypePoolShare { - result["trustline_liquidity_pool_id"] = o.PoolIDToString(*ledgerKey.TrustLine.Asset.LiquidityPoolId) + ledgerKeyDetail.TrustlineLiquidityPoolID, err = PoolIDToString(*ledgerKey.TrustLine.Asset.LiquidityPoolId) + if err != nil { + return LedgerKeyDetail{}, err + } } else { - result["trustline_asset"] = ledgerKey.TrustLine.Asset.ToAsset().StringCanonical() + var assetCode, assetIssuer, assetType string + err = ledgerKey.TrustLine.Asset.ToAsset().Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return LedgerKeyDetail{}, err + } + + ledgerKeyDetail.TrustlineAssetCode = assetCode + ledgerKeyDetail.TrustlineAssetIssuer = assetIssuer + ledgerKeyDetail.TrustlineAssetType = assetType } case xdr.LedgerEntryTypeLiquidityPool: - result["liquidity_pool_id"] = o.PoolIDToString(ledgerKey.LiquidityPool.LiquidityPoolId) - } - return nil -} - -func (o *LedgerOperation) ClawbackDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetClawbackOp() - if !ok { - return details, fmt.Errorf("could not access Clawback info for this operation (index %d)", o.OperationIndex) - } - - if err := o.addAssetDetails(details, op.Asset, ""); err != nil { - return details, err - } - if err := o.addAccountAndMuxedAccountDetails(details, op.From, "from"); err != nil { - return details, err - } - details["amount"] = int64(op.Amount) - - return details, nil -} -func (o *LedgerOperation) ClawbackClaimableBalanceDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetClawbackClaimableBalanceOp() - if !ok { - return details, fmt.Errorf("could not access ClawbackClaimableBalance info for this operation (index %d)", o.OperationIndex) - } - - balanceID, err := xdr.MarshalHex(op.BalanceId) - if err != nil { - return details, fmt.Errorf("invalid balanceId in op: %d", o.OperationIndex) - } - details["balance_id"] = balanceID - - return details, nil -} -func (o *LedgerOperation) SetTrustLineFlagsDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetSetTrustLineFlagsOp() - if !ok { - return details, fmt.Errorf("could not access SetTrustLineFlags info for this operation (index %d)", o.OperationIndex) - } - - details["trustor"] = op.Trustor.Address() - if err := o.addAssetDetails(details, op.Asset, ""); err != nil { - return details, err - } - if op.SetFlags > 0 { - o.addTrustLineFlagToDetails(details, xdr.TrustLineFlags(op.SetFlags), "set") - - } - if op.ClearFlags > 0 { - o.addTrustLineFlagToDetails(details, xdr.TrustLineFlags(op.ClearFlags), "clear") - } - - return details, nil -} - -func (o *LedgerOperation) addTrustLineFlagToDetails(result map[string]interface{}, f xdr.TrustLineFlags, prefix string) { - var ( - n []int32 - s []string - ) - - if f.IsAuthorized() { - n = append(n, int32(xdr.TrustLineFlagsAuthorizedFlag)) - s = append(s, "authorized") - } - - if f.IsAuthorizedToMaintainLiabilitiesFlag() { - n = append(n, int32(xdr.TrustLineFlagsAuthorizedToMaintainLiabilitiesFlag)) - s = append(s, "authorized_to_maintain_liabilities") - } - - if f.IsClawbackEnabledFlag() { - n = append(n, int32(xdr.TrustLineFlagsTrustlineClawbackEnabledFlag)) - s = append(s, "clawback_enabled") - } - - prefix = o.FormatPrefix(prefix) - result[prefix+"flags"] = n - result[prefix+"flags_s"] = s -} - -func (o *LedgerOperation) LiquidityPoolDepositDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetLiquidityPoolDepositOp() - if !ok { - return details, fmt.Errorf("could not access LiquidityPoolDeposit info for this operation (index %d)", o.OperationIndex) - } - - details["liquidity_pool_id"] = o.PoolIDToString(op.LiquidityPoolId) - var ( - assetA, assetB xdr.Asset - depositedA, depositedB xdr.Int64 - sharesReceived xdr.Int64 - ) - if o.Transaction.Successful() { - // we will use the defaults (omitted asset and 0 amounts) if the transaction failed - lp, delta, err := o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) + ledgerKeyDetail.LiquidityPoolID, err = PoolIDToString(ledgerKey.LiquidityPool.LiquidityPoolId) if err != nil { - return nil, err + return LedgerKeyDetail{}, err } - params := lp.Body.ConstantProduct.Params - assetA, assetB = params.AssetA, params.AssetB - depositedA, depositedB = delta.ReserveA, delta.ReserveB - sharesReceived = delta.TotalPoolShares - } - - // Process ReserveA Details - if err := o.addAssetDetails(details, assetA, "reserve_a"); err != nil { - return details, err - } - details["reserve_a_max_amount"] = int64(op.MaxAmountA) - depositA, err := strconv.ParseFloat(amount.String(depositedA), 64) - if err != nil { - return details, err - } - details["reserve_a_deposit_amount"] = depositA - - //Process ReserveB Details - if err := o.addAssetDetails(details, assetB, "reserve_b"); err != nil { - return details, err - } - details["reserve_b_max_amount"] = int64(op.MaxAmountB) - depositB, err := strconv.ParseFloat(amount.String(depositedB), 64) - if err != nil { - return details, err - } - details["reserve_b_deposit_amount"] = depositB - - if err := o.addPriceDetails(details, op.MinPrice, "min"); err != nil { - return details, err - } - if err := o.addPriceDetails(details, op.MaxPrice, "max"); err != nil { - return details, err - } - - sharesToFloat, err := strconv.ParseFloat(amount.String(sharesReceived), 64) - if err != nil { - return details, err } - details["shares_received"] = sharesToFloat - return details, nil + return ledgerKeyDetail, nil } -// operation xdr.Operation, operationIndex int32, transaction LedgerTransaction, ledgerSeq int32 func (o *LedgerOperation) getLiquidityPoolAndProductDelta(lpID *xdr.PoolId) (*xdr.LiquidityPoolEntry, *LiquidityPoolDelta, error) { changes, err := o.Transaction.GetOperationChanges(uint32(o.OperationIndex)) if err != nil { @@ -985,218 +361,6 @@ func (o *LedgerOperation) getLiquidityPoolAndProductDelta(lpID *xdr.PoolId) (*xd return nil, nil, fmt.Errorf("liquidity pool change not found") } -func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetLiquidityPoolWithdrawOp() - if !ok { - return details, fmt.Errorf("could not access LiquidityPoolWithdraw info for this operation (index %d)", o.OperationIndex) - } - - details["liquidity_pool_id"] = o.PoolIDToString(op.LiquidityPoolId) - var ( - assetA, assetB xdr.Asset - receivedA, receivedB xdr.Int64 - ) - if o.Transaction.Successful() { - // we will use the defaults (omitted asset and 0 amounts) if the transaction failed - lp, delta, err := o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) - if err != nil { - return nil, err - } - params := lp.Body.ConstantProduct.Params - assetA, assetB = params.AssetA, params.AssetB - receivedA, receivedB = -delta.ReserveA, -delta.ReserveB - } - // Process AssetA Details - if err := o.addAssetDetails(details, assetA, "reserve_a"); err != nil { - return details, err - } - details["reserve_a_min_amount"] = int64(op.MinAmountA) - details["reserve_a_withdraw_amount"] = int64(receivedA) - - // Process AssetB Details - if err := o.addAssetDetails(details, assetB, "reserve_b"); err != nil { - return details, err - } - details["reserve_b_min_amount"] = int64(op.MinAmountB) - details["reserve_b_withdraw_amount"] = int64(receivedB) - - details["shares"] = int64(op.Amount) - - return details, nil -} - -func (o *LedgerOperation) InvokeHostFunctionDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetInvokeHostFunctionOp() - if !ok { - return details, fmt.Errorf("could not access InvokeHostFunction info for this operation (index %d)", o.OperationIndex) - } - - details["function"] = op.HostFunction.Type.String() - - switch op.HostFunction.Type { - case xdr.HostFunctionTypeHostFunctionTypeInvokeContract: - invokeArgs := op.HostFunction.MustInvokeContract() - args := make([]xdr.ScVal, 0, len(invokeArgs.Args)+2) - args = append(args, xdr.ScVal{Type: xdr.ScValTypeScvAddress, Address: &invokeArgs.ContractAddress}) - args = append(args, xdr.ScVal{Type: xdr.ScValTypeScvSymbol, Sym: &invokeArgs.FunctionName}) - args = append(args, invokeArgs.Args...) - - details["type"] = "invoke_contract" - - contractId, err := invokeArgs.ContractAddress.String() - if err != nil { - return nil, err - } - - details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() - details["contract_id"] = contractId - var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() - if ok { - details["contract_code_hash"] = contractCodeHash - } - - details["parameters"], details["parameters_decoded"] = o.serializeParameters(args) - - balanceChanges, err := o.parseAssetBalanceChangesFromContractEvents() - if err != nil { - return nil, err - } - - details["asset_balance_changes"] = balanceChanges - - case xdr.HostFunctionTypeHostFunctionTypeCreateContract: - args := op.HostFunction.MustCreateContract() - details["type"] = "create_contract" - - details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() - - var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() - if ok { - details["contract_id"] = contractID - } - - var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() - if ok { - details["contract_code_hash"] = contractCodeHash - } - - preimageTypeMap, err := o.switchContractIdPreimageType(args.ContractIdPreimage) - if err != nil { - return details, nil - } - - for key, val := range preimageTypeMap { - if _, ok := preimageTypeMap[key]; ok { - details[key] = val - } - } - case xdr.HostFunctionTypeHostFunctionTypeUploadContractWasm: - details["type"] = "upload_wasm" - details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() - - var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() - if ok { - details["contract_code_hash"] = contractCodeHash - } - case xdr.HostFunctionTypeHostFunctionTypeCreateContractV2: - args := op.HostFunction.MustCreateContractV2() - details["type"] = "create_contract_v2" - - details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() - - var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() - if ok { - details["contract_id"] = contractID - } - - var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() - if ok { - details["contract_code_hash"] = contractCodeHash - } - - // ConstructorArgs is a list of ScVals - // This will initially be handled the same as InvokeContractParams until a different - // model is found necessary. - constructorArgs := args.ConstructorArgs - details["parameters"], details["parameters_decoded"] = o.serializeParameters(constructorArgs) - - preimageTypeMap, err := o.switchContractIdPreimageType(args.ContractIdPreimage) - if err != nil { - return details, nil - } - - for key, val := range preimageTypeMap { - if _, ok := preimageTypeMap[key]; ok { - details[key] = val - } - } - default: - panic(fmt.Errorf("unknown host function type: %s", op.HostFunction.Type)) - } - - return details, nil -} - -func (o *LedgerOperation) ExtendFootprintTtlDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - op, ok := o.Operation.Body.GetExtendFootprintTtlOp() - if !ok { - return details, fmt.Errorf("could not access ExtendFootprintTtl info for this operation (index %d)", o.OperationIndex) - } - - details["type"] = "extend_footprint_ttl" - details["extend_to"] = int32(op.ExtendTo) - - details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() - - var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() - if ok { - details["contract_id"] = contractID - } - - var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() - if ok { - details["contract_code_hash"] = contractCodeHash - } - - return details, nil -} -func (o *LedgerOperation) RestoreFootprintDetails() (map[string]interface{}, error) { - details := map[string]interface{}{} - _, ok := o.Operation.Body.GetRestoreFootprintOp() - if !ok { - return details, fmt.Errorf("could not access RestoreFootprint info for this operation (index %d)", o.OperationIndex) - } - - details["type"] = "restore_footprint" - - details["ledger_key_hash"] = o.Transaction.LedgerKeyHashFromTxEnvelope() - - var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() - if ok { - details["contract_id"] = contractID - } - - var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() - if ok { - details["contract_code_hash"] = contractCodeHash - } - - return details, nil -} - func (o *LedgerOperation) serializeParameters(args []xdr.ScVal) ([]map[string]string, []map[string]string) { params := make([]map[string]string, 0, len(args)) paramsDecoded := make([]map[string]string, 0, len(args)) @@ -1225,8 +389,8 @@ func (o *LedgerOperation) serializeParameters(args []xdr.ScVal) ([]map[string]st return params, paramsDecoded } -func (o *LedgerOperation) parseAssetBalanceChangesFromContractEvents() ([]map[string]interface{}, error) { - balanceChanges := []map[string]interface{}{} +func (o *LedgerOperation) parseAssetBalanceChangesFromContractEvents() ([]BalanceChangeDetail, error) { + balanceChanges := []BalanceChangeDetail{} diagnosticEvents, err := o.Transaction.GetDiagnosticEvents() if err != nil { @@ -1238,21 +402,44 @@ func (o *LedgerOperation) parseAssetBalanceChangesFromContractEvents() ([]map[st for _, contractEvent := range o.filterEvents(diagnosticEvents) { // Parse the xdr contract event to contractevents.StellarAssetContractEvent model + var err error + var balanceChangeDetail BalanceChangeDetail + var sacEvent contractevents.StellarAssetContractEvent // has some convenience like to/from attributes are expressed in strkey format for accounts(G...) and contracts(C...) - if sacEvent, err := contractevents.NewStellarAssetContractEvent(&contractEvent, o.NetworkPassphrase); err == nil { + if sacEvent, err = contractevents.NewStellarAssetContractEvent(&contractEvent, o.NetworkPassphrase); err == nil { switch sacEvent.GetType() { case contractevents.EventTypeTransfer: transferEvt := sacEvent.(*contractevents.TransferEvent) - balanceChanges = append(balanceChanges, o.createSACBalanceChangeEntry(transferEvt.From, transferEvt.To, transferEvt.Amount, transferEvt.Asset, "transfer")) + balanceChangeDetail, err = createSACBalanceChangeEntry(transferEvt.From, transferEvt.To, transferEvt.Amount, transferEvt.Asset, "transfer") + if err != nil { + return []BalanceChangeDetail{}, err + } + + balanceChanges = append(balanceChanges, balanceChangeDetail) case contractevents.EventTypeMint: mintEvt := sacEvent.(*contractevents.MintEvent) - balanceChanges = append(balanceChanges, o.createSACBalanceChangeEntry("", mintEvt.To, mintEvt.Amount, mintEvt.Asset, "mint")) + balanceChangeDetail, err = createSACBalanceChangeEntry("", mintEvt.To, mintEvt.Amount, mintEvt.Asset, "mint") + if err != nil { + return []BalanceChangeDetail{}, err + } + + balanceChanges = append(balanceChanges, balanceChangeDetail) case contractevents.EventTypeClawback: clawbackEvt := sacEvent.(*contractevents.ClawbackEvent) - balanceChanges = append(balanceChanges, o.createSACBalanceChangeEntry(clawbackEvt.From, "", clawbackEvt.Amount, clawbackEvt.Asset, "clawback")) + balanceChangeDetail, err = createSACBalanceChangeEntry(clawbackEvt.From, "", clawbackEvt.Amount, clawbackEvt.Asset, "clawback") + if err != nil { + return []BalanceChangeDetail{}, err + } + + balanceChanges = append(balanceChanges, balanceChangeDetail) case contractevents.EventTypeBurn: burnEvt := sacEvent.(*contractevents.BurnEvent) - balanceChanges = append(balanceChanges, o.createSACBalanceChangeEntry(burnEvt.From, "", burnEvt.Amount, burnEvt.Asset, "burn")) + balanceChangeDetail, err = createSACBalanceChangeEntry(burnEvt.From, "", burnEvt.Amount, burnEvt.Asset, "burn") + if err != nil { + return []BalanceChangeDetail{}, err + } + + balanceChanges = append(balanceChanges, balanceChangeDetail) } } } @@ -1271,6 +458,16 @@ func (o *LedgerOperation) filterEvents(diagnosticEvents []xdr.DiagnosticEvent) [ return filtered } +type BalanceChangeDetail struct { + From string `json:"from"` + To string `json:"to"` + Type string `json:"type"` + Amount string `json:"amount"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` +} + // fromAccount - strkey format of contract or address // toAccount - strkey format of contract or address, or nillable // amountChanged - absolute value that asset balance changed @@ -1278,74 +475,62 @@ func (o *LedgerOperation) filterEvents(diagnosticEvents []xdr.DiagnosticEvent) [ // changeType - the type of source sac event that triggered this change // // return - a balance changed record expressed as map of key/value's -func (o *LedgerOperation) createSACBalanceChangeEntry(fromAccount string, toAccount string, amountChanged xdr.Int128Parts, asset xdr.Asset, changeType string) map[string]interface{} { - balanceChange := map[string]interface{}{} +func createSACBalanceChangeEntry(fromAccount string, toAccount string, amountChanged xdr.Int128Parts, asset xdr.Asset, changeType string) (BalanceChangeDetail, error) { + balanceChangeDetail := BalanceChangeDetail{ + Type: changeType, + Amount: amount.String128(amountChanged), + } if fromAccount != "" { - balanceChange["from"] = fromAccount + balanceChangeDetail.From = fromAccount } if toAccount != "" { - balanceChange["to"] = toAccount + balanceChangeDetail.To = toAccount } - balanceChange["type"] = changeType - balanceChange["amount"] = amount.String128(amountChanged) - o.addAssetDetails(balanceChange, asset, "") - return balanceChange -} - -// addAssetDetails sets the details for `a` on `result` using keys with `prefix` -func (o *LedgerOperation) addAssetDetails(result map[string]interface{}, a xdr.Asset, prefix string) error { - var ( - assetType string - code string - issuer string - ) - err := a.Extract(&assetType, &code, &issuer) + var assetCode, assetIssuer, assetType string + err := asset.Extract(&assetType, &assetCode, &assetIssuer) if err != nil { - err = fmt.Errorf("xdr.Asset.Extract error: %w", err) - return err + return BalanceChangeDetail{}, err } - prefix = o.FormatPrefix(prefix) - result[prefix+"asset_type"] = assetType - - if a.Type == xdr.AssetTypeAssetTypeNative { - result[prefix+"asset_id"] = int64(-5706705804583548011) - return nil - } - - result[prefix+"asset_code"] = code - result[prefix+"asset_issuer"] = issuer - result[prefix+"asset_id"] = o.FarmHashAsset(code, issuer, assetType) - - return nil + return balanceChangeDetail, nil } -func (o *LedgerOperation) switchContractIdPreimageType(contractIdPreimage xdr.ContractIdPreimage) (map[string]interface{}, error) { - details := map[string]interface{}{} +type PreImageDetails struct { + From string `json:"from"` + Address string `json:"address"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` +} +func switchContractIdPreimageType(contractIdPreimage xdr.ContractIdPreimage) (PreImageDetails, error) { switch contractIdPreimage.Type { case xdr.ContractIdPreimageTypeContractIdPreimageFromAddress: fromAddress := contractIdPreimage.MustFromAddress() address, err := fromAddress.Address.String() if err != nil { - return details, err + return PreImageDetails{}, err } - details["from"] = "address" - details["address"] = address + return PreImageDetails{ + From: "address", + Address: address, + }, nil case xdr.ContractIdPreimageTypeContractIdPreimageFromAsset: - details["from"] = "asset" - details["asset"] = contractIdPreimage.MustFromAsset().StringCanonical() - err := o.addAssetDetails(details, contractIdPreimage.MustFromAsset(), "") - if err != nil { - return details, err - } + var assetCode, assetIssuer, assetType string + contractIdPreimage.MustFromAsset().Extract(&assetType, &assetCode, &assetIssuer) + + return PreImageDetails{ + From: "asset", + AssetCode: assetCode, + AssetIssuer: assetIssuer, + AssetType: assetType, + }, nil + default: - panic(fmt.Errorf("unknown contract id type: %s", contractIdPreimage.Type)) + return PreImageDetails{}, fmt.Errorf("unknown contract id type: %s", contractIdPreimage.Type) } - - return details, nil } func (o *LedgerOperation) ConvertStroopValueToReal(input int64) float64 { @@ -1400,8 +585,8 @@ type Price struct { Denominator int32 `json:"d"` } -func (o *LedgerOperation) PoolIDToString(id xdr.PoolId) string { - return xdr.Hash(id).HexString() +func PoolIDToString(id xdr.PoolId) (string, error) { + return xdr.MarshalBase64(id) } type Claimant struct { @@ -1409,7 +594,7 @@ type Claimant struct { Predicate xdr.ClaimPredicate `json:"predicate"` } -func (o *LedgerOperation) TransformClaimants(claimants []xdr.Claimant) []Claimant { +func transformClaimants(claimants []xdr.Claimant) []Claimant { var transformed []Claimant for _, c := range claimants { switch c.Type { diff --git a/ingest/liquidity_pool_deposit_details.go b/ingest/liquidity_pool_deposit_details.go new file mode 100644 index 0000000000..92f4322a98 --- /dev/null +++ b/ingest/liquidity_pool_deposit_details.go @@ -0,0 +1,110 @@ +package ingest + +import ( + "fmt" + "strconv" + + "github.com/stellar/go/xdr" +) + +type LiquidityPoolDepositDetail struct { + LiquidityPoolID string `json:"liquidity_pool_id"` + ReserveAAssetCode string `json:"reserve_a_asset_code"` + ReserveAAssetIssuer string `json:"reserve_a_asset_issuer"` + ReserveAAssetType string `json:"reserve_a_asset_type"` + ReserveAMaxAmount int64 `json:"reserve_a_max_amount"` + ReserveADepositAmount int64 `json:"reserve_a_deposit_amount"` + ReserveBAssetCode string `json:"reserve_b_asset_code"` + ReserveBAssetIssuer string `json:"reserve_b_asset_issuer"` + ReserveBAssetType string `json:"reserve_b_asset_type"` + ReserveBMaxAmount int64 `json:"reserve_b_max_amount"` + ReserveBDepositAmount int64 `json:"reserve_b_deposit_amount"` + MinPriceN int32 `json:"min_price_n"` + MinPriceD int32 `json:"min_price_d"` + MinPrice float64 `json:"min_price"` + MaxPriceN int32 `json:"max_price_n"` + MaxPriceD int32 `json:"max_price_d"` + MaxPrice float64 `json:"max_price"` + SharesReceived int64 `json:"shares_received"` +} + +func (o *LedgerOperation) LiquidityPoolDepositDetails() (LiquidityPoolDepositDetail, error) { + op, ok := o.Operation.Body.GetLiquidityPoolDepositOp() + if !ok { + return LiquidityPoolDepositDetail{}, fmt.Errorf("could not access LiquidityPoolDeposit info for this operation (index %d)", o.OperationIndex) + } + + liquidityPoolDepositDetail := LiquidityPoolDepositDetail{ + ReserveAMaxAmount: int64(op.MaxAmountA), + ReserveBMaxAmount: int64(op.MaxAmountB), + MinPriceN: int32(op.MinPrice.N), + MinPriceD: int32(op.MinPrice.D), + MaxPriceN: int32(op.MaxPrice.N), + MaxPriceD: int32(op.MaxPrice.D), + } + + var err error + var liquidityPoolID string + liquidityPoolID, err = PoolIDToString(op.LiquidityPoolId) + if err != nil { + return LiquidityPoolDepositDetail{}, err + } + + liquidityPoolDepositDetail.LiquidityPoolID = liquidityPoolID + + var ( + assetA, assetB xdr.Asset + depositedA, depositedB xdr.Int64 + sharesReceived xdr.Int64 + ) + if o.Transaction.Successful() { + // we will use the defaults (omitted asset and 0 amounts) if the transaction failed + lp, delta, err := o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) + if err != nil { + return LiquidityPoolDepositDetail{}, err + } + + params := lp.Body.ConstantProduct.Params + assetA, assetB = params.AssetA, params.AssetB + depositedA, depositedB = delta.ReserveA, delta.ReserveB + sharesReceived = delta.TotalPoolShares + } + + // Process ReserveA Details + var assetACode, assetAIssuer, assetAType string + err = assetA.Extract(&assetAType, &assetACode, &assetAIssuer) + if err != nil { + return LiquidityPoolDepositDetail{}, err + } + + liquidityPoolDepositDetail.ReserveAAssetCode = assetACode + liquidityPoolDepositDetail.ReserveAAssetIssuer = assetAIssuer + liquidityPoolDepositDetail.ReserveAAssetType = assetAType + liquidityPoolDepositDetail.ReserveADepositAmount = int64(depositedA) + + //Process ReserveB Details + var assetBCode, assetBIssuer, assetBType string + err = assetB.Extract(&assetBType, &assetBCode, &assetBIssuer) + if err != nil { + return LiquidityPoolDepositDetail{}, err + } + + liquidityPoolDepositDetail.ReserveBAssetCode = assetBCode + liquidityPoolDepositDetail.ReserveBAssetIssuer = assetBIssuer + liquidityPoolDepositDetail.ReserveBAssetType = assetBType + liquidityPoolDepositDetail.ReserveBDepositAmount = int64(depositedB) + + liquidityPoolDepositDetail.MinPrice, err = strconv.ParseFloat(op.MinPrice.String(), 64) + if err != nil { + return LiquidityPoolDepositDetail{}, err + } + + liquidityPoolDepositDetail.MaxPrice, err = strconv.ParseFloat(op.MaxPrice.String(), 64) + if err != nil { + return LiquidityPoolDepositDetail{}, err + } + + liquidityPoolDepositDetail.SharesReceived = int64(sharesReceived) + + return liquidityPoolDepositDetail, nil +} diff --git a/ingest/liquidity_pool_withdraw_details.go b/ingest/liquidity_pool_withdraw_details.go new file mode 100644 index 0000000000..c250494e3d --- /dev/null +++ b/ingest/liquidity_pool_withdraw_details.go @@ -0,0 +1,85 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type LiquidityPoolWithdrawDetail struct { + LiquidityPoolID string `json:"liquidity_pool_id"` + ReserveAAssetCode string `json:"reserve_a_asset_code"` + ReserveAAssetIssuer string `json:"reserve_a_asset_issuer"` + ReserveAAssetType string `json:"reserve_a_asset_type"` + ReserveAMinAmount int64 `json:"reserve_a_min_amount"` + ReserveAWithdrawAmount int64 `json:"reserve_a_withdraw_amount"` + ReserveBAssetCode string `json:"reserve_b_asset_code"` + ReserveBAssetIssuer string `json:"reserve_b_asset_issuer"` + ReserveBAssetType string `json:"reserve_b_asset_type"` + ReserveBMinAmount int64 `json:"reserve_b_min_amount"` + ReserveBWithdrawAmount int64 `json:"reserve_b_withdraw_amount"` + Shares int64 `json:"shares"` +} + +func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawDetail, error) { + op, ok := o.Operation.Body.GetLiquidityPoolWithdrawOp() + if !ok { + return LiquidityPoolWithdrawDetail{}, fmt.Errorf("could not access LiquidityPoolWithdraw info for this operation (index %d)", o.OperationIndex) + } + + liquidityPoolWithdrawDetail := LiquidityPoolWithdrawDetail{ + ReserveAMinAmount: int64(op.MinAmountA), + ReserveBMinAmount: int64(op.MinAmountB), + Shares: int64(op.Amount), + } + + var err error + var liquidityPoolID string + liquidityPoolID, err = PoolIDToString(op.LiquidityPoolId) + if err != nil { + return LiquidityPoolWithdrawDetail{}, err + } + + liquidityPoolWithdrawDetail.LiquidityPoolID = liquidityPoolID + + var ( + assetA, assetB xdr.Asset + receivedA, receivedB xdr.Int64 + ) + if o.Transaction.Successful() { + // we will use the defaults (omitted asset and 0 amounts) if the transaction failed + lp, delta, err := o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) + if err != nil { + return LiquidityPoolWithdrawDetail{}, err + } + params := lp.Body.ConstantProduct.Params + assetA, assetB = params.AssetA, params.AssetB + receivedA, receivedB = -delta.ReserveA, -delta.ReserveB + } + + // Process AssetA Details + var assetACode, assetAIssuer, assetAType string + err = assetA.Extract(&assetAType, &assetACode, &assetAIssuer) + if err != nil { + return LiquidityPoolWithdrawDetail{}, err + } + + liquidityPoolWithdrawDetail.ReserveAAssetCode = assetACode + liquidityPoolWithdrawDetail.ReserveAAssetIssuer = assetAIssuer + liquidityPoolWithdrawDetail.ReserveAAssetType = assetAType + liquidityPoolWithdrawDetail.ReserveAWithdrawAmount = int64(receivedA) + + // Process AssetB Details + var assetBCode, assetBIssuer, assetBType string + err = assetB.Extract(&assetBType, &assetBCode, &assetBIssuer) + if err != nil { + return LiquidityPoolWithdrawDetail{}, err + } + + liquidityPoolWithdrawDetail.ReserveBAssetCode = assetBCode + liquidityPoolWithdrawDetail.ReserveBAssetIssuer = assetBIssuer + liquidityPoolWithdrawDetail.ReserveBAssetType = assetBType + liquidityPoolWithdrawDetail.ReserveAWithdrawAmount = int64(receivedB) + + return liquidityPoolWithdrawDetail, nil +} diff --git a/ingest/manage_buy_offer_details.go b/ingest/manage_buy_offer_details.go new file mode 100644 index 0000000000..21c9ac35ab --- /dev/null +++ b/ingest/manage_buy_offer_details.go @@ -0,0 +1,62 @@ +package ingest + +import ( + "fmt" + "strconv" +) + +type ManageBuyOffer struct { + OfferID int64 `json:"offer_id"` + Amount int64 `json:"amount"` + PriceN int32 `json:"price_n"` + PriceD int32 `json:"price_d"` + Price float64 `json:"price"` + BuyingAssetCode string `json:"buying_asset_code"` + BuyingAssetIssuer string `json:"buying_asset_issuer"` + BuyingAssetType string `json:"buying_asset_type"` + SellingAssetCode string `json:"selling_asset_code"` + SellingAssetIssuer string `json:"selling_asset_issuer"` + SellingAssetType string `json:"selling_asset_type"` +} + +func (o *LedgerOperation) ManageBuyOfferDetails() (ManageBuyOffer, error) { + op, ok := o.Operation.Body.GetManageBuyOfferOp() + if !ok { + return ManageBuyOffer{}, fmt.Errorf("could not access ManageBuyOffer info for this operation (index %d)", o.OperationIndex) + } + + manageBuyOffer := ManageBuyOffer{ + OfferID: int64(op.OfferId), + Amount: int64(op.BuyAmount), + PriceN: int32(op.Price.N), + PriceD: int32(op.Price.D), + } + + var err error + manageBuyOffer.Price, err = strconv.ParseFloat(op.Price.String(), 64) + if err != nil { + return ManageBuyOffer{}, err + } + + var buyingAssetCode, buyingAssetIssuer, buyingAssetType string + err = op.Buying.Extract(&buyingAssetType, &buyingAssetCode, &buyingAssetIssuer) + if err != nil { + return ManageBuyOffer{}, err + } + + manageBuyOffer.BuyingAssetCode = buyingAssetCode + manageBuyOffer.BuyingAssetIssuer = buyingAssetIssuer + manageBuyOffer.BuyingAssetType = buyingAssetType + + var sellingAssetCode, sellingAssetIssuer, sellingAssetType string + err = op.Selling.Extract(&sellingAssetType, &sellingAssetCode, &sellingAssetIssuer) + if err != nil { + return ManageBuyOffer{}, err + } + + manageBuyOffer.SellingAssetCode = sellingAssetCode + manageBuyOffer.SellingAssetIssuer = sellingAssetIssuer + manageBuyOffer.SellingAssetType = sellingAssetType + + return manageBuyOffer, nil +} diff --git a/ingest/manage_data_details.go b/ingest/manage_data_details.go new file mode 100644 index 0000000000..abf523fd6a --- /dev/null +++ b/ingest/manage_data_details.go @@ -0,0 +1,28 @@ +package ingest + +import ( + "encoding/base64" + "fmt" +) + +type ManageDataDetail struct { + Name string `json:"name"` + Value string `json:value"` +} + +func (o *LedgerOperation) ManageDataDetails() (ManageDataDetail, error) { + op, ok := o.Operation.Body.GetManageDataOp() + if !ok { + return ManageDataDetail{}, fmt.Errorf("could not access GetManageData info for this operation (index %d)", o.OperationIndex) + } + + manageDataDetail := ManageDataDetail{ + Name: string(op.DataName), + } + + if op.DataValue != nil { + manageDataDetail.Value = base64.StdEncoding.EncodeToString(*op.DataValue) + } + + return manageDataDetail, nil +} diff --git a/ingest/manage_sell_offer_details.go b/ingest/manage_sell_offer_details.go new file mode 100644 index 0000000000..9b33fd4b03 --- /dev/null +++ b/ingest/manage_sell_offer_details.go @@ -0,0 +1,63 @@ +package ingest + +import ( + "fmt" + "strconv" +) + +type ManageSellOffer struct { + OfferID int64 `json:"offer_id"` + Amount int64 `json:"amount"` + PriceN int32 `json:"price_n"` + PriceD int32 `json:"price_d"` + Price float64 `json:"price"` + BuyingAssetCode string `json:"buying_asset_code"` + BuyingAssetIssuer string `json:"buying_asset_issuer"` + BuyingAssetType string `json:"buying_asset_type"` + SellingAssetCode string `json:"selling_asset_code"` + SellingAssetIssuer string `json:"selling_asset_issuer"` + SellingAssetType string `json:"selling_asset_type"` +} + +func (o *LedgerOperation) ManageSellOfferDetails() (ManageSellOffer, error) { + op, ok := o.Operation.Body.GetManageSellOfferOp() + if !ok { + return ManageSellOffer{}, fmt.Errorf("could not access ManageSellOffer info for this operation (index %d)", o.OperationIndex) + } + + manageSellOffer := ManageSellOffer{ + OfferID: int64(op.OfferId), + Amount: int64(op.Amount), + PriceN: int32(op.Price.N), + PriceD: int32(op.Price.D), + } + + var err error + manageSellOffer.Price, err = strconv.ParseFloat(op.Price.String(), 64) + if err != nil { + return ManageSellOffer{}, err + } + + var buyingAssetCode, buyingAssetIssuer, buyingAssetType string + err = op.Buying.Extract(&buyingAssetType, &buyingAssetCode, &buyingAssetIssuer) + if err != nil { + return ManageSellOffer{}, err + } + + manageSellOffer.BuyingAssetCode = buyingAssetCode + manageSellOffer.BuyingAssetIssuer = buyingAssetIssuer + manageSellOffer.BuyingAssetType = buyingAssetType + + var sellingAssetCode, sellingAssetIssuer, sellingAssetType string + err = op.Selling.Extract(&sellingAssetType, &sellingAssetCode, &sellingAssetIssuer) + if err != nil { + return ManageSellOffer{}, err + } + + manageSellOffer.SellingAssetCode = sellingAssetCode + manageSellOffer.SellingAssetIssuer = sellingAssetIssuer + manageSellOffer.SellingAssetType = sellingAssetType + + return manageSellOffer, nil + +} diff --git a/ingest/path_payment_strict_receive_details.go b/ingest/path_payment_strict_receive_details.go new file mode 100644 index 0000000000..3a9eab83d4 --- /dev/null +++ b/ingest/path_payment_strict_receive_details.go @@ -0,0 +1,100 @@ +package ingest + +import ( + "fmt" +) + +type PathPaymentStrictReceiveDetail struct { + From string `json:"from"` + FromMuxed string `json:"from_muxed"` + FromMuxedID uint64 `json:"from_muxed_id"` + To string `json:"to"` + ToMuxed string `json:"to_muxed"` + ToMuxedID uint64 `json:"to_muxed_id"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + Amount int64 `json:"amount"` + SourceAssetCode string `json:"source_asset_code"` + SourceAssetIssuer string `json:"source_asset_issuer"` + SourceAssetType string `json:"source_asset_type"` + SourceAmount int64 `json:"source_amount"` + SourceMax int64 `json:"source_max"` + Path []Path `json:"path"` +} + +func (o *LedgerOperation) PathPaymentStrictReceiveDetails() (PathPaymentStrictReceiveDetail, error) { + op, ok := o.Operation.Body.GetPathPaymentStrictReceiveOp() + if !ok { + return PathPaymentStrictReceiveDetail{}, fmt.Errorf("could not access PathPaymentStrictReceive info for this operation (index %d)", o.OperationIndex) + } + + pathPaymentStrictReceiveDetail := PathPaymentStrictReceiveDetail{ + From: o.SourceAccount(), + To: op.Destination.Address(), + Amount: int64(op.DestAmount), + SourceMax: int64(op.SendMax), + } + + var err error + var fromMuxed string + var fromMuxedID uint64 + fromMuxed, fromMuxedID, err = getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return PathPaymentStrictReceiveDetail{}, err + } + + pathPaymentStrictReceiveDetail.FromMuxed = fromMuxed + pathPaymentStrictReceiveDetail.FromMuxedID = fromMuxedID + + var toMuxed string + var toMuxedID uint64 + toMuxed, toMuxedID, err = getMuxedAccountDetails(op.Destination) + if err != nil { + return PathPaymentStrictReceiveDetail{}, err + } + + pathPaymentStrictReceiveDetail.ToMuxed = toMuxed + pathPaymentStrictReceiveDetail.ToMuxedID = toMuxedID + + var assetCode, assetIssuer, assetType string + err = op.DestAsset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return PathPaymentStrictReceiveDetail{}, err + } + + pathPaymentStrictReceiveDetail.AssetCode = assetCode + pathPaymentStrictReceiveDetail.AssetIssuer = assetIssuer + pathPaymentStrictReceiveDetail.AssetType = assetType + + var sourceAssetCode, sourceAssetIssuer, sourceAssetType string + err = op.SendAsset.Extract(&sourceAssetType, &sourceAssetCode, &sourceAssetIssuer) + if err != nil { + return PathPaymentStrictReceiveDetail{}, err + } + + pathPaymentStrictReceiveDetail.SourceAssetCode = sourceAssetCode + pathPaymentStrictReceiveDetail.SourceAssetIssuer = sourceAssetIssuer + pathPaymentStrictReceiveDetail.SourceAssetType = sourceAssetType + + if o.Transaction.Successful() { + allOperationResults, ok := o.Transaction.Result.OperationResults() + if !ok { + return PathPaymentStrictReceiveDetail{}, fmt.Errorf("could not access any results for this transaction") + } + currentOperationResult := allOperationResults[o.OperationIndex] + resultBody, ok := currentOperationResult.GetTr() + if !ok { + return PathPaymentStrictReceiveDetail{}, fmt.Errorf("could not access result body for this operation (index %d)", o.OperationIndex) + } + result, ok := resultBody.GetPathPaymentStrictReceiveResult() + if !ok { + return PathPaymentStrictReceiveDetail{}, fmt.Errorf("could not access PathPaymentStrictReceive result info for this operation (index %d)", o.OperationIndex) + } + pathPaymentStrictReceiveDetail.SourceAmount = int64(result.SendAmount()) + } + + pathPaymentStrictReceiveDetail.Path = o.TransformPath(op.Path) + + return pathPaymentStrictReceiveDetail, nil +} diff --git a/ingest/path_payment_strict_send_details.go b/ingest/path_payment_strict_send_details.go new file mode 100644 index 0000000000..6b0c28e69f --- /dev/null +++ b/ingest/path_payment_strict_send_details.go @@ -0,0 +1,100 @@ +package ingest + +import ( + "fmt" +) + +type PathPaymentStrictSendDetail struct { + From string `json:"from"` + FromMuxed string `json:"from_muxed"` + FromMuxedID uint64 `json:"from_muxed_id"` + To string `json:"to"` + ToMuxed string `json:"to_muxed"` + ToMuxedID uint64 `json:"to_muxed_id"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + Amount int64 `json:"amount"` + SourceAssetCode string `json:"source_asset_code"` + SourceAssetIssuer string `json:"source_asset_issuer"` + SourceAssetType string `json:"source_asset_type"` + SourceAmount int64 `json:"source_amount"` + DestinationMin int64 `json:"destination_min"` + Path []Path `json:"path"` +} + +func (o *LedgerOperation) PathPaymentStrictSendDetails() (PathPaymentStrictSendDetail, error) { + op, ok := o.Operation.Body.GetPathPaymentStrictSendOp() + if !ok { + return PathPaymentStrictSendDetail{}, fmt.Errorf("could not access PathPaymentStrictSend info for this operation (index %d)", o.OperationIndex) + } + + pathPaymentStrictSendDetail := PathPaymentStrictSendDetail{ + From: o.SourceAccount(), + To: op.Destination.Address(), + SourceAmount: int64(op.SendAmount), + DestinationMin: int64(op.DestMin), + } + + var err error + var fromMuxed string + var fromMuxedID uint64 + fromMuxed, fromMuxedID, err = getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return PathPaymentStrictSendDetail{}, err + } + + pathPaymentStrictSendDetail.FromMuxed = fromMuxed + pathPaymentStrictSendDetail.FromMuxedID = fromMuxedID + + var toMuxed string + var toMuxedID uint64 + toMuxed, toMuxedID, err = getMuxedAccountDetails(op.Destination) + if err != nil { + return PathPaymentStrictSendDetail{}, err + } + + pathPaymentStrictSendDetail.ToMuxed = toMuxed + pathPaymentStrictSendDetail.ToMuxedID = toMuxedID + + var assetCode, assetIssuer, assetType string + err = op.DestAsset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return PathPaymentStrictSendDetail{}, err + } + + pathPaymentStrictSendDetail.AssetCode = assetCode + pathPaymentStrictSendDetail.AssetIssuer = assetIssuer + pathPaymentStrictSendDetail.AssetType = assetType + + var sourceAssetCode, sourceAssetIssuer, sourceAssetType string + err = op.SendAsset.Extract(&sourceAssetType, &sourceAssetCode, &sourceAssetIssuer) + if err != nil { + return PathPaymentStrictSendDetail{}, err + } + + pathPaymentStrictSendDetail.SourceAssetCode = sourceAssetCode + pathPaymentStrictSendDetail.SourceAssetIssuer = sourceAssetIssuer + pathPaymentStrictSendDetail.SourceAssetType = sourceAssetType + + if o.Transaction.Successful() { + allOperationResults, ok := o.Transaction.Result.OperationResults() + if !ok { + return PathPaymentStrictSendDetail{}, fmt.Errorf("could not access any results for this transaction") + } + currentOperationResult := allOperationResults[o.OperationIndex] + resultBody, ok := currentOperationResult.GetTr() + if !ok { + return PathPaymentStrictSendDetail{}, fmt.Errorf("could not access result body for this operation (index %d)", o.OperationIndex) + } + result, ok := resultBody.GetPathPaymentStrictSendResult() + if !ok { + return PathPaymentStrictSendDetail{}, fmt.Errorf("could not access GetPathPaymentStrictSendResult result info for this operation (index %d)", o.OperationIndex) + } + pathPaymentStrictSendDetail.Amount = int64(result.DestAmount()) + } + + pathPaymentStrictSendDetail.Path = o.TransformPath(op.Path) + + return pathPaymentStrictSendDetail, nil +} diff --git a/ingest/payment_details.go b/ingest/payment_details.go new file mode 100644 index 0000000000..c7845ed503 --- /dev/null +++ b/ingest/payment_details.go @@ -0,0 +1,60 @@ +package ingest + +import ( + "fmt" +) + +type PaymentDetail struct { + From string `json:"from"` + FromMuxed string `json:"from_muxed"` + FromMuxedID uint64 `json:"from_muxed_id"` + To string `json:"to"` + ToMuxed string `json:"to_muxed"` + ToMuxedID uint64 `json:"to_muxed_id"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + Amount int64 `json:"amount"` +} + +func (o *LedgerOperation) PaymentDetails() (PaymentDetail, error) { + op, ok := o.Operation.Body.GetPaymentOp() + if !ok { + return PaymentDetail{}, fmt.Errorf("could not access Payment info for this operation (index %d)", o.OperationIndex) + } + + paymentDetail := PaymentDetail{ + From: o.SourceAccount(), + To: op.Destination.Address(), + Amount: int64(op.Amount), + } + + var err error + var fromMuxed string + var fromMuxedID uint64 + fromMuxed, fromMuxedID, err = getMuxedAccountDetails(o.sourceAccountXDR()) + if err != nil { + return PaymentDetail{}, err + } + + paymentDetail.FromMuxed = fromMuxed + paymentDetail.FromMuxedID = fromMuxedID + + var toMuxed string + var toMuxedID uint64 + toMuxed, toMuxedID, err = getMuxedAccountDetails(op.Destination) + if err != nil { + return PaymentDetail{}, err + } + + paymentDetail.ToMuxed = toMuxed + paymentDetail.ToMuxedID = toMuxedID + + var assetCode, assetIssuer, assetType string + err = op.Asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return PaymentDetail{}, err + } + + return paymentDetail, nil +} diff --git a/ingest/restore_footprint_details.go b/ingest/restore_footprint_details.go new file mode 100644 index 0000000000..496308ffad --- /dev/null +++ b/ingest/restore_footprint_details.go @@ -0,0 +1,36 @@ +package ingest + +import "fmt" + +type RestoreFootprintDetail struct { + Type string `json:"type"` + LedgerKeyHash []string `json:"ledger_key_hash"` + ContractID string `json:"contract_id"` + ContractCodeHash string `json:"contract_code_hash"` +} + +func (o *LedgerOperation) RestoreFootprintDetails() (RestoreFootprintDetail, error) { + _, ok := o.Operation.Body.GetRestoreFootprintOp() + if !ok { + return RestoreFootprintDetail{}, fmt.Errorf("could not access RestoreFootprint info for this operation (index %d)", o.OperationIndex) + } + + restoreFootprintDetail := RestoreFootprintDetail{ + Type: "restore_footprint", + LedgerKeyHash: o.Transaction.LedgerKeyHashFromTxEnvelope(), + } + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + restoreFootprintDetail.ContractID = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + restoreFootprintDetail.ContractCodeHash = contractCodeHash + } + + return restoreFootprintDetail, nil +} diff --git a/ingest/revoke_sponsorship_details.go b/ingest/revoke_sponsorship_details.go new file mode 100644 index 0000000000..9ca5a1aefb --- /dev/null +++ b/ingest/revoke_sponsorship_details.go @@ -0,0 +1,37 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type RevokeSponsorshipDetail struct { + SignerAccountID string `json:"signer_account_id"` + SignerKey string `json:"signer_key"` + LedgerKeyDetails LedgerKeyDetail `json:"ledger_key_detail` +} + +func (o *LedgerOperation) RevokeSponsorshipDetails() (RevokeSponsorshipDetail, error) { + op, ok := o.Operation.Body.GetRevokeSponsorshipOp() + if !ok { + return RevokeSponsorshipDetail{}, fmt.Errorf("could not access RevokeSponsorship info for this operation (index %d)", o.OperationIndex) + } + + var revokeSponsorshipDetail RevokeSponsorshipDetail + + switch op.Type { + case xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry: + ledgerKeyDetail, err := addLedgerKeyToDetails(*op.LedgerKey) + if err != nil { + return RevokeSponsorshipDetail{}, err + } + + revokeSponsorshipDetail.LedgerKeyDetails = ledgerKeyDetail + case xdr.RevokeSponsorshipTypeRevokeSponsorshipSigner: + revokeSponsorshipDetail.SignerAccountID = op.Signer.AccountId.Address() + revokeSponsorshipDetail.SignerKey = op.Signer.SignerKey.Address() + } + + return revokeSponsorshipDetail, nil +} diff --git a/ingest/set_options_details.go b/ingest/set_options_details.go new file mode 100644 index 0000000000..2216e4b9b0 --- /dev/null +++ b/ingest/set_options_details.go @@ -0,0 +1,97 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type SetOptionsDetails struct { + InflationDestination string `json:"inflation_destination"` + MasterKeyWeight uint32 `json:"master_key_weight"` + LowThreshold uint32 `json:"low_threshold"` + MediumThreshold uint32 `json:"medium_threshold"` + HighThreshold uint32 `json:"high_threshold"` + HomeDomain string `json:"home_domain"` + SignerKey string `json:"signer_key"` + SignerWeight uint32 `json:"signer_weight"` + SetFlags []int32 `json:"set_flags"` + SetFlagsString []string `json:"set_flags_string"` + ClearFlags []int32 `json:"clear_flags"` + ClearFlagsString []string `json:"clear_flags_string"` +} + +func (o *LedgerOperation) SetOptionsDetails() (SetOptionsDetails, error) { + op, ok := o.Operation.Body.GetSetOptionsOp() + if !ok { + return SetOptionsDetails{}, fmt.Errorf("could not access GetSetOptions info for this operation (index %d)", o.OperationIndex) + } + + var setOptionsDetail SetOptionsDetails + + if op.InflationDest != nil { + setOptionsDetail.InflationDestination = op.InflationDest.Address() + } + + if op.SetFlags != nil && *op.SetFlags > 0 { + setOptionsDetail.SetFlags, setOptionsDetail.SetFlagsString = addOperationFlagToOperationDetails(uint32(*op.SetFlags)) + } + + if op.ClearFlags != nil && *op.ClearFlags > 0 { + setOptionsDetail.ClearFlags, setOptionsDetail.ClearFlagsString = addOperationFlagToOperationDetails(uint32(*op.ClearFlags)) + } + + if op.MasterWeight != nil { + setOptionsDetail.MasterKeyWeight = uint32(*op.MasterWeight) + } + + if op.LowThreshold != nil { + setOptionsDetail.LowThreshold = uint32(*op.LowThreshold) + } + + if op.MedThreshold != nil { + setOptionsDetail.MediumThreshold = uint32(*op.MedThreshold) + } + + if op.HighThreshold != nil { + setOptionsDetail.HighThreshold = uint32(*op.HighThreshold) + } + + if op.HomeDomain != nil { + setOptionsDetail.HomeDomain = string(*op.HomeDomain) + } + + if op.Signer != nil { + setOptionsDetail.SignerKey = op.Signer.Key.Address() + setOptionsDetail.SignerWeight = uint32(op.Signer.Weight) + } + + return setOptionsDetail, nil +} + +func addOperationFlagToOperationDetails(flag uint32) ([]int32, []string) { + intFlags := make([]int32, 0) + stringFlags := make([]string, 0) + + if (int64(flag) & int64(xdr.AccountFlagsAuthRequiredFlag)) > 0 { + intFlags = append(intFlags, int32(xdr.AccountFlagsAuthRequiredFlag)) + stringFlags = append(stringFlags, "auth_required") + } + + if (int64(flag) & int64(xdr.AccountFlagsAuthRevocableFlag)) > 0 { + intFlags = append(intFlags, int32(xdr.AccountFlagsAuthRevocableFlag)) + stringFlags = append(stringFlags, "auth_revocable") + } + + if (int64(flag) & int64(xdr.AccountFlagsAuthImmutableFlag)) > 0 { + intFlags = append(intFlags, int32(xdr.AccountFlagsAuthImmutableFlag)) + stringFlags = append(stringFlags, "auth_immutable") + } + + if (int64(flag) & int64(xdr.AccountFlagsAuthClawbackEnabledFlag)) > 0 { + intFlags = append(intFlags, int32(xdr.AccountFlagsAuthClawbackEnabledFlag)) + stringFlags = append(stringFlags, "auth_clawback_enabled") + } + + return intFlags, stringFlags +} diff --git a/ingest/set_trustline_flags_details.go b/ingest/set_trustline_flags_details.go new file mode 100644 index 0000000000..6a71c4c22a --- /dev/null +++ b/ingest/set_trustline_flags_details.go @@ -0,0 +1,73 @@ +package ingest + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type SetTrustlineFlagsDetail struct { + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + Trustor string `json:"trustor"` + SetFlags []int32 `json:"set_flags"` + SetFlagsString []string `json:"set_flags_string"` + ClearFlags []int32 `json:"clear_flags"` + ClearFlagsString []string `json:"clear_flags_string"` +} + +func (o *LedgerOperation) SetTrustlineFlagsDetails() (SetTrustlineFlagsDetail, error) { + op, ok := o.Operation.Body.GetSetTrustLineFlagsOp() + if !ok { + return SetTrustlineFlagsDetail{}, fmt.Errorf("could not access SetTrustLineFlags info for this operation (index %d)", o.OperationIndex) + } + + setTrustLineFlagsDetail := SetTrustlineFlagsDetail{ + Trustor: op.Trustor.Address(), + } + + var err error + var assetCode, assetIssuer, assetType string + err = op.Asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return SetTrustlineFlagsDetail{}, err + } + + setTrustLineFlagsDetail.AssetCode = assetCode + setTrustLineFlagsDetail.AssetIssuer = assetIssuer + setTrustLineFlagsDetail.AssetType = assetType + + if op.SetFlags > 0 { + setTrustLineFlagsDetail.SetFlags, setTrustLineFlagsDetail.SetFlagsString = getTrustLineFlagToDetails(xdr.TrustLineFlags(op.SetFlags)) + } + if op.ClearFlags > 0 { + setTrustLineFlagsDetail.ClearFlags, setTrustLineFlagsDetail.ClearFlagsString = getTrustLineFlagToDetails(xdr.TrustLineFlags(op.ClearFlags)) + } + + return setTrustLineFlagsDetail, nil +} + +func getTrustLineFlagToDetails(f xdr.TrustLineFlags) ([]int32, []string) { + var ( + n []int32 + s []string + ) + + if f.IsAuthorized() { + n = append(n, int32(xdr.TrustLineFlagsAuthorizedFlag)) + s = append(s, "authorized") + } + + if f.IsAuthorizedToMaintainLiabilitiesFlag() { + n = append(n, int32(xdr.TrustLineFlagsAuthorizedToMaintainLiabilitiesFlag)) + s = append(s, "authorized_to_maintain_liabilities") + } + + if f.IsClawbackEnabledFlag() { + n = append(n, int32(xdr.TrustLineFlagsTrustlineClawbackEnabledFlag)) + s = append(s, "clawback_enabled") + } + + return n, s +} From b7c0737e0b1af37f0cf5694609837c76eb362207 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Mon, 3 Feb 2025 17:55:32 -0500 Subject: [PATCH 31/40] Update marshalbase64 --- ingest/ledger_transaction.go | 6 +++--- xdr/hash.go | 12 ------------ 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index d32b403743..bbfa86da22 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -632,7 +632,7 @@ func (t *LedgerTransaction) LedgerKeyHashFromTxEnvelope() []string { } for _, ledgerKey := range v1Envelope.Tx.Ext.SorobanData.Resources.Footprint.ReadOnly { - ledgerKeyBase64, err := ledgerKey.MarshalBinaryBase64() + ledgerKeyBase64, err := xdr.MarshalBase64(ledgerKey) if err != nil { panic(err) } @@ -642,7 +642,7 @@ func (t *LedgerTransaction) LedgerKeyHashFromTxEnvelope() []string { } for _, ledgerKey := range v1Envelope.Tx.Ext.SorobanData.Resources.Footprint.ReadWrite { - ledgerKeyBase64, err := ledgerKey.MarshalBinaryBase64() + ledgerKeyBase64, err := xdr.MarshalBase64(ledgerKey) if err != nil { panic(err) } @@ -688,7 +688,7 @@ func (t *LedgerTransaction) contractCodeFromContractData(ledgerKey xdr.LedgerKey return "", false } - codeHash, err := contractCode.Hash.MarshalBinaryBase64() + codeHash, err := xdr.MarshalBase64(contractCode.Hash) if err != nil { panic(err) } diff --git a/xdr/hash.go b/xdr/hash.go index c0107163b6..084520d082 100644 --- a/xdr/hash.go +++ b/xdr/hash.go @@ -1,7 +1,6 @@ package xdr import ( - "encoding/base64" "encoding/hex" ) @@ -20,14 +19,3 @@ func (s Hash) Equals(o Hash) bool { } return true } - -// MarshalBinaryBase64 marshals XDR into a binary form and then encodes it -// using base64. -func (h Hash) MarshalBinaryBase64() (string, error) { - b, err := h.MarshalBinary() - if err != nil { - return "", err - } - - return base64.StdEncoding.EncodeToString(b), nil -} From a3846f2c97a1851f98b66fd8f141baf4ed487896 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Mon, 3 Feb 2025 18:33:05 -0500 Subject: [PATCH 32/40] Fix typos --- ingest/manage_data_details.go | 2 +- ingest/revoke_sponsorship_details.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ingest/manage_data_details.go b/ingest/manage_data_details.go index abf523fd6a..ce52817130 100644 --- a/ingest/manage_data_details.go +++ b/ingest/manage_data_details.go @@ -7,7 +7,7 @@ import ( type ManageDataDetail struct { Name string `json:"name"` - Value string `json:value"` + Value string `json:"value"` } func (o *LedgerOperation) ManageDataDetails() (ManageDataDetail, error) { diff --git a/ingest/revoke_sponsorship_details.go b/ingest/revoke_sponsorship_details.go index 9ca5a1aefb..654d5f128e 100644 --- a/ingest/revoke_sponsorship_details.go +++ b/ingest/revoke_sponsorship_details.go @@ -9,7 +9,7 @@ import ( type RevokeSponsorshipDetail struct { SignerAccountID string `json:"signer_account_id"` SignerKey string `json:"signer_key"` - LedgerKeyDetails LedgerKeyDetail `json:"ledger_key_detail` + LedgerKeyDetails LedgerKeyDetail `json:"ledger_key_detail"` } func (o *LedgerOperation) RevokeSponsorshipDetails() (RevokeSponsorshipDetail, error) { From fc6b854ce66fe08c04a75b59158ac0ce7003a8c6 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Mon, 3 Feb 2025 18:49:55 -0500 Subject: [PATCH 33/40] fix ci/cd --- ingest/ledger_operation.go | 3 ++- ingest/liquidity_pool_deposit_details.go | 4 +++- ingest/liquidity_pool_withdraw_details.go | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ingest/ledger_operation.go b/ingest/ledger_operation.go index 77b831448d..3b6d4e49f1 100644 --- a/ingest/ledger_operation.go +++ b/ingest/ledger_operation.go @@ -69,13 +69,14 @@ func (o *LedgerOperation) OperationTraceCode() (string, error) { var operationTraceCode string var operationResults []xdr.OperationResult var ok bool + var err error operationResults, ok = o.Transaction.Result.Result.OperationResults() if ok { var operationResultTr xdr.OperationResultTr operationResultTr, ok = operationResults[o.OperationIndex].GetTr() if ok { - operationTraceCode, err := operationResultTr.MapOperationResultTr() + operationTraceCode, err = operationResultTr.MapOperationResultTr() if err != nil { return "", err } diff --git a/ingest/liquidity_pool_deposit_details.go b/ingest/liquidity_pool_deposit_details.go index 92f4322a98..39e65288c5 100644 --- a/ingest/liquidity_pool_deposit_details.go +++ b/ingest/liquidity_pool_deposit_details.go @@ -56,10 +56,12 @@ func (o *LedgerOperation) LiquidityPoolDepositDetails() (LiquidityPoolDepositDet assetA, assetB xdr.Asset depositedA, depositedB xdr.Int64 sharesReceived xdr.Int64 + lp *xdr.LiquidityPoolEntry + delta *LiquidityPoolDelta ) if o.Transaction.Successful() { // we will use the defaults (omitted asset and 0 amounts) if the transaction failed - lp, delta, err := o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) + lp, delta, err = o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) if err != nil { return LiquidityPoolDepositDetail{}, err } diff --git a/ingest/liquidity_pool_withdraw_details.go b/ingest/liquidity_pool_withdraw_details.go index c250494e3d..9c4de93b3b 100644 --- a/ingest/liquidity_pool_withdraw_details.go +++ b/ingest/liquidity_pool_withdraw_details.go @@ -45,10 +45,12 @@ func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawD var ( assetA, assetB xdr.Asset receivedA, receivedB xdr.Int64 + lp *xdr.LiquidityPoolEntry + delta *LiquidityPoolDelta ) if o.Transaction.Successful() { // we will use the defaults (omitted asset and 0 amounts) if the transaction failed - lp, delta, err := o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) + lp, delta, err = o.getLiquidityPoolAndProductDelta(&op.LiquidityPoolId) if err != nil { return LiquidityPoolWithdrawDetail{}, err } From 875c995d4cedd78b0607beacc6d1e25fb4e0a469 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Mon, 3 Feb 2025 20:30:24 -0500 Subject: [PATCH 34/40] fix tests --- ingest/allow_trust_details.go | 2 +- ingest/bump_sequence_details.go | 4 +- ingest/clawback_details.go | 1 + ingest/ledger_operation_test.go | 538 +++++++++++----------- ingest/liquidity_pool_withdraw_details.go | 2 +- ingest/payment_details.go | 4 + 6 files changed, 269 insertions(+), 282 deletions(-) diff --git a/ingest/allow_trust_details.go b/ingest/allow_trust_details.go index df06278738..f2cbed5cb8 100644 --- a/ingest/allow_trust_details.go +++ b/ingest/allow_trust_details.go @@ -28,7 +28,7 @@ func (o *LedgerOperation) AllowTrustDetails() (AllowTrustDetail, error) { allowTrustDetail := AllowTrustDetail{ Trustor: op.Trustor.Address(), Trustee: o.SourceAccount(), - Authorize: xdr.TrustLineFlags(op.Authorize).IsAuthorizedToMaintainLiabilitiesFlag(), + Authorize: xdr.TrustLineFlags(op.Authorize).IsAuthorized(), AuthorizeToMaintainLiabilities: xdr.TrustLineFlags(op.Authorize).IsAuthorizedToMaintainLiabilitiesFlag(), ClawbackEnabled: xdr.TrustLineFlags(op.Authorize).IsClawbackEnabledFlag(), } diff --git a/ingest/bump_sequence_details.go b/ingest/bump_sequence_details.go index c3e3d2e86e..b2e16a895c 100644 --- a/ingest/bump_sequence_details.go +++ b/ingest/bump_sequence_details.go @@ -3,7 +3,7 @@ package ingest import "fmt" type BumpSequenceDetails struct { - BumpTo string `json:"bump_to"` + BumpTo int64 `json:"bump_to"` } func (o *LedgerOperation) BumpSequenceDetails() (BumpSequenceDetails, error) { @@ -13,6 +13,6 @@ func (o *LedgerOperation) BumpSequenceDetails() (BumpSequenceDetails, error) { } return BumpSequenceDetails{ - BumpTo: fmt.Sprintf("%d", op.BumpTo), + BumpTo: int64(op.BumpTo), }, nil } diff --git a/ingest/clawback_details.go b/ingest/clawback_details.go index f9dc0f6fd4..f91dda8487 100644 --- a/ingest/clawback_details.go +++ b/ingest/clawback_details.go @@ -20,6 +20,7 @@ func (o *LedgerOperation) ClawbackDetails() (ClawbackDetail, error) { clawbackDetail := ClawbackDetail{ Amount: int64(op.Amount), + From: op.From.Address(), } var err error diff --git a/ingest/ledger_operation_test.go b/ingest/ledger_operation_test.go index d7127104dc..f70a8534c7 100644 --- a/ingest/ledger_operation_test.go +++ b/ingest/ledger_operation_test.go @@ -488,7 +488,7 @@ func transactionTestInput() *LedgerTransaction { type testOutput struct { err error - result map[string]interface{} + result interface{} } func operationTestInput() []xdr.Operation { @@ -1086,218 +1086,194 @@ func resultTestOutput() []testOutput { output := []testOutput{ { err: nil, - result: map[string]interface{}{ - "account": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "funder": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "funder_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - "funder_muxed_id": uint64(123), - "starting_balance": int64(25000000)}, + result: CreateAccountDetail{ + Account: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + Funder: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + FunderMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + FunderMuxedID: uint64(123), + StartingBalance: int64(25000000)}, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(350000000), - "asset_code": "USDT", - "asset_id": int64(-8205667356306085451), - "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_type": "credit_alphanum4", - "from": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "from_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - "from_muxed_id": uint64(123), - "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + result: PaymentDetail{ + Amount: int64(350000000), + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + FromMuxedID: uint64(123), + To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(350000000), - "asset_id": int64(-5706705804583548011), - "asset_type": "native", - "from": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "from_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - "from_muxed_id": uint64(123), - "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + result: PaymentDetail{ + Amount: int64(350000000), + AssetType: "native", + From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + FromMuxedID: uint64(123), + To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(8951495900), - "asset_id": int64(-5706705804583548011), - "asset_type": "native", - "from": "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", - "path": []Path{ + result: PathPaymentStrictReceiveDetail{ + Amount: int64(8951495900), + AssetType: "native", + From: "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", + Path: []Path{ { AssetCode: "USDT", AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", AssetType: "credit_alphanum4", }, }, - "source_amount": int64(0), - "source_asset_id": int64(-5706705804583548011), - "source_asset_type": "native", - "source_max": int64(8951495900), - "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + SourceAmount: int64(0), + SourceAssetType: "native", + SourceMax: int64(8951495900), + To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(765860000), - "buying_asset_id": int64(-5706705804583548011), - "buying_asset_type": "native", - "offer_id": int64(0), - "price": 0.514092, - "price_r": Price{ - Numerator: 128523, - Denominator: 250000, - }, - "selling_asset_code": "USDT", - "selling_asset_id": int64(-8205667356306085451), - "selling_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "selling_asset_type": "credit_alphanum4"}, + result: ManageSellOffer{ + Amount: int64(765860000), + BuyingAssetType: "native", + OfferID: int64(0), + Price: 0.514092, + PriceN: 128523, + PriceD: 250000, + SellingAssetCode: "USDT", + SellingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + SellingAssetType: "credit_alphanum4"}, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(631595000), - "buying_asset_code": "USDT", - "buying_asset_id": int64(-8205667356306085451), - "buying_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "buying_asset_type": "credit_alphanum4", - "price": 0.0791606, - "price_r": Price{ - Numerator: 99583200, - Denominator: 1257990000, - }, - "selling_asset_id": int64(-5706705804583548011), - "selling_asset_type": "native"}, + result: CreatePassiveSellOfferDetail{ + Amount: int64(631595000), + BuyingAssetCode: "USDT", + BuyingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + BuyingAssetType: "credit_alphanum4", + Price: 0.0791606, + PriceN: 99583200, + PriceD: 1257990000, + SellingAssetType: "native"}, }, { err: nil, - result: map[string]interface{}{ - "clear_flags": []int32{1, - 2}, - "clear_flags_s": []string{"auth_required", - "auth_revocable"}, - "high_threshold": uint32(5), - "home_domain": "2019=DRA;n-test", - "inflation_dest": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "low_threshold": uint32(1), - "master_key_weight": uint32(3), - "med_threshold": uint32(3), - "set_flags": []int32{4}, - "set_flags_s": []string{"auth_immutable"}, - "signer_key": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", - "signer_weight": uint32(1)}, + result: SetOptionsDetails{ + ClearFlags: []int32{1, 2}, + ClearFlagsString: []string{"auth_required", "auth_revocable"}, + HighThreshold: uint32(5), + HomeDomain: "2019=DRA;n-test", + InflationDestination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + LowThreshold: uint32(1), + MasterKeyWeight: uint32(3), + MediumThreshold: uint32(3), + SetFlags: []int32{4}, + SetFlagsString: []string{"auth_immutable"}, + SignerKey: "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + SignerWeight: uint32(1)}, }, { err: nil, - result: map[string]interface{}{ - "asset_code": "USSD", - "asset_id": int64(6690054458235693884), - "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_type": "credit_alphanum4", - "limit": int64(500000000000000000), - "trustee": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "trustor": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "trustor_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - "trustor_muxed_id": uint64(123)}, + result: ChangeTrustDetail{ + AssetCode: "USSD", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + Limit: int64(500000000000000000), + Trustee: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + Trustor: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + TrustorMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + TrustorMuxedID: uint64(123)}, }, { err: nil, - result: map[string]interface{}{ - "asset_type": "liquidity_pool_shares", - "limit": int64(500000000000000000), - "liquidity_pool_id": "1c261d6c75930204a73b480c3020ab525e9be48ce93de6194cf69fb06f07452d", - "trustor": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "trustor_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - "trustor_muxed_id": uint64(123)}, + result: ChangeTrustDetail{ + AssetType: "liquidity_pool_shares", + Limit: int64(500000000000000000), + LiquidityPoolID: "HCYdbHWTAgSnO0gMMCCrUl6b5IzpPeYZTPafsG8HRS0=", + Trustor: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + TrustorMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + TrustorMuxedID: uint64(123)}, }, { err: nil, - result: map[string]interface{}{ - "asset_code": "USDT", - "asset_id": int64(8181787832768848499), - "asset_issuer": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "asset_type": "credit_alphanum4", - "authorize": true, - "trustee": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "trustee_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - "trustee_muxed_id": uint64(123), - "trustor": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + result: AllowTrustDetail{ + AssetCode: "USDT", + AssetIssuer: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + AssetType: "credit_alphanum4", + Authorize: true, + Trustee: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + TrusteeMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + TrusteeMuxedID: uint64(123), + Trustor: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, }, { err: nil, - result: map[string]interface{}{ - "account": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "account_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - "account_muxed_id": uint64(123), - "into": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + result: AccountMergeDetail{ + Account: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + AccountMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + AccountMuxedID: uint64(123), + Into: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, }, { err: nil, - result: map[string]interface{}{}, + result: InflationDetail{}, }, { err: nil, - result: map[string]interface{}{ - "name": "test", - "value": "dmFsdWU=", + result: ManageDataDetail{ + Name: "test", + Value: "dmFsdWU=", }, }, { err: nil, - result: map[string]interface{}{ - "bump_to": "100", + result: BumpSequenceDetails{ + BumpTo: int64(100), }, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(7654501001), - "buying_asset_id": int64(-5706705804583548011), - "buying_asset_type": "native", - "offer_id": int64(100), - "price": 0.3496823, - "price_r": Price{ - Numerator: 635863285, - Denominator: 1818402817, - }, - "selling_asset_code": "USDT", - "selling_asset_id": int64(-8205667356306085451), - "selling_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "selling_asset_type": "credit_alphanum4"}, + result: ManageBuyOffer{ + Amount: int64(7654501001), + BuyingAssetType: "native", + OfferID: int64(100), + Price: 0.3496823, + PriceN: 635863285, + PriceD: 1818402817, + SellingAssetCode: "USDT", + SellingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + SellingAssetType: "credit_alphanum4"}, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(640000000), - "asset_id": int64(-5706705804583548011), - "asset_type": "native", - "destination_min": "428.0460538", - "from": "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - "from_muxed": "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - "from_muxed_id": uint64(123), - "path": []Path{ + result: PathPaymentStrictSendDetail{ + Amount: int64(640000000), + AssetType: "native", + DestinationMin: 4280460538, + From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + FromMuxedID: uint64(123), + Path: []Path{ { AssetCode: "USDT", AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", AssetType: "credit_alphanum4", }, }, - "source_amount": int64(1598182), - "source_asset_id": int64(-5706705804583548011), - "source_asset_type": "native", - "to": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + SourceAmount: int64(1598182), + SourceAssetType: "native", + To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(1234567890000), - "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_code": "USDT", - "asset_id": int64(-8205667356306085451), - "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_type": "credit_alphanum4", - "claimants": []Claimant{ + result: CreateClaimableBalanceDetail{ + Amount: int64(1234567890000), + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + Claimants: []Claimant{ { Destination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", Predicate: xdr.ClaimPredicate{ @@ -1314,143 +1290,153 @@ func resultTestOutput() []testOutput { }, { err: nil, - result: map[string]interface{}{ - "balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000", - "claimant": "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", + result: ClaimClaimableBalanceDetail{ + BalanceID: "AAAAAAECAwQFBgcICQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + Claimant: "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", }, }, { err: nil, - result: map[string]interface{}{ - "sponsored_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + result: BeginSponsoringFutureReservesDetail{ + SponsoredID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", }, }, { err: nil, - result: map[string]interface{}{ - "signer_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "signer_key": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + result: RevokeSponsorshipDetail{ + SignerAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + SignerKey: "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", }, }, { err: nil, - result: map[string]interface{}{ - "account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + AccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, }, }, { err: nil, - result: map[string]interface{}{ - "claimable_balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000", + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + ClaimableBalanceID: "000000000102030405060708090000000000000000000000000000000000000000000000", + }, }, }, { err: nil, - result: map[string]interface{}{ - "data_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "data_name": "test", + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + DataAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + DataName: "test", + }, }, }, { err: nil, - result: map[string]interface{}{ - "offer_id": int64(100), + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + OfferID: int64(100), + }, }, }, { err: nil, - result: map[string]interface{}{ - "trustline_account_id": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "trustline_asset": "USTT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + TrustlineAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + TrustlineAssetCode: "USTT", + TrustlineAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + TrustlineAssetType: "credit_alphanum4", + }, }, }, { err: nil, - result: map[string]interface{}{ - "liquidity_pool_id": "0102030405060708090000000000000000000000000000000000000000000000", + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + }, }, }, { err: nil, - result: map[string]interface{}{ - "amount": int64(1598182), - "asset_code": "USDT", - "asset_id": int64(-8205667356306085451), - "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_type": "credit_alphanum4", - "from": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + result: ClawbackDetail{ + Amount: int64(1598182), + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + From: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", }, }, { err: nil, - result: map[string]interface{}{ - "balance_id": "000000000102030405060708090000000000000000000000000000000000000000000000", + result: ClawbackClaimableBalanceDetail{ + BalanceID: "AAAAAAECAwQFBgcICQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", }, }, { err: nil, - result: map[string]interface{}{ - "asset_code": "USDT", - "asset_id": int64(-8205667356306085451), - "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_type": "credit_alphanum4", - "clear_flags": []int32{1, 2}, - "clear_flags_s": []string{"authorized", "authorized_to_maintain_liabilities"}, - "set_flags": []int32{4}, - "set_flags_s": []string{"clawback_enabled"}, - "trustor": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + result: SetTrustlineFlagsDetail{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + ClearFlags: []int32{1, 2}, + ClearFlagsString: []string{"authorized", "authorized_to_maintain_liabilities"}, + SetFlags: []int32{4}, + SetFlagsString: []string{"clawback_enabled"}, + Trustor: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", }, }, { err: nil, - result: map[string]interface{}{ - "liquidity_pool_id": "0102030405060708090000000000000000000000000000000000000000000000", - "max_price": 1e+06, - "max_price_r": Price{Numerator: 1000000, Denominator: 1}, - "min_price": 1e-06, - "min_price_r": Price{Numerator: 1, Denominator: 1000000}, - "reserve_a_asset_code": "USDT", - "reserve_a_asset_id": int64(-8205667356306085451), - "reserve_a_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "reserve_a_asset_type": "credit_alphanum4", - "reserve_a_deposit_amount": 1e-07, - "reserve_a_max_amount": int64(1000), - "reserve_b_asset_code": "USDT", - "reserve_b_asset_id": int64(-8205667356306085451), - "reserve_b_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "reserve_b_asset_type": "credit_alphanum4", - "reserve_b_deposit_amount": 1e-07, - "reserve_b_max_amount": int64(100), - "shares_received": 1e-07, + result: LiquidityPoolDepositDetail{ + LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + MaxPrice: 1e+06, + MaxPriceN: 1000000, + MaxPriceD: 1, + MinPrice: 1e-06, + MinPriceN: 1, + MinPriceD: 1000000, + ReserveAAssetCode: "USDT", + ReserveAAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + ReserveAAssetType: "credit_alphanum4", + ReserveADepositAmount: int64(1), + ReserveAMaxAmount: int64(1000), + ReserveBAssetCode: "USDT", + ReserveBAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + ReserveBAssetType: "credit_alphanum4", + ReserveBDepositAmount: 1, + ReserveBMaxAmount: int64(100), + SharesReceived: 1, }, }, { err: nil, - result: map[string]interface{}{ - "liquidity_pool_id": "0102030405060708090000000000000000000000000000000000000000000000", - "reserve_a_asset_code": "USDT", - "reserve_a_asset_id": int64(-8205667356306085451), - "reserve_a_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "reserve_a_asset_type": "credit_alphanum4", - "reserve_a_min_amount": int64(1), - "reserve_a_withdraw_amount": int64(-1), - "reserve_b_asset_code": "USDT", - "reserve_b_asset_id": int64(-8205667356306085451), - "reserve_b_asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "reserve_b_asset_type": "credit_alphanum4", - "reserve_b_min_amount": int64(1), - "reserve_b_withdraw_amount": int64(-1), - "shares": int64(4), + result: LiquidityPoolWithdrawDetail{ + LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + ReserveAAssetCode: "USDT", + ReserveAAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + ReserveAAssetType: "credit_alphanum4", + ReserveAMinAmount: int64(1), + ReserveAWithdrawAmount: int64(-1), + ReserveBAssetCode: "USDT", + ReserveBAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + ReserveBAssetType: "credit_alphanum4", + ReserveBMinAmount: int64(1), + ReserveBWithdrawAmount: int64(-1), + Shares: int64(4), }, }, { err: nil, - result: map[string]interface{}{ - "asset_balance_changes": []map[string]interface{}{}, - "contract_id": "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", - "function": "HostFunctionTypeHostFunctionTypeInvokeContract", - "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - "parameters": []map[string]string{ + result: InvokeHostFunctionDetail{ + AssetBalanceChanges: []BalanceChangeDetail{}, + ContractID: "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", + Function: "HostFunctionTypeHostFunctionTypeInvokeContract", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Parameters: []map[string]string{ { "type": "Address", "value": "AAAAEgAAAAESNFZ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", @@ -1460,7 +1446,7 @@ func resultTestOutput() []testOutput { "value": "AAAADwAAAAR0ZXN0", }, }, - "parameters_decoded": []map[string]string{ + ParametersDecoded: []map[string]string{ { "type": "Address", "value": "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", @@ -1470,85 +1456,81 @@ func resultTestOutput() []testOutput { "value": "test", }, }, - "type": "invoke_contract", + Type: "invoke_contract", }, }, { err: nil, - result: map[string]interface{}{ - "address": "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", - "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - "from": "address", - "function": "HostFunctionTypeHostFunctionTypeCreateContract", - "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - "type": "create_contract", + result: InvokeHostFunctionDetail{ + Address: "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + From: "address", + Function: "HostFunctionTypeHostFunctionTypeCreateContract", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Type: "create_contract", }, }, { err: nil, - result: map[string]interface{}{ - "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_code": "USDT", - "asset_id": int64(-8205667356306085451), - "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_type": "credit_alphanum4", - "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - "from": "asset", - "function": "HostFunctionTypeHostFunctionTypeCreateContract", - "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - "type": "create_contract", + result: InvokeHostFunctionDetail{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + From: "asset", + Function: "HostFunctionTypeHostFunctionTypeCreateContract", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Type: "create_contract", }, }, { err: nil, - result: map[string]interface{}{ - "asset": "USDT:GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_code": "USDT", - "asset_id": int64(-8205667356306085451), - "asset_issuer": "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - "asset_type": "credit_alphanum4", - "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - "from": "asset", - "function": "HostFunctionTypeHostFunctionTypeCreateContractV2", - "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - "parameters": []map[string]string{ + result: InvokeHostFunctionDetail{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + From: "asset", + Function: "HostFunctionTypeHostFunctionTypeCreateContractV2", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Parameters: []map[string]string{ { "type": "B", "value": "AAAAAAAAAAE=", }, }, - "parameters_decoded": []map[string]string{ + ParametersDecoded: []map[string]string{ { "type": "B", "value": "true", }, }, - "type": "create_contract_v2", + Type: "create_contract_v2", }, }, { err: nil, - result: map[string]interface{}{ - "function": "HostFunctionTypeHostFunctionTypeUploadContractWasm", - "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - "type": "upload_wasm", + result: InvokeHostFunctionDetail{ + Function: "HostFunctionTypeHostFunctionTypeUploadContractWasm", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Type: "upload_wasm", }, }, { err: nil, - result: map[string]interface{}{ - "extend_to": int32(1234), - "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - "type": "extend_footprint_ttl", + result: ExtendFootprintTtlDetail{ + ExtendTo: uint32(1234), + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + Type: "extend_footprint_ttl", }, }, { err: nil, - result: map[string]interface{}{ - "ledger_key_hash": []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - "contract_id": "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - "type": "restore_footprint", + result: RestoreFootprintDetail{ + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + Type: "restore_footprint", }, }, } diff --git a/ingest/liquidity_pool_withdraw_details.go b/ingest/liquidity_pool_withdraw_details.go index 9c4de93b3b..a8e5249d57 100644 --- a/ingest/liquidity_pool_withdraw_details.go +++ b/ingest/liquidity_pool_withdraw_details.go @@ -81,7 +81,7 @@ func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawD liquidityPoolWithdrawDetail.ReserveBAssetCode = assetBCode liquidityPoolWithdrawDetail.ReserveBAssetIssuer = assetBIssuer liquidityPoolWithdrawDetail.ReserveBAssetType = assetBType - liquidityPoolWithdrawDetail.ReserveAWithdrawAmount = int64(receivedB) + liquidityPoolWithdrawDetail.ReserveBWithdrawAmount = int64(receivedB) return liquidityPoolWithdrawDetail, nil } diff --git a/ingest/payment_details.go b/ingest/payment_details.go index c7845ed503..0266ec9f58 100644 --- a/ingest/payment_details.go +++ b/ingest/payment_details.go @@ -56,5 +56,9 @@ func (o *LedgerOperation) PaymentDetails() (PaymentDetail, error) { return PaymentDetail{}, err } + paymentDetail.AssetCode = assetCode + paymentDetail.AssetIssuer = assetIssuer + paymentDetail.AssetType = assetType + return paymentDetail, nil } From 5c68c65ea0178d17f12438c2660a746ca8cdc220 Mon Sep 17 00:00:00 2001 From: chowbao Date: Tue, 4 Feb 2025 11:18:42 -0500 Subject: [PATCH 35/40] Update hash.go --- xdr/hash.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xdr/hash.go b/xdr/hash.go index 084520d082..2a15c18c9c 100644 --- a/xdr/hash.go +++ b/xdr/hash.go @@ -1,8 +1,6 @@ package xdr -import ( - "encoding/hex" -) +import "encoding/hex" func (h Hash) HexString() string { return hex.EncodeToString(h[:]) From cc6d49df2de93fbffceb5557a714a3166d38de82 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 6 Feb 2025 10:58:38 -0500 Subject: [PATCH 36/40] add string for js --- ingest/account_merge_details.go | 2 +- ingest/allow_trust_details.go | 2 +- ingest/bump_sequence_details.go | 2 +- ingest/change_trust_details.go | 4 ++-- ingest/claim_claimable_balance_details.go | 2 +- ingest/clawback_details.go | 4 ++-- ingest/create_account_details.go | 4 ++-- ingest/create_claimable_balance_details.go | 2 +- ingest/create_passive_sell_offer_details.go | 2 +- ingest/end_sponsoring_future_reserve_details.go | 2 +- ingest/ledger_operation.go | 2 +- ingest/liquidity_pool_deposit_details.go | 10 +++++----- ingest/liquidity_pool_withdraw_details.go | 10 +++++----- ingest/manage_buy_offer_details.go | 4 ++-- ingest/manage_sell_offer_details.go | 4 ++-- ingest/path_payment_strict_receive_details.go | 10 +++++----- ingest/path_payment_strict_send_details.go | 10 +++++----- ingest/payment_details.go | 6 +++--- 18 files changed, 41 insertions(+), 41 deletions(-) diff --git a/ingest/account_merge_details.go b/ingest/account_merge_details.go index fc70291188..b439a49ac5 100644 --- a/ingest/account_merge_details.go +++ b/ingest/account_merge_details.go @@ -5,7 +5,7 @@ import "fmt" type AccountMergeDetail struct { Account string `json:"account"` AccountMuxed string `json:"account_muxed"` - AccountMuxedID uint64 `json:"account_muxed_id"` + AccountMuxedID uint64 `json:"account_muxed_id,string"` Into string `json:"into"` IntoMuxed string `json:"into_muxed"` IntoMuxedID uint64 `json:"into_muxed_id"` diff --git a/ingest/allow_trust_details.go b/ingest/allow_trust_details.go index f2cbed5cb8..3c3785c88b 100644 --- a/ingest/allow_trust_details.go +++ b/ingest/allow_trust_details.go @@ -13,7 +13,7 @@ type AllowTrustDetail struct { Trustor string `json:"trustor"` Trustee string `json:"trustee"` TrusteeMuxed string `json:"trustee_muxed"` - TrusteeMuxedID uint64 `json:"trustee_muxed_id"` + TrusteeMuxedID uint64 `json:"trustee_muxed_id,string"` Authorize bool `json:"authorize"` AuthorizeToMaintainLiabilities bool `json:"authorize_to_maintain_liabilities"` ClawbackEnabled bool `json:"clawback_enabled"` diff --git a/ingest/bump_sequence_details.go b/ingest/bump_sequence_details.go index b2e16a895c..abeb2a4e52 100644 --- a/ingest/bump_sequence_details.go +++ b/ingest/bump_sequence_details.go @@ -3,7 +3,7 @@ package ingest import "fmt" type BumpSequenceDetails struct { - BumpTo int64 `json:"bump_to"` + BumpTo int64 `json:"bump_to,string"` } func (o *LedgerOperation) BumpSequenceDetails() (BumpSequenceDetails, error) { diff --git a/ingest/change_trust_details.go b/ingest/change_trust_details.go index a3302146f7..ca3040bd2d 100644 --- a/ingest/change_trust_details.go +++ b/ingest/change_trust_details.go @@ -11,11 +11,11 @@ type ChangeTrustDetail struct { AssetIssuer string `json:"asset_issuer"` AssetType string `json:"asset_type"` LiquidityPoolID string `json:"liquidity_pool_id"` - Limit int64 `json:"limit"` + Limit int64 `json:"limit,string"` Trustee string `json:"trustee"` Trustor string `json:"trustor"` TrustorMuxed string `json:"trustor_muxed"` - TrustorMuxedID uint64 `json:"trustor_muxed_id"` + TrustorMuxedID uint64 `json:"trustor_muxed_id,string"` } func (o *LedgerOperation) ChangeTrustDetails() (ChangeTrustDetail, error) { diff --git a/ingest/claim_claimable_balance_details.go b/ingest/claim_claimable_balance_details.go index 2125d31e6b..69d85950ad 100644 --- a/ingest/claim_claimable_balance_details.go +++ b/ingest/claim_claimable_balance_details.go @@ -10,7 +10,7 @@ type ClaimClaimableBalanceDetail struct { BalanceID string `json:"balance_id"` Claimant string `json:"claimant"` ClaimantMuxed string `json:"claimant_muxed"` - ClaimantMuxedID uint64 `json:"claimant_muxed_id"` + ClaimantMuxedID uint64 `json:"claimant_muxed_id,string"` } func (o *LedgerOperation) ClaimClaimableBalanceDetails() (ClaimClaimableBalanceDetail, error) { diff --git a/ingest/clawback_details.go b/ingest/clawback_details.go index f91dda8487..ff84f41705 100644 --- a/ingest/clawback_details.go +++ b/ingest/clawback_details.go @@ -8,8 +8,8 @@ type ClawbackDetail struct { AssetType string `json:"asset_type"` From string `json:"from"` FromMuxed string `json:"from_muxed"` - FromMuxedID uint64 `json:"from_muxed_id"` - Amount int64 `json:"amount"` + FromMuxedID uint64 `json:"from_muxed_id,string"` + Amount int64 `json:"amount,string"` } func (o *LedgerOperation) ClawbackDetails() (ClawbackDetail, error) { diff --git a/ingest/create_account_details.go b/ingest/create_account_details.go index 9a04de1be6..9eed63cc2d 100644 --- a/ingest/create_account_details.go +++ b/ingest/create_account_details.go @@ -6,10 +6,10 @@ import ( type CreateAccountDetail struct { Account string `json:"account"` - StartingBalance int64 `json:"starting_balance"` + StartingBalance int64 `json:"starting_balance,string"` Funder string `json:"funder"` FunderMuxed string `json:"funder_muxed"` - FunderMuxedID uint64 `json:"funder_muxed_id"` + FunderMuxedID uint64 `json:"funder_muxed_id,string"` } func (o *LedgerOperation) CreateAccountDetails() (CreateAccountDetail, error) { diff --git a/ingest/create_claimable_balance_details.go b/ingest/create_claimable_balance_details.go index 795ed5edf0..0aefcf1ffb 100644 --- a/ingest/create_claimable_balance_details.go +++ b/ingest/create_claimable_balance_details.go @@ -8,7 +8,7 @@ type CreateClaimableBalanceDetail struct { AssetCode string `json:"asset_code"` AssetIssuer string `json:"asset_issuer"` AssetType string `json:"asset_type"` - Amount int64 `json:"amount"` + Amount int64 `json:"amount,string"` Claimants []Claimant `json:"claimants"` } diff --git a/ingest/create_passive_sell_offer_details.go b/ingest/create_passive_sell_offer_details.go index 1532cb7d07..2ee8791b8c 100644 --- a/ingest/create_passive_sell_offer_details.go +++ b/ingest/create_passive_sell_offer_details.go @@ -6,7 +6,7 @@ import ( ) type CreatePassiveSellOfferDetail struct { - Amount int64 `json:"amount"` + Amount int64 `json:"amount,string"` PriceN int32 `json:"price_n"` PriceD int32 `json:"price_d"` Price float64 `json:"price"` diff --git a/ingest/end_sponsoring_future_reserve_details.go b/ingest/end_sponsoring_future_reserve_details.go index 5a9b58df9e..c2d6f609e3 100644 --- a/ingest/end_sponsoring_future_reserve_details.go +++ b/ingest/end_sponsoring_future_reserve_details.go @@ -3,7 +3,7 @@ package ingest type EndSponsoringFutureReserveDetail struct { BeginSponsor string `json:"begin_sponsor"` BeginSponsorMuxed string `json:"begin_sponsor_muxed"` - BeginSponsorMuxedID uint64 `json:"begin_sponsor_muxed_id"` + BeginSponsorMuxedID uint64 `json:"begin_sponsor_muxed_id,string"` } func (o *LedgerOperation) EndSponsoringFutureReserveDetails() (EndSponsoringFutureReserveDetail, error) { diff --git a/ingest/ledger_operation.go b/ingest/ledger_operation.go index 3b6d4e49f1..62f39c8271 100644 --- a/ingest/ledger_operation.go +++ b/ingest/ledger_operation.go @@ -257,7 +257,7 @@ type LedgerKeyDetail struct { ClaimableBalanceID string `json:"claimable_balance_id"` DataAccountID string `json:"data_account_id"` DataName string `json:"data_name"` - OfferID int64 `json:"offer_id"` + OfferID int64 `json:"offer_id,string"` TrustlineAccountID string `json:"trustline_account_id"` TrustlineLiquidityPoolID string `json:"trustline_liquidity_pool_id"` TrustlineAssetCode string `json:"trustline_asset_code"` diff --git a/ingest/liquidity_pool_deposit_details.go b/ingest/liquidity_pool_deposit_details.go index 39e65288c5..8d7dce32d6 100644 --- a/ingest/liquidity_pool_deposit_details.go +++ b/ingest/liquidity_pool_deposit_details.go @@ -12,20 +12,20 @@ type LiquidityPoolDepositDetail struct { ReserveAAssetCode string `json:"reserve_a_asset_code"` ReserveAAssetIssuer string `json:"reserve_a_asset_issuer"` ReserveAAssetType string `json:"reserve_a_asset_type"` - ReserveAMaxAmount int64 `json:"reserve_a_max_amount"` - ReserveADepositAmount int64 `json:"reserve_a_deposit_amount"` + ReserveAMaxAmount int64 `json:"reserve_a_max_amount,string"` + ReserveADepositAmount int64 `json:"reserve_a_deposit_amount,string"` ReserveBAssetCode string `json:"reserve_b_asset_code"` ReserveBAssetIssuer string `json:"reserve_b_asset_issuer"` ReserveBAssetType string `json:"reserve_b_asset_type"` - ReserveBMaxAmount int64 `json:"reserve_b_max_amount"` - ReserveBDepositAmount int64 `json:"reserve_b_deposit_amount"` + ReserveBMaxAmount int64 `json:"reserve_b_max_amount,string"` + ReserveBDepositAmount int64 `json:"reserve_b_deposit_amount,string"` MinPriceN int32 `json:"min_price_n"` MinPriceD int32 `json:"min_price_d"` MinPrice float64 `json:"min_price"` MaxPriceN int32 `json:"max_price_n"` MaxPriceD int32 `json:"max_price_d"` MaxPrice float64 `json:"max_price"` - SharesReceived int64 `json:"shares_received"` + SharesReceived int64 `json:"shares_received,string"` } func (o *LedgerOperation) LiquidityPoolDepositDetails() (LiquidityPoolDepositDetail, error) { diff --git a/ingest/liquidity_pool_withdraw_details.go b/ingest/liquidity_pool_withdraw_details.go index a8e5249d57..94d4a93ac7 100644 --- a/ingest/liquidity_pool_withdraw_details.go +++ b/ingest/liquidity_pool_withdraw_details.go @@ -11,14 +11,14 @@ type LiquidityPoolWithdrawDetail struct { ReserveAAssetCode string `json:"reserve_a_asset_code"` ReserveAAssetIssuer string `json:"reserve_a_asset_issuer"` ReserveAAssetType string `json:"reserve_a_asset_type"` - ReserveAMinAmount int64 `json:"reserve_a_min_amount"` - ReserveAWithdrawAmount int64 `json:"reserve_a_withdraw_amount"` + ReserveAMinAmount int64 `json:"reserve_a_min_amount,string"` + ReserveAWithdrawAmount int64 `json:"reserve_a_withdraw_amount,string"` ReserveBAssetCode string `json:"reserve_b_asset_code"` ReserveBAssetIssuer string `json:"reserve_b_asset_issuer"` ReserveBAssetType string `json:"reserve_b_asset_type"` - ReserveBMinAmount int64 `json:"reserve_b_min_amount"` - ReserveBWithdrawAmount int64 `json:"reserve_b_withdraw_amount"` - Shares int64 `json:"shares"` + ReserveBMinAmount int64 `json:"reserve_b_min_amount,string"` + ReserveBWithdrawAmount int64 `json:"reserve_b_withdraw_amount,string"` + Shares int64 `json:"shares,string"` } func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawDetail, error) { diff --git a/ingest/manage_buy_offer_details.go b/ingest/manage_buy_offer_details.go index 21c9ac35ab..81e39982a8 100644 --- a/ingest/manage_buy_offer_details.go +++ b/ingest/manage_buy_offer_details.go @@ -6,8 +6,8 @@ import ( ) type ManageBuyOffer struct { - OfferID int64 `json:"offer_id"` - Amount int64 `json:"amount"` + OfferID int64 `json:"offer_id,string"` + Amount int64 `json:"amount,string"` PriceN int32 `json:"price_n"` PriceD int32 `json:"price_d"` Price float64 `json:"price"` diff --git a/ingest/manage_sell_offer_details.go b/ingest/manage_sell_offer_details.go index 9b33fd4b03..5fc7811ce1 100644 --- a/ingest/manage_sell_offer_details.go +++ b/ingest/manage_sell_offer_details.go @@ -6,8 +6,8 @@ import ( ) type ManageSellOffer struct { - OfferID int64 `json:"offer_id"` - Amount int64 `json:"amount"` + OfferID int64 `json:"offer_id,string"` + Amount int64 `json:"amount,string"` PriceN int32 `json:"price_n"` PriceD int32 `json:"price_d"` Price float64 `json:"price"` diff --git a/ingest/path_payment_strict_receive_details.go b/ingest/path_payment_strict_receive_details.go index 3a9eab83d4..31dd64d514 100644 --- a/ingest/path_payment_strict_receive_details.go +++ b/ingest/path_payment_strict_receive_details.go @@ -7,19 +7,19 @@ import ( type PathPaymentStrictReceiveDetail struct { From string `json:"from"` FromMuxed string `json:"from_muxed"` - FromMuxedID uint64 `json:"from_muxed_id"` + FromMuxedID uint64 `json:"from_muxed_id,string"` To string `json:"to"` ToMuxed string `json:"to_muxed"` - ToMuxedID uint64 `json:"to_muxed_id"` + ToMuxedID uint64 `json:"to_muxed_id,string"` AssetCode string `json:"asset_code"` AssetIssuer string `json:"asset_issuer"` AssetType string `json:"asset_type"` - Amount int64 `json:"amount"` + Amount int64 `json:"amount,string"` SourceAssetCode string `json:"source_asset_code"` SourceAssetIssuer string `json:"source_asset_issuer"` SourceAssetType string `json:"source_asset_type"` - SourceAmount int64 `json:"source_amount"` - SourceMax int64 `json:"source_max"` + SourceAmount int64 `json:"source_amount,string"` + SourceMax int64 `json:"source_max,string"` Path []Path `json:"path"` } diff --git a/ingest/path_payment_strict_send_details.go b/ingest/path_payment_strict_send_details.go index 6b0c28e69f..1a28b8d173 100644 --- a/ingest/path_payment_strict_send_details.go +++ b/ingest/path_payment_strict_send_details.go @@ -7,19 +7,19 @@ import ( type PathPaymentStrictSendDetail struct { From string `json:"from"` FromMuxed string `json:"from_muxed"` - FromMuxedID uint64 `json:"from_muxed_id"` + FromMuxedID uint64 `json:"from_muxed_id,string"` To string `json:"to"` ToMuxed string `json:"to_muxed"` - ToMuxedID uint64 `json:"to_muxed_id"` + ToMuxedID uint64 `json:"to_muxed_id,string"` AssetCode string `json:"asset_code"` AssetIssuer string `json:"asset_issuer"` AssetType string `json:"asset_type"` - Amount int64 `json:"amount"` + Amount int64 `json:"amount,string"` SourceAssetCode string `json:"source_asset_code"` SourceAssetIssuer string `json:"source_asset_issuer"` SourceAssetType string `json:"source_asset_type"` - SourceAmount int64 `json:"source_amount"` - DestinationMin int64 `json:"destination_min"` + SourceAmount int64 `json:"source_amount,string"` + DestinationMin int64 `json:"destination_min,string"` Path []Path `json:"path"` } diff --git a/ingest/payment_details.go b/ingest/payment_details.go index 0266ec9f58..c209db38ee 100644 --- a/ingest/payment_details.go +++ b/ingest/payment_details.go @@ -7,14 +7,14 @@ import ( type PaymentDetail struct { From string `json:"from"` FromMuxed string `json:"from_muxed"` - FromMuxedID uint64 `json:"from_muxed_id"` + FromMuxedID uint64 `json:"from_muxed_id,string"` To string `json:"to"` ToMuxed string `json:"to_muxed"` - ToMuxedID uint64 `json:"to_muxed_id"` + ToMuxedID uint64 `json:"to_muxed_id,string"` AssetCode string `json:"asset_code"` AssetIssuer string `json:"asset_issuer"` AssetType string `json:"asset_type"` - Amount int64 `json:"amount"` + Amount int64 `json:"amount,string"` } func (o *LedgerOperation) PaymentDetails() (PaymentDetail, error) { From 0258c833933253b1b6e6f5a0c9f6bf9ac8a0567f Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 6 Feb 2025 11:07:08 -0500 Subject: [PATCH 37/40] make createcontract better --- ingest/invoke_host_function_details.go | 67 +++++++++++--------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/ingest/invoke_host_function_details.go b/ingest/invoke_host_function_details.go index 8a37365602..58a2720c46 100644 --- a/ingest/invoke_host_function_details.go +++ b/ingest/invoke_host_function_details.go @@ -70,30 +70,13 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, args := op.HostFunction.MustCreateContract() invokeHostFunctionDetail.Type = "create_contract" - invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() - - var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() - if ok { - invokeHostFunctionDetail.ContractID = contractID - } - - var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() - if ok { - invokeHostFunctionDetail.ContractCodeHash = contractCodeHash - } preImageDetails, err := switchContractIdPreimageType(args.ContractIdPreimage) if err != nil { return InvokeHostFunctionDetail{}, nil } - invokeHostFunctionDetail.From = preImageDetails.From - invokeHostFunctionDetail.Address = preImageDetails.Address - invokeHostFunctionDetail.AssetCode = preImageDetails.AssetCode - invokeHostFunctionDetail.AssetIssuer = preImageDetails.AssetIssuer - invokeHostFunctionDetail.AssetType = preImageDetails.AssetType + o.getCreateContractDetails(&invokeHostFunctionDetail, preImageDetails) case xdr.HostFunctionTypeHostFunctionTypeUploadContractWasm: invokeHostFunctionDetail.Type = "upload_wasm" invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() @@ -107,38 +90,44 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, args := op.HostFunction.MustCreateContractV2() invokeHostFunctionDetail.Type = "create_contract_v2" - invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() - var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() - if ok { - invokeHostFunctionDetail.ContractID = contractID + preImageDetails, err := switchContractIdPreimageType(args.ContractIdPreimage) + if err != nil { + return InvokeHostFunctionDetail{}, err } - var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() - if ok { - invokeHostFunctionDetail.ContractCodeHash = contractCodeHash - } + o.getCreateContractDetails(&invokeHostFunctionDetail, preImageDetails) // ConstructorArgs is a list of ScVals // This will initially be handled the same as InvokeContractParams until a different // model is found necessary. invokeHostFunctionDetail.Parameters, invokeHostFunctionDetail.ParametersDecoded = o.serializeParameters(args.ConstructorArgs) - - preImageDetails, err := switchContractIdPreimageType(args.ContractIdPreimage) - if err != nil { - return InvokeHostFunctionDetail{}, nil - } - - invokeHostFunctionDetail.From = preImageDetails.From - invokeHostFunctionDetail.Address = preImageDetails.Address - invokeHostFunctionDetail.AssetCode = preImageDetails.AssetCode - invokeHostFunctionDetail.AssetIssuer = preImageDetails.AssetIssuer - invokeHostFunctionDetail.AssetType = preImageDetails.AssetType default: return InvokeHostFunctionDetail{}, fmt.Errorf("unknown host function type: %s", op.HostFunction.Type) } return invokeHostFunctionDetail, nil } + +func (o *LedgerOperation) getCreateContractDetails(invokeHostFunctionDetail *InvokeHostFunctionDetail, preImageDetails PreImageDetails) { + var ok bool + invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() + + var contractID string + contractID, ok = o.Transaction.contractIdFromTxEnvelope() + if ok { + invokeHostFunctionDetail.ContractID = contractID + } + + var contractCodeHash string + contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + if ok { + invokeHostFunctionDetail.ContractCodeHash = contractCodeHash + } + + invokeHostFunctionDetail.From = preImageDetails.From + invokeHostFunctionDetail.Address = preImageDetails.Address + invokeHostFunctionDetail.AssetCode = preImageDetails.AssetCode + invokeHostFunctionDetail.AssetIssuer = preImageDetails.AssetIssuer + invokeHostFunctionDetail.AssetType = preImageDetails.AssetType +} From 52353e1b974c222560f56fc53cc60760d5187b57 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Thu, 13 Feb 2025 19:53:23 -0500 Subject: [PATCH 38/40] address comments --- go.mod | 1 + go.sum | 2 + ingest/account_merge_details.go | 2 +- ingest/invoke_host_function_details.go | 14 ++- ingest/ledger_operation.go | 40 ++++---- ingest/ledger_operation_test.go | 112 ++++++++++------------ ingest/liquidity_pool_deposit_details.go | 70 +++++++------- ingest/liquidity_pool_withdraw_details.go | 42 ++++---- 8 files changed, 142 insertions(+), 141 deletions(-) diff --git a/go.mod b/go.mod index 6d7e5fab5d..1a5c1e73ed 100644 --- a/go.mod +++ b/go.mod @@ -62,6 +62,7 @@ require ( github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fsouza/fake-gcs-server v1.49.2 + github.com/stellar/go-stellar-xdr-json v0.0.0-20250203230501-c6fa0788fe99 ) require ( diff --git a/go.sum b/go.sum index b071601459..8ecbbccca2 100644 --- a/go.sum +++ b/go.sum @@ -469,6 +469,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= +github.com/stellar/go-stellar-xdr-json v0.0.0-20250203230501-c6fa0788fe99 h1:m6P+35IPHoxYjAnEgZOgSiDXwEnFCIOpXdwNt8tZ/cw= +github.com/stellar/go-stellar-xdr-json v0.0.0-20250203230501-c6fa0788fe99/go.mod h1:BQ9LWqVJ14qa7ctsyLmjEHSx3Pi7r/8A0mbKzib4cgs= github.com/stellar/go-xdr v0.0.0-20231122183749-b53fb00bcac2 h1:OzCVd0SV5qE3ZcDeSFCmOWLZfEWZ3Oe8KtmSOYKEVWE= github.com/stellar/go-xdr v0.0.0-20231122183749-b53fb00bcac2/go.mod h1:yoxyU/M8nl9LKeWIoBrbDPQ7Cy+4jxRcWcOayZ4BMps= github.com/stellar/throttled v2.2.3-0.20190823235211-89d75816f59d+incompatible h1:jMXXAcz6xTarGDQ4VtVbtERogcmDQw4RaE85Cr9CgoQ= diff --git a/ingest/account_merge_details.go b/ingest/account_merge_details.go index b439a49ac5..f75ed00d1a 100644 --- a/ingest/account_merge_details.go +++ b/ingest/account_merge_details.go @@ -8,7 +8,7 @@ type AccountMergeDetail struct { AccountMuxedID uint64 `json:"account_muxed_id,string"` Into string `json:"into"` IntoMuxed string `json:"into_muxed"` - IntoMuxedID uint64 `json:"into_muxed_id"` + IntoMuxedID uint64 `json:"into_muxed_id,string"` } func (o *LedgerOperation) AccountMergeDetails() (AccountMergeDetail, error) { diff --git a/ingest/invoke_host_function_details.go b/ingest/invoke_host_function_details.go index 58a2720c46..69a74f8d16 100644 --- a/ingest/invoke_host_function_details.go +++ b/ingest/invoke_host_function_details.go @@ -12,8 +12,7 @@ type InvokeHostFunctionDetail struct { LedgerKeyHash []string `json:"ledger_key_hash"` ContractID string `json:"contract_id"` ContractCodeHash string `json:"contract_code_hash"` - Parameters []map[string]string `json:"parameters"` - ParametersDecoded []map[string]string `json:"parameters_decoded"` + Parameters []interface{} `json:"parameters"` AssetBalanceChanges []BalanceChangeDetail `json:"asset_balance_changes"` From string `json:"from"` Address string `json:"address"` @@ -56,8 +55,10 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, invokeHostFunctionDetail.ContractCodeHash = contractCodeHash } - // TODO: Parameters should be processed with xdr2json - invokeHostFunctionDetail.Parameters, invokeHostFunctionDetail.ParametersDecoded = o.serializeParameters(args) + invokeHostFunctionDetail.Parameters, err = o.serializeParameters(args) + if err != nil { + return InvokeHostFunctionDetail{}, err + } balanceChanges, err := o.parseAssetBalanceChangesFromContractEvents() if err != nil { @@ -101,7 +102,10 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, // ConstructorArgs is a list of ScVals // This will initially be handled the same as InvokeContractParams until a different // model is found necessary. - invokeHostFunctionDetail.Parameters, invokeHostFunctionDetail.ParametersDecoded = o.serializeParameters(args.ConstructorArgs) + invokeHostFunctionDetail.Parameters, err = o.serializeParameters(args.ConstructorArgs) + if err != nil { + return InvokeHostFunctionDetail{}, err + } default: return InvokeHostFunctionDetail{}, fmt.Errorf("unknown host function type: %s", op.HostFunction.Type) } diff --git a/ingest/ledger_operation.go b/ingest/ledger_operation.go index 62f39c8271..981ac8bfb2 100644 --- a/ingest/ledger_operation.go +++ b/ingest/ledger_operation.go @@ -1,11 +1,12 @@ package ingest import ( - "encoding/base64" + "encoding/json" "fmt" "math/big" "github.com/dgryski/go-farm" + "github.com/stellar/go-stellar-xdr-json/xdr2json" "github.com/stellar/go/amount" "github.com/stellar/go/support/contractevents" "github.com/stellar/go/toid" @@ -362,32 +363,29 @@ func (o *LedgerOperation) getLiquidityPoolAndProductDelta(lpID *xdr.PoolId) (*xd return nil, nil, fmt.Errorf("liquidity pool change not found") } -func (o *LedgerOperation) serializeParameters(args []xdr.ScVal) ([]map[string]string, []map[string]string) { - params := make([]map[string]string, 0, len(args)) - paramsDecoded := make([]map[string]string, 0, len(args)) +func (o *LedgerOperation) serializeParameters(args []xdr.ScVal) ([]interface{}, error) { + var params []interface{} for _, param := range args { - serializedParam := map[string]string{} - serializedParam["value"] = "n/a" - serializedParam["type"] = "n/a" - - serializedParamDecoded := map[string]string{} - serializedParamDecoded["value"] = "n/a" - serializedParamDecoded["type"] = "n/a" - - if scValTypeName, ok := param.ArmForSwitch(int32(param.Type)); ok { - serializedParam["type"] = scValTypeName - serializedParamDecoded["type"] = scValTypeName - if raw, err := param.MarshalBinary(); err == nil { - serializedParam["value"] = base64.StdEncoding.EncodeToString(raw) - serializedParamDecoded["value"] = param.String() + if _, ok := param.ArmForSwitch(int32(param.Type)); ok { + var err error + var raw []byte + var jsonMessage json.RawMessage + raw, err = param.MarshalBinary() + if err != nil { + return nil, err } + + jsonMessage, err = xdr2json.ConvertBytes(xdr.ScVal{}, raw) + if err != nil { + return nil, err + } + + params = append(params, jsonMessage) } - params = append(params, serializedParam) - paramsDecoded = append(paramsDecoded, serializedParamDecoded) } - return params, paramsDecoded + return params, nil } func (o *LedgerOperation) parseAssetBalanceChangesFromContractEvents() ([]BalanceChangeDetail, error) { diff --git a/ingest/ledger_operation_test.go b/ingest/ledger_operation_test.go index f70a8534c7..74c6cb6d37 100644 --- a/ingest/ledger_operation_test.go +++ b/ingest/ledger_operation_test.go @@ -1,12 +1,16 @@ package ingest import ( + "encoding/json" "testing" "github.com/stellar/go/xdr" "github.com/stretchr/testify/assert" ) +var testScSymbol xdr.ScSymbol = "test" +var testScBool bool = true + func TestOperation(t *testing.T) { o := LedgerOperation{ OperationIndex: int32(0), @@ -1392,41 +1396,50 @@ func resultTestOutput() []testOutput { { err: nil, result: LiquidityPoolDepositDetail{ - LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - MaxPrice: 1e+06, - MaxPriceN: 1000000, - MaxPriceD: 1, - MinPrice: 1e-06, - MinPriceN: 1, - MinPriceD: 1000000, - ReserveAAssetCode: "USDT", - ReserveAAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - ReserveAAssetType: "credit_alphanum4", - ReserveADepositAmount: int64(1), - ReserveAMaxAmount: int64(1000), - ReserveBAssetCode: "USDT", - ReserveBAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - ReserveBAssetType: "credit_alphanum4", - ReserveBDepositAmount: 1, - ReserveBMaxAmount: int64(100), - SharesReceived: 1, + LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + MaxPrice: 1e+06, + MaxPriceN: 1000000, + MaxPriceD: 1, + MinPrice: 1e-06, + MinPriceN: 1, + MinPriceD: 1000000, + ReserveAssetA: ReserveAsset{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + DepositAmount: int64(1), + MaxAmount: int64(1000), + }, + ReserveAssetB: ReserveAsset{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + DepositAmount: 1, + MaxAmount: int64(100), + }, + SharesReceived: 1, }, }, { err: nil, result: LiquidityPoolWithdrawDetail{ - LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - ReserveAAssetCode: "USDT", - ReserveAAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - ReserveAAssetType: "credit_alphanum4", - ReserveAMinAmount: int64(1), - ReserveAWithdrawAmount: int64(-1), - ReserveBAssetCode: "USDT", - ReserveBAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - ReserveBAssetType: "credit_alphanum4", - ReserveBMinAmount: int64(1), - ReserveBWithdrawAmount: int64(-1), - Shares: int64(4), + LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + ReserveAssetA: ReserveAsset{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + MinAmount: int64(1), + WithdrawAmount: int64(-1), + }, + + ReserveAssetB: ReserveAsset{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + MinAmount: int64(1), + WithdrawAmount: int64(-1), + }, + Shares: int64(4), }, }, { @@ -1436,25 +1449,15 @@ func resultTestOutput() []testOutput { ContractID: "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", Function: "HostFunctionTypeHostFunctionTypeInvokeContract", LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - Parameters: []map[string]string{ - { - "type": "Address", - "value": "AAAAEgAAAAESNFZ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", - }, - { - "type": "Sym", - "value": "AAAADwAAAAR0ZXN0", - }, - }, - ParametersDecoded: []map[string]string{ - { - "type": "Address", - "value": "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", - }, - { - "type": "Sym", - "value": "test", + Parameters: []interface{}{ + json.RawMessage{ + 0x7b, 0x22, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x22, 0x43, 0x41, 0x4a, 0x44, + 0x49, 0x56, 0x54, 0x59, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x42, 0x52, 0x33, 0x37, 0x22, 0x7d, }, + json.RawMessage{0x7b, 0x22, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x22, 0x3a, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x7d}, }, Type: "invoke_contract", }, @@ -1493,17 +1496,8 @@ func resultTestOutput() []testOutput { From: "asset", Function: "HostFunctionTypeHostFunctionTypeCreateContractV2", LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - Parameters: []map[string]string{ - { - "type": "B", - "value": "AAAAAAAAAAE=", - }, - }, - ParametersDecoded: []map[string]string{ - { - "type": "B", - "value": "true", - }, + Parameters: []interface{}{ + json.RawMessage{0x7b, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x7d}, }, Type: "create_contract_v2", }, diff --git a/ingest/liquidity_pool_deposit_details.go b/ingest/liquidity_pool_deposit_details.go index 8d7dce32d6..d4d38635f8 100644 --- a/ingest/liquidity_pool_deposit_details.go +++ b/ingest/liquidity_pool_deposit_details.go @@ -8,24 +8,26 @@ import ( ) type LiquidityPoolDepositDetail struct { - LiquidityPoolID string `json:"liquidity_pool_id"` - ReserveAAssetCode string `json:"reserve_a_asset_code"` - ReserveAAssetIssuer string `json:"reserve_a_asset_issuer"` - ReserveAAssetType string `json:"reserve_a_asset_type"` - ReserveAMaxAmount int64 `json:"reserve_a_max_amount,string"` - ReserveADepositAmount int64 `json:"reserve_a_deposit_amount,string"` - ReserveBAssetCode string `json:"reserve_b_asset_code"` - ReserveBAssetIssuer string `json:"reserve_b_asset_issuer"` - ReserveBAssetType string `json:"reserve_b_asset_type"` - ReserveBMaxAmount int64 `json:"reserve_b_max_amount,string"` - ReserveBDepositAmount int64 `json:"reserve_b_deposit_amount,string"` - MinPriceN int32 `json:"min_price_n"` - MinPriceD int32 `json:"min_price_d"` - MinPrice float64 `json:"min_price"` - MaxPriceN int32 `json:"max_price_n"` - MaxPriceD int32 `json:"max_price_d"` - MaxPrice float64 `json:"max_price"` - SharesReceived int64 `json:"shares_received,string"` + LiquidityPoolID string `json:"liquidity_pool_id"` + ReserveAssetA ReserveAsset `json:"reserve_asset_a"` + ReserveAssetB ReserveAsset `json:"reserve_asset_b"` + MinPriceN int32 `json:"min_price_n"` + MinPriceD int32 `json:"min_price_d"` + MinPrice float64 `json:"min_price"` + MaxPriceN int32 `json:"max_price_n"` + MaxPriceD int32 `json:"max_price_d"` + MaxPrice float64 `json:"max_price"` + SharesReceived int64 `json:"shares_received,string"` +} + +type ReserveAsset struct { + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + MinAmount int64 `json:"min_amount,string"` + MaxAmount int64 `json:"max_amount,string"` + DepositAmount int64 `json:"deposit_amount,string"` + WithdrawAmount int64 `json:"withdraw_amount,string"` } func (o *LedgerOperation) LiquidityPoolDepositDetails() (LiquidityPoolDepositDetail, error) { @@ -35,12 +37,16 @@ func (o *LedgerOperation) LiquidityPoolDepositDetails() (LiquidityPoolDepositDet } liquidityPoolDepositDetail := LiquidityPoolDepositDetail{ - ReserveAMaxAmount: int64(op.MaxAmountA), - ReserveBMaxAmount: int64(op.MaxAmountB), - MinPriceN: int32(op.MinPrice.N), - MinPriceD: int32(op.MinPrice.D), - MaxPriceN: int32(op.MaxPrice.N), - MaxPriceD: int32(op.MaxPrice.D), + ReserveAssetA: ReserveAsset{ + MaxAmount: int64(op.MaxAmountA), + }, + ReserveAssetB: ReserveAsset{ + MaxAmount: int64(op.MaxAmountB), + }, + MinPriceN: int32(op.MinPrice.N), + MinPriceD: int32(op.MinPrice.D), + MaxPriceN: int32(op.MaxPrice.N), + MaxPriceD: int32(op.MaxPrice.D), } var err error @@ -79,10 +85,10 @@ func (o *LedgerOperation) LiquidityPoolDepositDetails() (LiquidityPoolDepositDet return LiquidityPoolDepositDetail{}, err } - liquidityPoolDepositDetail.ReserveAAssetCode = assetACode - liquidityPoolDepositDetail.ReserveAAssetIssuer = assetAIssuer - liquidityPoolDepositDetail.ReserveAAssetType = assetAType - liquidityPoolDepositDetail.ReserveADepositAmount = int64(depositedA) + liquidityPoolDepositDetail.ReserveAssetA.AssetCode = assetACode + liquidityPoolDepositDetail.ReserveAssetA.AssetIssuer = assetAIssuer + liquidityPoolDepositDetail.ReserveAssetA.AssetType = assetAType + liquidityPoolDepositDetail.ReserveAssetA.DepositAmount = int64(depositedA) //Process ReserveB Details var assetBCode, assetBIssuer, assetBType string @@ -91,10 +97,10 @@ func (o *LedgerOperation) LiquidityPoolDepositDetails() (LiquidityPoolDepositDet return LiquidityPoolDepositDetail{}, err } - liquidityPoolDepositDetail.ReserveBAssetCode = assetBCode - liquidityPoolDepositDetail.ReserveBAssetIssuer = assetBIssuer - liquidityPoolDepositDetail.ReserveBAssetType = assetBType - liquidityPoolDepositDetail.ReserveBDepositAmount = int64(depositedB) + liquidityPoolDepositDetail.ReserveAssetB.AssetCode = assetBCode + liquidityPoolDepositDetail.ReserveAssetB.AssetIssuer = assetBIssuer + liquidityPoolDepositDetail.ReserveAssetB.AssetType = assetBType + liquidityPoolDepositDetail.ReserveAssetB.DepositAmount = int64(depositedB) liquidityPoolDepositDetail.MinPrice, err = strconv.ParseFloat(op.MinPrice.String(), 64) if err != nil { diff --git a/ingest/liquidity_pool_withdraw_details.go b/ingest/liquidity_pool_withdraw_details.go index 94d4a93ac7..44d750fbab 100644 --- a/ingest/liquidity_pool_withdraw_details.go +++ b/ingest/liquidity_pool_withdraw_details.go @@ -7,18 +7,10 @@ import ( ) type LiquidityPoolWithdrawDetail struct { - LiquidityPoolID string `json:"liquidity_pool_id"` - ReserveAAssetCode string `json:"reserve_a_asset_code"` - ReserveAAssetIssuer string `json:"reserve_a_asset_issuer"` - ReserveAAssetType string `json:"reserve_a_asset_type"` - ReserveAMinAmount int64 `json:"reserve_a_min_amount,string"` - ReserveAWithdrawAmount int64 `json:"reserve_a_withdraw_amount,string"` - ReserveBAssetCode string `json:"reserve_b_asset_code"` - ReserveBAssetIssuer string `json:"reserve_b_asset_issuer"` - ReserveBAssetType string `json:"reserve_b_asset_type"` - ReserveBMinAmount int64 `json:"reserve_b_min_amount,string"` - ReserveBWithdrawAmount int64 `json:"reserve_b_withdraw_amount,string"` - Shares int64 `json:"shares,string"` + LiquidityPoolID string `json:"liquidity_pool_id"` + ReserveAssetA ReserveAsset `json:"reserve_asset_a"` + ReserveAssetB ReserveAsset `json:"reserve_asset_b"` + Shares int64 `json:"shares,string"` } func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawDetail, error) { @@ -28,9 +20,13 @@ func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawD } liquidityPoolWithdrawDetail := LiquidityPoolWithdrawDetail{ - ReserveAMinAmount: int64(op.MinAmountA), - ReserveBMinAmount: int64(op.MinAmountB), - Shares: int64(op.Amount), + ReserveAssetA: ReserveAsset{ + MinAmount: int64(op.MinAmountA), + }, + ReserveAssetB: ReserveAsset{ + MinAmount: int64(op.MinAmountB), + }, + Shares: int64(op.Amount), } var err error @@ -66,10 +62,10 @@ func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawD return LiquidityPoolWithdrawDetail{}, err } - liquidityPoolWithdrawDetail.ReserveAAssetCode = assetACode - liquidityPoolWithdrawDetail.ReserveAAssetIssuer = assetAIssuer - liquidityPoolWithdrawDetail.ReserveAAssetType = assetAType - liquidityPoolWithdrawDetail.ReserveAWithdrawAmount = int64(receivedA) + liquidityPoolWithdrawDetail.ReserveAssetA.AssetCode = assetACode + liquidityPoolWithdrawDetail.ReserveAssetA.AssetIssuer = assetAIssuer + liquidityPoolWithdrawDetail.ReserveAssetA.AssetType = assetAType + liquidityPoolWithdrawDetail.ReserveAssetA.WithdrawAmount = int64(receivedA) // Process AssetB Details var assetBCode, assetBIssuer, assetBType string @@ -78,10 +74,10 @@ func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawD return LiquidityPoolWithdrawDetail{}, err } - liquidityPoolWithdrawDetail.ReserveBAssetCode = assetBCode - liquidityPoolWithdrawDetail.ReserveBAssetIssuer = assetBIssuer - liquidityPoolWithdrawDetail.ReserveBAssetType = assetBType - liquidityPoolWithdrawDetail.ReserveBWithdrawAmount = int64(receivedB) + liquidityPoolWithdrawDetail.ReserveAssetB.AssetCode = assetBCode + liquidityPoolWithdrawDetail.ReserveAssetB.AssetIssuer = assetBIssuer + liquidityPoolWithdrawDetail.ReserveAssetB.AssetType = assetBType + liquidityPoolWithdrawDetail.ReserveAssetB.WithdrawAmount = int64(receivedB) return liquidityPoolWithdrawDetail, nil } From 76c6f878446c6123051f22ae8d7612464ffb14b9 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Sun, 13 Apr 2025 22:16:50 -0400 Subject: [PATCH 39/40] Move xdrill operations to procesors/operations --- go.mod | 1 - go.sum | 2 - ingest/ledger_operation.go | 619 ------- ingest/ledger_operation_test.go | 1533 ----------------- ingest/ledger_transaction.go | 18 +- .../account_merge_details.go | 2 +- .../allow_trust_details.go | 2 +- ...begin_sponsoring_future_reserve_details.go | 2 +- .../bump_sequence_details.go | 2 +- .../change_trust_details.go | 7 +- .../claim_claimable_balance_details.go | 2 +- .../clawback_claimable_balance_details.go | 2 +- .../operation_processor}/clawback_details.go | 2 +- .../create_account_details.go | 2 +- .../create_claimable_balance_details.go | 2 +- .../create_passive_sell_offer_details.go | 2 +- .../end_sponsoring_future_reserve_details.go | 2 +- .../extend_footprint_ttl_details.go | 4 +- .../operation_processor}/inflation_details.go | 2 +- .../invoke_host_function_details.go | 8 +- .../liquidity_pool_deposit_details.go | 8 +- .../liquidity_pool_withdraw_details.go | 8 +- .../manage_buy_offer_details.go | 2 +- .../manage_data_details.go | 2 +- .../manage_sell_offer_details.go | 2 +- .../operation_processor/operation.go | 591 +++++++ .../operation_processor/operation_test.go | 1515 ++++++++++++++++ .../path_payment_strict_receive_details.go | 2 +- .../path_payment_strict_send_details.go | 2 +- .../operation_processor}/payment_details.go | 2 +- .../restore_footprint_details.go | 4 +- .../revoke_sponsorship_details.go | 4 +- .../set_options_details.go | 8 +- .../set_trustline_flags_details.go | 2 +- 34 files changed, 2146 insertions(+), 2222 deletions(-) delete mode 100644 ingest/ledger_operation.go delete mode 100644 ingest/ledger_operation_test.go rename ingest/{ => processors/operation_processor}/account_merge_details.go (98%) rename ingest/{ => processors/operation_processor}/allow_trust_details.go (99%) rename ingest/{ => processors/operation_processor}/begin_sponsoring_future_reserve_details.go (96%) rename ingest/{ => processors/operation_processor}/bump_sequence_details.go (95%) rename ingest/{ => processors/operation_processor}/change_trust_details.go (95%) rename ingest/{ => processors/operation_processor}/claim_claimable_balance_details.go (98%) rename ingest/{ => processors/operation_processor}/clawback_claimable_balance_details.go (97%) rename ingest/{ => processors/operation_processor}/clawback_details.go (98%) rename ingest/{ => processors/operation_processor}/create_account_details.go (98%) rename ingest/{ => processors/operation_processor}/create_claimable_balance_details.go (98%) rename ingest/{ => processors/operation_processor}/create_passive_sell_offer_details.go (99%) rename ingest/{ => processors/operation_processor}/end_sponsoring_future_reserve_details.go (99%) rename ingest/{ => processors/operation_processor}/extend_footprint_ttl_details.go (93%) rename ingest/{ => processors/operation_processor}/inflation_details.go (88%) rename ingest/{ => processors/operation_processor}/invoke_host_function_details.go (95%) rename ingest/{ => processors/operation_processor}/liquidity_pool_deposit_details.go (95%) rename ingest/{ => processors/operation_processor}/liquidity_pool_withdraw_details.go (93%) rename ingest/{ => processors/operation_processor}/manage_buy_offer_details.go (99%) rename ingest/{ => processors/operation_processor}/manage_data_details.go (97%) rename ingest/{ => processors/operation_processor}/manage_sell_offer_details.go (99%) rename ingest/{ => processors/operation_processor}/path_payment_strict_receive_details.go (99%) rename ingest/{ => processors/operation_processor}/path_payment_strict_send_details.go (99%) rename ingest/{ => processors/operation_processor}/payment_details.go (98%) rename ingest/{ => processors/operation_processor}/restore_footprint_details.go (92%) rename ingest/{ => processors/operation_processor}/revoke_sponsorship_details.go (93%) rename ingest/{ => processors/operation_processor}/set_options_details.go (93%) rename ingest/{ => processors/operation_processor}/set_trustline_flags_details.go (99%) diff --git a/go.mod b/go.mod index 44026a6d97..b132636d65 100644 --- a/go.mod +++ b/go.mod @@ -62,7 +62,6 @@ require ( github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fsouza/fake-gcs-server v1.49.2 - github.com/stellar/go-stellar-xdr-json v0.0.0-20250203230501-c6fa0788fe99 ) require ( diff --git a/go.sum b/go.sum index da4a183483..7d61a32a8a 100644 --- a/go.sum +++ b/go.sum @@ -469,8 +469,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= -github.com/stellar/go-stellar-xdr-json v0.0.0-20250203230501-c6fa0788fe99 h1:m6P+35IPHoxYjAnEgZOgSiDXwEnFCIOpXdwNt8tZ/cw= -github.com/stellar/go-stellar-xdr-json v0.0.0-20250203230501-c6fa0788fe99/go.mod h1:BQ9LWqVJ14qa7ctsyLmjEHSx3Pi7r/8A0mbKzib4cgs= github.com/stellar/go-xdr v0.0.0-20231122183749-b53fb00bcac2 h1:OzCVd0SV5qE3ZcDeSFCmOWLZfEWZ3Oe8KtmSOYKEVWE= github.com/stellar/go-xdr v0.0.0-20231122183749-b53fb00bcac2/go.mod h1:yoxyU/M8nl9LKeWIoBrbDPQ7Cy+4jxRcWcOayZ4BMps= github.com/stellar/throttled v2.2.3-0.20190823235211-89d75816f59d+incompatible h1:jMXXAcz6xTarGDQ4VtVbtERogcmDQw4RaE85Cr9CgoQ= diff --git a/ingest/ledger_operation.go b/ingest/ledger_operation.go deleted file mode 100644 index 981ac8bfb2..0000000000 --- a/ingest/ledger_operation.go +++ /dev/null @@ -1,619 +0,0 @@ -package ingest - -import ( - "encoding/json" - "fmt" - "math/big" - - "github.com/dgryski/go-farm" - "github.com/stellar/go-stellar-xdr-json/xdr2json" - "github.com/stellar/go/amount" - "github.com/stellar/go/support/contractevents" - "github.com/stellar/go/toid" - "github.com/stellar/go/xdr" -) - -type LedgerOperation struct { - OperationIndex int32 - Operation xdr.Operation - Transaction *LedgerTransaction - NetworkPassphrase string -} - -func (o *LedgerOperation) sourceAccountXDR() xdr.MuxedAccount { - sourceAccount := o.Operation.SourceAccount - if sourceAccount != nil { - return *sourceAccount - } - - return o.Transaction.Envelope.SourceAccount() -} - -func (o *LedgerOperation) SourceAccount() string { - muxedAccount := o.sourceAccountXDR() - return muxedAccount.ToAccountId().Address() -} - -func (o *LedgerOperation) Type() int32 { - return int32(o.Operation.Body.Type) -} - -func (o *LedgerOperation) TypeString() string { - return xdr.OperationTypeToStringMap[o.Type()] -} - -func (o *LedgerOperation) ID() int64 { - //operationIndex needs +1 increment to stay in sync with ingest package - return toid.New(int32(o.Transaction.Ledger.LedgerSequence()), int32(o.Transaction.Index), o.OperationIndex+1).ToInt64() -} - -func (o *LedgerOperation) SourceAccountMuxed() (string, bool) { - muxedAccount := o.sourceAccountXDR() - if muxedAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { - return "", false - } - - return muxedAccount.Address(), true -} - -func (o *LedgerOperation) OperationResultCode() string { - var operationResultCode string - operationResults, ok := o.Transaction.Result.Result.OperationResults() - if ok { - operationResultCode = operationResults[o.OperationIndex].Code.String() - } - - return operationResultCode -} - -func (o *LedgerOperation) OperationTraceCode() (string, error) { - var operationTraceCode string - var operationResults []xdr.OperationResult - var ok bool - var err error - - operationResults, ok = o.Transaction.Result.Result.OperationResults() - if ok { - var operationResultTr xdr.OperationResultTr - operationResultTr, ok = operationResults[o.OperationIndex].GetTr() - if ok { - operationTraceCode, err = operationResultTr.MapOperationResultTr() - if err != nil { - return "", err - } - return operationTraceCode, nil - } - } - - return operationTraceCode, nil -} - -func (o *LedgerOperation) OperationDetails() (interface{}, error) { - var err error - var details interface{} - - switch o.Operation.Body.Type { - case xdr.OperationTypeCreateAccount: - details, err = o.CreateAccountDetails() - if err != nil { - return details, err - } - case xdr.OperationTypePayment: - details, err = o.PaymentDetails() - if err != nil { - return details, err - } - case xdr.OperationTypePathPaymentStrictReceive: - details, err = o.PathPaymentStrictReceiveDetails() - if err != nil { - return details, err - } - case xdr.OperationTypePathPaymentStrictSend: - details, err = o.PathPaymentStrictSendDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeManageBuyOffer: - details, err = o.ManageBuyOfferDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeManageSellOffer: - details, err = o.ManageSellOfferDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeCreatePassiveSellOffer: - details, err = o.CreatePassiveSellOfferDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeSetOptions: - details, err = o.SetOptionsDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeChangeTrust: - details, err = o.ChangeTrustDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeAllowTrust: - details, err = o.AllowTrustDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeAccountMerge: - details, err = o.AccountMergeDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeInflation: - details, err = o.InflationDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeManageData: - details, err = o.ManageDataDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeBumpSequence: - details, err = o.BumpSequenceDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeCreateClaimableBalance: - details, err = o.CreateClaimableBalanceDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeClaimClaimableBalance: - details, err = o.ClaimClaimableBalanceDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeBeginSponsoringFutureReserves: - details, err = o.BeginSponsoringFutureReservesDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeEndSponsoringFutureReserves: - details, err = o.EndSponsoringFutureReserveDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeRevokeSponsorship: - details, err = o.RevokeSponsorshipDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeClawback: - details, err = o.ClawbackDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeClawbackClaimableBalance: - details, err = o.ClawbackClaimableBalanceDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeSetTrustLineFlags: - details, err = o.SetTrustlineFlagsDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeLiquidityPoolDeposit: - details, err = o.LiquidityPoolDepositDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeLiquidityPoolWithdraw: - details, err = o.LiquidityPoolWithdrawDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeInvokeHostFunction: - details, err = o.InvokeHostFunctionDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeExtendFootprintTtl: - details, err = o.ExtendFootprintTtlDetails() - if err != nil { - return details, err - } - case xdr.OperationTypeRestoreFootprint: - details, err = o.RestoreFootprintDetails() - if err != nil { - return details, err - } - default: - return details, fmt.Errorf("unknown operation type: %s", o.Operation.Body.Type.String()) - } - - return details, nil -} - -func getMuxedAccountDetails(a xdr.MuxedAccount) (string, uint64, error) { - var err error - var muxedAccountAddress string - var muxedAccountID uint64 - - if a.Type == xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { - muxedAccountAddress, err = a.GetAddress() - if err != nil { - return "", 0, err - } - muxedAccountID, err = a.GetId() - if err != nil { - return "", 0, err - } - } - return muxedAccountAddress, muxedAccountID, nil -} - -type LedgerKeyDetail struct { - AccountID string `json:"account_id"` - ClaimableBalanceID string `json:"claimable_balance_id"` - DataAccountID string `json:"data_account_id"` - DataName string `json:"data_name"` - OfferID int64 `json:"offer_id,string"` - TrustlineAccountID string `json:"trustline_account_id"` - TrustlineLiquidityPoolID string `json:"trustline_liquidity_pool_id"` - TrustlineAssetCode string `json:"trustline_asset_code"` - TrustlineAssetIssuer string `json:"trustline_asset_issuer"` - TrustlineAssetType string `json:"trustline_asset_type"` - LiquidityPoolID string `json:"liquidity_pool_id"` -} - -func addLedgerKeyToDetails(ledgerKey xdr.LedgerKey) (LedgerKeyDetail, error) { - var err error - var ledgerKeyDetail LedgerKeyDetail - - switch ledgerKey.Type { - case xdr.LedgerEntryTypeAccount: - ledgerKeyDetail.AccountID = ledgerKey.Account.AccountId.Address() - case xdr.LedgerEntryTypeClaimableBalance: - var marshalHex string - marshalHex, err = xdr.MarshalHex(ledgerKey.ClaimableBalance.BalanceId) - if err != nil { - return LedgerKeyDetail{}, fmt.Errorf("in claimable balance: %w", err) - } - ledgerKeyDetail.ClaimableBalanceID = marshalHex - case xdr.LedgerEntryTypeData: - ledgerKeyDetail.DataAccountID = ledgerKey.Data.AccountId.Address() - ledgerKeyDetail.DataName = string(ledgerKey.Data.DataName) - case xdr.LedgerEntryTypeOffer: - ledgerKeyDetail.OfferID = int64(ledgerKey.Offer.OfferId) - case xdr.LedgerEntryTypeTrustline: - ledgerKeyDetail.TrustlineAccountID = ledgerKey.TrustLine.AccountId.Address() - if ledgerKey.TrustLine.Asset.Type == xdr.AssetTypeAssetTypePoolShare { - ledgerKeyDetail.TrustlineLiquidityPoolID, err = PoolIDToString(*ledgerKey.TrustLine.Asset.LiquidityPoolId) - if err != nil { - return LedgerKeyDetail{}, err - } - } else { - var assetCode, assetIssuer, assetType string - err = ledgerKey.TrustLine.Asset.ToAsset().Extract(&assetType, &assetCode, &assetIssuer) - if err != nil { - return LedgerKeyDetail{}, err - } - - ledgerKeyDetail.TrustlineAssetCode = assetCode - ledgerKeyDetail.TrustlineAssetIssuer = assetIssuer - ledgerKeyDetail.TrustlineAssetType = assetType - } - case xdr.LedgerEntryTypeLiquidityPool: - ledgerKeyDetail.LiquidityPoolID, err = PoolIDToString(ledgerKey.LiquidityPool.LiquidityPoolId) - if err != nil { - return LedgerKeyDetail{}, err - } - } - - return ledgerKeyDetail, nil -} - -func (o *LedgerOperation) getLiquidityPoolAndProductDelta(lpID *xdr.PoolId) (*xdr.LiquidityPoolEntry, *LiquidityPoolDelta, error) { - changes, err := o.Transaction.GetOperationChanges(uint32(o.OperationIndex)) - if err != nil { - return nil, nil, err - } - - for _, c := range changes { - if c.Type != xdr.LedgerEntryTypeLiquidityPool { - continue - } - // The delta can be caused by a full removal or full creation of the liquidity pool - var lp *xdr.LiquidityPoolEntry - var preA, preB, preShares xdr.Int64 - if c.Pre != nil { - if lpID != nil && c.Pre.Data.LiquidityPool.LiquidityPoolId != *lpID { - // if we were looking for specific pool id, then check on it - continue - } - lp = c.Pre.Data.LiquidityPool - if c.Pre.Data.LiquidityPool.Body.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { - return nil, nil, fmt.Errorf("unexpected liquity pool body type %d", c.Pre.Data.LiquidityPool.Body.Type) - } - cpPre := c.Pre.Data.LiquidityPool.Body.ConstantProduct - preA, preB, preShares = cpPre.ReserveA, cpPre.ReserveB, cpPre.TotalPoolShares - } - var postA, postB, postShares xdr.Int64 - if c.Post != nil { - if lpID != nil && c.Post.Data.LiquidityPool.LiquidityPoolId != *lpID { - // if we were looking for specific pool id, then check on it - continue - } - lp = c.Post.Data.LiquidityPool - if c.Post.Data.LiquidityPool.Body.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { - return nil, nil, fmt.Errorf("unexpected liquity pool body type %d", c.Post.Data.LiquidityPool.Body.Type) - } - cpPost := c.Post.Data.LiquidityPool.Body.ConstantProduct - postA, postB, postShares = cpPost.ReserveA, cpPost.ReserveB, cpPost.TotalPoolShares - } - delta := &LiquidityPoolDelta{ - ReserveA: postA - preA, - ReserveB: postB - preB, - TotalPoolShares: postShares - preShares, - } - return lp, delta, nil - } - - return nil, nil, fmt.Errorf("liquidity pool change not found") -} - -func (o *LedgerOperation) serializeParameters(args []xdr.ScVal) ([]interface{}, error) { - var params []interface{} - - for _, param := range args { - if _, ok := param.ArmForSwitch(int32(param.Type)); ok { - var err error - var raw []byte - var jsonMessage json.RawMessage - raw, err = param.MarshalBinary() - if err != nil { - return nil, err - } - - jsonMessage, err = xdr2json.ConvertBytes(xdr.ScVal{}, raw) - if err != nil { - return nil, err - } - - params = append(params, jsonMessage) - } - } - - return params, nil -} - -func (o *LedgerOperation) parseAssetBalanceChangesFromContractEvents() ([]BalanceChangeDetail, error) { - balanceChanges := []BalanceChangeDetail{} - - diagnosticEvents, err := o.Transaction.GetDiagnosticEvents() - if err != nil { - // this operation in this context must be an InvokeHostFunctionOp, therefore V3Meta should be present - // as it's in same soroban model, so if any err, it's real, - return nil, err - } - - for _, contractEvent := range o.filterEvents(diagnosticEvents) { - // Parse the xdr contract event to contractevents.StellarAssetContractEvent model - - var err error - var balanceChangeDetail BalanceChangeDetail - var sacEvent contractevents.StellarAssetContractEvent - // has some convenience like to/from attributes are expressed in strkey format for accounts(G...) and contracts(C...) - if sacEvent, err = contractevents.NewStellarAssetContractEvent(&contractEvent, o.NetworkPassphrase); err == nil { - switch sacEvent.GetType() { - case contractevents.EventTypeTransfer: - transferEvt := sacEvent.(*contractevents.TransferEvent) - balanceChangeDetail, err = createSACBalanceChangeEntry(transferEvt.From, transferEvt.To, transferEvt.Amount, transferEvt.Asset, "transfer") - if err != nil { - return []BalanceChangeDetail{}, err - } - - balanceChanges = append(balanceChanges, balanceChangeDetail) - case contractevents.EventTypeMint: - mintEvt := sacEvent.(*contractevents.MintEvent) - balanceChangeDetail, err = createSACBalanceChangeEntry("", mintEvt.To, mintEvt.Amount, mintEvt.Asset, "mint") - if err != nil { - return []BalanceChangeDetail{}, err - } - - balanceChanges = append(balanceChanges, balanceChangeDetail) - case contractevents.EventTypeClawback: - clawbackEvt := sacEvent.(*contractevents.ClawbackEvent) - balanceChangeDetail, err = createSACBalanceChangeEntry(clawbackEvt.From, "", clawbackEvt.Amount, clawbackEvt.Asset, "clawback") - if err != nil { - return []BalanceChangeDetail{}, err - } - - balanceChanges = append(balanceChanges, balanceChangeDetail) - case contractevents.EventTypeBurn: - burnEvt := sacEvent.(*contractevents.BurnEvent) - balanceChangeDetail, err = createSACBalanceChangeEntry(burnEvt.From, "", burnEvt.Amount, burnEvt.Asset, "burn") - if err != nil { - return []BalanceChangeDetail{}, err - } - - balanceChanges = append(balanceChanges, balanceChangeDetail) - } - } - } - - return balanceChanges, nil -} - -func (o *LedgerOperation) filterEvents(diagnosticEvents []xdr.DiagnosticEvent) []xdr.ContractEvent { - var filtered []xdr.ContractEvent - for _, diagnosticEvent := range diagnosticEvents { - if !diagnosticEvent.InSuccessfulContractCall || diagnosticEvent.Event.Type != xdr.ContractEventTypeContract { - continue - } - filtered = append(filtered, diagnosticEvent.Event) - } - return filtered -} - -type BalanceChangeDetail struct { - From string `json:"from"` - To string `json:"to"` - Type string `json:"type"` - Amount string `json:"amount"` - AssetCode string `json:"asset_code"` - AssetIssuer string `json:"asset_issuer"` - AssetType string `json:"asset_type"` -} - -// fromAccount - strkey format of contract or address -// toAccount - strkey format of contract or address, or nillable -// amountChanged - absolute value that asset balance changed -// asset - the fully qualified issuer:code for asset that had balance change -// changeType - the type of source sac event that triggered this change -// -// return - a balance changed record expressed as map of key/value's -func createSACBalanceChangeEntry(fromAccount string, toAccount string, amountChanged xdr.Int128Parts, asset xdr.Asset, changeType string) (BalanceChangeDetail, error) { - balanceChangeDetail := BalanceChangeDetail{ - Type: changeType, - Amount: amount.String128(amountChanged), - } - - if fromAccount != "" { - balanceChangeDetail.From = fromAccount - } - if toAccount != "" { - balanceChangeDetail.To = toAccount - } - - var assetCode, assetIssuer, assetType string - err := asset.Extract(&assetType, &assetCode, &assetIssuer) - if err != nil { - return BalanceChangeDetail{}, err - } - - return balanceChangeDetail, nil -} - -type PreImageDetails struct { - From string `json:"from"` - Address string `json:"address"` - AssetCode string `json:"asset_code"` - AssetIssuer string `json:"asset_issuer"` - AssetType string `json:"asset_type"` -} - -func switchContractIdPreimageType(contractIdPreimage xdr.ContractIdPreimage) (PreImageDetails, error) { - switch contractIdPreimage.Type { - case xdr.ContractIdPreimageTypeContractIdPreimageFromAddress: - fromAddress := contractIdPreimage.MustFromAddress() - address, err := fromAddress.Address.String() - if err != nil { - return PreImageDetails{}, err - } - return PreImageDetails{ - From: "address", - Address: address, - }, nil - case xdr.ContractIdPreimageTypeContractIdPreimageFromAsset: - var assetCode, assetIssuer, assetType string - contractIdPreimage.MustFromAsset().Extract(&assetType, &assetCode, &assetIssuer) - - return PreImageDetails{ - From: "asset", - AssetCode: assetCode, - AssetIssuer: assetIssuer, - AssetType: assetType, - }, nil - - default: - return PreImageDetails{}, fmt.Errorf("unknown contract id type: %s", contractIdPreimage.Type) - } -} - -func (o *LedgerOperation) ConvertStroopValueToReal(input int64) float64 { - output, _ := big.NewRat(int64(input), int64(10000000)).Float64() - return output -} - -func (o *LedgerOperation) FormatPrefix(p string) string { - if p != "" { - p += "_" - } - return p -} - -func (o *LedgerOperation) FarmHashAsset(assetCode, assetIssuer, assetType string) int64 { - asset := fmt.Sprintf("%s%s%s", assetCode, assetIssuer, assetType) - hash := farm.Fingerprint64([]byte(asset)) - - return int64(hash) -} - -// Path is a representation of an asset without an ID that forms part of a path in a path payment -type Path struct { - AssetCode string `json:"asset_code"` - AssetIssuer string `json:"asset_issuer"` - AssetType string `json:"asset_type"` -} - -func (o *LedgerOperation) TransformPath(initialPath []xdr.Asset) []Path { - if len(initialPath) == 0 { - return nil - } - var path = make([]Path, 0) - for _, pathAsset := range initialPath { - var assetType, code, issuer string - err := pathAsset.Extract(&assetType, &code, &issuer) - if err != nil { - return nil - } - - path = append(path, Path{ - AssetType: assetType, - AssetIssuer: issuer, - AssetCode: code, - }) - } - return path -} - -type Price struct { - Numerator int32 `json:"n"` - Denominator int32 `json:"d"` -} - -func PoolIDToString(id xdr.PoolId) (string, error) { - return xdr.MarshalBase64(id) -} - -type Claimant struct { - Destination string `json:"destination"` - Predicate xdr.ClaimPredicate `json:"predicate"` -} - -func transformClaimants(claimants []xdr.Claimant) []Claimant { - var transformed []Claimant - for _, c := range claimants { - switch c.Type { - case 0: - transformed = append(transformed, Claimant{ - Destination: c.V0.Destination.Address(), - Predicate: c.V0.Predicate, - }) - } - } - return transformed -} - -type SponsorshipOutput struct { - Operation xdr.Operation - OperationIndex uint32 -} - -type LiquidityPoolDelta struct { - ReserveA xdr.Int64 - ReserveB xdr.Int64 - TotalPoolShares xdr.Int64 -} diff --git a/ingest/ledger_operation_test.go b/ingest/ledger_operation_test.go deleted file mode 100644 index 74c6cb6d37..0000000000 --- a/ingest/ledger_operation_test.go +++ /dev/null @@ -1,1533 +0,0 @@ -package ingest - -import ( - "encoding/json" - "testing" - - "github.com/stellar/go/xdr" - "github.com/stretchr/testify/assert" -) - -var testScSymbol xdr.ScSymbol = "test" -var testScBool bool = true - -func TestOperation(t *testing.T) { - o := LedgerOperation{ - OperationIndex: int32(0), - Operation: operationTestInput()[1], - Transaction: transactionTestInput(), - NetworkPassphrase: "", - } - - assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", o.SourceAccount()) - assert.Equal(t, int32(1), o.Type()) - assert.Equal(t, "OperationTypePayment", o.TypeString()) - assert.Equal(t, int64(131335723340009473), o.ID()) - - var ok bool - var sourceAccountMuxed string - sourceAccountMuxed, ok = o.SourceAccountMuxed() - assert.Equal(t, true, ok) - assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", sourceAccountMuxed) - - assert.Equal(t, "OperationResultCodeOpInner", o.OperationResultCode()) - - var err error - var operationTraceCode string - operationTraceCode, err = o.OperationTraceCode() - assert.Equal(t, nil, err) - assert.Equal(t, "PathPaymentStrictReceiveResultCodePathPaymentStrictReceiveSuccess", operationTraceCode) -} - -func TestOperationDetails(t *testing.T) { - testOutput := resultTestOutput() - for i, op := range operationTestInput() { - ledgerOperation := LedgerOperation{ - OperationIndex: int32(i), - Operation: op, - Transaction: transactionTestInput(), - NetworkPassphrase: "", - } - - result, err := ledgerOperation.OperationDetails() - assert.Equal(t, testOutput[i].err, err) - assert.Equal(t, testOutput[i].result, result) - } -} - -func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { - lcm = xdr.LedgerCloseMeta{ - V: 1, - V1: &xdr.LedgerCloseMetaV1{ - LedgerHeader: xdr.LedgerHeaderHistoryEntry{ - Header: xdr.LedgerHeader{ - LedgerSeq: 30578981, - LedgerVersion: 22, - }, - }, - }, - } - - return lcm -} - -func transactionTestInput() *LedgerTransaction { - testAccountAddress := "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA" - testAccountID, _ := xdr.AddressToAccountId(testAccountAddress) - dummyBool := true - - ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) - muxedAccount := xdr.MuxedAccount{ - Type: 256, - Ed25519: &ed25519, - Med25519: &xdr.MuxedAccountMed25519{ - Id: xdr.Uint64(123), - Ed25519: ed25519, - }, - } - - memoText := "test memo" - minSeqNum := xdr.SequenceNumber(123) - - transaction := &LedgerTransaction{ - Index: 1, - Envelope: xdr.TransactionEnvelope{ - Type: xdr.EnvelopeTypeEnvelopeTypeTx, - V1: &xdr.TransactionV1Envelope{ - Signatures: []xdr.DecoratedSignature{ - { - Signature: []byte{0x11, 0x22}, - }, - }, - Tx: xdr.Transaction{ - SourceAccount: muxedAccount, - SeqNum: xdr.SequenceNumber(30578981), - Fee: xdr.Uint32(4560), - Operations: []xdr.Operation{ - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - { - SourceAccount: &muxedAccount, - Body: xdr.OperationBody{}, - }, - }, - Memo: xdr.Memo{ - Type: xdr.MemoTypeMemoText, - Text: &memoText, - }, - Cond: xdr.Preconditions{ - Type: 2, - V2: &xdr.PreconditionsV2{ - TimeBounds: &xdr.TimeBounds{ - MinTime: xdr.TimePoint(1), - MaxTime: xdr.TimePoint(10), - }, - LedgerBounds: &xdr.LedgerBounds{ - MinLedger: 2, - MaxLedger: 20, - }, - MinSeqNum: &minSeqNum, - MinSeqAge: 456, - MinSeqLedgerGap: 789, - }, - }, - Ext: xdr.TransactionExt{ - V: 1, - SorobanData: &xdr.SorobanTransactionData{ - Resources: xdr.SorobanResources{ - Instructions: 123, - ReadBytes: 456, - WriteBytes: 789, - Footprint: xdr.LedgerFootprint{ - ReadOnly: []xdr.LedgerKey{ - { - Type: 6, - ContractData: &xdr.LedgerKeyContractData{ - Contract: xdr.ScAddress{ - Type: 1, - ContractId: &xdr.Hash{0x12, 0x34}, - }, - Key: xdr.ScVal{ - Type: 0, - B: &dummyBool, - }, - }, - }, - }, - }, - }, - ResourceFee: 1234, - }, - }, - }, - }, - }, - Result: xdr.TransactionResultPair{ - TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, - Result: xdr.TransactionResult{ - FeeCharged: xdr.Int64(789), - Result: xdr.TransactionResultResult{ - Code: 0, - Results: &[]xdr.OperationResult{ - { - Code: 0, - Tr: &xdr.OperationResultTr{ - Type: 2, - PathPaymentStrictReceiveResult: &xdr.PathPaymentStrictReceiveResult{ - Code: 0, - Success: &xdr.PathPaymentStrictReceiveResultSuccess{}, - NoIssuer: &xdr.Asset{}, - }, - }, - }, - {}, - {}, - { - Code: 0, - Tr: &xdr.OperationResultTr{ - Type: 2, - PathPaymentStrictReceiveResult: &xdr.PathPaymentStrictReceiveResult{ - Code: 0, - Success: &xdr.PathPaymentStrictReceiveResultSuccess{}, - NoIssuer: &xdr.Asset{}, - }, - }, - }, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - { - Code: 0, - Tr: &xdr.OperationResultTr{ - Type: 13, - PathPaymentStrictSendResult: &xdr.PathPaymentStrictSendResult{ - Code: 0, - Success: &xdr.PathPaymentStrictSendResultSuccess{ - Last: xdr.SimplePaymentResult{ - Amount: 640000000, - }, - }, - NoIssuer: &xdr.Asset{}, - }, - }, - }, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - { - Code: 0, - Tr: &xdr.OperationResultTr{ - Type: 22, - LiquidityPoolDepositResult: &xdr.LiquidityPoolDepositResult{ - Code: 0, - }, - }, - }, - { - Code: 0, - Tr: &xdr.OperationResultTr{ - Type: 23, - LiquidityPoolWithdrawResult: &xdr.LiquidityPoolWithdrawResult{ - Code: 0, - }, - }, - }, - {}, - }, - }, - }, - }, - FeeChanges: xdr.LedgerEntryChanges{ - { - Type: xdr.LedgerEntryChangeTypeLedgerEntryState, - State: &xdr.LedgerEntry{ - Data: xdr.LedgerEntryData{ - Type: xdr.LedgerEntryTypeAccount, - Account: &xdr.AccountEntry{ - AccountId: xdr.AccountId{ - Type: 0, - Ed25519: &ed25519, - }, - Balance: 1000, - }, - }, - }, - }, - {}, - }, - UnsafeMeta: xdr.TransactionMeta{ - V: 3, - V3: &xdr.TransactionMetaV3{ - TxChangesAfter: xdr.LedgerEntryChanges{}, - SorobanMeta: &xdr.SorobanTransactionMeta{ - Ext: xdr.SorobanTransactionMetaExt{ - V: 1, - V1: &xdr.SorobanTransactionMetaExtV1{ - TotalNonRefundableResourceFeeCharged: 321, - TotalRefundableResourceFeeCharged: 123, - RentFeeCharged: 456, - }, - }, - }, - Operations: []xdr.OperationMeta{ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - { - Changes: []xdr.LedgerEntryChange{ - { - Type: 3, - State: &xdr.LedgerEntry{ - Data: xdr.LedgerEntryData{ - Type: 5, - LiquidityPool: &xdr.LiquidityPoolEntry{ - LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, - Body: xdr.LiquidityPoolEntryBody{ - Type: 0, - ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ - Params: xdr.LiquidityPoolConstantProductParameters{ - AssetA: xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - }, - AssetB: xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - }, - Fee: 1, - }, - ReserveA: 1, - ReserveB: 1, - TotalPoolShares: 1, - PoolSharesTrustLineCount: 1, - }, - }, - }, - }, - }, - }, - { - Type: 1, - Updated: &xdr.LedgerEntry{ - Data: xdr.LedgerEntryData{ - Type: 5, - LiquidityPool: &xdr.LiquidityPoolEntry{ - LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, - Body: xdr.LiquidityPoolEntryBody{ - Type: 0, - ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ - Params: xdr.LiquidityPoolConstantProductParameters{ - AssetA: xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - }, - AssetB: xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - }, - Fee: 1, - }, - ReserveA: 2, - ReserveB: 2, - TotalPoolShares: 2, - PoolSharesTrustLineCount: 1, - }, - }, - }, - }, - }, - }, - }, - }, - { - Changes: []xdr.LedgerEntryChange{ - { - Type: 3, - State: &xdr.LedgerEntry{ - Data: xdr.LedgerEntryData{ - Type: 5, - LiquidityPool: &xdr.LiquidityPoolEntry{ - LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, - Body: xdr.LiquidityPoolEntryBody{ - Type: 0, - ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ - Params: xdr.LiquidityPoolConstantProductParameters{ - AssetA: xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - }, - AssetB: xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - }, - Fee: 1, - }, - ReserveA: 1, - ReserveB: 1, - TotalPoolShares: 1, - PoolSharesTrustLineCount: 1, - }, - }, - }, - }, - }, - }, - { - Type: 1, - Updated: &xdr.LedgerEntry{ - Data: xdr.LedgerEntryData{ - Type: 5, - LiquidityPool: &xdr.LiquidityPoolEntry{ - LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, - Body: xdr.LiquidityPoolEntryBody{ - Type: 0, - ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ - Params: xdr.LiquidityPoolConstantProductParameters{ - AssetA: xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - }, - AssetB: xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - }, - Fee: 1, - }, - ReserveA: 2, - ReserveB: 2, - TotalPoolShares: 2, - PoolSharesTrustLineCount: 1, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - LedgerVersion: 22, - Ledger: ledgerTestInput(), - Hash: xdr.Hash{}, - } - - return transaction -} - -type testOutput struct { - err error - result interface{} -} - -func operationTestInput() []xdr.Operation { - testAccountAddress := "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA" - testAccountID, _ := xdr.AddressToAccountId(testAccountAddress) - testAccountMuxed := testAccountID.ToMuxedAccount() - - sourceAccountAddress := "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN" - sourceAccountID, _ := xdr.AddressToAccountId(sourceAccountAddress) - sourceAccountMuxed := sourceAccountID.ToMuxedAccount() - - usdtAsset := xdr.Asset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), - Issuer: testAccountID, - }, - } - assetCode, _ := usdtAsset.ToAssetCode("USDT") - nativeAsset := xdr.MustNewNativeAsset() - - clearFlags := xdr.Uint32(3) - setFlags := xdr.Uint32(4) - masterWeight := xdr.Uint32(3) - lowThresh := xdr.Uint32(1) - medThresh := xdr.Uint32(3) - highThresh := xdr.Uint32(5) - homeDomain := xdr.String32("2019=DRA;n-test") - signerKey, _ := xdr.NewSignerKey(xdr.SignerKeyTypeSignerKeyTypeEd25519, xdr.Uint256([32]byte{})) - signer := xdr.Signer{ - Key: signerKey, - Weight: xdr.Uint32(1), - } - - usdtChangeTrustAsset := xdr.ChangeTrustAsset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x53, 0x44}), - Issuer: testAccountID, - }, - } - - usdtLiquidityPoolShare := xdr.ChangeTrustAsset{ - Type: xdr.AssetTypeAssetTypePoolShare, - LiquidityPool: &xdr.LiquidityPoolParameters{ - Type: xdr.LiquidityPoolTypeLiquidityPoolConstantProduct, - ConstantProduct: &xdr.LiquidityPoolConstantProductParameters{ - AssetA: nativeAsset, - AssetB: usdtAsset, - Fee: 30, - }, - }, - } - - dataValue := xdr.DataValue([]byte{0x76, 0x61, 0x6c, 0x75, 0x65}) - - testClaimant := xdr.Claimant{ - Type: xdr.ClaimantTypeClaimantTypeV0, - V0: &xdr.ClaimantV0{ - Destination: testAccountID, - Predicate: xdr.ClaimPredicate{ - Type: xdr.ClaimPredicateTypeClaimPredicateUnconditional, - }, - }, - } - - claimableBalance := xdr.ClaimableBalanceId{ - Type: xdr.ClaimableBalanceIdTypeClaimableBalanceIdTypeV0, - V0: &xdr.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9}, - } - - contractHash := xdr.Hash{0x12, 0x34, 0x56, 0x78} - salt := [32]byte{0x12, 0x34, 0x56} - wasm := []byte{0x12, 0x34} - dummyBool := true - - operation := []xdr.Operation{ - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeCreateAccount, - CreateAccountOp: &xdr.CreateAccountOp{ - StartingBalance: 25000000, - Destination: testAccountID, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypePayment, - PaymentOp: &xdr.PaymentOp{ - Destination: testAccountMuxed, - Asset: usdtAsset, - Amount: 350000000, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypePayment, - PaymentOp: &xdr.PaymentOp{ - Destination: testAccountMuxed, - Asset: nativeAsset, - Amount: 350000000, - }, - }, - }, - { - SourceAccount: &sourceAccountMuxed, - Body: xdr.OperationBody{ - Type: xdr.OperationTypePathPaymentStrictReceive, - PathPaymentStrictReceiveOp: &xdr.PathPaymentStrictReceiveOp{ - SendAsset: nativeAsset, - SendMax: 8951495900, - Destination: testAccountMuxed, - DestAsset: nativeAsset, - DestAmount: 8951495900, - Path: []xdr.Asset{usdtAsset}, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeManageSellOffer, - ManageSellOfferOp: &xdr.ManageSellOfferOp{ - Selling: usdtAsset, - Buying: nativeAsset, - Amount: 765860000, - Price: xdr.Price{ - N: 128523, - D: 250000, - }, - OfferId: 0, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeCreatePassiveSellOffer, - CreatePassiveSellOfferOp: &xdr.CreatePassiveSellOfferOp{ - Selling: nativeAsset, - Buying: usdtAsset, - Amount: 631595000, - Price: xdr.Price{ - N: 99583200, - D: 1257990000, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeSetOptions, - SetOptionsOp: &xdr.SetOptionsOp{ - InflationDest: &testAccountID, - ClearFlags: &clearFlags, - SetFlags: &setFlags, - MasterWeight: &masterWeight, - LowThreshold: &lowThresh, - MedThreshold: &medThresh, - HighThreshold: &highThresh, - HomeDomain: &homeDomain, - Signer: &signer, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeChangeTrust, - ChangeTrustOp: &xdr.ChangeTrustOp{ - Line: usdtChangeTrustAsset, - Limit: xdr.Int64(500000000000000000), - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeChangeTrust, - ChangeTrustOp: &xdr.ChangeTrustOp{ - Line: usdtLiquidityPoolShare, - Limit: xdr.Int64(500000000000000000), - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeAllowTrust, - AllowTrustOp: &xdr.AllowTrustOp{ - Trustor: testAccountID, - Asset: assetCode, - Authorize: xdr.Uint32(1), - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeAccountMerge, - Destination: &testAccountMuxed, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeInflation, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeManageData, - ManageDataOp: &xdr.ManageDataOp{ - DataName: "test", - DataValue: &dataValue, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeBumpSequence, - BumpSequenceOp: &xdr.BumpSequenceOp{ - BumpTo: xdr.SequenceNumber(100), - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeManageBuyOffer, - ManageBuyOfferOp: &xdr.ManageBuyOfferOp{ - Selling: usdtAsset, - Buying: nativeAsset, - BuyAmount: 7654501001, - Price: xdr.Price{ - N: 635863285, - D: 1818402817, - }, - OfferId: 100, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypePathPaymentStrictSend, - PathPaymentStrictSendOp: &xdr.PathPaymentStrictSendOp{ - SendAsset: nativeAsset, - SendAmount: 1598182, - Destination: testAccountMuxed, - DestAsset: nativeAsset, - DestMin: 4280460538, - Path: []xdr.Asset{usdtAsset}, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeCreateClaimableBalance, - CreateClaimableBalanceOp: &xdr.CreateClaimableBalanceOp{ - Asset: usdtAsset, - Amount: 1234567890000, - Claimants: []xdr.Claimant{testClaimant}, - }, - }, - }, - { - SourceAccount: &sourceAccountMuxed, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeClaimClaimableBalance, - ClaimClaimableBalanceOp: &xdr.ClaimClaimableBalanceOp{ - BalanceId: claimableBalance, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeBeginSponsoringFutureReserves, - BeginSponsoringFutureReservesOp: &xdr.BeginSponsoringFutureReservesOp{ - SponsoredId: testAccountID, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeRevokeSponsorship, - RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ - Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipSigner, - Signer: &xdr.RevokeSponsorshipOpSigner{ - AccountId: testAccountID, - SignerKey: signer.Key, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeRevokeSponsorship, - RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ - Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, - LedgerKey: &xdr.LedgerKey{ - Type: xdr.LedgerEntryTypeAccount, - Account: &xdr.LedgerKeyAccount{ - AccountId: testAccountID, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeRevokeSponsorship, - RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ - Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, - LedgerKey: &xdr.LedgerKey{ - Type: xdr.LedgerEntryTypeClaimableBalance, - ClaimableBalance: &xdr.LedgerKeyClaimableBalance{ - BalanceId: claimableBalance, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeRevokeSponsorship, - RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ - Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, - LedgerKey: &xdr.LedgerKey{ - Type: xdr.LedgerEntryTypeData, - Data: &xdr.LedgerKeyData{ - AccountId: testAccountID, - DataName: "test", - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeRevokeSponsorship, - RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ - Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, - LedgerKey: &xdr.LedgerKey{ - Type: xdr.LedgerEntryTypeOffer, - Offer: &xdr.LedgerKeyOffer{ - SellerId: testAccountID, - OfferId: 100, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeRevokeSponsorship, - RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ - Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, - LedgerKey: &xdr.LedgerKey{ - Type: xdr.LedgerEntryTypeTrustline, - TrustLine: &xdr.LedgerKeyTrustLine{ - AccountId: testAccountID, - Asset: xdr.TrustLineAsset{ - Type: xdr.AssetTypeAssetTypeCreditAlphanum4, - AlphaNum4: &xdr.AlphaNum4{ - AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x54, 0x54}), - Issuer: testAccountID, - }, - }, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeRevokeSponsorship, - RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ - Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, - LedgerKey: &xdr.LedgerKey{ - Type: xdr.LedgerEntryTypeLiquidityPool, - LiquidityPool: &xdr.LedgerKeyLiquidityPool{ - LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeClawback, - ClawbackOp: &xdr.ClawbackOp{ - Asset: usdtAsset, - From: testAccountMuxed, - Amount: 1598182, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeClawbackClaimableBalance, - ClawbackClaimableBalanceOp: &xdr.ClawbackClaimableBalanceOp{ - BalanceId: claimableBalance, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeSetTrustLineFlags, - SetTrustLineFlagsOp: &xdr.SetTrustLineFlagsOp{ - Trustor: testAccountID, - Asset: usdtAsset, - SetFlags: setFlags, - ClearFlags: clearFlags, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeLiquidityPoolDeposit, - LiquidityPoolDepositOp: &xdr.LiquidityPoolDepositOp{ - LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, - MaxAmountA: 1000, - MaxAmountB: 100, - MinPrice: xdr.Price{ - N: 1, - D: 1000000, - }, - MaxPrice: xdr.Price{ - N: 1000000, - D: 1, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeLiquidityPoolWithdraw, - LiquidityPoolWithdrawOp: &xdr.LiquidityPoolWithdrawOp{ - LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, - Amount: 4, - MinAmountA: 1, - MinAmountB: 1, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeInvokeHostFunction, - InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ - HostFunction: xdr.HostFunction{ - Type: xdr.HostFunctionTypeHostFunctionTypeInvokeContract, - InvokeContract: &xdr.InvokeContractArgs{ - ContractAddress: xdr.ScAddress{ - Type: xdr.ScAddressTypeScAddressTypeContract, - ContractId: &contractHash, - }, - FunctionName: "test", - Args: []xdr.ScVal{}, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeInvokeHostFunction, - InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ - HostFunction: xdr.HostFunction{ - Type: xdr.HostFunctionTypeHostFunctionTypeCreateContract, - CreateContract: &xdr.CreateContractArgs{ - ContractIdPreimage: xdr.ContractIdPreimage{ - Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAddress, - FromAddress: &xdr.ContractIdPreimageFromAddress{ - Address: xdr.ScAddress{ - Type: xdr.ScAddressTypeScAddressTypeContract, - ContractId: &contractHash, - }, - Salt: salt, - }, - }, - Executable: xdr.ContractExecutable{}, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeInvokeHostFunction, - InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ - HostFunction: xdr.HostFunction{ - Type: xdr.HostFunctionTypeHostFunctionTypeCreateContract, - CreateContract: &xdr.CreateContractArgs{ - ContractIdPreimage: xdr.ContractIdPreimage{ - Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAsset, - FromAsset: &usdtAsset, - }, - Executable: xdr.ContractExecutable{}, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeInvokeHostFunction, - InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ - HostFunction: xdr.HostFunction{ - Type: xdr.HostFunctionTypeHostFunctionTypeCreateContractV2, - CreateContractV2: &xdr.CreateContractArgsV2{ - ContractIdPreimage: xdr.ContractIdPreimage{ - Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAsset, - FromAsset: &usdtAsset, - }, - Executable: xdr.ContractExecutable{}, - ConstructorArgs: []xdr.ScVal{ - { - Type: xdr.ScValTypeScvBool, - B: &dummyBool, - }, - }, - }, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeInvokeHostFunction, - InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ - HostFunction: xdr.HostFunction{ - Type: xdr.HostFunctionTypeHostFunctionTypeUploadContractWasm, - Wasm: &wasm, - }, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeExtendFootprintTtl, - ExtendFootprintTtlOp: &xdr.ExtendFootprintTtlOp{ - Ext: xdr.ExtensionPoint{ - V: 0, - }, - ExtendTo: 1234, - }, - }, - }, - { - SourceAccount: nil, - Body: xdr.OperationBody{ - Type: xdr.OperationTypeRestoreFootprint, - RestoreFootprintOp: &xdr.RestoreFootprintOp{ - Ext: xdr.ExtensionPoint{ - V: 0, - }, - }, - }, - }, - } - - return operation -} - -func resultTestOutput() []testOutput { - output := []testOutput{ - { - err: nil, - result: CreateAccountDetail{ - Account: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - Funder: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - FunderMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - FunderMuxedID: uint64(123), - StartingBalance: int64(25000000)}, - }, - { - err: nil, - result: PaymentDetail{ - Amount: int64(350000000), - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - FromMuxedID: uint64(123), - To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, - }, - { - err: nil, - result: PaymentDetail{ - Amount: int64(350000000), - AssetType: "native", - From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - FromMuxedID: uint64(123), - To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, - }, - { - err: nil, - result: PathPaymentStrictReceiveDetail{ - Amount: int64(8951495900), - AssetType: "native", - From: "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", - Path: []Path{ - { - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - }, - }, - SourceAmount: int64(0), - SourceAssetType: "native", - SourceMax: int64(8951495900), - To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, - }, - { - err: nil, - result: ManageSellOffer{ - Amount: int64(765860000), - BuyingAssetType: "native", - OfferID: int64(0), - Price: 0.514092, - PriceN: 128523, - PriceD: 250000, - SellingAssetCode: "USDT", - SellingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - SellingAssetType: "credit_alphanum4"}, - }, - { - err: nil, - result: CreatePassiveSellOfferDetail{ - Amount: int64(631595000), - BuyingAssetCode: "USDT", - BuyingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - BuyingAssetType: "credit_alphanum4", - Price: 0.0791606, - PriceN: 99583200, - PriceD: 1257990000, - SellingAssetType: "native"}, - }, - { - err: nil, - result: SetOptionsDetails{ - ClearFlags: []int32{1, 2}, - ClearFlagsString: []string{"auth_required", "auth_revocable"}, - HighThreshold: uint32(5), - HomeDomain: "2019=DRA;n-test", - InflationDestination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - LowThreshold: uint32(1), - MasterKeyWeight: uint32(3), - MediumThreshold: uint32(3), - SetFlags: []int32{4}, - SetFlagsString: []string{"auth_immutable"}, - SignerKey: "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", - SignerWeight: uint32(1)}, - }, - { - err: nil, - result: ChangeTrustDetail{ - AssetCode: "USSD", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - Limit: int64(500000000000000000), - Trustee: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - Trustor: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - TrustorMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - TrustorMuxedID: uint64(123)}, - }, - { - err: nil, - result: ChangeTrustDetail{ - AssetType: "liquidity_pool_shares", - Limit: int64(500000000000000000), - LiquidityPoolID: "HCYdbHWTAgSnO0gMMCCrUl6b5IzpPeYZTPafsG8HRS0=", - Trustor: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - TrustorMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - TrustorMuxedID: uint64(123)}, - }, - { - err: nil, - result: AllowTrustDetail{ - AssetCode: "USDT", - AssetIssuer: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - AssetType: "credit_alphanum4", - Authorize: true, - Trustee: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - TrusteeMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - TrusteeMuxedID: uint64(123), - Trustor: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, - }, - { - err: nil, - result: AccountMergeDetail{ - Account: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - AccountMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - AccountMuxedID: uint64(123), - Into: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, - }, - { - err: nil, - result: InflationDetail{}, - }, - { - err: nil, - result: ManageDataDetail{ - Name: "test", - Value: "dmFsdWU=", - }, - }, - { - err: nil, - result: BumpSequenceDetails{ - BumpTo: int64(100), - }, - }, - { - err: nil, - result: ManageBuyOffer{ - Amount: int64(7654501001), - BuyingAssetType: "native", - OfferID: int64(100), - Price: 0.3496823, - PriceN: 635863285, - PriceD: 1818402817, - SellingAssetCode: "USDT", - SellingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - SellingAssetType: "credit_alphanum4"}, - }, - { - err: nil, - result: PathPaymentStrictSendDetail{ - Amount: int64(640000000), - AssetType: "native", - DestinationMin: 4280460538, - From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", - FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", - FromMuxedID: uint64(123), - Path: []Path{ - { - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - }, - }, - SourceAmount: int64(1598182), - SourceAssetType: "native", - To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, - }, - { - err: nil, - result: CreateClaimableBalanceDetail{ - Amount: int64(1234567890000), - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - Claimants: []Claimant{ - { - Destination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - Predicate: xdr.ClaimPredicate{ - Type: 0, - AndPredicates: (*[]xdr.ClaimPredicate)(nil), - OrPredicates: (*[]xdr.ClaimPredicate)(nil), - NotPredicate: (**xdr.ClaimPredicate)(nil), - AbsBefore: (*xdr.Int64)(nil), - RelBefore: (*xdr.Int64)(nil), - }, - }, - }, - }, - }, - { - err: nil, - result: ClaimClaimableBalanceDetail{ - BalanceID: "AAAAAAECAwQFBgcICQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - Claimant: "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", - }, - }, - { - err: nil, - result: BeginSponsoringFutureReservesDetail{ - SponsoredID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - }, - }, - { - err: nil, - result: RevokeSponsorshipDetail{ - SignerAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - SignerKey: "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", - }, - }, - { - err: nil, - result: RevokeSponsorshipDetail{ - LedgerKeyDetails: LedgerKeyDetail{ - AccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - }, - }, - }, - { - err: nil, - result: RevokeSponsorshipDetail{ - LedgerKeyDetails: LedgerKeyDetail{ - ClaimableBalanceID: "000000000102030405060708090000000000000000000000000000000000000000000000", - }, - }, - }, - { - err: nil, - result: RevokeSponsorshipDetail{ - LedgerKeyDetails: LedgerKeyDetail{ - DataAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - DataName: "test", - }, - }, - }, - { - err: nil, - result: RevokeSponsorshipDetail{ - LedgerKeyDetails: LedgerKeyDetail{ - OfferID: int64(100), - }, - }, - }, - { - err: nil, - result: RevokeSponsorshipDetail{ - LedgerKeyDetails: LedgerKeyDetail{ - TrustlineAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - TrustlineAssetCode: "USTT", - TrustlineAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - TrustlineAssetType: "credit_alphanum4", - }, - }, - }, - { - err: nil, - result: RevokeSponsorshipDetail{ - LedgerKeyDetails: LedgerKeyDetail{ - LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - }, - }, - }, - { - err: nil, - result: ClawbackDetail{ - Amount: int64(1598182), - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - From: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - }, - }, - { - err: nil, - result: ClawbackClaimableBalanceDetail{ - BalanceID: "AAAAAAECAwQFBgcICQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - }, - }, - { - err: nil, - result: SetTrustlineFlagsDetail{ - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - ClearFlags: []int32{1, 2}, - ClearFlagsString: []string{"authorized", "authorized_to_maintain_liabilities"}, - SetFlags: []int32{4}, - SetFlagsString: []string{"clawback_enabled"}, - Trustor: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - }, - }, - { - err: nil, - result: LiquidityPoolDepositDetail{ - LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - MaxPrice: 1e+06, - MaxPriceN: 1000000, - MaxPriceD: 1, - MinPrice: 1e-06, - MinPriceN: 1, - MinPriceD: 1000000, - ReserveAssetA: ReserveAsset{ - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - DepositAmount: int64(1), - MaxAmount: int64(1000), - }, - ReserveAssetB: ReserveAsset{ - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - DepositAmount: 1, - MaxAmount: int64(100), - }, - SharesReceived: 1, - }, - }, - { - err: nil, - result: LiquidityPoolWithdrawDetail{ - LiquidityPoolID: "AQIDBAUGBwgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - ReserveAssetA: ReserveAsset{ - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - MinAmount: int64(1), - WithdrawAmount: int64(-1), - }, - - ReserveAssetB: ReserveAsset{ - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - MinAmount: int64(1), - WithdrawAmount: int64(-1), - }, - Shares: int64(4), - }, - }, - { - err: nil, - result: InvokeHostFunctionDetail{ - AssetBalanceChanges: []BalanceChangeDetail{}, - ContractID: "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", - Function: "HostFunctionTypeHostFunctionTypeInvokeContract", - LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - Parameters: []interface{}{ - json.RawMessage{ - 0x7b, 0x22, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3a, 0x22, 0x43, 0x41, 0x4a, 0x44, - 0x49, 0x56, 0x54, 0x59, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x42, 0x52, 0x33, 0x37, 0x22, 0x7d, - }, - json.RawMessage{0x7b, 0x22, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x22, 0x3a, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x7d}, - }, - Type: "invoke_contract", - }, - }, - { - err: nil, - result: InvokeHostFunctionDetail{ - Address: "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", - ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - From: "address", - Function: "HostFunctionTypeHostFunctionTypeCreateContract", - LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - Type: "create_contract", - }, - }, - { - err: nil, - result: InvokeHostFunctionDetail{ - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - From: "asset", - Function: "HostFunctionTypeHostFunctionTypeCreateContract", - LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - Type: "create_contract", - }, - }, - { - err: nil, - result: InvokeHostFunctionDetail{ - AssetCode: "USDT", - AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", - AssetType: "credit_alphanum4", - ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - From: "asset", - Function: "HostFunctionTypeHostFunctionTypeCreateContractV2", - LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - Parameters: []interface{}{ - json.RawMessage{0x7b, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x22, 0x3a, 0x74, 0x72, 0x75, 0x65, 0x7d}, - }, - Type: "create_contract_v2", - }, - }, - { - err: nil, - result: InvokeHostFunctionDetail{ - Function: "HostFunctionTypeHostFunctionTypeUploadContractWasm", - LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - Type: "upload_wasm", - }, - }, - { - err: nil, - result: ExtendFootprintTtlDetail{ - ExtendTo: uint32(1234), - LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - Type: "extend_footprint_ttl", - }, - }, - { - err: nil, - result: RestoreFootprintDetail{ - LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, - ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", - Type: "restore_footprint", - }, - }, - } - - return output -} diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index feaadce7fc..b634568eee 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -618,22 +618,6 @@ func (t *LedgerTransaction) Successful() bool { return t.Result.Successful() } -func (t *LedgerTransaction) GetOperations(networkPassphrase string) []LedgerOperation { - var ledgerOperations []LedgerOperation - - for i, operation := range t.Envelope.Operations() { - ledgerOperation := LedgerOperation{ - OperationIndex: int32(i), - Operation: operation, - Transaction: t, - NetworkPassphrase: networkPassphrase, - } - ledgerOperations = append(ledgerOperations, ledgerOperation) - } - - return ledgerOperations -} - func (t *LedgerTransaction) GetTransactionV1Envelope() (xdr.TransactionV1Envelope, bool) { switch t.Envelope.Type { case xdr.EnvelopeTypeEnvelopeTypeTx: @@ -723,7 +707,7 @@ func (t *LedgerTransaction) contractCodeFromContractData(ledgerKey xdr.LedgerKey return codeHash, true } -func (t *LedgerTransaction) contractIdFromTxEnvelope() (string, bool) { +func (t *LedgerTransaction) ContractIdFromTxEnvelope() (string, bool) { v1Envelope, ok := t.GetTransactionV1Envelope() if !ok { return "", false diff --git a/ingest/account_merge_details.go b/ingest/processors/operation_processor/account_merge_details.go similarity index 98% rename from ingest/account_merge_details.go rename to ingest/processors/operation_processor/account_merge_details.go index f75ed00d1a..268b606945 100644 --- a/ingest/account_merge_details.go +++ b/ingest/processors/operation_processor/account_merge_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import "fmt" diff --git a/ingest/allow_trust_details.go b/ingest/processors/operation_processor/allow_trust_details.go similarity index 99% rename from ingest/allow_trust_details.go rename to ingest/processors/operation_processor/allow_trust_details.go index 3c3785c88b..cf841d2cc3 100644 --- a/ingest/allow_trust_details.go +++ b/ingest/processors/operation_processor/allow_trust_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/begin_sponsoring_future_reserve_details.go b/ingest/processors/operation_processor/begin_sponsoring_future_reserve_details.go similarity index 96% rename from ingest/begin_sponsoring_future_reserve_details.go rename to ingest/processors/operation_processor/begin_sponsoring_future_reserve_details.go index ea0c255468..c2a1dd7fd8 100644 --- a/ingest/begin_sponsoring_future_reserve_details.go +++ b/ingest/processors/operation_processor/begin_sponsoring_future_reserve_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import "fmt" diff --git a/ingest/bump_sequence_details.go b/ingest/processors/operation_processor/bump_sequence_details.go similarity index 95% rename from ingest/bump_sequence_details.go rename to ingest/processors/operation_processor/bump_sequence_details.go index abeb2a4e52..355146d8b1 100644 --- a/ingest/bump_sequence_details.go +++ b/ingest/processors/operation_processor/bump_sequence_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import "fmt" diff --git a/ingest/change_trust_details.go b/ingest/processors/operation_processor/change_trust_details.go similarity index 95% rename from ingest/change_trust_details.go rename to ingest/processors/operation_processor/change_trust_details.go index ca3040bd2d..fda755d638 100644 --- a/ingest/change_trust_details.go +++ b/ingest/processors/operation_processor/change_trust_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" @@ -76,10 +76,7 @@ func getLiquidityPoolAssetDetails(lpp xdr.LiquidityPoolParameters) (string, stri return "", "", err } - poolIDString, err = PoolIDToString(poolID) - if err != nil { - return "", "", err - } + poolIDString = PoolIDToString(poolID) return "liquidity_pool_shares", poolIDString, nil } diff --git a/ingest/claim_claimable_balance_details.go b/ingest/processors/operation_processor/claim_claimable_balance_details.go similarity index 98% rename from ingest/claim_claimable_balance_details.go rename to ingest/processors/operation_processor/claim_claimable_balance_details.go index 69d85950ad..a1b412a924 100644 --- a/ingest/claim_claimable_balance_details.go +++ b/ingest/processors/operation_processor/claim_claimable_balance_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/clawback_claimable_balance_details.go b/ingest/processors/operation_processor/clawback_claimable_balance_details.go similarity index 97% rename from ingest/clawback_claimable_balance_details.go rename to ingest/processors/operation_processor/clawback_claimable_balance_details.go index 5a8e19f796..3f46fd5b0a 100644 --- a/ingest/clawback_claimable_balance_details.go +++ b/ingest/processors/operation_processor/clawback_claimable_balance_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/clawback_details.go b/ingest/processors/operation_processor/clawback_details.go similarity index 98% rename from ingest/clawback_details.go rename to ingest/processors/operation_processor/clawback_details.go index ff84f41705..d21452eea6 100644 --- a/ingest/clawback_details.go +++ b/ingest/processors/operation_processor/clawback_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import "fmt" diff --git a/ingest/create_account_details.go b/ingest/processors/operation_processor/create_account_details.go similarity index 98% rename from ingest/create_account_details.go rename to ingest/processors/operation_processor/create_account_details.go index 9eed63cc2d..4a7647eff8 100644 --- a/ingest/create_account_details.go +++ b/ingest/processors/operation_processor/create_account_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/create_claimable_balance_details.go b/ingest/processors/operation_processor/create_claimable_balance_details.go similarity index 98% rename from ingest/create_claimable_balance_details.go rename to ingest/processors/operation_processor/create_claimable_balance_details.go index 0aefcf1ffb..3a79d80c1f 100644 --- a/ingest/create_claimable_balance_details.go +++ b/ingest/processors/operation_processor/create_claimable_balance_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/create_passive_sell_offer_details.go b/ingest/processors/operation_processor/create_passive_sell_offer_details.go similarity index 99% rename from ingest/create_passive_sell_offer_details.go rename to ingest/processors/operation_processor/create_passive_sell_offer_details.go index 2ee8791b8c..b8247fb588 100644 --- a/ingest/create_passive_sell_offer_details.go +++ b/ingest/processors/operation_processor/create_passive_sell_offer_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/end_sponsoring_future_reserve_details.go b/ingest/processors/operation_processor/end_sponsoring_future_reserve_details.go similarity index 99% rename from ingest/end_sponsoring_future_reserve_details.go rename to ingest/processors/operation_processor/end_sponsoring_future_reserve_details.go index c2d6f609e3..f719b3a3e8 100644 --- a/ingest/end_sponsoring_future_reserve_details.go +++ b/ingest/processors/operation_processor/end_sponsoring_future_reserve_details.go @@ -1,4 +1,4 @@ -package ingest +package operation type EndSponsoringFutureReserveDetail struct { BeginSponsor string `json:"begin_sponsor"` diff --git a/ingest/extend_footprint_ttl_details.go b/ingest/processors/operation_processor/extend_footprint_ttl_details.go similarity index 93% rename from ingest/extend_footprint_ttl_details.go rename to ingest/processors/operation_processor/extend_footprint_ttl_details.go index 8889077e03..091a6bebc5 100644 --- a/ingest/extend_footprint_ttl_details.go +++ b/ingest/processors/operation_processor/extend_footprint_ttl_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import "fmt" @@ -23,7 +23,7 @@ func (o *LedgerOperation) ExtendFootprintTtlDetails() (ExtendFootprintTtlDetail, } var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() + contractID, ok = o.Transaction.ContractIdFromTxEnvelope() if ok { extendFootprintTtlDetail.ContractID = contractID } diff --git a/ingest/inflation_details.go b/ingest/processors/operation_processor/inflation_details.go similarity index 88% rename from ingest/inflation_details.go rename to ingest/processors/operation_processor/inflation_details.go index 6eda8adea1..833a822465 100644 --- a/ingest/inflation_details.go +++ b/ingest/processors/operation_processor/inflation_details.go @@ -1,4 +1,4 @@ -package ingest +package operation type InflationDetail struct{} diff --git a/ingest/invoke_host_function_details.go b/ingest/processors/operation_processor/invoke_host_function_details.go similarity index 95% rename from ingest/invoke_host_function_details.go rename to ingest/processors/operation_processor/invoke_host_function_details.go index 69a74f8d16..c7159692b5 100644 --- a/ingest/invoke_host_function_details.go +++ b/ingest/processors/operation_processor/invoke_host_function_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" @@ -72,7 +72,7 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, invokeHostFunctionDetail.Type = "create_contract" - preImageDetails, err := switchContractIdPreimageType(args.ContractIdPreimage) + preImageDetails, err := switchContractIdPreimage(args.ContractIdPreimage) if err != nil { return InvokeHostFunctionDetail{}, nil } @@ -92,7 +92,7 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, invokeHostFunctionDetail.Type = "create_contract_v2" - preImageDetails, err := switchContractIdPreimageType(args.ContractIdPreimage) + preImageDetails, err := switchContractIdPreimage(args.ContractIdPreimage) if err != nil { return InvokeHostFunctionDetail{}, err } @@ -118,7 +118,7 @@ func (o *LedgerOperation) getCreateContractDetails(invokeHostFunctionDetail *Inv invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() + contractID, ok = o.Transaction.ContractIdFromTxEnvelope() if ok { invokeHostFunctionDetail.ContractID = contractID } diff --git a/ingest/liquidity_pool_deposit_details.go b/ingest/processors/operation_processor/liquidity_pool_deposit_details.go similarity index 95% rename from ingest/liquidity_pool_deposit_details.go rename to ingest/processors/operation_processor/liquidity_pool_deposit_details.go index d4d38635f8..957372f773 100644 --- a/ingest/liquidity_pool_deposit_details.go +++ b/ingest/processors/operation_processor/liquidity_pool_deposit_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" @@ -50,11 +50,7 @@ func (o *LedgerOperation) LiquidityPoolDepositDetails() (LiquidityPoolDepositDet } var err error - var liquidityPoolID string - liquidityPoolID, err = PoolIDToString(op.LiquidityPoolId) - if err != nil { - return LiquidityPoolDepositDetail{}, err - } + liquidityPoolID := PoolIDToString(op.LiquidityPoolId) liquidityPoolDepositDetail.LiquidityPoolID = liquidityPoolID diff --git a/ingest/liquidity_pool_withdraw_details.go b/ingest/processors/operation_processor/liquidity_pool_withdraw_details.go similarity index 93% rename from ingest/liquidity_pool_withdraw_details.go rename to ingest/processors/operation_processor/liquidity_pool_withdraw_details.go index 44d750fbab..1db6c652da 100644 --- a/ingest/liquidity_pool_withdraw_details.go +++ b/ingest/processors/operation_processor/liquidity_pool_withdraw_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" @@ -30,11 +30,7 @@ func (o *LedgerOperation) LiquidityPoolWithdrawDetails() (LiquidityPoolWithdrawD } var err error - var liquidityPoolID string - liquidityPoolID, err = PoolIDToString(op.LiquidityPoolId) - if err != nil { - return LiquidityPoolWithdrawDetail{}, err - } + liquidityPoolID := PoolIDToString(op.LiquidityPoolId) liquidityPoolWithdrawDetail.LiquidityPoolID = liquidityPoolID diff --git a/ingest/manage_buy_offer_details.go b/ingest/processors/operation_processor/manage_buy_offer_details.go similarity index 99% rename from ingest/manage_buy_offer_details.go rename to ingest/processors/operation_processor/manage_buy_offer_details.go index 81e39982a8..66579ebdf5 100644 --- a/ingest/manage_buy_offer_details.go +++ b/ingest/processors/operation_processor/manage_buy_offer_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/manage_data_details.go b/ingest/processors/operation_processor/manage_data_details.go similarity index 97% rename from ingest/manage_data_details.go rename to ingest/processors/operation_processor/manage_data_details.go index ce52817130..87ba2a516e 100644 --- a/ingest/manage_data_details.go +++ b/ingest/processors/operation_processor/manage_data_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "encoding/base64" diff --git a/ingest/manage_sell_offer_details.go b/ingest/processors/operation_processor/manage_sell_offer_details.go similarity index 99% rename from ingest/manage_sell_offer_details.go rename to ingest/processors/operation_processor/manage_sell_offer_details.go index 5fc7811ce1..e24f91eaa0 100644 --- a/ingest/manage_sell_offer_details.go +++ b/ingest/processors/operation_processor/manage_sell_offer_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/processors/operation_processor/operation.go b/ingest/processors/operation_processor/operation.go index 0a80367e40..2421b0f1ef 100644 --- a/ingest/processors/operation_processor/operation.go +++ b/ingest/processors/operation_processor/operation.go @@ -3,9 +3,11 @@ package operation import ( "encoding/base64" "fmt" + "math/big" "strconv" "time" + "github.com/dgryski/go-farm" "github.com/guregu/null" "github.com/pkg/errors" @@ -2220,3 +2222,592 @@ func switchContractIdPreimageType(contractIdPreimage xdr.ContractIdPreimage) map return details } + +type LedgerOperation struct { + OperationIndex int32 + Operation xdr.Operation + Transaction *ingest.LedgerTransaction + NetworkPassphrase string +} + +func (o *LedgerOperation) sourceAccountXDR() xdr.MuxedAccount { + sourceAccount := o.Operation.SourceAccount + if sourceAccount != nil { + return *sourceAccount + } + + return o.Transaction.Envelope.SourceAccount() +} + +func (o *LedgerOperation) SourceAccount() string { + muxedAccount := o.sourceAccountXDR() + return muxedAccount.ToAccountId().Address() +} + +func (o *LedgerOperation) Type() int32 { + return int32(o.Operation.Body.Type) +} + +func (o *LedgerOperation) TypeString() string { + return xdr.OperationTypeToStringMap[o.Type()] +} + +func (o *LedgerOperation) ID() int64 { + //operationIndex needs +1 increment to stay in sync with ingest package + return toid.New(int32(o.Transaction.Ledger.LedgerSequence()), int32(o.Transaction.Index), o.OperationIndex+1).ToInt64() +} + +func (o *LedgerOperation) SourceAccountMuxed() (string, bool) { + muxedAccount := o.sourceAccountXDR() + if muxedAccount.Type != xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + return "", false + } + + return muxedAccount.Address(), true +} + +func (o *LedgerOperation) OperationResultCode() string { + var operationResultCode string + operationResults, ok := o.Transaction.Result.Result.OperationResults() + if ok { + operationResultCode = operationResults[o.OperationIndex].Code.String() + } + + return operationResultCode +} + +func (o *LedgerOperation) OperationTraceCode() (string, error) { + var operationTraceCode string + var operationResults []xdr.OperationResult + var ok bool + var err error + + operationResults, ok = o.Transaction.Result.Result.OperationResults() + if ok { + var operationResultTr xdr.OperationResultTr + operationResultTr, ok = operationResults[o.OperationIndex].GetTr() + if ok { + operationTraceCode, err = operationResultTr.MapOperationResultTr() + if err != nil { + return "", err + } + return operationTraceCode, nil + } + } + + return operationTraceCode, nil +} + +func (o *LedgerOperation) OperationDetails() (interface{}, error) { + var err error + var details interface{} + + switch o.Operation.Body.Type { + case xdr.OperationTypeCreateAccount: + details, err = o.CreateAccountDetails() + if err != nil { + return details, err + } + case xdr.OperationTypePayment: + details, err = o.PaymentDetails() + if err != nil { + return details, err + } + case xdr.OperationTypePathPaymentStrictReceive: + details, err = o.PathPaymentStrictReceiveDetails() + if err != nil { + return details, err + } + case xdr.OperationTypePathPaymentStrictSend: + details, err = o.PathPaymentStrictSendDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeManageBuyOffer: + details, err = o.ManageBuyOfferDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeManageSellOffer: + details, err = o.ManageSellOfferDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeCreatePassiveSellOffer: + details, err = o.CreatePassiveSellOfferDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeSetOptions: + details, err = o.SetOptionsDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeChangeTrust: + details, err = o.ChangeTrustDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeAllowTrust: + details, err = o.AllowTrustDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeAccountMerge: + details, err = o.AccountMergeDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeInflation: + details, err = o.InflationDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeManageData: + details, err = o.ManageDataDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeBumpSequence: + details, err = o.BumpSequenceDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeCreateClaimableBalance: + details, err = o.CreateClaimableBalanceDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeClaimClaimableBalance: + details, err = o.ClaimClaimableBalanceDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeBeginSponsoringFutureReserves: + details, err = o.BeginSponsoringFutureReservesDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeEndSponsoringFutureReserves: + details, err = o.EndSponsoringFutureReserveDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeRevokeSponsorship: + details, err = o.RevokeSponsorshipDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeClawback: + details, err = o.ClawbackDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeClawbackClaimableBalance: + details, err = o.ClawbackClaimableBalanceDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeSetTrustLineFlags: + details, err = o.SetTrustlineFlagsDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeLiquidityPoolDeposit: + details, err = o.LiquidityPoolDepositDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeLiquidityPoolWithdraw: + details, err = o.LiquidityPoolWithdrawDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeInvokeHostFunction: + details, err = o.InvokeHostFunctionDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeExtendFootprintTtl: + details, err = o.ExtendFootprintTtlDetails() + if err != nil { + return details, err + } + case xdr.OperationTypeRestoreFootprint: + details, err = o.RestoreFootprintDetails() + if err != nil { + return details, err + } + default: + return details, fmt.Errorf("unknown operation type: %s", o.Operation.Body.Type.String()) + } + + return details, nil +} + +func getMuxedAccountDetails(a xdr.MuxedAccount) (string, uint64, error) { + var err error + var muxedAccountAddress string + var muxedAccountID uint64 + + if a.Type == xdr.CryptoKeyTypeKeyTypeMuxedEd25519 { + muxedAccountAddress, err = a.GetAddress() + if err != nil { + return "", 0, err + } + muxedAccountID, err = a.GetId() + if err != nil { + return "", 0, err + } + } + return muxedAccountAddress, muxedAccountID, nil +} + +type LedgerKeyDetail struct { + AccountID string `json:"account_id"` + ClaimableBalanceID string `json:"claimable_balance_id"` + DataAccountID string `json:"data_account_id"` + DataName string `json:"data_name"` + OfferID int64 `json:"offer_id,string"` + TrustlineAccountID string `json:"trustline_account_id"` + TrustlineLiquidityPoolID string `json:"trustline_liquidity_pool_id"` + TrustlineAssetCode string `json:"trustline_asset_code"` + TrustlineAssetIssuer string `json:"trustline_asset_issuer"` + TrustlineAssetType string `json:"trustline_asset_type"` + LiquidityPoolID string `json:"liquidity_pool_id"` +} + +func addLedgerKey(ledgerKey xdr.LedgerKey) (LedgerKeyDetail, error) { + var err error + var ledgerKeyDetail LedgerKeyDetail + + switch ledgerKey.Type { + case xdr.LedgerEntryTypeAccount: + ledgerKeyDetail.AccountID = ledgerKey.Account.AccountId.Address() + case xdr.LedgerEntryTypeClaimableBalance: + var marshalHex string + marshalHex, err = xdr.MarshalHex(ledgerKey.ClaimableBalance.BalanceId) + if err != nil { + return LedgerKeyDetail{}, fmt.Errorf("in claimable balance: %w", err) + } + ledgerKeyDetail.ClaimableBalanceID = marshalHex + case xdr.LedgerEntryTypeData: + ledgerKeyDetail.DataAccountID = ledgerKey.Data.AccountId.Address() + ledgerKeyDetail.DataName = string(ledgerKey.Data.DataName) + case xdr.LedgerEntryTypeOffer: + ledgerKeyDetail.OfferID = int64(ledgerKey.Offer.OfferId) + case xdr.LedgerEntryTypeTrustline: + ledgerKeyDetail.TrustlineAccountID = ledgerKey.TrustLine.AccountId.Address() + if ledgerKey.TrustLine.Asset.Type == xdr.AssetTypeAssetTypePoolShare { + ledgerKeyDetail.TrustlineLiquidityPoolID = PoolIDToString(*ledgerKey.TrustLine.Asset.LiquidityPoolId) + } else { + var assetCode, assetIssuer, assetType string + err = ledgerKey.TrustLine.Asset.ToAsset().Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return LedgerKeyDetail{}, err + } + + ledgerKeyDetail.TrustlineAssetCode = assetCode + ledgerKeyDetail.TrustlineAssetIssuer = assetIssuer + ledgerKeyDetail.TrustlineAssetType = assetType + } + case xdr.LedgerEntryTypeLiquidityPool: + ledgerKeyDetail.LiquidityPoolID = PoolIDToString(ledgerKey.LiquidityPool.LiquidityPoolId) + } + + return ledgerKeyDetail, nil +} + +func (o *LedgerOperation) getLiquidityPoolAndProductDelta(lpID *xdr.PoolId) (*xdr.LiquidityPoolEntry, *LiquidityPoolDelta, error) { + changes, err := o.Transaction.GetOperationChanges(uint32(o.OperationIndex)) + if err != nil { + return nil, nil, err + } + + for _, c := range changes { + if c.Type != xdr.LedgerEntryTypeLiquidityPool { + continue + } + // The delta can be caused by a full removal or full creation of the liquidity pool + var lp *xdr.LiquidityPoolEntry + var preA, preB, preShares xdr.Int64 + if c.Pre != nil { + if lpID != nil && c.Pre.Data.LiquidityPool.LiquidityPoolId != *lpID { + // if we were looking for specific pool id, then check on it + continue + } + lp = c.Pre.Data.LiquidityPool + if c.Pre.Data.LiquidityPool.Body.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { + return nil, nil, fmt.Errorf("unexpected liquity pool body type %d", c.Pre.Data.LiquidityPool.Body.Type) + } + cpPre := c.Pre.Data.LiquidityPool.Body.ConstantProduct + preA, preB, preShares = cpPre.ReserveA, cpPre.ReserveB, cpPre.TotalPoolShares + } + var postA, postB, postShares xdr.Int64 + if c.Post != nil { + if lpID != nil && c.Post.Data.LiquidityPool.LiquidityPoolId != *lpID { + // if we were looking for specific pool id, then check on it + continue + } + lp = c.Post.Data.LiquidityPool + if c.Post.Data.LiquidityPool.Body.Type != xdr.LiquidityPoolTypeLiquidityPoolConstantProduct { + return nil, nil, fmt.Errorf("unexpected liquity pool body type %d", c.Post.Data.LiquidityPool.Body.Type) + } + cpPost := c.Post.Data.LiquidityPool.Body.ConstantProduct + postA, postB, postShares = cpPost.ReserveA, cpPost.ReserveB, cpPost.TotalPoolShares + } + delta := &LiquidityPoolDelta{ + ReserveA: postA - preA, + ReserveB: postB - preB, + TotalPoolShares: postShares - preShares, + } + return lp, delta, nil + } + + return nil, nil, fmt.Errorf("liquidity pool change not found") +} + +func (o *LedgerOperation) serializeParameters(args []xdr.ScVal) ([]interface{}, error) { + var params []interface{} + + for _, param := range args { + if _, ok := param.ArmForSwitch(int32(param.Type)); ok { + var err error + var raw []byte + raw, err = param.MarshalBinary() + if err != nil { + return nil, err + } + + params = append(params, raw) + } + } + + return params, nil +} + +func (o *LedgerOperation) parseAssetBalanceChangesFromContractEvents() ([]BalanceChangeDetail, error) { + balanceChanges := []BalanceChangeDetail{} + + diagnosticEvents, err := o.Transaction.GetDiagnosticEvents() + if err != nil { + // this operation in this context must be an InvokeHostFunctionOp, therefore V3Meta should be present + // as it's in same soroban model, so if any err, it's real, + return nil, err + } + + for _, contractEvent := range o.filterEvents(diagnosticEvents) { + // Parse the xdr contract event to contractevents.StellarAssetContractEvent model + + var err error + var balanceChangeDetail BalanceChangeDetail + var sacEvent contractevents.StellarAssetContractEvent + // has some convenience like to/from attributes are expressed in strkey format for accounts(G...) and contracts(C...) + if sacEvent, err = contractevents.NewStellarAssetContractEvent(&contractEvent, o.NetworkPassphrase); err == nil { + switch sacEvent.GetType() { + case contractevents.EventTypeTransfer: + transferEvt := sacEvent.(*contractevents.TransferEvent) + balanceChangeDetail, err = createSACBalanceChange(transferEvt.From, transferEvt.To, transferEvt.Amount, transferEvt.Asset, "transfer") + if err != nil { + return []BalanceChangeDetail{}, err + } + + balanceChanges = append(balanceChanges, balanceChangeDetail) + case contractevents.EventTypeMint: + mintEvt := sacEvent.(*contractevents.MintEvent) + balanceChangeDetail, err = createSACBalanceChange("", mintEvt.To, mintEvt.Amount, mintEvt.Asset, "mint") + if err != nil { + return []BalanceChangeDetail{}, err + } + + balanceChanges = append(balanceChanges, balanceChangeDetail) + case contractevents.EventTypeClawback: + clawbackEvt := sacEvent.(*contractevents.ClawbackEvent) + balanceChangeDetail, err = createSACBalanceChange(clawbackEvt.From, "", clawbackEvt.Amount, clawbackEvt.Asset, "clawback") + if err != nil { + return []BalanceChangeDetail{}, err + } + + balanceChanges = append(balanceChanges, balanceChangeDetail) + case contractevents.EventTypeBurn: + burnEvt := sacEvent.(*contractevents.BurnEvent) + balanceChangeDetail, err = createSACBalanceChange(burnEvt.From, "", burnEvt.Amount, burnEvt.Asset, "burn") + if err != nil { + return []BalanceChangeDetail{}, err + } + + balanceChanges = append(balanceChanges, balanceChangeDetail) + } + } + } + + return balanceChanges, nil +} + +func (o *LedgerOperation) filterEvents(diagnosticEvents []xdr.DiagnosticEvent) []xdr.ContractEvent { + var filtered []xdr.ContractEvent + for _, diagnosticEvent := range diagnosticEvents { + if !diagnosticEvent.InSuccessfulContractCall || diagnosticEvent.Event.Type != xdr.ContractEventTypeContract { + continue + } + filtered = append(filtered, diagnosticEvent.Event) + } + return filtered +} + +type BalanceChangeDetail struct { + From string `json:"from"` + To string `json:"to"` + Type string `json:"type"` + Amount string `json:"amount"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` +} + +// fromAccount - strkey format of contract or address +// toAccount - strkey format of contract or address, or nillable +// amountChanged - absolute value that asset balance changed +// asset - the fully qualified issuer:code for asset that had balance change +// changeType - the type of source sac event that triggered this change +// +// return - a balance changed record expressed as map of key/value's +func createSACBalanceChange(fromAccount string, toAccount string, amountChanged xdr.Int128Parts, asset xdr.Asset, changeType string) (BalanceChangeDetail, error) { + balanceChangeDetail := BalanceChangeDetail{ + Type: changeType, + Amount: amount.String128(amountChanged), + } + + if fromAccount != "" { + balanceChangeDetail.From = fromAccount + } + if toAccount != "" { + balanceChangeDetail.To = toAccount + } + + var assetCode, assetIssuer, assetType string + err := asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return BalanceChangeDetail{}, err + } + + return balanceChangeDetail, nil +} + +type PreImageDetails struct { + From string `json:"from"` + Address string `json:"address"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` +} + +func switchContractIdPreimage(contractIdPreimage xdr.ContractIdPreimage) (PreImageDetails, error) { + switch contractIdPreimage.Type { + case xdr.ContractIdPreimageTypeContractIdPreimageFromAddress: + fromAddress := contractIdPreimage.MustFromAddress() + address, err := fromAddress.Address.String() + if err != nil { + return PreImageDetails{}, err + } + return PreImageDetails{ + From: "address", + Address: address, + }, nil + case xdr.ContractIdPreimageTypeContractIdPreimageFromAsset: + var assetCode, assetIssuer, assetType string + contractIdPreimage.MustFromAsset().Extract(&assetType, &assetCode, &assetIssuer) + + return PreImageDetails{ + From: "asset", + AssetCode: assetCode, + AssetIssuer: assetIssuer, + AssetType: assetType, + }, nil + + default: + return PreImageDetails{}, fmt.Errorf("unknown contract id type: %s", contractIdPreimage.Type) + } +} + +func (o *LedgerOperation) ConvertStroopValueToReal(input int64) float64 { + output, _ := big.NewRat(int64(input), int64(10000000)).Float64() + return output +} + +func (o *LedgerOperation) FormatPrefix(p string) string { + if p != "" { + p += "_" + } + return p +} + +func (o *LedgerOperation) FarmHashAsset(assetCode, assetIssuer, assetType string) int64 { + asset := fmt.Sprintf("%s%s%s", assetCode, assetIssuer, assetType) + hash := farm.Fingerprint64([]byte(asset)) + + return int64(hash) +} + +// Path is a representation of an asset without an ID that forms part of a path in a path payment +type Path struct { + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` +} + +func (o *LedgerOperation) TransformPath(initialPath []xdr.Asset) []Path { + if len(initialPath) == 0 { + return nil + } + var path = make([]Path, 0) + for _, pathAsset := range initialPath { + var assetType, code, issuer string + err := pathAsset.Extract(&assetType, &code, &issuer) + if err != nil { + return nil + } + + path = append(path, Path{ + AssetType: assetType, + AssetIssuer: issuer, + AssetCode: code, + }) + } + return path +} + +type Price struct { + Numerator int32 `json:"n"` + Denominator int32 `json:"d"` +} + +type Claimant struct { + Destination string `json:"destination"` + Predicate xdr.ClaimPredicate `json:"predicate"` +} + +func transformClaimants(claimants []xdr.Claimant) []Claimant { + var transformed []Claimant + for _, c := range claimants { + switch c.Type { + case 0: + transformed = append(transformed, Claimant{ + Destination: c.V0.Destination.Address(), + Predicate: c.V0.Predicate, + }) + } + } + return transformed +} + +type SponsorshipOutput struct { + Operation xdr.Operation + OperationIndex uint32 +} + +type LiquidityPoolDelta struct { + ReserveA xdr.Int64 + ReserveB xdr.Int64 + TotalPoolShares xdr.Int64 +} diff --git a/ingest/processors/operation_processor/operation_test.go b/ingest/processors/operation_processor/operation_test.go index 4609e779d8..0aa04cb7fb 100644 --- a/ingest/processors/operation_processor/operation_test.go +++ b/ingest/processors/operation_processor/operation_test.go @@ -2217,3 +2217,1518 @@ func makeOperationTestOutputs() (transformedOperations []OperationOutput) { } return } + +func TestOperation(t *testing.T) { + o := LedgerOperation{ + OperationIndex: int32(0), + Operation: operationTestInput()[1], + Transaction: transactionTestInput(), + NetworkPassphrase: "", + } + + assert.Equal(t, "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", o.SourceAccount()) + assert.Equal(t, int32(1), o.Type()) + assert.Equal(t, "OperationTypePayment", o.TypeString()) + assert.Equal(t, int64(131335723340009473), o.ID()) + + var ok bool + var sourceAccountMuxed string + sourceAccountMuxed, ok = o.SourceAccountMuxed() + assert.Equal(t, true, ok) + assert.Equal(t, "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", sourceAccountMuxed) + + assert.Equal(t, "OperationResultCodeOpInner", o.OperationResultCode()) + + var err error + var operationTraceCode string + operationTraceCode, err = o.OperationTraceCode() + assert.Equal(t, nil, err) + assert.Equal(t, "PathPaymentStrictReceiveResultCodePathPaymentStrictReceiveSuccess", operationTraceCode) +} + +func TestOperationDetails(t *testing.T) { + testOutput := resultTestOutput() + for i, op := range operationTestInput() { + ledgerOperation := LedgerOperation{ + OperationIndex: int32(i), + Operation: op, + Transaction: transactionTestInput(), + NetworkPassphrase: "", + } + + result, err := ledgerOperation.OperationDetails() + assert.Equal(t, testOutput[i].err, err) + assert.Equal(t, testOutput[i].result, result) + } +} + +func ledgerTestInput() (lcm xdr.LedgerCloseMeta) { + lcm = xdr.LedgerCloseMeta{ + V: 1, + V1: &xdr.LedgerCloseMetaV1{ + LedgerHeader: xdr.LedgerHeaderHistoryEntry{ + Header: xdr.LedgerHeader{ + LedgerSeq: 30578981, + LedgerVersion: 22, + }, + }, + }, + } + + return lcm +} + +func transactionTestInput() *ingest.LedgerTransaction { + testAccountAddress := "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA" + testAccountID, _ := xdr.AddressToAccountId(testAccountAddress) + dummyBool := true + + ed25519 := xdr.Uint256([32]byte{0x11, 0x22, 0x33}) + muxedAccount := xdr.MuxedAccount{ + Type: 256, + Ed25519: &ed25519, + Med25519: &xdr.MuxedAccountMed25519{ + Id: xdr.Uint64(123), + Ed25519: ed25519, + }, + } + + memoText := "test memo" + minSeqNum := xdr.SequenceNumber(123) + + transaction := &ingest.LedgerTransaction{ + Index: 1, + Envelope: xdr.TransactionEnvelope{ + Type: xdr.EnvelopeTypeEnvelopeTypeTx, + V1: &xdr.TransactionV1Envelope{ + Signatures: []xdr.DecoratedSignature{ + { + Signature: []byte{0x11, 0x22}, + }, + }, + Tx: xdr.Transaction{ + SourceAccount: muxedAccount, + SeqNum: xdr.SequenceNumber(30578981), + Fee: xdr.Uint32(4560), + Operations: []xdr.Operation{ + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + { + SourceAccount: &muxedAccount, + Body: xdr.OperationBody{}, + }, + }, + Memo: xdr.Memo{ + Type: xdr.MemoTypeMemoText, + Text: &memoText, + }, + Cond: xdr.Preconditions{ + Type: 2, + V2: &xdr.PreconditionsV2{ + TimeBounds: &xdr.TimeBounds{ + MinTime: xdr.TimePoint(1), + MaxTime: xdr.TimePoint(10), + }, + LedgerBounds: &xdr.LedgerBounds{ + MinLedger: 2, + MaxLedger: 20, + }, + MinSeqNum: &minSeqNum, + MinSeqAge: 456, + MinSeqLedgerGap: 789, + }, + }, + Ext: xdr.TransactionExt{ + V: 1, + SorobanData: &xdr.SorobanTransactionData{ + Resources: xdr.SorobanResources{ + Instructions: 123, + ReadBytes: 456, + WriteBytes: 789, + Footprint: xdr.LedgerFootprint{ + ReadOnly: []xdr.LedgerKey{ + { + Type: 6, + ContractData: &xdr.LedgerKeyContractData{ + Contract: xdr.ScAddress{ + Type: 1, + ContractId: &xdr.Hash{0x12, 0x34}, + }, + Key: xdr.ScVal{ + Type: 0, + B: &dummyBool, + }, + }, + }, + }, + }, + }, + ResourceFee: 1234, + }, + }, + }, + }, + }, + Result: xdr.TransactionResultPair{ + TransactionHash: xdr.Hash{0x11, 0x22, 0x33}, + Result: xdr.TransactionResult{ + FeeCharged: xdr.Int64(789), + Result: xdr.TransactionResultResult{ + Code: 0, + Results: &[]xdr.OperationResult{ + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 2, + PathPaymentStrictReceiveResult: &xdr.PathPaymentStrictReceiveResult{ + Code: 0, + Success: &xdr.PathPaymentStrictReceiveResultSuccess{}, + NoIssuer: &xdr.Asset{}, + }, + }, + }, + {}, + {}, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 2, + PathPaymentStrictReceiveResult: &xdr.PathPaymentStrictReceiveResult{ + Code: 0, + Success: &xdr.PathPaymentStrictReceiveResultSuccess{}, + NoIssuer: &xdr.Asset{}, + }, + }, + }, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 13, + PathPaymentStrictSendResult: &xdr.PathPaymentStrictSendResult{ + Code: 0, + Success: &xdr.PathPaymentStrictSendResultSuccess{ + Last: xdr.SimplePaymentResult{ + Amount: 640000000, + }, + }, + NoIssuer: &xdr.Asset{}, + }, + }, + }, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 22, + LiquidityPoolDepositResult: &xdr.LiquidityPoolDepositResult{ + Code: 0, + }, + }, + }, + { + Code: 0, + Tr: &xdr.OperationResultTr{ + Type: 23, + LiquidityPoolWithdrawResult: &xdr.LiquidityPoolWithdrawResult{ + Code: 0, + }, + }, + }, + {}, + }, + }, + }, + }, + FeeChanges: xdr.LedgerEntryChanges{ + { + Type: xdr.LedgerEntryChangeTypeLedgerEntryState, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: xdr.LedgerEntryTypeAccount, + Account: &xdr.AccountEntry{ + AccountId: xdr.AccountId{ + Type: 0, + Ed25519: &ed25519, + }, + Balance: 1000, + }, + }, + }, + }, + {}, + }, + UnsafeMeta: xdr.TransactionMeta{ + V: 3, + V3: &xdr.TransactionMetaV3{ + TxChangesAfter: xdr.LedgerEntryChanges{}, + SorobanMeta: &xdr.SorobanTransactionMeta{ + Ext: xdr.SorobanTransactionMetaExt{ + V: 1, + V1: &xdr.SorobanTransactionMetaExtV1{ + TotalNonRefundableResourceFeeCharged: 321, + TotalRefundableResourceFeeCharged: 123, + RentFeeCharged: 456, + }, + }, + }, + Operations: []xdr.OperationMeta{ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + { + Changes: []xdr.LedgerEntryChange{ + { + Type: 3, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: 5, + LiquidityPool: &xdr.LiquidityPoolEntry{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Body: xdr.LiquidityPoolEntryBody{ + Type: 0, + ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ + Params: xdr.LiquidityPoolConstantProductParameters{ + AssetA: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + AssetB: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + Fee: 1, + }, + ReserveA: 1, + ReserveB: 1, + TotalPoolShares: 1, + PoolSharesTrustLineCount: 1, + }, + }, + }, + }, + }, + }, + { + Type: 1, + Updated: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: 5, + LiquidityPool: &xdr.LiquidityPoolEntry{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Body: xdr.LiquidityPoolEntryBody{ + Type: 0, + ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ + Params: xdr.LiquidityPoolConstantProductParameters{ + AssetA: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + AssetB: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + Fee: 1, + }, + ReserveA: 2, + ReserveB: 2, + TotalPoolShares: 2, + PoolSharesTrustLineCount: 1, + }, + }, + }, + }, + }, + }, + }, + }, + { + Changes: []xdr.LedgerEntryChange{ + { + Type: 3, + State: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: 5, + LiquidityPool: &xdr.LiquidityPoolEntry{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Body: xdr.LiquidityPoolEntryBody{ + Type: 0, + ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ + Params: xdr.LiquidityPoolConstantProductParameters{ + AssetA: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + AssetB: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + Fee: 1, + }, + ReserveA: 1, + ReserveB: 1, + TotalPoolShares: 1, + PoolSharesTrustLineCount: 1, + }, + }, + }, + }, + }, + }, + { + Type: 1, + Updated: &xdr.LedgerEntry{ + Data: xdr.LedgerEntryData{ + Type: 5, + LiquidityPool: &xdr.LiquidityPoolEntry{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Body: xdr.LiquidityPoolEntryBody{ + Type: 0, + ConstantProduct: &xdr.LiquidityPoolEntryConstantProduct{ + Params: xdr.LiquidityPoolConstantProductParameters{ + AssetA: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + AssetB: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + }, + Fee: 1, + }, + ReserveA: 2, + ReserveB: 2, + TotalPoolShares: 2, + PoolSharesTrustLineCount: 1, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + LedgerVersion: 22, + Ledger: ledgerTestInput(), + Hash: xdr.Hash{}, + } + + return transaction +} + +type testOutput struct { + err error + result interface{} +} + +func operationTestInput() []xdr.Operation { + testAccountAddress := "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA" + testAccountID, _ := xdr.AddressToAccountId(testAccountAddress) + testAccountMuxed := testAccountID.ToMuxedAccount() + + sourceAccountAddress := "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN" + sourceAccountID, _ := xdr.AddressToAccountId(sourceAccountAddress) + sourceAccountMuxed := sourceAccountID.ToMuxedAccount() + + usdtAsset := xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x44, 0x54}), + Issuer: testAccountID, + }, + } + assetCode, _ := usdtAsset.ToAssetCode("USDT") + nativeAsset := xdr.MustNewNativeAsset() + + clearFlags := xdr.Uint32(3) + setFlags := xdr.Uint32(4) + masterWeight := xdr.Uint32(3) + lowThresh := xdr.Uint32(1) + medThresh := xdr.Uint32(3) + highThresh := xdr.Uint32(5) + homeDomain := xdr.String32("2019=DRA;n-test") + signerKey, _ := xdr.NewSignerKey(xdr.SignerKeyTypeSignerKeyTypeEd25519, xdr.Uint256([32]byte{})) + signer := xdr.Signer{ + Key: signerKey, + Weight: xdr.Uint32(1), + } + + usdtChangeTrustAsset := xdr.ChangeTrustAsset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x53, 0x44}), + Issuer: testAccountID, + }, + } + + usdtLiquidityPoolShare := xdr.ChangeTrustAsset{ + Type: xdr.AssetTypeAssetTypePoolShare, + LiquidityPool: &xdr.LiquidityPoolParameters{ + Type: xdr.LiquidityPoolTypeLiquidityPoolConstantProduct, + ConstantProduct: &xdr.LiquidityPoolConstantProductParameters{ + AssetA: nativeAsset, + AssetB: usdtAsset, + Fee: 30, + }, + }, + } + + dataValue := xdr.DataValue([]byte{0x76, 0x61, 0x6c, 0x75, 0x65}) + + testClaimant := xdr.Claimant{ + Type: xdr.ClaimantTypeClaimantTypeV0, + V0: &xdr.ClaimantV0{ + Destination: testAccountID, + Predicate: xdr.ClaimPredicate{ + Type: xdr.ClaimPredicateTypeClaimPredicateUnconditional, + }, + }, + } + + claimableBalance := xdr.ClaimableBalanceId{ + Type: xdr.ClaimableBalanceIdTypeClaimableBalanceIdTypeV0, + V0: &xdr.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9}, + } + + contractHash := xdr.Hash{0x12, 0x34, 0x56, 0x78} + salt := [32]byte{0x12, 0x34, 0x56} + wasm := []byte{0x12, 0x34} + dummyBool := true + + operation := []xdr.Operation{ + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeCreateAccount, + CreateAccountOp: &xdr.CreateAccountOp{ + StartingBalance: 25000000, + Destination: testAccountID, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypePayment, + PaymentOp: &xdr.PaymentOp{ + Destination: testAccountMuxed, + Asset: usdtAsset, + Amount: 350000000, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypePayment, + PaymentOp: &xdr.PaymentOp{ + Destination: testAccountMuxed, + Asset: nativeAsset, + Amount: 350000000, + }, + }, + }, + { + SourceAccount: &sourceAccountMuxed, + Body: xdr.OperationBody{ + Type: xdr.OperationTypePathPaymentStrictReceive, + PathPaymentStrictReceiveOp: &xdr.PathPaymentStrictReceiveOp{ + SendAsset: nativeAsset, + SendMax: 8951495900, + Destination: testAccountMuxed, + DestAsset: nativeAsset, + DestAmount: 8951495900, + Path: []xdr.Asset{usdtAsset}, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeManageSellOffer, + ManageSellOfferOp: &xdr.ManageSellOfferOp{ + Selling: usdtAsset, + Buying: nativeAsset, + Amount: 765860000, + Price: xdr.Price{ + N: 128523, + D: 250000, + }, + OfferId: 0, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeCreatePassiveSellOffer, + CreatePassiveSellOfferOp: &xdr.CreatePassiveSellOfferOp{ + Selling: nativeAsset, + Buying: usdtAsset, + Amount: 631595000, + Price: xdr.Price{ + N: 99583200, + D: 1257990000, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeSetOptions, + SetOptionsOp: &xdr.SetOptionsOp{ + InflationDest: &testAccountID, + ClearFlags: &clearFlags, + SetFlags: &setFlags, + MasterWeight: &masterWeight, + LowThreshold: &lowThresh, + MedThreshold: &medThresh, + HighThreshold: &highThresh, + HomeDomain: &homeDomain, + Signer: &signer, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeChangeTrust, + ChangeTrustOp: &xdr.ChangeTrustOp{ + Line: usdtChangeTrustAsset, + Limit: xdr.Int64(500000000000000000), + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeChangeTrust, + ChangeTrustOp: &xdr.ChangeTrustOp{ + Line: usdtLiquidityPoolShare, + Limit: xdr.Int64(500000000000000000), + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeAllowTrust, + AllowTrustOp: &xdr.AllowTrustOp{ + Trustor: testAccountID, + Asset: assetCode, + Authorize: xdr.Uint32(1), + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeAccountMerge, + Destination: &testAccountMuxed, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInflation, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeManageData, + ManageDataOp: &xdr.ManageDataOp{ + DataName: "test", + DataValue: &dataValue, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeBumpSequence, + BumpSequenceOp: &xdr.BumpSequenceOp{ + BumpTo: xdr.SequenceNumber(100), + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeManageBuyOffer, + ManageBuyOfferOp: &xdr.ManageBuyOfferOp{ + Selling: usdtAsset, + Buying: nativeAsset, + BuyAmount: 7654501001, + Price: xdr.Price{ + N: 635863285, + D: 1818402817, + }, + OfferId: 100, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypePathPaymentStrictSend, + PathPaymentStrictSendOp: &xdr.PathPaymentStrictSendOp{ + SendAsset: nativeAsset, + SendAmount: 1598182, + Destination: testAccountMuxed, + DestAsset: nativeAsset, + DestMin: 4280460538, + Path: []xdr.Asset{usdtAsset}, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeCreateClaimableBalance, + CreateClaimableBalanceOp: &xdr.CreateClaimableBalanceOp{ + Asset: usdtAsset, + Amount: 1234567890000, + Claimants: []xdr.Claimant{testClaimant}, + }, + }, + }, + { + SourceAccount: &sourceAccountMuxed, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeClaimClaimableBalance, + ClaimClaimableBalanceOp: &xdr.ClaimClaimableBalanceOp{ + BalanceId: claimableBalance, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeBeginSponsoringFutureReserves, + BeginSponsoringFutureReservesOp: &xdr.BeginSponsoringFutureReservesOp{ + SponsoredId: testAccountID, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipSigner, + Signer: &xdr.RevokeSponsorshipOpSigner{ + AccountId: testAccountID, + SignerKey: signer.Key, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeAccount, + Account: &xdr.LedgerKeyAccount{ + AccountId: testAccountID, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeClaimableBalance, + ClaimableBalance: &xdr.LedgerKeyClaimableBalance{ + BalanceId: claimableBalance, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeData, + Data: &xdr.LedgerKeyData{ + AccountId: testAccountID, + DataName: "test", + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeOffer, + Offer: &xdr.LedgerKeyOffer{ + SellerId: testAccountID, + OfferId: 100, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeTrustline, + TrustLine: &xdr.LedgerKeyTrustLine{ + AccountId: testAccountID, + Asset: xdr.TrustLineAsset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4([4]byte{0x55, 0x53, 0x54, 0x54}), + Issuer: testAccountID, + }, + }, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRevokeSponsorship, + RevokeSponsorshipOp: &xdr.RevokeSponsorshipOp{ + Type: xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry, + LedgerKey: &xdr.LedgerKey{ + Type: xdr.LedgerEntryTypeLiquidityPool, + LiquidityPool: &xdr.LedgerKeyLiquidityPool{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeClawback, + ClawbackOp: &xdr.ClawbackOp{ + Asset: usdtAsset, + From: testAccountMuxed, + Amount: 1598182, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeClawbackClaimableBalance, + ClawbackClaimableBalanceOp: &xdr.ClawbackClaimableBalanceOp{ + BalanceId: claimableBalance, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeSetTrustLineFlags, + SetTrustLineFlagsOp: &xdr.SetTrustLineFlagsOp{ + Trustor: testAccountID, + Asset: usdtAsset, + SetFlags: setFlags, + ClearFlags: clearFlags, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeLiquidityPoolDeposit, + LiquidityPoolDepositOp: &xdr.LiquidityPoolDepositOp{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + MaxAmountA: 1000, + MaxAmountB: 100, + MinPrice: xdr.Price{ + N: 1, + D: 1000000, + }, + MaxPrice: xdr.Price{ + N: 1000000, + D: 1, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeLiquidityPoolWithdraw, + LiquidityPoolWithdrawOp: &xdr.LiquidityPoolWithdrawOp{ + LiquidityPoolId: xdr.PoolId{1, 2, 3, 4, 5, 6, 7, 8, 9}, + Amount: 4, + MinAmountA: 1, + MinAmountB: 1, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeInvokeContract, + InvokeContract: &xdr.InvokeContractArgs{ + ContractAddress: xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeContract, + ContractId: &contractHash, + }, + FunctionName: "test", + Args: []xdr.ScVal{}, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeCreateContract, + CreateContract: &xdr.CreateContractArgs{ + ContractIdPreimage: xdr.ContractIdPreimage{ + Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAddress, + FromAddress: &xdr.ContractIdPreimageFromAddress{ + Address: xdr.ScAddress{ + Type: xdr.ScAddressTypeScAddressTypeContract, + ContractId: &contractHash, + }, + Salt: salt, + }, + }, + Executable: xdr.ContractExecutable{}, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeCreateContract, + CreateContract: &xdr.CreateContractArgs{ + ContractIdPreimage: xdr.ContractIdPreimage{ + Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAsset, + FromAsset: &usdtAsset, + }, + Executable: xdr.ContractExecutable{}, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeCreateContractV2, + CreateContractV2: &xdr.CreateContractArgsV2{ + ContractIdPreimage: xdr.ContractIdPreimage{ + Type: xdr.ContractIdPreimageTypeContractIdPreimageFromAsset, + FromAsset: &usdtAsset, + }, + Executable: xdr.ContractExecutable{}, + ConstructorArgs: []xdr.ScVal{ + { + Type: xdr.ScValTypeScvBool, + B: &dummyBool, + }, + }, + }, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeInvokeHostFunction, + InvokeHostFunctionOp: &xdr.InvokeHostFunctionOp{ + HostFunction: xdr.HostFunction{ + Type: xdr.HostFunctionTypeHostFunctionTypeUploadContractWasm, + Wasm: &wasm, + }, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeExtendFootprintTtl, + ExtendFootprintTtlOp: &xdr.ExtendFootprintTtlOp{ + Ext: xdr.ExtensionPoint{ + V: 0, + }, + ExtendTo: 1234, + }, + }, + }, + { + SourceAccount: nil, + Body: xdr.OperationBody{ + Type: xdr.OperationTypeRestoreFootprint, + RestoreFootprintOp: &xdr.RestoreFootprintOp{ + Ext: xdr.ExtensionPoint{ + V: 0, + }, + }, + }, + }, + } + + return operation +} + +func resultTestOutput() []testOutput { + output := []testOutput{ + { + err: nil, + result: CreateAccountDetail{ + Account: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + Funder: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + FunderMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + FunderMuxedID: uint64(123), + StartingBalance: int64(25000000)}, + }, + { + err: nil, + result: PaymentDetail{ + Amount: int64(350000000), + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + FromMuxedID: uint64(123), + To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: PaymentDetail{ + Amount: int64(350000000), + AssetType: "native", + From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + FromMuxedID: uint64(123), + To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: PathPaymentStrictReceiveDetail{ + Amount: int64(8951495900), + AssetType: "native", + From: "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", + Path: []Path{ + { + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + }, + }, + SourceAmount: int64(0), + SourceAssetType: "native", + SourceMax: int64(8951495900), + To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: ManageSellOffer{ + Amount: int64(765860000), + BuyingAssetType: "native", + OfferID: int64(0), + Price: 0.514092, + PriceN: 128523, + PriceD: 250000, + SellingAssetCode: "USDT", + SellingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + SellingAssetType: "credit_alphanum4"}, + }, + { + err: nil, + result: CreatePassiveSellOfferDetail{ + Amount: int64(631595000), + BuyingAssetCode: "USDT", + BuyingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + BuyingAssetType: "credit_alphanum4", + Price: 0.0791606, + PriceN: 99583200, + PriceD: 1257990000, + SellingAssetType: "native"}, + }, + { + err: nil, + result: SetOptionsDetails{ + ClearFlags: []int32{1, 2}, + ClearFlagsString: []string{"auth_required", "auth_revocable"}, + HighThreshold: uint32(5), + HomeDomain: "2019=DRA;n-test", + InflationDestination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + LowThreshold: uint32(1), + MasterKeyWeight: uint32(3), + MediumThreshold: uint32(3), + SetFlags: []int32{4}, + SetFlagsString: []string{"auth_immutable"}, + SignerKey: "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + SignerWeight: uint32(1)}, + }, + { + err: nil, + result: ChangeTrustDetail{ + AssetCode: "USSD", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + Limit: int64(500000000000000000), + Trustee: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + Trustor: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + TrustorMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + TrustorMuxedID: uint64(123)}, + }, + { + err: nil, + result: ChangeTrustDetail{ + AssetType: "liquidity_pool_shares", + Limit: int64(500000000000000000), + LiquidityPoolID: "1c261d6c75930204a73b480c3020ab525e9be48ce93de6194cf69fb06f07452d", + Trustor: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + TrustorMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + TrustorMuxedID: uint64(123)}, + }, + { + err: nil, + result: AllowTrustDetail{ + AssetCode: "USDT", + AssetIssuer: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + AssetType: "credit_alphanum4", + Authorize: true, + Trustee: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + TrusteeMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + TrusteeMuxedID: uint64(123), + Trustor: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: AccountMergeDetail{ + Account: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + AccountMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + AccountMuxedID: uint64(123), + Into: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: InflationDetail{}, + }, + { + err: nil, + result: ManageDataDetail{ + Name: "test", + Value: "dmFsdWU=", + }, + }, + { + err: nil, + result: BumpSequenceDetails{ + BumpTo: int64(100), + }, + }, + { + err: nil, + result: ManageBuyOffer{ + Amount: int64(7654501001), + BuyingAssetType: "native", + OfferID: int64(100), + Price: 0.3496823, + PriceN: 635863285, + PriceD: 1818402817, + SellingAssetCode: "USDT", + SellingAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + SellingAssetType: "credit_alphanum4"}, + }, + { + err: nil, + result: PathPaymentStrictSendDetail{ + Amount: int64(640000000), + AssetType: "native", + DestinationMin: 4280460538, + From: "GAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAK", + FromMuxed: "MAISEMYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMJ2I", + FromMuxedID: uint64(123), + Path: []Path{ + { + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + }, + }, + SourceAmount: int64(1598182), + SourceAssetType: "native", + To: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA"}, + }, + { + err: nil, + result: CreateClaimableBalanceDetail{ + Amount: int64(1234567890000), + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + Claimants: []Claimant{ + { + Destination: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + Predicate: xdr.ClaimPredicate{ + Type: 0, + AndPredicates: (*[]xdr.ClaimPredicate)(nil), + OrPredicates: (*[]xdr.ClaimPredicate)(nil), + NotPredicate: (**xdr.ClaimPredicate)(nil), + AbsBefore: (*xdr.Int64)(nil), + RelBefore: (*xdr.Int64)(nil), + }, + }, + }, + }, + }, + { + err: nil, + result: ClaimClaimableBalanceDetail{ + BalanceID: "AAAAAAECAwQFBgcICQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + Claimant: "GBT4YAEGJQ5YSFUMNKX6BPBUOCPNAIOFAVZOF6MIME2CECBMEIUXFZZN", + }, + }, + { + err: nil, + result: BeginSponsoringFutureReservesDetail{ + SponsoredID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, + }, + { + err: nil, + result: RevokeSponsorshipDetail{ + SignerAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + SignerKey: "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + }, + }, + { + err: nil, + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + AccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, + }, + }, + { + err: nil, + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + ClaimableBalanceID: "000000000102030405060708090000000000000000000000000000000000000000000000", + }, + }, + }, + { + err: nil, + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + DataAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + DataName: "test", + }, + }, + }, + { + err: nil, + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + OfferID: int64(100), + }, + }, + }, + { + err: nil, + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + TrustlineAccountID: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + TrustlineAssetCode: "USTT", + TrustlineAssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + TrustlineAssetType: "credit_alphanum4", + }, + }, + }, + { + err: nil, + result: RevokeSponsorshipDetail{ + LedgerKeyDetails: LedgerKeyDetail{ + LiquidityPoolID: "0102030405060708090000000000000000000000000000000000000000000000", + }, + }, + }, + { + err: nil, + result: ClawbackDetail{ + Amount: int64(1598182), + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + From: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, + }, + { + err: nil, + result: ClawbackClaimableBalanceDetail{ + BalanceID: "AAAAAAECAwQFBgcICQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + }, + }, + { + err: nil, + result: SetTrustlineFlagsDetail{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + ClearFlags: []int32{1, 2}, + ClearFlagsString: []string{"authorized", "authorized_to_maintain_liabilities"}, + SetFlags: []int32{4}, + SetFlagsString: []string{"clawback_enabled"}, + Trustor: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + }, + }, + { + err: nil, + result: LiquidityPoolDepositDetail{ + LiquidityPoolID: "0102030405060708090000000000000000000000000000000000000000000000", + MaxPrice: 1e+06, + MaxPriceN: 1000000, + MaxPriceD: 1, + MinPrice: 1e-06, + MinPriceN: 1, + MinPriceD: 1000000, + ReserveAssetA: ReserveAsset{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + DepositAmount: int64(1), + MaxAmount: int64(1000), + }, + ReserveAssetB: ReserveAsset{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + DepositAmount: 1, + MaxAmount: int64(100), + }, + SharesReceived: 1, + }, + }, + { + err: nil, + result: LiquidityPoolWithdrawDetail{ + LiquidityPoolID: "0102030405060708090000000000000000000000000000000000000000000000", + ReserveAssetA: ReserveAsset{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + MinAmount: int64(1), + WithdrawAmount: int64(-1), + }, + + ReserveAssetB: ReserveAsset{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + MinAmount: int64(1), + WithdrawAmount: int64(-1), + }, + Shares: int64(4), + }, + }, + { + err: nil, + result: InvokeHostFunctionDetail{ + AssetBalanceChanges: []BalanceChangeDetail{}, + ContractID: "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", + Function: "HostFunctionTypeHostFunctionTypeInvokeContract", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Parameters: []interface{}{ + []uint8{0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0x1, 0x12, 0x34, 0x56, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + []uint8{0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0x4, 0x74, 0x65, 0x73, 0x74}, + }, + Type: "invoke_contract", + }, + }, + { + err: nil, + result: InvokeHostFunctionDetail{ + Address: "CAJDIVTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABR37", + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + From: "address", + Function: "HostFunctionTypeHostFunctionTypeCreateContract", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Type: "create_contract", + }, + }, + { + err: nil, + result: InvokeHostFunctionDetail{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + From: "asset", + Function: "HostFunctionTypeHostFunctionTypeCreateContract", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Type: "create_contract", + }, + }, + { + err: nil, + result: InvokeHostFunctionDetail{ + AssetCode: "USDT", + AssetIssuer: "GBVVRXLMNCJQW3IDDXC3X6XCH35B5Q7QXNMMFPENSOGUPQO7WO7HGZPA", + AssetType: "credit_alphanum4", + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + From: "asset", + Function: "HostFunctionTypeHostFunctionTypeCreateContractV2", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Parameters: []interface{}{ + []uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, + }, + Type: "create_contract_v2", + }, + }, + { + err: nil, + result: InvokeHostFunctionDetail{ + Function: "HostFunctionTypeHostFunctionTypeUploadContractWasm", + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + Type: "upload_wasm", + }, + }, + { + err: nil, + result: ExtendFootprintTtlDetail{ + ExtendTo: uint32(1234), + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + Type: "extend_footprint_ttl", + }, + }, + { + err: nil, + result: RestoreFootprintDetail{ + LedgerKeyHash: []string{"AAAABgAAAAESNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=="}, + ContractID: "CAJDIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABT4W", + Type: "restore_footprint", + }, + }, + } + + return output +} diff --git a/ingest/path_payment_strict_receive_details.go b/ingest/processors/operation_processor/path_payment_strict_receive_details.go similarity index 99% rename from ingest/path_payment_strict_receive_details.go rename to ingest/processors/operation_processor/path_payment_strict_receive_details.go index 31dd64d514..db707f6b5b 100644 --- a/ingest/path_payment_strict_receive_details.go +++ b/ingest/processors/operation_processor/path_payment_strict_receive_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/path_payment_strict_send_details.go b/ingest/processors/operation_processor/path_payment_strict_send_details.go similarity index 99% rename from ingest/path_payment_strict_send_details.go rename to ingest/processors/operation_processor/path_payment_strict_send_details.go index 1a28b8d173..0530083e7d 100644 --- a/ingest/path_payment_strict_send_details.go +++ b/ingest/processors/operation_processor/path_payment_strict_send_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/payment_details.go b/ingest/processors/operation_processor/payment_details.go similarity index 98% rename from ingest/payment_details.go rename to ingest/processors/operation_processor/payment_details.go index c209db38ee..d62a91ceb7 100644 --- a/ingest/payment_details.go +++ b/ingest/processors/operation_processor/payment_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" diff --git a/ingest/restore_footprint_details.go b/ingest/processors/operation_processor/restore_footprint_details.go similarity index 92% rename from ingest/restore_footprint_details.go rename to ingest/processors/operation_processor/restore_footprint_details.go index 496308ffad..e6baa3d0e8 100644 --- a/ingest/restore_footprint_details.go +++ b/ingest/processors/operation_processor/restore_footprint_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import "fmt" @@ -21,7 +21,7 @@ func (o *LedgerOperation) RestoreFootprintDetails() (RestoreFootprintDetail, err } var contractID string - contractID, ok = o.Transaction.contractIdFromTxEnvelope() + contractID, ok = o.Transaction.ContractIdFromTxEnvelope() if ok { restoreFootprintDetail.ContractID = contractID } diff --git a/ingest/revoke_sponsorship_details.go b/ingest/processors/operation_processor/revoke_sponsorship_details.go similarity index 93% rename from ingest/revoke_sponsorship_details.go rename to ingest/processors/operation_processor/revoke_sponsorship_details.go index 654d5f128e..844ed5811a 100644 --- a/ingest/revoke_sponsorship_details.go +++ b/ingest/processors/operation_processor/revoke_sponsorship_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" @@ -22,7 +22,7 @@ func (o *LedgerOperation) RevokeSponsorshipDetails() (RevokeSponsorshipDetail, e switch op.Type { case xdr.RevokeSponsorshipTypeRevokeSponsorshipLedgerEntry: - ledgerKeyDetail, err := addLedgerKeyToDetails(*op.LedgerKey) + ledgerKeyDetail, err := addLedgerKey(*op.LedgerKey) if err != nil { return RevokeSponsorshipDetail{}, err } diff --git a/ingest/set_options_details.go b/ingest/processors/operation_processor/set_options_details.go similarity index 93% rename from ingest/set_options_details.go rename to ingest/processors/operation_processor/set_options_details.go index 2216e4b9b0..948e6b4c5e 100644 --- a/ingest/set_options_details.go +++ b/ingest/processors/operation_processor/set_options_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" @@ -34,11 +34,11 @@ func (o *LedgerOperation) SetOptionsDetails() (SetOptionsDetails, error) { } if op.SetFlags != nil && *op.SetFlags > 0 { - setOptionsDetail.SetFlags, setOptionsDetail.SetFlagsString = addOperationFlagToOperationDetails(uint32(*op.SetFlags)) + setOptionsDetail.SetFlags, setOptionsDetail.SetFlagsString = addOperationFlagToOperation(uint32(*op.SetFlags)) } if op.ClearFlags != nil && *op.ClearFlags > 0 { - setOptionsDetail.ClearFlags, setOptionsDetail.ClearFlagsString = addOperationFlagToOperationDetails(uint32(*op.ClearFlags)) + setOptionsDetail.ClearFlags, setOptionsDetail.ClearFlagsString = addOperationFlagToOperation(uint32(*op.ClearFlags)) } if op.MasterWeight != nil { @@ -69,7 +69,7 @@ func (o *LedgerOperation) SetOptionsDetails() (SetOptionsDetails, error) { return setOptionsDetail, nil } -func addOperationFlagToOperationDetails(flag uint32) ([]int32, []string) { +func addOperationFlagToOperation(flag uint32) ([]int32, []string) { intFlags := make([]int32, 0) stringFlags := make([]string, 0) diff --git a/ingest/set_trustline_flags_details.go b/ingest/processors/operation_processor/set_trustline_flags_details.go similarity index 99% rename from ingest/set_trustline_flags_details.go rename to ingest/processors/operation_processor/set_trustline_flags_details.go index 6a71c4c22a..52aabe7441 100644 --- a/ingest/set_trustline_flags_details.go +++ b/ingest/processors/operation_processor/set_trustline_flags_details.go @@ -1,4 +1,4 @@ -package ingest +package operation import ( "fmt" From 3f92082736b8e815762aa336665a090ac8f0f445 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Wed, 16 Apr 2025 22:34:35 -0400 Subject: [PATCH 40/40] Address comments --- ingest/ledger_transaction.go | 4 ++-- .../extend_footprint_ttl_details.go | 4 ++-- .../invoke_host_function_details.go | 12 ++++++------ .../operation_processor/restore_footprint_details.go | 4 ++-- xdr/operation_trace_result.go | 3 +++ 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/ingest/ledger_transaction.go b/ingest/ledger_transaction.go index 3107140eff..0287c71b38 100644 --- a/ingest/ledger_transaction.go +++ b/ingest/ledger_transaction.go @@ -632,7 +632,7 @@ func (t *LedgerTransaction) GetTransactionV1Envelope() (xdr.TransactionV1Envelop } } -func (t *LedgerTransaction) LedgerKeyHashFromTxEnvelope() []string { +func (t *LedgerTransaction) LedgerKeyHashesFromSorobanFootprint() []string { var ledgerKeyHash []string v1Envelope, ok := t.GetTransactionV1Envelope() @@ -663,7 +663,7 @@ func (t *LedgerTransaction) LedgerKeyHashFromTxEnvelope() []string { return ledgerKeyHash } -func (t *LedgerTransaction) ContractCodeHashFromTxEnvelope() (string, bool) { +func (t *LedgerTransaction) ContractCodeHashFromSorobanFootprint() (string, bool) { v1Envelope, ok := t.GetTransactionV1Envelope() if !ok { return "", false diff --git a/ingest/processors/operation_processor/extend_footprint_ttl_details.go b/ingest/processors/operation_processor/extend_footprint_ttl_details.go index 091a6bebc5..de645b25db 100644 --- a/ingest/processors/operation_processor/extend_footprint_ttl_details.go +++ b/ingest/processors/operation_processor/extend_footprint_ttl_details.go @@ -19,7 +19,7 @@ func (o *LedgerOperation) ExtendFootprintTtlDetails() (ExtendFootprintTtlDetail, extendFootprintTtlDetail := ExtendFootprintTtlDetail{ Type: "extend_footprint_ttl", ExtendTo: uint32(op.ExtendTo), - LedgerKeyHash: o.Transaction.LedgerKeyHashFromTxEnvelope(), + LedgerKeyHash: o.Transaction.LedgerKeyHashesFromSorobanFootprint(), } var contractID string @@ -29,7 +29,7 @@ func (o *LedgerOperation) ExtendFootprintTtlDetails() (ExtendFootprintTtlDetail, } var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + contractCodeHash, ok = o.Transaction.ContractCodeHashFromSorobanFootprint() if ok { extendFootprintTtlDetail.ContractCodeHash = contractCodeHash } diff --git a/ingest/processors/operation_processor/invoke_host_function_details.go b/ingest/processors/operation_processor/invoke_host_function_details.go index c7159692b5..98cc64c952 100644 --- a/ingest/processors/operation_processor/invoke_host_function_details.go +++ b/ingest/processors/operation_processor/invoke_host_function_details.go @@ -46,11 +46,11 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, return InvokeHostFunctionDetail{}, err } - invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() + invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashesFromSorobanFootprint() invokeHostFunctionDetail.ContractID = contractId var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + contractCodeHash, ok = o.Transaction.ContractCodeHashFromSorobanFootprint() if ok { invokeHostFunctionDetail.ContractCodeHash = contractCodeHash } @@ -80,10 +80,10 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, o.getCreateContractDetails(&invokeHostFunctionDetail, preImageDetails) case xdr.HostFunctionTypeHostFunctionTypeUploadContractWasm: invokeHostFunctionDetail.Type = "upload_wasm" - invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() + invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashesFromSorobanFootprint() var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + contractCodeHash, ok = o.Transaction.ContractCodeHashFromSorobanFootprint() if ok { invokeHostFunctionDetail.ContractCodeHash = contractCodeHash } @@ -115,7 +115,7 @@ func (o *LedgerOperation) InvokeHostFunctionDetails() (InvokeHostFunctionDetail, func (o *LedgerOperation) getCreateContractDetails(invokeHostFunctionDetail *InvokeHostFunctionDetail, preImageDetails PreImageDetails) { var ok bool - invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashFromTxEnvelope() + invokeHostFunctionDetail.LedgerKeyHash = o.Transaction.LedgerKeyHashesFromSorobanFootprint() var contractID string contractID, ok = o.Transaction.ContractIdFromTxEnvelope() @@ -124,7 +124,7 @@ func (o *LedgerOperation) getCreateContractDetails(invokeHostFunctionDetail *Inv } var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + contractCodeHash, ok = o.Transaction.ContractCodeHashFromSorobanFootprint() if ok { invokeHostFunctionDetail.ContractCodeHash = contractCodeHash } diff --git a/ingest/processors/operation_processor/restore_footprint_details.go b/ingest/processors/operation_processor/restore_footprint_details.go index e6baa3d0e8..002767e000 100644 --- a/ingest/processors/operation_processor/restore_footprint_details.go +++ b/ingest/processors/operation_processor/restore_footprint_details.go @@ -17,7 +17,7 @@ func (o *LedgerOperation) RestoreFootprintDetails() (RestoreFootprintDetail, err restoreFootprintDetail := RestoreFootprintDetail{ Type: "restore_footprint", - LedgerKeyHash: o.Transaction.LedgerKeyHashFromTxEnvelope(), + LedgerKeyHash: o.Transaction.LedgerKeyHashesFromSorobanFootprint(), } var contractID string @@ -27,7 +27,7 @@ func (o *LedgerOperation) RestoreFootprintDetails() (RestoreFootprintDetail, err } var contractCodeHash string - contractCodeHash, ok = o.Transaction.ContractCodeHashFromTxEnvelope() + contractCodeHash, ok = o.Transaction.ContractCodeHashFromSorobanFootprint() if ok { restoreFootprintDetail.ContractCodeHash = contractCodeHash } diff --git a/xdr/operation_trace_result.go b/xdr/operation_trace_result.go index f5c68c7989..8332797e63 100644 --- a/xdr/operation_trace_result.go +++ b/xdr/operation_trace_result.go @@ -2,6 +2,9 @@ package xdr import "fmt" +// MapOperationResultTr returns a string representation of the result code for the operation. +// Each operation type corresponds to a specific result struct (e.g., CreateAccountResult, PaymentResult, ...) +// This function extracts and returns the result code's string value. func (o OperationResultTr) MapOperationResultTr() (string, error) { var operationTraceDescription string operationType := o.Type