diff --git a/DaoPools/abis/TokenSale.json b/DaoPools/abis/TokenSale.json index 95e8739..0d2efdc 100644 --- a/DaoPools/abis/TokenSale.json +++ b/DaoPools/abis/TokenSale.json @@ -111,6 +111,43 @@ "name": "TierCreated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "tierId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "saleToken", + "type": "address" + }, + { + "components": [ + { + "internalType": "enum ITokenSaleProposal.ParticipationType", + "name": "participationType", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct ITokenSaleProposal.ParticipationDetails[]", + "name": "participationDetails", + "type": "tuple[]" + } + ], + "name": "TierModified", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -355,6 +392,36 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tierId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "enum ITokenSaleProposal.ParticipationType", + "name": "participationType", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct ITokenSaleProposal.ParticipationDetails[]", + "name": "newSettings", + "type": "tuple[]" + } + ], + "name": "changeParticipationDetails", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -571,6 +638,72 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tierId", + "type": "uint256" + } + ], + "name": "getParticipationDetails", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isWhitelisted", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isBABTed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "requiredDaoVotes", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "requiredTokenAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "requiredTokenAmounts", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "requiredNftAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "requiredNftAmounts", + "type": "uint256[]" + }, + { + "internalType": "bytes32", + "name": "merkleRoot", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "merkleUri", + "type": "string" + } + ], + "internalType": "struct ITokenSaleProposal.ParticipationInfoView", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -809,6 +942,11 @@ "internalType": "string", "name": "merkleUri", "type": "string" + }, + { + "internalType": "uint256", + "name": "lastModified", + "type": "uint256" } ], "internalType": "struct ITokenSaleProposal.TierAdditionalInfo", @@ -1102,6 +1240,132 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tierId", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "description", + "type": "string" + } + ], + "internalType": "struct ITokenSaleProposal.TierMetadata", + "name": "metadata", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "totalTokenProvided", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "saleStartTime", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "saleEndTime", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "claimLockDuration", + "type": "uint64" + }, + { + "internalType": "address", + "name": "saleTokenAddress", + "type": "address" + }, + { + "internalType": "address[]", + "name": "purchaseTokenAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "exchangeRates", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minAllocationPerUser", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxAllocationPerUser", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "vestingPercentage", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "vestingDuration", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "cliffPeriod", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "unlockStep", + "type": "uint64" + } + ], + "internalType": "struct ITokenSaleProposal.VestingSettings", + "name": "vestingSettings", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum ITokenSaleProposal.ParticipationType", + "name": "participationType", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "internalType": "struct ITokenSaleProposal.ParticipationDetails[]", + "name": "participationDetails", + "type": "tuple[]" + } + ], + "internalType": "struct ITokenSaleProposal.TierInitParams", + "name": "newSettings", + "type": "tuple" + } + ], + "name": "modifyTier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/DaoPools/src/helpers/PriceFeedInteractions.ts b/DaoPools/src/helpers/PriceFeedInteractions.ts index be094b5..41f0b75 100644 --- a/DaoPools/src/helpers/PriceFeedInteractions.ts +++ b/DaoPools/src/helpers/PriceFeedInteractions.ts @@ -6,7 +6,7 @@ export function getUSDValue(token: Bytes, amount: BigInt): BigInt { if (token.equals(Bytes.empty())) { return BigInt.zero(); } - + let pfPrototype = PriceFeed.bind(Address.fromString(PRICE_FEED_ADDRESS)); let resp = pfPrototype.try_getNormalizedPriceOutUSD(Address.fromBytes(token), amount); diff --git a/DaoPools/src/mappings/TokenSale.ts b/DaoPools/src/mappings/TokenSale.ts index 24a0949..3f98547 100644 --- a/DaoPools/src/mappings/TokenSale.ts +++ b/DaoPools/src/mappings/TokenSale.ts @@ -1,6 +1,6 @@ import { Address, BigInt, Bytes } from "@graphprotocol/graph-ts"; import { pushUnique } from "@solarity/graph-lib"; -import { Bought, TierCreated, Whitelisted } from "../../generated/templates/TokenSale/TokenSaleProposal"; +import { Bought, TierCreated, TierModified, Whitelisted } from "../../generated/templates/TokenSale/TokenSaleProposal"; import { getDaoPool } from "../entities/DaoPool"; import { getTokenSale } from "../entities/TokenSale"; import { getTokenSaleTier } from "../entities/TokenSaleTier"; @@ -25,6 +25,24 @@ export function onTierCreated(event: TierCreated): void { tokenSale.save(); } +export function onTierModified(event: TierModified): void { + let tokenSale = getTokenSale(event.address); + let tier = getTokenSaleTier(tokenSale, event.params.tierId, event.params.saleToken); + + let participationDetails = event.params.participationDetails; + + tier.whitelistTypes = new Array(); + tier.data = new Array(); + + for (let i = 0; i < participationDetails.length; i++) { + tier.whitelistTypes = push(tier.whitelistTypes, BigInt.fromI32(participationDetails[i].participationType)); + tier.data = push(tier.data, participationDetails[i].data); + } + + tier.save(); + tokenSale.save(); +} + export function onBought(event: Bought): void { let tokenSale = getTokenSale(event.address); let tier = getTokenSaleTier(tokenSale, event.params.tierId); diff --git a/DaoPools/subgraph.yaml b/DaoPools/subgraph.yaml index 3512f9f..86f11a6 100644 --- a/DaoPools/subgraph.yaml +++ b/DaoPools/subgraph.yaml @@ -169,6 +169,8 @@ templates: eventHandlers: - event: TierCreated(uint256,address,(uint8,bytes)[]) handler: onTierCreated + - event: TierModified(uint256,address,(uint8,bytes)[]) + handler: onTierModified - event: Bought(uint256,address,uint256,uint256,address) handler: onBought - event: Whitelisted(uint256,address) diff --git a/DaoPools/tests/TokenSale.test.ts b/DaoPools/tests/TokenSale.test.ts index dad67e5..8a2fe93 100644 --- a/DaoPools/tests/TokenSale.test.ts +++ b/DaoPools/tests/TokenSale.test.ts @@ -1,10 +1,10 @@ import { Address, BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"; -import { Bought, TierCreated, Whitelisted } from "../generated/templates/TokenSale/TokenSaleProposal"; +import { Bought, TierCreated, TierModified, Whitelisted } from "../generated/templates/TokenSale/TokenSaleProposal"; import { afterEach, assert, beforeAll, describe, newMockEvent, test } from "matchstick-as"; import { getBlock, getNextBlock, getNextTx, getTransaction } from "./utils"; import { getDaoPool } from "../src/entities/DaoPool"; import { getTokenSale } from "../src/entities/TokenSale"; -import { onBought, onTierCreated, onWhitelisted } from "../src/mappings/TokenSale"; +import { onBought, onTierCreated, onTierModified, onWhitelisted } from "../src/mappings/TokenSale"; function createBought( tierId: BigInt, @@ -68,6 +68,42 @@ function createTierCreated( return event; } +function createTierModified( + tierId: BigInt, + saleToken: Address, + participationTypes: BigInt[], + data: Bytes[], + contractSender: Address, + block: ethereum.Block, + tx: ethereum.Transaction +): TierModified { + let event = changetype(newMockEvent()); + event.parameters = new Array(); + + let participationTypesArray = new Array(participationTypes.length); + + for (let i = 0; i < participationTypes.length; i++) { + let tuple = new ethereum.Tuple(2); + + tuple[0] = ethereum.Value.fromUnsignedBigInt(participationTypes[i]); + tuple[1] = ethereum.Value.fromBytes(data[i]); + + participationTypesArray[i] = tuple; + } + + event.parameters.push(new ethereum.EventParam("tierId", ethereum.Value.fromUnsignedBigInt(tierId))); + event.parameters.push(new ethereum.EventParam("saleToken", ethereum.Value.fromAddress(saleToken))); + event.parameters.push( + new ethereum.EventParam("participationTypes", ethereum.Value.fromTupleArray(participationTypesArray)) + ); + + event.block = block; + event.transaction = tx; + event.address = contractSender; + + return event; +} + function createWhitelisted( tierId: BigInt, user: Address, @@ -147,6 +183,68 @@ describe("TokenSale", () => { ); }); + test("should handle tierModifier", () => { + let tierId = BigInt.fromI32(5); + let token = Address.fromString("0x96e08f7d84603AEb97cd1c89A80A9e914f181674"); + let participationTypes = [BigInt.fromI32(1), BigInt.fromI32(2)]; + let data = [Bytes.fromI32(1), Bytes.fromI32(2)]; + let event = createTierCreated(tierId, token, participationTypes, data, contractSender, block, tx); + + onTierCreated(event); + + let newBlock = getNextBlock(block); + let newTx = getNextTx(tx); + let newParticipationTypes = [BigInt.fromI32(3), BigInt.fromI32(4)]; + let newData = [Bytes.fromI32(3), Bytes.fromI32(4)]; + let modifyEvent = createTierModified( + tierId, + token, + newParticipationTypes, + newData, + contractSender, + newBlock, + newTx + ); + + onTierModified(modifyEvent); + + assert.fieldEquals("TokenSaleContract", contractSender.toHexString(), "daoPool", poolAddress.toHexString()); + + assert.fieldEquals( + "TokenSaleTier", + contractSender.concatI32(tierId.toI32()).toHexString(), + "tokenSale", + contractSender.toHexString() + ); + assert.fieldEquals( + "TokenSaleTier", + contractSender.concatI32(tierId.toI32()).toHexString(), + "creationHash", + tx.hash.toHexString() + ); + assert.fieldEquals( + "TokenSaleTier", + contractSender.concatI32(tierId.toI32()).toHexString(), + "saleToken", + token.toHexString() + ); + assert.fieldEquals( + "TokenSaleTier", + contractSender.concatI32(tierId.toI32()).toHexString(), + "whitelistTypes", + `[${newParticipationTypes[0].toString()}, ${newParticipationTypes[1].toString()}]` + ); + assert.fieldEquals( + "TokenSaleTier", + contractSender.concatI32(tierId.toI32()).toHexString(), + "data", + `[${newData[0].toHexString()}, ${newData[1].toHexString()}]` + ); + + block = newBlock; + tx = newTx; + }); + test("should handle bought", () => { let tierId = BigInt.fromI32(5); let paidToken = Address.fromString("0x96e08f7d84603AEb97cd1c89A80A9e914f181671"); diff --git a/DaoValidators/tests/DaoValidators.test.ts b/DaoValidators/tests/DaoValidators.test.ts index 83730b4..3468b0c 100644 --- a/DaoValidators/tests/DaoValidators.test.ts +++ b/DaoValidators/tests/DaoValidators.test.ts @@ -400,7 +400,7 @@ describe("DaoValidators", () => { assert.fieldEquals( "Proposal", - poolAddress.toHexString() + proposalId.toString() + '_' + (isInternal ? '1' : '0'), + poolAddress.toHexString() + proposalId.toString() + "_" + (isInternal ? "1" : "0"), "validatorsVoted", "1" ); @@ -453,7 +453,7 @@ describe("DaoValidators", () => { assert.fieldEquals( "Proposal", - poolAddress.toHexString() + proposalId.toString() + '_' + (isInternal ? '1' : '0'), + poolAddress.toHexString() + proposalId.toString() + "_" + (isInternal ? "1" : "0"), "validatorsVoted", "1" ); @@ -510,7 +510,7 @@ describe("DaoValidators", () => { assert.fieldEquals( "Proposal", - poolAddress.toHexString() + proposalId.toString() + '_' + (isInternal ? '1' : '0'), + poolAddress.toHexString() + proposalId.toString() + "_" + (isInternal ? "1" : "0"), "validatorsVoted", "2" ); @@ -568,7 +568,7 @@ describe("DaoValidators", () => { assert.fieldEquals( "Proposal", - poolAddress.toHexString() + proposalId.toString() + '_' + (isInternal ? '1' : '0'), + poolAddress.toHexString() + proposalId.toString() + "_" + (isInternal ? "1" : "0"), "validatorsVoted", "1" ); @@ -624,7 +624,7 @@ describe("DaoValidators", () => { assert.fieldEquals( "Proposal", - poolAddress.toHexString() + proposalId.toString() + '_' + (isInternal ? '1' : '0'), + poolAddress.toHexString() + proposalId.toString() + "_" + (isInternal ? "1" : "0"), "validatorsVoted", "0" ); diff --git a/package.json b/package.json index 9669a67..2964368 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "install-all": "cd AllInteractions && npm install && cd ../DaoPools && npm install && cd ../DaoValidators && npm install", "codegen-all": "cd AllInteractions && npm run codegen && cd ../DaoPools && npm run codegen && cd ../DaoValidators && npm run codegen", "test-all": "cd AllInteractions && npm run test && cd ../DaoPools && npm run test && cd ../DaoValidators && npm run test", + "test-all-docker": "cd AllInteractions && graph test -d && cd ../DaoPools && graph test -d && cd ../DaoValidators && graph test -d", "lint-fix": "npm run lint-ts-fix && npm run lint-ql-fix && npm run lint-json-fix && npm run lint-yaml-fix", "lint-json-fix": "prettier --write \"./[a-zA-Z0-9.]+(?!-lock).json\"", "lint-yaml-fix": "prettier --write \"./**/*.yaml\"",