mirror of
https://github.com/emo2007/block-accounting.git
synced 2025-01-18 15:36:27 +00:00
deploy multisig implemented but tests needed
This commit is contained in:
parent
05d802630e
commit
b590daf305
@ -508,16 +508,28 @@ Response:
|
|||||||
### Request body:
|
### Request body:
|
||||||
* title (string)
|
* title (string)
|
||||||
* owners (array of object { "public_key":"string" })
|
* owners (array of object { "public_key":"string" })
|
||||||
* confirmations (int)
|
* confirmations (uint)
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
Request:
|
Request:
|
||||||
``` bash
|
``` bash
|
||||||
|
curl --request POST \
|
||||||
|
--url http://localhost:8081/organizations/018fb246-1616-7f1b-9fe2-1a3202224695/multisig \
|
||||||
|
--header 'Authorization: Bearer token' \
|
||||||
|
--header 'content-type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"title":"new sig",
|
||||||
|
"owners":[
|
||||||
|
"0x5810f45ac87c0be03b4d8174132e2bc81ba1a928"
|
||||||
|
],
|
||||||
|
"confirmations":1
|
||||||
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
Response:
|
Response:
|
||||||
``` json
|
``` json
|
||||||
|
{
|
||||||
|
"Ok": true
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -95,12 +95,14 @@ func provideTxController(
|
|||||||
log *slog.Logger,
|
log *slog.Logger,
|
||||||
txInteractor transactions.TransactionsInteractor,
|
txInteractor transactions.TransactionsInteractor,
|
||||||
chainInteractor chain.ChainInteractor,
|
chainInteractor chain.ChainInteractor,
|
||||||
|
organizationsInteractor organizations.OrganizationsInteractor,
|
||||||
) controllers.TransactionsController {
|
) controllers.TransactionsController {
|
||||||
return controllers.NewTransactionsController(
|
return controllers.NewTransactionsController(
|
||||||
log.WithGroup("transactions-controller"),
|
log.WithGroup("transactions-controller"),
|
||||||
txInteractor,
|
txInteractor,
|
||||||
presenters.NewTransactionsPresenter(),
|
presenters.NewTransactionsPresenter(),
|
||||||
chainInteractor,
|
chainInteractor,
|
||||||
|
organizationsInteractor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func ProvideService(c config.Config) (service.Service, func(), error) {
|
|||||||
organizationsPresenter := provideOrganizationsPresenter()
|
organizationsPresenter := provideOrganizationsPresenter()
|
||||||
organizationsController := provideOrganizationsController(logger, organizationsInteractor, organizationsPresenter)
|
organizationsController := provideOrganizationsController(logger, organizationsInteractor, organizationsPresenter)
|
||||||
transactionsInteractor := provideTxInteractor(logger, transactionsRepository, organizationsInteractor)
|
transactionsInteractor := provideTxInteractor(logger, transactionsRepository, organizationsInteractor)
|
||||||
transactionsController := provideTxController(logger, transactionsInteractor, chainInteractor)
|
transactionsController := provideTxController(logger, transactionsInteractor, chainInteractor, organizationsInteractor)
|
||||||
participantsController := provideParticipantsController(logger, organizationsInteractor, usersInteractor)
|
participantsController := provideParticipantsController(logger, organizationsInteractor, usersInteractor)
|
||||||
rootController := provideControllers(logger, authController, organizationsController, transactionsController, participantsController)
|
rootController := provideControllers(logger, authController, organizationsController, transactionsController, participantsController)
|
||||||
server := provideRestServer(logger, rootController, c, jwtInteractor)
|
server := provideRestServer(logger, rootController, c, jwtInteractor)
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
|
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
|
||||||
"github.com/emochka2007/block-accounting/internal/pkg/models"
|
"github.com/emochka2007/block-accounting/internal/pkg/models"
|
||||||
"github.com/emochka2007/block-accounting/internal/usecase/interactors/chain"
|
"github.com/emochka2007/block-accounting/internal/usecase/interactors/chain"
|
||||||
|
"github.com/emochka2007/block-accounting/internal/usecase/interactors/organizations"
|
||||||
"github.com/emochka2007/block-accounting/internal/usecase/interactors/transactions"
|
"github.com/emochka2007/block-accounting/internal/usecase/interactors/transactions"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
@ -40,6 +41,7 @@ type transactionsController struct {
|
|||||||
txInteractor transactions.TransactionsInteractor
|
txInteractor transactions.TransactionsInteractor
|
||||||
txPresenter presenters.TransactionsPresenter
|
txPresenter presenters.TransactionsPresenter
|
||||||
chainInteractor chain.ChainInteractor
|
chainInteractor chain.ChainInteractor
|
||||||
|
organizationsInteractor organizations.OrganizationsInteractor
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransactionsController(
|
func NewTransactionsController(
|
||||||
@ -47,12 +49,14 @@ func NewTransactionsController(
|
|||||||
txInteractor transactions.TransactionsInteractor,
|
txInteractor transactions.TransactionsInteractor,
|
||||||
txPresenter presenters.TransactionsPresenter,
|
txPresenter presenters.TransactionsPresenter,
|
||||||
chainInteractor chain.ChainInteractor,
|
chainInteractor chain.ChainInteractor,
|
||||||
|
organizationsInteractor organizations.OrganizationsInteractor,
|
||||||
) TransactionsController {
|
) TransactionsController {
|
||||||
return &transactionsController{
|
return &transactionsController{
|
||||||
log: log,
|
log: log,
|
||||||
txInteractor: txInteractor,
|
txInteractor: txInteractor,
|
||||||
txPresenter: txPresenter,
|
txPresenter: txPresenter,
|
||||||
chainInteractor: chainInteractor,
|
chainInteractor: chainInteractor,
|
||||||
|
organizationsInteractor: organizationsInteractor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,18 +225,28 @@ func (c *transactionsController) NewMultisig(w http.ResponseWriter, r *http.Requ
|
|||||||
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
ownersPKs := make([]string, len(req.Owners))
|
ownersPKs := make([][]byte, len(req.Owners))
|
||||||
|
|
||||||
for i, pk := range req.Owners {
|
for i, pk := range req.Owners {
|
||||||
ownersPKs[i] = pk.PublicKey
|
ownersPKs[i] = common.Hex2Bytes(pk.PublicKey[2:])
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Confirmations <= 0 {
|
if req.Confirmations <= 0 {
|
||||||
req.Confirmations = 1
|
req.Confirmations = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
participants, err := c.organizationsInteractor.Participants(ctx, organizations.ParticipantsParams{
|
||||||
|
PKs: ownersPKs,
|
||||||
|
OrganizationID: organizationID,
|
||||||
|
UsersOnly: true,
|
||||||
|
ActiveOnly: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error fetch participants by pks. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.chainInteractor.NewMultisig(ctx, chain.NewMultisigParams{
|
if err := c.chainInteractor.NewMultisig(ctx, chain.NewMultisigParams{
|
||||||
OwnersPKs: ownersPKs,
|
Owners: participants,
|
||||||
Confirmations: req.Confirmations,
|
Confirmations: req.Confirmations,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, fmt.Errorf("error deploy multisig. %w", err)
|
return nil, fmt.Errorf("error deploy multisig. %w", err)
|
||||||
|
@ -144,7 +144,7 @@ func (s *Server) buildRouter() {
|
|||||||
r.Post("/invite", s.handle(s.controllers.Auth.Invite, "invite"))
|
r.Post("/invite", s.handle(s.controllers.Auth.Invite, "invite"))
|
||||||
|
|
||||||
r.Route("/{participant_id}", func(r chi.Router) {
|
r.Route("/{participant_id}", func(r chi.Router) {
|
||||||
r.Get("/", nil)
|
r.Get("/", nil) // todo если успею
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
type Multisig struct {
|
type Multisig struct {
|
||||||
ID uuid.UUID
|
ID uuid.UUID
|
||||||
Title string
|
Title string
|
||||||
|
Address []byte
|
||||||
OrganizationID uuid.UUID
|
OrganizationID uuid.UUID
|
||||||
Owners []OrganizationParticipant
|
Owners []OrganizationParticipant
|
||||||
ConfirmationsRequired int
|
ConfirmationsRequired int
|
||||||
|
@ -55,6 +55,10 @@ func (u *User) Seed() []byte {
|
|||||||
return u.Bip39Seed
|
return u.Bip39Seed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) PublicKey() []byte {
|
||||||
|
return u.PK
|
||||||
|
}
|
||||||
|
|
||||||
type OrganizationParticipantType int
|
type OrganizationParticipantType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -8,12 +8,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"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"
|
||||||
"github.com/emochka2007/block-accounting/internal/pkg/models"
|
"github.com/emochka2007/block-accounting/internal/pkg/models"
|
||||||
"github.com/emochka2007/block-accounting/internal/usecase/repository/transactions"
|
"github.com/emochka2007/block-accounting/internal/usecase/repository/transactions"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChainInteractor interface {
|
type ChainInteractor interface {
|
||||||
@ -41,10 +43,15 @@ func NewChainInteractor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
type NewMultisigParams struct {
|
type NewMultisigParams struct {
|
||||||
OwnersPKs []string
|
Title string
|
||||||
|
Owners []models.OrganizationParticipant
|
||||||
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"
|
||||||
|
|
||||||
@ -54,8 +61,18 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
slog.Any("params", params),
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
requestBody, err := json.Marshal(map[string]any{
|
requestBody, err := json.Marshal(map[string]any{
|
||||||
"owners": params.OwnersPKs,
|
"owners": pks,
|
||||||
"confirmations": params.Confirmations,
|
"confirmations": params.Confirmations,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -67,6 +84,11 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
return fmt.Errorf("error fetch user from context. %w", err)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
body := bytes.NewBuffer(requestBody)
|
body := bytes.NewBuffer(requestBody)
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, body)
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, body)
|
||||||
@ -90,6 +112,34 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
i.log.Debug(
|
i.log.Debug(
|
||||||
"deploy multisig response",
|
"deploy multisig response",
|
||||||
slog.Int("code", resp.StatusCode),
|
slog.Int("code", resp.StatusCode),
|
||||||
|
@ -49,6 +49,7 @@ type ParticipantParams struct {
|
|||||||
type ParticipantsParams struct {
|
type ParticipantsParams struct {
|
||||||
IDs uuid.UUIDs
|
IDs uuid.UUIDs
|
||||||
OrganizationID uuid.UUID
|
OrganizationID uuid.UUID
|
||||||
|
PKs [][]byte
|
||||||
|
|
||||||
UsersOnly bool
|
UsersOnly bool
|
||||||
ActiveOnly bool
|
ActiveOnly bool
|
||||||
@ -289,6 +290,7 @@ func (i *organizationsInteractor) Participants(
|
|||||||
participants, err := i.orgRepository.Participants(ctx, organizations.ParticipantsParams{
|
participants, err := i.orgRepository.Participants(ctx, organizations.ParticipantsParams{
|
||||||
Ids: params.IDs,
|
Ids: params.IDs,
|
||||||
OrganizationId: params.OrganizationID,
|
OrganizationId: params.OrganizationID,
|
||||||
|
PKs: params.PKs,
|
||||||
UsersOnly: params.UsersOnly,
|
UsersOnly: params.UsersOnly,
|
||||||
EmployeesOnly: params.EmployeesOnly,
|
EmployeesOnly: params.EmployeesOnly,
|
||||||
ActiveOnly: params.ActiveOnly,
|
ActiveOnly: params.ActiveOnly,
|
||||||
|
@ -31,6 +31,7 @@ type GetParams struct {
|
|||||||
type ParticipantsParams struct {
|
type ParticipantsParams struct {
|
||||||
OrganizationId uuid.UUID
|
OrganizationId uuid.UUID
|
||||||
Ids uuid.UUIDs
|
Ids uuid.UUIDs
|
||||||
|
PKs [][]byte
|
||||||
|
|
||||||
// Filters
|
// Filters
|
||||||
UsersOnly bool
|
UsersOnly bool
|
||||||
@ -388,6 +389,12 @@ func (r *repositorySQL) Participants(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(params.PKs) > 0 {
|
||||||
|
ouQuery = ouQuery.InnerJoin("users as u on u.id = ou.user_id").Where(sq.Eq{
|
||||||
|
"u.public_key": params.PKs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
rows, err := ouQuery.RunWith(r.Conn(ctx)).QueryContext(ctx)
|
rows, err := ouQuery.RunWith(r.Conn(ctx)).QueryContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error fetch organization participants. %w", err)
|
return fmt.Errorf("error fetch organization participants. %w", err)
|
||||||
@ -548,6 +555,7 @@ func (r *repositorySQL) Participants(
|
|||||||
|
|
||||||
usrs, err = r.usersRepository.Get(usersCtx, users.GetParams{
|
usrs, err = r.usersRepository.Get(usersCtx, users.GetParams{
|
||||||
Ids: ids,
|
Ids: ids,
|
||||||
|
PKs: params.PKs,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error fetch users by ids. %w", err)
|
return fmt.Errorf("error fetch users by ids. %w", err)
|
||||||
|
@ -435,7 +435,7 @@ func (r *repositorySQL) AddMultisig(
|
|||||||
owner.Id(),
|
owner.Id(),
|
||||||
multisig.CreatedAt,
|
multisig.CreatedAt,
|
||||||
multisig.UpdatedAt,
|
multisig.UpdatedAt,
|
||||||
)
|
).PlaceholderFormat(sq.Dollar)
|
||||||
|
|
||||||
if _, err := addOwnerQuery.RunWith(r.Conn(ctx)).ExecContext(ctx); err != nil {
|
if _, err := addOwnerQuery.RunWith(r.Conn(ctx)).ExecContext(ctx); err != nil {
|
||||||
return fmt.Errorf("error insert multisig owner data. %w", err)
|
return fmt.Errorf("error insert multisig owner data. %w", err)
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
type GetParams struct {
|
type GetParams struct {
|
||||||
Ids uuid.UUIDs
|
Ids uuid.UUIDs
|
||||||
|
PKs [][]byte
|
||||||
OrganizationId uuid.UUID
|
OrganizationId uuid.UUID
|
||||||
Seed []byte
|
Seed []byte
|
||||||
}
|
}
|
||||||
@ -60,6 +61,12 @@ func (r *repositorySQL) Get(ctx context.Context, params GetParams) ([]*models.Us
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(params.PKs) > 0 {
|
||||||
|
query = query.Where(sq.Eq{
|
||||||
|
"u.public_key": params.PKs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if params.OrganizationId != uuid.Nil {
|
if params.OrganizationId != uuid.Nil {
|
||||||
query = query.InnerJoin(
|
query = query.InnerJoin(
|
||||||
"organizations_users as ou on ou.user_id = u.id",
|
"organizations_users as ou on ou.user_id = u.id",
|
||||||
@ -72,6 +79,10 @@ func (r *repositorySQL) Get(ctx context.Context, params GetParams) ([]*models.Us
|
|||||||
query = query.Where("u.seed = ?", params.Seed)
|
query = query.Where("u.seed = ?", params.Seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.PKs != nil {
|
||||||
|
fmt.Println(query.ToSql())
|
||||||
|
}
|
||||||
|
|
||||||
rows, err := query.RunWith(r.Conn(ctx)).QueryContext(ctx)
|
rows, err := query.RunWith(r.Conn(ctx)).QueryContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error fetch data from database. %w", err)
|
return fmt.Errorf("error fetch data from database. %w", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user