Skip to content

Commit

Permalink
Add participant works
Browse files Browse the repository at this point in the history
  • Loading branch information
OmegaTymbJIep committed Jun 30, 2024
1 parent fb4e091 commit 811c971
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 18 deletions.
40 changes: 40 additions & 0 deletions internal/service/api/handlers/add_participant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package handlers

import (
"errors"
"net/http"

"gitlab.com/distributed_lab/ape"
"gitlab.com/distributed_lab/ape/problems"

"github.com/black-pepper-team/community-indexer/internal/service/api/requests"
"github.com/black-pepper-team/community-indexer/internal/service/api/responses"
"github.com/black-pepper-team/community-indexer/internal/service/core"
)

func AddCommunityParticipant(w http.ResponseWriter, r *http.Request) {
req, err := requests.NewAddCommunityParticipant(r)
if err != nil {
Log(r).WithField("reason", err).Debug("Bad request")
ape.RenderErr(w, problems.BadRequest(err)...)
return
}

mintRequest, err := Core(r).AddCommunityParticipant(
req.PrivateKey, req.ParticipantAddress, req.ContractAddress,
)
switch {
case errors.Is(err, core.ErrContractNotFound):
ape.RenderErr(w, problems.NotFound())
Log(r).WithError(err).
Debug("Contract not found")
return
case err != nil:
Log(r).WithError(err).
Error("Failed add community participant")
ape.RenderErr(w, problems.InternalError())
return
}

ape.Render(w, responses.NewRegisterInCommunity(mintRequest))
}
2 changes: 1 addition & 1 deletion internal/service/api/handlers/create_community.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func CreateCommunity(w http.ResponseWriter, r *http.Request) {
return
}

newCommunity, err := Core(r).CreateCommunity(req.CollectionName, req.CollectionSymbol)
newCommunity, err := Core(r).CreateCommunity(req.CollectionName, req.CollectionSymbol, req.PrivateKey)
if err != nil {
Log(r).WithError(err).
Error("Failed create community")
Expand Down
62 changes: 62 additions & 0 deletions internal/service/api/requests/add_participant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package requests

import (
"crypto/ecdsa"
"encoding/json"
"net/http"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
validation "github.com/go-ozzo/ozzo-validation/v4"
"gitlab.com/distributed_lab/logan/v3/errors"
)

type addCommunityParticipantRequest struct {
PrivateKey string `json:"private_key"`
ParticipantAddress string `json:"participant_address"`
ContractAddress string `json:"contract_address"`
}

type AddCommunityParticipantRequest struct {
PrivateKey *ecdsa.PrivateKey
ParticipantAddress common.Address
ContractAddress common.Address
}

func NewAddCommunityParticipant(r *http.Request) (*AddCommunityParticipantRequest, error) {
var requestBody addCommunityParticipantRequest

if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
return nil, errors.Wrap(err, "failed to decode json request body")
}

if err := requestBody.validate(); err != nil {
return nil, err
}

return requestBody.parse(), nil
}

// nolint
func (r *addCommunityParticipantRequest) validate() error {
return validation.Errors{
"body/private_key": validation.Validate(
r.PrivateKey, validation.Required, validation.Length(64, 64),
),
"body/participant_address": validation.Validate(
r.ParticipantAddress, validation.Required, validation.By(MustBeValidAddress),
),
"body/contract_address": validation.Validate(
r.ContractAddress, validation.Required, validation.By(MustBeValidAddress),
),
}.Filter()
}

func (r *addCommunityParticipantRequest) parse() *AddCommunityParticipantRequest {
sk, _ := crypto.HexToECDSA(r.PrivateKey)
return &AddCommunityParticipantRequest{
PrivateKey: sk,
ParticipantAddress: common.HexToAddress(r.ParticipantAddress),
ContractAddress: common.HexToAddress(r.ContractAddress),
}
}
9 changes: 9 additions & 0 deletions internal/service/api/requests/create_community.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
package requests

import (
"crypto/ecdsa"
"encoding/json"
"net/http"

"github.com/ethereum/go-ethereum/crypto"
validation "github.com/go-ozzo/ozzo-validation/v4"
"gitlab.com/distributed_lab/logan/v3/errors"
)

type createCommunityRequest struct {
CollectionName string `json:"collection_name"`
CollectionSymbol string `json:"collection_symbol"`
PrivateKey string `json:"private_key"`
}

type CreateCommunityRequest struct {
CollectionName string
CollectionSymbol string
PrivateKey *ecdsa.PrivateKey
}

func NewCreateCommunity(r *http.Request) (*CreateCommunityRequest, error) {
Expand All @@ -35,6 +39,9 @@ func NewCreateCommunity(r *http.Request) (*CreateCommunityRequest, error) {
// nolint
func (r *createCommunityRequest) validate() error {
return validation.Errors{
"body/private_key": validation.Validate(
r.PrivateKey, validation.Required, validation.Length(64, 64),
),
"body/collection_name": validation.Validate(
r.CollectionName, validation.Required,
),
Expand All @@ -45,7 +52,9 @@ func (r *createCommunityRequest) validate() error {
}

func (r *createCommunityRequest) parse() *CreateCommunityRequest {
sk, _ := crypto.HexToECDSA(r.PrivateKey)
return &CreateCommunityRequest{
PrivateKey: sk,
CollectionName: r.CollectionName,
CollectionSymbol: r.CollectionSymbol,
}
Expand Down
1 change: 1 addition & 0 deletions internal/service/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func (s *service) router() chi.Router {
r.Post("/import", handlers.ImportCommunity)
r.Post("/register", handlers.RegisterInCommunity)
r.Get("/register/{register-id}", handlers.GetRegisterStatus)
r.Post("/add-participant", handlers.AddCommunityParticipant)
})
})

Expand Down
11 changes: 7 additions & 4 deletions internal/service/core/eth_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package core
import (
"bytes"
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
Expand All @@ -13,6 +14,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)

Expand Down Expand Up @@ -44,9 +46,10 @@ func (c *Core) waitMined(ctx context.Context, tx *types.Transaction) (*types.Rec

func (c *Core) retryChainCall(
ctx context.Context,
privKey *ecdsa.PrivateKey,
contractCall func(signer *bind.TransactOpts) error,
) error {
signer, err := c.newSigner(ctx)
signer, err := c.newSigner(ctx, privKey)
if err != nil {
return fmt.Errorf("failed to get new signer: %w", err)
}
Expand All @@ -65,13 +68,13 @@ func (c *Core) retryChainCall(
return nil
}

func (c *Core) newSigner(ctx context.Context) (*bind.TransactOpts, error) {
nonce, err := c.ethClient.PendingNonceAt(ctx, c.address)
func (c *Core) newSigner(ctx context.Context, privKey *ecdsa.PrivateKey) (*bind.TransactOpts, error) {
nonce, err := c.ethClient.PendingNonceAt(ctx, crypto.PubkeyToAddress(privKey.PublicKey))
if err != nil {
return nil, fmt.Errorf("failed to get nonce: %w", err)
}

auth, err := bind.NewKeyedTransactorWithChainID(c.privateKey, c.chainID)
auth, err := bind.NewKeyedTransactorWithChainID(privKey, c.chainID)
if err != nil {
return nil, fmt.Errorf("failed to create transaction signer: %w", err)
}
Expand Down
81 changes: 68 additions & 13 deletions internal/service/core/handlers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package core

import (
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/google/uuid"
"github.com/iden3/go-iden3-crypto/babyjub"
"github.com/iden3/go-rapidsnark/prover"
Expand Down Expand Up @@ -53,16 +55,12 @@ func (c *Core) GetCommunityById(communityId uuid.UUID) (*data.Community, error)
func (c *Core) CreateCommunity(
collectionName string,
collectionSymbol string,
privKey *ecdsa.PrivateKey,
) (*data.Community, error) {
var err error
var tx *types.Transaction
var address common.Address
err = c.retryChainCall(c.ctx, func(signer *bind.TransactOpts) error {
signer, err := c.newSigner(c.ctx)
if err != nil {
return fmt.Errorf("failed to get new signer: %w", err)
}

err = c.retryChainCall(c.ctx, privKey, func(signer *bind.TransactOpts) error {
address, tx, _, err = contracts.DeployERC721Mock(signer, c.ethClient, collectionName, collectionSymbol)
if err != nil {
return fmt.Errorf("failed to deploy new community: %w", err)
Expand All @@ -85,7 +83,7 @@ func (c *Core) CreateCommunity(
Name: collectionName,
Symbol: collectionSymbol,
ContractAddress: address,
OwnerAddress: c.address,
OwnerAddress: crypto.PubkeyToAddress(privKey.PublicKey),
}

if err = c.db.New().CommunitiesQ().Insert(&newCommunity); err != nil {
Expand Down Expand Up @@ -244,12 +242,7 @@ func (c *Core) RegisterInCommunity(
}

var tx *types.Transaction
err = c.retryChainCall(c.ctx, func(signer *bind.TransactOpts) error {
signer, err := c.newSigner(c.ctx)
if err != nil {
return fmt.Errorf("failed to get new signer: %w", err)
}

err = c.retryChainCall(c.ctx, c.privateKey, func(signer *bind.TransactOpts) error {
tx, err = c.authStorageContract.Register(
signer,
contractId,
Expand Down Expand Up @@ -322,3 +315,65 @@ func (c *Core) GetRegister(registerRequestId uuid.UUID) (*RegisterRequest, error

return registerRequest, nil
}

func (c *Core) AddCommunityParticipant(
privKey *ecdsa.PrivateKey,
participantAddress common.Address,
contractAddress common.Address,
) (*RegisterRequest, error) {
community, err := c.db.CommunitiesQ().WhereContractAddress(contractAddress).Get()
if err != nil {
return nil, fmt.Errorf("failed to get community by contract address: %w", err)
}

if community == nil {
return nil, ErrContractNotFound
}

collectionContract, err := contracts.NewERC721Mock(contractAddress, c.ethClient)
if err != nil {
return nil, fmt.Errorf("failed to get ERC721 contract: %w", err)
}

var tx *types.Transaction
err = c.retryChainCall(c.ctx, privKey, func(signer *bind.TransactOpts) error {
newRandId := babyjub.NewRandPrivKey()
tx, err = collectionContract.Mint(signer, participantAddress, (newRandId).Scalar().BigInt())
if err != nil {
return fmt.Errorf("failed to call Register: %w", err)
}

return nil
})
if err != nil {
return nil, fmt.Errorf("failed to call retryChainCall: %w", err)
}

requestId := uuid.New()
mintRequest := RegisterRequest{
Id: requestId,
Status: Processing,
}

c.registerRequests[requestId] = &mintRequest

go func() {
nextStatus := Registered

if _, err := c.waitMined(c.ctx, tx); err != nil {
c.log.
WithField("tx-hash", tx.Hash().Hex()).
WithField("reason", err).
Errorf("failed to wait tx mined")

nextStatus = FailedRegister
}

mintRequest.Status = nextStatus
c.registerRequests[requestId] = &mintRequest

return
}()

return &mintRequest, nil
}
1 change: 1 addition & 0 deletions internal/service/core/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func New(ctx context.Context, cfg config.Config) (*Core, error) {
circuits: circuits,
chatContract: chatContract,
authStorageContract: authStorageContract,
registerRequests: make(map[uuid.UUID]*RegisterRequest),
registeredUsers: make(RegisterStorage),
}, nil
}
Expand Down

0 comments on commit 811c971

Please sign in to comment.