block-accounting/backend/internal/usecase/interactors/chain/chain.go

227 lines
5.6 KiB
Go
Raw Normal View History

2024-05-24 17:44:24 +00:00
package chain
import (
2024-05-24 22:45:56 +00:00
"bytes"
2024-05-24 17:44:24 +00:00
"context"
2024-05-24 22:45:56 +00:00
"encoding/json"
"fmt"
2024-05-24 23:39:32 +00:00
"io"
2024-05-24 22:45:56 +00:00
"log/slog"
"net/http"
"time"
2024-05-24 17:44:24 +00:00
2024-05-24 22:45:56 +00:00
"github.com/emochka2007/block-accounting/internal/pkg/config"
2024-05-25 13:00:21 +00:00
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
2024-05-24 22:45:56 +00:00
"github.com/emochka2007/block-accounting/internal/pkg/models"
2024-05-24 17:44:24 +00:00
"github.com/emochka2007/block-accounting/internal/usecase/repository/transactions"
2024-05-24 22:45:56 +00:00
"github.com/ethereum/go-ethereum/common"
"github.com/google/uuid"
2024-05-24 17:44:24 +00:00
)
type ChainInteractor interface {
2024-05-24 22:45:56 +00:00
NewMultisig(ctx context.Context, params NewMultisigParams) error
2024-05-25 13:00:21 +00:00
PubKey(ctx context.Context, user *models.User) ([]byte, error)
SalaryDeploy(ctx context.Context, firtsAdmin models.OrganizationParticipant) error
2024-05-24 17:44:24 +00:00
}
type chainInteractor struct {
2024-05-25 13:00:21 +00:00
log *slog.Logger
config config.Config
txRepository transactions.Repository
2024-05-24 17:44:24 +00:00
}
2024-05-24 22:45:56 +00:00
func NewChainInteractor(
log *slog.Logger,
config config.Config,
txRepository transactions.Repository,
) ChainInteractor {
return &chainInteractor{
2024-05-25 13:00:21 +00:00
log: log,
config: config,
txRepository: txRepository,
2024-05-24 22:45:56 +00:00
}
}
2024-05-24 17:44:24 +00:00
type NewMultisigParams struct {
Title string
Owners []models.OrganizationParticipant
2024-05-24 22:45:56 +00:00
Confirmations int
2024-05-24 17:44:24 +00:00
}
type newMultisigChainResponse struct {
Address string `json:"address"`
}
2024-05-24 22:45:56 +00:00
func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigParams) error {
2024-05-25 13:00:21 +00:00
endpoint := i.config.ChainAPI.Host + "/multi-sig/deploy"
2024-05-24 22:45:56 +00:00
i.log.Debug(
"deploy multisig",
2024-05-25 13:00:21 +00:00
slog.String("endpoint", endpoint),
2024-05-24 22:45:56 +00:00
slog.Any("params", params),
)
pks := make([]string, len(params.Owners))
for i, owner := range params.Owners {
if owner.GetUser() == nil {
return fmt.Errorf("error invalis owners set")
}
pks[i] = "0x" + common.Bytes2Hex(owner.GetUser().PublicKey())
}
2024-05-24 22:45:56 +00:00
requestBody, err := json.Marshal(map[string]any{
"owners": pks,
2024-05-24 22:45:56 +00:00
"confirmations": params.Confirmations,
})
if err != nil {
return fmt.Errorf("error marshal request body. %w", err)
}
2024-05-25 13:00:21 +00:00
user, err := ctxmeta.User(ctx)
if err != nil {
return fmt.Errorf("error fetch user from context. %w", err)
}
organizationID, err := ctxmeta.OrganizationId(ctx)
if err != nil {
return fmt.Errorf("error fetch organization id from context. %w", err)
}
2024-05-24 22:45:56 +00:00
body := bytes.NewBuffer(requestBody)
2024-05-25 13:00:21 +00:00
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, body)
if err != nil {
return fmt.Errorf("error build request. %w", err)
}
2024-05-24 22:45:56 +00:00
2024-05-25 13:00:21 +00:00
req.Header.Add("Content-Type", "application/json")
req.Header.Add("X-Seed", common.Bytes2Hex(user.Seed()))
2024-05-24 22:45:56 +00:00
2024-05-25 13:00:21 +00:00
resp, err := http.DefaultClient.Do(req)
if err != nil {
i.log.Error(
"error send deploy multisig request",
slog.String("endpoint", endpoint),
slog.Any("params", params),
)
2024-05-24 22:45:56 +00:00
2024-05-25 13:00:21 +00:00
return fmt.Errorf("error build new multisig request. %w", err)
}
2024-05-24 22:45:56 +00:00
2024-05-25 13:00:21 +00:00
defer resp.Body.Close()
2024-05-24 22:45:56 +00:00
raw, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("error read body. %w", err)
}
respObject := new(newMultisigChainResponse)
if err := json.Unmarshal(raw, &respObject); err != nil {
return fmt.Errorf("error parse chain-api response body. %w", err)
}
multisigAddress := common.Hex2Bytes(respObject.Address)
createdAt := time.Now()
if err := i.txRepository.AddMultisig(ctx, models.Multisig{
ID: uuid.Must(uuid.NewV7()),
Title: params.Title,
Address: multisigAddress,
OrganizationID: organizationID,
Owners: params.Owners,
ConfirmationsRequired: params.Confirmations,
CreatedAt: createdAt,
UpdatedAt: createdAt,
}); err != nil {
return fmt.Errorf("error add new multisig. %w", err)
}
2024-05-25 13:00:21 +00:00
i.log.Debug(
"deploy multisig response",
slog.Int("code", resp.StatusCode),
)
2024-05-24 22:45:56 +00:00
2024-05-25 13:00:21 +00:00
return nil
2024-05-24 22:45:56 +00:00
}
2024-05-24 23:39:32 +00:00
func (i *chainInteractor) PubKey(ctx context.Context, user *models.User) ([]byte, error) {
pubAddr := i.config.ChainAPI.Host + "/address-from-seed"
2024-05-24 22:45:56 +00:00
2024-05-24 23:39:32 +00:00
requestBody, err := json.Marshal(map[string]any{
"seedPhrase": user.Mnemonic,
})
if err != nil {
return nil, fmt.Errorf("error marshal request body. %w", err)
}
body := bytes.NewBuffer(requestBody)
2024-05-25 13:00:21 +00:00
req, err := http.NewRequestWithContext(ctx, http.MethodPost, pubAddr, body)
if err != nil {
return nil, fmt.Errorf("error build request. %w", err)
}
2024-05-24 23:39:32 +00:00
2024-05-25 13:00:21 +00:00
req.Header.Add("Content-Type", "application/json")
2024-05-24 23:39:32 +00:00
2024-05-25 13:00:21 +00:00
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error fetch pub address. %w", err)
}
2024-05-24 23:39:32 +00:00
2024-05-25 13:00:21 +00:00
defer resp.Body.Close()
2024-05-24 23:39:32 +00:00
2024-05-25 13:00:21 +00:00
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error read resp body. %w", err)
}
2024-05-24 23:39:32 +00:00
2024-05-25 13:00:21 +00:00
pubKeyStr := string(respBody)[2:]
2024-05-24 17:44:24 +00:00
2024-05-25 13:00:21 +00:00
return common.Hex2Bytes(pubKeyStr), nil
}
func (i *chainInteractor) SalaryDeploy(ctx context.Context, firtsAdmin models.OrganizationParticipant) error {
user, err := ctxmeta.User(ctx)
if err != nil {
return fmt.Errorf("error fetch user from context. %w", err)
2024-05-24 22:45:56 +00:00
}
2024-05-25 13:00:21 +00:00
if user.Id() != firtsAdmin.Id() || firtsAdmin.GetUser() == nil {
return fmt.Errorf("error unauthorized access")
}
requestBody, err := json.Marshal(map[string]any{
"authorizedWallet": common.Bytes2Hex(user.Seed()),
})
if err != nil {
return fmt.Errorf("error marshal request body. %w", err)
}
body := bytes.NewBuffer(requestBody)
endpoint := i.config.ChainAPI.Host + "/salaries/deploy"
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, body)
if err != nil {
return fmt.Errorf("error build request. %w", err)
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("X-Seed", common.Bytes2Hex(user.Seed()))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("error fetch deploy salary contract. %w", err)
}
defer resp.Body.Close()
return nil
2024-05-24 17:44:24 +00:00
}
2024-05-25 13:00:21 +00:00
// func (i *chainInteractor)