fn decode_from_token(schema: ProposedUpgradeSchema, token: Token) -> anyhow::Result<Self> {
        let tokens = token.into_tuple().context("not a tuple")?;
        let tokens_len = tokens.len();
        anyhow::ensure!(tokens_len == schema.expected_tuple_len());
        let mut t = tokens.into_iter();
        let mut next = || t.next().unwrap();

        let l2_protocol_upgrade_tx = L2CanonicalTransaction::decode(next())
            .context("l2_protocol_upgrade_tx")?
            .into();
        let next_token = next();
        let (factory_deps, bootloader_hash) = match schema {
            ProposedUpgradeSchema::PreGateway => {
                let factory_deps = next_token
                    .into_array()
                    .context("expected factory deps array")?
                    .into_iter();
                let factory_deps = factory_deps
                    .enumerate()
                    .map(|(i, b)| b.into_bytes().context(i))
                    .collect::<Result<_, _>>()
                    .context("factory_deps")?;
                (Some(factory_deps), next().into_fixed_bytes())
            }
            ProposedUpgradeSchema::PostGateway | ProposedUpgradeSchema::PostEvmEmulator => {
                let bootloader_hash = next_token.into_fixed_bytes().context("bootloader_hash")?;
                (None, Some(bootloader_hash))
            }
        };

        let bootloader_hash = bootloader_hash
            .and_then(|b| b.try_into().ok())
            .context("bootloader_hash")?;

        let upgrade = Self {
            l2_protocol_upgrade_tx,
            factory_deps,
            bootloader_hash,
            default_account_hash: next()
                .into_fixed_bytes()
                .and_then(|b| b.try_into().ok())
                .context("default_account_hash")?,
            evm_emulator_hash: if matches!(schema, ProposedUpgradeSchema::PostEvmEmulator) {
                next()
                    .into_fixed_bytes()
                    .and_then(|b| b.try_into().ok())
                    .context("evm_emulator_hash")?
            } else {
                [0_u8; 32]
            },
            verifier: next().into_address().context("verifier")?,
            verifier_params: VerifierParams::decode(next()).context("verifier_params")?,
            l1_contracts_upgrade_calldata: next()
                .into_bytes()
                .context("l1_contracts_upgrade_calldata")?,
            post_upgrade_calldata: next().into_bytes().context("post_upgrade_calldata")?,
            upgrade_timestamp: next().into_uint().context("upgrade_timestamp")?,
            new_protocol_version: next().into_uint().context("new_protocol_version")?,
        };

        let protocol_version =
            ProtocolSemanticVersion::try_from_packed(upgrade.new_protocol_version)
                .map_err(|err| anyhow::anyhow!(err))
                .context("Version is not supported")?
                .minor;
        anyhow::ensure!(
            schema.matches_protocol_version(protocol_version),
            "Unexpected protocol version: {protocol_version:?} for upgrade schema: {schema:?}"
        );

        Ok(upgrade)
    }
Decodes `ProposedUpgrade` from a RLP token. Returns an error if token doesn't match the `schema`.
core/lib/types/src/abi.rs