Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
namnhce committed Oct 18, 2023
0 parents commit 02ebf5d
Show file tree
Hide file tree
Showing 11 changed files with 396 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# OS:-
.DS_Store

# Editors:-
.idea
.vscode

# Env:-
.env
.env.prod

# Dependencies:-
vendor
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Mochi SDK for Go

The Mochi SDK for Go is a library that provides easy access to the Mochi API from your Go applications. It simplifies the process of making API requests, handling authentication, and processing responses. Use this SDK to integrate Mochi's functionality into your Go projects effortlessly.

## Features

- [x] GetApplicationBalances: Retrieve token balances for your Mochi application.
- [x] RequestPayment: Request a payment from a user.
- [x] Transfer: Transfer tokens from your application to a list of user.

## Installation

To use the Mochi SDK in your Go project, you can simply install it using:

```bash
go get github.com/consolelabs/mochi-sdk
```


## Authorization
From MochiPay, you will receive an application ID, application name, and API key. You can use these to create a new MochiPay client. The client will be used to make requests to the Mochi API.
```go
config := &mochipay.Config{
ApplicationID: "<application-id>",
ApplicationName: "<application-name>",
APIKey: "<api-key>",
}
```

## Examples
Here's a simple example of how to use the YourAPI SDK:
### `GetApplicationBalances()`
```go
package main

import (
"fmt"

"github.com/consolelabs/mochi-go-sdk/mochipay"
)

func main() {
config := &mochipay.Config{
ApplicationID: "<application-id>",
ApplicationName: "<application-name>",
APIKey: "<api-key>",
}

client := mochipay.NewClient(config)
balances, err := client.GetApplicationBalances()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}

fmt.Println("Balances:")
for _, balance := range balances {
fmt.Printf("Token ID: %s, Amount: %s\n", balance.TokenID, balance.Amount)
}
}

```

27 changes: 27 additions & 0 deletions example/mochipay/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"fmt"

"github.com/consolelabs/mochi-go-sdk/mochipay"
)

func main() {
config := &mochipay.Config{
ApplicationID: "<application-id>",
ApplicationName: "<application-name>",
APIKey: "<api-key>",
}

client := mochipay.NewClient(config)
balances, err := client.GetApplicationBalances()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}

fmt.Println("Balances:")
for _, balance := range balances {
fmt.Printf("Token ID: %s, Amount: %s\n", balance.TokenID, balance.Amount)
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/consolelabs/mochi-go-sdk

go 1.20
57 changes: 57 additions & 0 deletions mochipay/application-balance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package mochipay

import (
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"time"
)

func (c *Client) GetApplicationBalances() ([]TokenBalance, error) {
client := &http.Client{}
requestURL := fmt.Sprintf("%s/api/v1/applications/%v/balances", c.cfg.BaseURL, c.cfg.ApplicationID)
request, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return nil, err
}

messageHeader := strconv.FormatInt(time.Now().Unix(), 10)
privateKey, err := hex.DecodeString(c.cfg.APIKey)
signature := ed25519.Sign(privateKey, []byte(messageHeader))

request.Header.Add("X-Message", messageHeader)
request.Header.Add("X-Application", c.cfg.ApplicationName)
request.Header.Add("X-Signature", hex.EncodeToString(signature))

resp, err := client.Do(request)
if err != nil {
return nil, err
}

defer resp.Body.Close()
resBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

if resp.StatusCode != http.StatusOK {
var errMsg ErrorMessage
if err := json.Unmarshal(resBody, &errMsg); err != nil {
return nil, errors.New("invalid decoded, error " + err.Error())
}
return nil, errors.New("invalid call, code " + strconv.Itoa(resp.StatusCode) + " " + errMsg.Msg)
}

var respData TokenBalanceResponses

if err := json.Unmarshal(resBody, &respData); err != nil {
return nil, errors.New("invalid decoded, error " + err.Error())
}

return respData.Data, nil
}
19 changes: 19 additions & 0 deletions mochipay/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package mochipay

type Client struct {
cfg *Config
}

func NewClient(cfg *Config) APIClient {
if cfg.BaseURL == "" {
if cfg.IsPreview {
cfg.BaseURL = DefaultPreviewBaseURL
} else {
cfg.BaseURL = DefaultProdBaseURL
}
}

return &Client{
cfg: cfg,
}
}
14 changes: 14 additions & 0 deletions mochipay/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package mochipay

const (
DefaultPreviewBaseURL = "https://api-preview.mochi-pay.console.so"
DefaultProdBaseURL = "https://api.mochi-pay.console.so"
)

type Config struct {
BaseURL string
ApplicationID string
ApplicationName string
APIKey string
IsPreview bool
}
7 changes: 7 additions & 0 deletions mochipay/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package mochipay

type APIClient interface {
GetApplicationBalances() ([]TokenBalance, error)
RequestPayment(req *PaymentRequest) error
Transfer(req *TransferRequest) ([]TransactionResult, error)
}
76 changes: 76 additions & 0 deletions mochipay/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package mochipay

import "time"

type ErrorMessage struct {
Msg string `json:"msg"`
}

type TokenBalanceResponses struct {
Data []TokenBalance `json:"data"`
}

type TokenBalance struct {
ID string `json:"id"`
ProfileID string `json:"profile_id"`
TokenID string `json:"token_id"`
Amount string `json:"amount"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Token Token `json:"token"`
}

type Token struct {
ID string `json:"id"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimal int `json:"decimal"`
ChainID string `json:"chain_id"`
Native bool `json:"native"`
Address string `json:"address"`
Icon string `json:"icon"`
CoinGeckoID string `json:"coin_gecko_id"`
Price float64 `json:"price"`
Chain Chain `json:"chain"`
}

type Chain struct {
ID string `json:"id"`
ChainID string `json:"chain_id"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Rpc string `json:"rpc"`
Explorer string `json:"explorer"`
Icon string `json:"icon"`
IsEvm bool `json:"is_evm"`
}

type PaymentRequest struct {
UserProfileID string `json:"user_profile_id"`
TokenAmount string `json:"token_amount"`
TokenID string `json:"token_id"`
Description string `json:"description"`
CallbackURL string `json:"callback_url"`
}

type TransactionResult struct {
Timestamp int64 `json:"timestamp"`
TransactionID int64 `json:"tx_id"`
RecipientID string `json:"recipient_id"`
Amount string `json:"amount"`
TransactionFee string `json:"tx_fee"`
Status string `json:"status"`
References string `json:"references"`
}

type TransactionResponse struct {
Data []TransactionResult `json:"data"`
}

type TransferRequest struct {
RecipientIDs []string `json:"recipient_ids"`
Amounts []string `json:"amounts"`
TokenID string `json:"token_id"`
References string `json:"references"`
Description string `json:"description"`
}
57 changes: 57 additions & 0 deletions mochipay/request-payment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package mochipay

import (
"bytes"
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"time"
)

func (c *Client) RequestPayment(req *PaymentRequest) error {
requestBody, err := json.Marshal(req)
if err != nil {
return err
}

var client = &http.Client{}
requestURL := fmt.Sprintf("%s/api/v1/applications/%v/requests", c.cfg.BaseURL, c.cfg.ApplicationID)
request, err := http.NewRequest(http.MethodPost, requestURL, bytes.NewBuffer(requestBody))
if err != nil {
return err
}

messageHeader := strconv.FormatInt(time.Now().Unix(), 10)
privateKey, err := hex.DecodeString(c.cfg.APIKey)
signature := ed25519.Sign(privateKey, []byte(messageHeader))

request.Header.Add("X-Message", messageHeader)
request.Header.Add("X-Application", c.cfg.ApplicationName)
request.Header.Add("X-Signature", hex.EncodeToString(signature))

resp, err := client.Do(request)
if err != nil {
return err
}

defer resp.Body.Close()
resBody, err := io.ReadAll(resp.Body)
if err != nil {
return err
}

if resp.StatusCode != http.StatusOK {
var errMsg ErrorMessage
if err := json.Unmarshal(resBody, &errMsg); err != nil {
return errors.New("invalid decoded, error " + err.Error())
}
return errors.New("invalid call, code " + strconv.Itoa(resp.StatusCode) + " " + errMsg.Msg)
}

return nil
}
Loading

0 comments on commit 02ebf5d

Please sign in to comment.