Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env.development
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
NEXT_PUBLIC_ACCESS_NODE_API=http://localhost:8080
NEXT_PUBLIC_ACCESS_NODE_API=http://localhost:8888
NEXT_PUBLIC_DISCOVERY_WALLET=http://localhost:8701/fcl/authn
NEXT_PUBLIC_CONTRACT_PROFILE=0xf8d6e0586b0a20c7
NEXT_PUBLIC_FLOW_NETWORK=emulator
2 changes: 1 addition & 1 deletion .env.production
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
NEXT_PUBLIC_ACCESS_NODE_API=https://rest-testnet.onflow.org
NEXT_PUBLIC_DISCOVERY_WALLET=https://fcl-discovery.onflow.org/testnet/authn
NEXT_PUBLIC_CONTRACT_PROFILE=0xba1132bc08f82fe2
NEXT_PUBLIC_FLOW_NETWORK=testnet
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ npm run start
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start the emulator, deploy the contracts, followed by the development server:

```bash
flow emulator start --dev-wallet
flow project deploy --network emulator
flow emulator # run emulator
flow deploy # deploy smart contracts
flow dev-wallet # run dev wallet

npm run dev
# or start the server and open the app in a new browser tab
Expand Down
127 changes: 67 additions & 60 deletions cadence/contracts/Profile.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ This will lead to predictability in how applications can look up the data.

transaction {
let address: address
prepare(currentUser: AuthAccount) {
prepare(currentUser: auth(SaveValue, PublishCapability, IssueStorageCapabilityController) &Account) {
self.address = currentUser.address
if !Profile.check(self.address) {
currentUser.save(<- Profile.new(), to: Profile.privatePath)
currentUser.link<&Profile.Base{Profile.Public}>(Profile.publicPath, target: Profile.privatePath)
let profileCapability = currentUser.capabilities.storage.issue<&{Profile.Public}>(Profile.privatePath)
currentUser.capabilities.publish(profileCapability, at: Profile.publicPath)
}
}
post {
Expand All @@ -92,11 +92,12 @@ This will lead to predictability in how applications can look up the data.
import Profile from 0xba1132bc08f82fe2

transaction {
prepare(currentUser: AuthAccount) {
prepare(currentUser: auth(SaveValue, PublishCapability, IssueStorageCapabilityController) &Account) {
self.address = currentUser.address
if !Profile.check(self.address) {
currentUser.save(<- Profile.new(), to: Profile.privatePath)
currentUser.link<&Profile.Base{Profile.Public}>(Profile.publicPath, target: Profile.privatePath)
let profileCapability = currentUser.capabilities.storage.issue<&{Profile.Public}>(Profile.privatePath)
currentUser.capabilities.publish(profileCapability, at: Profile.publicPath)
}
}
post {
Expand Down Expand Up @@ -124,8 +125,9 @@ As the owner of a resource you can update the following:
import Profile from 0xba1132bc08f82fe2

transaction(name: String) {
prepare(currentUser: AuthAccount) {
prepare(currentUser: auth(BorrowValue) &Account) {
currentUser
.storage
.borrow<&{Profile.Owner}>(from: Profile.privatePath)!
.setName(name)
}
Expand All @@ -142,8 +144,9 @@ As the owner of a resource you can update the following:
import Profile from 0xba1132bc08f82fe2

transaction(name: String) {
prepare(currentUser: AuthAccount) {
prepare(currentUser: auth(BorrowValue) &Account) {
currentUser
.storage
.borrow<&{Profile.Owner}>(from: Profile.privatePath)!
.setName(name)
}
Expand All @@ -165,7 +168,7 @@ As the owner of a resource you can update the following:

import Profile from 0xba1132bc08f82fe2

pub fun main(address: Address): Profile.ReadOnly? {
access(all) fun main(address: Address): Profile.ReadOnly? {
return Profile.read(address)
}

Expand All @@ -179,7 +182,7 @@ As the owner of a resource you can update the following:
cadence: `
import Profile from 0xba1132bc08f82fe2

pub fun main(address: Address): Profile.ReadOnly? {
access(all) fun main(address: Address): Profile.ReadOnly? {
return Profile.read(address)
}
`,
Expand All @@ -198,7 +201,7 @@ As the owner of a resource you can update the following:

import Profile from 0xba1132bc08f82fe2

pub fun main(addresses: [Address]): {Address: Profile.ReadOnly} {
access(all) fun main(addresses: [Address]): {Address: Profile.ReadOnly} {
return Profile.readMultiple(addresses)
}

Expand All @@ -212,7 +215,7 @@ As the owner of a resource you can update the following:
cadence: `
import Profile from 0xba1132bc08f82fe2

pub fun main(addresses: [Address]): {Address: Profile.ReadOnly} {
access(all) fun main(addresses: [Address]): {Address: Profile.ReadOnly} {
return Profile.readMultiple(addresses)
}
`,
Expand All @@ -231,7 +234,7 @@ As the owner of a resource you can update the following:

import Profile from 0xba1132bc08f82fe2

pub fun main(address: Address): Bool {
access(all) fun main(address: Address): Bool {
return Profile.check(address)
}

Expand All @@ -245,7 +248,7 @@ As the owner of a resource you can update the following:
cadence: `
import Profile from 0xba1132bc08f82fe2

pub fun main(address: Address): Bool {
access(all) fun main(address: Address): Bool {
return Profile.check(address)
}
`,
Expand All @@ -255,39 +258,39 @@ As the owner of a resource you can update the following:
})

*/
pub contract Profile {
pub let publicPath: PublicPath
pub let privatePath: StoragePath

pub resource interface Public {
pub fun getName(): String
pub fun getAvatar(): String
pub fun getColor(): String
pub fun getInfo(): String
pub fun asReadOnly(): Profile.ReadOnly
access(all) contract Profile {
access(all) let publicPath: PublicPath
access(all) let privatePath: StoragePath

access(all) resource interface Public {
access(all) fun getName(): String
access(all) fun getAvatar(): String
access(all) fun getColor(): String
access(all) fun getInfo(): String
access(all) fun asReadOnly(): Profile.ReadOnly
}

pub resource interface Owner {
pub fun getName(): String
pub fun getAvatar(): String
pub fun getColor(): String
pub fun getInfo(): String
access(all) resource interface Owner {
access(all) fun getName(): String
access(all) fun getAvatar(): String
access(all) fun getColor(): String
access(all) fun getInfo(): String

pub fun setName(_ name: String) {
access(all) fun setName(_ name: String) {
pre {
name.length <= 15: "Names must be under 15 characters long."
}
}
pub fun setAvatar(_ src: String)
pub fun setColor(_ color: String)
pub fun setInfo(_ info: String) {
access(all) fun setAvatar(_ src: String)
access(all) fun setColor(_ color: String)
access(all) fun setInfo(_ info: String) {
pre {
info.length <= 280: "Profile Info can at max be 280 characters long."
}
}
}

pub resource Base: Owner, Public {
access(all) resource Base: Owner, Public {
access(self) var name: String
access(self) var avatar: String
access(self) var color: String
Expand All @@ -300,17 +303,17 @@ pub contract Profile {
self.info = ""
}

pub fun getName(): String { return self.name }
pub fun getAvatar(): String { return self.avatar }
pub fun getColor(): String {return self.color }
pub fun getInfo(): String { return self.info }
access(all) fun getName(): String { return self.name }
access(all) fun getAvatar(): String { return self.avatar }
access(all) fun getColor(): String {return self.color }
access(all) fun getInfo(): String { return self.info }

pub fun setName(_ name: String) { self.name = name }
pub fun setAvatar(_ src: String) { self.avatar = src }
pub fun setColor(_ color: String) { self.color = color }
pub fun setInfo(_ info: String) { self.info = info }
access(all) fun setName(_ name: String) { self.name = name }
access(all) fun setAvatar(_ src: String) { self.avatar = src }
access(all) fun setColor(_ color: String) { self.color = color }
access(all) fun setInfo(_ info: String) { self.info = info }

pub fun asReadOnly(): Profile.ReadOnly {
access(all) fun asReadOnly(): Profile.ReadOnly {
return Profile.ReadOnly(
address: self.owner?.address,
name: self.getName(),
Expand All @@ -321,12 +324,12 @@ pub contract Profile {
}
}

pub struct ReadOnly {
pub let address: Address?
pub let name: String
pub let avatar: String
pub let color: String
pub let info: String
access(all) struct ReadOnly {
access(all) let address: Address?
access(all) let name: String
access(all) let avatar: String
access(all) let color: String
access(all) let info: String

init(address: Address?, name: String, avatar: String, color: String, info: String) {
self.address = address
Expand All @@ -337,31 +340,33 @@ pub contract Profile {
}
}

pub fun new(): @Profile.Base {
access(all) fun new(): @Profile.Base {
return <- create Base()
}

pub fun check(_ address: Address): Bool {
access(all) fun check(_ address: Address): Bool {
return getAccount(address)
.getCapability<&{Profile.Public}>(Profile.publicPath)
.capabilities
.get<&{Profile.Public}>(Profile.publicPath)
.check()
}

pub fun fetch(_ address: Address): &{Profile.Public} {
access(all) fun fetch(_ address: Address): &{Profile.Public} {
return getAccount(address)
.getCapability<&{Profile.Public}>(Profile.publicPath)
.capabilities
.get<&{Profile.Public}>(Profile.publicPath)
.borrow()!
}

pub fun read(_ address: Address): Profile.ReadOnly? {
if let profile = getAccount(address).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() {
access(all) fun read(_ address: Address): Profile.ReadOnly? {
if let profile = getAccount(address).capabilities.get<&{Profile.Public}>(Profile.publicPath).borrow() {
return profile.asReadOnly()
} else {
return nil
}
}

pub fun readMultiple(_ addresses: [Address]): {Address: Profile.ReadOnly} {
access(all) fun readMultiple(_ addresses: [Address]): {Address: Profile.ReadOnly} {
let profiles: {Address: Profile.ReadOnly} = {}
for address in addresses {
let profile = Profile.read(address)
Expand All @@ -377,11 +382,13 @@ pub contract Profile {
self.publicPath = /public/profile
self.privatePath = /storage/profile

self.account.save(<- self.new(), to: self.privatePath)
self.account.link<&Base{Public}>(self.publicPath, target: self.privatePath)
self.account.storage.save(<- self.new(), to: self.privatePath)
let profileCapability = self.account.capabilities.storage.issue<&{Public}>(self.privatePath)
self.account.capabilities.publish(profileCapability, at: self.publicPath)

self.account
.borrow<&Base{Owner}>(from: self.privatePath)!
.storage
.borrow<&{Owner}>(from: self.privatePath)!
.setName("qvvg")
}
}
}
5 changes: 5 additions & 0 deletions cadence/scripts/read-profile.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import "Profile"

access(all) fun main(address: Address): Profile.ReadOnly? {
return Profile.read(address)
}
15 changes: 15 additions & 0 deletions cadence/transactions/create-profile.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import "Profile"

transaction {
prepare(account: auth(SaveValue, PublishCapability, IssueStorageCapabilityController) &Account) {
// Only initialize the account if it hasn't already been initialized
if (!Profile.check(account.address)) {
// This creates and stores the profile in the user's account
account.storage.save(<- Profile.new(), to: Profile.privatePath)

// This creates the public capability that lets applications read the profile's info
let profileCapability = account.capabilities.storage.issue<&{Profile.Public}>(Profile.privatePath)
account.capabilities.publish(profileCapability, at: Profile.publicPath)
}
}
}
20 changes: 20 additions & 0 deletions cadence/transactions/update-profile.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import "Profile"

transaction(name: String, color: String, info: String) {
prepare(account: auth(BorrowValue) &Account) {
account
.storage
.borrow<&{Profile.Owner}>(from: Profile.privatePath)!
.setName(name)

account
.storage
.borrow<&{Profile.Owner}>(from: Profile.privatePath)!
.setInfo(info)

account
.storage
.borrow<&{Profile.Owner}>(from: Profile.privatePath)!
.setColor(color)
}
}
Loading