Skip to content

Commit

Permalink
feat: add nowpayments gateway (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
b00f authored Feb 15, 2024
1 parent a8d5e12 commit 3e60e5f
Show file tree
Hide file tree
Showing 19 changed files with 562 additions and 171 deletions.
9 changes: 7 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ DISCORD_TOKEN=
DISCORD_GUILD_ID=
TWITTER_BEARER_TOKEN=
TWITTER_ID=
TURBOSWAP_API_TOKEN=
TURBOSWAP_URL=
AUTHORIZED_DISCORD_IDS=
NOWPAYMENTS_LISTEN_PORT=50055
NOWPAYMENTS_WEBHOOK=
NOWPAYMENTS_API_URL=https://api-sandbox.nowpayments.io
NOWPAYMENTS_API_KEY=
NOWPAYMENTS_IPN_SECRET=
NOWPAYMENTS_USERNAME=
NOWPAYMENTS_PASSWORD=
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ mock:
mockgen -source=./wallet/interface.go -destination=./wallet/mock.go -package=wallet
mockgen -source=./store/interface.go -destination=./store/mock.go -package=store
mockgen -source=./twitter_api/interface.go -destination=./twitter_api/mock.go -package=twitter_api
mockgen -source=./turboswap/interface.go -destination=./turboswap/mock.go -package=turboswap
mockgen -source=./nowpayments/interface.go -destination=./nowpayments/mock.go -package=nowpayments

### Formatting, linting, and vetting
fmt:
gofumpt -l -w .
go mod tidy

check:
golangci-lint run --build-tags "${BUILD_TAG}" --timeout=20m0s

Expand Down
37 changes: 19 additions & 18 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,21 @@ import (
"strings"

"github.com/joho/godotenv"
"github.com/kehiy/RoboPac/nowpayments"
"github.com/pactus-project/pactus/util"
)

type Config struct {
Network string
WalletAddress string
WalletPath string
WalletPassword string
NetworkNodes []string
LocalNode string
StorePath string
DiscordBotCfg DiscordBotConfig
TwitterAPICfg TwitterAPIConfig
TurboswapConfig TurboswapConfig
}

type TurboswapConfig struct {
APIToken string
URL string
Network string
WalletAddress string
WalletPath string
WalletPassword string
NetworkNodes []string
LocalNode string
StorePath string
DiscordBotCfg DiscordBotConfig
TwitterAPICfg TwitterAPIConfig
NowPaymentsConfig nowpayments.Config
}

type TwitterAPIConfig struct {
Expand Down Expand Up @@ -60,9 +56,14 @@ func Load(filePaths ...string) (*Config, error) {
BearerToken: os.Getenv("TWITTER_BEARER_TOKEN"),
TwitterID: os.Getenv("TWITTER_ID"),
},
TurboswapConfig: TurboswapConfig{
APIToken: os.Getenv("TURBOSWAP_API_TOKEN"),
URL: os.Getenv("TURBOSWAP_URL"),
NowPaymentsConfig: nowpayments.Config{
ListenPort: os.Getenv("NOWPAYMENTS_LISTEN_PORT"),
Webhook: os.Getenv("NOWPAYMENTS_WEBHOOK"),
APIToken: os.Getenv("NOWPAYMENTS_API_KEY"),
APIUrl: os.Getenv("NOWPAYMENTS_API_URL"),
IPNSecret: os.Getenv("NOWPAYMENTS_IPN_SECRET"),
Username: os.Getenv("NOWPAYMENTS_USERNAME"),
Password: os.Getenv("NOWPAYMENTS_PASSWORD"),
},
}

Expand Down
36 changes: 18 additions & 18 deletions discord/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ var commands = []*discordgo.ApplicationCommand{
Description: "TestNet reward claim status",
},
{
Name: "twitter-campaign",
Description: "Get Twitter campaign discount code",
Name: "booster-payment",
Description: "Create payment link in Validator Booster Program",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Expand All @@ -118,8 +118,8 @@ var commands = []*discordgo.ApplicationCommand{
},
},
{
Name: "twitter-campaign-status",
Description: "Status of Twitter campaign",
Name: "booster-claim",
Description: "Claim the stake PAC coin in Validator Booster Program",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Expand All @@ -130,8 +130,8 @@ var commands = []*discordgo.ApplicationCommand{
},
},
{
Name: "twitter-campaign-whitelist",
Description: "Whitelist a non-active Twitter account for Twitter campaign",
Name: "booster-whitelist",
Description: "Whitelist a non-active Twitter account in Validator Booster Program",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Expand All @@ -144,16 +144,16 @@ var commands = []*discordgo.ApplicationCommand{
}

var commandHandlers = map[string]func(*DiscordBot, *discordgo.Session, *discordgo.InteractionCreate){
"help": helpCommandHandler,
"claim": claimCommandHandler,
"claimer-info": claimerInfoCommandHandler,
"node-info": nodeInfoCommandHandler,
"network-health": networkHealthCommandHandler,
"network-status": networkStatusCommandHandler,
"wallet": walletCommandHandler,
"claim-status": claimStatusCommandHandler,
"reward-calc": rewardCalcCommandHandler,
"twitter-campaign": twitterCampaignCommandHandler,
"twitter-campaign-status": twitterCampaignStatusCommandHandler,
"twitter-campaign-whitelist": twitterCampaignWhitelistCommandHandler,
"help": helpCommandHandler,
"claim": claimCommandHandler,
"claimer-info": claimerInfoCommandHandler,
"node-info": nodeInfoCommandHandler,
"network-health": networkHealthCommandHandler,
"network-status": networkStatusCommandHandler,
"wallet": walletCommandHandler,
"claim-status": claimStatusCommandHandler,
"reward-calc": rewardCalcCommandHandler,
"booster-payment": boosterPaymentCommandHandler,
"booster-claim": boosterClaimCommandHandler,
"booster-whitelist": boosterWhitelistCommandHandler,
}
8 changes: 4 additions & 4 deletions discord/embeds.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ func helpEmbed(s *discordgo.Session) *discordgo.MessageEmbed {
"```/network-status``` Shows a brief info about network.\n" +
"```/network-health``` Check and shows network health status.\n" +
"```/wallet``` Shows RoboPac wallet address and balance.\n" +
"```/twitter-campaign``` Get discount code on Twitter Campaign.\n" +
"```/twitter-campaign-status``` Check the status of Twitter Campaign.\n",
"```/booster-payment``` Create payment link in Validator Booster Program.\n" +
"```/booster-claim``` Claim the stake PAC coin in Validator Booster Program.\n",
Color: PACTUS,
}
}
Expand Down Expand Up @@ -93,9 +93,9 @@ func rewardCalcEmbed(s *discordgo.Session, i *discordgo.InteractionCreate, resul
}
}

func twitterCampaignEmbed(s *discordgo.Session, i *discordgo.InteractionCreate, result string) *discordgo.MessageEmbed {
func boosterEmbed(s *discordgo.Session, i *discordgo.InteractionCreate, result string) *discordgo.MessageEmbed {
return &discordgo.MessageEmbed{
Title: "Twitter(X) Campaign 𝕏",
Title: "Pactus Validator Booster Program ✨",
Description: result,
Color: PACTUS,
}
Expand Down
18 changes: 9 additions & 9 deletions discord/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,54 +182,54 @@ func rewardCalcCommandHandler(db *DiscordBot, s *discordgo.Session, i *discordgo
db.respondEmbed(embed, s, i)
}

func twitterCampaignCommandHandler(db *DiscordBot, s *discordgo.Session, i *discordgo.InteractionCreate) {
func boosterPaymentCommandHandler(db *DiscordBot, s *discordgo.Session, i *discordgo.InteractionCreate) {
if !checkMessage(i, s, db.GuildID, i.Member.User.ID) {
return
}

twitterName := i.ApplicationCommandData().Options[0].StringValue()
valAddr := i.ApplicationCommandData().Options[1].StringValue()

result, err := db.BotEngine.Run(fmt.Sprintf("twitter-campaign %v %v %v", i.Member.User.ID, twitterName, valAddr))
result, err := db.BotEngine.Run(fmt.Sprintf("booster-payment %v %v %v", i.Member.User.ID, twitterName, valAddr))
if err != nil {
db.respondErrMsg(err, s, i)
return
}

embed := twitterCampaignEmbed(s, i, result)
embed := boosterEmbed(s, i, result)
db.respondEmbed(embed, s, i)
}

func twitterCampaignStatusCommandHandler(db *DiscordBot, s *discordgo.Session, i *discordgo.InteractionCreate) {
func boosterClaimCommandHandler(db *DiscordBot, s *discordgo.Session, i *discordgo.InteractionCreate) {
if !checkMessage(i, s, db.GuildID, i.Member.User.ID) {
return
}

twitterID := i.ApplicationCommandData().Options[0].StringValue()

result, err := db.BotEngine.Run(fmt.Sprintf("twitter-campaign-status %v", twitterID))
result, err := db.BotEngine.Run(fmt.Sprintf("booster-payment-claim %v", twitterID))
if err != nil {
db.respondErrMsg(err, s, i)
return
}

embed := twitterCampaignEmbed(s, i, result)
embed := boosterEmbed(s, i, result)
db.respondEmbed(embed, s, i)
}

func twitterCampaignWhitelistCommandHandler(db *DiscordBot, s *discordgo.Session, i *discordgo.InteractionCreate) {
func boosterWhitelistCommandHandler(db *DiscordBot, s *discordgo.Session, i *discordgo.InteractionCreate) {
if !checkMessage(i, s, db.GuildID, i.Member.User.ID) {
return
}

twitterName := i.ApplicationCommandData().Options[0].StringValue()

result, err := db.BotEngine.Run(fmt.Sprintf("twitter-campaign-whitelist %v %v", twitterName, i.Member.User.ID))
result, err := db.BotEngine.Run(fmt.Sprintf("booster-payment-whitelist %v %v", twitterName, i.Member.User.ID))
if err != nil {
db.respondErrMsg(err, s, i)
return
}

embed := twitterCampaignEmbed(s, i, result)
embed := boosterEmbed(s, i, result)
db.respondEmbed(embed, s, i)
}
71 changes: 48 additions & 23 deletions engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,28 @@ import (
"github.com/kehiy/RoboPac/client"
"github.com/kehiy/RoboPac/config"
"github.com/kehiy/RoboPac/log"
"github.com/kehiy/RoboPac/nowpayments"
"github.com/kehiy/RoboPac/store"
"github.com/kehiy/RoboPac/turboswap"
"github.com/kehiy/RoboPac/twitter_api"
"github.com/kehiy/RoboPac/utils"
"github.com/kehiy/RoboPac/wallet"
"github.com/libp2p/go-libp2p/core/peer"
gonanoid "github.com/matoous/go-nanoid/v2"
putils "github.com/pactus-project/pactus/util"
"github.com/pactus-project/pactus/util/logger"
)

var BoosterPrice = 30

type BotEngine struct {
ctx context.Context //nolint
cancel func()

wallet wallet.IWallet
store store.IStore
turboswap turboswap.ITurboSwap
clientMgr *client.Mgr
logger *log.SubLogger
wallet wallet.IWallet
store store.IStore
nowpayments nowpayments.INowpayment
clientMgr *client.Mgr
logger *log.SubLogger

twitterClient twitter_api.IClient

Expand Down Expand Up @@ -88,17 +91,17 @@ func NewBotEngine(cfg *config.Config) (IEngine, error) {
}
log.Info("twitterClient loaded successfully")

turboswap, err := turboswap.NewTurboswap(cfg.TurboswapConfig.APIToken, cfg.TurboswapConfig.URL)
nowpayments, err := nowpayments.NewNowPayments(&cfg.NowPaymentsConfig)
if err != nil {
log.Error("could not start twitter client", "err", err)
}
log.Info("turboswap loaded successfully")
log.Info("nowpayments loaded successfully")

return newBotEngine(eSl, cm, wallet, store, twitterClient, turboswap), nil
return newBotEngine(eSl, cm, wallet, store, twitterClient, nowpayments), nil
}

func newBotEngine(logger *log.SubLogger, cm *client.Mgr, w wallet.IWallet, s store.IStore,
twitterClient twitter_api.IClient, turboswap turboswap.ITurboSwap,
twitterClient twitter_api.IClient, nowpayments nowpayments.INowpayment,
) *BotEngine {
ctx, cancel := context.WithCancel(context.Background())

Expand All @@ -110,7 +113,7 @@ func newBotEngine(logger *log.SubLogger, cm *client.Mgr, w wallet.IWallet, s sto
clientMgr: cm,
store: s,
twitterClient: twitterClient,
turboswap: turboswap,
nowpayments: nowpayments,
}
}

Expand Down Expand Up @@ -312,7 +315,7 @@ func (be *BotEngine) RewardCalculate(stake int64, t string) (int64, string, int6
return reward, time, int64(utils.ChangeToCoin(bi.TotalPower)), nil
}

func (be *BotEngine) TwitterCampaign(discordID, twitterName, valAddr string) (*store.TwitterParty, error) {
func (be *BotEngine) BoosterPayment(discordID, twitterName, valAddr string) (*store.TwitterParty, error) {
be.Lock()
defer be.Unlock()

Expand Down Expand Up @@ -355,13 +358,13 @@ func (be *BotEngine) TwitterCampaign(discordID, twitterName, valAddr string) (*s
return nil, err
}

discountCode, err := gonanoid.Generate("0123456789", 6)
discountCode, err := gonanoid.Generate("0123456789", 8)
if err != nil {
return nil, err
}

totalPrice := 50
amountInPAC := 150
totalPrice := BoosterPrice
amountInPAC := int64(150)
if userInfo.Followers > 1000 {
amountInPAC = 200
}
Expand All @@ -379,33 +382,55 @@ func (be *BotEngine) TwitterCampaign(discordID, twitterName, valAddr string) (*s
CreatedAt: time.Now().Unix(),
}

err = be.turboswap.SendDiscountCode(be.ctx, party)
err = be.nowpayments.CreatePayment(party)
if err != nil {
return nil, err
}

err = be.store.AddTwitterParty(party)
err = be.store.SaveTwitterParty(party)
if err != nil {
return nil, err
}

return party, nil
}

func (be *BotEngine) TwitterCampaignStatus(twitterName string) (*store.TwitterParty, *turboswap.DiscountStatus, error) {
func (be *BotEngine) BoosterClaim(twitterName string) (*store.TwitterParty, error) {
party := be.store.FindTwitterParty(twitterName)
if party == nil {
return nil, nil, fmt.Errorf("no discount code generated for this Twitter account: `%v`", twitterName)
return nil, fmt.Errorf("no discount code generated for this Twitter account: `%v`", twitterName)
}
status, err := be.turboswap.GetStatus(be.ctx, party)
err := be.nowpayments.UpdatePayment(party)
if err != nil {
return nil, nil, err
return nil, err
}

if party.NowPaymentsFinished {
if party.TransactionID == "" {
logger.Info("sending bond transaction", "receiver", party.ValAddr, "amount", party.AmountInPAC)
memo := "Booster Program"
txID, err := be.wallet.BondTransaction(party.ValPubKey, party.ValAddr, memo, utils.CoinToChange(float64(party.AmountInPAC)))
if err != nil {
return nil, err
}

if txID == "" {
return nil, errors.New("can't send bond transaction")
}

party.TransactionID = txID

err = be.store.SaveTwitterParty(party)
if err != nil {
return nil, err
}
}
}

return party, status, nil
return party, nil
}

func (be *BotEngine) TwitterCampaignWhitelist(twitterName string, authorizedDiscordID string) error {
func (be *BotEngine) BoosterWhitelist(twitterName string, authorizedDiscordID string) error {
authorizedIDs := []string{}

if !slices.Contains(authorizedIDs, authorizedDiscordID) {
Expand Down
Loading

0 comments on commit 3e60e5f

Please sign in to comment.