Skip to content
This repository was archived by the owner on Jul 1, 2024. It is now read-only.

Commit 6a86de4

Browse files
authored
Merge pull request #10 from oxygenpay/develop
merge: develop
2 parents 3dbe5f1 + 9dd0662 commit 6a86de4

File tree

22 files changed

+126
-71
lines changed

22 files changed

+126
-71
lines changed

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,37 @@
55
</p>
66

77
[OxygenPay](https://o2pay.co) is a cloud or self-hosted crypto payment gateway.
8-
Accept ETH, MATIC, TRON, and USDT with ease. Open new opportunities for your product by accepting cryptocurrency.
8+
Accept ETH, MATIC, TRON, USDT, and USDC with ease. Open new opportunities for your product by accepting cryptocurrency.
99

1010
<img src="./.github/static/demo.jpg" alt="demo">
1111

12+
## Supported Currencies 🔗
13+
14+
<table>
15+
<tr>
16+
<td align="center">
17+
<img src="./ui-dashboard/src/assets/icons/crypto/eth.svg" height="64" alt="eth">
18+
<div>Ethereum</div>
19+
</td>
20+
<td>
21+
<img src="./ui-dashboard/src/assets/icons/crypto/matic.svg" height="64" alt="matic">
22+
<div>Polygon</div>
23+
</td>
24+
<td align="center">
25+
<img src="./ui-dashboard/src/assets/icons/crypto/tron.svg" height="64" alt="tron">
26+
<div>TRON</div>
27+
</td>
28+
<td align="center">
29+
<img src="./ui-dashboard/src/assets/icons/crypto/usdt.svg" height="64" alt="usdt">
30+
<div>USDT</div>
31+
</td>
32+
<td align="center">
33+
<img src="./ui-dashboard/src/assets/icons/crypto/usdc.svg" height="64" alt="usdc">
34+
<div>USDC</div>
35+
</td>
36+
</tr>
37+
</table>
38+
1239
## Features ✨
1340

1441
- Self-hosted
@@ -29,7 +56,7 @@ Visit [docs.o2pay.co](https://docs.o2pay.co) for setup guides.
2956

3057
## Roadmap 🛣️
3158

32-
- [ ] Support for USDC
59+
- [x] Support for USDC
3360
- [ ] Support for Binance Smart Chain (BNB, BUSD)
3461
- [ ] Donations feature
3562
- [ ] Support for [WalletConnect](https://walletconnect.com/)

api/proto/merchant/v1/merchant.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ definitions:
4242
minItems: 1
4343
items:
4444
type: string
45-
enum: [ ETH, ETH_USDT, MATIC, MATIC_USDT, TRON, TRON_USDT ]
45+
example: ETH_USDT
4646

4747
UpdateMerchantRequest: *createMerchantRequest
4848

internal/service/blockchain/currencies.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@
2424
"minimal_withdrawal_amount_usd": "40",
2525
"minimal_instant_internal_transfer_amount_usd": "100"
2626
},
27+
{
28+
"blockchain": "ETH",
29+
"blockchainName": "Ethereum",
30+
"ticker": "ETH_USDC",
31+
"type": "token",
32+
"name": "USDC",
33+
"tokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
34+
"decimals": "6",
35+
"networkId": "1",
36+
"testNetworkId": "5",
37+
"minimal_withdrawal_amount_usd": "40",
38+
"minimal_instant_internal_transfer_amount_usd": "100"
39+
},
2740
{
2841
"blockchain": "MATIC",
2942
"blockchainName": "Polygon",
@@ -49,6 +62,19 @@
4962
"minimal_withdrawal_amount_usd": "10",
5063
"minimal_instant_internal_transfer_amount_usd": "30"
5164
},
65+
{
66+
"blockchain": "MATIC",
67+
"blockchainName": "Polygon",
68+
"ticker": "MATIC_USDC",
69+
"type": "token",
70+
"name": "USDC",
71+
"tokenAddress": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
72+
"decimals": "6",
73+
"networkId": "137",
74+
"testNetworkId": "80001",
75+
"minimal_withdrawal_amount_usd": "10",
76+
"minimal_instant_internal_transfer_amount_usd": "30"
77+
},
5278
{
5379
"blockchain": "TRON",
5480
"blockchainName": "Tron",

internal/service/blockchain/service_convertor.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ func (s *Service) GetExchangeRate(ctx context.Context, from, to string) (Exchang
7171

7272
switch convType {
7373
case ConversionTypeFiatToFiat, ConversionTypeCryptoToFiat:
74-
rate, at, err = s.getExchangeRate(ctx, normalizeTicker(to), normalizeTicker(from))
74+
rate, at, err = s.getExchangeRate(ctx, NormalizeTicker(to), NormalizeTicker(from))
7575
case ConversionTypeFiatToCrypto:
7676
// Tatum does not support USD to ETH, that's why we need to calculate ETH to USD and reverse it
77-
rate, at, err = s.getExchangeRate(ctx, normalizeTicker(from), normalizeTicker(to))
77+
rate, at, err = s.getExchangeRate(ctx, NormalizeTicker(from), NormalizeTicker(to))
7878
if err == nil {
7979
rate = 1 / rate
8080
}
@@ -336,9 +336,14 @@ func determineConversionType(from, to string) (ConversionType, error) {
336336
// e.g. ETH_USDT -> USDT
337337
var normalizations = map[string]string{
338338
"_USDT": "USDT",
339+
"_USDC": "USDC",
340+
"_BUSD": "BUSD",
339341
}
340342

341-
func normalizeTicker(ticker string) string {
343+
// NormalizeTicker normalizes fiat / crypto ticker for further usage in external services (e.g. Tatum).
344+
func NormalizeTicker(ticker string) string {
345+
ticker = strings.ToUpper(ticker)
346+
342347
for substr, replaced := range normalizations {
343348
if strings.Contains(ticker, substr) {
344349
return replaced

internal/service/blockchain/service_convertor_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ func TestConvertor(t *testing.T) {
2323
tatum.SetupRates(money.USD.String(), money.EUR, 0.91)
2424
tatum.SetupRates("ETH", money.USD, 1000)
2525
tatum.SetupRates("ETH_USDT", money.USD, 1)
26+
tatum.SetupRates("MATIC_USDC", money.USD, 1)
2627
tatum.SetupRates("TRON", money.USD, 0.07)
2728

2829
eth := lo.Must(conv.GetCurrencyByTicker("ETH"))
2930
ethUSDT := lo.Must(conv.GetCurrencyByTicker("ETH_USDT"))
31+
ethUSDC := lo.Must(conv.GetCurrencyByTicker("ETH_USDC"))
3032

3133
for _, tt := range []struct {
3234
from string
@@ -101,6 +103,17 @@ func TestConvertor(t *testing.T) {
101103
To: lo.Must(ethUSDT.MakeAmount("500_000_000")),
102104
},
103105
},
106+
{
107+
from: "USD",
108+
to: "ETH_USDC",
109+
amount: "200",
110+
expected: blockchain.Conversion{
111+
Type: blockchain.ConversionTypeFiatToCrypto,
112+
Rate: 1,
113+
From: lo.Must(money.USD.MakeAmount("200_00")),
114+
To: lo.Must(ethUSDC.MakeAmount("200_000_000")),
115+
},
116+
},
104117
{
105118
// case-insensitive
106119
from: "usd",

internal/test/mocks_tatum.go

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import (
44
"fmt"
55
"net/http"
66
"net/http/httptest"
7-
"strings"
87
"sync"
98
"time"
109

1110
"github.com/labstack/echo/v4"
1211
"github.com/oxygenpay/oxygen/internal/money"
1312
tatumprovider "github.com/oxygenpay/oxygen/internal/provider/tatum"
13+
"github.com/oxygenpay/oxygen/internal/service/blockchain"
1414
"github.com/oxygenpay/oxygen/internal/service/registry"
1515
"github.com/oxygenpay/tatum-sdk/tatum"
1616
"github.com/rs/zerolog"
@@ -53,7 +53,7 @@ func (m *TatumMock) SetupRates(from string, to money.FiatCurrency, rate float64)
5353
m.mu.Lock()
5454
defer m.mu.Unlock()
5555

56-
from = transformTicker(from)
56+
from = blockchain.NormalizeTicker(from)
5757

5858
if m.rates[from] == nil {
5959
m.rates[from] = make(map[string]float64, 0)
@@ -62,11 +62,11 @@ func (m *TatumMock) SetupRates(from string, to money.FiatCurrency, rate float64)
6262
m.rates[from][string(to)] = rate
6363
}
6464

65-
func (m *TatumMock) SetupSubscription(blockchain, address string, isTest bool, resultID string) {
65+
func (m *TatumMock) SetupSubscription(chain, address string, isTest bool, resultID string) {
6666
m.mu.Lock()
6767
defer m.mu.Unlock()
6868

69-
m.wallets[tatumSubKey(blockchain, address, isTest)] = resultID
69+
m.wallets[tatumSubKey(chain, address, isTest)] = resultID
7070
}
7171

7272
func (m *TatumMock) Clear() {
@@ -78,7 +78,7 @@ func (m *TatumMock) Clear() {
7878
}
7979

8080
func (m *TatumMock) ratesEndpoint(c echo.Context) error {
81-
from := transformTicker(c.Param("from"))
81+
from := blockchain.NormalizeTicker(c.Param("from"))
8282
to := c.QueryParam("basePair")
8383

8484
rate, exists := m.rates[from][to]
@@ -127,14 +127,6 @@ func (m *TatumMock) subscriptionEndpoint(c echo.Context) error {
127127
return c.JSON(http.StatusOK, tatumprovider.SubscriptionResponse{ID: id})
128128
}
129129

130-
func tatumSubKey(blockchain, address string, isTest bool) string {
131-
return fmt.Sprintf("%s/%s/is_test:%t", blockchain, address, isTest)
132-
}
133-
134-
func transformTicker(from string) string {
135-
if strings.Contains(from, "USDT") {
136-
from = "USDT"
137-
}
138-
139-
return from
130+
func tatumSubKey(chain, address string, isTest bool) string {
131+
return fmt.Sprintf("%s/%s/is_test:%t", chain, address, isTest)
140132
}

pkg/api-dashboard/v1/model/update_supported_payment_methods_request.go

Lines changed: 0 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)