cairo_native
cairo_native copied to clipboard
Invalid parameter deserialisation in contructor (2.6.3)
Hi! When integrating the latest changes from #504 I've got an errors while running a ERC20 tests.
When we are trying to deploy a contract and instantiate it with constructor, we are getting the following error:
NativeExecutionError { info: "Failed to deserialize param #1" }
The contract executed is basically uses only latest OpenZeppelin contracts:
Scarb.toml
:
[package]
name = "oz_erc20"
version = "0.1.0"
edition = "2023_10"
# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html
[dependencies]
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts", branch = "release-v0.11.0" }
starknet = "2.6.3"
[[target.starknet-contract]]
lib.rs
:
Details
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts for Cairo ^0.10.0
#[starknet::contract]
mod Native {
use openzeppelin::token::erc20::ERC20Component;
use openzeppelin::token::erc20::interface;
use openzeppelin::security::pausable::PausableComponent;
use openzeppelin::access::ownable::OwnableComponent;
use openzeppelin::upgrades::UpgradeableComponent;
use openzeppelin::upgrades::interface::IUpgradeable;
use starknet::ContractAddress;
use starknet::get_caller_address;
use starknet::ClassHash;
component!(path: ERC20Component, storage: erc20, event: ERC20Event);
component!(path: PausableComponent, storage: pausable, event: PausableEvent);
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);
#[abi(embed_v0)]
impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl<ContractState>;
#[abi(embed_v0)]
impl PausableImpl = PausableComponent::PausableImpl<ContractState>;
#[abi(embed_v0)]
impl OwnableImpl = OwnableComponent::OwnableImpl<ContractState>;
#[abi(embed_v0)]
impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl<ContractState>;
impl ERC20InternalImpl = ERC20Component::InternalImpl<ContractState>;
impl PausableInternalImpl = PausableComponent::InternalImpl<ContractState>;
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;
impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;
#[storage]
struct Storage {
#[substorage(v0)]
erc20: ERC20Component::Storage,
#[substorage(v0)]
pausable: PausableComponent::Storage,
#[substorage(v0)]
ownable: OwnableComponent::Storage,
#[substorage(v0)]
upgradeable: UpgradeableComponent::Storage,
}
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC20Event: ERC20Component::Event,
#[flat]
PausableEvent: PausableComponent::Event,
#[flat]
OwnableEvent: OwnableComponent::Event,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event,
}
#[constructor]
fn constructor(ref self: ContractState, recipient: ContractAddress, owner: ContractAddress) {
self.erc20.initializer("Native", "MTK");
self.ownable.initializer(owner);
self.erc20._mint(recipient, 10000000000000000000000);
}
#[abi(embed_v0)]
impl ERC20Impl of interface::IERC20<ContractState> {
fn total_supply(self: @ContractState) -> u256 {
self.erc20.total_supply()
}
fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {
self.erc20.balance_of(account)
}
fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 {
self.erc20.allowance(owner, spender)
}
fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {
self.pausable.assert_not_paused();
self.erc20.transfer(recipient, amount)
}
fn transfer_from(
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256,
) -> bool {
self.pausable.assert_not_paused();
self.erc20.transfer_from(sender, recipient, amount)
}
fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {
self.pausable.assert_not_paused();
self.erc20.approve(spender, amount)
}
}
#[abi(embed_v0)]
impl ERC20CamelOnlyImpl of interface::IERC20CamelOnly<ContractState> {
fn totalSupply(self: @ContractState) -> u256 {
self.total_supply()
}
fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {
self.balance_of(account)
}
fn transferFrom(
ref self: ContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256,
) -> bool {
self.pausable.assert_not_paused();
self.transfer_from(sender, recipient, amount)
}
}
#[generate_trait]
#[abi(per_item)]
impl ExternalImpl of ExternalTrait {
#[external(v0)]
fn pause(ref self: ContractState) {
self.ownable.assert_only_owner();
self.pausable._pause();
}
#[external(v0)]
fn unpause(ref self: ContractState) {
self.ownable.assert_only_owner();
self.pausable._unpause();
}
#[external(v0)]
fn burn(ref self: ContractState, value: u256) {
self.pausable.assert_not_paused();
let caller = get_caller_address();
self.erc20._burn(caller, value);
}
#[external(v0)]
fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {
self.ownable.assert_only_owner();
self.pausable.assert_not_paused();
self.erc20._mint(recipient, amount);
}
}
#[abi(embed_v0)]
impl UpgradeableImpl of IUpgradeable<ContractState> {
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
self.ownable.assert_only_owner();
self.upgradeable._upgrade(new_class_hash);
}
}
}
And the values we are passing is just two addresses:
let (contract_address, _) = deploy_contract(
&mut state,
class_hash,
Felt::from(0),
&[
contract_address_to_native_felt(Signers::Alice.into()), // Recipient
contract_address_to_native_felt(Signers::Alice.into()), // Owner
],
)
.unwrap();
Do you have any ideas regarding this one? Let me know, if you need any more additional info!