diff --git a/src/crowdsale/CrowdSale.sol b/src/crowdsale/CrowdSale.sol index deedb7aa..75039039 100644 --- a/src/crowdsale/CrowdSale.sol +++ b/src/crowdsale/CrowdSale.sol @@ -70,7 +70,7 @@ contract CrowdSale is ReentrancyGuard, Ownable { */ uint16 public currentFeeBp = 0; - event Started(uint256 indexed saleId, address indexed issuer, Sale sale, uint16 percentageFee); + event Started(uint256 indexed saleId, address indexed issuer, Sale sale, uint16 feeBp); event Settled(uint256 indexed saleId, uint256 totalBids, uint256 surplus); /// @notice emitted when participants of the sale claim their tokens event Claimed(uint256 indexed saleId, address indexed claimer, uint256 claimed, uint256 refunded); diff --git a/src/crowdsale/LockingCrowdSale.sol b/src/crowdsale/LockingCrowdSale.sol index 6e335277..7610ff34 100644 --- a/src/crowdsale/LockingCrowdSale.sol +++ b/src/crowdsale/LockingCrowdSale.sol @@ -27,7 +27,7 @@ contract LockingCrowdSale is CrowdSale { address immutable lockingTokenImplementation = address(new TimelockedToken()); - event Started(uint256 indexed saleId, address indexed issuer, Sale sale, TimelockedToken lockingToken, uint256 lockingDuration); + event Started(uint256 indexed saleId, address indexed issuer, Sale sale, TimelockedToken lockingToken, uint256 lockingDuration, uint16 feeBp); event LockingContractCreated(TimelockedToken indexed lockingContract, IERC20Metadata indexed underlyingToken); /// @dev disable parent sale starting functions @@ -71,7 +71,14 @@ contract LockingCrowdSale is CrowdSale { } function _afterSaleStarted(uint256 saleId) internal virtual override { - emit Started(saleId, msg.sender, _sales[saleId], lockingContracts[address(_sales[saleId].auctionToken)], salesLockingDuration[saleId]); + emit Started( + saleId, + msg.sender, + _sales[saleId], + lockingContracts[address(_sales[saleId].auctionToken)], + salesLockingDuration[saleId], + _saleInfo[saleId].feeBp + ); } function _afterSaleSettled(uint256 saleId) internal override { diff --git a/src/crowdsale/StakedLockingCrowdSale.sol b/src/crowdsale/StakedLockingCrowdSale.sol index b8747882..b0159b40 100644 --- a/src/crowdsale/StakedLockingCrowdSale.sol +++ b/src/crowdsale/StakedLockingCrowdSale.sol @@ -45,7 +45,8 @@ contract StakedLockingCrowdSale is LockingCrowdSale { StakingInfo staking, TimelockedToken lockingToken, uint256 lockingDuration, - uint256 stakingDuration + uint256 stakingDuration, + uint16 feeBp ); event Staked(uint256 indexed saleId, address indexed bidder, uint256 stakedAmount, uint256 price); event ClaimedStakes(uint256 indexed saleId, address indexed claimer, uint256 stakesClaimed, uint256 stakesRefunded); @@ -139,7 +140,8 @@ contract StakedLockingCrowdSale is LockingCrowdSale { salesStaking[saleId], lockingContracts[address(_sales[saleId].auctionToken)], salesLockingDuration[saleId], - stakingDuration + stakingDuration, + _saleInfo[saleId].feeBp ); } diff --git a/subgraph/abis/CrowdSale.json b/subgraph/abis/CrowdSale.json index 9394c18b..42038142 100644 --- a/subgraph/abis/CrowdSale.json +++ b/subgraph/abis/CrowdSale.json @@ -289,7 +289,7 @@ { "indexed": false, "internalType": "uint16", - "name": "percentageFee", + "name": "feeBp", "type": "uint16" } ], diff --git a/subgraph/abis/StakedLockingCrowdSale.json b/subgraph/abis/StakedLockingCrowdSale.json index a662c8df..c8635483 100644 --- a/subgraph/abis/StakedLockingCrowdSale.json +++ b/subgraph/abis/StakedLockingCrowdSale.json @@ -432,6 +432,12 @@ "internalType": "uint256", "name": "stakingDuration", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feeBp", + "type": "uint16" } ], "name": "Started", @@ -506,6 +512,12 @@ "internalType": "uint256", "name": "lockingDuration", "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "feeBp", + "type": "uint16" } ], "name": "Started", @@ -572,7 +584,7 @@ { "indexed": false, "internalType": "uint16", - "name": "percentageFee", + "name": "feeBp", "type": "uint16" } ], @@ -1210,5 +1222,108 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "saleId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "issuer", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20Metadata", + "name": "auctionToken", + "type": "address" + }, + { + "internalType": "contract IERC20Metadata", + "name": "biddingToken", + "type": "address" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "fundingGoal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "salesAmount", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "closingTime", + "type": "uint64" + }, + { + "internalType": "contract IPermissioner", + "name": "permissioner", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct Sale", + "name": "sale", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "contract IERC20Metadata", + "name": "stakedToken", + "type": "address" + }, + { + "internalType": "contract TokenVesting", + "name": "stakesVestingContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wadFixedStakedPerBidPrice", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct StakingInfo", + "name": "staking", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "contract TimelockedToken", + "name": "lockingToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lockingDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stakingDuration", + "type": "uint256" + } + ], + "name": "Started", + "type": "event" } ] diff --git a/subgraph/makeAbis.sh b/subgraph/makeAbis.sh index 06bb3657..f701bb67 100755 --- a/subgraph/makeAbis.sh +++ b/subgraph/makeAbis.sh @@ -72,3 +72,111 @@ jq '. += [{ rm ./abis/_Tokenizer.json +# add the old StakedLockingCrowdSale's `Started` event to the abi so the subgraph can index them +#event Started(uint256 indexed saleId, address indexed issuer, Sale sale); + +cat ../out/StakedLockingCrowdSale.sol/StakedLockingCrowdSale.json | jq .abi > ./abis/_StakedLockingCrowdSale.json +jq '. += [{ + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "saleId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "issuer", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20Metadata", + "name": "auctionToken", + "type": "address" + }, + { + "internalType": "contract IERC20Metadata", + "name": "biddingToken", + "type": "address" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "fundingGoal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "salesAmount", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "closingTime", + "type": "uint64" + }, + { + "internalType": "contract IPermissioner", + "name": "permissioner", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct Sale", + "name": "sale", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "contract IERC20Metadata", + "name": "stakedToken", + "type": "address" + }, + { + "internalType": "contract TokenVesting", + "name": "stakesVestingContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "wadFixedStakedPerBidPrice", + "type": "uint256" + } + ], + "indexed": false, + "internalType": "struct StakingInfo", + "name": "staking", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "contract TimelockedToken", + "name": "lockingToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lockingDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stakingDuration", + "type": "uint256" + } + ], + "name": "Started", + "type": "event" + }]' ./abis/_StakedLockingCrowdSale.json > ./abis/StakedLockingCrowdSale.json + rm ./abis/_StakedLockingCrowdSale.json \ No newline at end of file diff --git a/subgraph/schema.graphql b/subgraph/schema.graphql index 61b69259..f11b8ca7 100644 --- a/subgraph/schema.graphql +++ b/subgraph/schema.graphql @@ -133,6 +133,7 @@ type CrowdSale @entity { permissioner: Bytes! #a crowdsale can be configured with an individual permissioner claimedAt: BigInt # the date when the auctioneer has claimed their return (depending on failed / settled sales) contributions: [Contribution!] @derivedFrom(field: "crowdSale") + feeBp: Int # the percentage fee that will be cut from the crowdsale upon its success type: SaleType! } diff --git a/subgraph/src/crowdSaleMapping.ts b/subgraph/src/crowdSaleMapping.ts index b3a29dee..0c5bdfcb 100644 --- a/subgraph/src/crowdSaleMapping.ts +++ b/subgraph/src/crowdSaleMapping.ts @@ -27,6 +27,7 @@ export function handleStarted(event: StartedEvent): void { crowdSale.ipt = ipt.id crowdSale.issuer = event.params.issuer + crowdSale.feeBp = event.params.feeBp crowdSale.beneficiary = event.params.sale.beneficiary crowdSale.closingTime = event.params.sale.closingTime crowdSale.createdAt = event.block.timestamp diff --git a/subgraph/src/stakedLockingCrowdSaleMapping.ts b/subgraph/src/stakedLockingCrowdSaleMapping.ts index 0562e46e..bb225e38 100644 --- a/subgraph/src/stakedLockingCrowdSaleMapping.ts +++ b/subgraph/src/stakedLockingCrowdSaleMapping.ts @@ -1,4 +1,10 @@ -import { BigInt, Bytes, DataSourceContext, log } from '@graphprotocol/graph-ts' +import { + BigInt, + Bytes, + DataSourceContext, + log, + ethereum +} from '@graphprotocol/graph-ts' import { IERC20Metadata } from '../generated/CrowdSale/IERC20Metadata' import { Bid as BidEvent, @@ -10,8 +16,14 @@ import { LockingContractCreated as LockingContractCreatedEvent, Settled as SettledEvent, Staked as StakedEvent, + Started3 as LegacyStartedEvent, Started as StartedEvent } from '../generated/StakedLockingCrowdSale/StakedLockingCrowdSale' + +import { Started as PlainStartedEvent } from '../generated/CrowdSale/CrowdSale' + +import { handleStarted as plainHandleStarted } from './crowdSaleMapping' + import * as GenericCrowdSale from './genericCrowdSale' import { Contribution, CrowdSale, ERC20Token, IPT } from '../generated/schema' @@ -19,8 +31,52 @@ import { Contribution, CrowdSale, ERC20Token, IPT } from '../generated/schema' import { TimelockedToken as TimelockedTokenTemplate } from '../generated/templates' import { makeERC20Token, makeTimelockedToken } from './common' +export function handleStartedLegacy(event: LegacyStartedEvent): void { + const parameters = event.parameters + parameters[7] = new ethereum.EventParam( + 'feeBp', + new ethereum.Value(ethereum.ValueKind.UINT, 0) + ) + const _started = new StartedEvent( + event.address, + event.logIndex, + event.transactionLogIndex, + event.logType, + event.block, + event.transaction, + parameters, + event.receipt + ) + + return handleStarted(_started) +} + export function handleStarted(event: StartedEvent): void { - let crowdSale = new CrowdSale(event.params.saleId.toString()) + const _plain = new PlainStartedEvent( + event.address, + event.logIndex, + event.transactionLogIndex, + event.logType, + event.block, + event.transaction, + [ + event.parameters[0], + event.parameters[1], + event.parameters[2], + event.parameters[7] + ], + event.receipt + ) + + plainHandleStarted(_plain) + + let crowdSale = CrowdSale.load(event.params.saleId.toString()) + if (!crowdSale) { + log.error('[Crowdsale] Creation failed for: {}', [ + event.params.saleId.toHexString() + ]) + return + } let ipt = IPT.load(event.params.sale.auctionToken.toHexString()) if (!ipt) { @@ -44,26 +100,9 @@ export function handleStarted(event: StartedEvent): void { } } - crowdSale.ipt = ipt.id - crowdSale.issuer = event.params.issuer - crowdSale.beneficiary = event.params.sale.beneficiary - crowdSale.closingTime = event.params.sale.closingTime - crowdSale.createdAt = event.block.timestamp - crowdSale.state = 'RUNNING' - - crowdSale.salesAmount = event.params.sale.salesAmount - - crowdSale.biddingToken = makeERC20Token( - IERC20Metadata.bind(event.params.sale.biddingToken) - ).id - crowdSale.fundingGoal = event.params.sale.fundingGoal - crowdSale.amountRaised = BigInt.fromU32(0) - crowdSale.amountStaked = BigInt.fromU32(0) - - crowdSale.permissioner = event.params.sale.permissioner - crowdSale.auctionLockingDuration = event.params.lockingDuration + crowdSale.stakingToken = makeERC20Token( IERC20Metadata.bind(event.params.staking.stakedToken) ).id @@ -77,7 +116,7 @@ export function handleStarted(event: StartedEvent): void { crowdSale.type = 'STAKED_LOCKING_CROWDSALE' crowdSale.save() - log.info('[handleStarted] crowdsale {}', [crowdSale.id]) + log.info('[handleStarted] staked locking crowdsale {}', [crowdSale.id]) } export function handleSettled(event: SettledEvent): void { diff --git a/subgraph/subgraph.template.yaml b/subgraph/subgraph.template.yaml index 95071b25..5636c0d8 100644 --- a/subgraph/subgraph.template.yaml +++ b/subgraph/subgraph.template.yaml @@ -103,7 +103,7 @@ dataSources: - name: IERC20Metadata file: ./abis/IERC20Metadata.json eventHandlers: - - event: Started(indexed uint256,indexed address,(address,address,address,uint256,uint256,uint64,address)) + - event: Started(indexed uint256,indexed address,(address,address,address,uint256,uint256,uint64,address),uint16) handler: handleStarted - event: Settled(indexed uint256,uint256,uint256) handler: handleSettled @@ -136,8 +136,13 @@ dataSources: abis: - name: StakedLockingCrowdSale file: ./abis/StakedLockingCrowdSale.json + - name: IERC20Metadata + file: ./abis/IERC20Metadata.json eventHandlers: + # the initial crowdsale contract didn't use any fees - event: Started(indexed uint256,indexed address,(address,address,address,uint256,uint256,uint64,address),(address,address,uint256),address,uint256,uint256) + handler: handleStartedLegacy + - event: Started(indexed uint256,indexed address,(address,address,address,uint256,uint256,uint64,address),(address,address,uint256),address,uint256,uint256,uint16) handler: handleStarted - event: Settled(indexed uint256,uint256,uint256) handler: handleSettled