Skip to content

Commit

Permalink
settlement added
Browse files Browse the repository at this point in the history
  • Loading branch information
TatarinovIgor committed Feb 14, 2024
1 parent a9cbb1f commit 187ec44
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 40 deletions.
51 changes: 45 additions & 6 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"birdhouse/modules/routing"
"birdhouse/modules/service"
"birdhouse/modules/storage"
stream_service "birdhouse/modules/stream-service"
"crypto/x509"
"encoding/pem"
"fmt"
Expand Down Expand Up @@ -41,6 +40,10 @@ func main() {
if appGUIDStr == "" {
log.Fatal("$PUBLIC_KEY env variable must be set")
}
privateKeyPath := os.Getenv("PRIVATE_KEY")
if appGUIDStr == "" {
log.Fatal("$PRIVATE_KEY env variable must be set")
}
tokenTimeToLiveStr := os.Getenv("TOKEN_TIME_TO_LIVE")
if tokenTimeToLiveStr == "" {
log.Fatal("$TOKEN_TIME_TO_LIVE env variable must be set")
Expand All @@ -65,6 +68,35 @@ func main() {
if walletKey == "" {
log.Fatal("$WALLET_KEY env variable must be set")
}

appGUID, err := uuid.Parse(appGUIDStr)
if err != nil {
log.Fatalf("incorrect $APP_GUID env variable: %s, error: %v", appGUIDStr, err)
}
systemWallet := os.Getenv("SYSTEM_WALLET")
if systemWallet == "" {
log.Fatal("$SYSTEM_WALLET env variable must be set")
}
systemWalletSeed := os.Getenv("SYSTEM_WALLET_SEED")
if systemWalletSeed == "" {
log.Fatal("$SYSTEM_WALLET_SEED env variable must be set")
}
tokenCode := os.Getenv("TOKEN_CODE")
if tokenCode == "" {
log.Fatal("$TOKEN_CODE env variable must be set")
}
tokenBlockchain := os.Getenv("TOKEN_BLOCKCHAIN")
if tokenBlockchain == "" {
log.Fatal("$TOKEN_BLOCKCHAIN env variable must be set")
}
tokenIssuer := os.Getenv("TOKEN_ISSUER")
if tokenIssuer == "" {
log.Fatal("$TOKEN_ISSUER env variable must be set")
}
processorUrl := os.Getenv("PROCESSOR_URL")
if processorUrl == "" {
log.Fatal("$PROCESSOR_URL env variable must be set")
}
publicKey, err := os.ReadFile(publicKeyPath)
if err != nil {
log.Fatalf("could not read public key: %s, error: %v", publicKey, err)
Expand All @@ -74,11 +106,18 @@ func main() {
if err != nil {
log.Fatalf("could not parse public key env variable: %s, error: %v", publicKey, err)
}
appGUID, err := uuid.Parse(appGUIDStr)
privateKey, err := os.ReadFile(privateKeyPath)
if err != nil {
log.Fatalf("incorrect $APP_GUID env variable: %s, error: %v", appGUIDStr, err)
log.Fatalf("could not read private key: %s, error: %v", privateKeyPath, err)
}
block, _ = pem.Decode(privateKey)
if block == nil {
panic("failed to parse PEM block containing the private key")
}
private, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
log.Fatalf("could not parse private key env variable: %s, error: %v", privateKeyPath, err)
}

//bot, err := tgbotapi.NewBotAPI(telegramBotToken)
if err != nil {
log.Panic(err)
Expand All @@ -90,7 +129,7 @@ func main() {
log.Fatalf("could not make store for Wallets, error: %v", err)
}

atWalletService := service.NewATWalletService(basePath, seed, pub, appGUID, tokenTimeToLive, store)
atWalletService := service.NewATWalletService(basePath, seed, systemWallet, systemWalletSeed, tokenCode, tokenBlockchain, tokenIssuer, processorUrl, pub, private, appGUID, tokenTimeToLive, store)
//telegramService := telegramservice.NewTelegramService(bot, atWalletService, walletUrl, walletKey)

//db := internal.DBConnect()
Expand All @@ -116,7 +155,7 @@ func main() {
{
g.Add(func() error {
fmt.Println("stream service starting")
stream_service.ListenAndServe()
atWalletService.ListenAndServe()
return nil
}, func(err error) {
fmt.Println("stream service stopping")
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ require (
github.com/BurntSushi/toml v1.2.1
github.com/go-openapi/runtime v0.24.1
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
github.com/golang-jwt/jwt v3.2.1+incompatible
github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/uuid v1.3.0
github.com/julienschmidt/httprouter v1.3.0
github.com/lestrrat-go/jwx v1.2.25
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/V
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
Expand Down
150 changes: 146 additions & 4 deletions modules/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"github.com/BurntSushi/toml"
encoder "github.com/golang-jwt/jwt"
"github.com/google/uuid"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwt"
Expand All @@ -22,17 +23,151 @@ import (
"math/rand"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)

type ATWalletService struct {
baseWalletURL string
requestPublicKey interface{}
privateKey interface{}
appGUID uuid.UUID
tokenTimeToLive int64
seed string
store *storage.KeysPSQL
systemWallet string
systemWalletSeed string

tokenCode string
tokenBlockchain string
tokenIssuer string
processorUrl string
}

type TokenPayload struct {
ExternalId string `json:"external_id"`
MerchantID string `json:"merchant_id"`
}

type MintData struct {
Code string `json:"code"`
Blockchain string `json:"blockchain"`
Amount string `json:"amount"`
Issuer string `json:"issuer"`
}

type MintTokenResponse struct {
Issuer string
TxHash string
}

func (service ATWalletService) CreateToken(externalID, merchantID string) (string, error) {
token := encoder.New(encoder.SigningMethodRS256)
var tokenToSend TokenPayload
tokenToSend.MerchantID = merchantID
tokenToSend.ExternalId = externalID
claims := token.Claims.(encoder.MapClaims)
claims["exp"] = time.Now().Add(10 * time.Minute).Unix()
claims["payload"] = tokenToSend
tokenString, err := token.SignedString(service.privateKey)
if err != nil {
return "", err
}
return tokenString, nil
}

func (service ATWalletService) MintTokensOnProcessing(externalID, merchantID, amount string) error {
token, err := service.CreateToken(externalID, merchantID)
if err != nil {
return err
}
var mintData = MintData{Code: service.tokenCode, Blockchain: service.tokenBlockchain, Amount: amount, Issuer: service.tokenIssuer}
mintDataParsed, err := json.Marshal(mintData)
r, err := http.NewRequest("POST", service.processorUrl, bytes.NewBuffer(mintDataParsed))
if err != nil {
return err
}

r.Header.Add("Content-Type", "application/json")
r.Header.Add("Authorization", token)

client := &http.Client{}
res, err := client.Do(r)
if err != nil {
return err
}

defer res.Body.Close()
var responseMint MintTokenResponse
err = json.NewDecoder(res.Body).Decode(&responseMint)
if err != nil {
return err
}
if res.StatusCode != http.StatusCreated {
return err
}
log.Println(responseMint.TxHash, responseMint.Issuer)
return nil
}

func (service ATWalletService) ProcessDeposit(Seed, Issuer, Code, externalID, merchantID string, amount float64) error {
stellarTransactionText, err := service.BuildStellarTransactionText(Seed, Issuer, Code, service.systemWallet, "", amount)
if err != nil {
return err
}
log.Println(stellarTransactionText)
strAmount := fmt.Sprintf("%f", amount)
err = service.MintTokensOnProcessing(externalID, merchantID, strAmount)
if err != nil {
return err
}
return nil
}
func (service ATWalletService) ListenAndServe() {
ticker := time.NewTicker(time.Second * 1)
next := int64(0)
for {
select {
case <-ticker.C:
records, err := service.store.GetNext(next, 1)
if err != nil || len(records) == 0 {
next = 0
if err != nil {
log.Println("Error while getting DB records:", err)
}
} else if strings.Contains(records[0].ExternalID, records[0].MerchantID) {
next = records[0].ID
continue
} else {
record := records[len(records)-1]
accountRequest := horizonclient.AccountRequest{AccountID: record.Key}
client := horizonclient.DefaultTestNetClient

account, err := client.AccountDetail(accountRequest)
if err != nil {
return
}
for i := 0; i < len(account.Balances); i++ {
if account.Balances[i].Code == "ATUSD" {
log.Println("Account has:", account.Balances[i].Balance)
wallet := Wallet{}
err = json.Unmarshal(record.Data, &wallet)
if err != nil {
log.Println("Unable to parse wallet for processing, err:", err)
}
parsedBalance, err := strconv.ParseFloat(account.Balances[i].Balance, 64)
if err != nil {
log.Println("Unable to parse wallet for processing, err:", err)
}
service.ProcessDeposit(wallet.WalletSeed, account.Balances[i].Issuer, account.Balances[i].Code, record.ExternalID, record.MerchantID, parsedBalance)

}
}
next = record.ID
}
}
}
}

func (service ATWalletService) SignUp(token string) (*AuthResponse, error) {
Expand Down Expand Up @@ -194,7 +329,7 @@ func (service ATWalletService) Withdraw(jwtToken, token, assetCode, asseIssuer,
return nil, err
}

_, err = service.BuildStellarTransactionText(service.seed, asseIssuer, depositResponse.StellarAccountID, memo, amount)
_, err = service.BuildStellarTransactionText(service.seed, asseIssuer, assetCode, depositResponse.StellarAccountID, memo, amount)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -247,7 +382,7 @@ func (service ATWalletService) GetBalance(jwtToken, token string) (*UserPlatform
return &userPlatformResponse, nil
}

func NewATWalletService(baseWalletURL, seed string, requestPublicKey interface{}, appGUID uuid.UUID, tokenTimeToLive int64, store *storage.KeysPSQL) *ATWalletService {
func NewATWalletService(baseWalletURL, seed, systemWallet, systemWalletSeed, tokenCode, tokenBlockchain, tokenIssuer, processorUrl string, requestPublicKey interface{}, privateKey interface{}, appGUID uuid.UUID, tokenTimeToLive int64, store *storage.KeysPSQL) *ATWalletService {

return &ATWalletService{
baseWalletURL: baseWalletURL,
Expand All @@ -256,6 +391,13 @@ func NewATWalletService(baseWalletURL, seed string, requestPublicKey interface{}
tokenTimeToLive: tokenTimeToLive,
seed: seed,
store: store,
systemWallet: systemWallet,
systemWalletSeed: systemWalletSeed,
tokenCode: tokenCode,
tokenBlockchain: tokenBlockchain,
tokenIssuer: tokenIssuer,
privateKey: privateKey,
processorUrl: processorUrl,
}
}

Expand Down Expand Up @@ -367,7 +509,7 @@ func (service ATWalletService) BuildStellarTransactionHash(addressOrSeed, assetI
return nil, nil
}

func (service ATWalletService) BuildStellarTransactionText(addressOrSeed, assetIssuer, destination, memo string, amount float64) (io.ReadCloser, error) {
func (service ATWalletService) BuildStellarTransactionText(addressOrSeed, assetIssuer, Code, destination, memo string, amount float64) (io.ReadCloser, error) {
kp, err := keypair.Parse(addressOrSeed)
if err != nil {
return nil, fmt.Errorf("can't parse sender key, error: %v", err)
Expand All @@ -381,7 +523,7 @@ func (service ATWalletService) BuildStellarTransactionText(addressOrSeed, assetI
op := stellar.Payment{
Destination: destination,
Amount: fmt.Sprintf("%f", amount),
Asset: stellar.CreditAsset{Code: "ATUSD", Issuer: assetIssuer},
Asset: stellar.CreditAsset{Code: Code, Issuer: assetIssuer},
SourceAccount: sourceAccount.AccountID,
}
tx, err := stellar.NewTransaction(
Expand Down
1 change: 0 additions & 1 deletion modules/stream-service/contract.go

This file was deleted.

29 changes: 0 additions & 29 deletions modules/stream-service/service.go

This file was deleted.

0 comments on commit 187ec44

Please sign in to comment.