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

CallBuilder delegated calls API #1133

Merged
merged 21 commits into from
Mar 8, 2022

Conversation

VargSupercolony
Copy link
Contributor

This PR adds the possibility to make delegated calls into ink!. To achieve this, we:

  1. Add seal_delegate_call unstable interface import
  2. Refactor CallBuilder to two types of calls: Call (meaning cross-contract call) and DelegateCall (meaning delegated calls). This is a breaking change, as now the users must specify call_type on the builder manually, as opposed to it being always Call :)
  3. Add invoke_contract_delegate & eval_contract_delegate functions to backend trait & impls: we call those functions when making a delegated call
  4. Rework codegen for cross-contract calls (add set_call_type)
  5. Update docs in the ink! itself
  6. Update proxy example, rework it to use build_call with DelegateCall call type, add upgradeable flipper to showcase simple upgradeable contract example.

Massive thanks to @yarikbratashchuk for providing initial PoCs & ideas for the implementation.

@@ -420,9 +426,28 @@ impl TypedEnvBackend for EnvInstance {
unimplemented!("off-chain environment does not support contract invocation")
}

#[allow(clippy::type_complexity)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can create an alias to avoid type_complexity everywhere=)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, the compiler gives a warning that the type bounds are not checked.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can do the following:

type CallParamsTypedef<T, A> =
    CallParams<T, DelegateCall<T, <T as Environment>::Hash>, A, ()>;

// -- snip ---

fn invoke_contract_delegate<T, Args>(
    &mut self,
    params: &CallParamsTypedef<T, Args>,
) -> Result<()>
where
    T: Environment,
    Args: scale::Encode,
{
    let _code_hash = params.code_hash();
    unimplemented!("off-chain environment does not support contract invocation")
}

Notice that in the typedef we used fully qualified syntax to specify the trait being used. We should be able to do this everywhere in this PR

examples/proxy/lib.rs Outdated Show resolved Hide resolved
@athei athei linked an issue Feb 16, 2022 that may be closed by this pull request
@athei
Copy link
Contributor

athei commented Feb 23, 2022

Can you please satisfy the CI?

@VargSupercolony
Copy link
Contributor Author

@athei I will fix the errors I get now, but I remember some tests were failing in the ink-waterfall testing job. Is it fixable by doing fixes into my PR, or are there any external tests that are run not from ink?

@athei
Copy link
Contributor

athei commented Feb 23, 2022

The ink waterfall doesn't even start because it is failing before it comes to it. ink-waterfall only runs if the basic tests are successful.

ink-waterfall will fail because the node is too old and you added new functionality to examples which are deployed by the waterfall. I will upgrade the node it so it will be successful tomorrow (waterfall uses latest master of substrate-contracts-node but only updated nightly).

For the new examples you added we would need manually ad them to the ink-waterfall so that they are also deployed and testes there. But first we need to fix CI here.

@codecov-commenter
Copy link

codecov-commenter commented Feb 23, 2022

Codecov Report

Merging #1133 (6321e3f) into master (3122bad) will decrease coverage by 0.04%.
The diff coverage is 3.44%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1133      +/-   ##
==========================================
- Coverage   78.43%   78.39%   -0.05%     
==========================================
  Files         231      231              
  Lines        8760     8760              
==========================================
- Hits         6871     6867       -4     
- Misses       1889     1893       +4     
Impacted Files Coverage Δ
crates/env/src/backend.rs 83.33% <ø> (ø)
crates/env/src/call/call_builder.rs 0.00% <0.00%> (ø)
crates/env/src/call/create_builder.rs 0.00% <0.00%> (ø)
crates/env/src/types.rs 22.22% <ø> (ø)
...odegen/src/generator/as_dependency/call_builder.rs 100.00% <ø> (ø)
...ng/codegen/src/generator/trait_def/call_builder.rs 100.00% <ø> (ø)
crates/lang/src/env_access.rs 12.00% <0.00%> (ø)
...rates/lang/tests/ui/chain_extension/E-01-simple.rs 2.70% <0.00%> (+0.20%) ⬆️
crates/env/src/api.rs 31.81% <7.40%> (ø)
crates/env/src/engine/off_chain/impls.rs 42.50% <9.52%> (ø)
... and 4 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3122bad...6321e3f. Read the comment docs.

@VargSupercolony
Copy link
Contributor Author

@athei, please see that the CI completes before I update to the latest master.

Comment on lines 44 to 70
const PROXY_FIELDS_STORAGE_KEY: [u8; 32] = ink_lang::blake2x256!("ProxyFields");

impl SpreadLayout for ProxyFields {
const FOOTPRINT: u64 =
<AccountId as SpreadLayout>::FOOTPRINT + <Hash as SpreadLayout>::FOOTPRINT;
const REQUIRES_DEEP_CLEAN_UP: bool = false;

fn pull_spread(_: &mut KeyPtr) -> Self {
let mut ptr = KeyPtr::from(Key::from(PROXY_FIELDS_STORAGE_KEY));
Self {
delegate_to: SpreadLayout::pull_spread(&mut ptr),
admin: SpreadLayout::pull_spread(&mut ptr),
}
}

fn push_spread(&self, _: &mut KeyPtr) {
let mut ptr = KeyPtr::from(Key::from(PROXY_FIELDS_STORAGE_KEY));
SpreadLayout::push_spread(&self.delegate_to, &mut ptr);
SpreadLayout::push_spread(&self.admin, &mut ptr);
}

fn clear_spread(&self, _: &mut KeyPtr) {
let mut ptr = KeyPtr::from(Key::from(PROXY_FIELDS_STORAGE_KEY));
SpreadLayout::clear_spread(&self.delegate_to, &mut ptr);
SpreadLayout::clear_spread(&self.admin, &mut ptr);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to repeat some docs on this impl why it is needed (to not conflict with the storage of the called into contract).

This is kind of ugly. But it could be resolved by adding a new attribute to the #[ink(storage)] macro that allows changing the root key, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, but maybe it is okay for now because it will be fixed with #1134


#[ink(storage)]
pub struct Flipper {
value: Upgradable<bool, NotInitialized>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add docs why and what this Upgradable does. It is an example after all. The point is teaching things.

The whole point of this example is to teach people how to write upgradeable contracts.

where
E: Environment,
{
/// The account ID of the to-be-called smart contract.
callee: E::AccountId,
env: PhantomData<fn() -> E>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please call it _phantom and move it to the bottom of the struct. Please don't skip doc comments.

Comment on lines 105 to 108
#[allow(dead_code)] // it is used in the `invoke_contract_delegate` / `eval_contract_delegate` functions.
pub(crate) fn exec_input(&self) -> &ExecutionInput<Args> {
&self.exec_input
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this duplication necessary? Couldn't you have a single impl block where you put the shared functions with a generic CallType? Same for call_flags.

{
/// The default call type for cross-contract calls. Performs a cross-contract call to `callee`
/// with gas limit `gas_limit`, transferring `transferred_value` of currency.
pub struct Call<E, Callee, GasLimit, TransferredValue> {
env: PhantomData<fn() -> E>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like above should be called _phantom.

@cmichi
Copy link
Collaborator

cmichi commented Mar 1, 2022

@VargSupercolony Thanks for the PR. The ink-waterfall CI stage does not succeed because you modified the flipper example and the waterfall tests this with some defined interactions, which are no longer valid with your PR.

I would prefer if you leave the existing proxy example intact and instead create a new one upgradeable-contract. Could you do that please?

@cmichi
Copy link
Collaborator

cmichi commented Mar 1, 2022

@VargSupercolony We're shaping up for a stable ink! release ‒ hopefully this week. It would be awesome to have this PR in there! Do you think you can implement the comments this week?

@armyhaylenko
Copy link

hey @cmichi @athei, writing from my personal acc as I don't have much internet access. I will not be able to work with the PR in the coming days because of war, and I parted my ways with Supercolony, so I think someone will pick it up - probably @xgreenx :) but anything you need from me - please mention this acc, this is my personal one

@xgreenx
Copy link
Collaborator

xgreenx commented Mar 1, 2022

@VargSupercolony We're shaping up for a stable ink! release ‒ hopefully this week. It would be awesome to have this PR in there! Do you think you can implement the comments this week?

hey @cmichi @athei, writing from my personal acc as I don't have much internet access. I will not be able to work with the PR in the coming days because of war, and I parted my ways with Supercolony, so I think someone will pick it up - probably @xgreenx :) but anything you need from me - please mention this acc, this is my personal one

Yes, I will work on it, I will try to update it today=)

@xgreenx
Copy link
Collaborator

xgreenx commented Mar 1, 2022

@cmichi I returned the proxy example back, but ink-waterfall still fails=(

@cmichi
Copy link
Collaborator

cmichi commented Mar 2, 2022

@cmichi I returned the proxy example back, but ink-waterfall still fails=(

I'm still looking into it, but AFAIU it has nothing to do with this PR, the tests actually all run through. The CI only complains when shutting down. I currently suspect some combination of protected variables and first time external contribution.

Let's ignore the ink-waterfall tests here for now.

@cmichi
Copy link
Collaborator

cmichi commented Mar 2, 2022

@xgreenx I just merged #1144, could you merge master into this PR? There will unfortunately be a number of conflicts to fix.

Comment on lines 23 to 26
# Needed until https://github.com/paritytech/ink/issues/364 is resolved.
[profile.release]
overflow-checks = false

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Needed until https://github.com/paritytech/ink/issues/364 is resolved.
[profile.release]
overflow-checks = false

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed since #1049.

You will receive the respective `upgradeable_flipper.contract` bundle in the `examples/upgradable-contract/upgradeable_flipper/target/ink/` folder.

In order to perform migrations and have proxy working for contracts with different storage
layouts, we use the [`Upgradeable`](upgradeable_flipper/upgradeable.rs) type wrapper, which ensures
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have the term "upgradeable" and "upgradable" in this PR. @ascjones 🇬🇧 Wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will rename everything to upgradeable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've had this debate over on the Substrate side, and American spelling should be used 🇺🇸

@paritytech-cicd-pr
Copy link

paritytech-cicd-pr commented Mar 2, 2022

🦑 📈 ink! Example Contracts ‒ Changes Report 📉 🦑

⚠️ The ink! master is ahead of your branch, this might skew the comparison data below.

These are the results when building the examples/* contracts from this branch with cargo-contract 0.17.0-638ad57 and comparing them to ink! master:

Δ Optimized Size Δ Used Gas Total Optimized Size Total Used Gas
accumulator +1.28 K 1.28 K
adder +2.28 K 2.28 K
contract-terminate +1.23 K 1.23 K 214_418
contract-transfer +8.37 K 8.37 K 14_418
delegator +6.25 K +145 6.25 K 46_649
dns +9.62 K 9.62 K 43_254
erc1155 +27.49 K 27.49 K 86_508
erc20 +9.09 K 9.09 K 43_254
erc721 +14.37 K 14.37 K 115_344
flipper +1.55 K 1.55 K 14_418
incrementer +1.49 K 1.49 K 14_418
multisig +26.13 K +2 26.13 K 94_109
proxy +3.17 K +30 3.17 K 29_593
rand-extension 4.38 K 14_418
subber +2.29 K 2.29 K
trait-erc20 +9.36 K 9.36 K 43_254
trait-flipper +1.33 K 1.33 K 14_418
trait-incrementer +1.42 K 1.42 K 28_836
upgradeable-contract +3.22 K 3.22 K

Link to the run | Last update: Fri Mar 4 09:14:40 CET 2022

@cmichi
Copy link
Collaborator

cmichi commented Mar 2, 2022

I've found the issue which caused the ink-waterfall stage to fail!

(It was because this PR adds a new example, which is not yet tested in the waterfall. The regression bot which posted above went 💥 in that case.)

fn allocate_packed(&mut self, at: &Key) {
<T as PackedAllocate>::allocate_packed(&mut self.inner, at)
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😱 Wow that's a lot of boilerplate code for the storage. @xgreenx Do you think this will reduce significantly with #1134 ?

Copy link
Collaborator

@xgreenx xgreenx Mar 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, we will use only one trait(maybe two), and that trait will be automatically implemented by #[ink::storage_ext]. All keys will be managed by the user during the definition of the struct, so the code should look tiny=)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah all of this boilerplate is only needed because the current system doesn't allow to change the contract root key without manually implementing SpreadLayout.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The boilerplate, oh my 🙈

Copy link
Contributor

@HCastano HCastano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only took a quick peek today, will need to spend more time on it later in the week.

One thing that comes to mind is that we should really look for ways to simplify that example contract. If I were a newcomer to ink! and saw this as the base-case for upgradeable contracts I'd definitely be scared off

crates/env/src/api.rs Outdated Show resolved Hide resolved
fn allocate_packed(&mut self, at: &Key) {
<T as PackedAllocate>::allocate_packed(&mut self.inner, at)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The boilerplate, oh my 🙈

@xgreenx
Copy link
Collaborator

xgreenx commented Mar 3, 2022

One thing that comes to mind is that we should really look for ways to simplify that example contract. If I were a newcomer to ink! and saw this as the base-case for upgradeable contracts I'd definitely be scared off

With #1134 we can remove the Upgradeable struct. But we should introduce a new argument for #[ink::storage]. The problem is that in the proxy pattern the constructor of the callee contract is not called and storage is not initialized. It requires some workaround because nothing is stored under the storage key. For that, we created the Upgradeable wrapper.

But with #1134 we need to provide a way how to init the contract's storae if is not initialized. For example, argument in macro #[ink::storage(init = default())] or #[ink::storage(default_if_not_exist = true)]

@HCastano
Copy link
Contributor

HCastano commented Mar 4, 2022

@xgreenx can you avoid force-pushing PRs? It makes pulling the changes down easier, and also makes it harder to see what commits are new.

It's fine to merge master in order to keep up to date

@xgreenx
Copy link
Collaborator

xgreenx commented Mar 4, 2022

@xgreenx can you avoid force-pushing PRs? It makes pulling the changes down easier, and also makes it harder to see what commits are new.

It's fine to merge master in order to keep up to date

I'm only forcing it to rebase to master.
During each merge with the master, I need to resolve conflicts=) That means without rebasing I need to resolve all previous conflicts again and a new one.

I will try to not force for simple conflicts=)

@xgreenx
Copy link
Collaborator

xgreenx commented Mar 4, 2022

ink-waterfall fails because of a new test that is using builder=(
image

Copy link
Contributor

@HCastano HCastano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the right direction, but needs a bit of clean-up

crates/env/src/api.rs Outdated Show resolved Hide resolved
@@ -210,7 +202,7 @@ where
/// # type AccountId = <DefaultEnvironment as Environment>::AccountId;
/// # type Balance = <DefaultEnvironment as Environment>::Balance;
/// build_call::<DefaultEnvironment>()
/// .set_call_type(Call::new().set_callee(AccountId::from([0x42; 32])).set_gas_limit(5000).set_transferred_value(10))
/// .set_call_type(Call::new().callee(AccountId::from([0x42; 32])).gas_limit(5000).transferred_value(10))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump

@@ -420,9 +426,28 @@ impl TypedEnvBackend for EnvInstance {
unimplemented!("off-chain environment does not support contract invocation")
}

#[allow(clippy::type_complexity)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can do the following:

type CallParamsTypedef<T, A> =
    CallParams<T, DelegateCall<T, <T as Environment>::Hash>, A, ()>;

// -- snip ---

fn invoke_contract_delegate<T, Args>(
    &mut self,
    params: &CallParamsTypedef<T, Args>,
) -> Result<()>
where
    T: Environment,
    Args: scale::Encode,
{
    let _code_hash = params.code_hash();
    unimplemented!("off-chain environment does not support contract invocation")
}

Notice that in the typedef we used fully qualified syntax to specify the trait being used. We should be able to do this everywhere in this PR

Comment on lines 81 to 82
pub(crate) fn gas_limit(&self) -> &Gas {
&self.call_type.gas_limit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change this to return a reference? It's Copy anyways

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be consistent with code around)
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense in this case. We just end up dereferencing Gas immediately anyways

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we can return E::Balance from transferred_value=) It is u128

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but let's leave that for a follow up

crates/env/src/engine/on_chain/impls.rs Outdated Show resolved Hide resolved
const REQUIRES_DEEP_CLEAN_UP: bool = <T as SpreadLayout>::REQUIRES_DEEP_CLEAN_UP;

fn pull_spread(ptr: &mut KeyPtr) -> Self {
if ink_env::get_contract_storage::<T>(ptr.advance_by(0))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ink_env::get_contract_storage::<T>(ptr.advance_by(0))
if ink_env::get_contract_storage::<T>(ptr.key())

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key returns the previous key, we need here an actual key, so we are forcing advance_by(0).
image

Comment on lines +120 to +142
impl<T: SpreadAllocate + PackedLayout> SpreadAllocate for Upgradeable<T, Initialized> {
fn allocate_spread(ptr: &mut KeyPtr) -> Self {
Upgradeable::new(<T as SpreadAllocate>::allocate_spread(ptr))
}
}

impl<T: SpreadAllocate + PackedLayout> SpreadAllocate for Upgradeable<T, NotInitialized> {
fn allocate_spread(ptr: &mut KeyPtr) -> Self {
Upgradeable::new(<T as SpreadAllocate>::allocate_spread(ptr))
}
}

impl<T: PackedAllocate> PackedAllocate for Upgradeable<T, Initialized> {
fn allocate_packed(&mut self, at: &Key) {
<T as PackedAllocate>::allocate_packed(&mut self.inner, at)
}
}

impl<T: PackedAllocate> PackedAllocate for Upgradeable<T, NotInitialized> {
fn allocate_packed(&mut self, at: &Key) {
<T as PackedAllocate>::allocate_packed(&mut self.inner, at)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not make these generic over Upgradeable<T, S> the implementations are the same for Initialized and NotInitialized?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we can't, because SpreadAllocate requires SpreadAllocate. SpreadAllocate is implemented only for Upgradeable<T, NotInitialized> and Upgradeable<T, Initialized> so we can't create a generic implementation.

Copy link
Collaborator

@cmichi cmichi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

The failing ink-waterfall CI is because it tests some additional ink! examples which don't make sense to be committed into the ink! repo, they don't use the new API yet. So the failing CI stage can be ignored here. It's this one: https://github.com/paritytech/ink-waterfall/blob/master/examples/contract-introspection/lib.rs.

Copy link
Contributor

@HCastano HCastano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think the biggest thing left is fixing any merge conflicts from #1165, and we should be good

return_type: RetType,
/// The default call type for cross-contract calls. Performs a cross-contract call to `callee`
/// with gas limit `gas_limit`, transferring `transferred_value` of currency.
pub struct Call<E: Environment> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I like this more actually 👍

Comment on lines 81 to 82
pub(crate) fn gas_limit(&self) -> &Gas {
&self.call_type.gas_limit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense in this case. We just end up dereferencing Gas immediately anyways

pub struct EnvAccess<'a, T> {
/// Tricks the Rust compiler into thinking that we use `T`.
marker: PhantomData<fn() -> &'a T>,
pub struct EnvAccess<'a, E> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get why you renamed T to E, but in the future can you at least split this out into its own commit? It adds a lot of unnecessary noise. Tbh it should've been done in a follow-up PR

storage locations, while also tracking the initialization status (e.g., we uploaded
the code on chain, but haven't called the constructor).

3. Build the proxy contract:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you change all of these numbers to 1 Github is smart enough to render the the numbers in the correct order. Makes it easier when change are introduced (no need to update the entire list)

struct ProxyFields {
/// The `Hash` of a contract code where any call that does not match a
/// selector of this contract is forwarded to.
delegate_to: Hash,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I should've been more explicit here, I like the forward_to term more

# Conflicts:
#	crates/env/src/api.rs
#	crates/env/src/backend.rs
#	crates/env/src/call/call_builder.rs
#	crates/env/src/engine/off_chain/impls.rs
#	crates/env/src/engine/on_chain/impls.rs
#	crates/lang/src/env_access.rs
#	crates/lang/tests/ui/contract/fail/message-input-non-codec.stderr
#	crates/lang/tests/ui/trait_def/fail/message_input_non_codec.stderr
#	examples/erc1155/lib.rs
#	examples/multisig/lib.rs
Copy link
Contributor

@HCastano HCastano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I think this is good to go.

There are some things we should improve in follow-ups, but this will at least let the community play with these new mechanisms.

Thanks again Green!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

delegate_call API
9 participants