diff --git a/controllers/sender/sender.go b/controllers/sender/sender.go index 7a976af2..0b62b320 100644 --- a/controllers/sender/sender.go +++ b/controllers/sender/sender.go @@ -2894,8 +2894,9 @@ func (ctrl *SenderController) Stats(ctx *gin.Context) { // Get USD volume var w []struct { - Sum decimal.Decimal - SumFieldSenderFee decimal.Decimal + Sum decimal.Decimal + SumFieldSenderFee decimal.Decimal + SumFieldProviderFee decimal.Decimal } err := storage.Client.PaymentOrder. Query(). @@ -2907,6 +2908,7 @@ func (ctrl *SenderController) Stats(ctx *gin.Context) { Aggregate( ent.Sum(paymentorder.FieldAmount), ent.As(ent.Sum(paymentorder.FieldSenderFee), "SumFieldSenderFee"), + ent.As(ent.Sum(paymentorder.FieldProviderFee), "SumFieldProviderFee"), ). Scan(reqCtx, &w) if err != nil { @@ -2932,6 +2934,7 @@ func (ctrl *SenderController) Stats(ctx *gin.Context) { var localStablecoinSum decimal.Decimal var localStablecoinSenderFee decimal.Decimal + var localStablecoinProviderFee decimal.Decimal // Convert local stablecoin volume to USD (direction-aware: onramp use buy rate, offramp use sell rate) for _, paymentOrder := range paymentOrders { @@ -2957,9 +2960,13 @@ func (ctrl *SenderController) Stats(ctx *gin.Context) { if paymentOrder.SenderFee.GreaterThan(decimal.Zero) { paymentOrder.SenderFee = paymentOrder.SenderFee.Div(rate) } + if paymentOrder.ProviderFee.GreaterThan(decimal.Zero) { + paymentOrder.ProviderFee = paymentOrder.ProviderFee.Div(rate) + } localStablecoinSum = localStablecoinSum.Add(paymentOrder.Amount) localStablecoinSenderFee = localStablecoinSenderFee.Add(paymentOrder.SenderFee) + localStablecoinProviderFee = localStablecoinProviderFee.Add(paymentOrder.ProviderFee) } count, err := storage.Client.PaymentOrder. @@ -2975,9 +2982,10 @@ func (ctrl *SenderController) Stats(ctx *gin.Context) { } u.APIResponse(ctx, http.StatusOK, "success", "Sender stats retrieved successfully", types.SenderStatsResponse{ - TotalOrders: count, - TotalOrderVolume: w[0].Sum.Add(localStablecoinSum), - TotalFeeEarnings: w[0].SumFieldSenderFee.Add(localStablecoinSenderFee), + TotalOrders: count, + TotalOrderVolume: w[0].Sum.Add(localStablecoinSum), + TotalFeeEarnings: w[0].SumFieldSenderFee.Add(localStablecoinSenderFee), + TotalProviderFees: w[0].SumFieldProviderFee.Add(localStablecoinProviderFee), }) } diff --git a/ent/migrate/migrations/20260319165304_add_provider_fee.sql b/ent/migrate/migrations/20260319165304_add_provider_fee.sql new file mode 100644 index 00000000..ddd16275 --- /dev/null +++ b/ent/migrate/migrations/20260319165304_add_provider_fee.sql @@ -0,0 +1,2 @@ +-- Add provider_fee column to payment_orders for tracking provider's portion of transaction fee +ALTER TABLE "payment_orders" ADD COLUMN "provider_fee" numeric NOT NULL DEFAULT 0; diff --git a/ent/migrate/migrations/atlas.sum b/ent/migrate/migrations/atlas.sum index a2c0a60c..07f37be0 100644 --- a/ent/migrate/migrations/atlas.sum +++ b/ent/migrate/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:XGc0qj58R4xn+fMjZJqIdeosU14dhOs5U5YvG/w+7EM= +h1:8qEvlOVE47PPZVAj9dY0zt2RoYXdI34dFRVo0Gz0LyQ= 20240118234246_initial.sql h1:dYuYBqns33WT+3p8VQvbKUP62k3k6w6h8S+FqNqgSvU= 20240130122324_order_from_address.sql h1:mMVI2iBUd1roIYLUqu0d2jZ7+B6exppRN8qqn+aIHx4= 20240202010744_fees_on_order.sql h1:P7ngxZKqDKefBM5vk6M3kbWeMPVwbZ4MZVcLBjEfS34= @@ -80,3 +80,4 @@ h1:XGc0qj58R4xn+fMjZJqIdeosU14dhOs5U5YvG/w+7EM= 20260310185904_add_wallet_service.sql h1:eG863f+be3Cac7dzU6+rOJ+tVEVIouatPBlIGtKI+VY= 20260313024459_onramp_bump.sql h1:Px+OHr6ARShsDgaMq95Io5cY36KmfrSYSuk+KGfDvz4= 20260318151618_txlog_edge.sql h1:kgqV1eVk/bpOO0l8RGkLLJZ4EpQ5IaPS9MLbLCxgIao= +20260319165304_add_provider_fee.sql h1:Z6aWLnzTGWagWo7XXpbSrDVrOCzPLjnMHtkdHfJZiZk= diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 3db14900..8e75d094 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -190,6 +190,7 @@ var ( {Name: "amount_returned", Type: field.TypeFloat64}, {Name: "percent_settled", Type: field.TypeFloat64}, {Name: "sender_fee", Type: field.TypeFloat64}, + {Name: "provider_fee", Type: field.TypeFloat64}, {Name: "network_fee", Type: field.TypeFloat64}, {Name: "protocol_fee", Type: field.TypeFloat64}, {Name: "order_percent", Type: field.TypeFloat64}, @@ -232,31 +233,31 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "payment_orders_api_keys_payment_orders", - Columns: []*schema.Column{PaymentOrdersColumns[38]}, + Columns: []*schema.Column{PaymentOrdersColumns[39]}, RefColumns: []*schema.Column{APIKeysColumns[0]}, OnDelete: schema.SetNull, }, { Symbol: "payment_orders_provider_profiles_assigned_orders", - Columns: []*schema.Column{PaymentOrdersColumns[39]}, + Columns: []*schema.Column{PaymentOrdersColumns[40]}, RefColumns: []*schema.Column{ProviderProfilesColumns[0]}, OnDelete: schema.Cascade, }, { Symbol: "payment_orders_provision_buckets_payment_orders", - Columns: []*schema.Column{PaymentOrdersColumns[40]}, + Columns: []*schema.Column{PaymentOrdersColumns[41]}, RefColumns: []*schema.Column{ProvisionBucketsColumns[0]}, OnDelete: schema.SetNull, }, { Symbol: "payment_orders_sender_profiles_payment_orders", - Columns: []*schema.Column{PaymentOrdersColumns[41]}, + Columns: []*schema.Column{PaymentOrdersColumns[42]}, RefColumns: []*schema.Column{SenderProfilesColumns[0]}, OnDelete: schema.SetNull, }, { Symbol: "payment_orders_tokens_payment_orders", - Columns: []*schema.Column{PaymentOrdersColumns[42]}, + Columns: []*schema.Column{PaymentOrdersColumns[43]}, RefColumns: []*schema.Column{TokensColumns[0]}, OnDelete: schema.Cascade, }, @@ -265,7 +266,7 @@ var ( { Name: "paymentorder_gateway_id_rate_tx_hash_block_number_institution_account_identifier_account_name_memo_direction_refund_or_recipient_address_token_payment_orders", Unique: true, - Columns: []*schema.Column{PaymentOrdersColumns[17], PaymentOrdersColumns[4], PaymentOrdersColumns[14], PaymentOrdersColumns[15], PaymentOrdersColumns[25], PaymentOrdersColumns[26], PaymentOrdersColumns[27], PaymentOrdersColumns[33], PaymentOrdersColumns[35], PaymentOrdersColumns[19], PaymentOrdersColumns[42]}, + Columns: []*schema.Column{PaymentOrdersColumns[18], PaymentOrdersColumns[4], PaymentOrdersColumns[15], PaymentOrdersColumns[16], PaymentOrdersColumns[26], PaymentOrdersColumns[27], PaymentOrdersColumns[28], PaymentOrdersColumns[34], PaymentOrdersColumns[36], PaymentOrdersColumns[20], PaymentOrdersColumns[43]}, }, }, } diff --git a/ent/mutation.go b/ent/mutation.go index f65d1ea9..850d8e50 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -6523,6 +6523,8 @@ type PaymentOrderMutation struct { addpercent_settled *decimal.Decimal sender_fee *decimal.Decimal addsender_fee *decimal.Decimal + provider_fee *decimal.Decimal + addprovider_fee *decimal.Decimal network_fee *decimal.Decimal addnetwork_fee *decimal.Decimal protocol_fee *decimal.Decimal @@ -7148,6 +7150,62 @@ func (m *PaymentOrderMutation) ResetSenderFee() { m.addsender_fee = nil } +// SetProviderFee sets the "provider_fee" field. +func (m *PaymentOrderMutation) SetProviderFee(d decimal.Decimal) { + m.provider_fee = &d + m.addprovider_fee = nil +} + +// ProviderFee returns the value of the "provider_fee" field in the mutation. +func (m *PaymentOrderMutation) ProviderFee() (r decimal.Decimal, exists bool) { + v := m.provider_fee + if v == nil { + return + } + return *v, true +} + +// OldProviderFee returns the old "provider_fee" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldProviderFee(ctx context.Context) (v decimal.Decimal, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProviderFee is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProviderFee requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProviderFee: %w", err) + } + return oldValue.ProviderFee, nil +} + +// AddProviderFee adds d to the "provider_fee" field. +func (m *PaymentOrderMutation) AddProviderFee(d decimal.Decimal) { + if m.addprovider_fee != nil { + *m.addprovider_fee = m.addprovider_fee.Add(d) + } else { + m.addprovider_fee = &d + } +} + +// AddedProviderFee returns the value that was added to the "provider_fee" field in this mutation. +func (m *PaymentOrderMutation) AddedProviderFee() (r decimal.Decimal, exists bool) { + v := m.addprovider_fee + if v == nil { + return + } + return *v, true +} + +// ResetProviderFee resets all changes to the "provider_fee" field. +func (m *PaymentOrderMutation) ResetProviderFee() { + m.provider_fee = nil + m.addprovider_fee = nil +} + // SetNetworkFee sets the "network_fee" field. func (m *PaymentOrderMutation) SetNetworkFee(d decimal.Decimal) { m.network_fee = &d @@ -8851,7 +8909,7 @@ func (m *PaymentOrderMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *PaymentOrderMutation) Fields() []string { - fields := make([]string, 0, 37) + fields := make([]string, 0, 38) if m.created_at != nil { fields = append(fields, paymentorder.FieldCreatedAt) } @@ -8879,6 +8937,9 @@ func (m *PaymentOrderMutation) Fields() []string { if m.sender_fee != nil { fields = append(fields, paymentorder.FieldSenderFee) } + if m.provider_fee != nil { + fields = append(fields, paymentorder.FieldProviderFee) + } if m.network_fee != nil { fields = append(fields, paymentorder.FieldNetworkFee) } @@ -8989,6 +9050,8 @@ func (m *PaymentOrderMutation) Field(name string) (ent.Value, bool) { return m.PercentSettled() case paymentorder.FieldSenderFee: return m.SenderFee() + case paymentorder.FieldProviderFee: + return m.ProviderFee() case paymentorder.FieldNetworkFee: return m.NetworkFee() case paymentorder.FieldProtocolFee: @@ -9072,6 +9135,8 @@ func (m *PaymentOrderMutation) OldField(ctx context.Context, name string) (ent.V return m.OldPercentSettled(ctx) case paymentorder.FieldSenderFee: return m.OldSenderFee(ctx) + case paymentorder.FieldProviderFee: + return m.OldProviderFee(ctx) case paymentorder.FieldNetworkFee: return m.OldNetworkFee(ctx) case paymentorder.FieldProtocolFee: @@ -9200,6 +9265,13 @@ func (m *PaymentOrderMutation) SetField(name string, value ent.Value) error { } m.SetSenderFee(v) return nil + case paymentorder.FieldProviderFee: + v, ok := value.(decimal.Decimal) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProviderFee(v) + return nil case paymentorder.FieldNetworkFee: v, ok := value.(decimal.Decimal) if !ok { @@ -9425,6 +9497,9 @@ func (m *PaymentOrderMutation) AddedFields() []string { if m.addsender_fee != nil { fields = append(fields, paymentorder.FieldSenderFee) } + if m.addprovider_fee != nil { + fields = append(fields, paymentorder.FieldProviderFee) + } if m.addnetwork_fee != nil { fields = append(fields, paymentorder.FieldNetworkFee) } @@ -9465,6 +9540,8 @@ func (m *PaymentOrderMutation) AddedField(name string) (ent.Value, bool) { return m.AddedPercentSettled() case paymentorder.FieldSenderFee: return m.AddedSenderFee() + case paymentorder.FieldProviderFee: + return m.AddedProviderFee() case paymentorder.FieldNetworkFee: return m.AddedNetworkFee() case paymentorder.FieldProtocolFee: @@ -9535,6 +9612,13 @@ func (m *PaymentOrderMutation) AddField(name string, value ent.Value) error { } m.AddSenderFee(v) return nil + case paymentorder.FieldProviderFee: + v, ok := value.(decimal.Decimal) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddProviderFee(v) + return nil case paymentorder.FieldNetworkFee: v, ok := value.(decimal.Decimal) if !ok { @@ -9736,6 +9820,9 @@ func (m *PaymentOrderMutation) ResetField(name string) error { case paymentorder.FieldSenderFee: m.ResetSenderFee() return nil + case paymentorder.FieldProviderFee: + m.ResetProviderFee() + return nil case paymentorder.FieldNetworkFee: m.ResetNetworkFee() return nil diff --git a/ent/paymentorder.go b/ent/paymentorder.go index f7064890..67c414e3 100644 --- a/ent/paymentorder.go +++ b/ent/paymentorder.go @@ -43,6 +43,8 @@ type PaymentOrder struct { PercentSettled decimal.Decimal `json:"percent_settled,omitempty"` // SenderFee holds the value of the "sender_fee" field. SenderFee decimal.Decimal `json:"sender_fee,omitempty"` + // ProviderFee holds the value of the "provider_fee" field. + ProviderFee decimal.Decimal `json:"provider_fee,omitempty"` // NetworkFee holds the value of the "network_fee" field. NetworkFee decimal.Decimal `json:"network_fee,omitempty"` // ProtocolFee holds the value of the "protocol_fee" field. @@ -211,7 +213,7 @@ func (*PaymentOrder) scanValues(columns []string) ([]any, error) { switch columns[i] { case paymentorder.FieldReceiveAddressSalt, paymentorder.FieldMetadata, paymentorder.FieldCancellationReasons: values[i] = new([]byte) - case paymentorder.FieldAmount, paymentorder.FieldRate, paymentorder.FieldAmountInUsd, paymentorder.FieldAmountPaid, paymentorder.FieldAmountReturned, paymentorder.FieldPercentSettled, paymentorder.FieldSenderFee, paymentorder.FieldNetworkFee, paymentorder.FieldProtocolFee, paymentorder.FieldOrderPercent, paymentorder.FieldFeePercent: + case paymentorder.FieldAmount, paymentorder.FieldRate, paymentorder.FieldAmountInUsd, paymentorder.FieldAmountPaid, paymentorder.FieldAmountReturned, paymentorder.FieldPercentSettled, paymentorder.FieldSenderFee, paymentorder.FieldProviderFee, paymentorder.FieldNetworkFee, paymentorder.FieldProtocolFee, paymentorder.FieldOrderPercent, paymentorder.FieldFeePercent: values[i] = new(decimal.Decimal) case paymentorder.FieldBlockNumber, paymentorder.FieldCancellationCount: values[i] = new(sql.NullInt64) @@ -306,6 +308,12 @@ func (_m *PaymentOrder) assignValues(columns []string, values []any) error { } else if value != nil { _m.SenderFee = *value } + case paymentorder.FieldProviderFee: + if value, ok := values[i].(*decimal.Decimal); !ok { + return fmt.Errorf("unexpected type %T for field provider_fee", values[i]) + } else if value != nil { + _m.ProviderFee = *value + } case paymentorder.FieldNetworkFee: if value, ok := values[i].(*decimal.Decimal); !ok { return fmt.Errorf("unexpected type %T for field network_fee", values[i]) @@ -611,6 +619,9 @@ func (_m *PaymentOrder) String() string { builder.WriteString("sender_fee=") builder.WriteString(fmt.Sprintf("%v", _m.SenderFee)) builder.WriteString(", ") + builder.WriteString("provider_fee=") + builder.WriteString(fmt.Sprintf("%v", _m.ProviderFee)) + builder.WriteString(", ") builder.WriteString("network_fee=") builder.WriteString(fmt.Sprintf("%v", _m.NetworkFee)) builder.WriteString(", ") diff --git a/ent/paymentorder/paymentorder.go b/ent/paymentorder/paymentorder.go index da552331..1ff56343 100644 --- a/ent/paymentorder/paymentorder.go +++ b/ent/paymentorder/paymentorder.go @@ -35,6 +35,8 @@ const ( FieldPercentSettled = "percent_settled" // FieldSenderFee holds the string denoting the sender_fee field in the database. FieldSenderFee = "sender_fee" + // FieldProviderFee holds the string denoting the provider_fee field in the database. + FieldProviderFee = "provider_fee" // FieldNetworkFee holds the string denoting the network_fee field in the database. FieldNetworkFee = "network_fee" // FieldProtocolFee holds the string denoting the protocol_fee field in the database. @@ -170,6 +172,7 @@ var Columns = []string{ FieldAmountReturned, FieldPercentSettled, FieldSenderFee, + FieldProviderFee, FieldNetworkFee, FieldProtocolFee, FieldOrderPercent, @@ -240,6 +243,8 @@ var ( DefaultPercentSettled func() decimal.Decimal // DefaultSenderFee holds the default value on creation for the "sender_fee" field. DefaultSenderFee func() decimal.Decimal + // DefaultProviderFee holds the default value on creation for the "provider_fee" field. + DefaultProviderFee func() decimal.Decimal // DefaultNetworkFee holds the default value on creation for the "network_fee" field. DefaultNetworkFee func() decimal.Decimal // DefaultProtocolFee holds the default value on creation for the "protocol_fee" field. @@ -423,6 +428,11 @@ func BySenderFee(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldSenderFee, opts...).ToFunc() } +// ByProviderFee orders the results by the provider_fee field. +func ByProviderFee(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldProviderFee, opts...).ToFunc() +} + // ByNetworkFee orders the results by the network_fee field. func ByNetworkFee(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldNetworkFee, opts...).ToFunc() diff --git a/ent/paymentorder/where.go b/ent/paymentorder/where.go index e5f10449..54001e83 100644 --- a/ent/paymentorder/where.go +++ b/ent/paymentorder/where.go @@ -102,6 +102,11 @@ func SenderFee(v decimal.Decimal) predicate.PaymentOrder { return predicate.PaymentOrder(sql.FieldEQ(FieldSenderFee, v)) } +// ProviderFee applies equality check predicate on the "provider_fee" field. It's identical to ProviderFeeEQ. +func ProviderFee(v decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldProviderFee, v)) +} + // NetworkFee applies equality check predicate on the "network_fee" field. It's identical to NetworkFeeEQ. func NetworkFee(v decimal.Decimal) predicate.PaymentOrder { return predicate.PaymentOrder(sql.FieldEQ(FieldNetworkFee, v)) @@ -577,6 +582,46 @@ func SenderFeeLTE(v decimal.Decimal) predicate.PaymentOrder { return predicate.PaymentOrder(sql.FieldLTE(FieldSenderFee, v)) } +// ProviderFeeEQ applies the EQ predicate on the "provider_fee" field. +func ProviderFeeEQ(v decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldProviderFee, v)) +} + +// ProviderFeeNEQ applies the NEQ predicate on the "provider_fee" field. +func ProviderFeeNEQ(v decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldProviderFee, v)) +} + +// ProviderFeeIn applies the In predicate on the "provider_fee" field. +func ProviderFeeIn(vs ...decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldProviderFee, vs...)) +} + +// ProviderFeeNotIn applies the NotIn predicate on the "provider_fee" field. +func ProviderFeeNotIn(vs ...decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldProviderFee, vs...)) +} + +// ProviderFeeGT applies the GT predicate on the "provider_fee" field. +func ProviderFeeGT(v decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldProviderFee, v)) +} + +// ProviderFeeGTE applies the GTE predicate on the "provider_fee" field. +func ProviderFeeGTE(v decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldProviderFee, v)) +} + +// ProviderFeeLT applies the LT predicate on the "provider_fee" field. +func ProviderFeeLT(v decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldProviderFee, v)) +} + +// ProviderFeeLTE applies the LTE predicate on the "provider_fee" field. +func ProviderFeeLTE(v decimal.Decimal) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldProviderFee, v)) +} + // NetworkFeeEQ applies the EQ predicate on the "network_fee" field. func NetworkFeeEQ(v decimal.Decimal) predicate.PaymentOrder { return predicate.PaymentOrder(sql.FieldEQ(FieldNetworkFee, v)) diff --git a/ent/paymentorder_create.go b/ent/paymentorder_create.go index f4f5b3f2..8b65333c 100644 --- a/ent/paymentorder_create.go +++ b/ent/paymentorder_create.go @@ -134,6 +134,20 @@ func (_c *PaymentOrderCreate) SetNillableSenderFee(v *decimal.Decimal) *PaymentO return _c } +// SetProviderFee sets the "provider_fee" field. +func (_c *PaymentOrderCreate) SetProviderFee(v decimal.Decimal) *PaymentOrderCreate { + _c.mutation.SetProviderFee(v) + return _c +} + +// SetNillableProviderFee sets the "provider_fee" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableProviderFee(v *decimal.Decimal) *PaymentOrderCreate { + if v != nil { + _c.SetProviderFee(*v) + } + return _c +} + // SetNetworkFee sets the "network_fee" field. func (_c *PaymentOrderCreate) SetNetworkFee(v decimal.Decimal) *PaymentOrderCreate { _c.mutation.SetNetworkFee(v) @@ -668,6 +682,10 @@ func (_c *PaymentOrderCreate) defaults() { v := paymentorder.DefaultSenderFee() _c.mutation.SetSenderFee(v) } + if _, ok := _c.mutation.ProviderFee(); !ok { + v := paymentorder.DefaultProviderFee() + _c.mutation.SetProviderFee(v) + } if _, ok := _c.mutation.NetworkFee(); !ok { v := paymentorder.DefaultNetworkFee() _c.mutation.SetNetworkFee(v) @@ -743,6 +761,9 @@ func (_c *PaymentOrderCreate) check() error { if _, ok := _c.mutation.SenderFee(); !ok { return &ValidationError{Name: "sender_fee", err: errors.New(`ent: missing required field "PaymentOrder.sender_fee"`)} } + if _, ok := _c.mutation.ProviderFee(); !ok { + return &ValidationError{Name: "provider_fee", err: errors.New(`ent: missing required field "PaymentOrder.provider_fee"`)} + } if _, ok := _c.mutation.NetworkFee(); !ok { return &ValidationError{Name: "network_fee", err: errors.New(`ent: missing required field "PaymentOrder.network_fee"`)} } @@ -926,6 +947,10 @@ func (_c *PaymentOrderCreate) createSpec() (*PaymentOrder, *sqlgraph.CreateSpec) _spec.SetField(paymentorder.FieldSenderFee, field.TypeFloat64, value) _node.SenderFee = value } + if value, ok := _c.mutation.ProviderFee(); ok { + _spec.SetField(paymentorder.FieldProviderFee, field.TypeFloat64, value) + _node.ProviderFee = value + } if value, ok := _c.mutation.NetworkFee(); ok { _spec.SetField(paymentorder.FieldNetworkFee, field.TypeFloat64, value) _node.NetworkFee = value @@ -1344,6 +1369,24 @@ func (u *PaymentOrderUpsert) AddSenderFee(v decimal.Decimal) *PaymentOrderUpsert return u } +// SetProviderFee sets the "provider_fee" field. +func (u *PaymentOrderUpsert) SetProviderFee(v decimal.Decimal) *PaymentOrderUpsert { + u.Set(paymentorder.FieldProviderFee, v) + return u +} + +// UpdateProviderFee sets the "provider_fee" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateProviderFee() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldProviderFee) + return u +} + +// AddProviderFee adds v to the "provider_fee" field. +func (u *PaymentOrderUpsert) AddProviderFee(v decimal.Decimal) *PaymentOrderUpsert { + u.Add(paymentorder.FieldProviderFee, v) + return u +} + // SetNetworkFee sets the "network_fee" field. func (u *PaymentOrderUpsert) SetNetworkFee(v decimal.Decimal) *PaymentOrderUpsert { u.Set(paymentorder.FieldNetworkFee, v) @@ -2030,6 +2073,27 @@ func (u *PaymentOrderUpsertOne) UpdateSenderFee() *PaymentOrderUpsertOne { }) } +// SetProviderFee sets the "provider_fee" field. +func (u *PaymentOrderUpsertOne) SetProviderFee(v decimal.Decimal) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetProviderFee(v) + }) +} + +// AddProviderFee adds v to the "provider_fee" field. +func (u *PaymentOrderUpsertOne) AddProviderFee(v decimal.Decimal) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddProviderFee(v) + }) +} + +// UpdateProviderFee sets the "provider_fee" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateProviderFee() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateProviderFee() + }) +} + // SetNetworkFee sets the "network_fee" field. func (u *PaymentOrderUpsertOne) SetNetworkFee(v decimal.Decimal) *PaymentOrderUpsertOne { return u.Update(func(s *PaymentOrderUpsert) { @@ -2962,6 +3026,27 @@ func (u *PaymentOrderUpsertBulk) UpdateSenderFee() *PaymentOrderUpsertBulk { }) } +// SetProviderFee sets the "provider_fee" field. +func (u *PaymentOrderUpsertBulk) SetProviderFee(v decimal.Decimal) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetProviderFee(v) + }) +} + +// AddProviderFee adds v to the "provider_fee" field. +func (u *PaymentOrderUpsertBulk) AddProviderFee(v decimal.Decimal) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddProviderFee(v) + }) +} + +// UpdateProviderFee sets the "provider_fee" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateProviderFee() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateProviderFee() + }) +} + // SetNetworkFee sets the "network_fee" field. func (u *PaymentOrderUpsertBulk) SetNetworkFee(v decimal.Decimal) *PaymentOrderUpsertBulk { return u.Update(func(s *PaymentOrderUpsert) { diff --git a/ent/paymentorder_update.go b/ent/paymentorder_update.go index bceecbec..ba8a06ba 100644 --- a/ent/paymentorder_update.go +++ b/ent/paymentorder_update.go @@ -191,6 +191,27 @@ func (_u *PaymentOrderUpdate) AddSenderFee(v decimal.Decimal) *PaymentOrderUpdat return _u } +// SetProviderFee sets the "provider_fee" field. +func (_u *PaymentOrderUpdate) SetProviderFee(v decimal.Decimal) *PaymentOrderUpdate { + _u.mutation.ResetProviderFee() + _u.mutation.SetProviderFee(v) + return _u +} + +// SetNillableProviderFee sets the "provider_fee" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableProviderFee(v *decimal.Decimal) *PaymentOrderUpdate { + if v != nil { + _u.SetProviderFee(*v) + } + return _u +} + +// AddProviderFee adds value to the "provider_fee" field. +func (_u *PaymentOrderUpdate) AddProviderFee(v decimal.Decimal) *PaymentOrderUpdate { + _u.mutation.AddProviderFee(v) + return _u +} + // SetNetworkFee sets the "network_fee" field. func (_u *PaymentOrderUpdate) SetNetworkFee(v decimal.Decimal) *PaymentOrderUpdate { _u.mutation.ResetNetworkFee() @@ -1079,6 +1100,12 @@ func (_u *PaymentOrderUpdate) sqlSave(ctx context.Context) (_node int, err error if value, ok := _u.mutation.AddedSenderFee(); ok { _spec.AddField(paymentorder.FieldSenderFee, field.TypeFloat64, value) } + if value, ok := _u.mutation.ProviderFee(); ok { + _spec.SetField(paymentorder.FieldProviderFee, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedProviderFee(); ok { + _spec.AddField(paymentorder.FieldProviderFee, field.TypeFloat64, value) + } if value, ok := _u.mutation.NetworkFee(); ok { _spec.SetField(paymentorder.FieldNetworkFee, field.TypeFloat64, value) } @@ -1645,6 +1672,27 @@ func (_u *PaymentOrderUpdateOne) AddSenderFee(v decimal.Decimal) *PaymentOrderUp return _u } +// SetProviderFee sets the "provider_fee" field. +func (_u *PaymentOrderUpdateOne) SetProviderFee(v decimal.Decimal) *PaymentOrderUpdateOne { + _u.mutation.ResetProviderFee() + _u.mutation.SetProviderFee(v) + return _u +} + +// SetNillableProviderFee sets the "provider_fee" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableProviderFee(v *decimal.Decimal) *PaymentOrderUpdateOne { + if v != nil { + _u.SetProviderFee(*v) + } + return _u +} + +// AddProviderFee adds value to the "provider_fee" field. +func (_u *PaymentOrderUpdateOne) AddProviderFee(v decimal.Decimal) *PaymentOrderUpdateOne { + _u.mutation.AddProviderFee(v) + return _u +} + // SetNetworkFee sets the "network_fee" field. func (_u *PaymentOrderUpdateOne) SetNetworkFee(v decimal.Decimal) *PaymentOrderUpdateOne { _u.mutation.ResetNetworkFee() @@ -2563,6 +2611,12 @@ func (_u *PaymentOrderUpdateOne) sqlSave(ctx context.Context) (_node *PaymentOrd if value, ok := _u.mutation.AddedSenderFee(); ok { _spec.AddField(paymentorder.FieldSenderFee, field.TypeFloat64, value) } + if value, ok := _u.mutation.ProviderFee(); ok { + _spec.SetField(paymentorder.FieldProviderFee, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedProviderFee(); ok { + _spec.AddField(paymentorder.FieldProviderFee, field.TypeFloat64, value) + } if value, ok := _u.mutation.NetworkFee(); ok { _spec.SetField(paymentorder.FieldNetworkFee, field.TypeFloat64, value) } diff --git a/ent/runtime/runtime.go b/ent/runtime/runtime.go index 5ae00bfc..cd26c12a 100644 --- a/ent/runtime/runtime.go +++ b/ent/runtime/runtime.go @@ -192,80 +192,84 @@ func init() { paymentorderDescSenderFee := paymentorderFields[7].Descriptor() // paymentorder.DefaultSenderFee holds the default value on creation for the sender_fee field. paymentorder.DefaultSenderFee = paymentorderDescSenderFee.Default.(func() decimal.Decimal) + // paymentorderDescProviderFee is the schema descriptor for provider_fee field. + paymentorderDescProviderFee := paymentorderFields[8].Descriptor() + // paymentorder.DefaultProviderFee holds the default value on creation for the provider_fee field. + paymentorder.DefaultProviderFee = paymentorderDescProviderFee.Default.(func() decimal.Decimal) // paymentorderDescNetworkFee is the schema descriptor for network_fee field. - paymentorderDescNetworkFee := paymentorderFields[8].Descriptor() + paymentorderDescNetworkFee := paymentorderFields[9].Descriptor() // paymentorder.DefaultNetworkFee holds the default value on creation for the network_fee field. paymentorder.DefaultNetworkFee = paymentorderDescNetworkFee.Default.(func() decimal.Decimal) // paymentorderDescProtocolFee is the schema descriptor for protocol_fee field. - paymentorderDescProtocolFee := paymentorderFields[9].Descriptor() + paymentorderDescProtocolFee := paymentorderFields[10].Descriptor() // paymentorder.DefaultProtocolFee holds the default value on creation for the protocol_fee field. paymentorder.DefaultProtocolFee = paymentorderDescProtocolFee.Default.(func() decimal.Decimal) // paymentorderDescOrderPercent is the schema descriptor for order_percent field. - paymentorderDescOrderPercent := paymentorderFields[10].Descriptor() + paymentorderDescOrderPercent := paymentorderFields[11].Descriptor() // paymentorder.DefaultOrderPercent holds the default value on creation for the order_percent field. paymentorder.DefaultOrderPercent = paymentorderDescOrderPercent.Default.(func() decimal.Decimal) // paymentorderDescFeePercent is the schema descriptor for fee_percent field. - paymentorderDescFeePercent := paymentorderFields[11].Descriptor() + paymentorderDescFeePercent := paymentorderFields[12].Descriptor() // paymentorder.DefaultFeePercent holds the default value on creation for the fee_percent field. paymentorder.DefaultFeePercent = paymentorderDescFeePercent.Default.(func() decimal.Decimal) // paymentorderDescTxHash is the schema descriptor for tx_hash field. - paymentorderDescTxHash := paymentorderFields[12].Descriptor() + paymentorderDescTxHash := paymentorderFields[13].Descriptor() // paymentorder.TxHashValidator is a validator for the "tx_hash" field. It is called by the builders before save. paymentorder.TxHashValidator = paymentorderDescTxHash.Validators[0].(func(string) error) // paymentorderDescBlockNumber is the schema descriptor for block_number field. - paymentorderDescBlockNumber := paymentorderFields[13].Descriptor() + paymentorderDescBlockNumber := paymentorderFields[14].Descriptor() // paymentorder.DefaultBlockNumber holds the default value on creation for the block_number field. paymentorder.DefaultBlockNumber = paymentorderDescBlockNumber.Default.(int64) // paymentorderDescGatewayID is the schema descriptor for gateway_id field. - paymentorderDescGatewayID := paymentorderFields[15].Descriptor() + paymentorderDescGatewayID := paymentorderFields[16].Descriptor() // paymentorder.GatewayIDValidator is a validator for the "gateway_id" field. It is called by the builders before save. paymentorder.GatewayIDValidator = paymentorderDescGatewayID.Validators[0].(func(string) error) // paymentorderDescFromAddress is the schema descriptor for from_address field. - paymentorderDescFromAddress := paymentorderFields[16].Descriptor() + paymentorderDescFromAddress := paymentorderFields[17].Descriptor() // paymentorder.FromAddressValidator is a validator for the "from_address" field. It is called by the builders before save. paymentorder.FromAddressValidator = paymentorderDescFromAddress.Validators[0].(func(string) error) // paymentorderDescRefundOrRecipientAddress is the schema descriptor for refund_or_recipient_address field. - paymentorderDescRefundOrRecipientAddress := paymentorderFields[17].Descriptor() + paymentorderDescRefundOrRecipientAddress := paymentorderFields[18].Descriptor() // paymentorder.RefundOrRecipientAddressValidator is a validator for the "refund_or_recipient_address" field. It is called by the builders before save. paymentorder.RefundOrRecipientAddressValidator = paymentorderDescRefundOrRecipientAddress.Validators[0].(func(string) error) // paymentorderDescReceiveAddress is the schema descriptor for receive_address field. - paymentorderDescReceiveAddress := paymentorderFields[18].Descriptor() + paymentorderDescReceiveAddress := paymentorderFields[19].Descriptor() // paymentorder.ReceiveAddressValidator is a validator for the "receive_address" field. It is called by the builders before save. paymentorder.ReceiveAddressValidator = paymentorderDescReceiveAddress.Validators[0].(func(string) error) // paymentorderDescFeeAddress is the schema descriptor for fee_address field. - paymentorderDescFeeAddress := paymentorderFields[21].Descriptor() + paymentorderDescFeeAddress := paymentorderFields[22].Descriptor() // paymentorder.FeeAddressValidator is a validator for the "fee_address" field. It is called by the builders before save. paymentorder.FeeAddressValidator = paymentorderDescFeeAddress.Validators[0].(func(string) error) // paymentorderDescInstitution is the schema descriptor for institution field. - paymentorderDescInstitution := paymentorderFields[23].Descriptor() + paymentorderDescInstitution := paymentorderFields[24].Descriptor() // paymentorder.InstitutionValidator is a validator for the "institution" field. It is called by the builders before save. paymentorder.InstitutionValidator = paymentorderDescInstitution.Validators[0].(func(string) error) // paymentorderDescAccountIdentifier is the schema descriptor for account_identifier field. - paymentorderDescAccountIdentifier := paymentorderFields[24].Descriptor() + paymentorderDescAccountIdentifier := paymentorderFields[25].Descriptor() // paymentorder.AccountIdentifierValidator is a validator for the "account_identifier" field. It is called by the builders before save. paymentorder.AccountIdentifierValidator = paymentorderDescAccountIdentifier.Validators[0].(func(string) error) // paymentorderDescAccountName is the schema descriptor for account_name field. - paymentorderDescAccountName := paymentorderFields[25].Descriptor() + paymentorderDescAccountName := paymentorderFields[26].Descriptor() // paymentorder.AccountNameValidator is a validator for the "account_name" field. It is called by the builders before save. paymentorder.AccountNameValidator = paymentorderDescAccountName.Validators[0].(func(string) error) // paymentorderDescSender is the schema descriptor for sender field. - paymentorderDescSender := paymentorderFields[27].Descriptor() + paymentorderDescSender := paymentorderFields[28].Descriptor() // paymentorder.SenderValidator is a validator for the "sender" field. It is called by the builders before save. paymentorder.SenderValidator = paymentorderDescSender.Validators[0].(func(string) error) // paymentorderDescReference is the schema descriptor for reference field. - paymentorderDescReference := paymentorderFields[28].Descriptor() + paymentorderDescReference := paymentorderFields[29].Descriptor() // paymentorder.ReferenceValidator is a validator for the "reference" field. It is called by the builders before save. paymentorder.ReferenceValidator = paymentorderDescReference.Validators[0].(func(string) error) // paymentorderDescCancellationCount is the schema descriptor for cancellation_count field. - paymentorderDescCancellationCount := paymentorderFields[29].Descriptor() + paymentorderDescCancellationCount := paymentorderFields[30].Descriptor() // paymentorder.DefaultCancellationCount holds the default value on creation for the cancellation_count field. paymentorder.DefaultCancellationCount = paymentorderDescCancellationCount.Default.(int) // paymentorderDescCancellationReasons is the schema descriptor for cancellation_reasons field. - paymentorderDescCancellationReasons := paymentorderFields[30].Descriptor() + paymentorderDescCancellationReasons := paymentorderFields[31].Descriptor() // paymentorder.DefaultCancellationReasons holds the default value on creation for the cancellation_reasons field. paymentorder.DefaultCancellationReasons = paymentorderDescCancellationReasons.Default.([]string) // paymentorderDescMemo is the schema descriptor for memo field. - paymentorderDescMemo := paymentorderFields[31].Descriptor() + paymentorderDescMemo := paymentorderFields[32].Descriptor() // paymentorder.MemoValidator is a validator for the "memo" field. It is called by the builders before save. paymentorder.MemoValidator = paymentorderDescMemo.Validators[0].(func(string) error) // paymentorderDescID is the schema descriptor for id field. diff --git a/ent/schema/paymentorder.go b/ent/schema/paymentorder.go index ef14338e..cb557205 100644 --- a/ent/schema/paymentorder.go +++ b/ent/schema/paymentorder.go @@ -42,6 +42,9 @@ func (PaymentOrder) Fields() []ent.Field { field.Float("sender_fee"). GoType(decimal.Decimal{}). DefaultFunc(func() decimal.Decimal { return decimal.Zero }), + field.Float("provider_fee"). + GoType(decimal.Decimal{}). + DefaultFunc(func() decimal.Decimal { return decimal.Zero }), field.Float("network_fee"). GoType(decimal.Decimal{}). DefaultFunc(func() decimal.Decimal { return decimal.Zero }), diff --git a/services/common/indexer.go b/services/common/indexer.go index ccc538a6..12b40d33 100644 --- a/services/common/indexer.go +++ b/services/common/indexer.go @@ -279,6 +279,21 @@ func ProcessSettleInOrders(ctx context.Context, network *ent.Network, orderIds [ return nil } +// ProcessLocalTransferFeeSplitEvents processes LocalTransferFeeSplit events and updates provider fees. +func ProcessLocalTransferFeeSplitEvents(ctx context.Context, network *ent.Network, events []*types.LocalTransferFeeSplitEvent) error { + for _, event := range events { + if err := UpdateProviderFee(ctx, network, event); err != nil { + logger.WithFields(logger.Fields{ + "Error": fmt.Sprintf("%v", err), + "OrderID": event.OrderId, + "TxHash": event.TxHash, + "Network": network.Identifier, + }).Errorf("Failed to update provider fee for order %s", event.OrderId) + } + } + return nil +} + // ProcessRefundedOrders processes refunded orders for a network func ProcessRefundedOrders(ctx context.Context, network *ent.Network, orderIds []string, orderIdToEvent map[string]*types.OrderRefundedEvent) error { lockOrders, err := storage.Client.PaymentOrder. diff --git a/services/common/order.go b/services/common/order.go index 8b0ff207..a0659bef 100644 --- a/services/common/order.go +++ b/services/common/order.go @@ -54,6 +54,25 @@ func normalizeGatewayID(orderID string) string { return strings.ToLower(s) } +// UpdateProviderFee updates the provider_fee field on a payment order from a LocalTransferFeeSplit event. +func UpdateProviderFee(ctx context.Context, network *ent.Network, event *types.LocalTransferFeeSplitEvent) error { + gatewayID := normalizeGatewayID(event.OrderId) + + _, err := db.Client.PaymentOrder. + Update(). + Where( + paymentorder.GatewayIDEQ(gatewayID), + paymentorder.HasTokenWith( + tokenent.HasNetworkWith( + networkent.IdentifierEQ(network.Identifier), + ), + ), + ). + SetProviderFee(event.ProviderAmount). + Save(ctx) + return err +} + // ErrNoProvisionBucketForAmount is returned when the amount falls in a gap between tier ranges (no bucket contains it). var ErrNoProvisionBucketForAmount = errors.New("no provision bucket for this amount") diff --git a/services/indexer/evm.go b/services/indexer/evm.go index 07d8840f..40b7d965 100644 --- a/services/indexer/evm.go +++ b/services/indexer/evm.go @@ -557,6 +557,7 @@ func (s *IndexerEVM) indexGatewayByTransaction(ctx context.Context, network *ent settleOutEvents := []*types.SettleOutEvent{} settleInEvents := []*types.SettleInEvent{} orderRefundedEvents := []*types.OrderRefundedEvent{} + localFeeSplitEvents := []*types.LocalTransferFeeSplitEvent{} // Use GetContractEventsWithFallback to try Thirdweb first and fall back to RPC eventPayload := map[string]string{ @@ -849,6 +850,46 @@ func (s *IndexerEVM) indexGatewayByTransaction(ctx context.Context, network *ent Fee: fee, } orderRefundedEvents = append(orderRefundedEvents, refundedEvent) + + case utils.LocalTransferFeeSplitEventSignature: + orderIdStr, ok := indexedParams["orderId"].(string) + if !ok || orderIdStr == "" { + continue + } + senderAmountStr, ok := nonIndexedParams["senderAmount"].(string) + if !ok || senderAmountStr == "" { + continue + } + senderAmount, err := decimal.NewFromString(senderAmountStr) + if err != nil { + continue + } + providerAmountStr, ok := nonIndexedParams["providerAmount"].(string) + if !ok || providerAmountStr == "" { + continue + } + providerAmount, err := decimal.NewFromString(providerAmountStr) + if err != nil { + continue + } + aggregatorAmountStr, ok := nonIndexedParams["aggregatorAmount"].(string) + if !ok || aggregatorAmountStr == "" { + continue + } + aggregatorAmount, err := decimal.NewFromString(aggregatorAmountStr) + if err != nil { + continue + } + + feeSplitEvent := &types.LocalTransferFeeSplitEvent{ + BlockNumber: blockNumber, + TxHash: txHashFromEvent, + OrderId: orderIdStr, + SenderAmount: senderAmount, + ProviderAmount: providerAmount, + AggregatorAmount: aggregatorAmount, + } + localFeeSplitEvents = append(localFeeSplitEvents, feeSplitEvent) } } @@ -916,6 +957,15 @@ func (s *IndexerEVM) indexGatewayByTransaction(ctx context.Context, network *ent } eventCounts.OrderRefunded = len(orderRefundedEvents) + // Process LocalTransferFeeSplit events + if len(localFeeSplitEvents) > 0 { + err := common.ProcessLocalTransferFeeSplitEvents(ctx, network, localFeeSplitEvents) + if err != nil { + logger.Errorf("Failed to process LocalTransferFeeSplit events: %v", err) + } + } + eventCounts.LocalTransferFeeSplit = len(localFeeSplitEvents) + return eventCounts, nil } diff --git a/types/types.go b/types/types.go index ea93916b..be848145 100644 --- a/types/types.go +++ b/types/types.go @@ -103,6 +103,16 @@ type SettleOutEvent struct { RebatePercent decimal.Decimal } +// LocalTransferFeeSplitEvent represents a LocalTransferFeeSplit event from the Gateway contract. +type LocalTransferFeeSplitEvent struct { + BlockNumber int64 + TxHash string + OrderId string + SenderAmount decimal.Decimal + ProviderAmount decimal.Decimal + AggregatorAmount decimal.Decimal +} + // OrderSettledEvent represents an order settled event. Only used for Starknet. type OrderSettledEvent struct { BlockNumber int64 @@ -994,9 +1004,10 @@ type ChangePasswordPayload struct { // SenderStatsResponse is the response for the sender stats endpoint type SenderStatsResponse struct { - TotalOrders int `json:"totalOrders"` - TotalOrderVolume decimal.Decimal `json:"totalOrderVolume"` - TotalFeeEarnings decimal.Decimal `json:"totalFeeEarnings"` + TotalOrders int `json:"totalOrders"` + TotalOrderVolume decimal.Decimal `json:"totalOrderVolume"` + TotalFeeEarnings decimal.Decimal `json:"totalFeeEarnings"` + TotalProviderFees decimal.Decimal `json:"totalProviderFees"` } // ProviderStatsResponse is the response for the provider stats endpoint @@ -1140,7 +1151,8 @@ type EventCounts struct { OrderCreated int `json:"OrderCreated"` SettleOut int `json:"SettleOut"` // SettleOut (offramp); Starknet OrderSettled is mapped here SettleIn int `json:"SettleIn"` // SettleIn (onramp) - OrderRefunded int `json:"OrderRefunded"` + OrderRefunded int `json:"OrderRefunded"` + LocalTransferFeeSplit int `json:"LocalTransferFeeSplit"` } // ThirdwebWebhookPayload represents the structure of thirdweb insight webhook payload diff --git a/utils/rpc_events.go b/utils/rpc_events.go index 21bb5681..db71a6b9 100644 --- a/utils/rpc_events.go +++ b/utils/rpc_events.go @@ -19,7 +19,10 @@ const ( // SettleIn (onramp): Gateway emits SettleIn(bytes32 indexed orderId, address indexed liquidityProvider, address indexed recipient, uint256 amount, address token, uint256 aggregatorFee, uint96 rate) // Topic must match contracts (see Gateway.go FilterSettleIn); legacy topic 0x44de25d6... was an older indexed-parameter layout and will not match current deployments. - SettleInEventSignature = "0xb5273ccce1412b056c9246e834895f9d717974c505f8e5a6c7d08cd0300a066b" + SettleInEventSignature = "0xb5273ccce1412b056c9246e834895f9d717974c505f8e5a6c7d08cd0300a066b" + + // LocalTransferFeeSplit: Gateway emits LocalTransferFeeSplit(bytes32 indexed orderId, uint256 senderAmount, uint256 providerAmount, uint256 aggregatorAmount) + LocalTransferFeeSplitEventSignature = "0x831c7cc0006d91462607c476603366c48469d125de6228c0791a7090efd7f7a4" OrderCreatedStarknetSelector = "0x3427759bfd3b941f14e687e129519da3c9b0046c5b9aaa290bb1dede63753b3" OrderSettledStarknetSelector = "0x2f4d375c16c9a465e9396e640dcf9032795bee57646a3117d94b9304be0868c" OrderRefundedStarknetSelector = "0x2b1527a936433fc64df27b599aa49d8cbaac3a88b1b3888cf4384b9e8bea9cd" @@ -217,6 +220,38 @@ func DecodeOrderRefundedEvent(log types.Log) (map[string]interface{}, error) { }, nil } +// DecodeLocalTransferFeeSplitEvent decodes a LocalTransferFeeSplit event from RPC log +func DecodeLocalTransferFeeSplitEvent(log types.Log) (map[string]interface{}, error) { + // LocalTransferFeeSplit event: LocalTransferFeeSplit(bytes32 indexed orderId, uint256 senderAmount, uint256 providerAmount, uint256 aggregatorAmount) + // Topics: [eventSignature, orderId] + // Data: [senderAmount (32 bytes), providerAmount (32 bytes), aggregatorAmount (32 bytes)] + + if len(log.Topics) != 2 { + return nil, fmt.Errorf("invalid LocalTransferFeeSplit event: expected 2 topics, got %d", len(log.Topics)) + } + + orderId := common.BytesToHash(log.Topics[1].Bytes()) + + if len(log.Data) < 96 { + return nil, fmt.Errorf("invalid LocalTransferFeeSplit event data: too short") + } + + senderAmount := new(big.Int).SetBytes(log.Data[:32]) + providerAmount := new(big.Int).SetBytes(log.Data[32:64]) + aggregatorAmount := new(big.Int).SetBytes(log.Data[64:96]) + + return map[string]interface{}{ + "indexed_params": map[string]interface{}{ + "orderId": orderId.Hex(), + }, + "non_indexed_params": map[string]interface{}{ + "senderAmount": senderAmount.String(), + "providerAmount": providerAmount.String(), + "aggregatorAmount": aggregatorAmount.String(), + }, + }, nil +} + // ProcessRPCEvents processes RPC events and converts them to the same format as Thirdweb Insight func ProcessRPCEvents(events []interface{}, eventSignature string) error { for _, event := range events { @@ -259,6 +294,8 @@ func ProcessRPCEvents(events []interface{}, eventSignature string) error { decoded, err = DecodeSettleInEvent(mockLog) case OrderRefundedEventSignature: decoded, err = DecodeOrderRefundedEvent(mockLog) + case LocalTransferFeeSplitEventSignature: + decoded, err = DecodeLocalTransferFeeSplitEvent(mockLog) default: continue } @@ -319,6 +356,8 @@ func ProcessRPCEventsBySignature(events []interface{}) error { decoded, err = DecodeSettleInEvent(mockLog) case OrderRefundedEventSignature: decoded, err = DecodeOrderRefundedEvent(mockLog) + case LocalTransferFeeSplitEventSignature: + decoded, err = DecodeLocalTransferFeeSplitEvent(mockLog) default: continue }