diff --git a/application.yaml b/application.yaml index 666113d..5243a54 100644 --- a/application.yaml +++ b/application.yaml @@ -272,6 +272,7 @@ miner: t1LimitCount: 2 welcomeBonusV2Amount: 500 t1ReferralsAllowedWithoutAnyMiningBoostLevel: false + dryRunDistribution: false kyc/quiz: maxResetCount: 0 maxAttemptsAllowed: 3 @@ -302,6 +303,16 @@ extra-bonus-notifier: balance-synchronizer: workers: 1 batchSize: 100 +users: &users + wintr/connectors/storage/v2: &usersdb + runDDL: false + primaryURL: postgresql://root:pass@localhost:5433/eskimo + timeout: 90s + credentials: + user: root + password: pass + replicaURLs: + - postgresql://root:pass@localhost:5433/eskimo tokenomics_test: <<: *tokenomics messageBroker: diff --git a/coin-distribution/DDL.sql b/coin-distribution/DDL.sql index afa9349..b904fa1 100644 --- a/coin-distribution/DDL.sql +++ b/coin-distribution/DDL.sql @@ -64,8 +64,10 @@ CREATE TABLE IF NOT EXISTS coin_distributions_by_earner ( user_id text NOT NULL, earner_user_id text NOT NULL, eth_address text NOT NULL, + verified boolean NOT NULL DEFAULT FALSE, PRIMARY KEY(day, user_id, earner_user_id)) WITH (FILLFACTOR = 70); +ALTER TABLE coin_distributions_by_earner ADD COLUMN IF NOT EXISTS verified boolean NOT NULL DEFAULT FALSE; CREATE TABLE IF NOT EXISTS coin_distributions_pending_review ( created_at timestamp , @@ -77,7 +79,9 @@ CREATE TABLE IF NOT EXISTS coin_distributions_pending_review ( referred_by_username text NOT NULL, user_id text NOT NULL, eth_address text NOT NULL, + verified boolean NOT NULL DEFAULT FALSE, PRIMARY KEY(day, user_id)); +ALTER TABLE coin_distributions_pending_review ADD COLUMN IF NOT EXISTS verified boolean NOT NULL DEFAULT FALSE; CREATE INDEX IF NOT EXISTS coin_distributions_pending_review_internal_id_ix ON coin_distributions_pending_review (internal_id NULLS FIRST); CREATE INDEX IF NOT EXISTS coin_distributions_pending_review_created_at_ix ON coin_distributions_pending_review (created_at); @@ -105,8 +109,9 @@ CREATE TABLE IF NOT EXISTS reviewed_coin_distributions ( eth_address text NOT NULL, reviewer_user_id text NOT NULL, decision text NOT NULL, + verified boolean NOT NULL DEFAULT FALSE, PRIMARY KEY(user_id, day, review_day)); - +ALTER TABLE reviewed_coin_distributions ADD COLUMN IF NOT EXISTS verified boolean NOT NULL DEFAULT FALSE; create or replace function approve_coin_distributions(reviewer_user_id text, process_immediately boolean, nested boolean) returns RECORD language plpgsql @@ -119,8 +124,8 @@ BEGIN select created_at, internal_id, day, iceflakes, user_id, eth_address from coin_distributions_pending_review; - insert into reviewed_coin_distributions(reviewed_at, created_at, internal_id, ice, day, review_day, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, decision) - select now, created_at, internal_id, ice, day, now::date, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, (case when process_immediately is true then 'approve-and-process-immediately' else 'approve' end) AS reason + insert into reviewed_coin_distributions(reviewed_at, created_at, internal_id, ice, day, review_day, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, decision, verified) + select now, created_at, internal_id, ice, day, now::date, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, (case when process_immediately is true then 'approve-and-process-immediately' else 'approve' end) AS reason, verified from coin_distributions_pending_review; IF process_immediately is true THEN @@ -148,8 +153,8 @@ language plpgsql declare now timestamp := current_timestamp; BEGIN - insert into reviewed_coin_distributions(reviewed_at, created_at, internal_id, ice, day, review_day, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, decision) - select now, created_at, internal_id, ice, day, now::date, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, 'deny' + insert into reviewed_coin_distributions(reviewed_at, created_at, internal_id, ice, day, review_day, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, decision, verified) + select now, created_at, internal_id, ice, day, now::date, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, 'deny', verified from coin_distributions_pending_review; delete from coin_distributions_pending_review where 1=1; @@ -175,8 +180,8 @@ declare BEGIN delete from coin_distributions_by_earner WHERE balance = 0; - insert into coin_distributions_pending_review(created_at, internal_id, ice, day, iceflakes, username, referred_by_username, user_id, eth_address) - SELECT created_at, internal_id, ice, day, (ice::text||zeros)::uint256 AS iceflakes, username, referred_by_username, user_id, eth_address + insert into coin_distributions_pending_review(created_at, internal_id, ice, day, iceflakes, username, referred_by_username, user_id, eth_address, verified) + SELECT created_at, internal_id, ice, day, (ice::text||zeros)::uint256 AS iceflakes, username, referred_by_username, user_id, eth_address, verified FROM (select min (created_at) filter ( where user_id=earner_user_id or internal_id = reward_pool_internal_id) AS created_at, min (internal_id) filter ( where user_id=earner_user_id or internal_id = reward_pool_internal_id) AS internal_id, @@ -185,7 +190,8 @@ BEGIN string_agg(distinct username,'') AS username, string_agg(distinct referred_by_username,'') AS referred_by_username, user_id, - string_agg(distinct eth_address,'') AS eth_address + string_agg(distinct eth_address,'') AS eth_address, + verified from coin_distributions_by_earner group by day,user_id) AS X; @@ -194,8 +200,8 @@ BEGIN WITH del as ( DELETE FROM coin_distributions_pending_review WHERE internal_id IS NULL RETURNING * ) - insert into reviewed_coin_distributions(reviewed_at, created_at, internal_id, ice, day, review_day, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, decision) - select now, COALESCE(created_at,to_timestamp(0)), COALESCE(internal_id,0), ice, day, now::date, iceflakes, username, referred_by_username, user_id, eth_address, 'system', 'deny due to incomplete data' + insert into reviewed_coin_distributions(reviewed_at, created_at, internal_id, ice, day, review_day, iceflakes, username, referred_by_username, user_id, eth_address, reviewer_user_id, decision, verified) + select now, COALESCE(created_at,to_timestamp(0)), COALESCE(internal_id,0), ice, day, now::date, iceflakes, username, referred_by_username, user_id, eth_address, 'system', 'deny due to incomplete data', verified from del; IF nested is false THEN diff --git a/coin-distribution/contract.go b/coin-distribution/contract.go index e54ed46..7d97f00 100644 --- a/coin-distribution/contract.go +++ b/coin-distribution/contract.go @@ -77,6 +77,7 @@ type ( EthAddress string `json:"ethAddress" swaggertype:"string" example:"0x43...."` Ice float64 `json:"ice" db:"-" example:"1000"` IceInternal int64 `json:"-" db:"ice" swaggerignore:"true"` + Verified bool `json:"verified" db:"verified" swaggerignore:"true"` } ByEarnerForReview struct { @@ -88,6 +89,7 @@ type ( EthAddress string InternalID int64 Balance float64 + Verified bool } ) diff --git a/coin-distribution/eligibility.go b/coin-distribution/eligibility.go index e8380b0..2242721 100644 --- a/coin-distribution/eligibility.go +++ b/coin-distribution/eligibility.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/ice-blockchain/eskimo/users" "github.com/ice-blockchain/freezer/model" "github.com/ice-blockchain/wintr/time" ) @@ -47,7 +46,6 @@ func IsEligibleForEthereumDistribution( ethAddress, country string, distributionDeniedCountries map[string]struct{}, now, collectingEndedAt, miningSessionSoloStartedAt, miningSessionSoloEndedAt, ethereumDistributionEndDate *time.Time, - kycState model.KYCState, miningSessionDuration, ethereumDistributionFrequencyMin, ethereumDistributionFrequencyMax stdlibtime.Duration) bool { var countryAllowed bool if _, countryDenied := distributionDeniedCountries[strings.ToLower(country)]; len(distributionDeniedCountries) == 0 || (country != "" && !countryDenied) { @@ -59,8 +57,7 @@ func IsEligibleForEthereumDistribution( !miningSessionSoloEndedAt.IsNil() && (miningSessionSoloEndedAt.After(*collectingEndedAt.Time) || AllowInactiveUsers) && isEthereumAddressValid(ethAddress) && ((minEthereumDistributionICEBalanceRequired > 0 && distributedBalance >= minEthereumDistributionICEBalanceRequired) || (minEthereumDistributionICEBalanceRequired == 0 && distributedBalance > 0)) && //nolint:lll // . - model.CalculateMiningStreak(now, miningSessionSoloStartedAt, miningSessionSoloEndedAt, miningSessionDuration) >= minMiningStreaksRequired && - kycState.KYCStepPassedCorrectly(users.QuizKYCStep) + model.CalculateMiningStreak(now, miningSessionSoloStartedAt, miningSessionSoloEndedAt, miningSessionDuration) >= minMiningStreaksRequired } func IsEligibleForEthereumDistributionNow(id int64, diff --git a/coin-distribution/eligibility_test.go b/coin-distribution/eligibility_test.go index 4852632..1d53f3c 100644 --- a/coin-distribution/eligibility_test.go +++ b/coin-distribution/eligibility_test.go @@ -89,8 +89,6 @@ func TestFinalDistribution(t *testing.T) { assert.False(t, IsEligibleForEthereumDistributionNow(5, now, userAlreadyProcessedLastEthereumProcessedAt, coinDistributionStartDate, lastCollectingProcessedAt, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) balanceRequired := float64(0) - var kycPassed model.KYCState = buildKYC(true, now) - var kycNotPassed model.KYCState = buildKYC(false, now) var collectingEndedAt *time.Time if lastCollectingProcessedAt.IsNil() { collectingEndedAt = time.New(time.Now().Add(-1 * stdlibtime.Millisecond).Add(20 * stdlibtime.Minute)) @@ -98,16 +96,16 @@ func TestFinalDistribution(t *testing.T) { miningSessionDuration := 24 * stdlibtime.Hour activeMiningSessionStarted := time.New(stdlibtime.Date(2024, 2, 25, 0, 0, 0, 0, stdlibtime.UTC)) nonActiveMiningSessionEnded := time.New(stdlibtime.Date(2024, 2, 26, 0, 0, 0, 0, stdlibtime.UTC)) - assert.True(t, IsEligibleForEthereumDistribution(uint64(0), 0.1, balanceRequired, "skip", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, nonActiveMiningSessionEnded, coinDistributionEndDate, kycPassed, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) - assert.True(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "skip", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, nonActiveMiningSessionEnded, coinDistributionEndDate, kycNotPassed, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) - assert.False(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "bogusInvalidAddress", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, nonActiveMiningSessionEnded, coinDistributionEndDate, kycPassed, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) - assert.False(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, nonActiveMiningSessionEnded, coinDistributionEndDate, kycPassed, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) + assert.True(t, IsEligibleForEthereumDistribution(uint64(0), 0.1, balanceRequired, "skip", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, nonActiveMiningSessionEnded, coinDistributionEndDate, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) + assert.True(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "skip", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, nonActiveMiningSessionEnded, coinDistributionEndDate, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) + assert.False(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "bogusInvalidAddress", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, nonActiveMiningSessionEnded, coinDistributionEndDate, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) + assert.False(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, nonActiveMiningSessionEnded, coinDistributionEndDate, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) activeMiningSessionEnded := time.New(stdlibtime.Date(2024, 2, 29, 0, 0, 0, 0, stdlibtime.UTC)) - assert.True(t, IsEligibleForEthereumDistribution(uint64(0), 0.1, balanceRequired, "skip", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, activeMiningSessionEnded, coinDistributionEndDate, kycPassed, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) - assert.True(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "skip", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, activeMiningSessionEnded, coinDistributionEndDate, kycNotPassed, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) - assert.False(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "bogusInvalidAddress", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionEnded, nonActiveMiningSessionEnded, coinDistributionEndDate, kycPassed, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) - assert.False(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, activeMiningSessionEnded, coinDistributionEndDate, kycPassed, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) + assert.True(t, IsEligibleForEthereumDistribution(uint64(0), 0.1, balanceRequired, "skip", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, activeMiningSessionEnded, coinDistributionEndDate, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) + assert.True(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "skip", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, activeMiningSessionEnded, coinDistributionEndDate, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) + assert.False(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "bogusInvalidAddress", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionEnded, nonActiveMiningSessionEnded, coinDistributionEndDate, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) + assert.False(t, IsEligibleForEthereumDistribution(uint64(0), 1, balanceRequired, "", "US", make(map[string]struct{}), now, collectingEndedAt, activeMiningSessionStarted, activeMiningSessionEnded, coinDistributionEndDate, miningSessionDuration, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour)) assert.Equal(t, float64(0), CalculateEthereumDistributionICEBalance(0, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour, now, coinDistributionEndDate)) assert.Equal(t, float64(100), CalculateEthereumDistributionICEBalance(100, 24*stdlibtime.Hour, 24*28*stdlibtime.Hour, now, coinDistributionEndDate)) diff --git a/coin-distribution/pending_review.go b/coin-distribution/pending_review.go index df8dc86..92dbb22 100644 --- a/coin-distribution/pending_review.go +++ b/coin-distribution/pending_review.go @@ -246,7 +246,7 @@ func (r *repository) CollectCoinDistributionsForReview(ctx context.Context, reco log.Warn(fmt.Sprintf("(%#v) is a duplicate of (%#v)", record, otherRecord)) } } - const columns = 9 + const columns = 10 values := make([]string, 0, len(records)) args := make([]any, 0, len(records)*columns) ix := 0 @@ -261,10 +261,11 @@ func (r *repository) CollectCoinDistributionsForReview(ctx context.Context, reco record.ReferredByUsername, record.UserID, record.EarnerUserID, - record.EthAddress) + record.EthAddress, + record.Verified) ix++ } - sql := fmt.Sprintf(`INSERT INTO coin_distributions_by_earner(created_at,day,internal_id,balance,username,referred_by_username,user_id,earner_user_id,eth_address) + sql := fmt.Sprintf(`INSERT INTO coin_distributions_by_earner(created_at,day,internal_id,balance,username,referred_by_username,user_id,earner_user_id,eth_address,verified) VALUES %v ON CONFLICT (day, user_id, earner_user_id) DO UPDATE SET @@ -272,7 +273,8 @@ func (r *repository) CollectCoinDistributionsForReview(ctx context.Context, reco balance = EXCLUDED.balance, username = EXCLUDED.username, referred_by_username = EXCLUDED.referred_by_username, - eth_address = EXCLUDED.eth_address`, strings.Join(values, ",\n")) + eth_address = EXCLUDED.eth_address, + verified = EXCLUDED.verified`, strings.Join(values, ",\n")) _, err := storage.Exec(ctx, r.db, sql, args...) return errors.Wrapf(err, "failed to insert into coin_distributions_by_earner [%v]", len(records)) diff --git a/go.mod b/go.mod index 1990ce5..428158d 100644 --- a/go.mod +++ b/go.mod @@ -22,19 +22,19 @@ require ( github.com/swaggo/swag v1.16.4 github.com/testcontainers/testcontainers-go v0.34.0 go.uber.org/zap v1.27.0 - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f + golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d ) require ( cel.dev/expr v0.19.0 // indirect cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.11.0 // indirect + cloud.google.com/go/auth v0.12.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/firestore v1.17.0 // indirect - cloud.google.com/go/iam v1.2.2 // indirect + cloud.google.com/go/iam v1.3.0 // indirect cloud.google.com/go/longrunning v0.6.3 // indirect - cloud.google.com/go/monitoring v1.21.2 // indirect + cloud.google.com/go/monitoring v1.22.0 // indirect cloud.google.com/go/storage v1.47.0 // indirect cosmossdk.io/math v1.4.0 // indirect dario.cat/mergo v1.0.1 // indirect @@ -203,21 +203,21 @@ require ( go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.12.0 // indirect - golang.org/x/crypto v0.29.0 // indirect + golang.org/x/crypto v0.30.0 // indirect golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.31.0 // indirect + golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.8.0 // indirect - golang.org/x/tools v0.27.0 // indirect - google.golang.org/api v0.209.0 // indirect + golang.org/x/tools v0.28.0 // indirect + google.golang.org/api v0.210.0 // indirect google.golang.org/appengine/v2 v2.0.6 // indirect google.golang.org/genproto v0.0.0-20241202173237-19429a94021a // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect - google.golang.org/grpc v1.68.0 // indirect + google.golang.org/grpc v1.68.1 // indirect google.golang.org/grpc/stats/opentelemetry v0.0.0-20241028142157-ada6787961b3 // indirect google.golang.org/protobuf v1.35.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 3e7c929..bc39808 100644 --- a/go.sum +++ b/go.sum @@ -3,22 +3,22 @@ cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.11.0 h1:Ic5SZz2lsvbYcWT5dfjNWgw6tTlGi2Wc8hyQSC9BstA= -cloud.google.com/go/auth v0.11.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth v0.12.0 h1:ARAD8r0lkiHw2go7kEnmviF6TOYhzLM+yDGcDt9mP68= +cloud.google.com/go/auth v0.12.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/firestore v1.17.0 h1:iEd1LBbkDZTFsLw3sTH50eyg4qe8eoG6CjocmEXO9aQ= cloud.google.com/go/firestore v1.17.0/go.mod h1:69uPx1papBsY8ZETooc71fOhoKkD70Q1DwMrtKuOT/Y= -cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= -cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= +cloud.google.com/go/iam v1.3.0 h1:4Wo2qTaGKFtajbLpF6I4mywg900u3TLlHDb6mriLDPU= +cloud.google.com/go/iam v1.3.0/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= cloud.google.com/go/logging v1.12.0 h1:ex1igYcGFd4S/RZWOCU51StlIEuey5bjqwH9ZYjHibk= cloud.google.com/go/logging v1.12.0/go.mod h1:wwYBt5HlYP1InnrtYI0wtwttpVU1rifnMT7RejksUAM= cloud.google.com/go/longrunning v0.6.3 h1:A2q2vuyXysRcwzqDpMMLSI6mb6o39miS52UEG/Rd2ng= cloud.google.com/go/longrunning v0.6.3/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= -cloud.google.com/go/monitoring v1.21.2 h1:FChwVtClH19E7pJ+e0xUhJPGksctZNVOk2UhMmblmdU= -cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= +cloud.google.com/go/monitoring v1.22.0 h1:mQ0040B7dpuRq1+4YiQD43M2vW9HgoVxY98xhqGT+YI= +cloud.google.com/go/monitoring v1.22.0/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= cloud.google.com/go/storage v1.47.0 h1:ajqgt30fnOMmLfWfu1PWcb+V9Dxz6n+9WKjdNg5R4HM= cloud.google.com/go/storage v1.47.0/go.mod h1:Ks0vP374w0PW6jOUameJbapbQKXqkjGd/OJRp2fb9IQ= cloud.google.com/go/trace v1.11.2 h1:4ZmaBdL8Ng/ajrgKqY5jfvzqMXbrDcBsUGXOT9aqTtI= @@ -593,11 +593,11 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0= +golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -623,8 +623,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= @@ -674,8 +674,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -688,15 +688,15 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= -golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.209.0 h1:Ja2OXNlyRlWCWu8o+GgI4yUn/wz9h/5ZfFbKz+dQX+w= -google.golang.org/api v0.209.0/go.mod h1:I53S168Yr/PNDNMi5yPnDc0/LGRZO6o7PoEbl/HY3CM= +google.golang.org/api v0.210.0 h1:HMNffZ57OoZCRYSbdWVRoqOa8V8NIHLL0CzdBPLztWk= +google.golang.org/api v0.210.0/go.mod h1:B9XDZGnx2NtyjzVkOVTGrFSAVZgPcbedzKg/gTLwqBs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine/v2 v2.0.6 h1:LvPZLGuchSBslPBp+LAhihBeGSiRh1myRoYK4NtuBIw= @@ -715,8 +715,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= -google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= +google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/grpc/stats/opentelemetry v0.0.0-20241028142157-ada6787961b3 h1:hUfOButuEtpc0UvYiaYRbNwxVYr0mQQOWq6X8beJ9Gc= google.golang.org/grpc/stats/opentelemetry v0.0.0-20241028142157-ada6787961b3/go.mod h1:jzYlkSMbKypzuu6xoAEijsNVo9ZeDF1u/zCfFgsx7jg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/miner/contract.go b/miner/contract.go index 8f2a92e..d016d33 100644 --- a/miner/contract.go +++ b/miner/contract.go @@ -10,6 +10,7 @@ import ( stdlibtime "time" "github.com/ice-blockchain/eskimo/kyc/quiz" + "github.com/ice-blockchain/eskimo/users" dwh "github.com/ice-blockchain/freezer/bookkeeper/storage" coindistribution "github.com/ice-blockchain/freezer/coin-distribution" "github.com/ice-blockchain/freezer/model" @@ -131,6 +132,11 @@ type ( model.SlashingRateForT0Field model.SlashingRateForTMinus1Field model.ExtraBonusDaysClaimNotAvailableField + model.PhoneNumberField + model.EmailField + model.DistributionScenariosVerifiedField + model.TelegramUserIDField + model.TelegramBotIDField } referralUpdated struct { model.DeserializedUsersKey @@ -163,6 +169,11 @@ type ( model.BalanceT2EthereumField model.PreStakingAllocationField model.PreStakingBonusField + model.PhoneNumberField + model.EmailField + model.DistributionScenariosVerifiedField + model.TelegramUserIDField + model.TelegramBotIDField } referralCountGuardUpdatedUser struct { @@ -194,6 +205,7 @@ type ( coinDistributionWorkerMX *sync.Mutex coinDistributionRepository coindistribution.Repository quizRepository quiz.ReadRepository + usersRepository users.Repository mb messagebroker.Client db storage.DB dwhClient dwh.Client @@ -220,5 +232,6 @@ type ( SlashingDaysCount int64 `yaml:"slashingDaysCount"` Development bool `yaml:"development"` T1ReferralsAllowedWithoutAnyMiningBoostLevel bool `yaml:"t1ReferralsAllowedWithoutAnyMiningBoostLevel" mapstructure:"t1ReferralsAllowedWithoutAnyMiningBoostLevel"` + DryRunDistribution bool `yaml:"dryRunDistribution" mapstructure:"dryRunDistribution"` } ) diff --git a/miner/ethereum_distribution.go b/miner/ethereum_distribution.go index d654483..f63e29f 100644 --- a/miner/ethereum_distribution.go +++ b/miner/ethereum_distribution.go @@ -26,11 +26,22 @@ func (ref *referral) username() string { return "icenetwork/bogus" } -func (ref *referral) isEligibleForSelfForEthereumDistribution(now, lastEthereumCoinDistributionProcessedAt *time.Time) bool { +func (ref *referral) isEligibleForSelfForEthereumDistribution(now, lastEthereumCoinDistributionProcessedAt *time.Time, selfVerified bool) bool { + if ref == nil { + return false + } coinDistributionCollectorSettings := cfg.coinDistributionCollectorSettings.Load() + miningBlockchainAccountAddress := ref.MiningBlockchainAccountAddress + if ref.isVerified() { + if !selfVerified { + return false + } + } else { + miningBlockchainAccountAddress = "skip" + } - return ref != nil && - ref.ID != 0 && + return ref.ID != 0 && + ref.isMandatoryFieldsSetForDistributionValid() && coindistribution.IsEligibleForEthereumDistributionNow( ref.ID, now, @@ -43,7 +54,7 @@ func (ref *referral) isEligibleForSelfForEthereumDistribution(now, lastEthereumC coinDistributionCollectorSettings.MinMiningStreaksRequired, ref.BalanceTotalStandard-ref.BalanceSoloEthereum-ref.BalanceT0Ethereum-ref.BalanceT1Ethereum-ref.BalanceT2Ethereum, coinDistributionCollectorSettings.MinBalanceRequired, - ref.MiningBlockchainAccountAddress, + miningBlockchainAccountAddress, ref.Country, coinDistributionCollectorSettings.DeniedCountries, now, @@ -51,17 +62,20 @@ func (ref *referral) isEligibleForSelfForEthereumDistribution(now, lastEthereumC ref.MiningSessionSoloStartedAt, ref.MiningSessionSoloEndedAt, coinDistributionCollectorSettings.EndDate, - ref.KYCState, cfg.MiningSessionDuration.Max, cfg.EthereumDistributionFrequency.Min, cfg.EthereumDistributionFrequency.Max) } -func (ref *referral) isEligibleForReferralForEthereumDistribution(now *time.Time) bool { +func (ref *referral) isEligibleForReferralForEthereumDistribution(now *time.Time, selfVerified bool) bool { coinDistributionCollectorSettings := cfg.coinDistributionCollectorSettings.Load() + if selfVerified && !ref.isVerified() { + return false + } return ref != nil && ref.ID != 0 && + ref.isMandatoryFieldsSetForDistributionValid() && coindistribution.IsEligibleForEthereumDistribution( 0, 0.1, @@ -74,17 +88,23 @@ func (ref *referral) isEligibleForReferralForEthereumDistribution(now *time.Time ref.MiningSessionSoloStartedAt, ref.MiningSessionSoloEndedAt, coinDistributionCollectorSettings.EndDate, - ref.KYCState, cfg.MiningSessionDuration.Max, cfg.EthereumDistributionFrequency.Min, cfg.EthereumDistributionFrequency.Max) } -func (u *user) isEligibleForSelfForEthereumDistribution(now *time.Time) bool { +func (u *user) isEligibleForSelfForEthereumDistribution(now *time.Time, selfVerified bool) bool { + if u == nil { + return false + } coinDistributionCollectorSettings := cfg.coinDistributionCollectorSettings.Load() + miningBlockchainAccountAddress := u.MiningBlockchainAccountAddress + if !selfVerified { + miningBlockchainAccountAddress = "skip" + } - return u != nil && - u.ID != 0 && + return u.ID != 0 && + u.isMandatoryFieldsSetForDistributionValid() && coindistribution.IsEligibleForEthereumDistributionNow( u.ID, now, @@ -97,7 +117,7 @@ func (u *user) isEligibleForSelfForEthereumDistribution(now *time.Time) bool { coinDistributionCollectorSettings.MinMiningStreaksRequired, u.BalanceTotalStandard-u.BalanceSoloEthereum-u.BalanceT0Ethereum-u.BalanceT1Ethereum-u.BalanceT2Ethereum, coinDistributionCollectorSettings.MinBalanceRequired, - u.MiningBlockchainAccountAddress, + miningBlockchainAccountAddress, u.Country, coinDistributionCollectorSettings.DeniedCountries, now, @@ -105,7 +125,6 @@ func (u *user) isEligibleForSelfForEthereumDistribution(now *time.Time) bool { u.MiningSessionSoloStartedAt, u.MiningSessionSoloEndedAt, coinDistributionCollectorSettings.EndDate, - u.KYCState, cfg.MiningSessionDuration.Max, cfg.EthereumDistributionFrequency.Min, cfg.EthereumDistributionFrequency.Max) @@ -114,6 +133,7 @@ func (u *user) isEligibleForSelfForEthereumDistribution(now *time.Time) bool { func (u *user) isEligibleForT0ForEthereumDistribution(now *time.Time, idT0 int64) bool { return u != nil && u.ID != 0 && + u.isMandatoryFieldsSetForDistributionValid() && coindistribution.IsEligibleForEthereumDistributionNow( idT0, now, @@ -128,6 +148,7 @@ func (u *user) isEligibleForT0ForEthereumDistribution(now *time.Time, idT0 int64 func (u *user) isEligibleForTMinus1ForEthereumDistribution(now *time.Time, idTMinus1 int64) bool { return u != nil && u.ID != 0 && + u.isMandatoryFieldsSetForDistributionValid() && coindistribution.IsEligibleForEthereumDistributionNow( idTMinus1, now, @@ -153,18 +174,17 @@ func (u *user) isEligibleForReferralForEthereumDistribution(now *time.Time) bool u.MiningSessionSoloStartedAt, u.MiningSessionSoloEndedAt, coinDistributionCollectorSettings.EndDate, - u.KYCState, cfg.MiningSessionDuration.Max, cfg.EthereumDistributionFrequency.Min, cfg.EthereumDistributionFrequency.Max) } func (u *user) couldHaveBeenEligibleForEthereumDistributionRecently(now *time.Time) bool { - return u != nil && !u.MiningSessionSoloEndedAt.IsNil() && u.KYCStepPassedCorrectly(users.QuizKYCStep) && (u.MiningSessionSoloEndedAt.After(now.Add(-(cfg.MiningSessionDuration.Max / 8))) || coindistribution.AllowInactiveUsers) //nolint:lll // . + return u != nil && !u.MiningSessionSoloEndedAt.IsNil() && (u.MiningSessionSoloEndedAt.After(now.Add(-(cfg.MiningSessionDuration.Max / 8))) || coindistribution.AllowInactiveUsers) //nolint:lll // . } func (ref *referral) couldHaveBeenEligibleForEthereumDistributionRecently(now *time.Time) bool { - return ref != nil && !ref.MiningSessionSoloEndedAt.IsNil() && ref.KYCStepPassedCorrectly(users.QuizKYCStep) && (ref.MiningSessionSoloEndedAt.After(now.Add(-(cfg.MiningSessionDuration.Max / 8))) || coindistribution.AllowInactiveUsers) //nolint:lll // . + return ref != nil && !ref.MiningSessionSoloEndedAt.IsNil() && (ref.MiningSessionSoloEndedAt.After(now.Add(-(cfg.MiningSessionDuration.Max / 8))) || coindistribution.AllowInactiveUsers) //nolint:lll // . } //nolint:funlen // . @@ -220,18 +240,22 @@ func (u *user) processEthereumCoinDistribution( EthAddress: u.MiningBlockchainAccountAddress, InternalID: u.ID, Balance: 0, + Verified: u.isVerified(), } - soloMainnetRewardPoolContributionCD = &coindistribution.ByEarnerForReview{ - CreatedAt: now, - Username: mainnetRewardPoolContributionIdentifier, - ReferredByUsername: mainnetRewardPoolContributionIdentifier, - UserID: mainnetRewardPoolContributionIdentifier, - EarnerUserID: fmt.Sprintf("(%v,%v)", u.UserID, u.UserID), - EthAddress: cfg.MainnetRewardPoolContributionEthAddress, - InternalID: 999999999, - Balance: 0, + records = append(records, soloCD) + if cfg.MainnetRewardPoolContributionPercentage > 0 { + soloMainnetRewardPoolContributionCD = &coindistribution.ByEarnerForReview{ + CreatedAt: now, + Username: mainnetRewardPoolContributionIdentifier, + ReferredByUsername: mainnetRewardPoolContributionIdentifier, + UserID: mainnetRewardPoolContributionIdentifier, + EarnerUserID: fmt.Sprintf("(%v,%v)", u.UserID, u.UserID), + EthAddress: cfg.MainnetRewardPoolContributionEthAddress, + InternalID: 999999999, + Balance: 0, + } + records = append(records, soloMainnetRewardPoolContributionCD) } - records = append(records, soloCD, soloMainnetRewardPoolContributionCD) } if u.couldHaveBeenEligibleForEthereumDistributionRecently(now) && t0.couldHaveBeenEligibleForEthereumDistributionRecently(now) && t0 != nil && t0.UserID != u.UserID && (tMinus1 == nil || (tMinus1.UserID != u.UserID && tMinus1.UserID != t0.UserID)) { //nolint:lll // . if wasNotProcessedToday(now, u.SoloLastEthereumCoinDistributionProcessedAt) { @@ -240,14 +264,18 @@ func (u *user) processEthereumCoinDistribution( UserID: u.UserID, EarnerUserID: t0.UserID, Balance: 0, + Verified: u.isVerified(), } - t0MainnetRewardPoolContributionCD = &coindistribution.ByEarnerForReview{ - CreatedAt: now, - UserID: mainnetRewardPoolContributionIdentifier, - EarnerUserID: fmt.Sprintf("(%v,%v)", u.UserID, t0.UserID), - Balance: 0, + records = append(records, t0CD) + if cfg.MainnetRewardPoolContributionPercentage > 0 { + t0MainnetRewardPoolContributionCD = &coindistribution.ByEarnerForReview{ + CreatedAt: now, + UserID: mainnetRewardPoolContributionIdentifier, + EarnerUserID: fmt.Sprintf("(%v,%v)", u.UserID, t0.UserID), + Balance: 0, + } + records = append(records, t0MainnetRewardPoolContributionCD) } - records = append(records, t0CD, t0MainnetRewardPoolContributionCD) } if wasNotProcessedToday(now, u.ForT0LastEthereumCoinDistributionProcessedAt) { forT0CD = &coindistribution.ByEarnerForReview{ @@ -255,48 +283,60 @@ func (u *user) processEthereumCoinDistribution( UserID: t0.UserID, EarnerUserID: u.UserID, Balance: 0, + Verified: t0.isVerified(), } - forT0MainnetRewardPoolContributionCD = &coindistribution.ByEarnerForReview{ - CreatedAt: now, - UserID: mainnetRewardPoolContributionIdentifier, - EarnerUserID: fmt.Sprintf("(%v,%v)", t0.UserID, u.UserID), - Balance: 0, + records = append(records, forT0CD) + if cfg.MainnetRewardPoolContributionPercentage > 0 { + forT0MainnetRewardPoolContributionCD = &coindistribution.ByEarnerForReview{ + CreatedAt: now, + UserID: mainnetRewardPoolContributionIdentifier, + EarnerUserID: fmt.Sprintf("(%v,%v)", t0.UserID, u.UserID), + Balance: 0, + } + records = append(records, forT0MainnetRewardPoolContributionCD) } - records = append(records, forT0CD, forT0MainnetRewardPoolContributionCD) } } - if u.couldHaveBeenEligibleForEthereumDistributionRecently(now) && tMinus1.couldHaveBeenEligibleForEthereumDistributionRecently(now) && tMinus1 != nil && tMinus1.UserID != u.UserID && t0 != nil && tMinus1.UserID != t0.UserID && wasNotProcessedToday(now, u.ForTMinus1LastEthereumCoinDistributionProcessedAt) { //nolint:lll // . + if false && u.couldHaveBeenEligibleForEthereumDistributionRecently(now) && tMinus1.couldHaveBeenEligibleForEthereumDistributionRecently(now) && tMinus1 != nil && tMinus1.UserID != u.UserID && t0 != nil && tMinus1.UserID != t0.UserID && wasNotProcessedToday(now, u.ForTMinus1LastEthereumCoinDistributionProcessedAt) { //nolint:lll // . forTMinus1CD = &coindistribution.ByEarnerForReview{ CreatedAt: now, UserID: tMinus1.UserID, EarnerUserID: u.UserID, Balance: 0, + Verified: tMinus1.isVerified(), } - forTMinus1MainnetRewardPoolContributionCD = &coindistribution.ByEarnerForReview{ - CreatedAt: now, - UserID: mainnetRewardPoolContributionIdentifier, - EarnerUserID: fmt.Sprintf("(%v,%v)", tMinus1.UserID, u.UserID), - Balance: 0, + records = append(records, forTMinus1CD) + if cfg.MainnetRewardPoolContributionPercentage > 0 { + forTMinus1MainnetRewardPoolContributionCD = &coindistribution.ByEarnerForReview{ + CreatedAt: now, + UserID: mainnetRewardPoolContributionIdentifier, + EarnerUserID: fmt.Sprintf("(%v,%v)", tMinus1.UserID, u.UserID), + Balance: 0, + } + records = append(records, forTMinus1MainnetRewardPoolContributionCD) } - records = append(records, forTMinus1CD, forTMinus1MainnetRewardPoolContributionCD) } - if u.isEligibleForSelfForEthereumDistribution(now) { + if u.isEligibleForSelfForEthereumDistribution(now, u.isVerified()) { // Amount I've earned for myself. soloCD.Balance = u.processEthereumCoinDistributionForSolo(now) - soloMainnetRewardPoolContributionCD.Balance = soloCD.Balance * cfg.MainnetRewardPoolContributionPercentage - soloCD.Balance -= soloMainnetRewardPoolContributionCD.Balance + if cfg.MainnetRewardPoolContributionPercentage > 0 { + soloMainnetRewardPoolContributionCD.Balance = soloCD.Balance * cfg.MainnetRewardPoolContributionPercentage + soloCD.Balance -= soloMainnetRewardPoolContributionCD.Balance + } totalForSelf := soloCD.Balance - if t0 != nil && t0.UserID != u.UserID && (tMinus1 == nil || (tMinus1.UserID != u.UserID && tMinus1.UserID != t0.UserID)) && t0.isEligibleForReferralForEthereumDistribution(now) { //nolint:lll // . + if t0 != nil && t0.UserID != u.UserID && (tMinus1 == nil || (tMinus1.UserID != u.UserID && tMinus1.UserID != t0.UserID)) && t0.isEligibleForReferralForEthereumDistribution(now, u.isVerified()) { //nolint:lll // . // Amount my T0 earned for me. t0CD.Balance = u.processEthereumCoinDistributionForT0(now) - t0MainnetRewardPoolContributionCD.Balance = t0CD.Balance * cfg.MainnetRewardPoolContributionPercentage - t0CD.Balance -= t0MainnetRewardPoolContributionCD.Balance + if cfg.MainnetRewardPoolContributionPercentage > 0 { + t0MainnetRewardPoolContributionCD.Balance = t0CD.Balance * cfg.MainnetRewardPoolContributionPercentage + t0CD.Balance -= t0MainnetRewardPoolContributionCD.Balance + } totalForSelf += t0CD.Balance } - if totalForSelf > 0 { + if totalForSelf > 0 && !cfg.DryRunDistribution { u.SoloLastEthereumCoinDistributionProcessedAt = now } else { u.SoloLastEthereumCoinDistributionProcessedAt = nil @@ -305,14 +345,16 @@ func (u *user) processEthereumCoinDistribution( u.SoloLastEthereumCoinDistributionProcessedAt = nil } - if t0 != nil && t0.UserID != u.UserID && (tMinus1 == nil || (tMinus1.UserID != u.UserID && tMinus1.UserID != t0.UserID)) && u.isEligibleForT0ForEthereumDistribution(now, t0.ID) && t0.isEligibleForSelfForEthereumDistribution(now, u.ForT0LastEthereumCoinDistributionProcessedAt) { //nolint:lll // . + if t0 != nil && t0.UserID != u.UserID && (tMinus1 == nil || (tMinus1.UserID != u.UserID && tMinus1.UserID != t0.UserID)) && u.isEligibleForT0ForEthereumDistribution(now, t0.ID) && t0.isEligibleForSelfForEthereumDistribution(now, u.ForT0LastEthereumCoinDistributionProcessedAt, u.isVerified()) { //nolint:lll // . // Amount I've earned for my T0. balanceDistributedForT0 = u.processEthereumCoinDistributionForForT0(t0, now) forT0CD.Balance = balanceDistributedForT0 - forT0MainnetRewardPoolContributionCD.Balance = forT0CD.Balance * cfg.MainnetRewardPoolContributionPercentage - forT0CD.Balance -= forT0MainnetRewardPoolContributionCD.Balance + if cfg.MainnetRewardPoolContributionPercentage > 0 { + forT0MainnetRewardPoolContributionCD.Balance = forT0CD.Balance * cfg.MainnetRewardPoolContributionPercentage + forT0CD.Balance -= forT0MainnetRewardPoolContributionCD.Balance + } - if forT0CD.Balance > 0 { + if forT0CD.Balance > 0 && !cfg.DryRunDistribution { u.ForT0LastEthereumCoinDistributionProcessedAt = now } else { u.ForT0LastEthereumCoinDistributionProcessedAt = nil @@ -322,14 +364,16 @@ func (u *user) processEthereumCoinDistribution( u.ForT0LastEthereumCoinDistributionProcessedAt = nil } - if tMinus1 != nil && tMinus1.UserID != u.UserID && t0 != nil && tMinus1.UserID != t0.UserID && u.isEligibleForTMinus1ForEthereumDistribution(now, tMinus1.ID) && tMinus1.isEligibleForSelfForEthereumDistribution(now, u.ForTMinus1LastEthereumCoinDistributionProcessedAt) { //nolint:lll // . + if false && tMinus1 != nil && tMinus1.UserID != u.UserID && t0 != nil && tMinus1.UserID != t0.UserID && u.isEligibleForTMinus1ForEthereumDistribution(now, tMinus1.ID) && tMinus1.isEligibleForSelfForEthereumDistribution(now, u.ForTMinus1LastEthereumCoinDistributionProcessedAt, u.isVerified()) { //nolint:lll // . // Amount I've earned for my T-1. balanceDistributedForTMinus1 = u.processEthereumCoinDistributionForForTMinus1(tMinus1, now) forTMinus1CD.Balance = balanceDistributedForTMinus1 - forTMinus1MainnetRewardPoolContributionCD.Balance = forTMinus1CD.Balance * cfg.MainnetRewardPoolContributionPercentage - forTMinus1CD.Balance -= forTMinus1MainnetRewardPoolContributionCD.Balance + if cfg.MainnetRewardPoolContributionPercentage > 0 { + forTMinus1MainnetRewardPoolContributionCD.Balance = forTMinus1CD.Balance * cfg.MainnetRewardPoolContributionPercentage + forTMinus1CD.Balance -= forTMinus1MainnetRewardPoolContributionCD.Balance + } - if forTMinus1CD.Balance > 0 { + if forTMinus1CD.Balance > 0 && !cfg.DryRunDistribution { u.ForTMinus1LastEthereumCoinDistributionProcessedAt = now } else { u.ForTMinus1LastEthereumCoinDistributionProcessedAt = nil @@ -355,7 +399,9 @@ func (u *user) processEthereumCoinDistributionForSolo(now *time.Time) float64 { } val := model.FlexibleFloat64(ethIce) - u.BalanceSoloEthereumPending = &val + if !cfg.DryRunDistribution { + u.BalanceSoloEthereumPending = &val + } return ethIce } @@ -368,20 +414,24 @@ func (u *user) processEthereumCoinDistributionForT0(now *time.Time) float64 { } val := model.FlexibleFloat64(ethIce) - u.BalanceT0EthereumPending = &val + if !cfg.DryRunDistribution { + u.BalanceT0EthereumPending = &val + } return ethIce } // The double `For` is intended, cuz it's ForXX, where XX can be Solo/T0/ForT1/ForTMinus1. func (u *user) processEthereumCoinDistributionForForT0(t0 *referral, now *time.Time) float64 { - standard, _ := tokenomics.ApplyPreStaking(u.BalanceForT0, t0.PreStakingAllocation, t0.PreStakingBonus) + standard, _ := tokenomics.ApplyPreStaking(u.BalanceForT0+cfg.WelcomeBonusV2Amount, t0.PreStakingAllocation, t0.PreStakingBonus) ethIce := coindistribution.CalculateEthereumDistributionICEBalance(standard-u.BalanceForT0Ethereum, cfg.EthereumDistributionFrequency.Min, cfg.EthereumDistributionFrequency.Max, now, cfg.coinDistributionCollectorSettings.Load().EndDate) //nolint:lll // . if ethIce <= 0 { return 0 } - u.BalanceForT0Ethereum += ethIce + if !cfg.DryRunDistribution { + u.BalanceForT0Ethereum += ethIce + } return ethIce } @@ -394,7 +444,9 @@ func (u *user) processEthereumCoinDistributionForForTMinus1(tMinus1 *referral, n return 0 } - u.BalanceForTMinus1Ethereum += ethIce + if !cfg.DryRunDistribution { + u.BalanceForTMinus1Ethereum += ethIce + } return ethIce } @@ -550,3 +602,21 @@ func currentCoinDistributionCollectingEndedAt() *time.Time { return time.New(coinDistributionCollectorStartedAt.Add(startingWindow)) } + +func (u *user) isMandatoryFieldsSetForDistributionValid() bool { + return (u.PhoneNumber != "" && u.PhoneNumber != u.UserID) || (u.Email != "" && u.Email != u.UserID) || + (u.TelegramUserID != "" && u.TelegramBotID != u.UserID && u.TelegramBotID != "" && u.TelegramUserID != u.UserID) +} + +func (r *referral) isMandatoryFieldsSetForDistributionValid() bool { + return (r.PhoneNumber != "" && r.PhoneNumber != r.UserID) || (r.Email != "" && r.Email != r.UserID) || + (r.TelegramUserID != "" && r.TelegramUserID != r.UserID && r.TelegramBotID != "" && r.TelegramBotID != r.UserID) +} + +func (r *referral) isVerified() bool { + return r.KYCStepPassedCorrectly(users.QuizKYCStep) && r.DistributionScenariosVerified +} + +func (u *user) isVerified() bool { + return u.KYCStepPassedCorrectly(users.QuizKYCStep) && u.DistributionScenariosVerified +} diff --git a/miner/miner.go b/miner/miner.go index 06908b0..625e1e2 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -19,6 +19,7 @@ import ( "github.com/redis/go-redis/v9" "github.com/ice-blockchain/eskimo/kyc/quiz" + "github.com/ice-blockchain/eskimo/users" balancesynchronizer "github.com/ice-blockchain/freezer/balance-synchronizer" dwh "github.com/ice-blockchain/freezer/bookkeeper/storage" coindistribution "github.com/ice-blockchain/freezer/coin-distribution" @@ -74,6 +75,9 @@ func MustStartMining(ctx context.Context, cancel context.CancelFunc) Client { mi.cancel = cancel mi.extraBonusStartDate = extrabonusnotifier.MustGetExtraBonusStartDate(ctx, mi.db) mi.mustInitCoinDistributionCollector(ctx) + if isTenantInDistributionMode() { + mi.usersRepository = users.New(context.Background(), nil) + } for workerNumber := int64(0); workerNumber < cfg.Workers; workerNumber++ { go func(wn int64) { @@ -90,13 +94,18 @@ func (m *miner) Close() error { m.wg.Wait() <-m.stopCoinDistributionCollectionWorkerManager - return multierror.Append( + errs := multierror.Append( errors.Wrap(m.mb.Close(), "failed to close mb"), errors.Wrap(m.db.Close(), "failed to close db"), errors.Wrap(m.dwhClient.Close(), "failed to close dwh"), errors.Wrap(m.coinDistributionRepository.Close(), "failed to close coinDistributionRepository"), //errors.Wrap(m.quizRepository.Close(), "failed to close quizClient"), - ).ErrorOrNil() + ) + if isTenantInDistributionMode() { + errs = multierror.Append(errs, errors.Wrap(m.usersRepository.Close(), "failed to close usersRepository")) + } + + return errs.ErrorOrNil() } func (m *miner) CheckHealth(ctx context.Context) error { @@ -156,36 +165,37 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { log.Error(dwhClient.Close()) }() var ( - batchNumber int64 - totalBatches uint64 - iteration uint64 - now, lastIterationStartedAt = time.Now(), time.Now() - workers = cfg.Workers - batchSize = cfg.BatchSize - userKeys, userHistoryKeys, referralKeys, syncQuizUserIDs = make([]string, 0, batchSize), make([]string, 0, batchSize), make([]string, 0, 2*batchSize), make([]string, 0, batchSize) - userResults, referralResults = make([]*user, 0, batchSize), make([]*referral, 0, 2*batchSize) - t0Referrals, tMinus1Referrals = make(map[int64]*referral, batchSize), make(map[int64]*referral, batchSize) - t1ReferralsToIncrementActiveValue, t2ReferralsToIncrementActiveValue = make(map[int64]int32, batchSize), make(map[int64]int32, batchSize) - t1ReferralsThatStoppedMining, t2ReferralsThatStoppedMining = make(map[int64]uint32, batchSize), make(map[int64]uint32, batchSize) - balanceT1EthereumIncr, balanceT2EthereumIncr = make(map[int64]float64, batchSize), make(map[int64]float64, batchSize) - balanceT1WelcomeBonusIncr = make(map[int64]float64, batchSize) - pendingBalancesForTMinus1, pendingBalancesForT0 = make(map[int64]float64, batchSize), make(map[int64]float64, batchSize) - referralsThatStoppedMining = make([]*referralThatStoppedMining, 0, batchSize) - coinDistributions = make([]*coindistribution.ByEarnerForReview, 0, 4*batchSize) - msgResponder = make(chan error, 3*batchSize) - msgs = make([]*messagebroker.Message, 0, 3*batchSize) - errs = make([]error, 0, 3*batchSize) - updatedUsers = make([]*UpdatedUser, 0, batchSize) - extraBonusOnlyUpdatedUsers = make([]*extrabonusnotifier.UpdatedUser, 0, batchSize) - referralsCountGuardOnlyUpdatedUsers = make([]*referralCountGuardUpdatedUser, 0, batchSize) - usersThatStoppedMiningForDistribution = make([]*userThatStoppedMiningForDistribution, 0, batchSize) - referralsUpdated = make([]*referralUpdated, 0, batchSize) - histories = make([]*model.User, 0, batchSize) - quizStatuses = make(map[string]*quiz.QuizStatus, batchSize) - userGlobalRanks = make([]redis.Z, 0, batchSize) - historyColumns, historyInsertMetadata = dwh.InsertDDL(int(batchSize)) - shouldSynchronizeBalanceFunc = func(batchNumberArg uint64) bool { return false } - startedCoinDistributionCollecting = isCoinDistributionCollectorEnabled(now) + batchNumber int64 + totalBatches uint64 + iteration uint64 + now, lastIterationStartedAt = time.Now(), time.Now() + workers = cfg.Workers + batchSize = cfg.BatchSize + userKeys, userHistoryKeys, referralKeys, syncQuizUserIDs, syncMandatoryUserFieldsForDistributionIDs = make([]string, 0, batchSize), make([]string, 0, batchSize), make([]string, 0, 2*batchSize), make([]string, 0, batchSize), make([]string, 0, batchSize) + userResults, referralResults = make([]*user, 0, batchSize), make([]*referral, 0, 2*batchSize) + t0Referrals, tMinus1Referrals = make(map[int64]*referral, batchSize), make(map[int64]*referral, batchSize) + t1ReferralsToIncrementActiveValue, t2ReferralsToIncrementActiveValue = make(map[int64]int32, batchSize), make(map[int64]int32, batchSize) + t1ReferralsThatStoppedMining, t2ReferralsThatStoppedMining = make(map[int64]uint32, batchSize), make(map[int64]uint32, batchSize) + balanceT1EthereumIncr, balanceT2EthereumIncr = make(map[int64]float64, batchSize), make(map[int64]float64, batchSize) + balanceT1WelcomeBonusIncr = make(map[int64]float64, batchSize) + pendingBalancesForTMinus1, pendingBalancesForT0 = make(map[int64]float64, batchSize), make(map[int64]float64, batchSize) + referralsThatStoppedMining = make([]*referralThatStoppedMining, 0, batchSize) + coinDistributions = make([]*coindistribution.ByEarnerForReview, 0, 4*batchSize) + msgResponder = make(chan error, 3*batchSize) + msgs = make([]*messagebroker.Message, 0, 3*batchSize) + errs = make([]error, 0, 3*batchSize) + updatedUsers = make([]*UpdatedUser, 0, batchSize) + extraBonusOnlyUpdatedUsers = make([]*extrabonusnotifier.UpdatedUser, 0, batchSize) + referralsCountGuardOnlyUpdatedUsers = make([]*referralCountGuardUpdatedUser, 0, batchSize) + usersThatStoppedMiningForDistribution = make([]*userThatStoppedMiningForDistribution, 0, batchSize) + referralsUpdated = make([]*referralUpdated, 0, batchSize) + histories = make([]*model.User, 0, batchSize) + quizStatuses = make(map[string]*quiz.QuizStatus, batchSize) + mandatoryUserFieldsForDistributionProfileList = make(map[string]*users.MandatoryForDistributionFieldsProfile, batchSize) + userGlobalRanks = make([]redis.Z, 0, batchSize) + historyColumns, historyInsertMetadata = dwh.InsertDDL(int(batchSize)) + shouldSynchronizeBalanceFunc = func(batchNumberArg uint64) bool { return false } + startedCoinDistributionCollecting = isCoinDistributionCollectorEnabled(now) ) if startedCoinDistributionCollecting { m.coinDistributionStartedSignaler <- struct{}{} @@ -220,6 +230,7 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { userKeys, userHistoryKeys, referralKeys = userKeys[:0], userHistoryKeys[:0], referralKeys[:0] userResults, referralResults = userResults[:0], referralResults[:0] syncQuizUserIDs = syncQuizUserIDs[:0] + syncMandatoryUserFieldsForDistributionIDs = syncMandatoryUserFieldsForDistributionIDs[:0] msgs, errs = msgs[:0], errs[:0] updatedUsers = updatedUsers[:0] extraBonusOnlyUpdatedUsers = extraBonusOnlyUpdatedUsers[:0] @@ -267,6 +278,9 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { for k := range quizStatuses { delete(quizStatuses, k) } + for k := range mandatoryUserFieldsForDistributionProfileList { + delete(mandatoryUserFieldsForDistributionProfileList, k) + } } for ctx.Err() == nil { /****************************************************************************************************************************************************** @@ -374,9 +388,12 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { syncQuizUserIDs = append(syncQuizUserIDs, usr.UserID) userHistoryKeys = append(userHistoryKeys, usr.Key()) } + if isTenantInDistributionMode() && !usr.isMandatoryFieldsSetForDistributionValid() && !usr.MiningSessionSoloStartedAt.IsNil() { + syncMandatoryUserFieldsForDistributionIDs = append(syncMandatoryUserFieldsForDistributionIDs, usr.UserID) + } if updatedUser != nil { - if cfg.Tenant != doctorXTenant { + if !isTenantInDistributionMode() { if userStoppedMining := didUserStoppedMining(now, usr); userStoppedMining != nil { referralsCountGuardOnlyUpdatedUsers = append(referralsCountGuardOnlyUpdatedUsers, userStoppedMining) } @@ -420,7 +437,7 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { if balanceDistributedForTMinus1 > 0 { balanceT2EthereumIncr[tMinus1Ref.ID] += balanceDistributedForTMinus1 } - if cfg.Tenant != doctorXTenant { + if !isTenantInDistributionMode() { if tMinus1Ref != nil && tMinus1Ref.ID != 0 && pendingAmountForTMinus1 != 0 { pendingBalancesForTMinus1[tMinus1Ref.ID] += pendingAmountForTMinus1 } @@ -437,7 +454,7 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { } updatedUsers = append(updatedUsers, &updatedUser.UpdatedUser) } else { - if cfg.Tenant != doctorXTenant { + if !isTenantInDistributionMode() { if updUsr := updateT0AndTMinus1ReferralsForUserHasNeverMined(usr); updUsr != nil { referralsUpdated = append(referralsUpdated, updUsr) if t0Ref != nil && t0Ref.ID != 0 && usr.ActiveT1Referrals > 0 { @@ -446,7 +463,7 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { } } } - if cfg.Tenant != doctorXTenant { + if !isTenantInDistributionMode() { totalStandardBalance, totalPreStakingBalance := usr.BalanceTotalStandard, usr.BalanceTotalPreStaking if updatedUser != nil { totalStandardBalance, totalPreStakingBalance = updatedUser.BalanceTotalStandard, updatedUser.BalanceTotalPreStaking @@ -506,7 +523,7 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { } /****************************************************************************************************************************************************** - 6. Syncing quiz state + 6. Syncing quiz state/syncing mandatory user fields for distribution ******************************************************************************************************************************************************/ before = time.Now() if false && (len(syncQuizUserIDs) > 0 && len(histories) > 0) { @@ -531,6 +548,22 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { go m.telemetry.collectElapsed(6, *before.Time) } } + if len(syncMandatoryUserFieldsForDistributionIDs) > 0 { + reqCtx, reqCancel = context.WithTimeout(context.Background(), requestDeadline) + var err error + mandatoryUserFieldsForDistributionProfileList, err = m.usersRepository.GetMandatoryForDistributionUserFieldsByIDList(reqCtx, syncMandatoryUserFieldsForDistributionIDs) + if err != nil { + log.Error(errors.Wrapf(err, "[miner] failed to sync mandatory fields for distribution (%v entries) batchNumber:%v,workerNumber:%v", len(syncMandatoryUserFieldsForDistributionIDs), batchNumber, workerNumber)) + reqCancel() + resetVars(false) + + continue + } + reqCancel() + if len(mandatoryUserFieldsForDistributionProfileList) > 0 { + go m.telemetry.collectElapsed(6, *before.Time) + } + } /****************************************************************************************************************************************************** 7. Inserting history/bookkeeping data. @@ -625,6 +658,15 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { value.KYCQuizDisabled = &disabled value.KYCQuizCompleted = &completed } + if mandatoryFieldsSync, hasMandatoryFieldsSync := mandatoryUserFieldsForDistributionProfileList[value.UserID]; hasMandatoryFieldsSync && mandatoryFieldsSync != nil { + value.PhoneNumber = mandatoryFieldsSync.PhoneNumber + value.Email = mandatoryFieldsSync.Email + value.TelegramUserID = mandatoryFieldsSync.TelegramUserID + value.TelegramBotID = mandatoryFieldsSync.TelegramBotID + if mandatoryFieldsSync.DistributionScenariosVerified != nil { + value.DistributionScenariosVerified = *mandatoryFieldsSync.DistributionScenariosVerified + } + } if err := pipeliner.HSet(reqCtx, value.Key(), storage.SerializeValue(value)...).Err(); err != nil { return err } @@ -676,7 +718,7 @@ func (m *miner) mine(ctx context.Context, workerNumber int64) { return err } } - if cfg.Tenant == doctorXTenant { + if isTenantInDistributionMode() { for _, value := range usersThatStoppedMiningForDistribution { if err := pipeliner.HSet(reqCtx, value.Key(), storage.SerializeValue(value)...).Err(); err != nil { return err @@ -797,3 +839,7 @@ func didUserStoppedMining(now *time.Time, before *user) *referralCountGuardUpdat return nil } + +func isTenantInDistributionMode() bool { + return cfg.Tenant == doctorXTenant +} diff --git a/miner/mining.go b/miner/mining.go index 5e5b204..8070a5c 100644 --- a/miner/mining.go +++ b/miner/mining.go @@ -17,7 +17,7 @@ func mine(now *time.Time, usr *user, t0Ref, tMinus1Ref *referral) (updatedUser * } clonedUser1 := *usr updatedUser = &clonedUser1 - if cfg.Tenant == doctorXTenant { + if isTenantInDistributionMode() { return updatedUser, false, false, 0, 0 } diff --git a/model/model.go b/model/model.go index 2544c93..ea5bc7d 100644 --- a/model/model.go +++ b/model/model.go @@ -380,6 +380,21 @@ type ( MiningBoostAmountBurntField struct { MiningBoostAmountBurnt *FlexibleFloat64 `json:"miningBoostAmountBurnt" redis:"mining_boost_amount_burnt,omitempty"` } + PhoneNumberField struct { + PhoneNumber string `redis:"phone_number,omitempty" json:"phone_number"` + } + EmailField struct { + Email string `redis:"email,omitempty" json:"email"` + } + DistributionScenariosVerifiedField struct { + DistributionScenariosVerified bool `redis:"distribution_scenarios_verified" json:"distributionScenariosVerified"` + } + TelegramUserIDField struct { + TelegramUserID string `redis:"telegram_user_id,omitempty" json:"telegramUserId"` + } + TelegramBotIDField struct { + TelegramBotID string `redis:"telegram_bot_id,omitempty" json:"telegramBotId"` + } ) type (