Why do contract IDs vary from forc to forc version?

This is something that has haunted me forever:
ContractIDs seem to vary depending on which forc version they were built with.

Is that correct?

Meaning that if e.g. your sway toolchain differs from your frontend toolchain, your contractIDs wont match which creates a ton of slightly annoying nuisances in DX.

Can someone help explain?

1 Like

forc compiles your contract bytecode. When we make updates to the compiler, so does the contract bytecode. And the contract ID is derived from it’s bytecode, salt and state root. You should use a consistent toolchain across your project.

1 Like

Ok so if I already have mainnet contracts in the wild that have say a fixed contract address, I cannot rely on the address being the same when you guys release a new version of forc?

I get that in theory you want people to have a consistent toolchain, in practice its hard to keep up with a 1 week deployment routine that forces us to make changes on all levels of the stack.

1 Like

Consider this scenario:

  • I have a contract (Contract A) that sends funds to a receiver contract. This receiver (Contract B) is fixed and deployed on mainnet
  • Now with a new forc version, I have to update the Contract A with a new const inside the sway code
  • now my tests will need a new contract ID as well
  • now my SDK needs new contractIDs as well
  • but most of all, when I deploy to mainnet, it will fail because that receiver has already been deployed on mainnet.

So basically in my DX I’m forced to re-release my receiver every time forc changes or I am forced to a human-error prone DX?

Or am I misunderstanding?

1 Like

Ok so if I already have mainnet contracts in the wild that have say a fixed contract address, I cannot rely on the address being the same when you guys release a new version of forc?

If you want fixed contract addresses that you can upgrade, you should put your contracts behind a proxy.

I get that in theory you want people to have a consistent toolchain, in practice its hard to keep up with a 1 week deployment routine that forces us to make changes on all levels of the stack.

That’s very fair. The team has been pushing hard at the moment so the throughput has been high and reactive, I expect us to hit a more consistent cadence after launch.

but most of all, when I deploy to mainnet, it will fail because that receiver has already been deployed on mainnet.

A forc update doesn’t necessarily mean it will impact your contract, it could be a small isolated fix. In an instance where forc updates and your contract bytecode does not change, meaning it can not be redeployed, then you do not need to redeploy the contract as nothing has changed for you. A redeploy in this instance is redundant. You can safely update your toolchain without redeploying.

1 Like

Sorry there was a misunderstanding.

We are not upgrading contracts.
We have contracts that call other contracts.

If the other called contract address changes with each forc update, then either tests or production fails as the contract address is part of the deployed contract as const - makes sense?

1 Like

Makes sense. But if you need to redeploy because of a forc update, I would class that as an upgrade, because your underlying bytecode has changed.

Making your contract upgradable solves this problem, as you can benefit from forc updates that brings bytecode opitmisations to your contracts.

If you stored the contract addresses as storage against a proxy contract rather than as constants, you could just update the storage of the static proxy contract address after a redeploy, rather than having to update a constant and another redeploy.

If you can bare with me I can make a proof of concept, with 2 contracts that can call each other by proxy.

1 Like