From 6bfcb1d7ed3a5fcd6ba31089e907ae8b02373288 Mon Sep 17 00:00:00 2001 From: violog <51th.apprent1ce.f0rce@gmail.com> Date: Wed, 5 Jun 2024 18:40:52 +0300 Subject: [PATCH] Refactor claim and withdrawal, according to new countries logic --- .../components/schemas/VerifyPassport.yaml | 4 +- docs/spec/components/schemas/Withdraw.yaml | 4 +- internal/service/handlers/claim_event.go | 29 +- internal/service/handlers/countries_config.go | 2 +- internal/service/handlers/verify_passport.go | 259 ++++++++++++------ internal/service/handlers/withdraw.go | 163 +++-------- resources/model_verify_passport_attributes.go | 6 +- resources/model_withdraw_attributes.go | 6 +- 8 files changed, 248 insertions(+), 225 deletions(-) diff --git a/docs/spec/components/schemas/VerifyPassport.yaml b/docs/spec/components/schemas/VerifyPassport.yaml index 9c0439b..c46b7e9 100644 --- a/docs/spec/components/schemas/VerifyPassport.yaml +++ b/docs/spec/components/schemas/VerifyPassport.yaml @@ -12,5 +12,5 @@ allOf: properties: proof: type: object - format: json.RawMessage - description: JSON encoded ZK passport verification proof. \ No newline at end of file + format: types.ZKProof + description: Iden3 ZK passport verification proof. \ No newline at end of file diff --git a/docs/spec/components/schemas/Withdraw.yaml b/docs/spec/components/schemas/Withdraw.yaml index 709fd15..0967736 100644 --- a/docs/spec/components/schemas/Withdraw.yaml +++ b/docs/spec/components/schemas/Withdraw.yaml @@ -23,5 +23,5 @@ allOf: example: rarimo15hcd6tv7pe8hk2re7hu0zg0aphqdm2dtjrs0ds proof: type: object - format: json.RawMessage - description: JSON encoded ZK passport verification proof. + format: types.ZKProof + description: Iden3 ZK passport verification proof. diff --git a/internal/service/handlers/claim_event.go b/internal/service/handlers/claim_event.go index b8c289e..22d2d6c 100644 --- a/internal/service/handlers/claim_event.go +++ b/internal/service/handlers/claim_event.go @@ -44,7 +44,7 @@ func ClaimEvent(w http.ResponseWriter, r *http.Request) { return } if evType.Disabled { - Log(r).Infof("Attempt to claim: event type %s is disabled", event.Type) + Log(r).Infof("Event type %s is disabled", event.Type) ape.RenderErr(w, problems.Forbidden()) return } @@ -55,9 +55,30 @@ func ClaimEvent(w http.ResponseWriter, r *http.Request) { ape.RenderErr(w, problems.InternalError()) return } - if balance == nil { - Log(r).Infof("Attempt to claim: balance nullifier=%s is disabled", event.Nullifier) - ape.RenderErr(w, problems.NotFound()) + if balance == nil || balance.Country == nil { + msg := "did not verify passport" + if balance == nil { + msg = "is disabled" + } + Log(r).Infof("Balance nullifier=%s %s", event.Nullifier, msg) + ape.RenderErr(w, problems.Forbidden()) + return + } + + country, err := CountriesQ(r).FilterByCodes(*balance.Country).Get() + if err != nil || country == nil { // country must exist if no errors + Log(r).WithError(err).Error("Failed to get country by code") + ape.RenderErr(w, problems.InternalError()) + return + } + if !country.ReserveAllowed { + Log(r).Infof("Reserve is not allowed for country=%s", *balance.Country) + ape.RenderErr(w, problems.Forbidden()) + return + } + if country.Reserved >= country.ReserveLimit { + Log(r).Infof("Reserve limit is reached for country=%s", *balance.Country) + ape.RenderErr(w, problems.Forbidden()) return } diff --git a/internal/service/handlers/countries_config.go b/internal/service/handlers/countries_config.go index cc3551e..9ee40b1 100644 --- a/internal/service/handlers/countries_config.go +++ b/internal/service/handlers/countries_config.go @@ -23,7 +23,7 @@ func GetCountriesConfig(w http.ResponseWriter, r *http.Request) { WithdrawalAllowed: c.WithdrawalAllowed, } // when the limit is reached, reserve is not allowed despite the config - if c.Reserved < c.ReserveLimit { + if c.Reserved >= c.ReserveLimit { prop.ReserveAllowed = false } cMap[c.Code] = prop diff --git a/internal/service/handlers/verify_passport.go b/internal/service/handlers/verify_passport.go index f148e18..a3ec5ea 100644 --- a/internal/service/handlers/verify_passport.go +++ b/internal/service/handlers/verify_passport.go @@ -1,13 +1,13 @@ package handlers import ( - "encoding/json" "fmt" "math/big" "net/http" "github.com/ethereum/go-ethereum/common/hexutil" validation "github.com/go-ozzo/ozzo-validation/v4" + "github.com/google/jsonapi" zkptypes "github.com/iden3/go-rapidsnark/types" "github.com/rarimo/decentralized-auth-svc/pkg/auth" "github.com/rarimo/rarime-points-svc/internal/data" @@ -19,6 +19,8 @@ import ( "gitlab.com/distributed_lab/logan/v3/errors" ) +const proofSelectorValue = "23073" + func VerifyPassport(w http.ResponseWriter, r *http.Request) { req, err := requests.NewVerifyPassport(r) if err != nil { @@ -27,128 +29,215 @@ func VerifyPassport(w http.ResponseWriter, r *http.Request) { return } - nullifier := req.Data.ID + balance, errs := getAndVerifyBalanceEligibility(r, req.Data.ID, &req.Data.Attributes.Proof) + if len(errs) > 0 { + ape.RenderErr(w, errs...) + return + } - if !auth.Authenticates(UserClaims(r), auth.UserGrant(nullifier)) { - ape.RenderErr(w, problems.Unauthorized()) + if balance.Country != nil { + Log(r).Debugf("Balance %s already verified", balance.Nullifier) + ape.RenderErr(w, problems.TooManyRequests()) return } - balance, err := BalancesQ(r).FilterByNullifier(nullifier).Get() + err = EventsQ(r).Transaction(func() error { + return doPassportScanUpdates(r, *balance, req.Data.Attributes.Proof) + }) if err != nil { - Log(r).WithError(err).Error("Failed to get balance by nullifier") + Log(r).WithError(err).Error("Failed to execute transaction") ape.RenderErr(w, problems.InternalError()) return } - if balance == nil { - Log(r).Debug("Balance absent") - ape.RenderErr(w, problems.NotFound()) - return + w.WriteHeader(http.StatusNoContent) +} + +// getAndVerifyBalanceEligibility provides common logic to verify that the user +// is eligible to verify passport or withdraw. Some extra checks still exist in +// the flows. +func getAndVerifyBalanceEligibility( + r *http.Request, + nullifier string, + proof *zkptypes.ZKProof, +) (balance *data.Balance, errs []*jsonapi.ErrorObject) { + + if !auth.Authenticates(UserClaims(r), auth.UserGrant(nullifier)) { + return nil, append(errs, problems.Unauthorized()) } - if !balance.ReferredBy.Valid { - Log(r).Debug("Balance inactive") - ape.RenderErr(w, problems.BadRequest(validation.Errors{"referred_by": errors.New("balance inactive")})...) - return + balance, err := BalancesQ(r).FilterByNullifier(nullifier).Get() + if err != nil { + Log(r).WithError(err).Error("Failed to get balance by nullifier") + return nil, append(errs, problems.InternalError()) } - evType := EventTypes(r).Get(evtypes.TypePassportScan, evtypes.FilterInactive) - if evType == nil { - Log(r).Debug("Passport scan event absent, disabled, hasn't start yet or expired") - ape.RenderErr(w, problems.BadRequest(validation.Errors{"passport_scan": errors.New("event disabled or absent")})...) - return + if errs = checkVerificationEligibility(r, balance); len(errs) > 0 { + return nil, errs } - event, err := EventsQ(r).FilterByNullifier(nullifier). - FilterByType(evtypes.TypePassportScan). - FilterByStatus(data.EventOpen).Get() + // MustDecode will never panic, because of the previous logic of request validation + proof.PubSignals[zk.Nullifier] = new(big.Int).SetBytes(hexutil.MustDecode(nullifier)).String() + err = Verifier(r).VerifyProof(*proof, zk.WithProofSelectorValue(proofSelectorValue)) if err != nil { - Log(r).WithError(err).Error("Failed to get passport scan event") - ape.RenderErr(w, problems.InternalError()) - return + return nil, problems.BadRequest(err) } - if event == nil { - Log(r).Debug("Event already fulfilled or absent for user") - ape.RenderErr(w, problems.TooManyRequests()) - return + return balance, nil +} + +func checkVerificationEligibility(r *http.Request, balance *data.Balance) (errs []*jsonapi.ErrorObject) { + switch { + case balance == nil: + Log(r).Debug("Balance absent") + return append(errs, problems.NotFound()) + case !balance.ReferredBy.Valid: + Log(r).Debug("Balance inactive") + return append(errs, problems.BadRequest(validation.Errors{ + "referred_by": errors.New("user must be referred to withdraw"), + })...) } - var proof zkptypes.ZKProof - if err := json.Unmarshal(req.Data.Attributes.Proof, &proof); err != nil { - ape.RenderErr(w, problems.BadRequest(err)...) - return + return nil +} + +// doPassportScanUpdates performs all the necessary updates when the passport +// scan proof is provided. This logic is shared between verification and +// withdrawal handlers. +func doPassportScanUpdates(r *http.Request, balance data.Balance, proof zkptypes.ZKProof) error { + country, err := updateBalanceCountry(r, balance, proof) + if err != nil { + return fmt.Errorf("update balance country: %w", err) + } + if !country.ReserveAllowed || !country.WithdrawalAllowed || country.Reserved >= country.ReserveLimit { + Log(r).Infof("User %s scanned passport which country has restrictions: %+v", balance.Nullifier, country) } - // MustDecode will never panic, because of the previous logic - proof.PubSignals[zk.Nullifier] = new(big.Int).SetBytes(hexutil.MustDecode(nullifier)).String() - if err := Verifier(r).VerifyProof(proof, zk.WithProofSelectorValue("23073")); err != nil { - ape.RenderErr(w, problems.BadRequest(err)...) - return + if err = fulfillPassportScanEvent(r, balance); err != nil { + return fmt.Errorf("fulfill passport scan event: %w", err) } - evType = EventTypes(r).Get(evtypes.TypeReferralSpecific, evtypes.FilterInactive) - if evType == nil { - Log(r).Debug("Referral event type is disabled or expired, not accruing points to referrer") + if err = addEventForReferrer(r, balance); err != nil { + return fmt.Errorf("add event for referrer: %w", err) } - err = EventsQ(r).Transaction(func() (err error) { - countryCode := decodeInt(proof.PubSignals[zk.Citizenship]) - if country, ok := Countries(r)[countryCode]; !ok { - err = CountriesQ(r).Insert(data.Country{Code: countryCode, - ReserveLimit: country.ReserveLimit, - ReserveAllowed: country.ReserveAllowed, - WithdrawalAllowed: country.WithdrawalAllowed}) - if err != nil { - return fmt.Errorf("failed to inser new country: %w", err) - } - } - if err = BalancesQ(r). - FilterByNullifier(nullifier). - Update(map[string]any{"country": countryCode}); err != nil { - return fmt.Errorf("failed to update country: %w", err) - } + return nil +} - if evType != nil { - // ReferredBy always valid because of the previous logic - referral, err := ReferralsQ(r).Get(balance.ReferredBy.String) - if err != nil { - return fmt.Errorf("failed to get referral by ID: %w", err) - } - - err = EventsQ(r).Insert(data.Event{ - Nullifier: referral.Nullifier, - Type: evType.Name, - Status: data.EventFulfilled, - Meta: data.Jsonb(fmt.Sprintf(`{"nullifier": "%s"}`, nullifier)), - }) - if err != nil { - return fmt.Errorf("add event for referrer: %w", err) - } +func updateBalanceCountry(r *http.Request, balance data.Balance, proof zkptypes.ZKProof) (*data.Country, error) { + country, err := getOrCreateCountry(CountriesQ(r), proof) + if err != nil { + return nil, fmt.Errorf("get or create country: %w", err) + } + if balance.Country != nil { + if *balance.Country == country.Code { + return country, nil } + // countries mismatch is handled separately in withdrawal flow before calling + // updateBalanceCountry, so this will never happen + return nil, errors.New("countries mismatch") + } - _, err = EventsQ(r). - FilterByID(event.ID). - Update(data.EventFulfilled, nil, nil) - if err != nil { - return fmt.Errorf("failed to update passport scan event: %w", err) - } + err = BalancesQ(r).FilterByNullifier(balance.Nullifier).Update(map[string]any{ + data.ColCountry: country.Code, + }) + if err != nil { + return nil, fmt.Errorf("update balance country: %w", err) + } + + return country, nil +} + +func fulfillPassportScanEvent(r *http.Request, balance data.Balance) error { + evTypePassport := EventTypes(r).Get(evtypes.TypePassportScan, evtypes.FilterInactive) + if evTypePassport == nil { + Log(r).Debug("Passport scan event type is inactive") + return nil + } + + event, err := EventsQ(r).FilterByNullifier(balance.Nullifier). + FilterByType(evtypes.TypePassportScan). + FilterByStatus(data.EventOpen).Get() + if err != nil { + return fmt.Errorf("get open passport scan event: %w", err) + } + + if event == nil { + return errors.New("inconsistent state: balance has no country, event type is active, but no open event was found") + } + + _, err = EventsQ(r). + FilterByID(event.ID). + Update(data.EventFulfilled, nil, nil) + return err +} + +func addEventForReferrer(r *http.Request, balance data.Balance) error { + evTypeRef := EventTypes(r).Get(evtypes.TypeReferralSpecific, evtypes.FilterInactive) + if evTypeRef == nil { + Log(r).Debug("Referral event type is inactive, not fulfilling event for referrer") return nil + } + + // ReferredBy always valid because of the previous logic + referral, err := ReferralsQ(r).Get(balance.ReferredBy.String) + if err != nil { + return fmt.Errorf("get referral by ID: %w", err) + } + + return EventsQ(r).Insert(data.Event{ + Nullifier: referral.Nullifier, + Type: evTypeRef.Name, + Status: data.EventFulfilled, + Meta: data.Jsonb(fmt.Sprintf(`{"nullifier": "%s"}`, balance.Nullifier)), }) +} +func getOrCreateCountry(q data.CountriesQ, proof zkptypes.ZKProof) (*data.Country, error) { + code := extractCountry(proof) + if code == "" { + return nil, errors.New("country pub signal is not decimal big integer") + } + + c, err := q.FilterByCodes(code).Get() if err != nil { - Log(r).WithError(err).Error("Failed to add referral event and update verify passport event") - ape.RenderErr(w, problems.InternalError()) - return + return nil, fmt.Errorf("get country by code: %w", err) + } + if c != nil { + return c, nil } - w.WriteHeader(http.StatusNoContent) + def, err := q.New().FilterByCodes(data.DefaultCountryCode).Get() + if err != nil { + return nil, fmt.Errorf("get default country: %w", err) + } + if def == nil { + return nil, errors.New("default country does not exist in DB") + } + + c = &data.Country{ + Code: code, + ReserveLimit: def.ReserveLimit, + ReserveAllowed: def.ReserveAllowed, + WithdrawalAllowed: def.WithdrawalAllowed, + } + + if err = q.New().Insert(*c); err != nil { + return nil, fmt.Errorf("insert country with default values: %w", err) + } + + return c, nil } -func decodeInt(s string) string { - b, ok := new(big.Int).SetString(s, 10) +// extractCountry extracts 3-letter country code from the proof. +// +// TODO: think about some validation and case normalization, because we don't +// know what values we may encounter, resulting to applying default settings when +// we must not do it. For example, if we specify 'USA' in forbidden countries, +// but the proof contains 'usa', this situation is unpleasant. +func extractCountry(proof zkptypes.ZKProof) string { + b, ok := new(big.Int).SetString(proof.PubSignals[zk.Citizenship], 10) if !ok { b = new(big.Int) } diff --git a/internal/service/handlers/withdraw.go b/internal/service/handlers/withdraw.go index ff4035b..26fd52e 100644 --- a/internal/service/handlers/withdraw.go +++ b/internal/service/handlers/withdraw.go @@ -1,30 +1,21 @@ package handlers import ( - "encoding/json" "fmt" - "math/big" "net/http" cosmos "github.com/cosmos/cosmos-sdk/types" bank "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/ethereum/go-ethereum/common/hexutil" validation "github.com/go-ozzo/ozzo-validation/v4" - zkptypes "github.com/iden3/go-rapidsnark/types" - "github.com/rarimo/decentralized-auth-svc/pkg/auth" + "github.com/google/jsonapi" "github.com/rarimo/rarime-points-svc/internal/data" - "github.com/rarimo/rarime-points-svc/internal/data/evtypes" "github.com/rarimo/rarime-points-svc/internal/data/pg" "github.com/rarimo/rarime-points-svc/internal/service/requests" "github.com/rarimo/rarime-points-svc/resources" - zk "github.com/rarimo/zkverifier-kit" "gitlab.com/distributed_lab/ape" "gitlab.com/distributed_lab/ape/problems" - "gitlab.com/distributed_lab/logan/v3/errors" ) -const usaAuthorithy = "8571562" - func Withdraw(w http.ResponseWriter, r *http.Request) { req, err := requests.NewWithdraw(r) if err != nil { @@ -38,133 +29,46 @@ func Withdraw(w http.ResponseWriter, r *http.Request) { }) if PointPrice(r).Disabled { - log.Debug("Withdrawal disabled!") + log.Debug("Withdrawal is disabled") ape.RenderErr(w, problems.Forbidden()) return } - nullifier := req.Data.ID + var ( + nullifier = req.Data.ID + proof = req.Data.Attributes.Proof + ) - if !auth.Authenticates(UserClaims(r), auth.UserGrant(nullifier)) { - ape.RenderErr(w, problems.Unauthorized()) + balance, errs := getAndVerifyBalanceEligibility(r, nullifier, &proof) + if len(errs) > 0 { + ape.RenderErr(w, errs...) return } - balance, err := BalancesQ(r).FilterByNullifier(nullifier).Get() + country, err := getOrCreateCountry(CountriesQ(r), proof) // +1 query is not critical if err != nil { - log.WithError(err).Error("Failed to get balance by nullifier") + log.WithError(err).Error("Failed to get or create country") ape.RenderErr(w, problems.InternalError()) return } - if balance == nil { - ape.RenderErr(w, problems.NotFound()) - return - } - - var proof zkptypes.ZKProof - if err = json.Unmarshal(req.Data.Attributes.Proof, &proof); err != nil { - ape.RenderErr(w, problems.BadRequest(err)...) + errs = isEligibleToWithdraw(r, balance, req.Data.Attributes.Amount, *country) + if len(errs) > 0 { + ape.RenderErr(w, errs...) return } - // MustDecode will never panic, because of the previous logic - proof.PubSignals[zk.Nullifier] = new(big.Int).SetBytes(hexutil.MustDecode(nullifier)).String() - if err := Verifier(r).VerifyProof(proof, zk.WithProofSelectorValue("23073")); err != nil { - ape.RenderErr(w, problems.BadRequest(err)...) - return - } - - // Fulfill passport scan event for user and give points for referred - evType := EventTypes(r).Get(evtypes.TypePassportScan, evtypes.FilterInactive) - logMsg := "Passport scan event absent, disabled, hasn't start yet or expired" - if evType != nil { - event, err := EventsQ(r).FilterByNullifier(nullifier). - FilterByType(evtypes.TypePassportScan). - FilterByStatus(data.EventOpen).Get() - if err != nil { - Log(r).WithError(err).Error("Failed to get passport scan event") - ape.RenderErr(w, problems.InternalError()) - return - } - - if event == nil { - logMsg = "Passport scan event already fulfilled or absent for user" - } - - evType = EventTypes(r).Get(evtypes.TypeReferralSpecific, evtypes.FilterInactive) - if evType == nil { - Log(r).Debug("Referral event type is disabled or expired, not accruing points to referrer") - } - - err = EventsQ(r).Transaction(func() (err error) { - if evType != nil { - // ReferredBy always valid because of the previous logic - referral, err := ReferralsQ(r).Get(balance.ReferredBy.String) - if err != nil { - return fmt.Errorf("failed to get referral by ID: %w", err) - } - - err = EventsQ(r).Insert(data.Event{ - Nullifier: referral.Nullifier, - Type: evType.Name, - Status: data.EventFulfilled, - Meta: data.Jsonb(fmt.Sprintf(`{"nullifier": "%s"}`, nullifier)), - }) - if err != nil { - return fmt.Errorf("add event for referrer: %w", err) - } - } - - if event != nil { - _, err = EventsQ(r). - FilterByID(event.ID). - Update(data.EventFulfilled, nil, nil) - if err != nil { - return fmt.Errorf("failed to update passport scan event: %w", err) - } - - countryCode := decodeInt(proof.PubSignals[zk.Citizenship]) - if country, ok := Countries(r)[countryCode]; !ok { - err = CountriesQ(r).Insert(data.Country{Code: countryCode, - ReserveLimit: country.ReserveLimit, - ReserveAllowed: country.ReserveAllowed, - WithdrawalAllowed: country.WithdrawalAllowed}) - if err != nil { - return fmt.Errorf("failed to inser new country: %w", err) - } - } - if err = BalancesQ(r). - FilterByNullifier(nullifier). - Update(map[string]any{"country": countryCode}); err != nil { - return fmt.Errorf("failed to update country: %w", err) - } + var withdrawal *data.Withdrawal + err = EventsQ(r).Transaction(func() error { + // If user hasn't provided passport proof yet, do all the necessary updates to + // potentially reduce the number of proofs in UX + if balance.Country == nil { + if err = doPassportScanUpdates(r, *balance, req.Data.Attributes.Proof); err != nil { + return fmt.Errorf("do passport scan updates: %w", err) } - - return nil - }) - - if err != nil { - Log(r).WithError(err).Error("Failed to add referral event and update verify passport event") - ape.RenderErr(w, problems.InternalError()) - return + log.Debug("Successfully performed passport scan updates for the first time") } - } - Log(r).Debug(logMsg) - - if proof.PubSignals[zk.Citizenship] == usaAuthorithy { - ape.RenderErr(w, problems.BadRequest(validation.Errors{"authority": errors.New("Incorrect authority")})...) - return - } - - if err = isEligibleToWithdraw(r, balance, req.Data.Attributes.Amount); err != nil { - ape.RenderErr(w, problems.BadRequest(err)...) - return - } - - var withdrawal *data.Withdrawal - err = EventsQ(r).Transaction(func() error { err = BalancesQ(r).FilterByNullifier(nullifier).Update(map[string]any{ data.ColAmount: pg.AddToValue(data.ColAmount, -req.Data.Attributes.Amount), }) @@ -184,6 +88,7 @@ func Withdraw(w http.ResponseWriter, r *http.Request) { if err = broadcastWithdrawalTx(req, r); err != nil { return fmt.Errorf("broadcast transfer tx: %w", err) } + return nil }) @@ -222,20 +127,28 @@ func newWithdrawResponse(w data.Withdrawal, balance data.Balance) *resources.Wit return &resp } -func isEligibleToWithdraw(r *http.Request, balance *data.Balance, amount int64) error { - mapValidationErr := func(field, format string, a ...any) validation.Errors { - return validation.Errors{ +func isEligibleToWithdraw( + r *http.Request, + balance *data.Balance, + amount int64, + country data.Country, +) []*jsonapi.ErrorObject { + + mapValidationErr := func(field, format string, a ...any) []*jsonapi.ErrorObject { + return problems.BadRequest(validation.Errors{ field: fmt.Errorf(format, a...), - } + }) } switch { - case !balance.ReferredBy.Valid: - return mapValidationErr("is_disabled", "user must be referred to withdraw") case balance.Amount < amount: return mapValidationErr("data/attributes/amount", "insufficient balance: %d", balance.Amount) + case !country.WithdrawalAllowed: + return mapValidationErr("country", "withdrawal is not allowed for country=%s", country.Code) case !Levels(r)[balance.Level].WithdrawalAllowed: - return mapValidationErr("withdrawal not allowed", "user must up level to have withdraw ability") + return mapValidationErr("level", "must up level to have withdraw ability") + case balance.Country != nil && *balance.Country != country.Code: + return mapValidationErr("country", "country mismatch in proof and balance: %s", *balance.Country) } return nil diff --git a/resources/model_verify_passport_attributes.go b/resources/model_verify_passport_attributes.go index af00563..cb28054 100644 --- a/resources/model_verify_passport_attributes.go +++ b/resources/model_verify_passport_attributes.go @@ -4,9 +4,9 @@ package resources -import "encoding/json" +import "github.com/iden3/go-rapidsnark/types" type VerifyPassportAttributes struct { - // JSON encoded ZK passport verification proof. - Proof json.RawMessage `json:"proof"` + // Iden3 ZK passport verification proof. + Proof types.ZKProof `json:"proof"` } diff --git a/resources/model_withdraw_attributes.go b/resources/model_withdraw_attributes.go index 65a0cdb..c07e3a8 100644 --- a/resources/model_withdraw_attributes.go +++ b/resources/model_withdraw_attributes.go @@ -4,13 +4,13 @@ package resources -import "encoding/json" +import "github.com/iden3/go-rapidsnark/types" type WithdrawAttributes struct { // Rarimo address to withdraw to. Can be any valid address. Address string `json:"address"` // Amount of points to withdraw Amount int64 `json:"amount"` - // JSON encoded ZK passport verification proof. - Proof json.RawMessage `json:"proof"` + // Iden3 ZK passport verification proof. + Proof types.ZKProof `json:"proof"` }