Skip to content

Commit

Permalink
Implement components to invoke Starknet contract (#35)
Browse files Browse the repository at this point in the history
* Add HasStarknetProvider trait

* Add HasStarknetAccount trait

* Add account field to chain context

* Implement InvokeStarknetContract

* Implement CanInvokeContract for StarknetChain

* Test call to invoke

* Ad hoc check that transfer is successful
  • Loading branch information
soareschen authored Jul 30, 2024
1 parent 0a5933c commit dfdd0e8
Show file tree
Hide file tree
Showing 17 changed files with 268 additions and 14 deletions.
1 change: 1 addition & 0 deletions relayer/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions relayer/crates/starknet-chain-components/src/components.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use cgp_core::prelude::*;
pub use hermes_relayer_components::transaction::traits::types::tx_hash::TransactionHashTypeComponent;

use crate::impls::contract::call::CallStarknetContract;
use crate::impls::contract::invoke::InvokeStarknetContract;
use crate::impls::types::address::ProvideFeltAddressType;
use crate::impls::types::blob::ProvideFeltBlobType;
use crate::impls::types::method::ProvideFeltMethodSelector;
use crate::impls::types::tx_hash::ProvideFeltTxHash;
pub use crate::traits::contract::call::ContractCallerComponent;
pub use crate::traits::contract::invoke::ContractInvokerComponent;
pub use crate::traits::types::address::AddressTypeComponent;
pub use crate::traits::types::blob::BlobTypeComponent;
pub use crate::traits::types::method::MethodSelectorTypeComponent;
Expand All @@ -15,9 +19,13 @@ define_components! {
ProvideFeltAddressType,
BlobTypeComponent:
ProvideFeltBlobType,
TransactionHashTypeComponent:
ProvideFeltTxHash,
MethodSelectorTypeComponent:
ProvideFeltMethodSelector,
ContractCallerComponent:
CallStarknetContract,
ContractInvokerComponent:
InvokeStarknetContract,
}
}
29 changes: 29 additions & 0 deletions relayer/crates/starknet-chain-components/src/impls/account.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::marker::PhantomData;

use cgp_core::prelude::*;
use starknet::accounts::ConnectedAccount;

use crate::traits::account::{
HasStarknetAccountType, ProvideStarknetAccountType, StarknetAccountGetter,
};

pub struct GetStarknetAccountField<Tag>(pub PhantomData<Tag>);

impl<Chain, Tag> ProvideStarknetAccountType<Chain> for GetStarknetAccountField<Tag>
where
Chain: Async + HasField<Tag>,
Tag: Async,
Chain::Field: Async + ConnectedAccount,
{
type Account = Chain::Field;
}

impl<Chain, Tag> StarknetAccountGetter<Chain> for GetStarknetAccountField<Tag>
where
Chain: Async + HasStarknetAccountType + HasField<Tag, Field = Chain::Account>,
Tag: Async,
{
fn account(chain: &Chain) -> &Chain::Account {
chain.get_field(PhantomData)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use cgp_core::error::CanRaiseError;
use starknet::core::types::{BlockId, BlockTag, Felt, FunctionCall};
use starknet::providers::{Provider, ProviderError};

use crate::traits::client::HasJsonRpcClient;
use crate::traits::contract::call::ContractCaller;
use crate::traits::provider::HasStarknetProvider;
use crate::traits::types::address::HasAddressType;
use crate::traits::types::blob::HasBlobType;
use crate::traits::types::method::HasMethodSelectorType;
Expand All @@ -15,7 +15,7 @@ where
Chain: HasAddressType<Address = Felt>
+ HasMethodSelectorType<MethodSelector = Felt>
+ HasBlobType<Blob = Vec<Felt>>
+ HasJsonRpcClient
+ HasStarknetProvider
+ CanRaiseError<ProviderError>,
{
async fn call_contract(
Expand All @@ -27,7 +27,7 @@ where
let block_id = BlockId::Tag(BlockTag::Pending);

let res = chain
.json_rpc_client()
.provider()
.call(
FunctionCall {
contract_address: *contract_address,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use hermes_relayer_components::transaction::traits::types::tx_hash::HasTransactionHashType;
use starknet::accounts::{Account, Call};
use starknet::core::types::Felt;

use crate::traits::account::{CanRaiseAccountErrors, HasStarknetAccount};
use crate::traits::contract::invoke::ContractInvoker;
use crate::traits::provider::HasStarknetProvider;
use crate::traits::types::address::HasAddressType;
use crate::traits::types::blob::HasBlobType;
use crate::traits::types::method::HasMethodSelectorType;

pub struct InvokeStarknetContract;

impl<Chain> ContractInvoker<Chain> for InvokeStarknetContract
where
Chain: HasAddressType<Address = Felt>
+ HasMethodSelectorType<MethodSelector = Felt>
+ HasBlobType<Blob = Vec<Felt>>
+ HasTransactionHashType<TxHash = Felt>
+ HasStarknetProvider
+ HasStarknetAccount
+ CanRaiseAccountErrors,
{
async fn invoke_contract(
chain: &Chain,
contract_address: &Felt,
entry_point_selector: &Felt,
calldata: &Vec<Felt>,
) -> Result<Felt, Chain::Error> {
let account = chain.account();

let call = Call {
to: *contract_address,
selector: *entry_point_selector,
calldata: calldata.clone(),
};

let execution = account.execute_v3(vec![call]);

let tx_hash = execution
.send()
.await
.map_err(Chain::raise_error)?
.transaction_hash;

Ok(tx_hash)
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod call;
pub mod invoke;
2 changes: 2 additions & 0 deletions relayer/crates/starknet-chain-components/src/impls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pub mod account;
pub mod contract;
pub mod provider;
pub mod types;
29 changes: 29 additions & 0 deletions relayer/crates/starknet-chain-components/src/impls/provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::marker::PhantomData;

use cgp_core::prelude::*;
use starknet::providers::Provider;

use crate::traits::provider::{
HasStarknetProviderType, ProvideStarknetProviderType, StarknetProviderGetter,
};

pub struct GetStarknetProviderField<Tag>(pub PhantomData<Tag>);

impl<Chain, Tag> ProvideStarknetProviderType<Chain> for GetStarknetProviderField<Tag>
where
Chain: Async + HasField<Tag>,
Tag: Async,
Chain::Field: Async + Provider,
{
type Provider = Chain::Field;
}

impl<Chain, Tag> StarknetProviderGetter<Chain> for GetStarknetProviderField<Tag>
where
Chain: Async + HasStarknetProviderType + HasField<Tag, Field = Chain::Provider>,
Tag: Async,
{
fn provider(chain: &Chain) -> &Chain::Provider {
chain.get_field(PhantomData)
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod address;
pub mod blob;
pub mod method;
pub mod tx_hash;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use cgp_core::Async;
use hermes_relayer_components::transaction::traits::types::tx_hash::ProvideTransactionHashType;
use starknet::core::types::Felt;

pub struct ProvideFeltTxHash;

impl<Chain: Async> ProvideTransactionHashType<Chain> for ProvideFeltTxHash {
type TxHash = Felt;
}
26 changes: 26 additions & 0 deletions relayer/crates/starknet-chain-components/src/traits/account.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use cgp_core::prelude::*;
use starknet::accounts::{Account, AccountError, ConnectedAccount};

#[derive_component(StarknetAccountTypeComponent, ProvideStarknetAccountType<Chain>)]
pub trait HasStarknetAccountType: Async {
type Account: Async + ConnectedAccount;
}

#[derive_component(StarknetAccountGetterComponent, StarknetAccountGetter<Chain>)]
pub trait HasStarknetAccount: HasStarknetAccountType {
fn account(&self) -> &Self::Account;
}

pub trait CanRaiseAccountErrors:
HasStarknetAccountType
+ CanRaiseError<<Self::Account as Account>::SignError>
+ CanRaiseError<AccountError<<Self::Account as Account>::SignError>>
{
}

impl<Chain> CanRaiseAccountErrors for Chain where
Chain: HasStarknetAccountType
+ CanRaiseError<<Chain::Account as Account>::SignError>
+ CanRaiseError<AccountError<<Self::Account as Account>::SignError>>
{
}
2 changes: 2 additions & 0 deletions relayer/crates/starknet-chain-components/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod account;
pub mod client;
pub mod contract;
pub mod provider;
pub mod types;
12 changes: 12 additions & 0 deletions relayer/crates/starknet-chain-components/src/traits/provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use cgp_core::prelude::*;
use starknet::providers::Provider;

#[derive_component(StarknetProviderTypeComponent, ProvideStarknetProviderType<Chain>)]
pub trait HasStarknetProviderType: Async {
type Provider: Async + Provider;
}

#[derive_component(StarknetProviderGetterComponent, StarknetProviderGetter<Chain>)]
pub trait HasStarknetProvider: HasStarknetProviderType {
fn provider(&self) -> &Self::Provider;
}
39 changes: 29 additions & 10 deletions relayer/crates/starknet-chain-context/src/contexts/chain.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
use std::sync::Arc;

use cgp_core::error::{DelegateErrorRaiser, ErrorRaiserComponent, ErrorTypeComponent};
use cgp_core::prelude::*;
use hermes_error::impls::ProvideHermesError;
use hermes_starknet_chain_components::components::*;
use hermes_starknet_chain_components::impls::account::GetStarknetAccountField;
use hermes_starknet_chain_components::impls::provider::GetStarknetProviderField;
use hermes_starknet_chain_components::traits::account::{
HasStarknetAccount, StarknetAccountGetterComponent, StarknetAccountTypeComponent,
};
use hermes_starknet_chain_components::traits::client::JsonRpcClientGetter;
use hermes_starknet_chain_components::traits::contract::call::CanCallContract;
use hermes_starknet_chain_components::traits::contract::invoke::CanInvokeContract;
use hermes_starknet_chain_components::traits::provider::{
HasStarknetProvider, StarknetProviderGetterComponent, StarknetProviderTypeComponent,
};
use hermes_starknet_chain_components::traits::types::address::HasAddressType;
use hermes_starknet_chain_components::traits::types::blob::HasBlobType;
use hermes_starknet_chain_components::traits::types::method::HasMethodSelectorType;
use starknet::accounts::SingleOwnerAccount;
use starknet::core::types::Felt;
use starknet::providers::jsonrpc::HttpTransport;
use starknet::providers::JsonRpcClient;
use url::Url;
use starknet::signers::LocalWallet;

use crate::impls::error::HandleStarknetError;

#[derive(HasField)]
pub struct StarknetChain {
pub rpc_client: JsonRpcClient<HttpTransport>,
pub rpc_client: Arc<JsonRpcClient<HttpTransport>>,
pub account: SingleOwnerAccount<Arc<JsonRpcClient<HttpTransport>>, LocalWallet>,
}

pub struct StarknetChainContextComponents;

impl StarknetChain {
pub fn new(json_rpc_url: Url) -> Self {
let rpc_client = JsonRpcClient::new(HttpTransport::new(json_rpc_url));

Self { rpc_client }
}
}

impl HasComponents for StarknetChain {
type Components = StarknetChainContextComponents;
}
Expand All @@ -36,6 +42,16 @@ delegate_components! {
StarknetChainContextComponents {
ErrorTypeComponent: ProvideHermesError,
ErrorRaiserComponent: DelegateErrorRaiser<HandleStarknetError>,
[
StarknetProviderTypeComponent,
StarknetProviderGetterComponent,
]:
GetStarknetProviderField<symbol!("rpc_client")>,
[
StarknetAccountTypeComponent,
StarknetAccountGetterComponent,
]:
GetStarknetAccountField<symbol!("account")>,
}
}

Expand All @@ -57,7 +73,10 @@ pub trait CanUseStarknetChain:
HasAddressType<Address = Felt>
+ HasMethodSelectorType<MethodSelector = Felt>
+ HasBlobType<Blob = Vec<Felt>>
+ HasStarknetProvider
+ HasStarknetAccount
+ CanCallContract
+ CanInvokeContract
{
}

Expand Down
6 changes: 6 additions & 0 deletions relayer/crates/starknet-chain-context/src/impls/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ use hermes_error::handlers::report::ReportError;
use hermes_error::handlers::wrap::WrapErrorDetail;
use hermes_error::traits::wrap::WrapError;
use hermes_error::types::Error;
use starknet::accounts::{single_owner, AccountError};
use starknet::providers::ProviderError;
use starknet::signers::local_wallet;

pub struct HandleStarknetError;

pub type SignError = single_owner::SignError<local_wallet::SignError>;

delegate_components! {
HandleStarknetError {
Error: ReturnError,
Infallible: HandleInfallible,
[
Report,
ProviderError,
SignError,
AccountError<SignError>,
]: ReportError,
[
<'a> &'a str,
Expand Down
1 change: 1 addition & 0 deletions relayer/crates/starknet-integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ readme = "README.md"
cgp-core = { workspace = true }
hermes-error = { workspace = true }
hermes-relayer-components = { workspace = true }
hermes-runtime-components = { workspace = true }
hermes-starknet-chain-components = { workspace = true }
hermes-starknet-chain-context = { workspace = true }
hermes-cosmos-integration-tests = { workspace = true }
Expand Down
Loading

0 comments on commit dfdd0e8

Please sign in to comment.