mirror of
https://github.com/emo2007/block-accounting.git
synced 2024-11-10 04:36:26 +00:00
+1
This commit is contained in:
parent
24bc9fd7f2
commit
512fc397da
@ -3,6 +3,7 @@ package factory
|
|||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/emochka2007/block-accounting/internal/infrastructure/ethapi"
|
||||||
"github.com/emochka2007/block-accounting/internal/infrastructure/repository/auth"
|
"github.com/emochka2007/block-accounting/internal/infrastructure/repository/auth"
|
||||||
"github.com/emochka2007/block-accounting/internal/infrastructure/repository/cache"
|
"github.com/emochka2007/block-accounting/internal/infrastructure/repository/cache"
|
||||||
orepo "github.com/emochka2007/block-accounting/internal/infrastructure/repository/organizations"
|
orepo "github.com/emochka2007/block-accounting/internal/infrastructure/repository/organizations"
|
||||||
@ -60,5 +61,8 @@ func provideChainInteractor(
|
|||||||
txRepository txRepo.Repository,
|
txRepository txRepo.Repository,
|
||||||
orgInteractor organizations.OrganizationsInteractor,
|
orgInteractor organizations.OrganizationsInteractor,
|
||||||
) chain.ChainInteractor {
|
) chain.ChainInteractor {
|
||||||
return chain.NewChainInteractor(log, config, txRepository, orgInteractor)
|
return chain.NewChainInteractor(log, config, txRepository, orgInteractor, ethapi.NewEthAPIClient(
|
||||||
|
config.ChainAPI.Host,
|
||||||
|
log.WithGroup("eth-api-client"),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
104
backend/internal/infrastructure/ethapi/client.go
Normal file
104
backend/internal/infrastructure/ethapi/client.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package ethapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EthAPIClient interface {
|
||||||
|
DeployMultisig(
|
||||||
|
ctx context.Context,
|
||||||
|
ownersPubKeys []string,
|
||||||
|
confirmations int,
|
||||||
|
) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ethAPIClient struct {
|
||||||
|
host string
|
||||||
|
c *http.Client
|
||||||
|
log *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEthAPIClient(
|
||||||
|
address string,
|
||||||
|
log *slog.Logger,
|
||||||
|
) EthAPIClient {
|
||||||
|
return ðAPIClient{
|
||||||
|
host: address,
|
||||||
|
c: &http.Client{},
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ethAPIClient) DeployMultisig(
|
||||||
|
ctx context.Context,
|
||||||
|
ownersPubKeys []string,
|
||||||
|
confirmations int,
|
||||||
|
) (string, error) {
|
||||||
|
endpoint := c.host + "/multi-sig/deploy"
|
||||||
|
|
||||||
|
user, err := ctxmeta.User(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error fetch user from context. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBody, err := json.Marshal(map[string]any{
|
||||||
|
"owners": ownersPubKeys,
|
||||||
|
"confirmations": confirmations,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error marshal request body. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
body := bytes.NewBuffer(requestBody)
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, body)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error create a new 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 send deploy multisig request. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
raw, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error read response body. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.log.Debug(
|
||||||
|
"deploy multisig response",
|
||||||
|
slog.Int("code", resp.StatusCode),
|
||||||
|
slog.String("body", string(raw)),
|
||||||
|
)
|
||||||
|
|
||||||
|
respBody := make(map[string]string, 1)
|
||||||
|
|
||||||
|
if err := json.Unmarshal(raw, &respBody); err != nil {
|
||||||
|
return "", fmt.Errorf("error parse chain-api response body. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if address, ok := respBody["address"]; ok {
|
||||||
|
if address == "" {
|
||||||
|
return "", fmt.Errorf("error empty address")
|
||||||
|
}
|
||||||
|
|
||||||
|
return address, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("error deploy multisig. %+v", respBody)
|
||||||
|
}
|
@ -10,6 +10,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/emochka2007/block-accounting/internal/infrastructure/ethapi"
|
||||||
"github.com/emochka2007/block-accounting/internal/infrastructure/repository/transactions"
|
"github.com/emochka2007/block-accounting/internal/infrastructure/repository/transactions"
|
||||||
"github.com/emochka2007/block-accounting/internal/pkg/config"
|
"github.com/emochka2007/block-accounting/internal/pkg/config"
|
||||||
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
|
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
|
||||||
@ -36,6 +37,7 @@ type chainInteractor struct {
|
|||||||
config config.Config
|
config config.Config
|
||||||
txRepository transactions.Repository
|
txRepository transactions.Repository
|
||||||
organizationsInteractor organizations.OrganizationsInteractor
|
organizationsInteractor organizations.OrganizationsInteractor
|
||||||
|
client ethapi.EthAPIClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChainInteractor(
|
func NewChainInteractor(
|
||||||
@ -43,6 +45,7 @@ func NewChainInteractor(
|
|||||||
config config.Config,
|
config config.Config,
|
||||||
txRepository transactions.Repository,
|
txRepository transactions.Repository,
|
||||||
organizationsInteractor organizations.OrganizationsInteractor,
|
organizationsInteractor organizations.OrganizationsInteractor,
|
||||||
|
client ethapi.EthAPIClient,
|
||||||
) ChainInteractor {
|
) ChainInteractor {
|
||||||
return &chainInteractor{
|
return &chainInteractor{
|
||||||
log: log,
|
log: log,
|
||||||
@ -58,10 +61,6 @@ type NewMultisigParams struct {
|
|||||||
Confirmations int
|
Confirmations int
|
||||||
}
|
}
|
||||||
|
|
||||||
type newMultisigChainResponse struct {
|
|
||||||
Address string `json:"address"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigParams) error {
|
func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigParams) error {
|
||||||
endpoint := i.config.ChainAPI.Host + "/multi-sig/deploy"
|
endpoint := i.config.ChainAPI.Host + "/multi-sig/deploy"
|
||||||
|
|
||||||
@ -81,14 +80,6 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
pks[i] = "0x" + common.Bytes2Hex(owner.GetUser().PublicKey())
|
pks[i] = "0x" + common.Bytes2Hex(owner.GetUser().PublicKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
requestBody, err := json.Marshal(map[string]any{
|
|
||||||
"owners": pks,
|
|
||||||
"confirmations": params.Confirmations,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error marshal request body. %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := ctxmeta.User(ctx)
|
user, err := ctxmeta.User(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error fetch user from context. %w", err)
|
return fmt.Errorf("error fetch user from context. %w", err)
|
||||||
@ -99,7 +90,7 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
return fmt.Errorf("error fetch organization id from context. %w", err)
|
return fmt.Errorf("error fetch organization id from context. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() { // TODO remove this subroutine shit and replace it with worker pools
|
go func() { // TODO remove this subroutine shit and replace it with worker queue tasks
|
||||||
pid := uuid.Must(uuid.NewV7()).String()
|
pid := uuid.Must(uuid.NewV7()).String()
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
@ -142,23 +133,9 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
requestContext, cancel := context.WithTimeout(context.TODO(), time.Minute*15)
|
requestContext, cancel := context.WithTimeout(context.TODO(), time.Minute*15)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
body := bytes.NewBuffer(requestBody)
|
requestContext = ctxmeta.UserContext(requestContext, user)
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(requestContext, http.MethodPost, endpoint, body)
|
address, err := i.client.DeployMultisig(requestContext, pks, params.Confirmations)
|
||||||
if err != nil {
|
|
||||||
i.log.Error(
|
|
||||||
"error build request",
|
|
||||||
logger.Err(err),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
|
||||||
req.Header.Add("X-Seed", common.Bytes2Hex(user.Seed()))
|
|
||||||
|
|
||||||
// TODO replace http.DefaultClient with custom ChainAPi client from infrastructure/ethapi mod
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.log.Error(
|
i.log.Error(
|
||||||
"error send deploy multisig request",
|
"error send deploy multisig request",
|
||||||
@ -169,38 +146,7 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
multisigAddress := common.Hex2Bytes(address[2:])
|
||||||
|
|
||||||
raw, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
i.log.Error(
|
|
||||||
"error read body",
|
|
||||||
logger.Err(err),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
respObject := new(newMultisigChainResponse)
|
|
||||||
|
|
||||||
if err := json.Unmarshal(raw, &respObject); err != nil {
|
|
||||||
i.log.Error(
|
|
||||||
"error parse chain-api response body",
|
|
||||||
logger.Err(err),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if respObject.Address == "" {
|
|
||||||
i.log.Error(
|
|
||||||
"error multisig address is empty",
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
multisigAddress := common.Hex2Bytes(respObject.Address[2:])
|
|
||||||
|
|
||||||
createdAt := time.Now()
|
createdAt := time.Now()
|
||||||
|
|
||||||
@ -215,14 +161,6 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
UpdatedAt: createdAt,
|
UpdatedAt: createdAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
i.log.Debug(
|
|
||||||
"deploy multisig response",
|
|
||||||
slog.Int("code", resp.StatusCode),
|
|
||||||
slog.String("body", string(raw)),
|
|
||||||
slog.Any("parsed", respObject),
|
|
||||||
slog.Any("multisig object", msg),
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := i.txRepository.AddMultisig(requestContext, msg); err != nil {
|
if err := i.txRepository.AddMultisig(requestContext, msg); err != nil {
|
||||||
i.log.Error(
|
i.log.Error(
|
||||||
"error add new multisig",
|
"error add new multisig",
|
||||||
@ -272,7 +210,7 @@ func (i *chainInteractor) PubKey(ctx context.Context, user *models.User) ([]byte
|
|||||||
pubKeyStr := string(respBody)[2:]
|
pubKeyStr := string(respBody)[2:]
|
||||||
|
|
||||||
if pubKeyStr == "" {
|
if pubKeyStr == "" {
|
||||||
return nil, fmt.Errorf("error empty public key")
|
return nil, fmt.Errorf("error empty public key...")
|
||||||
}
|
}
|
||||||
|
|
||||||
return common.Hex2Bytes(pubKeyStr), nil
|
return common.Hex2Bytes(pubKeyStr), nil
|
||||||
|
Loading…
Reference in New Issue
Block a user