From c8c4cafb6600ba511f167146f3fddcda49abc54c Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Wed, 29 Jan 2025 18:02:53 -0500 Subject: [PATCH 1/4] xdrill functions for ledger entry changes --- ingest/change.go | 659 ++++++++++++++++++++++++++++++++++++ xdr/claimable_balance_id.go | 13 + xdr/data_value.go | 14 + xdr/pool_id.go | 12 + 4 files changed, 698 insertions(+) create mode 100644 xdr/data_value.go diff --git a/ingest/change.go b/ingest/change.go index 6680faa057..2f36964a61 100644 --- a/ingest/change.go +++ b/ingest/change.go @@ -3,8 +3,12 @@ package ingest import ( "bytes" "fmt" + "math/big" "sort" + "time" + "github.com/stellar/go/ingest/ledger" + "github.com/stellar/go/strkey" "github.com/stellar/go/support/errors" "github.com/stellar/go/xdr" ) @@ -327,3 +331,658 @@ func (c Change) AccountChangedExceptSigners() (bool, error) { return !bytes.Equal(preBinary, postBinary), nil } + +func (c Change) ExtractEntry() (xdr.LedgerEntry, xdr.LedgerEntryChangeType, bool, error) { + switch changeType := c.LedgerEntryChangeType(); changeType { + case xdr.LedgerEntryChangeTypeLedgerEntryCreated, xdr.LedgerEntryChangeTypeLedgerEntryUpdated: + return *c.Post, changeType, false, nil + case xdr.LedgerEntryChangeTypeLedgerEntryRemoved: + return *c.Pre, changeType, true, nil + default: + return xdr.LedgerEntry{}, changeType, false, fmt.Errorf("unable to extract ledger entry type from change") + } +} + +func (c Change) Deleted() (bool, error) { + _, _, deleted, err := c.ExtractEntry() + if err != nil { + return false, err + } + + return deleted, nil +} + +func (c Change) ClosedAt() time.Time { + if c.Ledger != nil { + return ledger.ClosedAt(*c.Ledger) + } + + return ledger.ClosedAt(c.Transaction.Ledger) +} + +func (c Change) Sequence() uint32 { + if c.Ledger != nil { + return ledger.Sequence(*c.Ledger) + } + + return ledger.Sequence(c.Transaction.Ledger) +} + +func (c Change) LastModifiedLedger() (uint32, error) { + ledgerEntry, _, _, err := c.ExtractEntry() + if err != nil { + return 0, err + } + + return uint32(ledgerEntry.LastModifiedLedgerSeq), nil +} + +func (c Change) Sponsor() (string, error) { + ledgerEntry, _, _, err := c.ExtractEntry() + if err != nil { + return "", err + } + + if ledgerEntry.SponsoringID() == nil { + return "", nil + } + + return ledgerEntry.SponsoringID().Address(), nil +} + +func (c Change) LedgerKeyHash() (string, error) { + ledgerKey, err := c.LedgerKey() + if err != nil { + return "", err + } + + return ledgerKey.MarshalBinaryBase64() +} + +func (c Change) EntryDetails(passphrase string) (map[string]interface{}, error) { + var err error + var ledgerEntry xdr.LedgerEntry + var details map[string]interface{} + + ledgerEntry, _, _, err = c.ExtractEntry() + if err != nil { + return nil, err + } + + switch ledgerEntry.Data.Type { + case xdr.LedgerEntryTypeAccount: + details, err = AccountDetails(ledgerEntry.Data.Account) + if err != nil { + return details, err + } + case xdr.LedgerEntryTypeTrustline: + details, err = TrustlineDetails(ledgerEntry.Data.TrustLine) + if err != nil { + return details, err + } + case xdr.LedgerEntryTypeOffer: + details, err = OfferDetails(ledgerEntry.Data.Offer) + if err != nil { + return details, err + } + case xdr.LedgerEntryTypeData: + details, err = DataDetails(ledgerEntry.Data.Data) + if err != nil { + return details, err + } + case xdr.LedgerEntryTypeClaimableBalance: + details, err = ClaimableBalanceDetails(ledgerEntry.Data.ClaimableBalance) + if err != nil { + return details, err + } + case xdr.LedgerEntryTypeLiquidityPool: + details, err = LiquidityPoolDetails(ledgerEntry.Data.LiquidityPool) + if err != nil { + return details, err + } + case xdr.LedgerEntryTypeContractData: + details, err = ContractDataDetails(passphrase, ledgerEntry.Data.ContractData) + if err != nil { + return details, err + } + case xdr.LedgerEntryTypeContractCode: + details, err = ContractCodeDetails(ledgerEntry.Data.ContractCode) + if err != nil { + return details, err + } + case xdr.LedgerEntryTypeTtl: + details, err = TtlDetails(ledgerEntry.Data.Ttl) + if err != nil { + return details, err + } + default: + return details, fmt.Errorf("unknown LedgerEntry data type") + } + + return details, nil +} + +type Signers struct { + Address string + Weight int32 + Sponsor string +} + +func AccountDetails(accountEntry *xdr.AccountEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + details["account_id"] = accountEntry.AccountId.Address() + details["balance"] = int64(accountEntry.Balance) + details["sequence_number"] = int64(accountEntry.SeqNum) + details["sequence_ledger"] = uint32(accountEntry.SeqLedger()) + details["sequence_time"] = int64(accountEntry.SeqTime()) + details["num_sub_entries"] = uint32(accountEntry.NumSubEntries) + details["flags"] = uint32(accountEntry.Flags) + details["home_domain"] = accountEntry.HomeDomain + details["master_key_weight"] = int32(accountEntry.MasterKeyWeight()) + details["threshold_low"] = int32(accountEntry.ThresholdLow()) + details["threshold_medium"] = int32(accountEntry.ThresholdMedium()) + details["threshold_high"] = int32(accountEntry.ThresholdHigh()) + details["num_sponsored"] = uint32(accountEntry.NumSponsored()) + details["num_sponsoring"] = uint32(accountEntry.NumSponsoring()) + + if accountEntry.InflationDest != nil { + details["inflation_destination"] = accountEntry.InflationDest.Address() + } + + accountExtensionInfo, ok := accountEntry.Ext.GetV1() + if ok { + details["buying_liabilities"] = int64(accountExtensionInfo.Liabilities.Buying) + details["selling_liabilities"] = int64(accountExtensionInfo.Liabilities.Selling) + } + + signers := []Signers{} + sponsors := accountEntry.SponsorPerSigner() + for signer, weight := range accountEntry.SignerSummary() { + sponsorDesc := sponsors[signer] + + signers = append(signers, Signers{ + Address: signer, + Weight: weight, + Sponsor: sponsorDesc.Address(), + }) + } + + details["signers"] = signers + + return details, nil +} + +func TrustlineDetails(trustlineEntry *xdr.TrustLineEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + details["account_id"] = trustlineEntry.AccountId.Address() + details["balance"] = int64(trustlineEntry.Balance) + details["trustline_limit"] = int64(trustlineEntry.Limit) + details["buying_liabilities"] = int64(trustlineEntry.Liabilities().Buying) + details["selling_liabilities"] = int64(trustlineEntry.Liabilities().Selling) + details["flags"] = uint32(trustlineEntry.Flags) + + var err error + var assetType, assetCode, assetIssuer string + err = trustlineEntry.Asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return details, err + } + + details["asset_code"] = assetCode + details["asset_issuer"] = assetIssuer + details["asset_type"] = assetType + + var poolID string + poolID, err = trustlineEntry.Asset.LiquidityPoolId.MarshalBinaryBase64() + if err != nil { + return details, err + } + + details["liquidity_pool_id"] = poolID + + return details, nil +} + +func OfferDetails(offerEntry *xdr.OfferEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + details["seller_id"] = offerEntry.SellerId.Address() + details["offer_id"] = int64(offerEntry.OfferId) + details["amount"] = int64(offerEntry.Amount) + details["price_n"] = int32(offerEntry.Price.N) + details["price_d"] = int32(offerEntry.Price.D) + details["flags"] = uint32(offerEntry.Flags) + + var err error + var sellingAssetType, sellingAssetCode, sellingAssetIssuer string + err = offerEntry.Selling.Extract(&sellingAssetType, &sellingAssetCode, &sellingAssetIssuer) + if err != nil { + return details, err + } + + details["selling_asset_code"] = sellingAssetCode + details["selling_asset_issuer"] = sellingAssetIssuer + details["selling_asset_type"] = sellingAssetType + + var buyingAssetType, buyingAssetCode, buyingAssetIssuer string + err = offerEntry.Buying.Extract(&buyingAssetType, &buyingAssetCode, &buyingAssetIssuer) + if err != nil { + return details, err + } + + details["buying_asset_code"] = buyingAssetCode + details["buying_asset_issuer"] = buyingAssetIssuer + details["buying_asset_type"] = buyingAssetType + + return details, nil +} + +func DataDetails(dataEntry *xdr.DataEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + details["account_id"] = dataEntry.AccountId.Address() + details["data_name"] = string(dataEntry.DataName) + + dataValue, err := dataEntry.DataValue.MarshalBinaryBase64() + if err != nil { + return details, err + } + + details["data_value"] = dataValue + + return details, nil +} + +func ClaimableBalanceDetails(claimableBalanceEntry *xdr.ClaimableBalanceEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + details["amount"] = int64(claimableBalanceEntry.Amount) + details["flags"] = uint32(claimableBalanceEntry.Flags()) + + var err error + var balanceId string + balanceId, err = claimableBalanceEntry.BalanceId.MarshalBinaryBase64() + if err != nil { + return details, err + } + + details["balance_id"] = balanceId + + var assetType, assetCode, assetIssuer string + err = claimableBalanceEntry.Asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return details, err + } + + details["asset_code"] = assetCode + details["asset_issuer"] = assetIssuer + details["asset_type"] = assetType + + var claimants []Claimant + for _, c := range claimableBalanceEntry.Claimants { + switch c.Type { + case 0: + claimants = append(claimants, Claimant{ + Destination: c.V0.Destination.Address(), + Predicate: c.V0.Predicate, + }) + } + } + + details["claimants"] = claimants + + return details, nil +} + +func LiquidityPoolDetails(liquidityPoolEntry *xdr.LiquidityPoolEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + details["liquidity_pool_type"] = liquidityPoolEntry.Body.Type + + var err error + var liquidtiyPoolID string + liquidtiyPoolID, err = liquidityPoolEntry.LiquidityPoolId.MarshalBinaryBase64() + if err != nil { + return details, err + } + + details["liquidity_pool_id"] = liquidtiyPoolID + + var ok bool + var constantProduct xdr.LiquidityPoolEntryConstantProduct + constantProduct, ok = liquidityPoolEntry.Body.GetConstantProduct() + if !ok { + details["liquidity_pool_fee"] = int32(0) + details["trustline_count"] = int64(0) + details["pool_share_count"] = int64(0) + details["asset_a_code"] = "" + details["asset_a_issuer"] = "" + details["asset_a_type"] = "" + details["asset_a_reserve"] = int64(0) + details["asset_b_code"] = "" + details["asset_b_issuer"] = "" + details["asset_b_type"] = "" + details["asset_b_reserve"] = int64(0) + } else { + details["liquidity_pool_fee"] = int32(constantProduct.Params.Fee) + details["trustline_count"] = int64(constantProduct.PoolSharesTrustLineCount) + details["pool_share_count"] = int64(constantProduct.PoolSharesTrustLineCount) + var assetAType, assetACode, assetAIssuer string + err = constantProduct.Params.AssetA.Extract(&assetAType, &assetACode, &assetAIssuer) + if err != nil { + return details, err + } + + details["asset_a_code"] = assetACode + details["asset_a_issuer"] = assetAIssuer + details["asset_a_type"] = assetAType + details["asset_a_reserve"] = int64(constantProduct.ReserveA) + + var assetBType, assetBCode, assetBIssuer string + err = constantProduct.Params.AssetB.Extract(&assetBType, &assetBCode, &assetBIssuer) + if err != nil { + return details, err + } + + details["asset_b_code"] = assetBCode + details["asset_b_issuer"] = assetBIssuer + details["asset_b_type"] = assetBType + details["asset_b_reserve"] = int64(constantProduct.ReserveB) + } + + return details, nil +} + +func ContractDataDetails(passphrase string, contractDataEntry *xdr.ContractDataEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + // This should use xdr2json + details["contract_key"] = contractDataEntry.Key + details["contract_val"] = contractDataEntry.Val + + details["contract_durability"] = contractDataEntry.Durability.String() + + contractAsset := AssetFromContractData(passphrase, *contractDataEntry) + + var err error + var ok bool + var assetType, assetCode, assetIssuer string + err = contractAsset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return details, err + } + + details["asset_code"] = assetCode + details["asset_issuer"] = assetIssuer + details["asset_type"] = assetType + + var contractDataBalanceHolder string + dataBalanceHolder, dataBalance, ok := ContractBalanceFromContractData(passphrase, *contractDataEntry) + if ok { + holderHashByte, _ := xdr.Hash(dataBalanceHolder).MarshalBinary() + contractDataBalanceHolder, _ = strkey.Encode(strkey.VersionByteContract, holderHashByte) + details["balance_holder"] = contractDataBalanceHolder + details["balance"] = dataBalance.String() + } + + var contractDataContractId xdr.Hash + contractDataContractId, ok = contractDataEntry.Contract.GetContractId() + if ok { + var contractDataContractIdByte []byte + contractDataContractIdByte, err = contractDataContractId.MarshalBinary() + if err != nil { + return details, err + } + + var contractDataContractIdString string + contractDataContractIdString, err = strkey.Encode(strkey.VersionByteContract, contractDataContractIdByte) + if err != nil { + return details, err + } + + details["contract_id"] = contractDataContractIdString + } + + return details, nil +} + +func ContractCodeDetails(contractCodeEntry *xdr.ContractCodeEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + switch contractCodeEntry.Ext.V { + case 1: + details["n_instructions"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NInstructions) + details["n_functions"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NFunctions) + details["n_globals"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NGlobals) + details["n_table_entries"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NTableEntries) + details["n_types"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NTypes) + details["n_data_segments"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NDataSegments) + details["n_elem_segments"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NElemSegments) + details["n_imports"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NImports) + details["n_exports"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NExports) + details["n_data_segment_bytes"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NDataSegmentBytes) + default: + return details, fmt.Errorf("unknown ContractCodeEntry.Ext.V") + } + + var err error + var contractCode string + contractCode, err = contractCodeEntry.Hash.MarshalBinaryBase64() + if err != nil { + return details, err + } + + details["contract_code_hash"] = contractCode + + return details, nil +} + +func TtlDetails(ttlEntry *xdr.TtlEntry) (map[string]interface{}, error) { + details := map[string]interface{}{} + + details["live_until_ledger_seq"] = uint32(ttlEntry.LiveUntilLedgerSeq) + + return details, nil +} + +var ( + // these are storage DataKey enum + // https://github.com/stellar/rs-soroban-env/blob/v0.0.16/soroban-env-host/src/native_contract/token/storage_types.rs#L23 + balanceMetadataSym = xdr.ScSymbol("Balance") + issuerSym = xdr.ScSymbol("issuer") + assetCodeSym = xdr.ScSymbol("asset_code") + assetInfoSym = xdr.ScSymbol("AssetInfo") + assetInfoVec = &xdr.ScVec{ + xdr.ScVal{ + Type: xdr.ScValTypeScvSymbol, + Sym: &assetInfoSym, + }, + } + assetInfoKey = xdr.ScVal{ + Type: xdr.ScValTypeScvVec, + Vec: &assetInfoVec, + } +) + +func AssetFromContractData(passphrase string, contractData xdr.ContractDataEntry) *xdr.Asset { + if contractData.Key.Type != xdr.ScValTypeScvLedgerKeyContractInstance { + return nil + } + contractInstanceData, ok := contractData.Val.GetInstance() + if !ok || contractInstanceData.Storage == nil { + return nil + } + + nativeAssetContractID, err := xdr.MustNewNativeAsset().ContractID(passphrase) + if err != nil { + return nil + } + + var assetInfo *xdr.ScVal + for _, mapEntry := range *contractInstanceData.Storage { + if mapEntry.Key.Equals(assetInfoKey) { + // clone the map entry to avoid reference to loop iterator + mapValXdr, cloneErr := mapEntry.Val.MarshalBinary() + if cloneErr != nil { + return nil + } + assetInfo = &xdr.ScVal{} + cloneErr = assetInfo.UnmarshalBinary(mapValXdr) + if cloneErr != nil { + return nil + } + break + } + } + + if assetInfo == nil { + return nil + } + + vecPtr, ok := assetInfo.GetVec() + if !ok || vecPtr == nil || len(*vecPtr) != 2 { + return nil + } + vec := *vecPtr + + sym, ok := vec[0].GetSym() + if !ok { + return nil + } + switch sym { + case "AlphaNum4": + case "AlphaNum12": + case "Native": + if contractData.Contract.ContractId != nil && (*contractData.Contract.ContractId) == nativeAssetContractID { + asset := xdr.MustNewNativeAsset() + return &asset + } + default: + return nil + } + + var assetCode, assetIssuer string + assetMapPtr, ok := vec[1].GetMap() + if !ok || assetMapPtr == nil || len(*assetMapPtr) != 2 { + return nil + } + assetMap := *assetMapPtr + + assetCodeEntry, assetIssuerEntry := assetMap[0], assetMap[1] + if sym, ok = assetCodeEntry.Key.GetSym(); !ok || sym != assetCodeSym { + return nil + } + assetCodeSc, ok := assetCodeEntry.Val.GetStr() + if !ok { + return nil + } + if assetCode = string(assetCodeSc); assetCode == "" { + return nil + } + + if sym, ok = assetIssuerEntry.Key.GetSym(); !ok || sym != issuerSym { + return nil + } + assetIssuerSc, ok := assetIssuerEntry.Val.GetBytes() + if !ok { + return nil + } + assetIssuer, err = strkey.Encode(strkey.VersionByteAccountID, assetIssuerSc) + if err != nil { + return nil + } + + asset, err := xdr.NewCreditAsset(assetCode, assetIssuer) + if err != nil { + return nil + } + + expectedID, err := asset.ContractID(passphrase) + if err != nil { + return nil + } + if contractData.Contract.ContractId == nil || expectedID != *(contractData.Contract.ContractId) { + return nil + } + + return &asset +} + +// ContractBalanceFromContractData takes a ledger entry and verifies that the +// ledger entry corresponds to the balance entry written to contract storage by +// the Stellar Asset Contract. +// +// Reference: +// +// https://github.com/stellar/rs-soroban-env/blob/da325551829d31dcbfa71427d51c18e71a121c5f/soroban-env-host/src/native_contract/token/storage_types.rs#L11-L24 +func ContractBalanceFromContractData(passphrase string, contractData xdr.ContractDataEntry) ([32]byte, *big.Int, bool) { + _, err := xdr.MustNewNativeAsset().ContractID(passphrase) + if err != nil { + return [32]byte{}, nil, false + } + + if contractData.Contract.ContractId == nil { + return [32]byte{}, nil, false + } + + keyEnumVecPtr, ok := contractData.Key.GetVec() + if !ok || keyEnumVecPtr == nil { + return [32]byte{}, nil, false + } + keyEnumVec := *keyEnumVecPtr + if len(keyEnumVec) != 2 || !keyEnumVec[0].Equals( + xdr.ScVal{ + Type: xdr.ScValTypeScvSymbol, + Sym: &balanceMetadataSym, + }, + ) { + return [32]byte{}, nil, false + } + + scAddress, ok := keyEnumVec[1].GetAddress() + if !ok { + return [32]byte{}, nil, false + } + + holder, ok := scAddress.GetContractId() + if !ok { + return [32]byte{}, nil, false + } + + balanceMapPtr, ok := contractData.Val.GetMap() + if !ok || balanceMapPtr == nil { + return [32]byte{}, nil, false + } + balanceMap := *balanceMapPtr + if !ok || len(balanceMap) != 3 { + return [32]byte{}, nil, false + } + + var keySym xdr.ScSymbol + if keySym, ok = balanceMap[0].Key.GetSym(); !ok || keySym != "amount" { + return [32]byte{}, nil, false + } + if keySym, ok = balanceMap[1].Key.GetSym(); !ok || keySym != "authorized" || + !balanceMap[1].Val.IsBool() { + return [32]byte{}, nil, false + } + if keySym, ok = balanceMap[2].Key.GetSym(); !ok || keySym != "clawback" || + !balanceMap[2].Val.IsBool() { + return [32]byte{}, nil, false + } + amount, ok := balanceMap[0].Val.GetI128() + if !ok { + return [32]byte{}, nil, false + } + + // amount cannot be negative + // https://github.com/stellar/rs-soroban-env/blob/a66f0815ba06a2f5328ac420950690fd1642f887/soroban-env-host/src/native_contract/token/balance.rs#L92-L93 + if int64(amount.Hi) < 0 { + return [32]byte{}, nil, false + } + amt := new(big.Int).Lsh(new(big.Int).SetInt64(int64(amount.Hi)), 64) + amt.Add(amt, new(big.Int).SetUint64(uint64(amount.Lo))) + return holder, amt, true +} diff --git a/xdr/claimable_balance_id.go b/xdr/claimable_balance_id.go index 43b07d084c..129347f5c7 100644 --- a/xdr/claimable_balance_id.go +++ b/xdr/claimable_balance_id.go @@ -1,5 +1,7 @@ package xdr +import "encoding/base64" + func (e *EncodingBuffer) claimableBalanceCompressEncodeTo(cb ClaimableBalanceId) error { if err := e.xdrEncoderBuf.WriteByte(byte(cb.Type)); err != nil { return err @@ -12,3 +14,14 @@ func (e *EncodingBuffer) claimableBalanceCompressEncodeTo(cb ClaimableBalanceId) panic("Unknown type") } } + +// MarshalBinaryBase64 marshals XDR into a binary form and then encodes it +// using base64. +func (c ClaimableBalanceId) MarshalBinaryBase64() (string, error) { + b, err := c.MarshalBinary() + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(b), nil +} diff --git a/xdr/data_value.go b/xdr/data_value.go new file mode 100644 index 0000000000..78a613ba61 --- /dev/null +++ b/xdr/data_value.go @@ -0,0 +1,14 @@ +package xdr + +import "encoding/base64" + +// MarshalBinaryBase64 marshals XDR into a binary form and then encodes it +// using base64. +func (d DataValue) MarshalBinaryBase64() (string, error) { + b, err := d.MarshalBinary() + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(b), nil +} diff --git a/xdr/pool_id.go b/xdr/pool_id.go index 605c6edaa0..7f366c99fc 100644 --- a/xdr/pool_id.go +++ b/xdr/pool_id.go @@ -3,6 +3,7 @@ package xdr import ( "bytes" "crypto/sha256" + "encoding/base64" "github.com/stellar/go/support/errors" ) @@ -28,3 +29,14 @@ func NewPoolId(a, b Asset, fee Int32) (PoolId, error) { } return sha256.Sum256(buf.Bytes()), nil } + +// MarshalBinaryBase64 marshals XDR into a binary form and then encodes it +// using base64. +func (p PoolId) MarshalBinaryBase64() (string, error) { + b, err := p.MarshalBinary() + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(b), nil +} From 17a986826e8d483b6bdbb57ded69b0daa39c35b7 Mon Sep 17 00:00:00 2001 From: chowbao Date: Thu, 30 Jan 2025 11:57:12 -0500 Subject: [PATCH 2/4] Update ingest/change.go Co-authored-by: George --- ingest/change.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ingest/change.go b/ingest/change.go index 2f36964a61..deefa03a5e 100644 --- a/ingest/change.go +++ b/ingest/change.go @@ -344,12 +344,7 @@ func (c Change) ExtractEntry() (xdr.LedgerEntry, xdr.LedgerEntryChangeType, bool } func (c Change) Deleted() (bool, error) { - _, _, deleted, err := c.ExtractEntry() - if err != nil { - return false, err - } - - return deleted, nil + return c.LedgerEntryChangeType() == xdr.LedgerEntryChangeTypeEntryRemoved } func (c Change) ClosedAt() time.Time { From 691bfd81b7155b1494bdbb4a546552dfcd51ed23 Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Mon, 3 Feb 2025 12:23:02 -0500 Subject: [PATCH 3/4] reformat changes --- ingest/change.go | 554 +----------------------- ingest/ledgerentry/account.go | 76 ++++ ingest/ledgerentry/claimable_balance.go | 62 +++ ingest/ledgerentry/contract_code.go | 52 +++ ingest/ledgerentry/contract_data.go | 272 ++++++++++++ ingest/ledgerentry/data.go | 25 ++ ingest/ledgerentry/liquidity_pool.go | 71 +++ ingest/ledgerentry/offer.go | 52 +++ ingest/ledgerentry/trustline.go | 48 ++ ingest/ledgerentry/ttl.go | 13 + 10 files changed, 685 insertions(+), 540 deletions(-) create mode 100644 ingest/ledgerentry/account.go create mode 100644 ingest/ledgerentry/claimable_balance.go create mode 100644 ingest/ledgerentry/contract_code.go create mode 100644 ingest/ledgerentry/contract_data.go create mode 100644 ingest/ledgerentry/data.go create mode 100644 ingest/ledgerentry/liquidity_pool.go create mode 100644 ingest/ledgerentry/offer.go create mode 100644 ingest/ledgerentry/trustline.go create mode 100644 ingest/ledgerentry/ttl.go diff --git a/ingest/change.go b/ingest/change.go index deefa03a5e..e60bef5a98 100644 --- a/ingest/change.go +++ b/ingest/change.go @@ -3,12 +3,11 @@ package ingest import ( "bytes" "fmt" - "math/big" "sort" "time" "github.com/stellar/go/ingest/ledger" - "github.com/stellar/go/strkey" + "github.com/stellar/go/ingest/ledgerentry" "github.com/stellar/go/support/errors" "github.com/stellar/go/xdr" ) @@ -343,8 +342,8 @@ func (c Change) ExtractEntry() (xdr.LedgerEntry, xdr.LedgerEntryChangeType, bool } } -func (c Change) Deleted() (bool, error) { - return c.LedgerEntryChangeType() == xdr.LedgerEntryChangeTypeEntryRemoved +func (c Change) Deleted() bool { + return c.LedgerEntryChangeType() == xdr.LedgerEntryChangeTypeLedgerEntryRemoved } func (c Change) ClosedAt() time.Time { @@ -394,10 +393,10 @@ func (c Change) LedgerKeyHash() (string, error) { return ledgerKey.MarshalBinaryBase64() } -func (c Change) EntryDetails(passphrase string) (map[string]interface{}, error) { +func (c Change) EntryDetails(passphrase string) (interface{}, error) { var err error var ledgerEntry xdr.LedgerEntry - var details map[string]interface{} + var details interface{} ledgerEntry, _, _, err = c.ExtractEntry() if err != nil { @@ -406,47 +405,47 @@ func (c Change) EntryDetails(passphrase string) (map[string]interface{}, error) switch ledgerEntry.Data.Type { case xdr.LedgerEntryTypeAccount: - details, err = AccountDetails(ledgerEntry.Data.Account) + details, err = ledgerentry.AccountDetails(ledgerEntry.Data.Account) if err != nil { return details, err } case xdr.LedgerEntryTypeTrustline: - details, err = TrustlineDetails(ledgerEntry.Data.TrustLine) + details, err = ledgerentry.TrustlineDetails(ledgerEntry.Data.TrustLine) if err != nil { return details, err } case xdr.LedgerEntryTypeOffer: - details, err = OfferDetails(ledgerEntry.Data.Offer) + details, err = ledgerentry.OfferDetails(ledgerEntry.Data.Offer) if err != nil { return details, err } case xdr.LedgerEntryTypeData: - details, err = DataDetails(ledgerEntry.Data.Data) + details, err = ledgerentry.DataDetails(ledgerEntry.Data.Data) if err != nil { return details, err } case xdr.LedgerEntryTypeClaimableBalance: - details, err = ClaimableBalanceDetails(ledgerEntry.Data.ClaimableBalance) + details, err = ledgerentry.ClaimableBalanceDetails(ledgerEntry.Data.ClaimableBalance) if err != nil { return details, err } case xdr.LedgerEntryTypeLiquidityPool: - details, err = LiquidityPoolDetails(ledgerEntry.Data.LiquidityPool) + details, err = ledgerentry.LiquidityPoolDetails(ledgerEntry.Data.LiquidityPool) if err != nil { return details, err } case xdr.LedgerEntryTypeContractData: - details, err = ContractDataDetails(passphrase, ledgerEntry.Data.ContractData) + details, err = ledgerentry.ContractDataDetails(passphrase, ledgerEntry.Data.ContractData) if err != nil { return details, err } case xdr.LedgerEntryTypeContractCode: - details, err = ContractCodeDetails(ledgerEntry.Data.ContractCode) + details, err = ledgerentry.ContractCodeDetails(ledgerEntry.Data.ContractCode) if err != nil { return details, err } case xdr.LedgerEntryTypeTtl: - details, err = TtlDetails(ledgerEntry.Data.Ttl) + details, err = ledgerentry.TtlDetails(ledgerEntry.Data.Ttl) if err != nil { return details, err } @@ -456,528 +455,3 @@ func (c Change) EntryDetails(passphrase string) (map[string]interface{}, error) return details, nil } - -type Signers struct { - Address string - Weight int32 - Sponsor string -} - -func AccountDetails(accountEntry *xdr.AccountEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - details["account_id"] = accountEntry.AccountId.Address() - details["balance"] = int64(accountEntry.Balance) - details["sequence_number"] = int64(accountEntry.SeqNum) - details["sequence_ledger"] = uint32(accountEntry.SeqLedger()) - details["sequence_time"] = int64(accountEntry.SeqTime()) - details["num_sub_entries"] = uint32(accountEntry.NumSubEntries) - details["flags"] = uint32(accountEntry.Flags) - details["home_domain"] = accountEntry.HomeDomain - details["master_key_weight"] = int32(accountEntry.MasterKeyWeight()) - details["threshold_low"] = int32(accountEntry.ThresholdLow()) - details["threshold_medium"] = int32(accountEntry.ThresholdMedium()) - details["threshold_high"] = int32(accountEntry.ThresholdHigh()) - details["num_sponsored"] = uint32(accountEntry.NumSponsored()) - details["num_sponsoring"] = uint32(accountEntry.NumSponsoring()) - - if accountEntry.InflationDest != nil { - details["inflation_destination"] = accountEntry.InflationDest.Address() - } - - accountExtensionInfo, ok := accountEntry.Ext.GetV1() - if ok { - details["buying_liabilities"] = int64(accountExtensionInfo.Liabilities.Buying) - details["selling_liabilities"] = int64(accountExtensionInfo.Liabilities.Selling) - } - - signers := []Signers{} - sponsors := accountEntry.SponsorPerSigner() - for signer, weight := range accountEntry.SignerSummary() { - sponsorDesc := sponsors[signer] - - signers = append(signers, Signers{ - Address: signer, - Weight: weight, - Sponsor: sponsorDesc.Address(), - }) - } - - details["signers"] = signers - - return details, nil -} - -func TrustlineDetails(trustlineEntry *xdr.TrustLineEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - details["account_id"] = trustlineEntry.AccountId.Address() - details["balance"] = int64(trustlineEntry.Balance) - details["trustline_limit"] = int64(trustlineEntry.Limit) - details["buying_liabilities"] = int64(trustlineEntry.Liabilities().Buying) - details["selling_liabilities"] = int64(trustlineEntry.Liabilities().Selling) - details["flags"] = uint32(trustlineEntry.Flags) - - var err error - var assetType, assetCode, assetIssuer string - err = trustlineEntry.Asset.Extract(&assetType, &assetCode, &assetIssuer) - if err != nil { - return details, err - } - - details["asset_code"] = assetCode - details["asset_issuer"] = assetIssuer - details["asset_type"] = assetType - - var poolID string - poolID, err = trustlineEntry.Asset.LiquidityPoolId.MarshalBinaryBase64() - if err != nil { - return details, err - } - - details["liquidity_pool_id"] = poolID - - return details, nil -} - -func OfferDetails(offerEntry *xdr.OfferEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - details["seller_id"] = offerEntry.SellerId.Address() - details["offer_id"] = int64(offerEntry.OfferId) - details["amount"] = int64(offerEntry.Amount) - details["price_n"] = int32(offerEntry.Price.N) - details["price_d"] = int32(offerEntry.Price.D) - details["flags"] = uint32(offerEntry.Flags) - - var err error - var sellingAssetType, sellingAssetCode, sellingAssetIssuer string - err = offerEntry.Selling.Extract(&sellingAssetType, &sellingAssetCode, &sellingAssetIssuer) - if err != nil { - return details, err - } - - details["selling_asset_code"] = sellingAssetCode - details["selling_asset_issuer"] = sellingAssetIssuer - details["selling_asset_type"] = sellingAssetType - - var buyingAssetType, buyingAssetCode, buyingAssetIssuer string - err = offerEntry.Buying.Extract(&buyingAssetType, &buyingAssetCode, &buyingAssetIssuer) - if err != nil { - return details, err - } - - details["buying_asset_code"] = buyingAssetCode - details["buying_asset_issuer"] = buyingAssetIssuer - details["buying_asset_type"] = buyingAssetType - - return details, nil -} - -func DataDetails(dataEntry *xdr.DataEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - details["account_id"] = dataEntry.AccountId.Address() - details["data_name"] = string(dataEntry.DataName) - - dataValue, err := dataEntry.DataValue.MarshalBinaryBase64() - if err != nil { - return details, err - } - - details["data_value"] = dataValue - - return details, nil -} - -func ClaimableBalanceDetails(claimableBalanceEntry *xdr.ClaimableBalanceEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - details["amount"] = int64(claimableBalanceEntry.Amount) - details["flags"] = uint32(claimableBalanceEntry.Flags()) - - var err error - var balanceId string - balanceId, err = claimableBalanceEntry.BalanceId.MarshalBinaryBase64() - if err != nil { - return details, err - } - - details["balance_id"] = balanceId - - var assetType, assetCode, assetIssuer string - err = claimableBalanceEntry.Asset.Extract(&assetType, &assetCode, &assetIssuer) - if err != nil { - return details, err - } - - details["asset_code"] = assetCode - details["asset_issuer"] = assetIssuer - details["asset_type"] = assetType - - var claimants []Claimant - for _, c := range claimableBalanceEntry.Claimants { - switch c.Type { - case 0: - claimants = append(claimants, Claimant{ - Destination: c.V0.Destination.Address(), - Predicate: c.V0.Predicate, - }) - } - } - - details["claimants"] = claimants - - return details, nil -} - -func LiquidityPoolDetails(liquidityPoolEntry *xdr.LiquidityPoolEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - details["liquidity_pool_type"] = liquidityPoolEntry.Body.Type - - var err error - var liquidtiyPoolID string - liquidtiyPoolID, err = liquidityPoolEntry.LiquidityPoolId.MarshalBinaryBase64() - if err != nil { - return details, err - } - - details["liquidity_pool_id"] = liquidtiyPoolID - - var ok bool - var constantProduct xdr.LiquidityPoolEntryConstantProduct - constantProduct, ok = liquidityPoolEntry.Body.GetConstantProduct() - if !ok { - details["liquidity_pool_fee"] = int32(0) - details["trustline_count"] = int64(0) - details["pool_share_count"] = int64(0) - details["asset_a_code"] = "" - details["asset_a_issuer"] = "" - details["asset_a_type"] = "" - details["asset_a_reserve"] = int64(0) - details["asset_b_code"] = "" - details["asset_b_issuer"] = "" - details["asset_b_type"] = "" - details["asset_b_reserve"] = int64(0) - } else { - details["liquidity_pool_fee"] = int32(constantProduct.Params.Fee) - details["trustline_count"] = int64(constantProduct.PoolSharesTrustLineCount) - details["pool_share_count"] = int64(constantProduct.PoolSharesTrustLineCount) - var assetAType, assetACode, assetAIssuer string - err = constantProduct.Params.AssetA.Extract(&assetAType, &assetACode, &assetAIssuer) - if err != nil { - return details, err - } - - details["asset_a_code"] = assetACode - details["asset_a_issuer"] = assetAIssuer - details["asset_a_type"] = assetAType - details["asset_a_reserve"] = int64(constantProduct.ReserveA) - - var assetBType, assetBCode, assetBIssuer string - err = constantProduct.Params.AssetB.Extract(&assetBType, &assetBCode, &assetBIssuer) - if err != nil { - return details, err - } - - details["asset_b_code"] = assetBCode - details["asset_b_issuer"] = assetBIssuer - details["asset_b_type"] = assetBType - details["asset_b_reserve"] = int64(constantProduct.ReserveB) - } - - return details, nil -} - -func ContractDataDetails(passphrase string, contractDataEntry *xdr.ContractDataEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - // This should use xdr2json - details["contract_key"] = contractDataEntry.Key - details["contract_val"] = contractDataEntry.Val - - details["contract_durability"] = contractDataEntry.Durability.String() - - contractAsset := AssetFromContractData(passphrase, *contractDataEntry) - - var err error - var ok bool - var assetType, assetCode, assetIssuer string - err = contractAsset.Extract(&assetType, &assetCode, &assetIssuer) - if err != nil { - return details, err - } - - details["asset_code"] = assetCode - details["asset_issuer"] = assetIssuer - details["asset_type"] = assetType - - var contractDataBalanceHolder string - dataBalanceHolder, dataBalance, ok := ContractBalanceFromContractData(passphrase, *contractDataEntry) - if ok { - holderHashByte, _ := xdr.Hash(dataBalanceHolder).MarshalBinary() - contractDataBalanceHolder, _ = strkey.Encode(strkey.VersionByteContract, holderHashByte) - details["balance_holder"] = contractDataBalanceHolder - details["balance"] = dataBalance.String() - } - - var contractDataContractId xdr.Hash - contractDataContractId, ok = contractDataEntry.Contract.GetContractId() - if ok { - var contractDataContractIdByte []byte - contractDataContractIdByte, err = contractDataContractId.MarshalBinary() - if err != nil { - return details, err - } - - var contractDataContractIdString string - contractDataContractIdString, err = strkey.Encode(strkey.VersionByteContract, contractDataContractIdByte) - if err != nil { - return details, err - } - - details["contract_id"] = contractDataContractIdString - } - - return details, nil -} - -func ContractCodeDetails(contractCodeEntry *xdr.ContractCodeEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - switch contractCodeEntry.Ext.V { - case 1: - details["n_instructions"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NInstructions) - details["n_functions"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NFunctions) - details["n_globals"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NGlobals) - details["n_table_entries"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NTableEntries) - details["n_types"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NTypes) - details["n_data_segments"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NDataSegments) - details["n_elem_segments"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NElemSegments) - details["n_imports"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NImports) - details["n_exports"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NExports) - details["n_data_segment_bytes"] = uint32(contractCodeEntry.Ext.V1.CostInputs.NDataSegmentBytes) - default: - return details, fmt.Errorf("unknown ContractCodeEntry.Ext.V") - } - - var err error - var contractCode string - contractCode, err = contractCodeEntry.Hash.MarshalBinaryBase64() - if err != nil { - return details, err - } - - details["contract_code_hash"] = contractCode - - return details, nil -} - -func TtlDetails(ttlEntry *xdr.TtlEntry) (map[string]interface{}, error) { - details := map[string]interface{}{} - - details["live_until_ledger_seq"] = uint32(ttlEntry.LiveUntilLedgerSeq) - - return details, nil -} - -var ( - // these are storage DataKey enum - // https://github.com/stellar/rs-soroban-env/blob/v0.0.16/soroban-env-host/src/native_contract/token/storage_types.rs#L23 - balanceMetadataSym = xdr.ScSymbol("Balance") - issuerSym = xdr.ScSymbol("issuer") - assetCodeSym = xdr.ScSymbol("asset_code") - assetInfoSym = xdr.ScSymbol("AssetInfo") - assetInfoVec = &xdr.ScVec{ - xdr.ScVal{ - Type: xdr.ScValTypeScvSymbol, - Sym: &assetInfoSym, - }, - } - assetInfoKey = xdr.ScVal{ - Type: xdr.ScValTypeScvVec, - Vec: &assetInfoVec, - } -) - -func AssetFromContractData(passphrase string, contractData xdr.ContractDataEntry) *xdr.Asset { - if contractData.Key.Type != xdr.ScValTypeScvLedgerKeyContractInstance { - return nil - } - contractInstanceData, ok := contractData.Val.GetInstance() - if !ok || contractInstanceData.Storage == nil { - return nil - } - - nativeAssetContractID, err := xdr.MustNewNativeAsset().ContractID(passphrase) - if err != nil { - return nil - } - - var assetInfo *xdr.ScVal - for _, mapEntry := range *contractInstanceData.Storage { - if mapEntry.Key.Equals(assetInfoKey) { - // clone the map entry to avoid reference to loop iterator - mapValXdr, cloneErr := mapEntry.Val.MarshalBinary() - if cloneErr != nil { - return nil - } - assetInfo = &xdr.ScVal{} - cloneErr = assetInfo.UnmarshalBinary(mapValXdr) - if cloneErr != nil { - return nil - } - break - } - } - - if assetInfo == nil { - return nil - } - - vecPtr, ok := assetInfo.GetVec() - if !ok || vecPtr == nil || len(*vecPtr) != 2 { - return nil - } - vec := *vecPtr - - sym, ok := vec[0].GetSym() - if !ok { - return nil - } - switch sym { - case "AlphaNum4": - case "AlphaNum12": - case "Native": - if contractData.Contract.ContractId != nil && (*contractData.Contract.ContractId) == nativeAssetContractID { - asset := xdr.MustNewNativeAsset() - return &asset - } - default: - return nil - } - - var assetCode, assetIssuer string - assetMapPtr, ok := vec[1].GetMap() - if !ok || assetMapPtr == nil || len(*assetMapPtr) != 2 { - return nil - } - assetMap := *assetMapPtr - - assetCodeEntry, assetIssuerEntry := assetMap[0], assetMap[1] - if sym, ok = assetCodeEntry.Key.GetSym(); !ok || sym != assetCodeSym { - return nil - } - assetCodeSc, ok := assetCodeEntry.Val.GetStr() - if !ok { - return nil - } - if assetCode = string(assetCodeSc); assetCode == "" { - return nil - } - - if sym, ok = assetIssuerEntry.Key.GetSym(); !ok || sym != issuerSym { - return nil - } - assetIssuerSc, ok := assetIssuerEntry.Val.GetBytes() - if !ok { - return nil - } - assetIssuer, err = strkey.Encode(strkey.VersionByteAccountID, assetIssuerSc) - if err != nil { - return nil - } - - asset, err := xdr.NewCreditAsset(assetCode, assetIssuer) - if err != nil { - return nil - } - - expectedID, err := asset.ContractID(passphrase) - if err != nil { - return nil - } - if contractData.Contract.ContractId == nil || expectedID != *(contractData.Contract.ContractId) { - return nil - } - - return &asset -} - -// ContractBalanceFromContractData takes a ledger entry and verifies that the -// ledger entry corresponds to the balance entry written to contract storage by -// the Stellar Asset Contract. -// -// Reference: -// -// https://github.com/stellar/rs-soroban-env/blob/da325551829d31dcbfa71427d51c18e71a121c5f/soroban-env-host/src/native_contract/token/storage_types.rs#L11-L24 -func ContractBalanceFromContractData(passphrase string, contractData xdr.ContractDataEntry) ([32]byte, *big.Int, bool) { - _, err := xdr.MustNewNativeAsset().ContractID(passphrase) - if err != nil { - return [32]byte{}, nil, false - } - - if contractData.Contract.ContractId == nil { - return [32]byte{}, nil, false - } - - keyEnumVecPtr, ok := contractData.Key.GetVec() - if !ok || keyEnumVecPtr == nil { - return [32]byte{}, nil, false - } - keyEnumVec := *keyEnumVecPtr - if len(keyEnumVec) != 2 || !keyEnumVec[0].Equals( - xdr.ScVal{ - Type: xdr.ScValTypeScvSymbol, - Sym: &balanceMetadataSym, - }, - ) { - return [32]byte{}, nil, false - } - - scAddress, ok := keyEnumVec[1].GetAddress() - if !ok { - return [32]byte{}, nil, false - } - - holder, ok := scAddress.GetContractId() - if !ok { - return [32]byte{}, nil, false - } - - balanceMapPtr, ok := contractData.Val.GetMap() - if !ok || balanceMapPtr == nil { - return [32]byte{}, nil, false - } - balanceMap := *balanceMapPtr - if !ok || len(balanceMap) != 3 { - return [32]byte{}, nil, false - } - - var keySym xdr.ScSymbol - if keySym, ok = balanceMap[0].Key.GetSym(); !ok || keySym != "amount" { - return [32]byte{}, nil, false - } - if keySym, ok = balanceMap[1].Key.GetSym(); !ok || keySym != "authorized" || - !balanceMap[1].Val.IsBool() { - return [32]byte{}, nil, false - } - if keySym, ok = balanceMap[2].Key.GetSym(); !ok || keySym != "clawback" || - !balanceMap[2].Val.IsBool() { - return [32]byte{}, nil, false - } - amount, ok := balanceMap[0].Val.GetI128() - if !ok { - return [32]byte{}, nil, false - } - - // amount cannot be negative - // https://github.com/stellar/rs-soroban-env/blob/a66f0815ba06a2f5328ac420950690fd1642f887/soroban-env-host/src/native_contract/token/balance.rs#L92-L93 - if int64(amount.Hi) < 0 { - return [32]byte{}, nil, false - } - amt := new(big.Int).Lsh(new(big.Int).SetInt64(int64(amount.Hi)), 64) - amt.Add(amt, new(big.Int).SetUint64(uint64(amount.Lo))) - return holder, amt, true -} diff --git a/ingest/ledgerentry/account.go b/ingest/ledgerentry/account.go new file mode 100644 index 0000000000..33437f52d9 --- /dev/null +++ b/ingest/ledgerentry/account.go @@ -0,0 +1,76 @@ +package ledgerentry + +import ( + "github.com/stellar/go/xdr" +) + +type Account struct { + AccountID string `json:"account_id"` + Balance int64 `json:"balance"` + SequenceNumber int64 `json:"sequence_number"` + SequenceLedger uint32 `json:"sequence_ledger"` + SequenceTime int64 `json:"sequence_time"` + NumSubentries uint32 `json:"num_subentries"` + Flags uint32 `json:"flags"` + HomeDomain string `json:"home_domain"` + MasterWeight int32 `json:"master_weight"` + ThresholdLow int32 `json:"threshold_low"` + ThresholdMedium int32 `json:"threshold_medium"` + ThresholdHigh int32 `json:"threshold_high"` + NumSponsored uint32 `json:"num_sponsored"` + NumSponsoring uint32 `json:"num_sponsoring"` + BuyingLiabilities int64 `json:"buying_liabilities"` + SellingLiabilities int64 `json:"selling_liabilities"` + InflationDestination string `json:"inflation_destination"` + Signers []Signers `json:"signers"` +} + +type Signers struct { + Address string + Weight int32 + Sponsor string +} + +func AccountDetails(accountEntry *xdr.AccountEntry) (Account, error) { + account := Account{ + AccountID: accountEntry.AccountId.Address(), + SequenceNumber: int64(accountEntry.SeqNum), + SequenceLedger: uint32(accountEntry.SeqLedger()), + SequenceTime: int64(accountEntry.SeqTime()), + NumSubentries: uint32(accountEntry.NumSubEntries), + Flags: uint32(accountEntry.Flags), + HomeDomain: string(accountEntry.HomeDomain), + MasterWeight: int32(accountEntry.MasterKeyWeight()), + ThresholdLow: int32(accountEntry.ThresholdLow()), + ThresholdMedium: int32(accountEntry.ThresholdMedium()), + ThresholdHigh: int32(accountEntry.ThresholdHigh()), + NumSponsored: uint32(accountEntry.NumSponsored()), + NumSponsoring: uint32(accountEntry.NumSponsoring()), + } + + if accountEntry.InflationDest != nil { + account.InflationDestination = accountEntry.InflationDest.Address() + } + + accountExtensionInfo, ok := accountEntry.Ext.GetV1() + if ok { + account.BuyingLiabilities = int64(accountExtensionInfo.Liabilities.Buying) + account.SellingLiabilities = int64(accountExtensionInfo.Liabilities.Selling) + } + + signers := []Signers{} + sponsors := accountEntry.SponsorPerSigner() + for signer, weight := range accountEntry.SignerSummary() { + sponsorDesc := sponsors[signer] + + signers = append(signers, Signers{ + Address: signer, + Weight: weight, + Sponsor: sponsorDesc.Address(), + }) + } + + account.Signers = signers + + return account, nil +} diff --git a/ingest/ledgerentry/claimable_balance.go b/ingest/ledgerentry/claimable_balance.go new file mode 100644 index 0000000000..ff39276538 --- /dev/null +++ b/ingest/ledgerentry/claimable_balance.go @@ -0,0 +1,62 @@ +package ledgerentry + +import ( + "github.com/stellar/go/xdr" +) + +type ClaimableBalance struct { + BalanceID string `json:"balance_id"` + Claimants []Claimant `json:"claimants"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + AssetID int64 `json:"asset_id"` + Amount int64 `json:"amount"` + Flags uint32 `json:"flags"` +} + +type Claimant struct { + Destination string `json:"destination"` + Predicate xdr.ClaimPredicate `json:"predicate"` +} + +func ClaimableBalanceDetails(claimableBalanceEntry *xdr.ClaimableBalanceEntry) (ClaimableBalance, error) { + claimableBalance := ClaimableBalance{ + Amount: int64(claimableBalanceEntry.Amount), + Flags: uint32(claimableBalanceEntry.Flags()), + } + + var err error + var balanceID string + balanceID, err = claimableBalanceEntry.BalanceId.MarshalBinaryBase64() + if err != nil { + return ClaimableBalance{}, err + } + + claimableBalance.BalanceID = balanceID + + var assetType, assetCode, assetIssuer string + err = claimableBalanceEntry.Asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return ClaimableBalance{}, err + } + + claimableBalance.AssetCode = assetCode + claimableBalance.AssetIssuer = assetIssuer + claimableBalance.AssetType = assetType + + var claimants []Claimant + for _, c := range claimableBalanceEntry.Claimants { + switch c.Type { + case 0: + claimants = append(claimants, Claimant{ + Destination: c.V0.Destination.Address(), + Predicate: c.V0.Predicate, + }) + } + } + + claimableBalance.Claimants = claimants + + return claimableBalance, nil +} diff --git a/ingest/ledgerentry/contract_code.go b/ingest/ledgerentry/contract_code.go new file mode 100644 index 0000000000..0376a79dcc --- /dev/null +++ b/ingest/ledgerentry/contract_code.go @@ -0,0 +1,52 @@ +package ledgerentry + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +type ContractCode struct { + ContractCodeHash string `json:"contract_code_hash"` + NInstructions uint32 `json:"n_instructions"` + NFunctions uint32 `json:"n_functions"` + NGlobals uint32 `json:"n_globals"` + NTableEntries uint32 `json:"n_table_entries"` + NTypes uint32 `json:"n_types"` + NDataSegments uint32 `json:"n_data_segments"` + NElemSegments uint32 `json:"n_elem_segments"` + NImports uint32 `json:"n_imports"` + NExports uint32 `json:"n_exports"` + NDataSegmentBytes uint32 `json:"n_data_segment_bytes"` +} + +func ContractCodeDetails(contractCodeEntry *xdr.ContractCodeEntry) (ContractCode, error) { + var contractCode ContractCode + + switch contractCodeEntry.Ext.V { + case 1: + contractCode.NInstructions = uint32(contractCodeEntry.Ext.V1.CostInputs.NInstructions) + contractCode.NFunctions = uint32(contractCodeEntry.Ext.V1.CostInputs.NFunctions) + contractCode.NGlobals = uint32(contractCodeEntry.Ext.V1.CostInputs.NGlobals) + contractCode.NTableEntries = uint32(contractCodeEntry.Ext.V1.CostInputs.NTableEntries) + contractCode.NTypes = uint32(contractCodeEntry.Ext.V1.CostInputs.NTypes) + contractCode.NDataSegments = uint32(contractCodeEntry.Ext.V1.CostInputs.NDataSegments) + contractCode.NElemSegments = uint32(contractCodeEntry.Ext.V1.CostInputs.NElemSegments) + contractCode.NImports = uint32(contractCodeEntry.Ext.V1.CostInputs.NImports) + contractCode.NExports = uint32(contractCodeEntry.Ext.V1.CostInputs.NExports) + contractCode.NDataSegmentBytes = uint32(contractCodeEntry.Ext.V1.CostInputs.NDataSegmentBytes) + default: + return ContractCode{}, fmt.Errorf("unknown ContractCodeEntry.Ext.V") + } + + var err error + var contractCodeHash string + contractCodeHash, err = contractCodeEntry.Hash.MarshalBinaryBase64() + if err != nil { + return ContractCode{}, err + } + + contractCode.ContractCodeHash = contractCodeHash + + return contractCode, nil +} diff --git a/ingest/ledgerentry/contract_data.go b/ingest/ledgerentry/contract_data.go new file mode 100644 index 0000000000..a8275a6751 --- /dev/null +++ b/ingest/ledgerentry/contract_data.go @@ -0,0 +1,272 @@ +package ledgerentry + +import ( + "math/big" + + "github.com/stellar/go/strkey" + "github.com/stellar/go/xdr" +) + +type ContractData struct { + ContractId string `json:"contract_id"` + ContractKeyType string `json:"contract_key_type"` + Durability string `json:"durability"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + BalanceHolder string `json:"balance_holder"` + Balance string `json:"balance"` + KeyDecoded interface{} `json:"key_decoded"` + ValDecoded interface{} `json:"val_decoded"` +} + +func ContractDataDetails(passphrase string, contractDataEntry *xdr.ContractDataEntry) (ContractData, error) { + contractData := ContractData{ + Durability: contractDataEntry.Durability.String(), + KeyDecoded: contractDataEntry.Key, + ValDecoded: contractDataEntry.Val, + } + + contractAsset := AssetFromContractData(passphrase, *contractDataEntry) + + var err error + var ok bool + var assetType, assetCode, assetIssuer string + err = contractAsset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return ContractData{}, err + } + + contractData.AssetCode = assetCode + contractData.AssetIssuer = assetIssuer + contractData.AssetType = assetType + + var contractDataBalanceHolder string + dataBalanceHolder, dataBalance, ok := ContractBalanceFromContractData(passphrase, *contractDataEntry) + if ok { + holderHashByte, _ := xdr.Hash(dataBalanceHolder).MarshalBinary() + contractDataBalanceHolder, _ = strkey.Encode(strkey.VersionByteContract, holderHashByte) + contractData.BalanceHolder = contractDataBalanceHolder + contractData.Balance = dataBalance.String() + } + + var contractDataContractId xdr.Hash + contractDataContractId, ok = contractDataEntry.Contract.GetContractId() + if ok { + var contractDataContractIdByte []byte + contractDataContractIdByte, err = contractDataContractId.MarshalBinary() + if err != nil { + return ContractData{}, err + } + + var contractDataContractIdString string + contractDataContractIdString, err = strkey.Encode(strkey.VersionByteContract, contractDataContractIdByte) + if err != nil { + return ContractData{}, err + } + + contractData.ContractId = contractDataContractIdString + } + + return contractData, nil +} + +var ( + // these are storage DataKey enum + // https://github.com/stellar/rs-soroban-env/blob/v0.0.16/soroban-env-host/src/native_contract/token/storage_types.rs#L23 + balanceMetadataSym = xdr.ScSymbol("Balance") + issuerSym = xdr.ScSymbol("issuer") + assetCodeSym = xdr.ScSymbol("asset_code") + assetInfoSym = xdr.ScSymbol("AssetInfo") + assetInfoVec = &xdr.ScVec{ + xdr.ScVal{ + Type: xdr.ScValTypeScvSymbol, + Sym: &assetInfoSym, + }, + } + assetInfoKey = xdr.ScVal{ + Type: xdr.ScValTypeScvVec, + Vec: &assetInfoVec, + } +) + +func AssetFromContractData(passphrase string, contractData xdr.ContractDataEntry) *xdr.Asset { + if contractData.Key.Type != xdr.ScValTypeScvLedgerKeyContractInstance { + return nil + } + contractInstanceData, ok := contractData.Val.GetInstance() + if !ok || contractInstanceData.Storage == nil { + return nil + } + + nativeAssetContractID, err := xdr.MustNewNativeAsset().ContractID(passphrase) + if err != nil { + return nil + } + + var assetInfo *xdr.ScVal + for _, mapEntry := range *contractInstanceData.Storage { + if mapEntry.Key.Equals(assetInfoKey) { + // clone the map entry to avoid reference to loop iterator + mapValXdr, cloneErr := mapEntry.Val.MarshalBinary() + if cloneErr != nil { + return nil + } + assetInfo = &xdr.ScVal{} + cloneErr = assetInfo.UnmarshalBinary(mapValXdr) + if cloneErr != nil { + return nil + } + break + } + } + + if assetInfo == nil { + return nil + } + + vecPtr, ok := assetInfo.GetVec() + if !ok || vecPtr == nil || len(*vecPtr) != 2 { + return nil + } + vec := *vecPtr + + sym, ok := vec[0].GetSym() + if !ok { + return nil + } + switch sym { + case "AlphaNum4": + case "AlphaNum12": + case "Native": + if contractData.Contract.ContractId != nil && (*contractData.Contract.ContractId) == nativeAssetContractID { + asset := xdr.MustNewNativeAsset() + return &asset + } + default: + return nil + } + + var assetCode, assetIssuer string + assetMapPtr, ok := vec[1].GetMap() + if !ok || assetMapPtr == nil || len(*assetMapPtr) != 2 { + return nil + } + assetMap := *assetMapPtr + + assetCodeEntry, assetIssuerEntry := assetMap[0], assetMap[1] + if sym, ok = assetCodeEntry.Key.GetSym(); !ok || sym != assetCodeSym { + return nil + } + assetCodeSc, ok := assetCodeEntry.Val.GetStr() + if !ok { + return nil + } + if assetCode = string(assetCodeSc); assetCode == "" { + return nil + } + + if sym, ok = assetIssuerEntry.Key.GetSym(); !ok || sym != issuerSym { + return nil + } + assetIssuerSc, ok := assetIssuerEntry.Val.GetBytes() + if !ok { + return nil + } + assetIssuer, err = strkey.Encode(strkey.VersionByteAccountID, assetIssuerSc) + if err != nil { + return nil + } + + asset, err := xdr.NewCreditAsset(assetCode, assetIssuer) + if err != nil { + return nil + } + + expectedID, err := asset.ContractID(passphrase) + if err != nil { + return nil + } + if contractData.Contract.ContractId == nil || expectedID != *(contractData.Contract.ContractId) { + return nil + } + + return &asset +} + +// ContractBalanceFromContractData takes a ledger entry and verifies that the +// ledger entry corresponds to the balance entry written to contract storage by +// the Stellar Asset Contract. +// +// Reference: +// +// https://github.com/stellar/rs-soroban-env/blob/da325551829d31dcbfa71427d51c18e71a121c5f/soroban-env-host/src/native_contract/token/storage_types.rs#L11-L24 +func ContractBalanceFromContractData(passphrase string, contractData xdr.ContractDataEntry) ([32]byte, *big.Int, bool) { + _, err := xdr.MustNewNativeAsset().ContractID(passphrase) + if err != nil { + return [32]byte{}, nil, false + } + + if contractData.Contract.ContractId == nil { + return [32]byte{}, nil, false + } + + keyEnumVecPtr, ok := contractData.Key.GetVec() + if !ok || keyEnumVecPtr == nil { + return [32]byte{}, nil, false + } + keyEnumVec := *keyEnumVecPtr + if len(keyEnumVec) != 2 || !keyEnumVec[0].Equals( + xdr.ScVal{ + Type: xdr.ScValTypeScvSymbol, + Sym: &balanceMetadataSym, + }, + ) { + return [32]byte{}, nil, false + } + + scAddress, ok := keyEnumVec[1].GetAddress() + if !ok { + return [32]byte{}, nil, false + } + + holder, ok := scAddress.GetContractId() + if !ok { + return [32]byte{}, nil, false + } + + balanceMapPtr, ok := contractData.Val.GetMap() + if !ok || balanceMapPtr == nil { + return [32]byte{}, nil, false + } + balanceMap := *balanceMapPtr + if !ok || len(balanceMap) != 3 { + return [32]byte{}, nil, false + } + + var keySym xdr.ScSymbol + if keySym, ok = balanceMap[0].Key.GetSym(); !ok || keySym != "amount" { + return [32]byte{}, nil, false + } + if keySym, ok = balanceMap[1].Key.GetSym(); !ok || keySym != "authorized" || + !balanceMap[1].Val.IsBool() { + return [32]byte{}, nil, false + } + if keySym, ok = balanceMap[2].Key.GetSym(); !ok || keySym != "clawback" || + !balanceMap[2].Val.IsBool() { + return [32]byte{}, nil, false + } + amount, ok := balanceMap[0].Val.GetI128() + if !ok { + return [32]byte{}, nil, false + } + + // amount cannot be negative + // https://github.com/stellar/rs-soroban-env/blob/a66f0815ba06a2f5328ac420950690fd1642f887/soroban-env-host/src/native_contract/token/balance.rs#L92-L93 + if int64(amount.Hi) < 0 { + return [32]byte{}, nil, false + } + amt := new(big.Int).Lsh(new(big.Int).SetInt64(int64(amount.Hi)), 64) + amt.Add(amt, new(big.Int).SetUint64(uint64(amount.Lo))) + return holder, amt, true +} diff --git a/ingest/ledgerentry/data.go b/ingest/ledgerentry/data.go new file mode 100644 index 0000000000..be5ac56a9f --- /dev/null +++ b/ingest/ledgerentry/data.go @@ -0,0 +1,25 @@ +package ledgerentry + +import "github.com/stellar/go/xdr" + +type Data struct { + AccountID string `json:"account_id"` + DataName string `json:"data_name"` + DataValue string `json:"data_value"` +} + +func DataDetails(dataEntry *xdr.DataEntry) (Data, error) { + data := Data{ + AccountID: dataEntry.AccountId.Address(), + DataName: string(dataEntry.DataName), + } + + dataValue, err := dataEntry.DataValue.MarshalBinaryBase64() + if err != nil { + return Data{}, err + } + + data.DataValue = dataValue + + return data, nil +} diff --git a/ingest/ledgerentry/liquidity_pool.go b/ingest/ledgerentry/liquidity_pool.go new file mode 100644 index 0000000000..40d2b1c774 --- /dev/null +++ b/ingest/ledgerentry/liquidity_pool.go @@ -0,0 +1,71 @@ +package ledgerentry + +import ( + "github.com/stellar/go/xdr" +) + +type LiquidityPool struct { + LiquidityPoolID string `json:"liquidity_pool_id"` + Type int32 `json:"type"` + Fee int32 `json:"fee"` + TrustlineCount int64 `json:"trustline_count"` + PoolShareCount int64 `json:"pool_share_count"` + AssetAType string `json:"asset_a_type"` + AssetACode string `json:"asset_a_code"` + AssetAIssuer string `json:"asset_a_issuer"` + AssetAReserve int64 `json:"asset_a_amount"` + AssetBType string `json:"asset_b_type"` + AssetBCode string `json:"asset_b_code"` + AssetBIssuer string `json:"asset_b_issuer"` + AssetBReserve int64 `json:"asset_b_amount"` +} + +func LiquidityPoolDetails(liquidityPoolEntry *xdr.LiquidityPoolEntry) (LiquidityPool, error) { + lp := LiquidityPool{ + Type: int32(liquidityPoolEntry.Body.Type), + } + + var err error + var liquidtiyPoolID string + liquidtiyPoolID, err = liquidityPoolEntry.LiquidityPoolId.MarshalBinaryBase64() + if err != nil { + return LiquidityPool{}, err + } + + lp.LiquidityPoolID = liquidtiyPoolID + + var ok bool + var constantProduct xdr.LiquidityPoolEntryConstantProduct + constantProduct, ok = liquidityPoolEntry.Body.GetConstantProduct() + if !ok { + return lp, nil + } + + lp.Fee = int32(constantProduct.Params.Fee) + lp.TrustlineCount = int64(constantProduct.PoolSharesTrustLineCount) + lp.PoolShareCount = int64(constantProduct.TotalPoolShares) + + var assetAType, assetACode, assetAIssuer string + err = constantProduct.Params.AssetA.Extract(&assetAType, &assetACode, &assetAIssuer) + if err != nil { + return LiquidityPool{}, err + } + + lp.AssetACode = assetACode + lp.AssetAIssuer = assetAIssuer + lp.AssetAType = assetAType + lp.AssetAReserve = int64(constantProduct.ReserveA) + + var assetBType, assetBCode, assetBIssuer string + err = constantProduct.Params.AssetB.Extract(&assetBType, &assetBCode, &assetBIssuer) + if err != nil { + return LiquidityPool{}, err + } + + lp.AssetBCode = assetBCode + lp.AssetBIssuer = assetBIssuer + lp.AssetBType = assetBType + lp.AssetBReserve = int64(constantProduct.ReserveB) + + return lp, nil +} diff --git a/ingest/ledgerentry/offer.go b/ingest/ledgerentry/offer.go new file mode 100644 index 0000000000..041eef8a03 --- /dev/null +++ b/ingest/ledgerentry/offer.go @@ -0,0 +1,52 @@ +package ledgerentry + +import "github.com/stellar/go/xdr" + +type Offer struct { + SellerID string `json:"seller_id"` + OfferID int64 `json:"offer_id"` + SellingAssetType string `json:"selling_asset_type"` + SellingAssetCode string `json:"selling_asset_code"` + SellingAssetIssuer string `json:"selling_asset_issuer"` + BuyingAssetType string `json:"buying_asset_type"` + BuyingAssetCode string `json:"buying_asset_code"` + BuyingAssetIssuer string `json:"buying_asset_issuer"` + Amount int64 `json:"amount"` + PriceN int32 `json:"pricen"` + PriceD int32 `json:"priced"` + Flags uint32 `json:"flags"` +} + +func OfferDetails(offerEntry *xdr.OfferEntry) (Offer, error) { + offer := Offer{ + SellerID: offerEntry.SellerId.Address(), + OfferID: int64(offerEntry.OfferId), + Amount: int64(offerEntry.Amount), + PriceN: int32(offerEntry.Price.N), + PriceD: int32(offerEntry.Price.D), + Flags: uint32(offerEntry.Flags), + } + + var err error + var sellingAssetType, sellingAssetCode, sellingAssetIssuer string + err = offerEntry.Selling.Extract(&sellingAssetType, &sellingAssetCode, &sellingAssetIssuer) + if err != nil { + return Offer{}, err + } + + offer.SellingAssetCode = sellingAssetCode + offer.SellingAssetIssuer = sellingAssetIssuer + offer.SellingAssetType = sellingAssetType + + var buyingAssetType, buyingAssetCode, buyingAssetIssuer string + err = offerEntry.Buying.Extract(&buyingAssetType, &buyingAssetCode, &buyingAssetIssuer) + if err != nil { + return Offer{}, err + } + + offer.BuyingAssetCode = buyingAssetCode + offer.BuyingAssetIssuer = buyingAssetIssuer + offer.BuyingAssetType = buyingAssetType + + return offer, nil +} diff --git a/ingest/ledgerentry/trustline.go b/ingest/ledgerentry/trustline.go new file mode 100644 index 0000000000..26f24f9f0e --- /dev/null +++ b/ingest/ledgerentry/trustline.go @@ -0,0 +1,48 @@ +package ledgerentry + +import "github.com/stellar/go/xdr" + +type Trustline struct { + AccountID string `json:"account_id"` + AssetCode string `json:"asset_code"` + AssetIssuer string `json:"asset_issuer"` + AssetType string `json:"asset_type"` + Balance int64 `json:"balance"` + TrustlineLimit int64 `json:"trustline_limit"` + LiquidityPoolID string `json:"liquidity_pool_id"` + BuyingLiabilities int64 `json:"buying_liabilities"` + SellingLiabilities int64 `json:"selling_liabilities"` + Flags uint32 `json:"flags"` +} + +func TrustlineDetails(trustlineEntry *xdr.TrustLineEntry) (Trustline, error) { + trustline := Trustline{ + AccountID: trustlineEntry.AccountId.Address(), + Balance: int64(trustlineEntry.Balance), + TrustlineLimit: int64(trustlineEntry.Limit), + BuyingLiabilities: int64(trustlineEntry.Liabilities().Buying), + SellingLiabilities: int64(trustlineEntry.Liabilities().Selling), + Flags: uint32(trustlineEntry.Flags), + } + + var err error + var assetType, assetCode, assetIssuer string + err = trustlineEntry.Asset.Extract(&assetType, &assetCode, &assetIssuer) + if err != nil { + return Trustline{}, err + } + + trustline.AssetCode = assetCode + trustline.AssetIssuer = assetIssuer + trustline.AssetType = assetType + + var poolID string + poolID, err = trustlineEntry.Asset.LiquidityPoolId.MarshalBinaryBase64() + if err != nil { + return Trustline{}, err + } + + trustline.LiquidityPoolID = poolID + + return trustline, nil +} diff --git a/ingest/ledgerentry/ttl.go b/ingest/ledgerentry/ttl.go new file mode 100644 index 0000000000..17b871dbb5 --- /dev/null +++ b/ingest/ledgerentry/ttl.go @@ -0,0 +1,13 @@ +package ledgerentry + +import "github.com/stellar/go/xdr" + +type Ttl struct { + LiveUntilLedgerSeq uint32 +} + +func TtlDetails(ttlEntry *xdr.TtlEntry) (Ttl, error) { + return Ttl{ + LiveUntilLedgerSeq: uint32(ttlEntry.LiveUntilLedgerSeq), + }, nil +} From 08a42b71973472d390abf2d8fda3ef5e8c8180dc Mon Sep 17 00:00:00 2001 From: Simon Chow Date: Mon, 3 Feb 2025 12:32:30 -0500 Subject: [PATCH 4/4] use generic xdr marshalbase64 --- ingest/ledgerentry/claimable_balance.go | 2 +- ingest/ledgerentry/data.go | 2 +- ingest/ledgerentry/liquidity_pool.go | 2 +- ingest/ledgerentry/trustline.go | 2 +- xdr/claimable_balance_id.go | 13 ------------- xdr/data_value.go | 14 -------------- xdr/pool_id.go | 12 ------------ 7 files changed, 4 insertions(+), 43 deletions(-) delete mode 100644 xdr/data_value.go diff --git a/ingest/ledgerentry/claimable_balance.go b/ingest/ledgerentry/claimable_balance.go index ff39276538..ca64713f21 100644 --- a/ingest/ledgerentry/claimable_balance.go +++ b/ingest/ledgerentry/claimable_balance.go @@ -28,7 +28,7 @@ func ClaimableBalanceDetails(claimableBalanceEntry *xdr.ClaimableBalanceEntry) ( var err error var balanceID string - balanceID, err = claimableBalanceEntry.BalanceId.MarshalBinaryBase64() + balanceID, err = xdr.MarshalBase64(claimableBalanceEntry.BalanceId) if err != nil { return ClaimableBalance{}, err } diff --git a/ingest/ledgerentry/data.go b/ingest/ledgerentry/data.go index be5ac56a9f..47292bc73f 100644 --- a/ingest/ledgerentry/data.go +++ b/ingest/ledgerentry/data.go @@ -14,7 +14,7 @@ func DataDetails(dataEntry *xdr.DataEntry) (Data, error) { DataName: string(dataEntry.DataName), } - dataValue, err := dataEntry.DataValue.MarshalBinaryBase64() + dataValue, err := xdr.MarshalBase64(dataEntry.DataValue) if err != nil { return Data{}, err } diff --git a/ingest/ledgerentry/liquidity_pool.go b/ingest/ledgerentry/liquidity_pool.go index 40d2b1c774..79255d6272 100644 --- a/ingest/ledgerentry/liquidity_pool.go +++ b/ingest/ledgerentry/liquidity_pool.go @@ -27,7 +27,7 @@ func LiquidityPoolDetails(liquidityPoolEntry *xdr.LiquidityPoolEntry) (Liquidity var err error var liquidtiyPoolID string - liquidtiyPoolID, err = liquidityPoolEntry.LiquidityPoolId.MarshalBinaryBase64() + liquidtiyPoolID, err = xdr.MarshalBase64(liquidityPoolEntry.LiquidityPoolId) if err != nil { return LiquidityPool{}, err } diff --git a/ingest/ledgerentry/trustline.go b/ingest/ledgerentry/trustline.go index 26f24f9f0e..ae7239b230 100644 --- a/ingest/ledgerentry/trustline.go +++ b/ingest/ledgerentry/trustline.go @@ -37,7 +37,7 @@ func TrustlineDetails(trustlineEntry *xdr.TrustLineEntry) (Trustline, error) { trustline.AssetType = assetType var poolID string - poolID, err = trustlineEntry.Asset.LiquidityPoolId.MarshalBinaryBase64() + poolID, err = xdr.MarshalBase64(trustlineEntry.Asset.LiquidityPoolId) if err != nil { return Trustline{}, err } diff --git a/xdr/claimable_balance_id.go b/xdr/claimable_balance_id.go index 129347f5c7..43b07d084c 100644 --- a/xdr/claimable_balance_id.go +++ b/xdr/claimable_balance_id.go @@ -1,7 +1,5 @@ package xdr -import "encoding/base64" - func (e *EncodingBuffer) claimableBalanceCompressEncodeTo(cb ClaimableBalanceId) error { if err := e.xdrEncoderBuf.WriteByte(byte(cb.Type)); err != nil { return err @@ -14,14 +12,3 @@ func (e *EncodingBuffer) claimableBalanceCompressEncodeTo(cb ClaimableBalanceId) panic("Unknown type") } } - -// MarshalBinaryBase64 marshals XDR into a binary form and then encodes it -// using base64. -func (c ClaimableBalanceId) MarshalBinaryBase64() (string, error) { - b, err := c.MarshalBinary() - if err != nil { - return "", err - } - - return base64.StdEncoding.EncodeToString(b), nil -} diff --git a/xdr/data_value.go b/xdr/data_value.go deleted file mode 100644 index 78a613ba61..0000000000 --- a/xdr/data_value.go +++ /dev/null @@ -1,14 +0,0 @@ -package xdr - -import "encoding/base64" - -// MarshalBinaryBase64 marshals XDR into a binary form and then encodes it -// using base64. -func (d DataValue) MarshalBinaryBase64() (string, error) { - b, err := d.MarshalBinary() - if err != nil { - return "", err - } - - return base64.StdEncoding.EncodeToString(b), nil -} diff --git a/xdr/pool_id.go b/xdr/pool_id.go index 7f366c99fc..605c6edaa0 100644 --- a/xdr/pool_id.go +++ b/xdr/pool_id.go @@ -3,7 +3,6 @@ package xdr import ( "bytes" "crypto/sha256" - "encoding/base64" "github.com/stellar/go/support/errors" ) @@ -29,14 +28,3 @@ func NewPoolId(a, b Asset, fee Int32) (PoolId, error) { } return sha256.Sum256(buf.Bytes()), nil } - -// MarshalBinaryBase64 marshals XDR into a binary form and then encodes it -// using base64. -func (p PoolId) MarshalBinaryBase64() (string, error) { - b, err := p.MarshalBinary() - if err != nil { - return "", err - } - - return base64.StdEncoding.EncodeToString(b), nil -}