{"id":19610713,"url":"https://github.com/onflow/contract-updater","last_synced_at":"2026-03-03T17:09:07.193Z","repository":{"id":180468026,"uuid":"664865427","full_name":"onflow/contract-updater","owner":"onflow","description":"Enabling delayed contract updates to a wrapped account at or beyond a specified block height","archived":false,"fork":false,"pushed_at":"2024-07-29T23:48:48.000Z","size":1630,"stargazers_count":3,"open_issues_count":3,"forks_count":9,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-11-19T17:30:23.728Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Cadence","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/onflow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-10T23:46:30.000Z","updated_at":"2025-03-27T09:37:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"572ffe95-d953-4e73-89f4-d59d0372f6b6","html_url":"https://github.com/onflow/contract-updater","commit_stats":null,"previous_names":["sisyphussmiling/contract-updater","onflow/contract-updater"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/onflow/contract-updater","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fcontract-updater","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fcontract-updater/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fcontract-updater/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fcontract-updater/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onflow","download_url":"https://codeload.github.com/onflow/contract-updater/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onflow%2Fcontract-updater/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30052299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T15:26:47.567Z","status":"ssl_error","status_checked_at":"2026-03-03T15:26:17.132Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T10:32:12.777Z","updated_at":"2026-03-03T17:09:07.172Z","avatar_url":"https://github.com/onflow.png","language":"Cadence","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Onchain Contract Update Mechanisms\n\n![Tests](https://github.com/onflow/contract-updater/actions/workflows/ci.yml/badge.svg)\n[![codecov](https://codecov.io/gh/onflow/contract-updater/graph/badge.svg?token=TAIKIA95FU)](https://codecov.io/gh/onflow/contract-updater)\n\nThis repo contains contracts enabling onchain staging of contract updates, providing mechanisms to store code,\ndelegate update capabilities, and execute staged updates.\n\n## Context\n\nCadence 1.0 is a momentous milestone, introducing many advanced features to the language of Flow, the introduction of\nwhich will require changes to all contracts on the network. This makes crossing that milestone a coordinated effort,\nread on for how to prepare.\n\nYour contract's path to Cadence 1.0 can be broken down into the following four high-level phases:\n\n1. **Updated:** Update your code, validating refactored contracts, transactions and scripts via local testing and\n   emulated migration.\n2. **Staged:** Upload your Cadence 1.0 code to the `MigrationContractStaging` contract so your contract updates take\n   effect at the network-wide height coordinated upgrade (HCU). \n3. **Validated:** This step is automated and serves as external feedback provided by Flow that your contract is good\n   as-is, indicating readiness for the network migration. If your contract fails validation, you will need to update\n   your code and stage it again.\n4. **Migrated:** all core and staged contracts are updated via state migration\n\n![Path to Cadence 1.0](./resources/path_to_cadence_1.png)\n \nSteps 1 \u0026 2 require your effort and execution - you must update your contract and execute a transaction to stage it for\nmigration. Step 3 is an asynchronous feedback loop between Flow and contract owners where staged contracts are migrated\nin an emulated environment offchain, the results of which will be submitted to the staging contract on a set interval\n(TBD). Step 4 will be completed by the network, executed as an HCU.\n\nThis process will need to be completed for all contracts on all networks, with a number of opportunities to collectively\npractice on Crescendo Migration Testnet (CMT) before the HCU on Testnet and Mainnet.\n\n\u003e :mag: This repo addresses steps 2 \u0026 3 above, providing a central coordination point for contract updates to be staged,\n\u003e code and staging status to be retrieved, and offchain validation results to be committed, queried and broadcast. Focus\n\u003e on reaching validated status across all of your contracts before the HCU, giving you confidence your contract updates\n\u003e will be successful.\n\n## Overview\n\n\u003e :information_source: This document proceeds with an emphasis on the `MigrationContractStaging` contract, which will be\n\u003e used for the upcoming Cadence 1.0 network migration. Any contracts currently deployed on Testnet \u0026 Mainnet **WILL**\n\u003e need to be updated via state migration on the Cadence 1.0 milestone. This means you **MUST** stage your contract\n\u003e updates before the milestone for your contract to continue functioning. Keep reading to understand how to stage your\n\u003e contract update.\n\nThe `MigrationContractStaging` contract provides a mechanism for staging contract updates onchain in preparation for\nCadence 1.0. Once you have refactored your existing contracts to be Cadence 1.0 compatible, you will need to stage your\ncode in this contract for network state migrations to take effect and your contract to be updated with the Height\nCoordinated Upgrade.\n\n### `MigrationContractStaging` Deployments\n\n\u003e :information_source: The `MigrationContractStaging` contract is not yet deployed. Its deployment address will be added\n\u003e here once it has been deployed.\n\n| Network   | Address                                                                                                                   |\n| --------- | ------------------------------------------------------------------------------------------------------------------------- |\n| Crescendo | [0x27b2302520211b67](https://crescendo.flowdiver.io/contract/A.27b2302520211b67.MigrationContractStaging?tab=deployments) |\n| Testnet   | [0x2ceae959ed1a7e7a](https://contractbrowser.com/A.2ceae959ed1a7e7a.MigrationContractStaging)                             |\n| Mainnet   | [56100d46aa9b0212](https://contractbrowser.com/A.56100d46aa9b0212.MigrationContractStaging)                               |\n\n### Pre-Requisites\n\n- An existing contract deployed to your target network. For example, if you're staging `A` in address `0x01`, you should\n  already have a contract named `A` deployed to `0x01`.\n- A Cadence 1.0 compatible contract serving as an update to your existing contract. Extending our example, if you're\n  staging `A` in address `0x01`, you should have a contract named `A` that is Cadence 1.0 compatible. See the references\n  below for more information on Cadence 1.0 language changes.\n\n### Staging Your Contract Update\n\nArmed with your pre-requisites, you're ready to stage your contract update. Simply run the [`stage_contract.cdc`\ntransaction](./transactions/migration-contract-staging/stage_contract.cdc), passing your contract's name and Cadence\ncode as arguments and signing as the contract host account.\n\nYou can stage your contract using the [Flow Interaction Templates\n(FLIX)](https://developers.flow.com/tools/flow-cli/flix) and the following command to execute the staging transaction\nfrom [its interaction template](./flix/stage_contract.cdc.flix.json):\n\n\u003e :warning: Be sure to execute this transaction passing your contract's updated Cadence 1.0-compatible code\n\n```sh\nflow flix execute https://raw.githubusercontent.com/onflow/contract-updater/main/flix/stage_contract.cdc.flix.json \\\n    \u003cCONTRACT_NAME\u003e \"$(cat \u003cCONTRACT_FILEPATH\u003e)\" \\\n    --signer \u003cYOUR_SIGNER_ALIAS\u003e \\\n    --network \u003cTARGET_NETWORK\u003e\n```\n\nTo execute the transaction from this project's local transaction code, run:\n\n```sh\nflow transactions send ./transactions/migration-contract-staging/stage_contract.cdc \\\n    \u003cCONTRACT_NAME\u003e \"$(cat \u003cCONTRACT_FILEPATH\u003e)\" \\\n    --signer \u003cYOUR_SIGNER_ALIAS\u003e \\\n    --network \u003cTARGET_NETWORK\u003e\n```\n\nEither of the above will execute the following transaction:\n\n```cadence\nimport \"MigrationContractStaging\"\n\ntransaction(contractName: String, contractCode: String) {\n    let host: \u0026MigrationContractStaging.Host\n    \n    prepare(signer: AuthAccount) {\n        // Configure Host resource if needed\n        if signer.borrow\u003c\u0026MigrationContractStaging.Host\u003e(from: MigrationContractStaging.HostStoragePath) == nil {\n            signer.save(\u003c-MigrationContractStaging.createHost(), to: MigrationContractStaging.HostStoragePath)\n        }\n        // Assign Host reference\n        self.host = signer.borrow\u003c\u0026MigrationContractStaging.Host\u003e(from: MigrationContractStaging.HostStoragePath)!\n    }\n\n    execute {\n        // Call staging contract, storing the contract code that will update during Cadence 1.0 migration\n        // If code is already staged for the given contract, it will be overwritten.\n        MigrationContractStaging.stageContract(host: self.host, name: contractName, code: contractCode)\n    }\n\n    post {\n        MigrationContractStaging.isStaged(address: self.host.address(), name: contractName):\n            \"Problem while staging update\"\n    }\n}\n```\n\nAt the end of this transaction, your contract will be staged in the `MigrationContractStaging` account. If you staged\nthis contract's code previously, it will be overwritten by the code you provided in this transaction.\n\n\u003e :warning: NOTE: Staging your contract successfully does not mean that your contract code is correct. Your testing and\n\u003e validation processes should include testing your contract code against the Cadence 1.0 interpreter to ensure your\n\u003e contract will function as expected.\n\n### Checking Staging Status\n\nYou may later want to retrieve your contract's staged code. To do so, you can run the [`get_staged_contract_code.cdc`\nscript](./scripts/migration-contract-staging/get_staged_contract_code.cdc), passing the address \u0026 name of the contract\nyou're requesting and getting the Cadence code in return. This script can also help you get the staged code for your\ndependencies if the project owner has staged their code.\n\nYou can run this script from [its template](./flix/get_staged_contract_code.cdc.flix.json) using\n[FLIX](https://developers.flow.com/tools/flow-cli/flix) without the need to pull dependencies into your local project\nwith the Flow CLI command below.\n\n```sh\nflow flix execute https://raw.githubusercontent.com/onflow/contract-updater/main/flix/get_staged_contract_code.cdc.flix.json \\\n    \u003cCONTRACT_ADDRESS\u003e \u003cCONTRACT_NAME\u003e \\\n    --network \u003cTARGET_NETWORK\u003e\n```\n\nAlternatively, you can run the script from this project's local Cadence code with:\n\n```sh\nflow scripts execute ./scripts/migration-contract-staging/get_staged_contract_code.cdc \\\n    \u003cCONTRACT_ADDRESS\u003e \u003cCONTRACT_NAME\u003e \\\n    --network \u003cTARGET_NETWORK\u003e\n```\n\nEither of the above runs the script:\n\n```cadence\nimport \"MigrationContractStaging\"\n\n/// Returns the code as it is staged or nil if it not currently staged.\n///\naccess(all) fun main(contractAddress: Address, contractName: String): String? {\n    return MigrationContractStaging.getStagedContractCode(address: contractAddress, name: contractName)\n}\n```\n\n## `MigrationContractStaging` Contract Details\n\n### Developer Paths\n\nThe basic interface to stage a contract is the same as deploying a contract - name + code. See the\n[`stage_contract`](./transactions/migration-contract-staging/stage_contract.cdc) \u0026\n[`unstage_contract`](./transactions/migration-contract-staging/unstage_contract.cdc) transactions. Note that calling\n`stageContract()` again for the same contract will overwrite any existing staged code for that contract.\n\n```cadence\n/// 1 - Create a host and save it in your contract-hosting account at MigrationContractStaging.HostStoragePath\naccess(all) fun createHost(): @Host\n/// 2 - Call stageContract() with the host reference and contract name and contract code you wish to stage.\n/// NOTE: making updates to staged code resets validation status for that contract.\naccess(all) fun stageContract(host: \u0026Host, name: String, code: String)\n/// Removes the staged contract code from the staging environment.\naccess(all) fun unstageContract(host: \u0026Host, name: String)\n```\n\nTo stage a contract, the developer first saves a `Host` resource in their account which they pass as a reference along\nwith the contract name and code they wish to stage. The `Host` reference simply serves as proof of authority that the\ncaller has access to the contract-hosting account, which in the simplest case would be the signer of the staging\ntransaction, though conceivably this could be delegated to some other account via Capability - possibly helpful for some\nmultisig contract hosts.\n\n```cadence\n/// Serves as identification for a caller's address.\naccess(all) resource Host {\n    /// Returns the resource owner's address\n    access(all) view fun address(): Address\n}\n```\n\nWithin the `MigrationContractStaging` contract account, code is saved on a contract-basis as a `ContractUpdate` struct\nwithin a `Capsule` resource and stored at a the derived path. The `Capsule` simply serves as a dedicated repository for\nstaged contract code. (See [Validation Path](#validation-path) for more on how `isValidated()` is determined.)\n\n```cadence\n/// Represents contract and its corresponding code.\naccess(all) struct ContractUpdate {\n    /// Address of the contract host\n    access(all) let address: Address\n    /// Name of the contract\n    access(all) let name: String\n    /// The updated Cadence 1.0 code\n    access(all) var code: String\n    /// Timestamp the code was last updated\n    access(all) var lastUpdated: UFix64\n\n    /// Validates that the named contract exists at the target address.\n    access(all) view fun exists(): Bool \n    /// Serializes the address and name into a string of the form 0xADDRESS.NAME\n    access(all) view fun toString(): String\n    /// Serializes contact into its string identifier of the form A.ADDRESS.NAME where ADDRESS is lacks 0x\n    access(all) view fun identifier(): String\n    /// Returns whether this contract update passed the last emulated migration, validating the contained code.\n    /// NOTE: false could mean validation hasn't begun, the code wasn't included in emulation, or validation failed\n    access(all) view fun isValidated(): Bool {\n    /// Replaces the ContractUpdate code with that provided.\n    access(contract) fun replaceCode(_ code: String)\n}\n\n/// Resource that stores pending contract updates in a ContractUpdate struct.\naccess(all) resource Capsule {\n    /// The address, name and code of the contract that will be updated.\n    access(self) let update: ContractUpdate\n\n    /// Returns the staged contract update in the form of a ContractUpdate struct.\n    access(all) view fun getContractUpdate(): ContractUpdate\n    /// Replaces the staged contract code with the given Cadence code.\n    access(contract) fun replaceCode(code: String)\n}\n```\n\nTo support monitoring staging progress across the network, the single `StagingStatusUpdated` event is emitted any time a\ncontract is staged (`status == \"stage\"`), staged code is replaced (`status == \"replace\"`), or a contract is unstaged\n(`status == \"unstage\"`).\n\n```cadence\naccess(all) event StagingStatusUpdated(\n    capsuleUUID: UInt64,\n    address: Address,\n    code: String,\n    contract: String,\n    action: String\n)\n```\n\nIncluded in the contact are methods for querying staging status and retrieval of staged code. This enables platforms to\ndisplay the staging status of contracts on any given account should.\n\n```cadence\n/* --- Public Getters --- */\n//\n/// Returns true if the contract is currently staged.\naccess(all) view fun isStaged(address: Address, name: String): Bool\n/// Returns true if the contract is currently validated and nil if it's not staged.\naccess(all) view fun isValidated(address: Address, name: String): Bool?\n/// Returns the names of all staged contracts for the given address.\naccess(all) view fun getStagedContractNames(forAddress: Address): [String]\n/// Returns the staged contract Cadence code for the given address and name.\naccess(all) view fun getStagedContractCode(address: Address, name: String): String?\n/// Returns an array of all staged contract host addresses.\naccess(all) view fun getAllStagedContractHosts(): [Address]\n/// Returns the ContractUpdate struct for the given contract if it's been staged.\naccess(all) view fun getStagedContractUpdate(address: Address, name: String): ContractUpdate?\n/// Returns a dictionary of all staged contract code for the given address.\naccess(all) view fun getAllStagedContractCode(forAddress: Address): {String: String}\n/// Returns all staged contracts as a mapping of address to an array of contract names\naccess(all) view fun getAllStagedContracts(): {Address: [String]}\n```\n\n### Validation Path\n\nIn addition to monitoring the number of staged contracts, it will also be important to monitor staged contracts that\nfail validation.\n\nThe `EmulatedMigrationResult` event will be emitted whenever the `Admin` commits the result of offchain emulated migration.\n\n```cadence\n/// Emitted when emulated contract migrations have been completed, where failedContracts are named by their\n/// contract identifier - A.ADDRESS.NAME where ADDRESS is the host address without 0x\naccess(all) event EmulatedMigrationResultCommitted(\n    snapshotTimestamp: UFix64,\n    committedTimestamp: UFix64,\n    failedContracts: [String]\n)\n```\n\nEmulated migration results will be saved as `MigrationContractStaging.lastEmulatedMigrationResult: EmulatedMigrationResult?`,\nthe value of which will be `nil` until offchain emulation begins. `ContractUpdate.isValidated()` will check against\nthis value to determine if the staged contract code has been validated.\n\n```cadence \naccess(all) struct EmulatedMigrationResult {\n    /// Timestamp that the migration snapshot was taken\n    access(all) let snapshot: UFix64\n    /// Timestamp that the migration results were committed\n    access(all) let committed: UFix64\n    /// Identifiers of the contracts that failed validation during the emulated migration\n    access(all) let failedContracts: [String]\n}\n```\n\nFinally, the the entities empowered with coordinating both contract validation and the HCU can perform admin\nfunctionalities via the `Admin` resource.\n\n```cadence\naccess(all) resource Admin {\n    /// Sets the block height at which updates can no longer be staged\n    access(all) fun setStagingCutoff(at height: UInt64?)\n    /// Commits the results of an emulated contract migration\n    access(all) fun commitMigrationResults(snapshot: UFix64, failed: [String])\n}\n```\n\n## References\n\n\u003e Please feel free to submit a PR with updated references as they become available!\n\nMore tooling is slated to support Cadence 1.0 code changes and will be added as it arises. For any real-time help, be\nsure to join the [Flow discord](https://discord.com/invite/J6fFnh2xx6) (especially the developer channels) and the [Flow\nforum](https://forum.flow.com/).\n\n- [Cadence 1.0 contract migration plan](https://forum.flow.com/t/update-on-cadence-1-0-upgrade-plan/5597)\n- [Cadence 1.0 language update breakdown](https://forum.flow.com/t/update-on-cadence-1-0/5197)\n- [Cadence Language reference](https://cadence-lang.org/)\n- [Emerald City's Cadence 1.0 by Example](https://academy.ecdao.org/en/cadence-by-example)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonflow%2Fcontract-updater","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonflow%2Fcontract-updater","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonflow%2Fcontract-updater/lists"}