Skip to content

Commit

Permalink
Add new LinearCodeAddressGenerator contract (#467)
Browse files Browse the repository at this point in the history
* add new LinearCodeAddressGenerator contract

* refactor code words into dictionary to improve extensibility

* update assets

* test address is not valid with other chain codewords

* hide (invalid) code words behind chain

* update assets

* Apply suggestions from code review

Co-authored-by: Tarak Ben Youssef <50252200+tarakby@users.noreply.github.com>

* clean up

* rename code word function

* address at index is only valid in range [1 .. 2^45 - 1]

* update assets

* remove TODO, use bitshift

* use maxIndex variable

* add linear code address generator

---------

Co-authored-by: Tarak Ben Youssef <50252200+tarakby@users.noreply.github.com>
  • Loading branch information
turbolent and tarakby authored Mar 3, 2025
1 parent 9339cb6 commit 1102446
Show file tree
Hide file tree
Showing 5 changed files with 381 additions and 52 deletions.
112 changes: 60 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,27 @@ Flow is a new blockchain for open worlds. Read more about it [here](https://www.

# What is Cadence?

Cadence is a new Resource-oriented programming language
Cadence is a new Resource-oriented programming language
for developing smart contracts for the Flow Blockchain.
Read more about it [here](https://www.docs.onflow.org)

We recommend that anyone who is reading this should have already
completed the [Cadence Tutorials](https://docs.onflow.org/docs/getting-started-1)
completed the [Cadence Tutorials](https://docs.onflow.org/docs/getting-started-1)
so they can build a basic understanding of the programming language.

## FlowToken

`contracts/FlowToken.cdc`

| Network | Contract Address |
| ---------------------------- | -------------------- |
| Emulator | `0x0ae53cb6e3f42a79` |
| Testnet | `0x7e60df042a9c0868` |
| Mainnet | `0x1654653399040a61` |
| Network | Contract Address |
| ---------| -------------------- |
| Emulator | `0x0ae53cb6e3f42a79` |
| Testnet | `0x7e60df042a9c0868` |
| Mainnet | `0x1654653399040a61` |

This is the contract that defines the network token for Flow.
This token is used for account creation fees, transaction fees, staking, and more. It is
implemented as a regular smart contract so that it can be easily used
This is the contract that defines the network token for Flow.
This token is used for account creation fees, transaction fees, staking, and more. It is
implemented as a regular smart contract so that it can be easily used
just like any other token in the network. See the [flow fungible token repository](https://github.com/onflow/flow-ft)
for more information.

Expand All @@ -43,23 +43,23 @@ You can find transactions for using the Flow Token in the `transactions/flowToke

`contracts/FlowFees.cdc`

| Network | Contract Address |
| ---------------------------- | -------------------- |
| Emulator | `0xe5a8b7f23e8b548f` |
| Testnet | `0x912d5440f7e3769e` |
| Mainnet | `0xf919ee77447b7497` |
| Network | Contract Address |
| ---------| -------------------- |
| Emulator | `0xe5a8b7f23e8b548f` |
| Testnet | `0x912d5440f7e3769e` |
| Mainnet | `0xf919ee77447b7497` |

This contract defines fees that are spent for executing transactions and creating accounts.

## Storage Fee Contract

`contracts/FlowStorageFees.cdc`

| Network | Contract Address |
| ---------------------------- | -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x8c5303eaa26202d6` |
| Mainnet | `0xe467b9dd11fa00df` |
| Network | Contract Address |
| ---------| -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x8c5303eaa26202d6` |
| Mainnet | `0xe467b9dd11fa00df` |

This contract defines fees that are spent to pay for the storage that an account uses.
There is a minimum balance that an account needs to maintain in its main `FlowToken` Vault
Expand All @@ -70,11 +70,11 @@ You can see [more docs about storage capacity and fees here.](https://docs.onflo

`contracts/FlowServiceAccount.cdc`

| Network | Contract Address |
| ---------------------------- | -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x8c5303eaa26202d6` |
| Mainnet | `0xe467b9dd11fa00df` |
| Network | Contract Address |
| ---------| -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x8c5303eaa26202d6` |
| Mainnet | `0xe467b9dd11fa00df` |

This contract manages account creation and flow token initialization. It enforces temporary
requirements for which accounts are allowed to create other accounts, and provides common
Expand All @@ -86,11 +86,11 @@ You can find transactions for interacting with the service account contract in t

`contracts/RandomBeaconHistory.cdc`

| Network | Contract Address |
| ---------------------------- | -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x8c5303eaa26202d6` |
| Mainnet | `0xe467b9dd11fa00df` |
| Network | Contract Address |
| ---------| -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x8c5303eaa26202d6` |
| Mainnet | `0xe467b9dd11fa00df` |

This contract stores the history of random sources generated by
the Flow network. The defined Heartbeat resource is
Expand All @@ -104,11 +104,11 @@ You can find transactions for interacting with the random beacon

`contracts/NodeVersionBeacon.cdc`

| Network | Contract Address |
| ----------------- | -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x8c5303eaa26202d6` |
| Mainnet | `0xe467b9dd11fa00df` |
| Network | Contract Address |
| ---------| -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x8c5303eaa26202d6` |
| Mainnet | `0xe467b9dd11fa00df` |

The `NodeVersionBeacon` contract holds the past
and future protocol versions that should be used
Expand All @@ -122,11 +122,11 @@ history contract in the `transactions/nodeVersionBeacon` directory.
`contracts/FlowIDTableStaking.cdc`
`contracts/epochs/FlowEpoch.cdc`

| Network | Contract Address |
| ------------------- | -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x9eca2b38b18b5dfe` |
| Mainnet | `0x8624b52f9ddcd04a` |
| Network | Contract Address |
| ---------| -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x9eca2b38b18b5dfe` |
| Mainnet | `0x8624b52f9ddcd04a` |

These contract manages the list of identities that correspond to node operators in the Flow network
as well as the process for adding and removing nodes from the network via Epochs.
Expand All @@ -152,11 +152,11 @@ These scripts are documented in the [staking scripts section of the docs](https:

`contracts/LockedTokens.cdc`

| Network | Contract Address |
| --------------- | -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x95e019a17d0e23d7` |
| Mainnet | `0x8d0e87b65159ae63` |
| Network | Contract Address |
| ---------| -------------------- |
| Emulator | `0xf8d6e0586b0a20c7` |
| Testnet | `0x95e019a17d0e23d7` |
| Mainnet | `0x8d0e87b65159ae63` |

This contract manages the two year lockup of Flow tokens that backers purchased in the initial
token sale in October of 2020. See more documentation about `LockedTokens` [here.](https://docs.onflow.org/flow-token/locked-account-setup/)
Expand Down Expand Up @@ -195,16 +195,24 @@ then all the changes are handled for them and there is nothing for you to worry

### Staking Collection Technical features

* The staking collection contract stores [a dictionary of staking objects](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStakingCollection.cdc#L68) from the staking contract that are used to manage the stakers tokens. Since they are dictionaries, there can be as many node or delegator objects per account as the user wants.
* The staking collection contract stores [a dictionary of staking objects](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStakingCollection.cdc#L68) from the staking contract that are used to manage the stakers tokens. Since they are dictionaries, there can be as many node or delegator objects per account as the user wants.
* The resource only has one set of staking methods, which route the call to the correct staking object based on the arguments that the caller specifies. (nodeID, delegatorID)
* The contract also stores an [optional capability to the locked token vault](https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowStakingCollection.cdc#L63) and [locked tokens `TokenHolder` resource](https://github.com/onflow/flow-core-contracts/blob/master/ontracts/FlowStakingCollection.cdc#L73). This is only used if the user already has a locked account. The staking collection does not change the locked account setup at all, it only has access to it and to the locked vault.
* The collection makes the staking objects and vault capability fields private, because since it has access to the locked tokens, it needs to mediate access to the staking objects so users cannot withdraw tokens that are still locked from the sale. The resource has fields `unlockedTokensUsed` and `lockedTokensUsed`, to keep track of how many locked and unlocked tokens are being used for staking in order to allow the user to withdraw the correct amount when they choose to.
* The staking collection contract is a brand new contract that will be deployed to the same account as the existing locked tokens contract. A few of the fields on the `LockedTokens` contract have been updated to have `access(account)` visibility instead of `access(self)` because the staking collection contract needs to be able to access to them in order to work properly.
* We also included a public interface and getters in the contract so you can easily query it with an address to get node or delegator information from a collection.
* We also included a public interface and getters in the contract so you can easily query it with an address to get node or delegator information from a collection.

Looking for feedback on design decisions, implementation details, any events that would be useful to include in the contract, and whatever you feel is important!

We intend for this to be the method that all Flow Port users (ledger, blocto, etc) use for the forseeable future. When we enable it in Flow Port, we will ask every user to run a transaction to set up their account to use the staking collection from then on.
We intend for this to be the method that all Flow Port users (ledger, blocto, etc) use for the forseeable future. When we enable it in Flow Port, we will ask every user to run a transaction to set up their account to use the staking collection from then on.

## Linear Code Address Generator

`contracts/LinearCodeAddressGenerator.cdc`

The linear code address generator contract allows translating an address index to an address,
and and address back to an address index.
It implements the same address generation logic as used on all Flow networks.

# Testing

Expand All @@ -218,22 +226,22 @@ Flow Core Contracts were audited by Quantstamp in July 2021: [final report](http

# Getting Transaction Templates

If you need to use the contracts and transaction templates we have provided in an app, you don't necessarily
If you need to use the contracts and transaction templates we have provided in an app, you don't necessarily
need to copy and paste them into your code. We plan on providing packages for different
languages to import in order to use the transactions instead of copying and pasting.

We currently include the `lib/go/templates` package for getting templates in the Go programming language.
To use this package, run `go get github.com/onflow/flow-core-contracts/lib/go/templates@{latest version}`
in your Go project direcory. To use it in your Go code, you can simply call one of the many
template getters in one of the `*_templates.go` files.
in your Go project direcory. To use it in your Go code, you can simply call one of the many
template getters in one of the `*_templates.go` files.

### Packages in other languages

We would like to add new packages for other popular languages to get transaction templates.
If you would like to contribute to add one of these new packages, please reach out
to the team and we would be happy to help!

## License
## License

The works in these folders are under the [Unlicense](https://github.com/onflow/flow-core-contracts/blob/master/LICENSE):

Expand Down
126 changes: 126 additions & 0 deletions contracts/LinearCodeAddressGenerator.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@

/// LinearCodeAddressGenerator allows generating and validating Flow account addresses.
access(all)
contract LinearCodeAddressGenerator {

access(all)
enum Chain: UInt8 {
access(all)
case Mainnet

access(all)
case Testnet

access(all)
case Transient
}

/// Rows of the generator matrix G of the [64,45]-code used for Flow addresses.
/// G is a (k x n) matrix with coefficients in GF(2), each row is converted into
/// a big endian integer representation of the GF(2) raw vector.
/// G is used to generate the account addresses
access(self)
let generatorMatrixRows: [UInt64; 45]

/// Columns of the parity-check matrix H of the [64,45]-code used for Flow addresses.
/// H is a (n x p) matrix with coefficients in GF(2), each column is converted into
/// a big endian integer representation of the GF(2) column vector.
/// H is used to verify a code word is a valid account address.
access(self)
let parityCheckMatrixColumns: [UInt64; 64]

init() {
self.generatorMatrixRows = [
0xe467b9dd11fa00df, 0xf233dcee88fe0abe, 0xf919ee77447b7497, 0xfc8cf73ba23a260d,
0xfe467b9dd11ee2a1, 0xff233dcee888d807, 0xff919ee774476ce6, 0x7fc8cf73ba231d10,
0x3fe467b9dd11b183, 0x1ff233dcee8f96d6, 0x8ff919ee774757ba, 0x47fc8cf73ba2b331,
0x23fe467b9dd27f6c, 0x11ff233dceee8e82, 0x88ff919ee775dd8f, 0x447fc8cf73b905e4,
0xa23fe467b9de0d83, 0xd11ff233dce8d5a7, 0xe88ff919ee73c38a, 0x7447fc8cf73f171f,
0xba23fe467b9dcb2b, 0xdd11ff233dcb0cb4, 0xee88ff919ee26c5d, 0x77447fc8cf775dd3,
0x3ba23fe467b9b5a1, 0x9dd11ff233d9117a, 0xcee88ff919efa640, 0xe77447fc8cf3e297,
0x73ba23fe467fabd2, 0xb9dd11ff233fb16c, 0xdcee88ff919adde7, 0xee77447fc8ceb196,
0xf73ba23fe4621cd0, 0x7b9dd11ff2379ac3, 0x3dcee88ff91df46c, 0x9ee77447fc88e702,
0xcf73ba23fe4131b6, 0x67b9dd11ff240f9a, 0x33dcee88ff90f9e0, 0x19ee77447fcff4e3,
0x8cf73ba23fe64091, 0x467b9dd11ff115c7, 0x233dcee88ffdb735, 0x919ee77447fe2309,
0xc8cf73ba23fdc736
]

self.parityCheckMatrixColumns = [
0x00001, 0x00002, 0x00004, 0x00008, 0x00010, 0x00020, 0x00040, 0x00080,
0x00100, 0x00200, 0x00400, 0x00800, 0x01000, 0x02000, 0x04000, 0x08000,
0x10000, 0x20000, 0x40000, 0x7328d, 0x6689a, 0x6112f, 0x6084b, 0x433fd,
0x42aab, 0x41951, 0x233ce, 0x22a81, 0x21948, 0x1ef60, 0x1deca, 0x1c639,
0x1bdd8, 0x1a535, 0x194ac, 0x18c46, 0x1632b, 0x1529b, 0x14a43, 0x13184,
0x12942, 0x118c1, 0x0f812, 0x0e027, 0x0d00e, 0x0c83c, 0x0b01d, 0x0a831,
0x0982b, 0x07034, 0x0682a, 0x05819, 0x03807, 0x007d2, 0x00727, 0x0068e,
0x0067c, 0x0059d, 0x004eb, 0x003b4, 0x0036a, 0x002d9, 0x001c7, 0x0003f
]
}

access(self)
fun invalidCodeWord(forChain chain: Chain): UInt64 {
switch chain {
case Chain.Mainnet:
return 0
case Chain.Testnet:
return 0x6834ba37b3980209
case Chain.Transient:
return 0x1cb159857af02018
default:
panic("unsupported chain")
}
}

access(self)
fun encodeWord(_ word: UInt64): UInt64 {

// Multiply the index GF(2) vector by the code generator matrix
var codeWord: UInt64 = 0
var word = word

for generatorMatrixRow in self.generatorMatrixRows {
if word & 1 == 1 {
codeWord = codeWord ^ generatorMatrixRow
}
word = word >> 1
}

return codeWord
}

/// Returns the address at the given index, for the given chain.
access(all)
fun address(at index: UInt64, chain: Chain): Address? {
// The index must be in the range [1 .. 2^45 - 1]
if index < 1 || index > (2 << 44) - 1 {
return nil
}
return Address(self.encodeWord(index) ^ self.invalidCodeWord(forChain: chain))
}

/// Returns true if the given address is valid, for the given chain code word.
access(all)
fun isValidAddress(_ address: Address, chain: Chain): Bool {

let address = UInt64.fromBigEndianBytes(address.toBytes())!
var codeWord = self.invalidCodeWord(forChain: chain) ^ address

if codeWord == 0 {
return false
}

// Multiply the code word GF(2)-vector by the parity-check matrix
var parity: UInt64 = 0

for parityCheckMatrixColumn in self.parityCheckMatrixColumns {
if codeWord & 1 == 1 {
parity = parity ^ parityCheckMatrixColumn
}
codeWord = codeWord >> 1
}

return parity == 0 && codeWord == 0
}
}
6 changes: 6 additions & 0 deletions flow.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@
"testnet": "9a0766d93b6608b7"
}
},
"LinearCodeAddressGenerator": {
"source": "./contracts/LinearCodeAddressGenerator.cdc",
"aliases": {
"testing": "0x0000000000000007"
}
},
"LockedTokens": {
"source": "./contracts/LockedTokens.cdc",
"aliases": {
Expand Down
Loading

0 comments on commit 1102446

Please sign in to comment.