package main import ( "encoding/json" "fmt" "strconv" "github.com/hyperledger/fabric-contract-api-go/contractapi" ) // BridgeChaincode provides functions for cross-chain asset bridging type BridgeChaincode struct { contractapi.Contract } // Asset represents a bridged asset type Asset struct { ID string `json:"id"` Owner string `json:"owner"` Amount uint64 `json:"amount"` TokenType string `json:"tokenType"` Locked bool `json:"locked"` EvmTxHash string `json:"evmTxHash,omitempty"` RequestID string `json:"requestId,omitempty"` } // InitLedger initializes the ledger with sample assets func (s *BridgeChaincode) InitLedger(ctx contractapi.TransactionContextInterface) error { assets := []Asset{ {ID: "asset1", Owner: "Org1MSP", Amount: 1000, TokenType: "ERC20", Locked: false}, {ID: "asset2", Owner: "Org2MSP", Amount: 2000, TokenType: "ERC20", Locked: false}, } for _, asset := range assets { assetJSON, err := json.Marshal(asset) if err != nil { return err } err = ctx.GetStub().PutState(asset.ID, assetJSON) if err != nil { return fmt.Errorf("failed to put to world state. %v", err) } } return nil } // ReadAsset returns the asset stored in the world state with given id func (s *BridgeChaincode) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { assetJSON, err := ctx.GetStub().GetState(id) if err != nil { return nil, fmt.Errorf("failed to read from world state: %v", err) } if assetJSON == nil { return nil, fmt.Errorf("the asset %s does not exist", id) } var asset Asset err = json.Unmarshal(assetJSON, &asset) if err != nil { return nil, err } return &asset, nil } // LockAsset locks an asset for bridge transfer to EVM func (s *BridgeChaincode) LockAsset( ctx contractapi.TransactionContextInterface, assetId string, evmDestination string, requestId string, ) error { asset, err := s.ReadAsset(ctx, assetId) if err != nil { return err } if asset.Locked { return fmt.Errorf("asset %s is already locked", assetId) } asset.Locked = true asset.RequestID = requestId assetJSON, err := json.Marshal(asset) if err != nil { return err } // Emit event for EVM bridge to pick up err = ctx.GetStub().SetEvent("BridgeToEVM", []byte(fmt.Sprintf(`{"assetId":"%s","amount":%d,"evmRecipient":"%s","requestId":"%s"}`, assetId, asset.Amount, evmDestination, requestId))) if err != nil { return fmt.Errorf("failed to set event: %v", err) } return ctx.GetStub().PutState(assetId, assetJSON) } // UnlockAsset unlocks an asset after bridge completion func (s *BridgeChaincode) UnlockAsset( ctx contractapi.TransactionContextInterface, assetId string, evmTxHash string, ) error { asset, err := s.ReadAsset(ctx, assetId) if err != nil { return err } asset.Locked = false asset.EvmTxHash = evmTxHash assetJSON, err := json.Marshal(asset) if err != nil { return err } return ctx.GetStub().PutState(assetId, assetJSON) } // BurnAsset burns an asset on Fabric side (mint on EVM side) func (s *BridgeChaincode) BurnAsset( ctx contractapi.TransactionContextInterface, assetId string, evmRecipient string, requestId string, ) error { asset, err := s.ReadAsset(ctx, assetId) if err != nil { return err } // Emit event for EVM minting err = ctx.GetStub().SetEvent("BridgeToEVM", []byte(fmt.Sprintf(`{"assetId":"%s","amount":%d,"evmRecipient":"%s","requestId":"%s","action":"mint"}`, assetId, asset.Amount, evmRecipient, requestId))) if err != nil { return fmt.Errorf("failed to set event: %v", err) } // Delete asset (burn) return ctx.GetStub().DelState(assetId) } // CreateAsset creates a new asset func (s *BridgeChaincode) CreateAsset( ctx contractapi.TransactionContextInterface, id string, amount uint64, tokenType string, ) error { clientMSPID, err := ctx.GetClientIdentity().GetMSPID() if err != nil { return fmt.Errorf("failed to get client MSP ID: %v", err) } asset := Asset{ ID: id, Owner: clientMSPID, Amount: amount, TokenType: tokenType, Locked: false, } assetJSON, err := json.Marshal(asset) if err != nil { return err } return ctx.GetStub().PutState(id, assetJSON) } // GetAllAssets returns all assets found in world state func (s *BridgeChaincode) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) { resultsIterator, err := ctx.GetStub().GetStateByRange("", "") if err != nil { return nil, err } defer resultsIterator.Close() var assets []*Asset for resultsIterator.HasNext() { queryResponse, err := resultsIterator.Next() if err != nil { return nil, err } var asset Asset err = json.Unmarshal(queryResponse.Value, &asset) if err != nil { return nil, err } assets = append(assets, &asset) } return assets, nil } func main() { chaincode, err := contractapi.NewChaincode(&BridgeChaincode{}) if err != nil { fmt.Printf("Error creating bridge chaincode: %v", err) return } if err := chaincode.Start(); err != nil { fmt.Printf("Error starting bridge chaincode: %v", err) } }