77 "math"
88 "math/big"
99 "reflect"
10+ "regexp"
1011 "strconv"
1112 "strings"
1213 "time"
@@ -21,7 +22,6 @@ import (
2122 "github.com/iotaledger/wasp/v2/clients/iota-go/iotago/serialization"
2223 "github.com/iotaledger/wasp/v2/clients/iota-go/iotajsonrpc"
2324 "github.com/iotaledger/wasp/v2/clients/iota-go/iotasigner"
24- "github.com/iotaledger/wasp/v2/clients/iscmove/iscmoveclient"
2525 "github.com/iotaledger/wasp/v2/packages/cryptolib"
2626)
2727
@@ -49,7 +49,7 @@ func NewBindingClient(rpcUrl string) *BindingClient {
4949
5050 switch rpcUrl {
5151 case iotaconn .LocalnetEndpointURL :
52- client .qclient = iota_sdk_ffi .GraphQlClientNewLocalhost ()
52+ client .qclient = iota_sdk_ffi .GraphQlClientNewLocalnet ()
5353 case iotaconn .TestnetEndpointURL :
5454 client .qclient = iota_sdk_ffi .GraphQlClientNewTestnet ()
5555 case iotaconn .DevnetEndpointURL :
@@ -222,7 +222,7 @@ func toFfiTypeTag(tag *iotago.TypeTag) (*iota_sdk_ffi.TypeTag, error) {
222222 return nil , fmt .Errorf ("unknown TypeTag variant" )
223223}
224224
225- func mapFfiObjectToIotaResponse (obj * * iota_sdk_ffi.Object ) (* iotajsonrpc.IotaObjectResponse , error ) {
225+ func mapFfiObjectToIotaResponse (obj * * iota_sdk_ffi.Object , options * iotajsonrpc. IotaObjectDataOptions , bcsBytes * [] byte ) (* iotajsonrpc.IotaObjectResponse , error ) {
226226 if obj == nil || * obj == nil {
227227 return & iotajsonrpc.IotaObjectResponse {}, nil
228228 }
@@ -238,7 +238,8 @@ func mapFfiObjectToIotaResponse(obj **iota_sdk_ffi.Object) (*iotajsonrpc.IotaObj
238238 return nil , err
239239 }
240240 var typeStr * string
241- if ot := o .ObjectType (); ot != nil {
241+ ot := o .ObjectType ()
242+ if ot != nil {
242243 s := ot .String ()
243244 typeStr = & s
244245 }
@@ -255,9 +256,81 @@ func mapFfiObjectToIotaResponse(obj **iota_sdk_ffi.Object) (*iotajsonrpc.IotaObj
255256 PreviousTransaction : prev ,
256257 StorageRebate : iotajsonrpc .NewBigInt (o .StorageRebate ()),
257258 }
259+
260+ // Add owner if requested
261+ if options != nil && options .ShowOwner {
262+ if owner := o .Owner (); owner != nil {
263+ iotaOwner , err := fromFfiOwner (owner )
264+ if err != nil {
265+ return nil , fmt .Errorf ("failed to convert owner: %w" , err )
266+ }
267+ if iotaOwner != nil {
268+ ownerInternal := & iotajsonrpc.ObjectOwnerInternal {
269+ AddressOwner : iotaOwner .AddressOwner ,
270+ ObjectOwner : iotaOwner .ObjectOwner ,
271+ }
272+ // Convert Shared field if present
273+ if iotaOwner .Shared != nil {
274+ ownerInternal .Shared = & struct {
275+ InitialSharedVersion * iotago.SequenceNumber `json:"initial_shared_version"`
276+ }{
277+ InitialSharedVersion : & iotaOwner .Shared .InitialSharedVersion ,
278+ }
279+ }
280+ data .Owner = & iotajsonrpc.ObjectOwner {
281+ ObjectOwnerInternal : ownerInternal ,
282+ }
283+ }
284+ }
285+ }
286+
287+ // Add BCS data if requested and available
288+ if options != nil && options .ShowBcs && bcsBytes != nil && * bcsBytes != nil {
289+ bcsData := iotago .Base64Data (* bcsBytes )
290+
291+ // For move objects, we need to populate the IotaRawMoveObject structure
292+ if typeStr != nil {
293+ structTag , err := iotago .StructTagFromString (extractTypeTag (* typeStr ))
294+ if err == nil {
295+ data .Bcs = & serialization.TagJson [iotajsonrpc.IotaRawData ]{
296+ Data : iotajsonrpc.IotaRawData {
297+ MoveObject : & iotajsonrpc.IotaRawMoveObject {
298+ Type : * structTag ,
299+ HasPublicTransfer : false , // This would need to be determined from object data
300+ Version : iotago .SequenceNumber (ver ),
301+ BcsBytes : bcsData ,
302+ },
303+ },
304+ }
305+ }
306+ }
307+ }
308+
258309 return & iotajsonrpc.IotaObjectResponse {Data : data }, nil
259310}
260311
312+ var moveTagRe = regexp .MustCompile (
313+ `^(?:Struct\()?(0x[0-9a-fA-F]+::[A-Za-z_][A-Za-z0-9_]*::[A-Za-z_][A-Za-z0-9_]*)(?:\))?$` ,
314+ )
315+
316+ func extractTypeTag (s string ) string {
317+ s = strings .TrimSpace (s )
318+ if m := moveTagRe .FindStringSubmatch (s ); m != nil {
319+ return m [1 ]
320+ }
321+ // Fallback: if parentheses exist, peel the first (...) pair.
322+ if l := strings .IndexByte (s , '(' ); l >= 0 {
323+ if r := strings .IndexByte (s [l + 1 :], ')' ); r >= 0 {
324+ return s [l + 1 : l + 1 + r ]
325+ }
326+ }
327+ // Otherwise just return as-is if non-empty.
328+ if s != "" {
329+ return s
330+ }
331+ return ""
332+ }
333+
261334// formatExecutionError formats an ExecutionError with type information
262335func formatExecutionError (err iota_sdk_ffi.ExecutionError ) string {
263336 switch e := err .(type ) {
@@ -566,7 +639,8 @@ func populateObjectTypesFromDryRun(effects *iota_sdk_ffi.TransactionEffects, dry
566639}
567640
568641// convertChangedObjectsToObjectChanges converts FFI TransactionEffects ChangedObjects to ObjectChanges
569- func convertChangedObjectsToObjectChanges (effects * iota_sdk_ffi.TransactionEffects ) ([]serialization.TagJson [iotajsonrpc.ObjectChange ], error ) {
642+ func (c * BindingClient ) convertChangedObjectsToObjectChanges (effects * iota_sdk_ffi.TransactionEffects ) ([]serialization.TagJson [iotajsonrpc.ObjectChange ], error ) {
643+ time .Sleep (400 * time .Millisecond )
570644 if effects == nil {
571645 return nil , nil
572646 }
@@ -582,17 +656,17 @@ func convertChangedObjectsToObjectChanges(effects *iota_sdk_ffi.TransactionEffec
582656 // We'll create a zero address as a placeholder.
583657 zeroAddr := iotago.Address {}
584658 for _ , changedObj := range v1 .ChangedObjects {
659+ fmt .Println ("*******changedObj.IdOperation: " , changedObj .IdOperation )
660+ fmt .Println ("*******changedObj.ObjectType: " , changedObj .ObjectType )
661+ fmt .Println ("*******changedObj.ObjectId: " , changedObj .ObjectId .ToHex ())
662+ if changedObj .ObjectType != nil {
663+ fmt .Println ("*******!changedObj: " , * changedObj .ObjectType )
664+ }
585665 objID , err := fromFfiObjectID (changedObj .ObjectId )
586666 if err != nil || objID == nil {
587667 continue
588668 }
589669
590- // Extract object type if available
591- objectType := ""
592- if changedObj .ObjectType != nil {
593- objectType = * changedObj .ObjectType
594- }
595-
596670 // Determine object state changes
597671 inputIsMissing := false
598672 outputIsMissing := false
@@ -630,6 +704,10 @@ func convertChangedObjectsToObjectChanges(effects *iota_sdk_ffi.TransactionEffec
630704
631705 // Create ObjectChange based on state transitions
632706 var change iotajsonrpc.ObjectChange
707+ var changeObjectType string
708+ if changedObj .ObjectType != nil {
709+ changeObjectType = * changedObj .ObjectType
710+ }
633711
634712 switch changedObj .IdOperation {
635713 case iota_sdk_ffi .IdOperationCreated :
@@ -647,6 +725,19 @@ func convertChangedObjectsToObjectChanges(effects *iota_sdk_ffi.TransactionEffec
647725 Nodules : []string {}, // TODO: Extract module names if available
648726 }
649727 } else if ! outputIsMissing && outputDigest != nil && outputOwner != nil {
728+ resGetObject , err := c .GetObject (context .TODO (), iotaclient.GetObjectRequest {ObjectID : objID , Options : & iotajsonrpc.IotaObjectDataOptions {
729+ ShowType : true ,
730+ ShowContent : true ,
731+ ShowBcs : true ,
732+ ShowOwner : true ,
733+ ShowPreviousTransaction : true ,
734+ ShowStorageRebate : true ,
735+ ShowDisplay : true ,
736+ }})
737+ if err != nil {
738+ panic (err )
739+ }
740+
650741 change .Created = & struct {
651742 Sender iotago.Address `json:"sender"`
652743 Owner iotajsonrpc.ObjectOwner `json:"owner"`
@@ -657,7 +748,7 @@ func convertChangedObjectsToObjectChanges(effects *iota_sdk_ffi.TransactionEffec
657748 }{
658749 Sender : zeroAddr ,
659750 Owner : iotagoOwnerToObjectOwner (outputOwner ),
660- ObjectType : objectType ,
751+ ObjectType : * resGetObject . Data . Type ,
661752 ObjectID : * objID ,
662753 Version : iotajsonrpc .NewBigInt (v1 .LamportVersion ),
663754 Digest : * outputDigest ,
@@ -675,7 +766,7 @@ func convertChangedObjectsToObjectChanges(effects *iota_sdk_ffi.TransactionEffec
675766 Version * iotajsonrpc.BigInt `json:"version"`
676767 }{
677768 Sender : zeroAddr ,
678- ObjectType : objectType ,
769+ ObjectType : changeObjectType ,
679770 ObjectID : * objID ,
680771 Version : iotajsonrpc .NewBigInt (v1 .LamportVersion ),
681772 }
@@ -689,7 +780,7 @@ func convertChangedObjectsToObjectChanges(effects *iota_sdk_ffi.TransactionEffec
689780 Version * iotajsonrpc.BigInt `json:"version"`
690781 }{
691782 Sender : zeroAddr ,
692- ObjectType : objectType ,
783+ ObjectType : changeObjectType ,
693784 ObjectID : * objID ,
694785 Version : iotajsonrpc .NewBigInt (v1 .LamportVersion ),
695786 }
@@ -705,7 +796,7 @@ func convertChangedObjectsToObjectChanges(effects *iota_sdk_ffi.TransactionEffec
705796 }{
706797 Sender : zeroAddr ,
707798 Owner : iotagoOwnerToObjectOwner (outputOwner ),
708- ObjectType : objectType ,
799+ ObjectType : changeObjectType ,
709800 ObjectID : * objID ,
710801 Version : iotajsonrpc .NewBigInt (v1 .LamportVersion ),
711802 PreviousVersion : iotajsonrpc .NewBigInt (v1 .LamportVersion - 1 ), // Approximation
@@ -789,7 +880,7 @@ func (c *BindingClient) GetOwnedObjects(ctx context.Context, req iotaclient.GetO
789880 if err .(* iota_sdk_ffi.SdkFfiError ) != nil {
790881 return nil , fmt .Errorf ("Object failed: %w" , err )
791882 }
792- resp , err := mapFfiObjectToIotaResponse (obj )
883+ resp , err := mapFfiObjectToIotaResponse (obj , nil , nil )
793884 if err != nil {
794885 return nil , err
795886 }
@@ -941,7 +1032,7 @@ func (c *BindingClient) DryRunTransaction(ctx context.Context, txDataBytes iotag
9411032 response .Effects = serialization.TagJson [iotajsonrpc.IotaTransactionBlockEffects ]{Data : * convertedEffects }
9421033
9431034 // Convert object changes
944- objectChanges , err := convertChangedObjectsToObjectChanges (* dryRunResult .Effects )
1035+ objectChanges , err := c . convertChangedObjectsToObjectChanges (* dryRunResult .Effects )
9451036 if err != nil {
9461037 return nil , fmt .Errorf ("failed to convert object changes: %w" , err )
9471038 }
@@ -2705,7 +2796,7 @@ func (c *BindingClient) SignAndExecuteTransaction(ctx context.Context, req *iota
27052796 response .Effects = & serialization.TagJson [iotajsonrpc.IotaTransactionBlockEffects ]{Data : * convertedEffects }
27062797 }
27072798 if req .Options .ShowObjectChanges {
2708- objectChanges , err := convertChangedObjectsToObjectChanges (* txEffects )
2799+ objectChanges , err := c . convertChangedObjectsToObjectChanges (* txEffects )
27092800 if err != nil {
27102801 return nil , fmt .Errorf ("failed to convert object changes: %w" , err )
27112802 }
@@ -3011,7 +3102,7 @@ func (c *BindingClient) BatchGetObjectsOwnedByAddress(ctx context.Context, addre
30113102
30123103 var results []iotajsonrpc.IotaObjectResponse
30133104 for _ , obj := range objectPage .Data {
3014- resp , err := mapFfiObjectToIotaResponse (& obj )
3105+ resp , err := mapFfiObjectToIotaResponse (& obj , options , nil )
30153106 if err != nil {
30163107 return nil , fmt .Errorf ("failed to map object: %w" , err )
30173108 }
@@ -3340,12 +3431,25 @@ func (c *BindingClient) GetObject(ctx context.Context, req iotaclient.GetObjectR
33403431 if err != nil {
33413432 return nil , err
33423433 }
3434+
33433435 obj , err := c .qclient .Object (oid , nil )
33443436 if err .(* iota_sdk_ffi.SdkFfiError ) != nil {
33453437 return nil , fmt .Errorf ("GraphQL Object failed: %w" , err )
33463438 }
33473439
3348- return mapFfiObjectToIotaResponse (obj )
3440+ // Fetch BCS data if requested
3441+ var bcsBytes * []byte
3442+ if req .Options != nil && req .Options .ShowBcs {
3443+ // Use MoveObjectContentsBcs to get just the Move object contents (not the full object wrapper)
3444+ // This matches what the JSON-RPC API returns for showBcs and allows direct deserialization
3445+ bcs , err := c .qclient .MoveObjectContentsBcs (oid , nil )
3446+ if err .(* iota_sdk_ffi.SdkFfiError ) == nil && bcs != nil {
3447+ bcsBytes = bcs
3448+ }
3449+ // Silently ignore BCS fetch errors - BCS data might not be available for all objects
3450+ }
3451+
3452+ return mapFfiObjectToIotaResponse (obj , req .Options , bcsBytes )
33493453}
33503454
33513455func (c * BindingClient ) GetProtocolConfig (ctx context.Context , version * iotajsonrpc.BigInt ) (* iotajsonrpc.ProtocolConfig , error ) {
@@ -3495,7 +3599,7 @@ func (c *BindingClient) MultiGetObjects(ctx context.Context, req iotaclient.Mult
34953599
34963600 var results []iotajsonrpc.IotaObjectResponse
34973601 for _ , obj := range objectPage .Data {
3498- resp , err := mapFfiObjectToIotaResponse (& obj )
3602+ resp , err := mapFfiObjectToIotaResponse (& obj , req . Options , nil )
34993603 if err != nil {
35003604 return nil , fmt .Errorf ("failed to map object: %w" , err )
35013605 }
@@ -3574,8 +3678,7 @@ func (c *BindingClient) Health(ctx context.Context) error {
35743678}
35753679
35763680func (c * BindingClient ) L2 () L2Client {
3577- faucetURL := iotaconn .FaucetURL (c .RpcURL )
3578- return iscmoveclient .NewClient (c .RpcURL , faucetURL )
3681+ return NewBindingClientL2 (c .RpcURL , c )
35793682}
35803683
35813684func (c * BindingClient ) IotaClient () L1Client {
@@ -3867,7 +3970,7 @@ func (c *BindingClient) buildTransactionAndExecute(_ context.Context, signer iot
38673970 response .Effects = & serialization.TagJson [iotajsonrpc.IotaTransactionBlockEffects ]{Data : * convertedEffects }
38683971 }
38693972 if options .ShowObjectChanges {
3870- objectChanges , err := convertChangedObjectsToObjectChanges (* txEffects )
3973+ objectChanges , err := c . convertChangedObjectsToObjectChanges (* txEffects )
38713974 if err != nil {
38723975 return nil , fmt .Errorf ("failed to convert object changes: %w" , err )
38733976 }
0 commit comments