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

Add OpenGov precompile logs #2071

Merged
merged 23 commits into from
Feb 14, 2023
Merged
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
70 changes: 70 additions & 0 deletions precompiles/conviction-voting/ConvictionVoting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,74 @@ interface ConvictionVoting {
/// @param trackId The trackId
/// @param target The target address
function unlock(uint16 trackId, address target) external;

/// @dev An account made a vote in a poll.
/// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e
/// @param pollIndex uint32 Index of the poll.
/// @param voter address Address of the voter.
/// @param aye bool Is it a vote for or against the poll.
/// @param voteAmount uint256 Amount used to vote.
/// @param conviction uint8 Conviction of the vote.
event Voted(
uint32 indexed pollIndex,
address voter,
bool aye,
uint256 voteAmount,
uint8 conviction
);

/// @dev An account removed its vote from an ongoing poll.
/// @custom:selector 49fc1dd929f126e1d88cbb9c135625e30c2deba291adeea4740e446098b9957b
/// @param pollIndex uint32 Index of the poll.
/// @param voter address Address of the voter.
event VoteRemoved(
uint32 indexed pollIndex,
address voter
);

/// @dev An account removed a vote from a poll.
/// @custom:selector c1d068675720ab00d0c8792a0cbc7e198c0d2202111f0280f039f2c09c50491b
/// @param pollIndex uint32 Index of the poll.
/// @param caller address Address of the origin caller.
/// @param target address Address of the address which's vote is being removed.
/// @param trackId uint16 The trackId.
event VoteRemovedOther(
uint32 indexed pollIndex,
address caller,
address target,
uint16 trackId
);

/// @dev An account delegated for the given trackId.
/// @custom:selector 6cc151d547592e227b1e85a264ac3699c6f1014112b08bb3832de1f23b9c66db
/// @param trackId uint16 The trackId.
/// @param from address Address of the caller.
/// @param to address Address of the representative.
/// @param delegatedAmount uint256 Amount being delegated.
/// @param conviction uint8 Conviction being delegated.
event Delegated(
uint16 indexed trackId,
address from,
address to,
uint256 delegatedAmount,
uint8 conviction
);

/// @dev An account undelegated for the given trackId.
/// @custom:selector 1053303328f6db14014ccced6297bcad2b3897157ce46070711ab995a05dfa14
/// @param trackId uint16 The trackId.
/// @param caller address Address of the caller.
event Undelegated(
uint16 indexed trackId,
address caller
);

/// @dev An account called to unlock tokens for the given trackId.
/// @custom:selector dcf72fa65ca7fb720b9ccc8ee28e0188edc3d943115124cdd4086c49f836a128
/// @param trackId uint16 The trackId.
/// @param caller address Address of the caller.
event Unlocked(
uint16 indexed trackId,
address caller
);
}
129 changes: 118 additions & 11 deletions precompiles/conviction-voting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ 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_core::{H160, H256, U256};
use sp_runtime::traits::StaticLookup;
use sp_std::marker::PhantomData;

Expand Down Expand Up @@ -53,8 +53,29 @@ type ClassOf<Runtime> = <<Runtime as pallet_conviction_voting::Config>::Polls as
>,
>>::Class;

/// Solidity selector of the Vote log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_VOTED: [u8; 32] =
keccak256!("Voted(uint32,address,bool,uint256,uint8)");

/// Solidity selector of the VoteRemove log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_VOTE_REMOVED: [u8; 32] = keccak256!("VoteRemoved(uint32,address)");

/// Solidity selector of the VoteRemoveOther log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_VOTE_REMOVED_OTHER: [u8; 32] =
keccak256!("VoteRemovedOther(uint32,address,address,uint16)");

/// Solidity selector of the Delegate log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_DELEGATED: [u8; 32] =
keccak256!("Delegated(uint16,address,address,uint256,uint8)");

/// Solidity selector of the Undelegate log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_UNDELEGATED: [u8; 32] = keccak256!("Undelegated(uint16,address)");

/// Solidity selector of the Unlock log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_UNLOCKED: [u8; 32] = keccak256!("Unlocked(uint16,address)");

/// Direction of vote
enum VoteDirection {
pub(crate) enum VoteDirection {
Yes,
No,
#[allow(unused)]
Expand Down Expand Up @@ -85,15 +106,28 @@ where
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")?;
let conviction = Self::u8_to_conviction(conviction).in_field("conviction")?;

let caller = handle.context().caller;
let aye = match vote {
VoteDirection::Yes => true,
VoteDirection::No => false,
_ => return Err(RevertReason::custom("Abstain not supported").into()),
};
let event = log2(
handle.context().address,
SELECTOR_LOG_VOTED,
H256::from_low_u64_be(poll_index as u64), // poll index,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.write::<bool>(aye)
.write::<U256>(vote_amount)
.write::<u8>(conviction)
.build(),
);
handle.record_log_costs(&[&event])?;

let poll_index = Self::u32_to_index(poll_index).in_field("pollIndex")?;
let vote_amount = Self::u256_to_amount(vote_amount).in_field("voteAmount")?;
let conviction = Self::u8_to_conviction(conviction).in_field("conviction")?;

let vote = AccountVote::Standard {
vote: Vote { aye, conviction },
Expand All @@ -105,11 +139,13 @@ where
aye, poll_index, conviction
);

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

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

event.record(handle)?;

Ok(())
}

Expand Down Expand Up @@ -159,6 +195,17 @@ where

#[precompile::public("removeVote(uint32)")]
fn remove_vote(handle: &mut impl PrecompileHandle, poll_index: u32) -> EvmResult {
let caller = handle.context().caller;
let event = log2(
handle.context().address,
SELECTOR_LOG_VOTE_REMOVED,
H256::from_low_u64_be(poll_index as u64), // poll index,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.build(),
);
handle.record_log_costs(&[&event])?;

let index = Self::u32_to_index(poll_index).in_field("pollIndex")?;

log::trace!(
Expand All @@ -167,11 +214,13 @@ where
index
);

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

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

event.record(handle)?;

Ok(())
}

Expand All @@ -182,6 +231,20 @@ where
track_id: u16,
poll_index: u32,
) -> EvmResult {
let caller = handle.context().caller;

let event = log2(
handle.context().address,
SELECTOR_LOG_VOTE_REMOVED_OTHER,
H256::from_low_u64_be(poll_index as u64), // poll index,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.write::<Address>(target)
.write::<u16>(track_id)
.build(),
);
handle.record_log_costs(&[&event])?;

let class = Self::u16_to_track_id(track_id).in_field("trackId")?;
let index = Self::u32_to_index(poll_index).in_field("pollIndex")?;

Expand All @@ -195,7 +258,7 @@ where
index
);

let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let origin = Runtime::AddressMapping::into_account_id(caller);
let call = ConvictionVotingCall::<Runtime>::remove_other_vote {
target,
class,
Expand All @@ -204,6 +267,8 @@ where

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

event.record(handle)?;

Ok(())
}

Expand All @@ -215,6 +280,21 @@ where
conviction: u8,
amount: U256,
) -> EvmResult {
let caller = handle.context().caller;

let event = log2(
handle.context().address,
SELECTOR_LOG_DELEGATED,
H256::from_low_u64_be(track_id as u64), // track id,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.write::<Address>(representative)
.write::<U256>(amount)
.write::<u8>(conviction)
.build(),
);
handle.record_log_costs(&[&event])?;

let class = Self::u16_to_track_id(track_id).in_field("trackId")?;
let amount = Self::u256_to_amount(amount).in_field("amount")?;
let conviction = Self::u8_to_conviction(conviction).in_field("conviction")?;
Expand All @@ -227,7 +307,7 @@ where
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 origin = Runtime::AddressMapping::into_account_id(caller);
let call = ConvictionVotingCall::<Runtime>::delegate {
class,
to,
Expand All @@ -237,21 +317,46 @@ where

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

event.record(handle)?;

Ok(())
}
#[precompile::public("undelegate(uint16)")]
fn undelegate(handle: &mut impl PrecompileHandle, track_id: u16) -> EvmResult {
let caller = handle.context().caller;

let event = log2(
handle.context().address,
SELECTOR_LOG_UNDELEGATED,
H256::from_low_u64_be(track_id as u64), // track id,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.build(),
);
handle.record_log_costs(&[&event])?;

let class = Self::u16_to_track_id(track_id).in_field("trackId")?;
let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let origin = Runtime::AddressMapping::into_account_id(caller);
let call = ConvictionVotingCall::<Runtime>::undelegate { class };

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

event.record(handle)?;

Ok(())
}
#[precompile::public("unlock(uint16,address)")]
fn unlock(handle: &mut impl PrecompileHandle, track_id: u16, target: Address) -> EvmResult {
let class = Self::u16_to_track_id(track_id).in_field("trackId")?;

let event = log2(
handle.context().address,
SELECTOR_LOG_UNLOCKED,
H256::from_low_u64_be(track_id as u64), // track id,
EvmDataWriter::new().write::<Address>(target).build(),
);
handle.record_log_costs(&[&event])?;

let target: H160 = target.into();
let target = Runtime::AddressMapping::into_account_id(target);
let target: <Runtime::Lookup as StaticLookup>::Source =
Expand All @@ -267,6 +372,8 @@ where

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

event.record(handle)?;

Ok(())
}
fn u8_to_conviction(conviction: u8) -> MayRevert<Conviction> {
Expand Down
45 changes: 44 additions & 1 deletion precompiles/conviction-voting/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,47 @@ impl pallet_conviction_voting::Config for Runtime {
type Polls = TestPolls;
}

// genesis builder TODO
pub(crate) struct ExtBuilder {
/// Endowed accounts with balances
balances: Vec<(AccountId, Balance)>,
}

impl Default for ExtBuilder {
fn default() -> ExtBuilder {
ExtBuilder { balances: vec![] }
}
}

impl ExtBuilder {
/// Fund some accounts before starting the test
pub(crate) fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self {
self.balances = balances;
self
}

/// Build the test externalities for use in tests
pub(crate) fn build(self) -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default()
.build_storage::<Runtime>()
.expect("Frame system builds valid default genesis config");

pallet_balances::GenesisConfig::<Runtime> {
balances: self.balances.clone(),
}
.assimilate_storage(&mut t)
.expect("Pallet balances storage can be assimilated");

let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| {
System::set_block_number(1);
});
ext
}
}

pub(crate) fn events() -> Vec<RuntimeEvent> {
System::events()
.into_iter()
.map(|r| r.event)
.collect::<Vec<_>>()
}
Loading