Skip to content

Commit

Permalink
Merge 5e9b2b1 into d550358
Browse files Browse the repository at this point in the history
  • Loading branch information
fernandomg committed Aug 7, 2018
2 parents d550358 + 5e9b2b1 commit 3e3e799
Show file tree
Hide file tree
Showing 19 changed files with 386 additions and 49 deletions.
6 changes: 6 additions & 0 deletions package.json
Expand Up @@ -196,5 +196,11 @@
},
"eslintConfig": {
"extends": "react-app"
},
"husky": {
"hooks": {
"pre-commit": "npm precommit",
"pre-push": "npm test:dapp:web3"
}
}
}
20 changes: 15 additions & 5 deletions src/components/Common/DutchAuctionBlock.js
Expand Up @@ -15,7 +15,8 @@ import {
isGreaterThan,
isLessOrEqualThan,
isPositive,
isRequired
isRequired,
isGreaterOrEqualThan
} from '../../utils/validations'
import { DESCRIPTION, TEXT_FIELDS } from '../../utils/constants'
import { inject, observer } from 'mobx-react'
Expand Down Expand Up @@ -139,12 +140,21 @@ export const DutchAuctionBlock = inject('tierStore', 'tokenStore')(
<Field
name={`${name}.supply`}
component={InputField2}
validate={value => {
validate={(value, values) => {
const { supply } = tokenStore
const errors = composeValidators(
const listOfValidations = [
isPositive(),
isLessOrEqualThan(`Should not be greater than Token's total supply: ${supply}`)(supply)
)(value)
]

if (values.tiers[index].whitelistEnabled === 'yes') {
const maxCapSum = tierStore.whitelistMaxCapSum[index]
listOfValidations.push(
isGreaterOrEqualThan(`Can't be less than sum of whitelist's maxCap: ${maxCapSum}`)(maxCapSum)
)
}

const errors = composeValidators(...listOfValidations)(value)
if (errors) return errors.shift()
}}
parse={acceptPositiveIntegerOnly}
Expand Down Expand Up @@ -200,7 +210,7 @@ export const DutchAuctionBlock = inject('tierStore', 'tokenStore')(
<div className="section-title">
<p className="title">Whitelist</p>
</div>
<WhitelistInputBlock num={index} decimals={props.decimals} />
<WhitelistInputBlock num={index} decimals={props.decimals} supply={tierStore.tiers[index].supply} />
</div>
) : null}
</div>
Expand Down
31 changes: 27 additions & 4 deletions src/components/Common/TierBlock.js
Expand Up @@ -2,13 +2,13 @@ import React from 'react'
import { Field } from 'react-final-form'
import { InputField2 } from './InputField2'
import { WhitelistInputBlock } from './WhitelistInputBlock'
import { composeValidators, isRequired, isMaxLength } from '../../utils/validations'
import { composeValidators, isGreaterOrEqualThan, isMaxLength, isPositive, isRequired } from '../../utils/validations'
import { DESCRIPTION, TEXT_FIELDS } from '../../utils/constants'
import { CrowdsaleStartTime } from './CrowdsaleStartTime'
import { CrowdsaleEndTime } from './CrowdsaleEndTime'
import { CrowdsaleRate } from './CrowdsaleRate'
import { Supply } from './Supply'
import { MinCap } from './MinCap'
import { acceptPositiveIntegerOnly } from '../../utils/utils'

const { ALLOW_MODIFYING, CROWDSALE_SETUP_NAME, ENABLE_WHITELISTING } = TEXT_FIELDS

Expand Down Expand Up @@ -124,7 +124,30 @@ export const TierBlock = ({ fields, ...props }) => {

<div className="input-block-container">
<CrowdsaleRate name={`${name}.rate`} errorStyle={inputErrorStyle} side="left" />
<Supply name={`${name}.supply`} errorStyle={inputErrorStyle} side="right" />
<Field
name={`${name}.supply`}
component={InputField2}
validate={(value, values) => {
const { tierStore } = props
const listOfValidations = [isPositive()]

if (values.tiers[index].whitelistEnabled === 'yes') {
const maxCapSum = tierStore.whitelistMaxCapSum[index]
listOfValidations.push(
isGreaterOrEqualThan(`Can't be less than sum of whitelist's maxCap: ${maxCapSum}`)(maxCapSum)
)
}

const errors = composeValidators(...listOfValidations)(value)
if (errors) return errors.shift()
}}
parse={acceptPositiveIntegerOnly}
errorStyle={inputErrorStyle}
type="text"
side="right"
label={TEXT_FIELDS.SUPPLY_SHORT}
description={DESCRIPTION.SUPPLY}
/>
</div>
<div className="input-block-container">
<MinCap
Expand All @@ -142,7 +165,7 @@ export const TierBlock = ({ fields, ...props }) => {
<div className="section-title">
<p className="title">Whitelist</p>
</div>
<WhitelistInputBlock num={index} decimals={props.decimals} />
<WhitelistInputBlock num={index} decimals={props.decimals} supply={props.tierStore.tiers[index].supply} />
</div>
) : null}
</div>
Expand Down
58 changes: 43 additions & 15 deletions src/components/Common/WhitelistInputBlock.js
Expand Up @@ -12,10 +12,11 @@ import {
clearingWhitelist,
whitelistImported,
noMoreWhitelistedSlotAvailable,
noMoreWhitelistedSlotAvailableCSV
noMoreWhitelistedSlotAvailableCSV,
notEnoughSupplyForTotalMax
} from '../../utils/alerts'
import processWhitelist from '../../utils/processWhitelist'
import { validateWhitelistMax, validateWhitelistMin } from '../../utils/validations'
import { isLessOrEqualThan, validateWhitelistMax, validateWhitelistMin } from '../../utils/validations'
import logdown from 'logdown'

const logger = logdown('TW:WhitelistInputBlock')
Expand Down Expand Up @@ -50,6 +51,12 @@ export class WhitelistInputBlock extends React.Component {
}
}

componentDidUpdate(prevProps) {
if (prevProps.supply !== this.props.supply && !this.state.validation.max.pristine) {
this.handleMaxChange({ max: this.state.max })
}
}

validateWhitelistedAddressList = async tierIndex => {
const { tierStore } = this.props

Expand Down Expand Up @@ -142,11 +149,13 @@ export class WhitelistInputBlock extends React.Component {
}

handleMinChange = ({ min }) => {
const errorMessage = validateWhitelistMin({
min,
max: this.state.max,
decimals: this.props.decimals
})
const errorMessage =
!this.state.validation.max.pristine &&
validateWhitelistMin({
min,
max: this.state.max,
decimals: this.props.decimals
})

return new Promise(resolve => {
this.setState(
Expand All @@ -168,11 +177,19 @@ export class WhitelistInputBlock extends React.Component {
}

handleMaxChange = ({ max }) => {
const errorMessage = validateWhitelistMax({
min: this.state.min,
max,
decimals: this.props.decimals
})
let errorMessage =
!this.state.validation.max.pristine &&
validateWhitelistMax({
min: this.state.min,
max,
decimals: this.props.decimals
})

if (typeof errorMessage === 'undefined') {
const { tierStore, num } = this.props
const tierSupplyRemaining = tierStore.tiersSupplyRemaining[num]
errorMessage = isLessOrEqualThan(`Exceeds supply remaining (${tierSupplyRemaining})`)(tierSupplyRemaining)(max)
}

return new Promise(resolve => {
this.setState(
Expand Down Expand Up @@ -213,21 +230,32 @@ export class WhitelistInputBlock extends React.Component {
Papa.parse(file, {
skipEmptyLines: true,
complete: results => {
const { called, whitelistedAddressLengthError } = processWhitelist(
// filters out the already added addresses
const rows = results.data.reduce((rows, row) => {
if (!tierStore.whitelistAddressAlreadyAdded(num, row[0])) rows.push(row)
return rows
}, [])

const { called, whitelistedAddressLengthError, maxExceedsSupplyRemaining } = processWhitelist(
{
rows: results.data,
decimals: decimals
rows,
decimals
},
item => {
tierStore.addWhitelistItem(item, num)
},
() => {
return tierStore.validateWhitelistedAddressLength(num)
},
max => {
return isLessOrEqualThan()(tierStore.tiersSupplyRemaining[num])(max)
}
)

if (whitelistedAddressLengthError) {
noMoreWhitelistedSlotAvailableCSV(called)
} else if (maxExceedsSupplyRemaining) {
notEnoughSupplyForTotalMax(called)
} else {
whitelistImported(called)
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/crowdsale/utils.js
Expand Up @@ -654,7 +654,7 @@ export const isCrowdSaleFull = async (addr, execID, methods, account) => {
const userMaxContribution = await getUserMaxContribution()

const isCrowdsaleFullValue = isCrowdsaleFullInstance.is_crowdsale_full || isCrowdsaleFullInstance[0]
const checkIfCrowdsaleIsFull = isCrowdsaleFullValue || userMaxContribution.toFixed() == 0
const checkIfCrowdsaleIsFull = isCrowdsaleFullValue || userMaxContribution.eq(0)

logger.log(`Crowdsale is full`, checkIfCrowdsaleIsFull)

Expand Down
7 changes: 6 additions & 1 deletion src/components/manage/ManageDutchAuctionBlock.js
Expand Up @@ -105,7 +105,12 @@ export const ManageDutchAuctionBlock = inject('crowdsaleStore', 'tokenStore')(
<p className="title">Whitelist</p>
</div>
{canEditWhiteList ? (
<WhitelistInputBlock key={index.toString()} num={index} decimals={tokenStore.decimals} />
<WhitelistInputBlock
key={index.toString()}
num={index}
decimals={tokenStore.decimals}
supply={currentTier.supply}
/>
) : (
<ReadOnlyWhitelistAddresses tier={currentTier} />
)}
Expand Down
7 changes: 6 additions & 1 deletion src/components/manage/ManageTierBlock.js
Expand Up @@ -110,7 +110,12 @@ export const ManageTierBlock = inject('crowdsaleStore', 'tokenStore')(
<p className="title">Whitelist</p>
</div>
{canEditWhiteList ? (
<WhitelistInputBlock key={index.toString()} num={index} decimals={tokenStore.decimals} />
<WhitelistInputBlock
key={index.toString()}
num={index}
decimals={tokenStore.decimals}
supply={currentTier.supply}
/>
) : (
<ReadOnlyWhitelistAddresses tier={currentTier} />
)}
Expand Down
10 changes: 5 additions & 5 deletions src/components/manage/index.js
Expand Up @@ -553,16 +553,16 @@ export class Manage extends Component {

//Check if is minted capped strategy
if (isMintedCappedCrowdsale) {
let currentTier = await getCurrentTierInfoCustom(initCrowdsaleContract, execID)
const currentTier = await getCurrentTierInfoCustom(initCrowdsaleContract, execID)
const numOfTiers = await getTiersLength()

//Get tier index, tokens remaining and actual tier
const tierIndex = currentTier.tier_index || currentTier[1]
const tierTokensRemaining = currentTier.tier_tokens_remaining || currentTier[3]
const actualTier = +tierIndex + 1
const tierIndex = toBigNumber(currentTier.tier_index || currentTier[1])
const tierTokensRemaining = toBigNumber(currentTier.tier_tokens_remaining || currentTier[3])
const actualTier = tierIndex.plus(1)

//Check if is lastTier, if tokens remaining is zero in last tier
mintedCappedWithLastTierAllSold = numOfTiers == actualTier && tierTokensRemaining == 0
mintedCappedWithLastTierAllSold = actualTier.eq(numOfTiers) && tierTokensRemaining.eq(0)

logger.log(`Minted with last tier sold, can finalize`, mintedCappedWithLastTierAllSold)
}
Expand Down
5 changes: 1 addition & 4 deletions src/components/stepFour/index.js
Expand Up @@ -114,9 +114,6 @@ export class stepFour extends React.Component {
}

deployCrowdsale = () => {
const { deploymentStore } = this.props
const firstRun = deploymentStore.deploymentStep === 0

this.resumeContractDeployment()
}

Expand Down Expand Up @@ -480,7 +477,7 @@ export class stepFour extends React.Component {
This deploy was started with account <b>{deploymentStore.deployerAccount}</b> but the current account is{' '}
<b>{this.context.selectedAccount}</b>. Please select the original account to continue with the deploy. If you
don't want to continue with that deploy,{' '}
<a href="#" onClick={this.cancelDeploy}>
<a href="" onClick={this.cancelDeploy}>
click here
</a>.
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/stepThree/index.js
Expand Up @@ -112,7 +112,7 @@ export class stepThree extends React.Component {
const { tierStore } = this.props
const newValue = {}

if (tierStore.tiers[nextTierIndex]) {
if (tierStore.tiers.length >= nextTierIndex + 1) {
newValue[`tiers[${nextTierIndex}].startTime`] = value
}

Expand Down
1 change: 1 addition & 0 deletions src/components/stepTwo/index.js
Expand Up @@ -13,6 +13,7 @@ import logdown from 'logdown'
const { TOKEN_SETUP } = NAVIGATION_STEPS
const { VALID, INVALID } = VALIDATION_TYPES

// eslint-disable-next-line no-unused-vars
const logger = logdown('TW:stepTwo:index')

@inject('tokenStore', 'crowdsaleStore', 'web3Store', 'reservedTokenStore')
Expand Down
1 change: 1 addition & 0 deletions src/stores/DeploymentStore.js
Expand Up @@ -76,6 +76,7 @@ class DeploymentStore {

if (!txStatus) return

// eslint-disable-next-line array-callback-return
const toBeUpdated = txStatus.findIndex(isSuccess => {
if (isSuccess !== null) {
return !isSuccess
Expand Down
45 changes: 44 additions & 1 deletion src/stores/TierStore.js
@@ -1,6 +1,13 @@
import { observable, action, computed } from 'mobx'
import { defaultTier, defaultTierValidations, VALIDATION_TYPES, LIMIT_WHITELISTED_ADDRESSES } from '../utils/constants'
import { validateTime, validateSupply, validateLaterTime, validateLaterOrEqualTime, validateTier } from '../utils/utils'
import {
validateTime,
validateSupply,
validateLaterTime,
validateLaterOrEqualTime,
validateTier,
toBigNumber
} from '../utils/utils'
import autosave from './autosave'
import { defaultCompanyEndDate, defaultCompanyStartDate } from '../components/stepThree/utils'
import logdown from 'logdown'
Expand Down Expand Up @@ -308,6 +315,31 @@ class TierStore {
return this.tiers.some(tier => tier.whitelist.some(item => !item.stored))
}

/**
* Returns a list of the sum of maxCap of whitelisted addresses per tier
* @returns {Array.<string>}
*/
@computed
get whitelistMaxCapSum() {
return this.tiers
.map(tier => tier.whitelist.reduce((total, account) => total.plus(account.max), toBigNumber(0)))
.map(maxCapBigNumber => maxCapBigNumber.toFixed())
}

/**
* Returns a list of remaining supply per tier.
* Iterates over every tier and subtract the sum of whitelisted addresses' maxCap from tier's supply
* @returns {Array.<string>}
*/
@computed
get tiersSupplyRemaining() {
return this.tiers.map((tier, index) =>
toBigNumber(tier.supply)
.minus(this.whitelistMaxCapSum[index])
.toFixed()
)
}

/**
* Validate whitelisted for a given tier
* @param tierIndex
Expand All @@ -316,6 +348,17 @@ class TierStore {
validateWhitelistedAddressLength(tierIndex) {
return this.tiers[tierIndex].whitelist.length < LIMIT_WHITELISTED_ADDRESSES
}

/**
* Checks whether a whitelist address was already added to a specific tier
* @param {Number} tierIndex
* @param {String} whitelistAddress
* @returns {Boolean}
*/
whitelistAddressAlreadyAdded(tierIndex, whitelistAddress) {
whitelistAddress = whitelistAddress.toLowerCase()
return this.tiers[tierIndex].whitelist.some(whitelist => whitelist.addr.toLowerCase() === whitelistAddress)
}
}

export default TierStore
8 changes: 8 additions & 0 deletions src/utils/alerts.js
Expand Up @@ -310,3 +310,11 @@ export function noMoreWhitelistedSlotAvailableCSV(count) {
type: 'info'
})
}

export function notEnoughSupplyForTotalMax(count) {
return sweetAlert2({
title: `Max supply available reached`,
html: `You have reached tier's supply available. There where added <strong>${count} addresses</strong>. If you want to add more, increase the tier's Supply.`,
type: 'info'
})
}

0 comments on commit 3e3e799

Please sign in to comment.