-
Notifications
You must be signed in to change notification settings - Fork 534
Karthik/sep 48 event parsing #5806
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
karthikiyer56
wants to merge
3
commits into
master
Choose a base branch
from
karthik/sep-48-event-parsing
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
169 changes: 169 additions & 0 deletions
169
...torial/eg-3/contract_CCHEPGTHUPDTGPA7B6YLSG5X6PBG62RKDZU2DS6BDGALAA6TRRJVOAP2_bindings.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
// SEP-48 Contract Bindings | ||
// Auto-generated from Soroban contract specification | ||
// Contract ID: CCHEPGTHUPDTGPA7B6YLSG5X6PBG62RKDZU2DS6BDGALAA6TRRJVOAP2 | ||
// | ||
// This file contains: | ||
// - Event structures and parsers | ||
// - Function interfaces | ||
// - Type definitions | ||
// - Error constants | ||
|
||
package contracts | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
"github.com/stellar/go/xdr" | ||
) | ||
|
||
// Contract metadata | ||
const ContractID = "CCHEPGTHUPDTGPA7B6YLSG5X6PBG62RKDZU2DS6BDGALAA6TRRJVOAP2" | ||
|
||
// ============================================================================ | ||
// CONTRACT EVENTS (Complete SEP-48 Implementation) | ||
// ============================================================================ | ||
|
||
// DefaultEventEvent represents the 'DefaultEvent' contract event | ||
// | ||
// Event Structure: | ||
// - Prefix Topics: [default_event] | ||
// - Data Format: Map | ||
// - Topic Parameters: 2 | ||
// - Data Parameters: 3 | ||
type DefaultEventEvent struct { | ||
// Event metadata (for validation) | ||
EventName string `json:"event_name"` | ||
Prefix0 string `json:"prefix_0"` // Expected: "default_event" | ||
|
||
// Topic parameters (indexed, searchable) | ||
Addr string `json:"addr"` // Topic: string | ||
Num uint32 `json:"num"` // Topic: uint32 | ||
|
||
// Data parameters (event payload) | ||
Bignum *big.Int `json:"bignum"` // Data: *big.Int | ||
Nested []map[string]int64 `json:"nested"` // Data: []map[string]int64 | ||
Any interface{} `json:"any"` // Data: interface{} | ||
} | ||
|
||
// ParseDefaultEventEvent parses a 'DefaultEvent' event from Stellar ContractEvent XDR | ||
// | ||
// This parser validates: | ||
// - Topic count and structure | ||
// - Prefix topic values | ||
// - Data format (Map) | ||
// - Parameter types and conversion | ||
// | ||
// Returns: (*DefaultEventEvent, error) | ||
func ParseDefaultEventEvent(contractEvent xdr.ContractEvent) (*DefaultEventEvent, error) { | ||
// Extract event components from XDR | ||
topics := contractEvent.Body.V0.Topics | ||
data := contractEvent.Body.V0.Data | ||
|
||
// Validate topic structure | ||
if len(topics) < 3 { | ||
return nil, fmt.Errorf("invalid 'DefaultEvent' event: expected at least 3 topics, got %d", len(topics)) | ||
} | ||
|
||
// Validate prefix topics (event signature) | ||
topic0, ok0 := topics[0].GetSym() | ||
if !ok0 { | ||
return nil, fmt.Errorf("invalid event format: topic0 does not exist") | ||
} | ||
if string(topic0) != "default_event" { | ||
return nil, fmt.Errorf("invalid event signature: expected 'default_event' at topic[0]") | ||
} | ||
|
||
// Validate data format (expected: Map) | ||
dataMap, ok := data.GetMap() | ||
if !ok { | ||
return nil, fmt.Errorf("invalid event format: data does not exist") | ||
} | ||
|
||
// Create event instance | ||
event := &DefaultEventEvent{ | ||
EventName: "DefaultEvent", | ||
Prefix0: "default_event", | ||
} | ||
|
||
// Extract and convert topic parameters | ||
// Topic parameter: addr (string) | ||
topic1Value, ok := topics[1].GetSym() | ||
if !ok { | ||
return nil, fmt.Errorf("invalid event format: topic1") | ||
} | ||
event.Addr = string(topic1Value) | ||
|
||
// Topic parameter: num (uint32) | ||
topic2Value, ok := topics[2].GetU32() | ||
if !ok { | ||
return nil, fmt.Errorf("invalid event format: expected uint32 value for topic2") | ||
} | ||
event.Num = uint32(topic2Value) | ||
|
||
// Extract and convert data parameters from map | ||
// Data parameter: bignum (*big.Int) | ||
if bignumVal, exists := dataMap["bignum"]; exists { | ||
bignumValue, ok := bignumVal.GetI128() | ||
if !ok { | ||
return nil, fmt.Errorf("invalid event format: expected i128 value for bignum") | ||
} | ||
event.Bignum = new(big.Int).SetBytes(bignumValue[:]) | ||
} else { | ||
return nil, fmt.Errorf("missing required data parameter: bignum") | ||
} | ||
|
||
// Data parameter: nested ([]map[string]int64) | ||
if nestedVal, exists := dataMap["nested"]; exists { | ||
// TODO: Convert nestedVal to []map[string]int64 | ||
// This requires custom conversion logic for complex types | ||
event.Nested = nestedVal // Placeholder | ||
} else { | ||
return nil, fmt.Errorf("missing required data parameter: nested") | ||
} | ||
|
||
// Data parameter: any (interface{}) | ||
if anyVal, exists := dataMap["any"]; exists { | ||
// Keep any as raw ScVal for interface{} type | ||
event.Any = anyVal | ||
} else { | ||
return nil, fmt.Errorf("missing required data parameter: any") | ||
} | ||
|
||
return event, nil | ||
} | ||
|
||
// ParseContractEvent attempts to parse any contract event | ||
// Returns the parsed event as an interface{} or an error | ||
func ParseContractEvent(contractEvent xdr.ContractEvent) (interface{}, error) { | ||
// Extract event components from XDR | ||
topics := contractEvent.Body.V0.Topics | ||
if len(topics) == 0 { | ||
return nil, fmt.Errorf("event has no topics") | ||
} | ||
|
||
// Try to identify event by first topic (event name/prefix) | ||
firstTopic, ok := topics[0].GetSym() | ||
if !ok { | ||
return nil, fmt.Errorf("invalid event format: first topic is not a symbol") | ||
} | ||
eventName := string(firstTopic) | ||
|
||
// Dispatch to appropriate parser based on event signature | ||
switch eventName { | ||
case "default_event": | ||
return ParseDefaultEventEvent(contractEvent) | ||
default: | ||
return nil, fmt.Errorf("unknown event type: %s", eventName) | ||
} | ||
} | ||
|
||
// ============================================================================ | ||
// CONTRACT FUNCTIONS | ||
// ============================================================================ | ||
|
||
// ContractClient defines the interface for interacting with the contract | ||
type ContractClient interface { | ||
emit() error | ||
|
||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// SEP-48 Contract Bindings | ||
// Auto-generated from Soroban contract specification | ||
// Contract ID: CCHEPGTHUPDTGPA7B6YLSG5X6PBG62RKDZU2DS6BDGALAA6TRRJVOAP2 | ||
// | ||
// This file contains: | ||
// - Event structures and parsers | ||
// - Function interfaces | ||
// - Type definitions | ||
// - Error constants | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
"github.com/stellar/go/xdr" | ||
) | ||
|
||
// Contract metadata | ||
const ContractID = "CCHEPGTHUPDTGPA7B6YLSG5X6PBG62RKDZU2DS6BDGALAA6TRRJVOAP2" | ||
|
||
// ============================================================================ | ||
// CONTRACT EVENTS (Complete SEP-48 Implementation) | ||
// ============================================================================ | ||
|
||
// DefaultEventEvent represents the 'DefaultEvent' contract event | ||
// | ||
// Event Structure: | ||
// - Prefix Topics: [default_event] | ||
// - Data Format: Map | ||
// - Topic Parameters: 2 | ||
// - Data Parameters: 3 | ||
type DefaultEventEvent struct { | ||
// Event metadata (for validation) | ||
EventName string `json:"event_name"` | ||
Prefix0 string `json:"prefix_0"` // Expected: "default_event" | ||
|
||
// Topic parameters (indexed, searchable) | ||
Addr string `json:"addr"` // Topic: string | ||
Num uint32 `json:"num"` // Topic: uint32 | ||
|
||
// Data parameters (event payload) | ||
Bignum *big.Int `json:"bignum"` // Data: *big.Int | ||
Nested []map[string]int64 `json:"nested"` // Data: []map[string]int64 | ||
Any interface{} `json:"any"` // Data: interface{} | ||
} | ||
|
||
// ParseDefaultEventEvent parses a 'DefaultEvent' event from Stellar ContractEvent XDR | ||
// | ||
// This parser validates: | ||
// - Topic count and structure | ||
// - Prefix topic values | ||
// - Data format (Map) | ||
// - Parameter types and conversion | ||
// | ||
// Returns: (*DefaultEventEvent, error) | ||
func ParseDefaultEventEvent(contractEvent xdr.ContractEvent) (*DefaultEventEvent, error) { | ||
// Extract event components from XDR | ||
var topics []xdr.ScVal | ||
var data xdr.ScVal | ||
topics = contractEvent.Body.V0.Topics | ||
data = contractEvent.Body.V0.Data | ||
|
||
// Validate topic structure | ||
if len(topics) < 3 { | ||
return nil, fmt.Errorf("invalid 'DefaultEvent' event: expected at least 3 topics, got %d", len(topics)) | ||
} | ||
|
||
topic0, ok0 := topics[0].GetSym() | ||
if !ok0 { | ||
return nil, fmt.Errorf("invalid event format: topic0 does not exist") | ||
} | ||
// Validate prefix topics (event signature) | ||
if topic0 != "default_event" { | ||
return nil, fmt.Errorf("invalid event signature: expected 'default_event' at topic[0]") | ||
} | ||
|
||
dataMap, ok := data.GetMap() | ||
if !ok { | ||
return nil, fmt.Errorf("invalid event format: data does not exist") | ||
} | ||
|
||
// Create event instance | ||
event := &DefaultEventEvent{ | ||
EventName: "DefaultEvent", | ||
Prefix0: "default_event", | ||
} | ||
|
||
// Extract and convert topic parameters | ||
// Topic parameter: addr (string) | ||
topic1 := topics[1] | ||
|
||
topic1Value, ok := topic1.GetSym() | ||
if !ok { | ||
return nil, fmt.Errorf("invalid event format: topic1") | ||
} | ||
event.Addr = string(topic1Value) | ||
|
||
// Topic parameter: num (uint32) | ||
topic2 := topics[2] | ||
|
||
topic2Value, ok := topic2.GetU32() | ||
if !ok { | ||
return nil, fmt.Errorf("invalid event format: expected uint32 value for topic2") | ||
} | ||
event.Num = uint32(topic2Value) | ||
|
||
|
||
// Extract and convert data parameters | ||
// Extract parameters from data map | ||
// Data parameter: bignum (*big.Int) | ||
if bignumVal, exists := (*dataMap)["bignum"]; exists { | ||
|
||
var bignumValValue *big.Int | ||
if bignumVal.I128() != nil { | ||
bignumValValue = new(big.Int) | ||
bignumValValue.SetBytes((*bignumVal.I128())[:]) | ||
} else if bignumVal.U128() != nil { | ||
bignumValValue = new(big.Int) | ||
bignumValValue.SetBytes((*bignumVal.U128())[:]) | ||
} else { | ||
return nil, fmt.Errorf("expected 128-bit int value for %!s(MISSING)") | ||
} event.Bignum = bignumValValue | ||
Check failure on line 123 in ingest/tutorial/eg-3/contract_cchepgth_bindings.go
|
||
} else { | ||
return nil, fmt.Errorf("missing required data parameter: bignum") | ||
} | ||
|
||
// Data parameter: nested ([]map[string]int64) | ||
if nestedVal, exists := (*dataMap)["nested"]; exists { | ||
|
||
// TODO: Convert nestedVal to []map[string]int64 | ||
// This requires custom conversion logic for user-defined types | ||
nestedValValue := nestedVal // Placeholder event.Nested = nestedValValue | ||
} else { | ||
return nil, fmt.Errorf("missing required data parameter: nested") | ||
} | ||
|
||
// Data parameter: any (interface{}) | ||
if anyVal, exists := (*dataMap)["any"]; exists { | ||
|
||
// TODO: Convert anyVal to interface{} | ||
// This requires custom conversion logic for user-defined types | ||
anyValValue := anyVal // Placeholder event.Any = anyValValue | ||
} else { | ||
return nil, fmt.Errorf("missing required data parameter: any") | ||
} | ||
|
||
return event, nil | ||
} | ||
|
||
// ParseContractEvent attempts to parse any contract event | ||
// Returns the parsed event as an interface{} or an error | ||
func ParseContractEvent(contractEvent xdr.ContractEvent) (interface{}, error) { | ||
topics := contractEvent.Body().V0.Topics | ||
if len(topics) == 0 { | ||
return nil, fmt.Errorf("event has no topics") | ||
} | ||
|
||
// Try to identify event by first topic (event name/prefix) | ||
firstTopic := topics[0] | ||
var eventName string | ||
if firstTopic.Str() != nil { | ||
eventName = string(*firstTopic.Str()) | ||
} else { | ||
return nil, fmt.Errorf("cannot identify event: first topic is not a string") | ||
} | ||
|
||
// Dispatch to appropriate parser based on event signature | ||
switch eventName { | ||
case "default_event": | ||
return ParseDefaultEventEvent(contractEvent) | ||
default: | ||
return nil, fmt.Errorf("unknown event type: %s", eventName) | ||
} | ||
} | ||
|
||
// ============================================================================ | ||
// CONTRACT FUNCTIONS | ||
// ============================================================================ | ||
|
||
// ContractClient defines the interface for interacting with the contract | ||
type ContractClient interface { | ||
emit() error | ||
|
||
} | ||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😯