Last release today
02 Sep 2026
Ships on a steady schedule
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
7565 releases ยท first in 2020
One column per quarter.
Nothing published for this version
This release adds support for deploying multiple contracts per account. The API for deploying has changed:
The functions AuthAccount.setCode and AuthAccount.unsafeNotInitializingSetCode were removed (#390).
A new contract management API has been added, which allows adding, updating, and removing multiple contracts per account (#333, #352).
See the updated documentation for details and examples.
This release adds support for enumerations (#344).
For example, a days-of-the-week enum can be declared though:
enum Day: UInt8 {
case Monday
case Tuesday
case Wednesday
case Thursday
case Friday
case Saturday
case Sunday
}
See the documentation for further details and examples.
This release adds support for switch statements (#365).
fun describe(number: Int): String {
switch number {
case 1:
return "one"
case 2:
return "two"
default:
return "other"
}
}
See the documentation for further details and examples.
Development of a code formatter has started, in form of a plugin for Prettier (#348). If you would like to contribute, please let us know!
This release depends on a fork of the CBOR library that Cadence uses.
When importing Cadence in another Go codebase, add the following statement to the go.mod file:
replace github.com/fxamacker/cbor/v2 => github.com/turbolent/cbor/v2 v2.2.1-0.20200911003300-cac23af49154
[Changes][v0.10.0]
<a id="v0.9.0"></a>
Nothing published for this version
[Changes][v0.9.3]
<a id="v0.11.1"></a>
Nothing published for this version
[Changes][v0.9.2]
<a id="v0.10.0"></a>
Nothing published for this version
Nothing published for this version
map function for optionals (#299)Refactor the documentation (#380).
The new documentation is more accessible and available at https://docs.onflow.org/cadence/language
[Changes][v0.9.0]
<a id="v0.8.2"></a>
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
This release focuses on improvements, bug fixes, and bringing the documentation up-to-date.
Improved support on Windows: Treat carriage returns as space (#304)
Improved JSON marshalling for more AST elements (#292, #286)
Recursively check if assignment target expression is valid, don't copy returned values (#288)
Consider existing prefix when suggesting completion items (#285)
Include available declarations in "not declared" error (#280)
Enforce the requirement for types to be storable in more places:
load and store functions (#251)Previously, using non-storable failed at run-time, now the programs are rejected statically.
Arguments passed to cadence.Value#WithType are now typed as pointers (*cadence.Type) rather than values (cadence.Type)
Example:
myEventType := cadence.EventType{...})
// this ๐
myEvent := cadence.NewEvent(...).WithType(myEventType)
// changes to this ๐
myEvent := cadence.NewEvent(...).WithType(&myEventType)
[Changes][v0.8.0]
<a id="v0.7.0"></a>
This release contains a lot of improvements to the language server, which improve the development experience in the Visual Studio Code extension, and will also soon be integrated into the Flow Playground.
Added member completion to the language server (#257)
Enabled running the language server in the browser by compiling it to WebAssembly (#242)
Added support for pragmas to the parser (#239)
Started a source compatibility suite (#226, #270).
Cadence will be regularly checked for compatibility with existing code to ensure it does not regress in source compatibility and performance. As a start, the Fungible Token standard and Non-Fungible Token standard repositories are checked.
Consider requesting your repository to be included in the compatibility suite!
Added a simple minifier (#252)
[Changes][v0.7.0]
<a id="v0.6.0"></a>
Nothing published for this version
Nothing published for this version
This is a small release with some bug fixes, internal improvements, and one breaking change for code that embeds Cadence.
Removed the unused controller parameter from the storage interface methods:
func GetValue(owner, controller, key []byte) (value []byte, err error)
โ func GetValue(owner, key []byte) (value []byte, err error)
SetValue(owner, controller, key, value []byte) (err error)
โ SetValue(owner, key, value []byte) (err error)
ValueExists(owner, controller, key []byte) (exists bool, err error)
โ ValueExists(owner, key []byte) (exists bool, err error)
This is only a breaking change in the implementation of Cadence, i.e for code that embeds Cadence, not in the Cadence language, i.e. for users of Cadence.
Added an optional callback for writes with high-level values to the interface:
type HighLevelStorage interface {
// HighLevelStorageEnabled should return true
// if the functions of HighLevelStorage should be called,
// e.g. SetCadenceValue
HighLevelStorageEnabled() bool
// SetCadenceValue sets a value for the given key in the storage, owned by the given account.
SetCadenceValue(owner Address, key string, value cadence.Value) (err error)
}
This is a feature in the implementation of Cadence, i.e for code that embeds Cadence, not in the Cadence language, i.e. for users of Cadence.
[Changes][v0.6.0]
<a id="v0.5.1"></a>
Nothing published for this version
[Changes][v0.5.1]
<a id="v0.5.0"></a>
A new built-in contract Crypto was added for performing cryptographic operations.
The contract can be imported using import Crypto.
This first iteration provides support for validating signatures, with an API that supports multiple signatures and weighted keys.
For example, to verify two signatures with equal weights for some signed data:
let keyList = Crypto.KeyList()
let publicKeyA = Crypto.PublicKey(
publicKey:
"db04940e18ec414664ccfd31d5d2d4ece3985acb8cb17a2025b2f1673427267968e52e2bbf3599059649d4b2cce98fdb8a3048e68abf5abe3e710129e90696ca".decodeHex(),
signatureAlgorithm: Crypto.ECDSA_P256
)
keyList.add(
publicKeyA,
hashAlgorithm: Crypto.SHA3_256,
weight: 0.5
)
let publicKeyB = Crypto.PublicKey(
publicKey:
"df9609ee588dd4a6f7789df8d56f03f545d4516f0c99b200d73b9a3afafc14de5d21a4fc7a2a2015719dc95c9e756cfa44f2a445151aaf42479e7120d83df956".decodeHex(),
signatureAlgorithm: Crypto.ECDSA_P256
)
keyList.add(
publicKeyB,
hashAlgorithm: Crypto.SHA3_256,
weight: 0.5
)
let signatureSet = [
Crypto.KeyListSignature(
keyIndex: 0,
signature:
"8870a8cbe6f44932ba59e0d15a706214cc4ad2538deb12c0cf718d86f32c47765462a92ce2da15d4a29eb4e2b6fa05d08c7db5d5b2a2cd8c2cb98ded73da31f6".decodeHex()
),
Crypto.KeyListSignature(
keyIndex: 1,
signature:
"bbdc5591c3f937a730d4f6c0a6fde61a0a6ceaa531ccb367c3559335ab9734f4f2b9da8adbe371f1f7da913b5a3fdd96a871e04f078928ca89a83d841c72fadf".decodeHex()
)
]
// "foo", encoded as UTF-8, in hex representation
let signedData = "666f6f".decodeHex()
let isValid = keyList.isValid(
signatureSet: signatureSet,
signedData: signedData
)
The type Type was added to represent types at run-time.
To create a type value, use the constructor function Type<T>(), which accepts the static type as a type argument.
This is similar to e.g. T.self in Swift, T::class in Kotlin, and T.class in Java.
For example, to represent the type Int at run-time:
let intType: Type = Type<Int>()
This works for both built-in and user-defined types. For example, to get the type value for a resource:
resource Collectible {}
let collectibleType = Type<@Collectible>()
The function fun isInstance(_ type: Type): Bool can be used to check if a value has a certain type:
let collectible <- create Collectible()
let collectibleType = Type<@Collectible>()
let result = collectible.isInstance(collectibleType)
For example, this allows implementing a marketplace sale resource:
pub resource SimpleSale {
pub var objectForSale: @AnyResource?
pub let priceForObject: UFix64
pub let requiredCurrency: Type
pub let paymentReceiver: Capability<&{FungibleToken.Receiver}>
init(
objectForSale: @AnyResource,
priceForObject: UFix64,
requiredCurrency: Type,
paymentReceiver: Capability<&{FungibleToken.Receiver}>
) {
self.objectForSale <- objectForSale
self.priceForObject = priceForObject
self.requiredCurrency = requiredCurrency
self.paymentReceiver = paymentReceiver
}
destroy() {
destroy self.objectForSale
}
pub fun buyObject(purchaseAmount: @FungibleToken.Vault): @AnyResource {
pre {
self.objectForSale != nil
purchaseAmount.balance >= self.priceForObject
purchaseAmount.isInstance(self.requiredCurrency)
}
let receiver = self.paymentReceiver.borrow()
?? panic("failed to borrow payment receiver capability")
receiver.deposit(from: <-purchaseAmount)
let objectForSale <- self.objectForSale <- nil
return <-objectForSale
}
}
The existing parser was replaced by a new implementation, completely written from scratch, producing the same result as the old parser.
It is significantly faster than the old parser. For example, the following benchmark shows the difference for parsing all fungible and non-fungible token contracts and example transactions:
$ go run ./cmd/parse -bench ../../flow-{n,}ft/{contracts,transactions}/*
flow-nft/contracts/ExampleNFT.cdc: [old] 9 111116110 ns/op
flow-nft/contracts/ExampleNFT.cdc: [new] 2712 463483 ns/op
flow-nft/contracts/NonFungibleToken.cdc: [old] 393 3097172 ns/op
flow-nft/contracts/NonFungibleToken.cdc: [new] 3489 348496 ns/op
flow-nft/transactions/mint_nft.cdc: [old] 700 1574730 ns/op
flow-nft/transactions/mint_nft.cdc: [new] 12770 94070 ns/op
flow-nft/transactions/read_nft_data.cdc: [old] 994 1222887 ns/op
flow-nft/transactions/read_nft_data.cdc: [new] 15242 79295 ns/op
flow-nft/transactions/setup_account.cdc: [old] 1281 879751 ns/op
flow-nft/transactions/setup_account.cdc: [new] 16675 71759 ns/op
flow-nft/transactions/transfer_nft.cdc: [old] 72 16417568 ns/op
flow-nft/transactions/transfer_nft.cdc: [new] 10000 109380 ns/op
flow-ft/contracts/CustodialDeposit.cdc: [old] 18 64938763 ns/op
flow-ft/contracts/CustodialDeposit.cdc: [new] 3482 354662 ns/op
flow-ft/contracts/FlowToken.cdc: [old] 7 177111544 ns/op
flow-ft/contracts/FlowToken.cdc: [new] 1920 640557 ns/op
flow-ft/contracts/FungibleToken.cdc: [old] 232 5324962 ns/op
flow-ft/contracts/FungibleToken.cdc: [new] 2947 419529 ns/op
flow-ft/contracts/TokenForwarding.cdc: [old] 44 25136749 ns/op
flow-ft/contracts/TokenForwarding.cdc: [new] 7183 172917 ns/op
flow-ft/transactions/burn_tokens.cdc: [old] 37 31475393 ns/op
flow-ft/transactions/burn_tokens.cdc: [new] 11361 105932 ns/op
flow-ft/transactions/create_forwarder.cdc: [old] 733 1636347 ns/op
flow-ft/transactions/create_forwarder.cdc: [new] 8127 147520 ns/op
flow-ft/transactions/create_minter.cdc: [old] 1306 923201 ns/op
flow-ft/transactions/create_minter.cdc: [new] 15240 77666 ns/op
flow-ft/transactions/custodial_deposit.cdc: [old] 69 16504795 ns/op
flow-ft/transactions/custodial_deposit.cdc: [new] 7940 144228 ns/op
flow-ft/transactions/get_balance.cdc: [old] 1094 1111272 ns/op
flow-ft/transactions/get_balance.cdc: [new] 18741 65745 ns/op
flow-ft/transactions/get_supply.cdc: [old] 1392 740989 ns/op
flow-ft/transactions/get_supply.cdc: [new] 46008 26719 ns/op
flow-ft/transactions/mint_tokens.cdc: [old] 72 17435128 ns/op
flow-ft/transactions/mint_tokens.cdc: [new] 8841 124117 ns/op
flow-ft/transactions/setup_account.cdc: [old] 1219 1089357 ns/op
flow-ft/transactions/setup_account.cdc: [new] 13797 84948 ns/op
flow-ft/transactions/transfer_tokens.cdc: [old] 74 17011751 ns/op
flow-ft/transactions/transfer_tokens.cdc: [new] 9578 125829 ns/op
The new parser also provides better error messages and will allow us to provide even better error messages in the future.
The new parser is enabled by default โ if you discover any problems or regressions, please report them!
Capabilities now accept an optional type argument, the reference type the capability should be borrowed as.
If a type argument is provided, it will be used for borrow and check calls, so there is no need to provide a type argument for the calls anymore.
The function getCapability now also accepts an optional type argument, and returns a typed capability if one is provided.
For example, the following two functions have the same behaviour:
fun cap1(): &Something? {
// The type annotation for `cap` is only added for demonstration purposes,
// it can also be omitted, because it can be inferred from the value
let cap: Capability = getAccount(0x1).getCapability(/public/something)!
return cap.borrow<&Something>()
}
fun cap2(): &Something? {
// The type annotation for `cap` is only added for demonstration purposes,
// it can also be omitted, because it can be inferred from the value
let cap: Capability<&Something> =
getAccount(0x1).getCapability<&Something>(/public/something)!
return cap.borrow()
}
Prefer a typed capability over a non-typed one to reduce uses / borrows to a simple .borrow(), instead of having to repeatedly mention the borrowed type.
Just like transactions, the main functions of scripts can now have parameters.
For example, a script that can be passed an integer and a string, and which logs both values, can be written as:
pub fun main(x: Int, y: String) {
log(x)
log(y)
}
The function fun toString(): String was added to all number types and addresses. It returns the textual representation of the type. A future version of Cadence will add this function to more types.
The function fun toBytes(): [UInt8] was added to Address. It returns the byte representation of the address.
The function fun toBigEndianBytes(): [UInt8] was added to all number types. It returns the big-endian byte representation of the number value.
Fields which have a non-storable type are now rejected:
Non-storable types are:
((Int): Bool))AuthAccount / PublicAccount)VoidA future version will also make references non-storable. Instead of storing a reference, store a capability and borrow it to acquire a reference.
Cadence now represents all byte arrays as [UInt8] rather than [Int]. This affects the following functions:
String.decodeHex(): [Int] => String.decodeHex(): [UInt8]AuthAccount.addPublicKey(publicKey: [Int]) => AuthAccount.addPublicKey(publicKey: [UInt8])AuthAccount.setCode(code: [Int]) => AuthAccount.setCode(code: [UInt8])However, array literals such as the following will still be inferred as [Int], meaning that they can't be used directly:
myAccount.addPublicKey([1, 2, 3])
Consider using String.decodeHex() for now until type inference has been improved.
[Changes][v0.5.0]
<a id="v0.4.0"></a>
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version