Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/phone-number-privacy/signer/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface Config {
additionalVerifiedQueryMax: number
queryPerTransaction: number
minDollarBalance: BigNumber
minEuroBalance: BigNumber
minCeloBalance: BigNumber
}
attestations: {
Expand Down Expand Up @@ -94,6 +95,8 @@ const config: Config = {
queryPerTransaction: toNum(env.QUERY_PER_TRANSACTION) || 2,
// Min balance is .01 cUSD
minDollarBalance: new BigNumber(env.MIN_DOLLAR_BALANCE || 1e16),
// Min balance is .01 cEUR
minEuroBalance: new BigNumber(env.MIN_DOLLAR_BALANCE || 1e16),
// Min balance is .005 CELO
minCeloBalance: new BigNumber(env.MIN_DOLLAR_BALANCE || 5e15),
},
Expand Down
29 changes: 22 additions & 7 deletions packages/phone-number-privacy/signer/src/signing/query-quota.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { retryAsyncWithBackOffAndTimeout } from '@celo/base'
import { NULL_ADDRESS } from '@celo/contractkit'
import { NULL_ADDRESS, StableToken } from '@celo/contractkit'
import {
authenticateUser,
ErrorMessage,
Expand Down Expand Up @@ -159,34 +159,42 @@ async function _getQueryQuota(logger: Logger, account: string, hashedPhoneNumber
.labels('balances')
.startTimer()
let cUSDAccountBalance = new BigNumber(0)
let cEURAccountBalance = new BigNumber(0)
let celoAccountBalance = new BigNumber(0)

await Promise.all([
new Promise((resolve) => {
resolve(getDollarBalance(logger, account, walletAddress))
resolve(getStableTokenBalance(StableToken.cUSD, logger, account, walletAddress))
}),
new Promise((resolve) => {
resolve(getStableTokenBalance(StableToken.cEUR, logger, account, walletAddress))
}),
new Promise((resolve) => {
resolve(getCeloBalance(logger, account, walletAddress))
}),
])
.then((values) => {
cUSDAccountBalance = values[0] as BigNumber
celoAccountBalance = values[1] as BigNumber
cEURAccountBalance = values[1] as BigNumber
celoAccountBalance = values[2] as BigNumber
})
.finally(getBalancesMeter)

// Min balance can be in either cUSD or CELO
// Min balance can be in either cUSD, cEUR or CELO
if (
cUSDAccountBalance.isGreaterThanOrEqualTo(config.quota.minDollarBalance) ||
cEURAccountBalance.isGreaterThanOrEqualTo(config.quota.minEuroBalance) ||
celoAccountBalance.isGreaterThanOrEqualTo(config.quota.minCeloBalance)
) {
Counters.requestsWithUnverifiedAccountWithMinBalance.inc()
logger.debug(
{
account,
cUSDAccountBalance,
cEURAccountBalance,
celoAccountBalance,
minDollarBalance: config.quota.minDollarBalance,
minEuroBalance: config.quota.minEuroBalance,
minCeloBalance: config.quota.minCeloBalance,
},
'Account is not verified but meets min balance'
Expand All @@ -208,8 +216,10 @@ async function _getQueryQuota(logger: Logger, account: string, hashedPhoneNumber
logger.trace({
account,
cUSDAccountBalance,
cEURAccountBalance,
celoAccountBalance,
minDollarBalance: config.quota.minDollarBalance,
minEuroBalance: config.quota.minEuroBalance,
minCeloBalance: config.quota.minCeloBalance,
quota: 0,
})
Expand Down Expand Up @@ -246,13 +256,18 @@ export async function getTransactionCount(logger: Logger, ...addresses: string[]
return res
}

export async function getDollarBalance(logger: Logger, ...addresses: string[]): Promise<BigNumber> {
export async function getStableTokenBalance(
stableToken: StableToken,
logger: Logger,
...addresses: string[]
): Promise<BigNumber> {
return Promise.all(
addresses
.filter((address) => address !== NULL_ADDRESS)
.map((address) =>
retryAsyncWithBackOffAndTimeout(
async () => (await getContractKit().contracts.getStableToken()).balanceOf(address),
async () =>
(await getContractKit().contracts.getStableToken(stableToken)).balanceOf(address),
RETRY_COUNT,
[],
RETRY_DELAY_IN_MS,
Expand All @@ -266,7 +281,7 @@ export async function getDollarBalance(logger: Logger, ...addresses: string[]):
).then((values) => {
logger.trace(
{ addresses, balances: values.map((bn) => bn.toString()) },
'Fetched cusd balances for addresses'
`Fetched ${stableToken} balances for addresses`
)
return values.reduce((a, b) => a.plus(b))
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isVerified, rootLogger } from '@celo/phone-number-privacy-common'
import { StableToken } from '@celo/contractkit'
import BigNumber from 'bignumber.js'
import allSettled from 'promise.allsettled'
import {
Expand Down Expand Up @@ -118,16 +119,48 @@ describe(getRemainingQueryCount, () => {
totalQuota: 0,
})
})
it('Calculates remaining query count for unverified account with only cUSD balance', async () => {
it('Calculates remaining query count for unverified account with cUSD balance', async () => {
const contractKitVerifiedNoTx = createMockContractKit(
{
[ContractRetrieval.getAttestations]: createMockAttestation(0, 0),
[ContractRetrieval.getStableToken]: createMockToken(new BigNumber(200000000000000000)),
[ContractRetrieval.getStableToken]: createMockToken(new BigNumber(0)),
[ContractRetrieval.getGoldToken]: createMockToken(new BigNumber(0)),
[ContractRetrieval.getAccounts]: createMockAccounts('0x0'),
},
createMockWeb3(0)
)
contractKitVerifiedNoTx.contracts[ContractRetrieval.getStableToken] = jest.fn(
(stableToken: StableToken) => {
return stableToken === StableToken.cUSD
? createMockToken(new BigNumber(200000000000000000))
: createMockToken(new BigNumber(0))
}
)
mockPerformedQueryCount.mockImplementation(() => new Promise((resolve) => resolve(1)))
mockIsVerified.mockReturnValue(false)
mockGetContractKit.mockImplementation(() => contractKitVerifiedNoTx)
expect(await getRemainingQueryCount(rootLogger, mockAccount, mockPhoneNumber)).toEqual({
performedQueryCount: 1,
totalQuota: 10,
})
})
it('Calculates remaining query count for unverified account with cEUR balance', async () => {
const contractKitVerifiedNoTx = createMockContractKit(
{
[ContractRetrieval.getAttestations]: createMockAttestation(0, 0),
[ContractRetrieval.getStableToken]: createMockToken(new BigNumber(0)),
[ContractRetrieval.getGoldToken]: createMockToken(new BigNumber(0)),
[ContractRetrieval.getAccounts]: createMockAccounts('0x0'),
},
createMockWeb3(0)
)
contractKitVerifiedNoTx.contracts[ContractRetrieval.getStableToken] = jest.fn(
(stableToken: StableToken) => {
return stableToken === StableToken.cEUR
? createMockToken(new BigNumber(200000000000000000))
: createMockToken(new BigNumber(0))
}
)
mockPerformedQueryCount.mockImplementation(() => new Promise((resolve) => resolve(1)))
mockIsVerified.mockReturnValue(false)
mockGetContractKit.mockImplementation(() => contractKitVerifiedNoTx)
Expand Down