-
Notifications
You must be signed in to change notification settings - Fork 426
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
delegate_call
API
#1109
Comments
@athei, maybe you have any thoughts on this? |
You don't need this sub |
@athei, so you want the CallType to hold just the type of the call, not the data related (such as gas_limit, value), right? |
Inside the |
Ah, yeah. I got your point. Maybe that's a good idea. |
@athei so, as the delegate call PR is merged, I think it's a good idea to get back to this issue. If we want to keep the API flat, we'd probably have to go with creating a new builder (e.g., This has the following advantages and disadvantages: (+) We keep the existing APIs as-is, which makes the change non-breaking The other way is to do the (+) We allow for easier integration of further call types (if any) IMO, breaking changes at this stage are still OK, as the versions being released are still RCs. So both approaches sound good to me, and for both, we'd have to design new codegen/utilities to turn calls to delegate_calls :) That said, I personally like the first approach more, as we don't break anything and the other Code examplesIf we take the first approach, our code will look like this: /// Build simple call (non-delegated, codegen)
#[ink(message)]
pub fn foo(&mut self) -> Result<(), Error> {
self.a.foo()
}
/// Build simple call (non-delegated, builder)
#[ink(message)]
pub fn foo(&mut self) -> Result<(), Error> {
build_call::<DefaultEnvironment>()
.callee(ToAccountId::to_account_id(self.a))
.gas_limit(5000)
.transferred_value(10)
.exec_input(ExecutionInput::new(selector_bytes!("foo")))
.returns::<Result<(), Error>>()
.fire()
.unwrap();
}
/// Build delegate call (codegen)
#[ink(message)]
pub fn foo(&mut self) -> Result<(), Error> {
ink_env::call::delegate!(self.a.foo()) // this is a subject to change, I've no idea how to make that pretty now
}
/// Build delegate call (builder)
pub fn foo(&mut self) -> Result<(), Error> {
build_delegate_call::<DefaultEnvironment>()
.code_hash(self.a_code_hash)
// .call_flags(...)
.exec_input(ExecutionInput::new(selector_bytes!("foo")))
.returns::<Result<(), Error>>()
.fire()
.unwrap();
} For the second approach, builder examples are provided in the original issue. Codegen would look the same, I think. I'd love to hear your thoughts on both of the approaches :) |
I want to highlight another important point: With the ContractRef{ account_id: some_account }.call().foo(). // <- Currently it returns `CallBuilder` with selector for method `foo` and configured arguments for cross-contract call
.call_type(
CallType::delegate_call()
.code_hash(CodeHash::from([0x42; 32]))
) // <- Here we changed the type to delegated call, but all previous configuration related to input and selector are correct
.fire(); |
What is wrong about my suggestion? Keeping a single This would also allow conversion between the two modes. |
It means that
It is clear that
|
This is fair. It might be confusing.
The source type would be irrelevant. So it would be one function with the name of the mode you are switching to. Your example would look like this: ContractRef{ account_id: some_account }.call().foo(). // <- Currently it returns `CallBuilder` with selector for method `foo` and configured arguments for cross-contract call
.delegate_call()
.code_hash(CodeHash::from([0x42; 32]))
.fire(); Please note that in both cases you will delete the supplied I am not really sure which is the best way to do this but unflatten this seems harder to read. |
Right now for
|
Okay I get that we don't want to litter the |
I'm working on a PoC right now to show you, but the basic idea is following: pub struct Call<Callee, GasLimit, TransferredValue> {
callee: Callee,
gas_limit: GasLimit,
transferred_value: TransferredValue,
}
pub struct DelegateCall<E: Environment> {
code_hash: E::Hash,
}
/// Builds up a cross contract call.
pub struct CallBuilder<E, CallType, Args, RetType>
where
E: Environment,
CallType: seal::CallTypeSealed,
{
env: PhantomData<fn() -> E>,
/// The current parameters that have been built up so far.
call_type: CallType,
call_flags: CallFlags,
exec_input: Args,
return_type: RetType,
}
#[allow(clippy::type_complexity)]
pub fn build_call<E, CallType>() -> CallBuilder<
E,
CallType,
Unset<ExecutionInput<EmptyArgumentList>>,
Unset<ReturnType<()>>,
>
where
E: Environment,
CallType: CallTypeSealed,
{
CallBuilder {
env: Default::default(),
call_type: Default::default(),
call_flags: Default::default(),
exec_input: Default::default(),
return_type: Default::default(),
}
} We expose the CallType to the user, so we'll call At the same time, CallType is sealed, so user will not create their own STATICCALLs and stuff :) |
How will that work with codegen? I think all your examples started from the wrong premise that it is created from a |
Ahhhh ok I see what you mean. Then it's simple too: we will provide |
By default, the codegen will generate the implementation for Also in the future, we also can generate |
Imho we should do what @VargSupercolony says. Creating a delegate call from a |
I meant that the approach with
I meant the same idea as Varg=)
It is let erc20: Erc20DelegatedRef = CodeHash::from_hash(some_hash);
erc20.transfer(to, amount); // <- It is delegated call instead of cross contract call here |
We don't want to convert. Those are different things. |
Maybe we don't want to convert, but we can provide a flexible API. If the developer is simpler to convert instead of using So, what do you think about the idea of the usage of one generic type |
I think this approach is fine.
I think we should allow a call to |
@athei I will make a PR really soon; what should I check before submitting the PR? Does the |
I have never called this script. CI doesn't do either as far as I can tell. So I would say "NO". |
Hello, ink! team. PR for delegate_call hopefully, will be merged soon, and now it's time to think about how to add this to the ink! API.
To support delegate_call we need to make changes to
CallBuilder
(and respective codegen part) and implementCallTypeBuilder
(for buildingCallType
structure)I can't find an easy way to do this, but to break existing API. Here is an example how it is going to look like after the change:
I am asking for your thoughts/suggestions before I make actual PR.
The text was updated successfully, but these errors were encountered: