-
Notifications
You must be signed in to change notification settings - Fork 352
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
Bump to cairo v0.10 #449
Bump to cairo v0.10 #449
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing that's not documented on the issue is updating documentation. Considering we aim to safely launch as soon as possible I suggest to leave it outside of scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Andrew, I left a couple of question and comments.
let (success) = ERC165.supports_interface(interfaceId) | ||
return (success) | ||
end | ||
func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we refactor to avoid returning tuples but single values in cases like this? (0.10 introduction of single return values)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh yes, good call. This is just what cairo-migrate
spit out. I'll update
let (res) = Account.get_public_key(); | ||
return (res=res); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let (res) = Account.get_public_key(); | |
return (res=res); | |
return Account.get_public_key(); |
let's try to return a single value. if not, at least not res
:
let (res) = Account.get_public_key(); | |
return (res=res); | |
let (publicKey) = Account.get_public_key(); | |
return (publicKey); |
let (res) = Account.get_public_key(); | ||
return (res=res); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as the other
# Account | ||
const IACCOUNT_ID = 0xf10dbd44 | ||
// Account | ||
const IACCOUNT_ID = 0xf10dbd44; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should update that value according to the new IAccount
interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@juniset @martriay we're including isValidSignature
in the interface, correct? If so, this is how it looks. Let me know if there are any objections.
interface IAccount {
function isValidSignature(bytes32, bytes32, bytes32) external; // hash, r, s
function __execute__(address, bytes4, bytes calldata) external; // to, selector, calldata
function __validate__(address, bytes4, bytes calldata) external; // to, selector, calldata
function __validate_declare__(bytes32) external; // class hash
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrew-fleming I don't think that properly represents the IAccount
interface. We need to take into account that we can have multiple signatures in isValidSignature
and multicalls in __execute__
and __validate__
.
I would propose to use
interface IAccount {
struct Call {
address to;
bytes4 selector;
uint256 data;
}
function isValidSignature(bytes32, bytes32[] calldata) external;
function __execute__(Call[] calldata) external;
function __validate__(Call[] calldata) external;
function __validate_declare__(bytes32) external;
}
contract Selector {
// returns 0x56ad812f
function calculateSelector() public pure returns (bytes4) {
IAccount i;
return i.isValidSignature.selector ^
i.__execute__.selector ^
i.__validate__.selector ^
i.__validate_declare__.selector;
}
}
which gives IACCOUNT_ID = 0x56ad812f
.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, shouldn't we include supportsInterface
to the IAccount
interface? It's the only way for a contract to detect that an address is an account hence it should be mandatory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right.But I think it should be bytes
then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect. And I just spoke to @martriay and we're all in agreement with adding supportsInterface
to IAccount
; therefore:
interface IAccount {
struct Call {
address to;
bytes4 selector;
bytes data;
}
function supportsInterface(bytes4) external;
function isValidSignature(bytes32, bytes32[] calldata) external;
function __execute__(Call[] calldata) external;
function __validate__(Call[] calldata) external;
function __validate_declare__(bytes32) external;
}
contract Selector {
// returns 0xa66bd575
function calculateSelector() public pure returns (bytes4) {
IAccount i;
return i.supportsInterface.selector^
i.isValidSignature.selector ^
i.__execute__.selector ^
i.__validate__.selector ^
i.__validate_declare__.selector;
}
}
which gives us IACCOUNT = 0xa66bd575
. What does everyone think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @andrew-fleming , that looks good to me!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! I still have two doubts:
- should
bytes4
bebytes32
considering that selectors are way longer (1 felt
) in Cairo? - our current interface doesn't actually take
Call[]
because we can't handle arrays of complex structs yet. I guess we want to be future proof but do we agree this isn't the current interface?
other than that, LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should bytes4 be bytes32 considering that selectors are way longer (1 felt) in Cairo?
I agree that bytes32
is a more accurate type for SN selectors; however, bytes4
seems more compliant with EIP165. I vote for keeping bytes4
our current interface doesn't actually take Call[] because we can't handle arrays of complex structs yet. I guess we want to be future proof but do we agree this isn't the current interface?
And yes, I agree the proposed interface is the interface-to-be, not the interface right now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getting there 🥺
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super small changes requested, otherwise good to go!
ERC20.transfer_from(sender, recipient, amount); | ||
return ERC20.transfer_from(sender, recipient, amount); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doublespend! is this passing the tests?
Co-authored-by: Martín Triay <martriay@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@martriay @andrew-fleming I left some comments but overall the PR LGTM (I know is already merged, but I added the last review as requested by @martriay).
// | ||
|
||
func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( | ||
_public_key: felt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This underscore at the beginning of the argument name has some purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. It did serve a purpose early on when public_key
itself was a storage variable
# | ||
# Getters | ||
# | ||
func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We changing the implicit arguments to lay in one line (instead of multiline as before) implies that we will follow the Cairo provided formatter to format the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of now, this is temporary^. We just wanted to ship the cairo v0.10 update
ecdsa_ptr: SignatureBuiltin*, | ||
range_check_ptr, | ||
}(hash: felt, signature_len: felt, signature: felt*) -> (is_valid: felt) { | ||
let (_public_key) = Account_public_key.read(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another leading underscore.
# | ||
# Business logic | ||
# | ||
func setPublicKey{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method can make the contract unusable if a wrong public key is set by mistake. Maybe it would be good to add a two steps process allowing to claim the new public key before removing the old one? (Similar to the ownership two-steps transfers process in Solidity contracts).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, agreed. If we're all in agreement, it's probably better suited for the next
release
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created an issue for this #469
Account.set_public_key(new_eth_address) | ||
return () | ||
end | ||
func setEthAddress{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment for two steps process as mentioned in Account.cairo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mentioned in #469
# | ||
# Getters | ||
# | ||
func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a reminder of the upgradeAndCall suggestion to keep the atomicity if the new implementation needs initialization (this is in general for the upgrade function in upgradeable contracts).
@@ -14,549 +14,458 @@ from openzeppelin.introspection.erc165.IERC165 import IERC165 | |||
from openzeppelin.security.safemath.library import SafeUint256 | |||
from openzeppelin.token.erc721.IERC721Receiver import IERC721Receiver | |||
from openzeppelin.utils.constants.library import ( | |||
IERC721_ID, IERC721_METADATA_ID, IERC721_RECEIVER_ID, IACCOUNT_ID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A reminder for myself to double check Interface IDs.
func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( | ||
proxy_admin: felt | ||
) { | ||
let (initialized) = Proxy_initialized.read(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we be using here the initializable library instead? I think importing libraries from libraries is not against the Extensibility Pattern right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we be using here the initializable library instead?
Agreed
I think importing libraries from libraries is not against the Extensibility Pattern right?
Correct :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created an issue for this #470
|
||
# ERC165 | ||
const IERC165_ID = 0x01ffc9a7 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The remainder for double-checking Interfaces Ids is better left here.
This PR proposes to:
Account.execute
, separate validation with__validate__
and__validate_declare__
res
return values to a more meaningful nameOn top of the many changes, the new Cairo version's testing framework hasn't accounted for all the updates. This PR proposes to account for this by refactoring the
MockSigner
. Some things to note:signer
calls is different i.e.return_val.result.response
is nowreturn_val.call_info.retdata[]
assert_event_emitted
makes assertions against theOrderedEvent
object instead ofEvent
signers.py
includes a local mock Nile. This should be removed once Nile supports Cairo v0.10cairo-nile
is removed as a dep in tox. This should also be removed upon its update.