cryptopay

package module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2022 License: MIT Imports: 12 Imported by: 0

README

go-crypto-pay

Go

Crypto Pay is a payment system based on @CryptoBot, which allows you to accept payments in cryptocurrency using the API.

This library help you to work with Crypto Pay via Crypto Pay API.

Install

go get -u github.com/vitaliy-ukiru/go-cryptopay

Documentation

For start, you need to create your application and get an API token. Open @CryptoBot or @CryptoTestnetBot (for testnet), send a command /pay to create a new app and get API Token.

In this library, the high-level is the Client.
Internally, it calls the ApiCore methods, which is lower-level and is essentially a gateway for API requests. The Client methods, in addition to the usual errors, can return an api error (ApiError). If you want to check whether the received error is such, call the GetApiError function.

if apiErr := cryptopay.GetApiError(err); apiErr != nil {
// handling error of api. 
// apiErr is *ApiError
}

Configure NewClient

  • Token - token of you app.
  • ApiHost - url to api host. Default mainnet.
  • HttpClient - client for make requests. Default http.DefaultClient.
  • Webhook - webhook configure
    • OnError - handler for error handling in webhook.
    • DefaultHandler - set of default handlers. Default empty.

Networks in CryptoPay:

Net Bot Hostname Code reference
mainnet @CryptoBot https://pay.crypt.bot/ cryptopay.MainNetHost
testnet @CryptoTestnetBot https://testnet-pay.crypt.bot/ cryptopay.TestNetHost

Webhooks

To get started, send /pay command to bot, choose "My Apps", select application, open "Webhooks" and set your endpoint.

To work with webhooks, you need to start the server yourself and install Webhook.ServeHTTP as a handler to the endpoint. If you are running a "net/http" server, you can pass the Webhook as http.Handler type. But if you don't use std server, see the Adaptation section.

Examples

getMe
package main

import (
  "fmt"

  "github.com/vitaliy-ukiru/go-cryptopay"
)

func main() {
  client := cryptopay.NewClient(cryptopay.ClientSettings{
    Token:   "your_token_here",
    ApiHost: cryptopay.TestNetHost,
  })
  app, err := client.GetMe()
  if err != nil {
    panic(err)
  }
  fmt.Printf(
    "app_id=%d; name=%q; payment_bot=%q",
    app.Id,
    app.Name,
    app.PaymentBotUsername,
  )

}
transfer
package main

import (
	"fmt"
	"time"

	"github.com/vitaliy-ukiru/go-cryptopay"
)

func main() {
	client := cryptopay.NewClient(cryptopay.ClientSettings{
		Token: "your_token",
	})
	transfer, err := client.DoTransfer(-1, cryptopay.USDT, 100, "generate unique data", cryptopay.DoTransferOptions{
		Comment: "You winner!",
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("Transfer completed at %s", transfer.CompletedAt.Format(time.RFC850))
}
webhook
package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/vitaliy-ukiru/go-cryptopay"
)

func main() {
	client := cryptopay.NewClient(cryptopay.ClientSettings{
		Token: "your_token", // token required for webhooks, because using for verification updates
		Webhook: cryptopay.WebhookSettings{
			OnError: func(_ *http.Request, err error) {
				panic(err)
			},
		},
	})
	client.OnInvoicePaid(func(update *cryptopay.WebhookUpdate) {
		invoice := update.Payload
		fmt.Printf(
			"Invoice № %d for %s %s was paid on %s",
			invoice.Id,
			invoice.Amount,
			invoice.Asset,
			invoice.PaidAt.Format(time.RFC850))
	})
}

Webhook Adaptation

If you use other router you can adapt. For this you must create handler that call ServeHTTP method.

For gin-gonic/gin:

//  router is gin.Engine
router.POST("/path/", func (c *gin.Context) {
    webhook.ServerHTTP(http.ResponseWriter(c.Writer), c.Request)
})

For julienschmidt/httprouter:

// router is httprouter.Router.
router.POST("/path", func (w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    webhook.ServerHTTP(w, r)
})

For gorilla/mux

// router is mux.Router
router.Handle("/path", webhook)

Documentation

Index

Constants

View Source
const (
	MainNetHost = "https://pay.crypt.bot"
	TestNetHost = "https://testnet-pay.crypt.bot"
)

Aliases for officials hosts

Variables

View Source
var ErrorWrongSignature = fmt.Errorf("crypto-pay/webhook: %s", wrongSignature)

ErrorWrongSignature is returned if webhook don't verify update. For example, this can happen if someone who knows webhook's path endpoint and sends fake requests. Also, it could happen when request body was changed from outside.

If this happens, the update is not processed, but Webhook.OnError is called

Functions

This section is empty.

Types

type ApiCore

type ApiCore struct {
	// contains filtered or unexported fields
}

func NewApi

func NewApi(token, url string, httpClient *http.Client) *ApiCore

NewApi returns new ApiCore

func (ApiCore) CreateInvoice

func (c ApiCore) CreateInvoice(opt CreateInvoiceOptions) (*CreateInvoiceResponse, error)

CreateInvoice call api/createInvoice.

func (ApiCore) DoTransfer

func (c ApiCore) DoTransfer(opt DoTransferOptions) (*DoTransferResponse, error)

DoTransfer call api/transfer.

func (ApiCore) GetBalance

func (c ApiCore) GetBalance() (*GetBalanceResponse, error)

GetBalance call api/getBalance.

func (ApiCore) GetCurrencies

func (c ApiCore) GetCurrencies() (*GetCurrenciesResponse, error)

GetCurrencies call api/getCurrencies.

func (ApiCore) GetExchangeRates

func (c ApiCore) GetExchangeRates() (*GetExchangeRatesResponse, error)

GetExchangeRates call api/getExchangeRates.

func (ApiCore) GetInvoices

func (c ApiCore) GetInvoices(opt *GetInvoicesOptions) (*GetInvoicesResponse, error)

GetInvoices call api/getInvoices. Set opt as nil for empty API params.

func (ApiCore) GetMe

func (c ApiCore) GetMe() (*GetMeResponse, error)

GetMe call api/getMe.

type ApiError

type ApiError struct {
	Code int    `json:"code"` // HTTP Code of error.
	Name string `json:"name"` // Name of error.
}

ApiError is error of CryptoPay API.

func GetApiError

func GetApiError(err error) *ApiError

GetApiError retrieves the ApiError from given error. If unsuccessfully returns nil.

func (ApiError) Error

func (a ApiError) Error() string

type AppInfo

type AppInfo struct {
	Id                 int    `json:"app_id"`                          // ID of application.
	Name               string `json:"name"`                            // Name of application (sets on create app).
	PaymentBotUsername string `json:"payment_processing_bot_username"` // Telegram username of the bot that processing payments.
}

AppInfo basic information about an app.

type Asset

type Asset string

Asset is currency code.

const (
	BTC  Asset = "BTC"
	TON  Asset = "TON"
	ETH  Asset = "ETH"
	USDT Asset = "USDT"
	USDC Asset = "USDC"
	BUSD Asset = "BUSD"
)

func (Asset) String

func (a Asset) String() string

type BalanceCurrency

type BalanceCurrency struct {
	CurrencyCode Asset  `json:"currency_code"`
	Available    string `json:"available"` // Balance
}

BalanceCurrency contains information about available funds for a particular currency.

type BalanceInfo

type BalanceInfo []BalanceCurrency

BalanceInfo alias for slice of BalanceCurrency.

func (BalanceInfo) AsMap

func (b BalanceInfo) AsMap() map[Asset]string

AsMap returns transformed BalanceInfo ([]BalanceCurrency) into map, key - currency code (Asset), value - balance for Asset as string

func (BalanceInfo) AsMapFloat

func (b BalanceInfo) AsMapFloat() (map[Asset]float64, error)

AsMapFloat returns transformed BalanceInfo ([]BalanceCurrency) into map, key - currency code (Asset), value - balance for Asset as float64

type BaseApiResponse

type BaseApiResponse struct {
	// Ok indicates whether the request was successfully executed.
	Ok bool `json:"ok"`
	// Error from API, nil on successfully.
	Error *ApiError `json:"error,omitempty"`
}

BaseApiResponse is contained in all api responses .

func (BaseApiResponse) IsSuccessfully

func (r BaseApiResponse) IsSuccessfully() bool

IsSuccessfully indicates whether API request success.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is high-level API.

Methods that call API and return error can return ApiError. For get ApiError use GetApiError.

If you want set regular params in opt parameter - set regular parameters default value (empty string for Asset & string, 0 for numbers).

func NewClient

func NewClient(settings ClientSettings) *Client

NewClient returns new Client.

func (Client) Api

func (c Client) Api() ApiCore

Api return instance of ApiCore

func (*Client) CreateInvoice

func (c *Client) CreateInvoice(asset Asset, amount float64, opt CreateInvoiceOptions) (*Invoice, error)

CreateInvoice is representation for api/createInvoice.

func (*Client) DeleteAllHandlersFor

func (c *Client) DeleteAllHandlersFor(updateType UpdateType)

DeleteAllHandlersFor alias for Webhook.DeleteHandlers.

Delete all handlers for given update type. Also if update type is "*" reset handlers to empty value for EVERY UPDATE TYPE

func (*Client) DeleteHandler

func (c *Client) DeleteHandler(updateType UpdateType, i int)

func (*Client) DoTransfer

func (c *Client) DoTransfer(userId int, asset Asset, amount float64, spendId string, opt DoTransferOptions) (*Transfer, error)

DoTransfer is representation for api/transfer. Error regular or ApiError.

If you want set regular params in opt - set regular parameters default value (empty string for Asset & string, 0 for numbers) spendId must be unique for every operation.

func (*Client) GetBalance

func (c *Client) GetBalance() (BalanceInfo, error)

GetBalance is representation for api/getBalance.

func (*Client) GetCurrencies

func (c *Client) GetCurrencies() (CurrencyInfoArray, error)

GetCurrencies is representation for api/getCurrencies.

func (*Client) GetExchangeRates

func (c *Client) GetExchangeRates() (ExchangeRateArray, error)

GetExchangeRates is representation for api/getExchangeRates.

func (*Client) GetInvoices

func (c *Client) GetInvoices(opt *GetInvoicesOptions) ([]Invoice, error)

GetInvoices is representation for api/getInvoices. Set opt parameter as nil for empty API params.

func (*Client) GetMe

func (c *Client) GetMe() (*AppInfo, error)

GetMe is representation of api/getMe.

func (*Client) On

func (c *Client) On(updateType UpdateType, handler Handler) int

On alias for Webhook.Bind. Add handler to slice for given update type. Return index of new handler

func (*Client) OnInvoicePaid

func (c *Client) OnInvoicePaid(handler Handler) int

OnInvoicePaid is shortcut for Client.On with update type "invoice_paid".

func (*Client) Once

func (c *Client) Once(updateType UpdateType, handler Handler)

Once add handler that will call once.

func (Client) Webhook

func (c Client) Webhook() Webhook

Webhook return instance of Webhook

type ClientSettings

type ClientSettings struct {
	// Token of CryptoPay App.
	Token string
	// ApiHost url to api host. Default mainnet (MainNetHost).
	ApiHost string
	// HttpClient for make requests. Default http.DefaultClient.
	HttpClient *http.Client
	// Webhook settings. If set default value webhook can correct work.
	Webhook WebhookSettings
}

ClientSettings for easy configure NewClient.

type CreateInvoiceOptions

type CreateInvoiceOptions struct {
	Asset          Asset      // Currency code.
	Amount         string     // Amount of the invoice in float.
	Description    string     // Optional. Description for the invoice. User will see this description when they pay the invoice. Up to 1024 characters.
	HiddenMessage  string     // Optional. Text of the message that will be shown to a user after the invoice is paid. Up to 2o48 characters.
	PaidButtonName PaidButton // Optional. Name of the button that will be shown to a user after the invoice is paid.
	PaidButtonUrl  string     // Optional. Required if PaidButtonName is used. URL to be opened when the button is pressed. You can set any success link (for example, a link to your bot). Starts with https or http.
	Payload        string     // Optional. Any data you want to attach to the invoice (for example, user ID, payment ID, ect). Up to 4kb.
	AllowComments  bool       // Optional. Allow a user to add a comment to the payment. Default is true.
	AllowAnonymous bool       // Optional. Allow a user to pay the invoice anonymously. Default is true.
	ExpiresIn      int        // Optional. You can set a payment time limit for the invoice in seconds. Values between 1-2678400 are accepted
}

CreateInvoiceOptions for `createInvoice` api method.

func (CreateInvoiceOptions) QueryParams

func (opt CreateInvoiceOptions) QueryParams() string

QueryParams encode options to query params for `createInvoice` method.

type CreateInvoiceResponse

type CreateInvoiceResponse struct {
	BaseApiResponse
	Result *Invoice `json:"result,omitempty"`
}

CreateInvoiceResponse for `createInvoice` method

type CurrencyInfo

type CurrencyInfo struct {
	IsBlockchain bool   `json:"is_blockchain"` // Indicates what currency is crypto.
	IsStablecoin bool   `json:"is_stablecoin"` // Indicates what currency is stablecoin.
	IsFiat       bool   `json:"is_fiat"`       // Indicates what currency is fiat (real)
	Name         string `json:"name"`          // Name of currency
	Code         Asset  `json:"code"`          // Currency code
	Url          string `json:"url"`           // Url to currency homepage
	Decimals     int    `json:"decimals"`      // I don't know what is
}

type CurrencyInfoArray

type CurrencyInfoArray []CurrencyInfo

CurrencyInfoArray alias for slice of CurrencyInfo

func (CurrencyInfoArray) AsMap

func (c CurrencyInfoArray) AsMap() map[Asset]CurrencyInfo

AsMap returns transformed CurrencyInfoArray ([]CurrencyInfo) into map.

type DoTransferOptions

type DoTransferOptions struct {
	UserId                  int    // Telegram user ID. User must have previously used @CryptoBot (@CryptoTestnetBot for testnet).
	Asset                   Asset  // Currency code.
	Amount                  string // Amount of the invoice in float.
	SpendId                 string // Unique ID to make your request idempotent and ensure that only one of the transfers with the same spend_id will be accepted by Crypto Pay API. More https://telegra.ph/Crypto-Pay-API-11-25#transfer
	Comment                 string // Optional. Comment for the transfer. Users will see this comment when they receive a notification about the transfer. Up to 1024 symbols.
	DisableSendNotification bool   // Optional. Pass true if the user should not receive a notification about the transfer. Default is false.
}

DoTransferOptions for `transfer` (DoTransfer) api method.

func (DoTransferOptions) QueryParams

func (opt DoTransferOptions) QueryParams() string

QueryParams encode options to query params for `transfer` method.

type DoTransferResponse

type DoTransferResponse struct {
	BaseApiResponse
	Result *Transfer `json:"result,omitempty"`
}

DoTransferResponse for `transfer` method

type ErrorHandler

type ErrorHandler func(r *http.Request, err error)

ErrorHandler is signature of Webhook.OnError

type ExchangeRate

type ExchangeRate struct {
	IsValid bool   `json:"is_valid"` // Indicates valid exchange
	Source  Asset  `json:"source"`   // Source currency
	Target  Asset  `json:"target"`   // Target currency
	Rate    string `json:"rate"`     // Cost Target in Source currency
}

type ExchangeRateArray

type ExchangeRateArray []ExchangeRate

ExchangeRateArray alias for slice of ExchangeRate.

func (ExchangeRateArray) AsMap

func (e ExchangeRateArray) AsMap() map[RatesKey]ExchangeRate

AsMap returns transformed ExchangeRateArray ([]ExchangeRate) into map.

func (ExchangeRateArray) Get

func (e ExchangeRateArray) Get(source, target Asset) (string, bool)

Get returns exchange rate of target currency in source currency and the success indicator.

type GetBalanceResponse

type GetBalanceResponse struct {
	BaseApiResponse
	Result []BalanceCurrency `json:"result,omitempty"`
}

GetBalanceResponse for `getBalance` method

type GetCurrenciesResponse

type GetCurrenciesResponse struct {
	BaseApiResponse
	Result []CurrencyInfo `json:"result,omitempty"`
}

GetCurrenciesResponse for `getCurrencies` method

type GetExchangeRatesResponse

type GetExchangeRatesResponse struct {
	BaseApiResponse
	Result []ExchangeRate `json:"result,omitempty"`
}

GetExchangeRatesResponse for `getExchangeRates` method

type GetInvoicesOptions

type GetInvoicesOptions struct {
	Asset      Asset         // Currency code.
	InvoiceIds []string      // Optional. Invoice IDs
	Status     InvoiceStatus // Optional. Status of invoices to be returned. Defaults to all statuses.
	Offset     int           // Optional. Offset needed to return a specific subset of invoices. Default is 0.
	Count      int           // Optional. Number of invoices to be returned. Values between 1-1000 are accepted. Defaults to 100.
}

GetInvoicesOptions for `getInvoices` api method.

func (GetInvoicesOptions) QueryParams

func (opt GetInvoicesOptions) QueryParams() string

QueryParams encode options to query params for `getInvoices` method.

type GetInvoicesResponse

type GetInvoicesResponse struct {
	BaseApiResponse
	Result struct {
		Items []Invoice `json:"items"`
	} `json:"result,omitempty"`
}

GetInvoicesResponse for `getInvoices` method

type GetMeResponse

type GetMeResponse struct {
	BaseApiResponse
	Result *AppInfo `json:"result,omitempty"`
}

GetMeResponse for `getMe` method

type Handler

type Handler func(update *WebhookUpdate)

Handler is signature of handler for Webhook

type Invoice

type Invoice struct {
	Id              int           `json:"invoice_id"`                 // Unique ID for this invoice.
	Status          InvoiceStatus `json:"status"`                     // Status of the invoice, can be either .
	Hash            string        `json:"hash,omitempty"`             // Hash of the invoice.
	Asset           Asset         `json:"asset"`                      // Currency code.
	Amount          string        `json:"amount"`                     // Amount of the invoice.
	Fee             string        `json:"fee"`                        // Optional. Amount of charged service fees.
	PayUrl          string        `json:"pay_url,omitempty"`          // URL should be presented to the user to pay the invoice.
	CreatedAt       time.Time     `json:"created_at"`                 // Date the invoice was created in ISO 8601 format.
	USDRate         string        `json:"usd_rate"`                   // Optional. Price of the Asset in USD at the time the invoice was paid.
	AllowComments   bool          `json:"allow_comments,omitempty"`   // True, if the user can add comment to the payment.
	AllowAnonymous  bool          `json:"allow_anonymous,omitempty"`  // True, if the user can pay the invoice anonymously.
	PaidAt          time.Time     `json:"paid_at,omitempty"`          // Optional. Date the invoice was paid in Unix time.
	PaidAnonymously bool          `json:"paid_anonymously,omitempty"` // Optional. Text of the hidden message for this invoice.
	Description     string        `json:"description,omitempty"`      // Optional. Description for this invoice.
	ExpirationDate  string        `json:"expiration_date,omitempty"`  // Optional. Date the invoice expires in Unix time. (not timestamp)
	Comment         string        `json:"comment,omitempty"`          // Optional. Comment to the payment from the user.
	HiddenMessage   string        `json:"hidden_message,omitempty"`   // Optional. Text of the hidden message for this invoice.
	Payload         string        `json:"payload,omitempty"`          // Optional. Previously provided data for this invoice.
	PaidBtnName     PaidButton    `json:"paid_btn_name,omitempty"`    // Optional. Name of the button.
	PaidBtnUrl      string        `json:"paid_btn_url,omitempty"`     // Optional. URL of the button.
}

Invoice object.

type InvoiceStatus

type InvoiceStatus string

InvoiceStatus is status of the invoice.

const (
	StatusActive  InvoiceStatus = "active"
	StatusPaid    InvoiceStatus = "paid"
	StatusExpired InvoiceStatus = "expired"
)

func (InvoiceStatus) String

func (i InvoiceStatus) String() string

type PaidButton

type PaidButton string

PaidButton is name of the button that will be shown to a user after the invoice is paid.

const (
	ButtonViewItem    PaidButton = "viewItem"
	ButtonOpenChannel PaidButton = "openChannel"
	ButtonOpenBot     PaidButton = "openBot"
	ButtonCallback    PaidButton = "callback"
)

func (PaidButton) String

func (p PaidButton) String() string

type RatesKey

type RatesKey struct {
	Source Asset
	Target Asset
}

RatesKey is two-value key for ExchangeRateArray.

type Transfer

type Transfer struct {
	Id          int       `json:"transfer_id"`       // Unique ID for this transfer.
	UserId      int       `json:"user_id"`           // Telegram user ID the transfer was sent to.
	Asset       Asset     `json:"asset"`             // Currency code.
	Amount      string    `json:"amount"`            // Amount of the transfer.
	Status      string    `json:"status"`            // Status of the transfer, can be “completed”.
	CompletedAt time.Time `json:"completed_at"`      // Date the transfer was completed in ISO 8601 format.
	Comment     string    `json:"comment,omitempty"` // Optional. Comment for this transfer.
}

Transfer object

type UpdateType

type UpdateType string

UpdateType is type of webhook update.

const (
	// UpdateInvoicePaid update type, indicates that invoice was paid.
	UpdateInvoicePaid UpdateType = "invoice_paid"
)

type Webhook

type Webhook struct {

	// OnError handler for errors
	OnError ErrorHandler
	// contains filtered or unexported fields
}

Webhook representation http.Handler for works with CryptoPay updates

func NewWebhook

func NewWebhook(token string, defaultHandlers map[UpdateType][]Handler, onError ErrorHandler) *Webhook

NewWebhook returns new Webhook.

func (*Webhook) Bind

func (w *Webhook) Bind(updateType UpdateType, handler Handler) int

Bind add handler given update type. Returns handler index.

func (*Webhook) DeleteHandlerByIndex

func (w *Webhook) DeleteHandlerByIndex(updateType UpdateType, i int)

DeleteHandlerByIndex deletes handler given type and index.

func (*Webhook) DeleteHandlers

func (w *Webhook) DeleteHandlers(updateType UpdateType)

DeleteHandlers deletes all handlers given type. Also, can delete all handlers for all update types. If you want to delete all handlers for all types, then pass "*" as a parameter

func (Webhook) ServeHTTP

func (w Webhook) ServeHTTP(rw http.ResponseWriter, r *http.Request)

ServeHTTP implementing http.Handler.

Thanks to this, you can transmit a webhook as a handler for a "net/http" server. By recommended use this like as http.Handler parameter for function http.Handle.

If you use other router you can adapt. For this you must create handler that call this method. Examples of adapt see in README.md file

type WebhookSettings

type WebhookSettings struct {
	// OnError is handler for error in webhook.
	OnError func(r *http.Request, err error)
	// DefaultHandlers is set of default handlers. Default creates new set.
	DefaultHandlers map[UpdateType][]Handler
}

WebhookSettings for configure webhook in ClientSettings.

type WebhookUpdate

type WebhookUpdate struct {
	// Id is Non-unique update ID.
	Id int `json:"update_id"`
	// UpdateType is webhook update type.
	UpdateType UpdateType `json:"update_type"`
	// RequestDate is date the request was sent in ISO 8601 format.
	RequestDate time.Time `json:"request_date"`
	// Payload is base invoice information.
	Payload Invoice `json:"payload"`
}

WebhookUpdate is object of update from request body.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL