Compare commits

...

21 Commits

Author SHA1 Message Date
Alfred Kamanda
74e5fb016c Merge branch 'master' into update-go-vise 2025-11-18 13:11:54 +03:00
0f3e084a53 Merge pull request 'credit-send-endpoints' (#19) from credit-send-endpoints into master
Reviewed-on: #19
2025-11-18 11:11:00 +01:00
Alfred Kamanda
fe897cca84 added the GetCreditSendReverseQuote to tests 2025-10-28 11:34:21 +03:00
Alfred Kamanda
7eaa771eb4 added the GetCreditSendReverseQuote function 2025-10-28 11:33:17 +03:00
Alfred Kamanda
72af514cf3 added the CreditSendReverseQouteResult type for API responses 2025-10-28 11:32:51 +03:00
Alfred Kamanda
81ff6c4034 added the CreditSendReverseQuote prefix and URL 2025-10-28 11:32:03 +03:00
Alfred Kamanda
a705443786 added a comment to describe the use of the TestAccountService 2025-10-28 11:10:48 +03:00
Alfred Kamanda
af76541c86 added the USD voucher to the TokenHoldings 2025-10-28 11:09:33 +03:00
Alfred Kamanda
75a7ec6b32 correct the spelling of toTokenAddress 2025-10-28 11:06:01 +03:00
Alfred Kamanda
3e82e16923 added the GetCreditSendMaxLimit to tests 2025-10-28 11:04:43 +03:00
Alfred Kamanda
c11060648d added the CreditSendLimitsResult type for the API responses 2025-10-28 11:04:12 +03:00
Alfred Kamanda
01569b9b39 added the GetCreditSendMaxLimit function 2025-10-28 11:03:08 +03:00
Alfred Kamanda
96c323f202 added the CreditSendPrefix and URL 2025-10-28 11:02:33 +03:00
2731a787e3 Merge pull request 'handle-error-codes' (#18) from handle-error-codes into master
Reviewed-on: #18 and is working on prod
2025-10-27 11:29:55 +01:00
Alfred Kamanda
532547899f include the error code 2025-10-22 11:46:13 +03:00
Alfred Kamanda
6f7802b58c modify doRequest() to return APIError on err 2025-10-21 15:05:22 +03:00
Alfred Kamanda
73e6220a8c create a custom error struct that carries both fields from the API 2025-10-21 15:02:36 +03:00
8d4fbb9c2e Merge pull request 'Normalize symbols before returning' (#17) from sanitize-symbols into master
Reviewed-on: #17

Merged after successful tests
2025-10-06 11:02:42 +02:00
Alfred Kamanda
61410b2b29 Normalize symbols before returning 2025-10-06 11:43:25 +03:00
Alfred Kamanda
3c8e3d1bc8 added the grassrootseconomics/go-vise package to sarafu-api 2025-08-19 12:43:50 +03:00
c44ac0116f Merge pull request 'update-alias' (#15) from update-alias into master
Reviewed-on: #15
2025-08-19 11:35:23 +02:00
10 changed files with 246 additions and 102 deletions

View File

@@ -7,25 +7,27 @@ import (
)
const (
createAccountPath = "/api/v2/account/create"
trackStatusPath = "/api/track"
balancePathPrefix = "/api/account"
trackPath = "/api/v2/account/status"
tokenTransferPrefix = "/api/v2/token/transfer"
voucherHoldingsPathPrefix = "/api/v1/holdings"
voucherTransfersPathPrefix = "/api/v1/transfers/last10"
voucherDataPathPrefix = "/api/v1/token"
SendSMSPrefix = "api/v1/external/upsell"
poolDepositPrefix = "/api/v2/pool/deposit"
poolSwapQoutePrefix = "/api/v2/pool/quote"
poolSwapPrefix = "/api/v2/pool/swap"
topPoolsPrefix = "/api/v1/pool/top"
retrievePoolDetailsPrefix = "/api/v1/pool/reverse"
poolSwappableVouchersPrefix = "/api/v1/pool"
AliasRegistrationPrefix = "/api/v1/internal/register"
AliasResolverPrefix = "/api/v1/resolve"
ExternalSMSPrefix = "/api/v1/external"
AliasUpdatePrefix = "/api/v1/internal/update"
createAccountPath = "/api/v2/account/create"
trackStatusPath = "/api/track"
balancePathPrefix = "/api/account"
trackPath = "/api/v2/account/status"
tokenTransferPrefix = "/api/v2/token/transfer"
voucherHoldingsPathPrefix = "/api/v1/holdings"
voucherTransfersPathPrefix = "/api/v1/transfers/last10"
voucherDataPathPrefix = "/api/v1/token"
SendSMSPrefix = "api/v1/external/upsell"
poolDepositPrefix = "/api/v2/pool/deposit"
poolSwapQoutePrefix = "/api/v2/pool/quote"
poolSwapPrefix = "/api/v2/pool/swap"
topPoolsPrefix = "/api/v1/pool/top"
retrievePoolDetailsPrefix = "/api/v1/pool/reverse"
poolSwappableVouchersPrefix = "/api/v1/pool"
AliasRegistrationPrefix = "/api/v1/internal/register"
AliasResolverPrefix = "/api/v1/resolve"
ExternalSMSPrefix = "/api/v1/external"
AliasUpdatePrefix = "/api/v1/internal/update"
CreditSendPrefix = "/api/v1/credit-send"
CreditSendReverseQuotePrefix = "/api/v1/pool/reverse-quote"
)
var (
@@ -38,25 +40,27 @@ var (
)
var (
CreateAccountURL string
TrackStatusURL string
BalanceURL string
TrackURL string
TokenTransferURL string
VoucherHoldingsURL string
VoucherTransfersURL string
VoucherDataURL string
PoolDepositURL string
PoolSwapQuoteURL string
PoolSwapURL string
TopPoolsURL string
RetrievePoolDetailsURL string
PoolSwappableVouchersURL string
SendSMSURL string
AliasRegistrationURL string
AliasResolverURL string
ExternalSMSURL string
AliasUpdateURL string
CreateAccountURL string
TrackStatusURL string
BalanceURL string
TrackURL string
TokenTransferURL string
VoucherHoldingsURL string
VoucherTransfersURL string
VoucherDataURL string
PoolDepositURL string
PoolSwapQuoteURL string
PoolSwapURL string
TopPoolsURL string
RetrievePoolDetailsURL string
PoolSwappableVouchersURL string
SendSMSURL string
AliasRegistrationURL string
AliasResolverURL string
ExternalSMSURL string
AliasUpdateURL string
CreditSendURL string
CreditSendReverseQuoteURL string
)
func setBase() error {
@@ -105,6 +109,8 @@ func LoadConfig() error {
AliasResolverURL, _ = url.JoinPath(aliasEnsURLBase, AliasResolverPrefix)
ExternalSMSURL, _ = url.JoinPath(externalSMSBase, ExternalSMSPrefix)
AliasUpdateURL, _ = url.JoinPath(aliasEnsURLBase, AliasUpdatePrefix)
CreditSendURL, _ = url.JoinPath(dataURLBase, CreditSendPrefix)
CreditSendReverseQuoteURL, _ = url.JoinPath(dataURLBase, CreditSendReverseQuotePrefix)
return nil
}

View File

@@ -12,18 +12,18 @@ import (
"strings"
"time"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/common/phone"
"git.grassecon.net/grassrootseconomics/sarafu-api/event"
"git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"github.com/gofrs/uuid"
"github.com/grassrootseconomics/go-vise/db"
slogging "github.com/grassrootseconomics/go-vise/slog"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
)
var (
logg = logging.NewVanilla().WithDomain("sarafu-api.devapi")
logg = slogging.Get().With("component", "sarafu-api.devapi")
aliasRegex = regexp.MustCompile("^\\+?[a-zA-Z0-9\\-_]+$")
searchDomain = ".sarafu.local"
)
@@ -587,10 +587,10 @@ func (das *DevAccountService) FetchVouchers(ctx context.Context, publicKey strin
//TODO: Iterate over the account acc.Balances object
for _, voucher := range das.vouchers {
holdings = append(holdings, dataserviceapi.TokenHoldings{
TokenAddress: voucher.Address,
TokenSymbol: voucher.Symbol,
TokenDecimals: strconv.Itoa(voucher.Decimals),
Balance: strconv.Itoa(int(defaultVoucherBalance)),
TokenAddress: voucher.Address,
TokenSymbol: voucher.Symbol,
TokenDecimals: strconv.Itoa(voucher.Decimals),
Balance: strconv.Itoa(int(defaultVoucherBalance)),
})
}
@@ -861,10 +861,10 @@ func (das *DevAccountService) GetPoolSwappableFromVouchers(ctx context.Context,
}
for _, v := range p.Vouchers {
swapFromList = append(swapFromList, dataserviceapi.TokenHoldings{
TokenAddress: v.Address,
TokenSymbol: v.Symbol,
TokenDecimals: string(defaultDecimals),
Balance: fmt.Sprintf("%f", defaultVoucherBalance),
TokenAddress: v.Address,
TokenSymbol: v.Symbol,
TokenDecimals: string(defaultDecimals),
Balance: fmt.Sprintf("%f", defaultVoucherBalance),
})
}
@@ -907,3 +907,17 @@ func (das *DevAccountService) CheckTokenInPool(ctx context.Context, poolAddress,
CanSwapFrom: true,
}, nil
}
func (das *DevAccountService) GetCreditSendMaxLimit(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, publicKey string) (*models.CreditSendLimitsResult, error) {
return &models.CreditSendLimitsResult{
MaxRAT: "45599996",
MaxSAT: "3507692",
}, nil
}
func (das *DevAccountService) GetCreditSendReverseQuote(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount string) (*models.CreditSendReverseQouteResult, error) {
return &models.CreditSendReverseQouteResult{
InputAmount: "3076923",
OutputAmount: "40000000",
}, nil
}

22
go.mod
View File

@@ -1,13 +1,15 @@
module git.grassecon.net/grassrootseconomics/sarafu-api
go 1.23.4
go 1.24
toolchain go1.24.6
require (
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250122123424-6749c632b0a2
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250819084006-5a9c82207578
github.com/gofrs/uuid v4.4.0+incompatible
github.com/grassrootseconomics/eth-custodial v1.3.0-beta
github.com/grassrootseconomics/go-vise v0.5.0
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta
github.com/stretchr/testify v1.9.0
)
@@ -15,22 +17,20 @@ require (
require (
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect
github.com/jackc/pgx/v5 v5.7.5 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect
github.com/leonelquinteros/gotext v1.7.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/text v0.27.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

52
go.sum
View File

@@ -1,41 +1,29 @@
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9 h1:sPcqXQcywxA8W3W+9qQncLPmsrgqTIlec7vmD4/7vyA=
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d h1:5mzLas+jxTUtusOKx4XvU+n2QvrV/mH17MnJRy46siQ=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60=
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250122123424-6749c632b0a2 h1:ON77G5K0JNuwPb5JT/hRfF6G6+xstlBQgEIEzWydnhg=
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250122123424-6749c632b0a2/go.mod h1:pjKp9L/ZsWW3kMB0UoIl1yv9TBIuU33mn9Aghxp7vGk=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250819084006-5a9c82207578 h1:GKhBMVbjGBus3eAp2tw3M66irOnEWWg0QEKVn0bBS8E=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250819084006-5a9c82207578/go.mod h1:hx6mjSyxKv5oxiJxB6EevJrMJIYjVoYxFEzBtpD+29c=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU=
github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo=
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta h1:fn1gwbWIwHVEBtUC2zi5OqTlfI/5gU1SMk0fgGixIXk=
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta/go.mod h1:omfI0QtUwIdpu9gMcUqLMCG8O1XWjqJGBx1qUMiGWC0=
github.com/grassrootseconomics/ussd-data-service v1.4.0-beta h1:4fMd/3h2ZIhRg4GdHQmRw5FfD3MpJvFNNJQo+Q27f5M=
github.com/grassrootseconomics/ussd-data-service v1.4.0-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI=
github.com/grassrootseconomics/ussd-data-service v1.4.4-beta h1:turlyo0i3OLj29mWpWNoB/3Qao8qEngT/5d1jDWTZE4=
github.com/grassrootseconomics/ussd-data-service v1.4.4-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI=
github.com/grassrootseconomics/ussd-data-service v1.4.7-beta h1:yAe1YaOBsdxW2m20jnVU4F0kLmFr+mK/gHCWEdHmE90=
github.com/grassrootseconomics/ussd-data-service v1.4.7-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI=
github.com/grassrootseconomics/ussd-data-service v1.5.0-beta h1:BSSQL/yPEvTVku9ja/ENZyZdwZkEaiTzzOUfg72bTy4=
github.com/grassrootseconomics/ussd-data-service v1.5.0-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI=
github.com/grassrootseconomics/go-vise v0.5.0 h1:FRg2de55Eb5SisrgTBeFWfWX+sXwp5q9r7YWtKWDwsk=
github.com/grassrootseconomics/go-vise v0.5.0/go.mod h1:b2/q4jfTu2i1wyUwYUu7FYq4m2f1AZv8MpiDM3ZcoGo=
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta h1:pY6zns6ifXyClRxP+JJaWrged3oRE7tTS2xaftF9clA=
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
@@ -44,10 +32,12 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk=
github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s=
github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A=
github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+YP7G1Mc=
github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8=
github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/pashagolub/pgxmock/v4 v4.7.0 h1:de2ORuFYyjwOQR7NBm57+321RnZxpYiuUjsmqRiqgh8=
github.com/pashagolub/pgxmock/v4 v4.7.0/go.mod h1:9L57pC193h2aKRHVyiiE817avasIPZnPwPlw3JczWvM=
github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVYH6rfNr9I=
github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljMorYBpqlvt3cS83U=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -64,17 +54,15 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 h1:8d9/fdTG0kn/B7NNGV1BsEyvektXFAbkMsTZS2sFSCc=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1/go.mod h1:X1WlGDeAFIYsW6GjgMm4VwUwZ2XjI7Zan2InxSUQWrU=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -20,3 +20,13 @@ type MaxLimitResult struct {
type TokenInPoolResult struct {
CanSwapFrom bool `json:"canSwapFrom"`
}
type CreditSendLimitsResult struct {
MaxRAT string `json:"maxRAT"`
MaxSAT string `json:"maxSAT"`
}
type CreditSendReverseQouteResult struct {
InputAmount string `json:"inputAmount"`
OutputAmount string `json:"outputAmount"`
}

View File

@@ -30,4 +30,6 @@ type AccountService interface {
PoolSwap(ctx context.Context, amount, from, fromTokenAddress, poolAddress, toTokenAddress string) (*models.PoolSwapResult, error)
GetSwapFromTokenMaxLimit(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, publicKey string) (*models.MaxLimitResult, error)
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)
}

View File

@@ -13,25 +13,50 @@ import (
"regexp"
"strings"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-api/config"
"git.grassecon.net/grassrootseconomics/sarafu-api/dev"
"git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"github.com/grassrootseconomics/eth-custodial/pkg/api"
slogging "github.com/grassrootseconomics/go-vise/slog"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
)
var (
aliasRegex = regexp.MustCompile("^\\+?[a-zA-Z0-9\\-_]+$")
logg = logging.NewVanilla().WithDomain("sarafu-api.devapi")
logg = slogging.Get().With("component", "sarafu-api.devapi")
)
type APIError struct {
Code string
Description string
}
func (e *APIError) Error() string {
if e.Code != "" {
return fmt.Sprintf("[%s] %s", e.Code, e.Description)
}
return e.Description
}
type HTTPAccountService struct {
SS storage.StorageService
UseApi bool
}
// symbolReplacements holds mappings of invalid symbols → valid ones
var symbolReplacements = map[string]string{
"USD₮": "USDT",
}
// sanitizeSymbol replaces known invalid token symbols with normalized ones
func sanitizeSymbol(symbol string) string {
if replacement, ok := symbolReplacements[symbol]; ok {
return replacement
}
return symbol
}
// Parameters:
// - trackingId: A unique identifier for the account.This should be obtained from a previous call to
// CreateAccount or a similar function that returns an AccountResponse. The `trackingId` field in the
@@ -130,6 +155,11 @@ func (as *HTTPAccountService) FetchVouchers(ctx context.Context, publicKey strin
return nil, err
}
// Normalize symbols before returning
for i := range r.Holdings {
r.Holdings[i].TokenSymbol = sanitizeSymbol(r.Holdings[i].TokenSymbol)
}
return r.Holdings, nil
}
@@ -156,6 +186,11 @@ func (as *HTTPAccountService) FetchTransactions(ctx context.Context, publicKey s
return nil, err
}
// Normalize symbols before returning
for i := range r.Transfers {
r.Transfers[i].TokenSymbol = sanitizeSymbol(r.Transfers[i].TokenSymbol)
}
return r.Transfers, nil
}
@@ -177,6 +212,9 @@ func (as *HTTPAccountService) VoucherData(ctx context.Context, address string) (
return nil, err
}
// Normalize symbols before returning
r.TokenDetails.TokenSymbol = sanitizeSymbol(r.TokenDetails.TokenSymbol)
_, err = doRequest(ctx, req, &r)
return &r.TokenDetails, err
}
@@ -367,7 +405,6 @@ func (as *HTTPAccountService) GetPoolSwappableFromVouchers(ctx context.Context,
svc := dev.NewDevAccountService(ctx, as.SS)
return svc.GetPoolSwappableFromVouchers(ctx, poolAddress, publicKey)
}
}
func (as *HTTPAccountService) getPoolSwappableFromVouchers(ctx context.Context, poolAddress, publicKey string) ([]dataserviceapi.TokenHoldings, error) {
@@ -383,6 +420,14 @@ func (as *HTTPAccountService) getPoolSwappableFromVouchers(ctx context.Context,
return nil, err
}
_, err = doRequest(ctx, req, &r)
if err != nil {
return nil, err
}
// Normalize symbols before returning
for i := range r.PoolSwappableVouchers {
r.PoolSwappableVouchers[i].TokenSymbol = sanitizeSymbol(r.PoolSwappableVouchers[i].TokenSymbol)
}
return r.PoolSwappableVouchers, nil
}
@@ -423,6 +468,15 @@ func (as HTTPAccountService) getPoolSwappableVouchers(ctx context.Context, poolA
}
_, err = doRequest(ctx, req, &r)
if err != nil {
return nil, err
}
// Normalize symbols before returning
for i := range r.PoolSwappableVouchers {
r.PoolSwappableVouchers[i].TokenSymbol = sanitizeSymbol(r.PoolSwappableVouchers[i].TokenSymbol)
}
return r.PoolSwappableVouchers, nil
}
@@ -463,10 +517,10 @@ func (as *HTTPAccountService) GetSwapFromTokenMaxLimit(ctx context.Context, pool
}
}
func (as *HTTPAccountService) getSwapFromTokenMaxLimit(ctx context.Context, poolAddress, fromTokenAddress, toTokeAddress, publicKey string) (*models.MaxLimitResult, error) {
func (as *HTTPAccountService) getSwapFromTokenMaxLimit(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, publicKey string) (*models.MaxLimitResult, error) {
var r models.MaxLimitResult
ep, err := url.JoinPath(config.PoolSwappableVouchersURL, poolAddress, "limit", fromTokenAddress, toTokeAddress, publicKey)
ep, err := url.JoinPath(config.PoolSwappableVouchersURL, poolAddress, "limit", fromTokenAddress, toTokenAddress, publicKey)
if err != nil {
return nil, err
}
@@ -688,6 +742,46 @@ func (as *HTTPAccountService) SendPINResetSMS(ctx context.Context, admin, phone
return nil
}
// GetCreditSendMaxLimit calls the API to check credit limits and return the maxRAT and maxSAT
func (as *HTTPAccountService) GetCreditSendMaxLimit(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, publicKey string) (*models.CreditSendLimitsResult, error) {
var r models.CreditSendLimitsResult
ep, err := url.JoinPath(config.CreditSendURL, poolAddress, fromTokenAddress, toTokenAddress, publicKey)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", ep, nil)
if err != nil {
return nil, err
}
_, err = doRequest(ctx, req, &r)
if err != nil {
return nil, err
}
return &r, nil
}
// GetCreditSendReverseQuote calls the API to getthe reverse quote for sending RAT amount
func (as *HTTPAccountService) GetCreditSendReverseQuote(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount string) (*models.CreditSendReverseQouteResult, error) {
var r models.CreditSendReverseQouteResult
ep, err := url.JoinPath(config.CreditSendReverseQuoteURL, poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", ep, nil)
if err != nil {
return nil, err
}
_, err = doRequest(ctx, req, &r)
if 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
@@ -720,7 +814,11 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons
if err := json.Unmarshal(body, &errResponse); err != nil {
return nil, err
}
return nil, errors.New(errResponse.Description)
return nil, &APIError{
Code: errResponse.ErrCode,
Description: errResponse.Description,
}
}
if err := json.Unmarshal(body, &okResponse); err != nil {
@@ -728,7 +826,7 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons
}
if len(okResponse.Result) == 0 {
return nil, errors.New("Empty api result")
return nil, errors.New("empty api result")
}
v, err := json.Marshal(okResponse.Result)

View File

@@ -3,13 +3,13 @@ package mocks
import (
"context"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-api/models"
slogging "github.com/grassrootseconomics/go-vise/slog"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
)
var (
logg = logging.NewVanilla().WithDomain("sarafu-vise-events.testutil")
logg = slogging.Get().With("component", "sarafu-vise-events.testutil")
)
const (

View File

@@ -120,3 +120,13 @@ func (m MockAccountService) CheckTokenInPool(ctx context.Context, poolAddress, t
args := m.Called(poolAddress, tokenAddress)
return args.Get(0).(*models.TokenInPoolResult), args.Error(1)
}
func (m MockAccountService) GetCreditSendMaxLimit(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, publicKey string) (*models.CreditSendLimitsResult, error) {
args := m.Called(poolAddress, fromTokenAddress, toTokenAddress, publicKey)
return args.Get(0).(*models.CreditSendLimitsResult), args.Error(1)
}
func (m MockAccountService) GetCreditSendReverseQuote(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount string) (*models.CreditSendReverseQouteResult, error) {
args := m.Called(poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount)
return args.Get(0).(*models.CreditSendReverseQouteResult), args.Error(1)
}

View File

@@ -8,6 +8,8 @@ import (
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
)
// This is used in the menu traversal tests
type TestAccountService struct {
}
@@ -34,12 +36,18 @@ func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey
func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) {
return []dataserviceapi.TokenHoldings{
dataserviceapi.TokenHoldings{
{
TokenAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee",
TokenSymbol: "SRF",
TokenDecimals: "6",
Balance: "2745987",
},
{
TokenAddress: "0x3f195a3F68BF4c6D49748eFa033a00C6634fF311",
TokenSymbol: "USD",
TokenDecimals: "6",
Balance: "4269100",
},
}, nil
}
@@ -116,3 +124,11 @@ func (m TestAccountService) GetSwapFromTokenMaxLimit(ctx context.Context, poolAd
func (m TestAccountService) CheckTokenInPool(ctx context.Context, poolAddress, tokenAddress string) (*models.TokenInPoolResult, error) {
return &models.TokenInPoolResult{}, nil
}
func (m TestAccountService) GetCreditSendMaxLimit(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, publicKey string) (*models.CreditSendLimitsResult, error) {
return &models.CreditSendLimitsResult{}, nil
}
func (m TestAccountService) GetCreditSendReverseQuote(ctx context.Context, poolAddress, fromTokenAddress, toTokenAddress, toTokenAMount string) (*models.CreditSendReverseQouteResult, error) {
return &models.CreditSendReverseQouteResult{}, nil
}