Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
pragma solidity 0.6.10;
pragma experimental "ABIEncoderV2";

/**
* @title SnapshotGovernanceAdapter
* @author Mridul Ahuja
*
* Governance adapter that allows a Set to delegate all of its voting power on Snapshot.org
*/

contract SnapshotGovernanceAdapter {
/* ============ Constants ============ */

// Signature of the delegate function in Delegate Registry
string public constant DELEGATE_SIGNATURE = "setDelegate(bytes32,address)";

string public constant CLEAR_DELEGATE_SIGNATURE = "clearDelegate(bytes32)";

/* ============ State Variables ============ */

// Address of the Delegate Registry
address public immutable delegateRegistryAddress;

/* ============ Constructor ============ */

/**
* Set state variables
*
* @param _delegateRegistryAddress Address of Delegate Registry Address
*/

constructor(address _delegateRegistryAddress) public {
delegateRegistryAddress = _delegateRegistryAddress;
}

/* ============ External Getter Functions ============ */

/**
* Delegates all votes of msg.sender to delegate. If id is left as ZERO_BYTES, then delegates all votes
*
* @param _delegatee Address to which votes will be delegated
*
* @return address Target contract address
* @return uint256 Total quantity of ETH (Set to 0)
* @return bytes Propose calldata
*/

function getDelegateCalldata(address _delegatee) external view returns (address, uint256, bytes memory){

bytes memory callData = abi.encodeWithSignature(DELEGATE_SIGNATURE, bytes32(0), _delegatee);

return (delegateRegistryAddress, 0, callData);
}

/**
* Revokes previous delegation from msg.sender. If id is left as ZERO_BYTES, then undelegates all votes
*
* @return address Target contract address
* @return uint256 Total quantity of ETH (Set to 0)
* @return bytes Propose calldata
*/

function getRevokeCalldata() external view returns (address, uint256, bytes memory){

bytes memory callData = abi.encodeWithSignature(CLEAR_DELEGATE_SIGNATURE, bytes32(0));

return (delegateRegistryAddress, 0, callData);
}
}
8 changes: 8 additions & 0 deletions external/abi/snapshot/DelegateRegistry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"contractName": "DelegateRegistry",
"abi": [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"}],"name":"ClearDelegate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"}],"name":"SetDelegate","type":"event"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"clearDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"delegation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"address","name":"delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"}],
"bytecode": "608060405234801561001057600080fd5b50610794806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806374c6c45414610046578063bd86e508146100be578063f0bedbe21461010c575b600080fd5b6100926004803603604081101561005c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061013a565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61010a600480360360408110156100d457600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061017c565b005b6101386004803603602081101561012257600080fd5b8101908080359060200190929190505050610538565b005b60006020528160005260406000206020528060005260406000206000915091509054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561021e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f43616e27742064656c656761746520746f2073656c660000000000000000000081525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156102c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f43616e27742064656c656761746520746f20307830000000000000000000000081525060200191505060405180910390fd5b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156103ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061073e6021913960400191505060405180910390fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146104d8578073ffffffffffffffffffffffffffffffffffffffff16833373ffffffffffffffffffffffffffffffffffffffff167f9c4f00c4291262731946e308dc2979a56bd22cce8f95906b975065e96cd5a06460405160405180910390a45b8173ffffffffffffffffffffffffffffffffffffffff16833373ffffffffffffffffffffffffffffffffffffffff167fa9a7fd460f56bddb880a465a9c3e9730389c70bc53108148f16d55a87a6c468e60405160405180910390a4505050565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561064f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f4e6f2064656c656761746520736574000000000000000000000000000000000081525060200191505060405180910390fd5b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16823373ffffffffffffffffffffffffffffffffffffffff167f9c4f00c4291262731946e308dc2979a56bd22cce8f95906b975065e96cd5a06460405160405180910390a4505056fe416c72656164792064656c65676174656420746f20746869732061646472657373a2646970667358221220b6cd5a8d04426e1189563fbec7dfec4ba70090dc70fe05097a137991fe1b396964736f6c63430007020033",
"deployedBytecode": "",
"linkReferences": {},
"deployedLinkReferences": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import "module-alias/register";
import { Address } from "@utils/types";
import { Account } from "@utils/test/types";
import { ZERO, ZERO_BYTES } from "@utils/constants";
import {
DelegateRegistry,
SnapshotGovernanceAdapter
} from "@utils/contracts";
import DeployHelper from "@utils/deploys";
import {
addSnapshotBeforeRestoreAfterEach,
getAccounts,
getWaffleExpect,
getRandomAddress
} from "@utils/test/index";

const expect = getWaffleExpect();

describe("SnapshotGovernanceAdapter", () => {
let owner: Account;
let deployer: DeployHelper;
let snapshotGovernanceAdapter: SnapshotGovernanceAdapter;
let delegateRegistry: DelegateRegistry;

before(async () => {
[owner] = await getAccounts();
deployer = new DeployHelper(owner.wallet);

delegateRegistry = await deployer.external.deployDelegateRegistry();
snapshotGovernanceAdapter = await deployer.adapters.deploySnapshotGovernanceAdapter(delegateRegistry.address);
});

addSnapshotBeforeRestoreAfterEach();

describe("#constructor", async () => {
let subjectDelegateRegistry: Address;

before(async() => {
subjectDelegateRegistry = delegateRegistry.address;
});

async function subject(): Promise<any> {
return await deployer.adapters.deploySnapshotGovernanceAdapter(subjectDelegateRegistry);
}

it("should have the correct delegateRegistry address", async () => {
const deployedSnapshotGovernanceAdapter = await subject();
const actualDelegateRegistry = await deployedSnapshotGovernanceAdapter.delegateRegistryAddress();

expect(actualDelegateRegistry).to.eq(subjectDelegateRegistry);
});
});

describe("#getDelegateCallData", async () => {
let subjectDelegatee: Address;

before(async() => {
subjectDelegatee = await getRandomAddress();
});

async function subject(): Promise<any> {
return snapshotGovernanceAdapter.getDelegateCalldata(subjectDelegatee);
}

it("should return correct data for delegating", async () => {
const [targetAddress, ethValue, callData] = await subject();
const expectedCallData = delegateRegistry.interface.encodeFunctionData("setDelegate", [ZERO_BYTES, subjectDelegatee]);

expect(targetAddress).to.eq(delegateRegistry.address);
expect(ethValue).to.eq(ZERO);
expect(callData).to.eq(expectedCallData);
});
});

describe("#getRevokeCallData", async () => {
async function subject(): Promise<any> {
return snapshotGovernanceAdapter.getRevokeCalldata();
}

it("shoud return correct data for revoking", async () => {
const [targetAddress, ethValue, callData] = await subject();
const expectedCallData = delegateRegistry.interface.encodeFunctionData("clearDelegate", [ZERO_BYTES]);

expect(targetAddress).to.eq(delegateRegistry.address);
expect(ethValue).to.eq(ZERO);
expect(callData).to.eq(expectedCallData);
});
});
});
2 changes: 2 additions & 0 deletions utils/contracts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export { CustomSetValuerMock } from "../../typechain/CustomSetValuerMock";
export { DebtIssuanceMock } from "../../typechain/DebtIssuanceMock";
export { DebtIssuanceModule } from "../../typechain/DebtIssuanceModule";
export { DebtModuleMock } from "../../typechain/DebtModuleMock";
export { DelegateRegistry } from "../../typechain/DelegateRegistry";
export { ExplicitERC20Mock } from "../../typechain/ExplicitERC20Mock";
export { ForceFunderMock } from "../../typechain/ForceFunderMock";
export { GaugeControllerMock } from "../../typechain/GaugeControllerMock";
Expand Down Expand Up @@ -67,6 +68,7 @@ export { SetToken } from "../../typechain/SetToken";
export { SetTokenCreator } from "../../typechain/SetTokenCreator";
export { SetValuer } from "../../typechain/SetValuer";
export { SingleIndexModule } from "../../typechain/SingleIndexModule";
export { SnapshotGovernanceAdapter } from "../../typechain/SnapshotGovernanceAdapter";
export { StakingAdapterMock } from "../../typechain/StakingAdapterMock";
export { StakingModule } from "../../typechain/StakingModule";
export { StakingRewards } from "../../typechain/StakingRewards";
Expand Down
6 changes: 6 additions & 0 deletions utils/deploys/deployAdapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
UniswapV2IndexExchangeAdapter,
UniswapV2TransferFeeExchangeAdapter,
ZeroExApiAdapter,
SnapshotGovernanceAdapter,
SynthetixExchangeAdapter,
CompoundBravoGovernanceAdapter,
CompClaimAdapter,
Expand All @@ -35,6 +36,7 @@ import { KyberExchangeAdapter__factory } from "../../typechain/factories/KyberEx
import { KyberMigrationWrapAdapter__factory } from "../../typechain/factories/KyberMigrationWrapAdapter__factory";
import { OneInchExchangeAdapter__factory } from "../../typechain/factories/OneInchExchangeAdapter__factory";
import { ZeroExApiAdapter__factory } from "../../typechain/factories/ZeroExApiAdapter__factory";
import { SnapshotGovernanceAdapter__factory } from "../../typechain/factories/SnapshotGovernanceAdapter__factory";
import { AaveMigrationWrapAdapter__factory } from "../../typechain/factories/AaveMigrationWrapAdapter__factory";
import { AaveWrapAdapter__factory } from "../../typechain/factories/AaveWrapAdapter__factory";
import { CompoundWrapAdapter__factory } from "../../typechain/factories/CompoundWrapAdapter__factory";
Expand Down Expand Up @@ -143,6 +145,10 @@ export default class DeployAdapters {
return await new CompoundBravoGovernanceAdapter__factory(this._deployerSigner).deploy(governorBravo, governanceToken);
}

public async deploySnapshotGovernanceAdapter(delegateRegistryAddress: Address): Promise<SnapshotGovernanceAdapter> {
return await new SnapshotGovernanceAdapter__factory(this._deployerSigner).deploy(delegateRegistryAddress);
}

public async deployCurveStakingAdapter(gaugeController: Address): Promise<CurveStakingAdapter> {
return await new CurveStakingAdapter__factory(this._deployerSigner).deploy(gaugeController);
}
Expand Down
7 changes: 7 additions & 0 deletions utils/deploys/deployExternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from "./../contracts/compound";
import {
WETH9,
DelegateRegistry
} from "./../contracts";

import { Address } from "./../types";
Expand All @@ -31,6 +32,7 @@ import { CompoundGovernorBravoDelegator__factory } from "../../typechain/factori
import { CompoundGovernorBravoDelegate__factory } from "../../typechain/factories/CompoundGovernorBravoDelegate__factory";
import { CompoundTimelock__factory } from "../../typechain/factories/CompoundTimelock__factory";
import { Comptroller__factory } from "../../typechain/factories/Comptroller__factory";
import { DelegateRegistry__factory } from "../../typechain/factories/DelegateRegistry__factory";
import { PriceOracleProxy__factory } from "../../typechain/factories/PriceOracleProxy__factory";
import { Unitroller__factory } from "../../typechain/factories/Unitroller__factory";
import { WETH9__factory } from "../../typechain/factories/WETH9__factory";
Expand Down Expand Up @@ -160,6 +162,11 @@ export default class DeployExternalContracts {
this._deployerSigner = deployerSigner;
}

// SNAPSHOT
public async deployDelegateRegistry(): Promise<DelegateRegistry> {
return await new DelegateRegistry__factory(this._deployerSigner).deploy();
}

// COMPOUND
public async deployComp(_account: Address): Promise<Comp> {
return await new Comp__factory(this._deployerSigner).deploy(_account);
Expand Down