Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create validator for deployed contracts (#247)
* create interface * Update IDeploymentValidator.sol * add contract and testing * Update deploymentValidatorTest.ts * add comments * more tests, approve separate mappings
- Loading branch information
Showing
3 changed files
with
245 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import "./libraries/Authorizable.sol"; | ||
import "./interfaces/IDeploymentValidator.sol"; | ||
|
||
contract DeploymentValidator is IDeploymentValidator, Authorizable { | ||
// a mapping of wrapped position contracts deployed by Element | ||
mapping(address => bool) public wrappedPositions; | ||
// a mapping of pool contracts deployed by Element | ||
mapping(address => bool) public pools; | ||
// a mapping of wrapped position + pool pairs that are deployed by Element | ||
// we keccak256 hash these tuples together to serve as the mapping keys | ||
mapping(bytes32 => bool) public pairs; | ||
|
||
/// @notice Constructs this contract and stores needed data | ||
/// @param _owner The contract owner authorized to validate addresses | ||
constructor(address _owner) { | ||
// authorize the owner address to be able to execute the validations | ||
_authorize(_owner); | ||
} | ||
|
||
/// @notice adds a wrapped position address to the mapping | ||
/// @param wrappedPosition The wrapped position contract address | ||
function validateWPAddress(address wrappedPosition) | ||
public | ||
override | ||
onlyAuthorized | ||
{ | ||
// add address to mapping to indicating it was deployed by Element | ||
wrappedPositions[wrappedPosition] = true; | ||
} | ||
|
||
/// @notice adds a wrapped position address to the mapping | ||
/// @param pool the pool contract address | ||
function validatePoolAddress(address pool) public override onlyAuthorized { | ||
// add address to mapping to indicating it was deployed by Element | ||
pools[pool] = true; | ||
} | ||
|
||
/// @notice adds a wrapped position + pool pair of addresses to mapping | ||
/// @param wrappedPosition the wrapped position contract address | ||
/// @param pool the pool contract address | ||
function validateAddresses(address wrappedPosition, address pool) | ||
external | ||
override | ||
onlyAuthorized | ||
{ | ||
// add to pool validation mapping | ||
validatePoolAddress(pool); | ||
// add to wp validation mapping | ||
validateWPAddress(wrappedPosition); | ||
// hash together the contract addresses | ||
bytes32 data = keccak256(abi.encodePacked(wrappedPosition, pool)); | ||
// add the hashed pair into the mapping | ||
pairs[data] = true; | ||
} | ||
|
||
/// @notice checks to see if the address has been validated | ||
/// @param wrappedPosition the address to check | ||
/// @return true if validated, false if not | ||
function checkWPValidation(address wrappedPosition) | ||
external | ||
view | ||
override | ||
returns (bool) | ||
{ | ||
return wrappedPositions[wrappedPosition]; | ||
} | ||
|
||
/// @notice checks to see if the address has been validated | ||
/// @param pool the address to check | ||
/// @return true if validated, false if not | ||
function checkPoolValidation(address pool) | ||
external | ||
view | ||
override | ||
returns (bool) | ||
{ | ||
return pools[pool]; | ||
} | ||
|
||
/// @notice checks to see if the pair of addresses have been validated | ||
/// @param wrappedPosition the wrapped position address to check | ||
/// @param pool the pool address to check | ||
/// @return true if validated, false if not | ||
function checkPairValidation(address wrappedPosition, address pool) | ||
external | ||
view | ||
override | ||
returns (bool) | ||
{ | ||
bytes32 data = keccak256(abi.encodePacked(wrappedPosition, pool)); | ||
return pairs[data]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.0; | ||
|
||
interface IDeploymentValidator { | ||
function validateWPAddress(address wrappedPosition) external; | ||
|
||
function validatePoolAddress(address pool) external; | ||
|
||
function validateAddresses(address wrappedPosition, address pool) external; | ||
|
||
function checkWPValidation(address wrappedPosition) | ||
external | ||
view | ||
returns (bool); | ||
|
||
function checkPoolValidation(address pool) external view returns (bool); | ||
|
||
function checkPairValidation(address wrappedPosition, address pool) | ||
external | ||
view | ||
returns (bool); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { ethers, waffle } from "hardhat"; | ||
import { expect } from "chai"; | ||
import { DeploymentValidator } from "typechain/DeploymentValidator"; | ||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; | ||
import { createSnapshot, restoreSnapshot } from "./helpers/snapshots"; | ||
import { boolean } from "hardhat/internal/core/params/argumentTypes"; | ||
|
||
const { provider } = waffle; | ||
|
||
describe("Deployment Validator", () => { | ||
let deploymentValidator: DeploymentValidator; | ||
let signers: SignerWithAddress[]; | ||
|
||
before(async () => { | ||
await createSnapshot(provider); | ||
signers = await ethers.getSigners(); | ||
|
||
const deployer = await ethers.getContractFactory( | ||
"DeploymentValidator", | ||
signers[0] | ||
); | ||
deploymentValidator = await deployer.deploy(signers[0].address); | ||
}); | ||
|
||
after(async () => { | ||
await restoreSnapshot(provider); | ||
}); | ||
|
||
beforeEach(async () => { | ||
await createSnapshot(provider); | ||
}); | ||
afterEach(async () => { | ||
await restoreSnapshot(provider); | ||
}); | ||
|
||
describe("validate wrapped position addresses", () => { | ||
it("validates wp address correctly", async () => { | ||
const mockWPAddress = "0x814C447a9F58A2b823504Fe2775bA48c843925B6"; | ||
await deploymentValidator | ||
.connect(signers[0]) | ||
.validateWPAddress(mockWPAddress); | ||
const result = await deploymentValidator | ||
.connect(signers[0]) | ||
.checkWPValidation(mockWPAddress); | ||
expect(result).to.be.equal(true); | ||
}); | ||
it("validate wp fails for unauthorized owner", async () => { | ||
const mockWPAddress = "0x814C447a9F58A2b823504Fe2775bA48c843925B6"; | ||
const tx = deploymentValidator | ||
.connect(signers[1]) | ||
.validateWPAddress(mockWPAddress); | ||
await expect(tx).to.be.revertedWith("Sender not Authorized"); | ||
}); | ||
it("validate wp returns false unregistered address", async () => { | ||
const mockWPAddress = "0x8dc82c95B8901Db35390Aa4096B643d7724F278D"; | ||
const result = await deploymentValidator | ||
.connect(signers[0]) | ||
.checkWPValidation(mockWPAddress); | ||
expect(result).to.be.equal(false); | ||
}); | ||
}); | ||
describe("validate pool addresses", () => { | ||
it("validates pool address correctly", async () => { | ||
const mockPoolAddress = "0x5941DB4d6C500C4FFa57c359eE0C55c6b41D0b61"; | ||
await deploymentValidator | ||
.connect(signers[0]) | ||
.validatePoolAddress(mockPoolAddress); | ||
const result = await deploymentValidator | ||
.connect(signers[0]) | ||
.checkPoolValidation(mockPoolAddress); | ||
expect(result).to.be.equal(true); | ||
}); | ||
it("validate pool fails for unauthorized owner", async () => { | ||
const mockPoolAddress = "0x814C447a9F58A2b823504Fe2775bA48c843925B6"; | ||
const tx = deploymentValidator | ||
.connect(signers[1]) | ||
.validatePoolAddress(mockPoolAddress); | ||
await expect(tx).to.be.revertedWith("Sender not Authorized"); | ||
}); | ||
it("validate pool returns false unregistered address", async () => { | ||
const mockPoolAddress = "0x8dc82c95B8901Db35390Aa4096B643d7724F278D"; | ||
const result = await deploymentValidator | ||
.connect(signers[0]) | ||
.checkPoolValidation(mockPoolAddress); | ||
expect(result).to.be.equal(false); | ||
}); | ||
}); | ||
describe("validate wp/pool pair addresses", () => { | ||
it("validates addresses correctly", async () => { | ||
const mockWPAddress = "0x6F643Ba6894D8C50c476A3539e1D1690B2194018"; | ||
const mockPoolAddress = "0xB59C7597228fEBccEC3dC0571a7Ee39A26E316B9"; | ||
await deploymentValidator | ||
.connect(signers[0]) | ||
.validateAddresses(mockWPAddress, mockPoolAddress); | ||
// check pair validation | ||
const result1 = await deploymentValidator | ||
.connect(signers[0]) | ||
.checkPairValidation(mockWPAddress, mockPoolAddress); | ||
expect(result1).to.be.equal(true); | ||
// check individual mapping validation | ||
const result2 = await deploymentValidator | ||
.connect(signers[0]) | ||
.checkWPValidation(mockWPAddress); | ||
expect(result2).to.be.equal(true); | ||
const result3 = await deploymentValidator | ||
.connect(signers[0]) | ||
.checkPoolValidation(mockPoolAddress); | ||
expect(result3).to.be.equal(true); | ||
}); | ||
it("validate pool/wp pair fails for unauthorized owner", async () => { | ||
const mockWPAddress = "0x6F643Ba6894D8C50c476A3539e1D1690B2194018"; | ||
const mockPoolAddress = "0x814C447a9F58A2b823504Fe2775bA48c843925B6"; | ||
const tx = deploymentValidator | ||
.connect(signers[1]) | ||
.validateAddresses(mockWPAddress, mockPoolAddress); | ||
await expect(tx).to.be.revertedWith("Sender not Authorized"); | ||
}); | ||
it("validation returns false unregistered addresses", async () => { | ||
const mockWPAddress = "0xb47E7a1fD90630CfC0868d90Cb8F518578010cFe"; | ||
const mockPoolAddress = "0x4294005520c453EB8Fa66F53042cfC79707855c4"; | ||
const result = await deploymentValidator | ||
.connect(signers[0]) | ||
.checkPairValidation(mockWPAddress, mockPoolAddress); | ||
expect(result).to.be.equal(false); | ||
}); | ||
}); | ||
}); |