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

Predeployed account not supporting interface ID of OZ 0.8.1, subsequent deployed accounts support #422

Closed
2 tasks done
jrcarlos2000 opened this issue Apr 12, 2024 · 3 comments · Fixed by #431
Closed
2 tasks done
Assignees
Labels
bug Something isn't working

Comments

@jrcarlos2000
Copy link

Describe the bug (observed vs expected behavior)

on devnet at commit : 6a51d04, the predeployed accounts with open zeppelin version 0.8.1 dont support this interface id

however other accounts deployed after devnet is started , with the same class hash, they do support the interface.

Not reproducible on testnet

  • This issue is only present on Devnet and cannot be reproduced on the alpha-sepolia testnet (check the box if true).

To Reproduce
Steps to reproduce the behavior:

  1. start the devnet
docker run -p 127.0.0.1:5050:5050 --rm -it shardlabs/starknet-devnet-rs:6a51d049c036a40166875e24583bf7ffe23a7a00 --seed 0 --account-class cairo1
  1. run this code with starknetjs@6.7.0
const provider = new RpcProvider({
    nodeUrl: "http://127.0.0.1:5050",
  });
  const deployer = new Account(
    provider,
    "0x4b3f4ba8c00a02b66142a4b1dd41a4dfab4f92650922a3280977b0f03c75ee1",
    "0x57b2f8431c772e647712ae93cc616638",
    1
  );
  const interfaceID =
    "0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd"; // OZ Standard
  console.log(`const ISRC6_ID: felt252 = ${interfaceID} `);

  let response = await provider.callContract({
    contractAddress: deployer.address, // deployer is 1st predeplyed account
    calldata: [interfaceID],
    entrypoint: "supports_interface",
  });
  console.log("existing account supports interface ?", response);

  // new Open Zeppelin account v0.8.1
  // Generate public and private key pair.
  const privateKey = stark.randomAddress();
  const starkKeyPub = ec.starkCurve.getStarkKey(privateKey);
  const OZaccountClassHash =
    "0x061dac032f228abef9c6626f995015233097ae253a7f72d68552db02f2971b8f";
  // Calculate future address of the account
  const OZaccountConstructorCallData = CallData.compile({
    publicKey: starkKeyPub,
  });
  const OZcontractAddress = hash.calculateContractAddressFromHash(
    starkKeyPub,
    OZaccountClassHash,
    OZaccountConstructorCallData,
    0
  );
  // transfer eth
  const { transaction_hash: transaction_hash1 } = await deployer.execute(
    [
      {
        contractAddress:
          "0x49D36570D4E46F48E99674BD3FCC84644DDD6B96F7C741B1562B82F9E004DC7",
        calldata: [
          OZcontractAddress,
          {
            low: 1e18,
            high: 0,
          },
        ],
        entrypoint: "transfer",
      },
    ],
    {
      maxFee: 1e18,
    }
  );
  await provider.waitForTransaction(transaction_hash1);
  const OZaccount = new Account(provider, OZcontractAddress, privateKey, 1);
  const { transaction_hash, contract_address } = await OZaccount.deployAccount({
    classHash: OZaccountClassHash,
    constructorCalldata: OZaccountConstructorCallData,
    addressSalt: starkKeyPub,
  });
  await provider.waitForTransaction(transaction_hash);
  response = await provider.callContract({
    contractAddress: OZaccount.address,
    calldata: [interfaceID],
    entrypoint: "supports_interface",
  });
  console.log("new Account supports interface", response);

  const classHash1 = await provider.getClassHashAt(OZaccount.address);
  const classHash2 = await provider.getClassHashAt(deployer.address);

  console.log("are class hashes the same?", classHash1 === classHash2);

Devnet version

  • I am using Devnet version: 6a51d04
  • This happens with a dockerized Devnet (check the box if true).
  • This does not appear on the following Devnet version:

System specifications

  • OS: MacOS 13.2.1
@FabijanC FabijanC self-assigned this Apr 16, 2024
@FabijanC FabijanC added the bug Something isn't working label Apr 16, 2024
@FabijanC
Copy link
Contributor

Notes:

  1. I am able to reproduce this on the latest Devnet (commit 47ee2a73c227ee356f344ce94e5f61871299be80) and using starknet.rs instead of starknet.js
  2. Instead of directly invoking the ERC20 token contract to increase the account balance, the /mint endpoint can be used (docs).
  3. How did you get the interfaceID value of 0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd?

@jrcarlos2000
Copy link
Author

Instead of directly invoking the ERC20 token contract to increase the account balance, the /mint endpoint can be used (docs).

  • True, i missed that on the script.

How did you get the interfaceID value of 0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd?

  • Account interface from OZ v8.1.0 here

@FabijanC
Copy link
Contributor

FabijanC commented Apr 16, 2024

Update

The problem is in the way we initialize predeployed accounts. We don't really execute their constructor logic, we only set the public key in their respective storage.

But when an account is deployed manually using a DEPLOY_ACCOUNT transaction, the constructor does get executed.

Actual Constructor Logic (Cairo)

https://github.com/OpenZeppelin/cairo-contracts/blob/89a450a88628ec3b86273f261b2d8d1ca9b1522b/src/account/account.cairo#L207-L211

Devnet Constructor Simulation (Wrong)

fn deploy(&self, state: &mut StarknetState) -> DevnetResult<()> {
self.declare_if_undeclared(state, self.class_hash, &self.contract_class)?;
state.predeploy_contract(self.account_address, self.class_hash)?;
// set public key directly in the most underlying state
let public_key_storage_var = get_storage_var_address("Account_public_key", &[])?;
state.state.state.set_storage_at(
self.account_address.try_into()?,
public_key_storage_var.try_into()?,
self.public_key.into(),
)?;
// set balance directly in the most underlying state
self.set_initial_balance(&mut state.state.state)?;
Ok(())
}

Solution Proposal

I'll probably deal with this by adding the remaining constructor logic simulation, i.e. do a direct write instead of calling

self.SRC5_supported_interfaces.write(interface_id, true);

I'll also expand the tests. But I can only continue working on Thursday.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants