Account Model
Cadence-or other resource-oriented smart contract languages like Move-completely differentiate themselves from central ledger-based languages such as Solidity.
Instead of storing user data inside the contract, data is stored in the form of Resources inside user accounts. This means users completely own and control their data once it is in their account, unless the user explicity allows their data to be accessed/modified through published Capabilities.
Solidity vs. Cadence
In the Solidity world, all data is stored inside of the contract. The contract acts as a central ledger.
Furthermore, assets such as NFTs are represented as simple integers. If we wanted to know who owned a specific NFT (with ‘id’ == 4), we would go inside the contract and ask “what is the address associated with ‘id’ == 4?”
However in Cadence, two things differ:
- Data is stored in user accounts, not the contract
- Assets such as NFTs are represented as actual objects (“resources”) that can store their own data and functions
This has a lot of benefits. Namely, resources have built-in properties that make them extremely secure. They cannot be copied or lost.
Let’s take a look at an NFT example in Cadence:
While definitions of the NFT resource and Collection are made in the contract, the user actually stores a Collection resource inside their account.
Example Implementation
Below is an example smart contract & associated transaction leveraging the resource-oriented nature of Cadence, and showing how they get stored in accounts.
pub contract Test {
// define a new Profile resource
pub resource Profile {
pub let id: UInt64
pub let name: String
pub let favoriteNumber: Int
init(name: String, favoriteNumber: Int) {
self.id = self.uuid // a unique identifier for every resource in existence
self.name = name
self.favoriteNumber = favoriteNumber
}
}
// public function to create a Profile
pub fun createProfile(name: String, favoriteNumber: Int): @Profile {
return <- create Profile(name: name, favoriteNumber: favoriteNumber)
}
}
import Test from 0x01
transaction(name: String, favoriteNumber: Int) {
prepare(signer: AuthAccount) {
// a new 'Profile' resource is created
let newProfile <- Profile.createProfile(name: name, favoriteNumber: favoriteNumber)
// the 'Profile' gets stored in the user's account
signer.save(<- newProfile, to: /storage/TestProfile)
}
}