-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Introduce impl Contract { .. }
and add to it free functions from std
like contract_id()
#2463
Comments
Thoughts @mohammadfawaz @mitchmindtree @nfurfaro ? |
impl for Contract
to contain free functions from std
like contract_id()
impl Contract { .. }
and add to it free functions from std
like contract_id()
Thanks! Looks great. Just updated the title a bit; I hope you're okay with that! And yeah we're going to have to make decisions on what goes in and what does not but the core work will be the same regardless... Some compiler work will be required to actually move |
Related: #2429 |
Yup! Hoping that if we go with this approach, then there would be fewer concerns with the |
Just copying the wallet example from the Sway book to see how it would look like. Turned everything into a method to see if that makes sense: contract;
use std::{
address::Address,
assert::assert,
constants::BASE_ASSET_ID,
contract_id::ContractId,
identity::Identity,
result::Result,
revert::revert,
contract::Contract, // New import
};
const OWNER_ADDRESS: b256 = 0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861;
storage {
balance: u64 = 0,
}
abi Wallet {
#[storage(read, write)]
fn receive_funds(self);
#[storage(read, write)]
fn send_funds(self, amount_to_send: u64, recipient_address: Address);
}
impl Wallet for Contract {
#[storage(read, write)]
fn receive_funds(self) {
if self.msg_asset_id() == BASE_ASSET_ID {
storage.balance += self.msg_amount();
}
}
#[storage(read, write)]
fn send_funds(self, amount_to_send: u64, recipient_address: Address) {
let sender = self.msg_sender();
match sender.unwrap() {
Identity::Address(addr) => {
assert(addr == ~Address::from(OWNER_ADDRESS));
},
_ => {
revert(0);
},
};
let current_balance = storage.balance;
assert(current_balance >= amount_to_send);
storage.balance = current_balance - amount_to_send;
self.transfer_to_output(amount_to_send, BASE_ASSET_ID, recipient_address);
}
} And when calling the contract methods from scripts, maybe the fn main() -> bool {
let wallet_contract: Contract = abi(Wallet, 0x417e8ee99a538fb03b032862bedf70ccd28dcec4a0fb455c72700f5234467f48);
wallet_contract.receive_funds {
coins: 42,
} ();
wallet_contract.send_funds(30, ~Address::from(0x0101010101010101010101010101010101010101010101010101010101010101));
} Maybe this would help replacing the |
I like this last point. Intuitively I tent to think of an instance of a |
I think that adding methods to the |
I think the reason Having If we are to keep them as free functions, we'll also require an extra language feature to isolate their use to contracts (like this one FuelLabs/sway-rfcs#9), which I think would unnecessarily complicate the language when we already have the language constructs we need to isolate their use (i.e. contract methods or contract method arguments). |
On a related note: perhaps one alternative might be to have a self.msg().sender() #[storage(read, write)]
fn receive_funds(self) {
let msg = self.msg();
if msg.asset_id() == BASE_ASSET_ID {
storage.balance += msg.amount();
}
} |
This sounds promising. One thing we should try to avoid is any confusion between this hypothetical We use the term |
I just noticed that most likely the type ~Contract::msg_amount()
~Contract::msg_sender() We may also want to think about introducing other types that could hold some of the standard library functions that don't belong to ~Block::height() If we agree with the above, then it might be time to really get rid of that |
While the Having the user pass Passing If we don't feel comfortable using Whatever we go with, I think it's important that we treat data that is unique to each contract method call (e.g. sender, amount, asset ID) as inputs to the contract method, rather than treating them as global state accessible by global functions and then trying to use attributes in an ad-hoc attempt to restrain where these global functions can be used when they shouldn't really be global in the first place. |
Thanks @mitchmindtree, this makes sense to me. I certainly do prefer Your comment about potential future fields for |
Summary
Currently the
Contract
does not behave like an object that takesself
as a parameter meaning it does not allow the user to do something likeself.contract_id()
wherecontract_id()
is a function defined in our standard library that returns a pointer to the Tx ID in an external context and the contract id in an internal context.There are many functions in the standard library that arguably should be moved into the context of the
Contract
rather than have them exist in the standard library where the user must explicitly import them. PerhapsContract
may be a library in and of itself.There's a trade-off between unwanted bloat and additional out-of-the-box functionality that should be evaluated but it's unlikely to be a huge issue unless we strictly follow the standard from Rust where the user does not pay for what they do not use.
That being said, here is a list of possible functions that could be added into
Contract
:Here are some additional ones that may receive more debate
timestamp()
once that is implemented)The text was updated successfully, but these errors were encountered: