From dda1d0d9db4b72b309c44cb089cc793461f228cc Mon Sep 17 00:00:00 2001 From: Alfred Kamanda Date: Fri, 28 Nov 2025 09:42:35 +0300 Subject: [PATCH] added the MpesaTriggerOnramp function --- dev/api.go | 8 +++++ remote/account_service.go | 1 + remote/http/service.go | 41 +++++++++++++++++++++++++ testutil/mocks/service_mock.go | 5 +++ testutil/testservice/account_service.go | 4 +++ 5 files changed, 59 insertions(+) diff --git a/dev/api.go b/dev/api.go index 472c184..8e088c4 100644 --- a/dev/api.go +++ b/dev/api.go @@ -921,3 +921,11 @@ func (das *DevAccountService) GetCreditSendReverseQuote(ctx context.Context, poo OutputAmount: "40000000", }, nil } + +func (das *DevAccountService) MpesaTriggerOnramp(ctx context.Context, address, phoneNumber, asset string, amount int) (*models.MpesaOnrampResponse, error) { + return &models.MpesaOnrampResponse{ + Message: "Success, kindly accept prompt sent.", + Status: "PENDING", + TransactionCode: "ae6fb33b-4653-4f38-a3b6-85dfea7a1e99", + }, nil +} diff --git a/remote/account_service.go b/remote/account_service.go index 29286ba..0a0078c 100644 --- a/remote/account_service.go +++ b/remote/account_service.go @@ -32,4 +32,5 @@ type AccountService interface { CheckTokenInPool(ctx context.Context, poolAddress, tokenAddress string) (*models.TokenInPoolResult, error) GetCreditSendMaxLimit(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, publicKey string) (*models.CreditSendLimitsResult, error) GetCreditSendReverseQuote(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount string) (*models.CreditSendReverseQouteResult, error) + MpesaTriggerOnramp(ctx context.Context, address, phoneNumber, asset string, amount int) (*models.MpesaOnrampResponse, error) } diff --git a/remote/http/service.go b/remote/http/service.go index 7fe62ff..4bb8654 100644 --- a/remote/http/service.go +++ b/remote/http/service.go @@ -784,6 +784,47 @@ func (as *HTTPAccountService) GetCreditSendReverseQuote(ctx context.Context, poo return &r, nil } +// MpesaTriggerOnramp calls the API to perform an STK Push. +// Parameters: +// - address: The user's public key. +// - phoneNumber: The user's phone number +// - asset: the intented USD voucher "USDT | USDC | cUSD" +// - amount: The amount in Kenyan shillings +func (as *HTTPAccountService) MpesaTriggerOnramp(ctx context.Context, address, phoneNumber, asset string, amount int) (*models.MpesaOnrampResponse, error) { + var r models.MpesaOnrampResponse + + ctx = context.WithValue(ctx, ctxKeyAuthToken, config.MpesaOnrampBearerToken) + + // Prepare payload + payload := struct { + Address string `json:"address"` + PhoneNumber string `json:"phoneNumber"` + Asset string `json:"asset"` + Amount int `json:"amount"` + }{ + Address: strings.TrimSpace(address), + PhoneNumber: strings.TrimSpace(phoneNumber), + Asset: strings.TrimSpace(asset), + Amount: amount, + } + + payloadBytes, err := json.Marshal(payload) + if err != nil { + return nil, fmt.Errorf("failed to marshal mpesa onramp payload: %w", err) + } + + req, err := http.NewRequest("POST", config.MpesaOnrampURL, bytes.NewBuffer(payloadBytes)) + if err != nil { + return nil, err + } + + if _, err := doRequest(ctx, req, &r); err != nil { + return nil, err + } + + return &r, nil +} + // TODO: remove eth-custodial api dependency func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { var okResponse api.OKResponse diff --git a/testutil/mocks/service_mock.go b/testutil/mocks/service_mock.go index 6962bfb..4e8d7e6 100644 --- a/testutil/mocks/service_mock.go +++ b/testutil/mocks/service_mock.go @@ -130,3 +130,8 @@ func (m MockAccountService) GetCreditSendReverseQuote(ctx context.Context, poolA args := m.Called(poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount) return args.Get(0).(*models.CreditSendReverseQouteResult), args.Error(1) } + +func (m MockAccountService) MpesaTriggerOnramp(ctx context.Context, address, phoneNumber, asset string, amount int) (*models.MpesaOnrampResponse, error) { + args := m.Called(address, phoneNumber, asset, amount) + return args.Get(0).(*models.MpesaOnrampResponse), args.Error(1) +} diff --git a/testutil/testservice/account_service.go b/testutil/testservice/account_service.go index 7c0f320..c278ba1 100644 --- a/testutil/testservice/account_service.go +++ b/testutil/testservice/account_service.go @@ -132,3 +132,7 @@ func (m TestAccountService) GetCreditSendMaxLimit(ctx context.Context, poolAddre func (m TestAccountService) GetCreditSendReverseQuote(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount string) (*models.CreditSendReverseQouteResult, error) { return &models.CreditSendReverseQouteResult{}, nil } + +func (m TestAccountService) MpesaTriggerOnramp(ctx context.Context, address, phoneNumber, asset string, amount int) (*models.MpesaOnrampResponse, error) { + return &models.MpesaOnrampResponse{}, nil +}