From 4b7a5dc41671bad7194d6a6399fd500296eed9a0 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Mon, 24 Feb 2025 11:38:07 -0500 Subject: [PATCH] Add fees to UnsignedOriginatorEnvelope --- pkg/api/message/publishWorker.go | 55 ++++++++++++++++++---- pkg/api/message/publish_test.go | 47 ++++++++++++++++++ pkg/api/message/service.go | 17 +++++-- pkg/constants/constants.go | 1 + pkg/db/queries.sql | 4 +- pkg/db/queries/queries.sql.go | 6 ++- pkg/envelopes/unsignedOriginator.go | 11 +++++ pkg/proto/xmtpv4/envelopes/envelopes.pb.go | 41 ++++++++++++---- pkg/registrant/registrant.go | 16 +++++-- pkg/registrant/registrant_test.go | 7 ++- pkg/server/server.go | 18 ++++++- pkg/testutils/api/api.go | 4 ++ pkg/testutils/fees/rates.go | 16 +++++++ 13 files changed, 211 insertions(+), 32 deletions(-) create mode 100644 pkg/testutils/fees/rates.go diff --git a/pkg/api/message/publishWorker.go b/pkg/api/message/publishWorker.go index 86bdc59d..0f2d5356 100644 --- a/pkg/api/message/publishWorker.go +++ b/pkg/api/message/publishWorker.go @@ -6,9 +6,12 @@ import ( "sync/atomic" "time" + "github.com/xmtp/xmtpd/pkg/constants" + "github.com/xmtp/xmtpd/pkg/currency" "github.com/xmtp/xmtpd/pkg/db" "github.com/xmtp/xmtpd/pkg/db/queries" "github.com/xmtp/xmtpd/pkg/envelopes" + "github.com/xmtp/xmtpd/pkg/fees" "github.com/xmtp/xmtpd/pkg/registrant" "go.uber.org/zap" ) @@ -22,6 +25,7 @@ type publishWorker struct { store *sql.DB subscription db.DBSubscription[queries.StagedOriginatorEnvelope, int64] lastProcessed atomic.Int64 + feeCalculator fees.IFeeCalculator } func startPublishWorker( @@ -29,6 +33,7 @@ func startPublishWorker( log *zap.Logger, reg *registrant.Registrant, store *sql.DB, + feeCalculator fees.IFeeCalculator, ) (*publishWorker, error) { log = log.Named("publishWorker") q := queries.New(store) @@ -62,13 +67,14 @@ func startPublishWorker( } worker := &publishWorker{ - ctx: ctx, - log: log, - notifier: notifier, - subscription: *subscription, - listener: listener, - registrant: reg, - store: store, + ctx: ctx, + log: log, + notifier: notifier, + subscription: *subscription, + listener: listener, + registrant: reg, + store: store, + feeCalculator: feeCalculator, } go worker.start() @@ -102,7 +108,13 @@ func (p *publishWorker) start() { func (p *publishWorker) publishStagedEnvelope(stagedEnv queries.StagedOriginatorEnvelope) bool { logger := p.log.With(zap.Int64("sequenceID", stagedEnv.ID)) - originatorEnv, err := p.registrant.SignStagedEnvelope(stagedEnv) + baseFee, congestionFee, err := p.calculateFees(&stagedEnv) + if err != nil { + logger.Error("Failed to calculate fees", zap.Error(err)) + return false + } + + originatorEnv, err := p.registrant.SignStagedEnvelope(stagedEnv, baseFee, congestionFee) if err != nil { logger.Error( "Failed to sign staged envelope", @@ -144,6 +156,7 @@ func (p *publishWorker) publishStagedEnvelope(stagedEnv queries.StagedOriginator Topic: stagedEnv.Topic, OriginatorEnvelope: originatorBytes, PayerID: db.NullInt32(payerId), + GatewayTime: stagedEnv.OriginatorTime, }, ) if p.ctx.Err() != nil { @@ -171,3 +184,29 @@ func (p *publishWorker) publishStagedEnvelope(stagedEnv queries.StagedOriginator return true } + +func (p *publishWorker) calculateFees( + stagedEnv *queries.StagedOriginatorEnvelope, +) (currency.PicoDollar, currency.PicoDollar, error) { + baseFee, err := p.feeCalculator.CalculateBaseFee( + stagedEnv.OriginatorTime, + int64(len(stagedEnv.PayerEnvelope)), + constants.DEFAULT_STORAGE_DURATION_DAYS, + ) + if err != nil { + return 0, 0, err + } + + // TODO:nm: Set this to the actual congestion fee + // For now we are setting congestion to 0 + congestionFee, err := p.feeCalculator.CalculateCongestionFee( + stagedEnv.OriginatorTime, + 0, + ) + + if err != nil { + return 0, 0, err + } + + return baseFee, congestionFee, nil +} diff --git a/pkg/api/message/publish_test.go b/pkg/api/message/publish_test.go index 3e8cc309..268e5a0e 100644 --- a/pkg/api/message/publish_test.go +++ b/pkg/api/message/publish_test.go @@ -7,7 +7,9 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/xmtp/xmtpd/pkg/currency" "github.com/xmtp/xmtpd/pkg/db/queries" + envelopeUtils "github.com/xmtp/xmtpd/pkg/envelopes" "github.com/xmtp/xmtpd/pkg/mlsvalidate" apiv1 "github.com/xmtp/xmtpd/pkg/proto/mls/api/v1" "github.com/xmtp/xmtpd/pkg/proto/xmtpv4/envelopes" @@ -294,3 +296,48 @@ func TestPublishEnvelopeOriginatorUnknown(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "DependsOn has not been seen by this node") } + +func TestPublishEnvelopeFees(t *testing.T) { + api, db, _, cleanup := apiTestUtils.NewTestReplicationAPIClient(t) + defer cleanup() + + payerEnvelope := envelopeTestUtils.CreatePayerEnvelope( + t, + envelopeTestUtils.DefaultClientEnvelopeNodeId, + ) + + resp, err := api.PublishPayerEnvelopes( + context.Background(), + &message_api.PublishPayerEnvelopesRequest{ + PayerEnvelopes: []*envelopes.PayerEnvelope{payerEnvelope}, + }, + ) + require.NoError(t, err) + require.NotNil(t, resp) + + returnedEnv, err := envelopeUtils.NewOriginatorEnvelope(resp.GetOriginatorEnvelopes()[0]) + require.NoError(t, err) + // BaseFee will always be > 0 + require.Greater(t, returnedEnv.UnsignedOriginatorEnvelope.BaseFee(), currency.PicoDollar(0)) + // CongestionFee will be 0 for now. + // TODO:nm: Set this to the actual congestion fee + require.Equal(t, returnedEnv.UnsignedOriginatorEnvelope.CongestionFee(), currency.PicoDollar(0)) + + envs, err := queries.New(db). + SelectGatewayEnvelopes(context.Background(), queries.SelectGatewayEnvelopesParams{}) + require.NoError(t, err) + require.Equal(t, len(envs), 1) + + originatorEnv, err := envelopeUtils.NewOriginatorEnvelopeFromBytes(envs[0].OriginatorEnvelope) + require.NoError(t, err) + require.Equal( + t, + originatorEnv.UnsignedOriginatorEnvelope.BaseFee(), + returnedEnv.UnsignedOriginatorEnvelope.BaseFee(), + ) + require.Equal( + t, + originatorEnv.UnsignedOriginatorEnvelope.CongestionFee(), + returnedEnv.UnsignedOriginatorEnvelope.CongestionFee(), + ) +} diff --git a/pkg/api/message/service.go b/pkg/api/message/service.go index aabefefb..bd6b6f11 100644 --- a/pkg/api/message/service.go +++ b/pkg/api/message/service.go @@ -4,9 +4,11 @@ import ( "context" "database/sql" "fmt" - "github.com/xmtp/xmtpd/pkg/api/metadata" "time" + "github.com/xmtp/xmtpd/pkg/api/metadata" + "github.com/xmtp/xmtpd/pkg/fees" + "github.com/xmtp/xmtpd/pkg/db" "github.com/xmtp/xmtpd/pkg/db/queries" "github.com/xmtp/xmtpd/pkg/envelopes" @@ -42,6 +44,7 @@ type Service struct { subscribeWorker *subscribeWorker validationService mlsvalidate.MLSValidationService cu metadata.CursorUpdater + feeCalculator fees.IFeeCalculator } func NewReplicationApiService( @@ -51,8 +54,10 @@ func NewReplicationApiService( store *sql.DB, validationService mlsvalidate.MLSValidationService, updater metadata.CursorUpdater, + rateFetcher fees.IRatesFetcher, ) (*Service, error) { - publishWorker, err := startPublishWorker(ctx, log, registrant, store) + feeCalculator := fees.NewFeeCalculator(rateFetcher) + publishWorker, err := startPublishWorker(ctx, log, registrant, store, feeCalculator) if err != nil { return nil, err } @@ -70,6 +75,7 @@ func NewReplicationApiService( subscribeWorker: subscribeWorker, validationService: validationService, cu: updater, + feeCalculator: feeCalculator, }, nil } @@ -349,7 +355,12 @@ func (s *Service) PublishPayerEnvelopes( } s.publishWorker.notifyStagedPublish() - originatorEnv, err := s.registrant.SignStagedEnvelope(stagedEnv) + baseFee, congestionFee, err := s.publishWorker.calculateFees(&stagedEnv) + if err != nil { + return nil, status.Errorf(codes.Internal, "could not calculate fees: %v", err) + } + + originatorEnv, err := s.registrant.SignStagedEnvelope(stagedEnv, baseFee, congestionFee) if err != nil { return nil, status.Errorf(codes.Internal, "could not sign envelope: %v", err) } diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 46d881ec..09ac6dd8 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -7,6 +7,7 @@ const ( ORIGINATOR_DOMAIN_SEPARATION_LABEL = "originator|" NODE_AUTHORIZATION_HEADER_NAME = "node-authorization" MAX_BLOCKCHAIN_ORIGINATOR_ID = 100 + DEFAULT_STORAGE_DURATION_DAYS = 60 ) type VerifiedNodeRequestCtxKey struct{} diff --git a/pkg/db/queries.sql b/pkg/db/queries.sql index a0e0182e..030aacd5 100644 --- a/pkg/db/queries.sql +++ b/pkg/db/queries.sql @@ -13,8 +13,8 @@ WHERE singleton_id = 1; -- name: InsertGatewayEnvelope :execrows -INSERT INTO gateway_envelopes(originator_node_id, originator_sequence_id, topic, originator_envelope, payer_id) - VALUES (@originator_node_id, @originator_sequence_id, @topic, @originator_envelope, @payer_id) +INSERT INTO gateway_envelopes(originator_node_id, originator_sequence_id, topic, originator_envelope, payer_id, gateway_time) + VALUES (@originator_node_id, @originator_sequence_id, @topic, @originator_envelope, @payer_id, COALESCE(@gateway_time, NOW())) ON CONFLICT DO NOTHING; diff --git a/pkg/db/queries/queries.sql.go b/pkg/db/queries/queries.sql.go index f717f173..6554d65d 100644 --- a/pkg/db/queries/queries.sql.go +++ b/pkg/db/queries/queries.sql.go @@ -272,8 +272,8 @@ func (q *Queries) InsertBlockchainMessage(ctx context.Context, arg InsertBlockch } const insertGatewayEnvelope = `-- name: InsertGatewayEnvelope :execrows -INSERT INTO gateway_envelopes(originator_node_id, originator_sequence_id, topic, originator_envelope, payer_id) - VALUES ($1, $2, $3, $4, $5) +INSERT INTO gateway_envelopes(originator_node_id, originator_sequence_id, topic, originator_envelope, payer_id, gateway_time) + VALUES ($1, $2, $3, $4, $5, COALESCE($6, NOW())) ON CONFLICT DO NOTHING ` @@ -284,6 +284,7 @@ type InsertGatewayEnvelopeParams struct { Topic []byte OriginatorEnvelope []byte PayerID sql.NullInt32 + GatewayTime interface{} } func (q *Queries) InsertGatewayEnvelope(ctx context.Context, arg InsertGatewayEnvelopeParams) (int64, error) { @@ -293,6 +294,7 @@ func (q *Queries) InsertGatewayEnvelope(ctx context.Context, arg InsertGatewayEn arg.Topic, arg.OriginatorEnvelope, arg.PayerID, + arg.GatewayTime, ) if err != nil { return 0, err diff --git a/pkg/envelopes/unsignedOriginator.go b/pkg/envelopes/unsignedOriginator.go index bd4a3d6a..3a00525e 100644 --- a/pkg/envelopes/unsignedOriginator.go +++ b/pkg/envelopes/unsignedOriginator.go @@ -3,6 +3,7 @@ package envelopes import ( "errors" + "github.com/xmtp/xmtpd/pkg/currency" envelopesProto "github.com/xmtp/xmtpd/pkg/proto/xmtpv4/envelopes" "github.com/xmtp/xmtpd/pkg/topic" "github.com/xmtp/xmtpd/pkg/utils" @@ -45,6 +46,16 @@ func (u *UnsignedOriginatorEnvelope) OriginatorNs() int64 { return u.proto.OriginatorNs } +func (u *UnsignedOriginatorEnvelope) BaseFee() currency.PicoDollar { + // Skip nil check because it is in the constructor + return currency.PicoDollar(u.proto.BaseFeePicodollars) +} + +func (u *UnsignedOriginatorEnvelope) CongestionFee() currency.PicoDollar { + // Skip nil check because it is in the constructor + return currency.PicoDollar(u.proto.CongestionFeePicodollars) +} + func NewUnsignedOriginatorEnvelopeFromBytes(bytes []byte) (*UnsignedOriginatorEnvelope, error) { message, err := utils.UnmarshalUnsignedEnvelope(bytes) if err != nil { diff --git a/pkg/proto/xmtpv4/envelopes/envelopes.pb.go b/pkg/proto/xmtpv4/envelopes/envelopes.pb.go index 04a10881..2cecb3d1 100644 --- a/pkg/proto/xmtpv4/envelopes/envelopes.pb.go +++ b/pkg/proto/xmtpv4/envelopes/envelopes.pb.go @@ -326,13 +326,15 @@ func (x *PayerEnvelope) GetTargetOriginator() uint32 { // For blockchain envelopes, these fields are set by the smart contract type UnsignedOriginatorEnvelope struct { - state protoimpl.MessageState `protogen:"open.v1"` - OriginatorNodeId uint32 `protobuf:"varint,1,opt,name=originator_node_id,json=originatorNodeId,proto3" json:"originator_node_id,omitempty"` - OriginatorSequenceId uint64 `protobuf:"varint,2,opt,name=originator_sequence_id,json=originatorSequenceId,proto3" json:"originator_sequence_id,omitempty"` - OriginatorNs int64 `protobuf:"varint,3,opt,name=originator_ns,json=originatorNs,proto3" json:"originator_ns,omitempty"` - PayerEnvelope *PayerEnvelope `protobuf:"bytes,4,opt,name=payer_envelope,json=payerEnvelope,proto3" json:"payer_envelope,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + OriginatorNodeId uint32 `protobuf:"varint,1,opt,name=originator_node_id,json=originatorNodeId,proto3" json:"originator_node_id,omitempty"` + OriginatorSequenceId uint64 `protobuf:"varint,2,opt,name=originator_sequence_id,json=originatorSequenceId,proto3" json:"originator_sequence_id,omitempty"` + OriginatorNs int64 `protobuf:"varint,3,opt,name=originator_ns,json=originatorNs,proto3" json:"originator_ns,omitempty"` + PayerEnvelope *PayerEnvelope `protobuf:"bytes,4,opt,name=payer_envelope,json=payerEnvelope,proto3" json:"payer_envelope,omitempty"` + BaseFeePicodollars uint64 `protobuf:"varint,5,opt,name=base_fee_picodollars,json=baseFeePicodollars,proto3" json:"base_fee_picodollars,omitempty"` // The base fee for the message in picodollars + CongestionFeePicodollars uint64 `protobuf:"varint,6,opt,name=congestion_fee_picodollars,json=congestionFeePicodollars,proto3" json:"congestion_fee_picodollars,omitempty"` // The congestion fee for the message in picodollars + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *UnsignedOriginatorEnvelope) Reset() { @@ -393,6 +395,20 @@ func (x *UnsignedOriginatorEnvelope) GetPayerEnvelope() *PayerEnvelope { return nil } +func (x *UnsignedOriginatorEnvelope) GetBaseFeePicodollars() uint64 { + if x != nil { + return x.BaseFeePicodollars + } + return 0 +} + +func (x *UnsignedOriginatorEnvelope) GetCongestionFeePicodollars() uint64 { + if x != nil { + return x.CongestionFeePicodollars + } + return 0 +} + // An alternative to a signature for blockchain payloads type BlockchainProof struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -607,7 +623,7 @@ var file_xmtpv4_envelopes_envelopes_proto_rawDesc = string([]byte{ 0x0e, 0x70, 0x61, 0x79, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xf2, 0x01, 0x0a, + 0x65, 0x74, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xe2, 0x02, 0x0a, 0x1a, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, @@ -623,7 +639,14 @@ var file_xmtpv4_envelopes_envelopes_proto_rawDesc = string([]byte{ 0x6d, 0x74, 0x70, 0x2e, 0x78, 0x6d, 0x74, 0x70, 0x76, 0x34, 0x2e, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x65, 0x72, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, - 0x65, 0x22, 0x3c, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x50, + 0x65, 0x12, 0x30, 0x0a, 0x14, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x69, + 0x63, 0x6f, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x12, 0x62, 0x61, 0x73, 0x65, 0x46, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x64, 0x6f, 0x6c, 0x6c, + 0x61, 0x72, 0x73, 0x12, 0x3c, 0x0a, 0x1a, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x69, 0x63, 0x6f, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x63, 0x6f, 0x6e, 0x67, 0x65, 0x73, 0x74, + 0x69, 0x6f, 0x6e, 0x46, 0x65, 0x65, 0x50, 0x69, 0x63, 0x6f, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, + 0x73, 0x22, 0x3c, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x73, 0x68, 0x22, diff --git a/pkg/registrant/registrant.go b/pkg/registrant/registrant.go index 7b1555e5..4d529f01 100644 --- a/pkg/registrant/registrant.go +++ b/pkg/registrant/registrant.go @@ -5,13 +5,15 @@ import ( "context" "crypto/ecdsa" "fmt" - "github.com/Masterminds/semver/v3" "slices" + "github.com/Masterminds/semver/v3" + "go.uber.org/zap" "github.com/ethereum/go-ethereum/crypto" "github.com/xmtp/xmtpd/pkg/authn" + "github.com/xmtp/xmtpd/pkg/currency" "github.com/xmtp/xmtpd/pkg/db/queries" "github.com/xmtp/xmtpd/pkg/proto/identity/associations" "github.com/xmtp/xmtpd/pkg/proto/xmtpv4/envelopes" @@ -76,16 +78,20 @@ func (r *Registrant) TokenFactory() *authn.TokenFactory { func (r *Registrant) SignStagedEnvelope( stagedEnv queries.StagedOriginatorEnvelope, + baseFee currency.PicoDollar, + congestionFee currency.PicoDollar, ) (*envelopes.OriginatorEnvelope, error) { payerEnv := &envelopes.PayerEnvelope{} if err := proto.Unmarshal(stagedEnv.PayerEnvelope, payerEnv); err != nil { return nil, fmt.Errorf("Could not unmarshal payer envelope: %v", err) } unsignedEnv := envelopes.UnsignedOriginatorEnvelope{ - OriginatorNodeId: r.record.NodeID, - OriginatorSequenceId: uint64(stagedEnv.ID), - OriginatorNs: stagedEnv.OriginatorTime.UnixNano(), - PayerEnvelope: payerEnv, + OriginatorNodeId: r.record.NodeID, + OriginatorSequenceId: uint64(stagedEnv.ID), + OriginatorNs: stagedEnv.OriginatorTime.UnixNano(), + PayerEnvelope: payerEnv, + BaseFeePicodollars: uint64(baseFee), + CongestionFeePicodollars: uint64(congestionFee), } unsignedBytes, err := proto.Marshal(&unsignedEnv) if err != nil { diff --git a/pkg/registrant/registrant_test.go b/pkg/registrant/registrant_test.go index c74551f9..81dc1355 100644 --- a/pkg/registrant/registrant_test.go +++ b/pkg/registrant/registrant_test.go @@ -3,10 +3,11 @@ package registrant_test import ( "context" "crypto/ecdsa" - "github.com/Masterminds/semver/v3" "testing" "time" + "github.com/Masterminds/semver/v3" + "go.uber.org/zap" "github.com/ethereum/go-ethereum/crypto" @@ -249,6 +250,8 @@ func TestSignStagedEnvelopeInvalidEnvelope(t *testing.T) { OriginatorTime: time.Now(), PayerEnvelope: []byte{0b1}, }, + 0, + 0, ) require.ErrorContains(t, err, "unmarshal") @@ -268,6 +271,8 @@ func TestSignStagedEnvelopeSuccess(t *testing.T) { OriginatorTime: time.Now(), PayerEnvelope: payerBytes, }, + 0, + 0, ) require.NoError(t, err) diff --git a/pkg/server/server.go b/pkg/server/server.go index 3022b540..22ba2ab8 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -3,14 +3,17 @@ package server import ( "context" "database/sql" - "github.com/xmtp/xmtpd/pkg/api/metadata" - "github.com/xmtp/xmtpd/pkg/proto/xmtpv4/metadata_api" "net" "os" "os/signal" "syscall" "time" + "github.com/xmtp/xmtpd/pkg/api/metadata" + "github.com/xmtp/xmtpd/pkg/currency" + "github.com/xmtp/xmtpd/pkg/fees" + "github.com/xmtp/xmtpd/pkg/proto/xmtpv4/metadata_api" + "github.com/Masterminds/semver/v3" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" @@ -194,6 +197,7 @@ func startAPIServer( writerDB, s.validationService, s.cursorUpdater, + getRatesFetcher(), ) if err != nil { return err @@ -329,3 +333,13 @@ func (s *ReplicationServer) Shutdown(timeout time.Duration) { s.cancel() } + +// TODO:nm Replace this with something that fetches rates from the blockchain +// Will need a rates smart contract first +func getRatesFetcher() fees.IRatesFetcher { + return fees.NewFixedRatesFetcher(&fees.Rates{ + MessageFee: currency.PicoDollar(100), + StorageFee: currency.PicoDollar(100), + CongestionFee: currency.PicoDollar(100), + }) +} diff --git a/pkg/testutils/api/api.go b/pkg/testutils/api/api.go index d782816b..b6c1c56c 100644 --- a/pkg/testutils/api/api.go +++ b/pkg/testutils/api/api.go @@ -23,6 +23,7 @@ import ( "github.com/xmtp/xmtpd/pkg/registrant" "github.com/xmtp/xmtpd/pkg/registry" "github.com/xmtp/xmtpd/pkg/testutils" + "github.com/xmtp/xmtpd/pkg/testutils/fees" "github.com/xmtp/xmtpd/pkg/utils" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -122,6 +123,8 @@ func NewTestAPIServer(t *testing.T) (*api.ApiServer, *sql.DB, ApiServerMocks, fu ) require.NoError(t, err) + ratesFetcher := fees.NewTestRatesFetcher() + serviceRegistrationFunc := func(grpcServer *grpc.Server) error { replicationService, err := message.NewReplicationApiService( ctx, @@ -130,6 +133,7 @@ func NewTestAPIServer(t *testing.T) (*api.ApiServer, *sql.DB, ApiServerMocks, fu db, mockValidationService, metadata.NewCursorUpdater(ctx, log, db), + ratesFetcher, ) require.NoError(t, err) message_api.RegisterReplicationApiServer(grpcServer, replicationService) diff --git a/pkg/testutils/fees/rates.go b/pkg/testutils/fees/rates.go new file mode 100644 index 00000000..820feff1 --- /dev/null +++ b/pkg/testutils/fees/rates.go @@ -0,0 +1,16 @@ +package fees + +import ( + "github.com/xmtp/xmtpd/pkg/currency" + "github.com/xmtp/xmtpd/pkg/fees" +) + +var TEST_RATES = &fees.Rates{ + MessageFee: currency.PicoDollar(100), + StorageFee: currency.PicoDollar(100), + CongestionFee: currency.PicoDollar(100), +} + +func NewTestRatesFetcher() *fees.FixedRatesFetcher { + return fees.NewFixedRatesFetcher(TEST_RATES) +}