Skip to content

Commit d90c1a4

Browse files
committed
Introduce the management of balances within Ethereum contracts.
1 parent 13c09b8 commit d90c1a4

File tree

19 files changed

+1163
-519
lines changed

19 files changed

+1163
-519
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ edition = "2021"
7373

7474
[workspace.dependencies]
7575
alloy = { version = "1.0.5", default-features = false }
76-
alloy-primitives = { version = "1.1.0", default-features = false, features = [
76+
alloy-primitives = { version = "1.3.0", default-features = false, features = [
7777
"serde",
7878
"k256",
7979
] }

examples/Cargo.lock

Lines changed: 16 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ members = [
2525
]
2626

2727
[workspace.dependencies]
28-
alloy-primitives = { version = "1.0.0", default-features = false }
28+
alloy-primitives = { version = "1.3.0", default-features = false }
2929
alloy-sol-types = { version = "1.0.0", default-features = false }
3030
anyhow = "1.0.80"
3131
assert_matches = "1.5.0"

examples/call-evm-counter/src/contract.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use alloy_sol_types::{sol, SolCall};
88
use call_evm_counter::{CallCounterAbi, CallCounterOperation};
99
use linera_sdk::{
1010
abis::evm::EvmAbi,
11-
linera_base_types::{ApplicationId, WithContractAbi},
11+
linera_base_types::{get_evm_operation, Amount, ApplicationId, WithContractAbi},
1212
Contract, ContractRuntime,
1313
};
1414

@@ -56,13 +56,15 @@ impl Contract for CallCounterContract {
5656
match operation {
5757
CallCounterOperation::Increment(increment) => {
5858
let operation = incrementCall { input: increment };
59-
let operation = operation.abi_encode();
59+
let operation =
60+
get_evm_operation(Amount::ZERO, operation.abi_encode()).expect("A mutation");
6061
self.process_operation(operation)
6162
}
6263
CallCounterOperation::TestCallAddress => {
6364
let remote_address = address!("0000000000000000000000000000000000000000");
6465
let operation = call_from_wasmCall { remote_address };
65-
let operation = operation.abi_encode();
66+
let operation =
67+
get_evm_operation(Amount::ZERO, operation.abi_encode()).expect("A mutation");
6668
self.process_operation(operation)
6769
}
6870
}

linera-base/src/data_types.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,25 @@ impl From<Amount> for U256 {
8888
}
8989
}
9090

91+
/// Converting amount from `U256` to Amount can fail since
92+
/// `Amount` is a `u128`.
93+
#[derive(Error, Debug)]
94+
pub struct AmountConversionError(U256);
95+
96+
impl fmt::Display for AmountConversionError {
97+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98+
write!(f, "Amount conversion error for {}", self.0)
99+
}
100+
}
101+
102+
impl TryFrom<U256> for Amount {
103+
type Error = AmountConversionError;
104+
fn try_from(value: U256) -> Result<Amount, Self::Error> {
105+
let value = u128::try_from(&value).map_err(|_| AmountConversionError(value))?;
106+
Ok(Amount(value))
107+
}
108+
}
109+
91110
/// A block height to identify blocks in a chain.
92111
#[derive(
93112
Eq,
@@ -1606,6 +1625,8 @@ mod metrics {
16061625
mod tests {
16071626
use std::str::FromStr;
16081627

1628+
use alloy_primitives::U256;
1629+
16091630
use super::{Amount, BlobContent};
16101631
use crate::identifiers::BlobType;
16111632

@@ -1665,4 +1686,12 @@ mod tests {
16651686
assert_eq!(hash1, hash2, "Hashes should be equal for same content");
16661687
assert_eq!(blob1.bytes(), blob2.bytes(), "Byte content should be equal");
16671688
}
1689+
1690+
#[test]
1691+
fn test_conversion_amount_u256() {
1692+
let value_amount = Amount::from_tokens(15656565652209004332);
1693+
let value_u256: U256 = value_amount.into();
1694+
let value_amount_rev = Amount::try_from(value_u256).expect("Failed conversion");
1695+
assert_eq!(value_amount, value_amount_rev);
1696+
}
16681697
}

linera-base/src/identifiers.rs

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ impl AccountOwner {
7979
}
8080
}
8181

82+
#[cfg(with_revm)]
83+
impl From<Address> for AccountOwner {
84+
fn from(address: Address) -> Self {
85+
let address = address.into_array();
86+
AccountOwner::Address20(address)
87+
}
88+
}
89+
8290
#[cfg(with_testing)]
8391
impl From<CryptoHash> for AccountOwner {
8492
fn from(address: CryptoHash) -> Self {
@@ -416,7 +424,12 @@ impl GenericApplicationId {
416424

417425
impl<A> From<ApplicationId<A>> for AccountOwner {
418426
fn from(app_id: ApplicationId<A>) -> Self {
419-
AccountOwner::Address32(app_id.application_description_hash)
427+
if app_id.is_evm() {
428+
let hash_bytes = app_id.application_description_hash.as_bytes();
429+
AccountOwner::Address20(hash_bytes[..20].try_into().unwrap())
430+
} else {
431+
AccountOwner::Address32(app_id.application_description_hash)
432+
}
420433
}
421434
}
422435

@@ -960,6 +973,14 @@ impl<A> ApplicationId<A> {
960973
}
961974
}
962975

976+
impl<A> ApplicationId<A> {
977+
/// Returns whether the `ApplicationId` is the one of an EVM application.
978+
pub fn is_evm(&self) -> bool {
979+
let bytes = self.application_description_hash.as_bytes();
980+
bytes.0[20..] == [0; 12]
981+
}
982+
}
983+
963984
#[cfg(with_revm)]
964985
impl From<Address> for ApplicationId {
965986
fn from(address: Address) -> ApplicationId {
@@ -985,18 +1006,6 @@ impl<A> ApplicationId<A> {
9851006
pub fn bytes32(&self) -> B256 {
9861007
*self.application_description_hash.as_bytes()
9871008
}
988-
989-
/// Returns whether the `ApplicationId` is the one of an EVM application.
990-
pub fn is_evm(&self) -> bool {
991-
let bytes = self.application_description_hash.as_bytes();
992-
let bytes = bytes.0.as_ref();
993-
for byte in &bytes[20..] {
994-
if byte != &0 {
995-
return false;
996-
}
997-
}
998-
true
999-
}
10001009
}
10011010

10021011
#[derive(Serialize, Deserialize)]
@@ -1261,4 +1270,18 @@ mod tests {
12611270
let stream_id2 = StreamId::from_str(&format!("{stream_id1}")).unwrap();
12621271
assert_eq!(stream_id1, stream_id2);
12631272
}
1273+
1274+
#[cfg(with_revm)]
1275+
#[test]
1276+
fn test_address_account_owner() {
1277+
use alloy_primitives::Address;
1278+
let mut vec = Vec::new();
1279+
for i in 0..20 {
1280+
vec.push(i as u8);
1281+
}
1282+
let address1 = Address::from_slice(&vec);
1283+
let account_owner = AccountOwner::from(address1);
1284+
let address2 = account_owner.to_evm_address().unwrap();
1285+
assert_eq!(address1, address2);
1286+
}
12641287
}

linera-base/src/vm.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,34 @@ pub enum EvmQuery {
6363
/// A read-only query.
6464
Query(Vec<u8>),
6565
/// A request to schedule an operation that can mutate the application state.
66-
Mutation(Vec<u8>),
66+
Operation(Vec<u8>),
67+
}
68+
69+
/// An EVM operation containing a value and argument data.
70+
#[derive(Debug, Default, Serialize, Deserialize)]
71+
pub struct EvmOperation {
72+
/// The amount being transferred.
73+
pub value: alloy_primitives::U256,
74+
/// The encoded argument data.
75+
pub argument: Vec<u8>,
76+
}
77+
78+
/// Creates an operation from value and argument data.
79+
pub fn get_evm_operation(
80+
amount: crate::data_types::Amount,
81+
argument: Vec<u8>,
82+
) -> Result<Vec<u8>, bcs::Error> {
83+
let value = amount.into();
84+
let evm_operation = EvmOperation { value, argument };
85+
bcs::to_bytes(&evm_operation)
86+
}
87+
88+
/// The instantiation argument to EVM smart contracts.
89+
/// `value` is the amount being transferred.
90+
#[derive(Default, Serialize, Deserialize)]
91+
pub struct EvmInstantiation {
92+
/// The initial value put in the instantiation of the contract.
93+
pub value: alloy_primitives::U256,
94+
/// The input to the `fn instantiate` of the EVM smart contract.
95+
pub argument: Vec<u8>,
6796
}

0 commit comments

Comments
 (0)