From e5287ce765bb353e727222188ca198d0547f77a0 Mon Sep 17 00:00:00 2001 From: Ales Verbic Date: Mon, 16 Dec 2024 15:03:24 -0500 Subject: [PATCH] feat: enhance searchUtxos by address with assetPattern Signed-off-by: Ales Verbic --- examples/query/main.go | 102 +++++++++++++++++++++++++++++++++++------ go.mod | 6 +-- go.sum | 16 +++---- 3 files changed, 98 insertions(+), 26 deletions(-) diff --git a/examples/query/main.go b/examples/query/main.go index 86048a3..92d2e1b 100644 --- a/examples/query/main.go +++ b/examples/query/main.go @@ -12,6 +12,7 @@ import ( "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" "github.com/utxorpc/go-codegen/utxorpc/v1alpha/query" utxorpc "github.com/utxorpc/go-sdk" + "google.golang.org/protobuf/types/known/fieldmaskpb" ) func main() { @@ -33,9 +34,19 @@ func main() { case "readParams": readParams(ctx, client) case "readUtxos": - readUtxos(ctx, client, "71a7498f086d378ec5e558581286629b678be1dd65d5d4e2a5d634ba6fdf8299", 0) + // readUtxos(ctx, client, "71a7498f086d378ec5e558581286629b678be1dd65d5d4e2a5d634ba6fdf8299", 0) + // readUtxos(ctx, client, "791309b6b0facc80b3fa896e830999e7bef321ea5279f6bedbe1279ee1e9d4ae", 1) + readUtxos(ctx, client, "24efe5f12d1d93bb419cfb84338d6602dfe78c614b489edb72df0594a077431c", 0) case "searchUtxos": - searchUtxos(ctx, client, "addr_test1qzrkvcfvd7k5jx54xxkz87p8xn88304jd2g4jsa0hwwmg20k3c7k36lsg8rdupz6e36j5ctzs6lzjymc9vw7djrmgdnqff9z6j") + // searchUtxos(ctx, client, "addr_test1qzrkvcfvd7k5jx54xxkz87p8xn88304jd2g4jsa0hwwmg20k3c7k36lsg8rdupz6e36j5ctzs6lzjymc9vw7djrmgdnqff9z6j", "", "") + // https://preprod.cexplorer.io/asset/asset1tvkt35str8aeepuflxmnjzcdj87em8xrlx4ehz + // Use policy ID and asset name in hex format (https://cips.cardano.org/cip/CIP-68/) + // Hunt + searchUtxos(ctx, client, "addr_test1qptfy9zhaeuqfptcu79q6gm9l3r6cfp5gnlqc7m42qwln0lsvex239qmryg4yh3pda3rh3rnce4wd46gdyqlscrq7s4shekqrt", "63f9a5fc96d4f87026e97af4569975016b50eef092a46859b61898e5", "0014df1048554e54") + // Dedi + searchUtxos(ctx, client, "addr_test1qptfy9zhaeuqfptcu79q6gm9l3r6cfp5gnlqc7m42qwln0lsvex239qmryg4yh3pda3rh3rnce4wd46gdyqlscrq7s4shekqrt", "63f9a5fc96d4f87026e97af4569975016b50eef092a46859b61898e5", "0014df1044454449") + // No assets + searchUtxos(ctx, client, "addr_test1qzrkvcfvd7k5jx54xxkz87p8xn88304jd2g4jsa0hwwmg20k3c7k36lsg8rdupz6e36j5ctzs6lzjymc9vw7djrmgdnqff9z6j", "63f9a5fc96d4f87026e97af4569975016b50eef092a46859b61898e5", "0014df1044454449") default: fmt.Println("Unknown mode:", mode) } @@ -123,7 +134,7 @@ func readUtxos(ctx context.Context, client *utxorpc.UtxorpcClient, txHashStr str } } -func searchUtxos(ctx context.Context, client *utxorpc.UtxorpcClient, rawAddress string) { +func searchUtxos(ctx context.Context, client *utxorpc.UtxorpcClient, rawAddress string, policyID string, assetName string) { // Use to support bech32/base58 addresses addr, err := common.NewAddress(rawAddress) if err != nil { @@ -134,19 +145,70 @@ func searchUtxos(ctx context.Context, client *utxorpc.UtxorpcClient, rawAddress log.Fatalf("failed to marshal address to CBOR: %v", err) } - req := connect.NewRequest(&query.SearchUtxosRequest{ - Predicate: &query.UtxoPredicate{ - Match: &query.AnyUtxoPattern{ - UtxoPattern: &query.AnyUtxoPattern_Cardano{ - Cardano: &cardano.TxOutputPattern{ - Address: &cardano.AddressPattern{ - ExactAddress: addrCbor, - }, - }, - }, + var txOutputPattern *cardano.TxOutputPattern + if policyID != "" && assetName != "" { + // Convert policyID from hex to bytes + policyIDBytes, err := hex.DecodeString(policyID) + if err != nil { + log.Fatalf("failed to decode policy ID: %v", err) + } + + // Convert assetName to bytes + assetNameBytes, err := hex.DecodeString(assetName) + if err != nil { + log.Fatalf("failed to decode asset name: %v", err) + } + + // Define the asset pattern with policy ID and asset name + assetPattern := &cardano.AssetPattern{ + PolicyId: policyIDBytes, + AssetName: assetNameBytes, + } + + // Define the TxOutput pattern including the asset filter + txOutputPattern = &cardano.TxOutputPattern{ + Address: &cardano.AddressPattern{ + ExactAddress: addrCbor, }, + Asset: assetPattern, + } + } else { + // Define the TxOutput pattern with only the address filter + txOutputPattern = &cardano.TxOutputPattern{ + Address: &cardano.AddressPattern{ + ExactAddress: addrCbor, + }, + } + } + + // Wrap the TxOutput pattern in AnyUtxoPattern for Cardano + anyUtxoPattern := &query.AnyUtxoPattern{ + UtxoPattern: &query.AnyUtxoPattern_Cardano{ + Cardano: txOutputPattern, }, - }) + } + + // Define the UtxoPredicate with the pattern + utxoPredicate := &query.UtxoPredicate{ + Match: anyUtxoPattern, + } + + // Define the field mask + fieldMask := &fieldmaskpb.FieldMask{ + Paths: []string{ + // "native_bytes", + }, + } + + // Prepare the search request + searchRequest := &query.SearchUtxosRequest{ + Predicate: utxoPredicate, + FieldMask: fieldMask, + MaxItems: 100, // Adjust based on your requirements + StartToken: "", // For pagination; empty for the first page + } + + req := connect.NewRequest(searchRequest) client.AddHeadersToRequest(req) fmt.Println("connecting to utxorpc host:", client.URL()) @@ -155,7 +217,8 @@ func searchUtxos(ctx context.Context, client *utxorpc.UtxorpcClient, rawAddress utxorpc.HandleError(err) } - fmt.Printf("Response: %+v\n", resp) + // Uncomment to print the full response for debugging + // fmt.Printf("Response: %+v\n", resp) if resp.Msg.LedgerTip != nil { fmt.Printf("Ledger Tip:\n Slot: %d\n Hash: %x\n", resp.Msg.LedgerTip.Slot, resp.Msg.LedgerTip.Hash) @@ -170,6 +233,15 @@ func searchUtxos(ctx context.Context, client *utxorpc.UtxorpcClient, rawAddress fmt.Println(" Cardano UTxO:") fmt.Printf(" Address: %x\n", cardano.Address) fmt.Printf(" Coin: %d\n", cardano.Coin) + fmt.Println(" Assets:") + for _, multiasset := range cardano.Assets { + fmt.Printf(" Policy ID: %x\n", multiasset.PolicyId) + for _, asset := range multiasset.Assets { + fmt.Printf(" Asset Name: %s\n", string(asset.Name)) + fmt.Printf(" Output Coin: %d\n", asset.OutputCoin) + fmt.Printf(" Mint Coin: %d\n", asset.MintCoin) + } + } } } } diff --git a/go.mod b/go.mod index 3798141..c208541 100644 --- a/go.mod +++ b/go.mod @@ -9,17 +9,17 @@ toolchain go1.22.8 require ( connectrpc.com/connect v1.17.0 - github.com/blinklabs-io/gouroboros v0.105.0 + github.com/blinklabs-io/gouroboros v0.105.1 github.com/utxorpc/go-codegen v0.14.0 golang.org/x/net v0.32.0 - google.golang.org/protobuf v1.35.2 + google.golang.org/protobuf v1.36.0 ) require ( github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/crypto v0.30.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect ) diff --git a/go.sum b/go.sum index 5efb946..70ee212 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ connectrpc.com/connect v1.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk= connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/blinklabs-io/gouroboros v0.105.0 h1:8/uo7mtijJrbS1mNP0KRCzdZm+lWuTGhWuA8Y40EsDU= -github.com/blinklabs-io/gouroboros v0.105.0/go.mod h1:nW0/J6Zv5Oupr4MHehfJ3noSXu7VSxKWusFRNKo0nhI= +github.com/blinklabs-io/gouroboros v0.105.1 h1:if1FBgjEPX2JVKMPwXecfP55hXBNJCzMypVlIubWngk= +github.com/blinklabs-io/gouroboros v0.105.1/go.mod h1:W7ENnAVntdrUg5c7SIfEhADTKgeXFNankI5Rfeyb5k4= 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/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -14,21 +14,21 @@ github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/utxorpc/go-codegen v0.14.0 h1:1CFhORw1c4JFae66BU6IZTJoJVhJeRPQ0alAFNE77sU= github.com/utxorpc/go-codegen v0.14.0/go.mod h1:vkKgK3zJpnaKsWqiBl/KfbNkTueDh50d8/ldxR9fDus= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= +google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=