Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement OpenGov Precompiles #1885

Merged
merged 61 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
50562c0
stash precompile changes in other branch and push pallet changes leak…
4meta5 Oct 20, 2022
9395e66
still leaking std
4meta5 Oct 20, 2022
8ed14e7
using sp std phantomdata did not fix
4meta5 Oct 21, 2022
315116a
ty @nanocryk for std leak fix
4meta5 Oct 21, 2022
8f24362
init referenda precompile needs tryfrom u8 for origins
4meta5 Oct 23, 2022
d83be8e
referenda submit precompile fn
4meta5 Oct 23, 2022
21ffc60
signed extrinsics for referenda precompile
4meta5 Oct 23, 2022
0eb6dc3
preimage precompile
4meta5 Oct 24, 2022
09e90db
init conviction voting precompile
4meta5 Oct 24, 2022
138a848
referenda delegate undelegate unlock
4meta5 Oct 25, 2022
8e1a709
fixes
4meta5 Oct 26, 2022
276d8a4
fix
4meta5 Oct 26, 2022
a940199
clean
4meta5 Oct 26, 2022
a9ab0e3
improve revert reasons for class and index inputs
4meta5 Oct 26, 2022
9067ba0
clean
4meta5 Oct 26, 2022
467e845
init accessors and clean
4meta5 Nov 3, 2022
c6c8d1b
Merge branch 'master' into amar-gov2-precompiles
4meta5 Nov 7, 2022
4d8f70a
referenda precompile
4meta5 Nov 16, 2022
a234655
clean
4meta5 Nov 16, 2022
def4e70
Merge branch 'master' into amar-gov2-precompiles
4meta5 Nov 21, 2022
e86512c
clean and init referenda precompile interface
4meta5 Nov 21, 2022
66e5164
into master
4meta5 Jan 2, 2023
c389722
fix merge
4meta5 Jan 4, 2023
5bb1673
try mock referenda precompile but did not succeed
4meta5 Jan 4, 2023
e7c765b
save
4meta5 Jan 6, 2023
c5e2220
fix referenda mock
nanocryk Jan 9, 2023
d05803f
add dot sol files for preimage and voting
4meta5 Jan 9, 2023
b784aca
add to moonbase precompiles
4meta5 Jan 9, 2023
f1c55b5
fix
4meta5 Jan 10, 2023
58620ed
precompile existence test fix
4meta5 Jan 10, 2023
6ed417f
update solidity addresses as per moonbase config
4meta5 Jan 10, 2023
2fcef74
rename standard vote to vote in conviction voting pallet
4meta5 Jan 11, 2023
8723589
start moving origins out of pallet and using additional generic instead
4meta5 Jan 11, 2023
a1f469e
fix finish moving pallet custom origins back into runtime
4meta5 Jan 11, 2023
3e4e868
into master
4meta5 Jan 11, 2023
72f78a1
Merge branch 'master' into amar-gov2-precompiles
librelois Jan 12, 2023
e1f84ca
add opengov precompiles in proxy evm filter
librelois Jan 12, 2023
6064e97
SolidityConvert no longer necessary
4meta5 Jan 12, 2023
19c2914
rm SolidityConvert and add Conviction enum
4meta5 Jan 12, 2023
046a7ac
use trackId as input for submit instead of origin and convert from tr…
4meta5 Jan 12, 2023
7839709
camelCase error msgs
4meta5 Jan 12, 2023
3357394
Update precompiles/referenda/src/lib.rs
4meta5 Jan 12, 2023
5efa9d5
fix conviction precompile interface
4meta5 Jan 12, 2023
145f6f9
fix referenda precompile interface
4meta5 Jan 12, 2023
694378d
test to ensure all tracks have min enactment period less than vote lo…
4meta5 Jan 12, 2023
9bfd9ff
update tracks based on wiki
4meta5 Jan 12, 2023
a11ee95
revert accidental commit
4meta5 Jan 12, 2023
a1941ec
fix referenda precompile unit tests
4meta5 Jan 12, 2023
6e99180
update config based on polkadot 6372 gov2 config tweaks
4meta5 Jan 12, 2023
83e5a1c
fix
4meta5 Jan 12, 2023
362fef7
Configure moonriver OpenGov (#2038)
4meta5 Jan 17, 2023
af079a9
into master
4meta5 Jan 17, 2023
db81510
remove TryFrom u8 impl for Origin unused
4meta5 Jan 17, 2023
d3a8bda
split convictionVoting vote into voteYes and voteNo so can add voteAb…
4meta5 Jan 17, 2023
4c3e81b
fix consistent conversion test
4meta5 Jan 17, 2023
fd381a7
Merge branch 'master' into amar-gov2-precompiles
4meta5 Jan 17, 2023
be79f7c
follow suggestions
4meta5 Jan 17, 2023
dea9998
add doc note to removeOtherVote
4meta5 Jan 17, 2023
052a56e
into master
4meta5 Jan 17, 2023
d4782eb
fix
4meta5 Jan 17, 2023
3cccdb4
Merge branch 'master' into amar-gov2-precompiles
crystalin Jan 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
163 changes: 134 additions & 29 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ members = [
"precompiles/batch",
"precompiles/call-permit",
"precompiles/collective",
"precompiles/conviction-voting",
"precompiles/crowdloan-rewards",
"precompiles/pallet-democracy",
"precompiles/parachain-staking",
"precompiles/preimage",
"precompiles/proxy",
"precompiles/randomness",
"precompiles/referenda",
"precompiles/relay-encoder",
"precompiles/utils",
"precompiles/utils/macro",
Expand Down
57 changes: 57 additions & 0 deletions precompiles/conviction-voting/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[package]
name = "pallet-evm-precompile-conviction-voting"
authors = [ "PureStake" ]
description = "A Precompile to make pallet-conviction-voting calls encoding accessible to pallet-evm"
edition = "2021"
version = "0.1.0"

[dependencies]
log = "0.4"
num_enum = { version = "0.5.3", default-features = false }
rustc-hex = { version = "2.0.1", default-features = false }

# Moonbeam
precompile-utils = { path = "../utils", default-features = false }

# Substrate
frame-support = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32", default-features = false }
frame-system = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32", default-features = false }
pallet-conviction-voting = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32", default-features = false }
parity-scale-codec = { version = "3.0.0", default-features = false, features = [ "derive" ] }
sp-core = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32", default-features = false }
sp-runtime = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32", default-features = false }
sp-std = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32", default-features = false }

# Frontier
fp-evm = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.32", default-features = false }
pallet-evm = { git = "https://github.com/purestake/frontier", branch = "moonbeam-polkadot-v0.9.32", default-features = false, features = [ "forbid-evm-reentrancy" ] }

[dev-dependencies]
derive_more = "0.99"
hex-literal = "0.3.3"
serde = "1.0.100"
sha3 = "0.9"

# Moonbeam
precompile-utils = { path = "../utils", features = [ "testing" ] }

# Substrate
pallet-balances = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32" }
pallet-timestamp = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32" }
scale-info = { version = "2.0", default-features = false, features = [ "derive" ] }
sp-io = { git = "https://github.com/purestake/substrate", branch = "moonbeam-polkadot-v0.9.32", default-features = false }

[features]
default = [ "std" ]
std = [
"fp-evm/std",
"frame-support/std",
"frame-system/std",
"pallet-conviction-voting/std",
"pallet-evm/std",
"parity-scale-codec/std",
"parity-scale-codec/std",
"precompile-utils/std",
"sp-runtime/std",
"sp-std/std",
]
81 changes: 81 additions & 0 deletions precompiles/conviction-voting/ConvictionVoting.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.3;

/// @dev The Conviction Voting contract's address.
address constant Conviction_Voting_ADDRESS = 0x0000000000000000000000000000000000000812;

/// @dev The Conviction Voting contract's instance.
ConvictionVoting constant Conviction_Voting_CONTRACT = ConvictionVoting(
Conviction_Voting_ADDRESS
);

/// @author The Moonbeam Team
/// @title Pallet Conviction Voting Interface
/// @title The interface through which solidity contracts will interact with the Conviction Voting pallet
/// @custom:address 0x0000000000000000000000000000000000000812
interface ConvictionVoting {
/// @dev Defines the conviction multiplier type represented as `uint8`.
/// The values start at `0` with 0.1x multiplier and votes unlocked.
enum Conviction {
None,
Locked1x,
Locked2x,
Locked3x,
Locked4x,
Locked5x,
Locked6x
}

/// @dev Vote in a poll.
/// @custom:selector f56cb3b3
/// @param pollIndex Index of poll
/// @param aye Yes or no vote
/// @param voteAmount Balance locked for vote
/// @param conviction Conviction multiplier for length of vote lock
function vote(
uint256 pollIndex,
bool aye,
uint256 voteAmount,
Conviction conviction
) external;

/// @dev Remove vote in poll
/// @custom:selector 3f68fde4
/// @param pollIndex Index of the poll
function removeVote(uint256 pollIndex) external;

/// @dev Remove vote in poll for other voter
/// @custom:selector 135ef12d
//// @param target The voter to have vote removed
/// @param class The class
/// @param pollIndex the poll index
function removeOtherVote(
address target,
uint256 class,
uint256 pollIndex
) external;

/// @dev Delegate to a representative for the vote class
/// @custom:selector 7efe44c7
/// @param class The class
/// @param representative The representative for the class
/// @param conviction The conviction multiplier
/// @param amount delegated to representative for this vote class
function delegate(
uint256 class,
address representative,
uint256 conviction,
4meta5 marked this conversation as resolved.
Show resolved Hide resolved
4meta5 marked this conversation as resolved.
Show resolved Hide resolved
uint256 amount
) external;

/// @dev Undelegate for the vote class
/// @custom:selector 6c68c0e1
/// @param class The class
function undelegate(uint256 class) external;

/// @dev Unlock tokens locked for vote class
/// @custom:selector f1d2ec1d
/// @param class The class
/// @param target The target address
function unlock(uint256 class, address target) external;
}
241 changes: 241 additions & 0 deletions precompiles/conviction-voting/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
// Copyright 2019-2022 PureStake Inc.
// This file is part of Moonbeam.

// Moonbeam is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Moonbeam is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Moonbeam. If not, see <http://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]
#![feature(assert_matches)]

use fp_evm::PrecompileHandle;
use frame_support::dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo};
use frame_support::traits::{Currency, Polling};
use pallet_conviction_voting::Call as ConvictionVotingCall;
use pallet_conviction_voting::{AccountVote, Conviction, Tally, Vote};
use pallet_evm::AddressMapping;
use precompile_utils::prelude::*;
use sp_core::{H160, U256};
use sp_runtime::traits::StaticLookup;
use sp_std::marker::PhantomData;

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

type BalanceOf<Runtime> = <<Runtime as pallet_conviction_voting::Config>::Currency as Currency<
<Runtime as frame_system::Config>::AccountId,
>>::Balance;
type IndexOf<Runtime> = <<Runtime as pallet_conviction_voting::Config>::Polls as Polling<
Tally<
<<Runtime as pallet_conviction_voting::Config>::Currency as Currency<
<Runtime as frame_system::Config>::AccountId,
>>::Balance,
<Runtime as pallet_conviction_voting::Config>::MaxTurnout,
>,
>>::Index;
type ClassOf<Runtime> = <<Runtime as pallet_conviction_voting::Config>::Polls as Polling<
Tally<
<<Runtime as pallet_conviction_voting::Config>::Currency as Currency<
<Runtime as frame_system::Config>::AccountId,
>>::Balance,
<Runtime as pallet_conviction_voting::Config>::MaxTurnout,
>,
>>::Class;

/// A precompile to wrap the functionality from pallet-conviction-voting.
pub struct ConvictionVotingPrecompile<Runtime>(PhantomData<Runtime>);

#[precompile_utils::precompile]
impl<Runtime> ConvictionVotingPrecompile<Runtime>
where
Runtime: pallet_conviction_voting::Config + pallet_evm::Config + frame_system::Config,
BalanceOf<Runtime>: TryFrom<U256>,
<Runtime as frame_system::Config>::RuntimeCall:
Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo,
<<Runtime as frame_system::Config>::RuntimeCall as Dispatchable>::RuntimeOrigin:
From<Option<Runtime::AccountId>>,
<Runtime as frame_system::Config>::RuntimeCall: From<ConvictionVotingCall<Runtime>>,
IndexOf<Runtime>: TryFrom<u32>,
ClassOf<Runtime>: TryFrom<u16>,
{
/// Vote in a poll.
///
/// Parameters:
/// * poll_index: Index of poll
/// * aye: Yes or no vote
/// * vote_amount: Balance locked for vote
/// * conviction: Conviction multiplier for length of vote lock
#[precompile::public("vote(uint256,bool,uint256,uint256)")]
4meta5 marked this conversation as resolved.
Show resolved Hide resolved
fn vote(
handle: &mut impl PrecompileHandle,
poll_index: u32,
aye: bool,
vote_amount: U256,
conviction: u8,
) -> EvmResult {
let poll_index = Self::u32_to_index(poll_index).in_field("pollIndex")?;
let vote_amount = Self::u256_to_amount(vote_amount).in_field("voteAmount")?;
notlesh marked this conversation as resolved.
Show resolved Hide resolved
let conviction = Self::u8_to_conviction(conviction).in_field("conviction")?;

let vote = AccountVote::Standard {
vote: Vote { aye, conviction },
balance: vote_amount,
};

log::trace!(target: "conviction-voting-precompile",
"Voting {:?} on poll {:?}, with conviction {:?}",
aye, poll_index, conviction
);

let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let call = ConvictionVotingCall::<Runtime>::vote { poll_index, vote }.into();

<RuntimeHelper<Runtime>>::try_dispatch(handle, Some(origin).into(), call)?;

Ok(())
}

#[precompile::public("removeVote(uint256)")]
fn remove_vote(handle: &mut impl PrecompileHandle, poll_index: u32) -> EvmResult {
let index = Self::u32_to_index(poll_index).in_field("pollIndex")?;

log::trace!(
target: "conviction-voting-precompile",
"Removing vote from poll {:?}",
index
);

let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let call = ConvictionVotingCall::<Runtime>::remove_vote { class: None, index };

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

Ok(())
}

#[precompile::public("removeOtherVote(address,uint256,uint256)")]
fn remove_other_vote(
handle: &mut impl PrecompileHandle,
target: Address,
class: u16,
poll_index: u32,
) -> EvmResult {
let class = Self::u16_to_class(class).in_field("class")?;
let index = Self::u32_to_index(poll_index).in_field("pollIndex")?;

let target = Runtime::AddressMapping::into_account_id(target.into());
let target: <Runtime::Lookup as StaticLookup>::Source =
Runtime::Lookup::unlookup(target.clone());

log::trace!(
target: "conviction-voting-precompile",
"Removing other vote from poll {:?}",
index
);

let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let call = ConvictionVotingCall::<Runtime>::remove_other_vote {
target,
class,
index,
};

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

Ok(())
}

#[precompile::public("delegate(uint256,address,uint256,uint256)")]
4meta5 marked this conversation as resolved.
Show resolved Hide resolved
fn delegate(
handle: &mut impl PrecompileHandle,
class: u16,
representative: Address,
conviction: u8,
amount: U256,
) -> EvmResult {
let class = Self::u16_to_class(class).in_field("class")?;
let amount = Self::u256_to_amount(amount).in_field("amount")?;
let conviction = Self::u8_to_conviction(conviction).in_field("conviction")?;

log::trace!(target: "conviction-voting-precompile",
"Delegating vote to {:?} with balance {:?} and conviction {:?}",
representative, amount, conviction
);

let representative = Runtime::AddressMapping::into_account_id(representative.into());
let to: <Runtime::Lookup as StaticLookup>::Source =
Runtime::Lookup::unlookup(representative.clone());
let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let call = ConvictionVotingCall::<Runtime>::delegate {
class,
to,
conviction,
balance: amount,
};

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

Ok(())
}
#[precompile::public("undelegate(uint256)")]
fn undelegate(handle: &mut impl PrecompileHandle, class: u16) -> EvmResult {
let class = Self::u16_to_class(class).in_field("class")?;
let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let call = ConvictionVotingCall::<Runtime>::undelegate { class };

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

Ok(())
}
#[precompile::public("unlock(uint256,address)")]
fn unlock(handle: &mut impl PrecompileHandle, class: u16, target: Address) -> EvmResult {
let class = Self::u16_to_class(class).in_field("class")?;
let target: H160 = target.into();
let target = Runtime::AddressMapping::into_account_id(target);
let target: <Runtime::Lookup as StaticLookup>::Source =
Runtime::Lookup::unlookup(target.clone());

log::trace!(
target: "conviction-voting-precompile",
"Unlocking conviction-voting tokens for {:?}", target
);

let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let call = ConvictionVotingCall::<Runtime>::unlock { class, target };

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

Ok(())
}
fn u8_to_conviction(conviction: u8) -> MayRevert<Conviction> {
conviction
.try_into()
.map_err(|_| RevertReason::custom("Must be an integer between 0 and 6 included").into())
}
fn u32_to_index(index: u32) -> MayRevert<IndexOf<Runtime>> {
index
.try_into()
.map_err(|_| RevertReason::value_is_too_large("index type").into())
}
fn u16_to_class(class: u16) -> MayRevert<ClassOf<Runtime>> {
class
.try_into()
.map_err(|_| RevertReason::value_is_too_large("class type").into())
}
fn u256_to_amount(value: U256) -> MayRevert<BalanceOf<Runtime>> {
value
.try_into()
.map_err(|_| RevertReason::value_is_too_large("balance type").into())
}
}