Skip to content

Commit

Permalink
Update to Stable Cadence
Browse files Browse the repository at this point in the history
  • Loading branch information
m-Peter committed Jan 2, 2024
1 parent 39beb3d commit 3fc5c0c
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 56 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
with:
go-version: 1.20
- name: Install Flow CLI
run: bash -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)"
run: bash -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" -- v1.9.2-stable-cadence.1
- name: Run tests
run: flow test --cover --covercode="contracts" --coverprofile="coverage.lcov" tests/test_*.cdc
- name: Normalize coverage report filepaths
Expand Down
32 changes: 18 additions & 14 deletions contracts/ApprovalVoting.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,31 @@
/// A user can choose their votes and cast them with the `cast_vote.cdc`
/// transaction.
///
pub contract ApprovalVoting {
access(all) contract ApprovalVoting {

// List of proposals to be approved.
pub var proposals: [String]
access(all) var proposals: [String]

// Number of votes per proposal.
pub let votes: {Int: Int}
access(all) let votes: {Int: Int}

// Event emitted when proposals are initialized by the admin.
pub event ProposalsInitialized(proposals: [String])
access(all) event ProposalsInitialized(proposals: [String])

// Event emitted when users cast a vote on a proposal.
pub event VoteCasted(proposal: String)
access(all) event VoteCasted(proposal: String)

/// This is the resource that is issued to users.
/// When a user gets a Ballot object, they call the `vote` function
/// to include their votes, and then cast it in the smart contract
/// using the `cast` function to have their vote included in the polling.
pub resource Ballot {
access(all) resource Ballot {

// Array of all the proposals.
pub let proposals: [String]
access(all) let proposals: [String]

// Corresponds to an array index in proposals after a vote.
pub let choices: {Int: Bool}
access(all) let choices: {Int: Bool}

init() {
self.proposals = ApprovalVoting.proposals
Expand All @@ -54,7 +54,8 @@ pub contract ApprovalVoting {
}

// Modifies the ballot to indicate which proposals it is voting for.
pub fun vote(proposal: Int) {
access(all)
fun vote(proposal: Int) {
pre {
proposal <= (self.proposals.length - 1): "Cannot vote for a proposal that doesn't exist"
}
Expand All @@ -64,10 +65,11 @@ pub contract ApprovalVoting {

/// Resource that the Administrator of the vote controls to initialize
/// the proposals and to pass out ballot resources to voters.
pub resource Administrator {
access(all) resource Administrator {

// Function to initialize all the proposals for the voting.
pub fun initializeProposals(_ proposals: [String]) {
access(all)
fun initializeProposals(_ proposals: [String]) {
pre {
ApprovalVoting.proposals.length == 0: "Proposals can only be initialized once"
proposals.length > 0: "Cannot initialize with no proposals"
Expand All @@ -86,14 +88,16 @@ pub contract ApprovalVoting {

// The admin calls this function to create a new Ballot
// that can be transferred to another user.
pub fun issueBallot(): @Ballot {
access(all)
fun issueBallot(): @Ballot {
return <-create Ballot()
}
}

// A user moves their ballot to this function in the contract where
// its votes are tallied and the ballot is destroyed.
pub fun cast(ballot: @Ballot) {
access(all)
fun cast(ballot: @Ballot) {
var proposal = ""
var index = 0
// Look through the ballot.
Expand All @@ -118,7 +122,7 @@ pub contract ApprovalVoting {
self.proposals = []
self.votes = {}

self.account.save<@Administrator>(
self.account.storage.save<@Administrator>(
<-create Administrator(),
to: /storage/VotingAdmin
)
Expand Down
23 changes: 15 additions & 8 deletions contracts/ArrayUtils.cdc
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copied from https://github.com/green-goo-dao/flow-utils/blob/main/cadence/contracts/ArrayUtils.cdc
pub contract ArrayUtils {
access(all) contract ArrayUtils {

pub fun rangeFunc(_ start: Int, _ end: Int, _ f: ((Int):Void)) {
access(all)
fun rangeFunc(_ start: Int, _ end: Int, _ f: fun(Int): Void) {
var current = start
if start > end {
while current > end {
Expand All @@ -17,21 +18,24 @@ pub contract ArrayUtils {
}
}

pub fun range(_ start: Int, _ end: Int): [Int] {
access(all)
fun range(_ start: Int, _ end: Int): [Int] {
var res: [Int] = []
self.rangeFunc(start, end, fun (i: Int) {
res.append(i)
})
return res
}

pub fun transform(_ array: &[AnyStruct], _ f: ((AnyStruct): AnyStruct)) {
access(all)
fun transform(_ array: auth(Mutate) &[AnyStruct], _ f: fun(AnyStruct): AnyStruct) {
for i in self.range(0, array.length) {
array[i] = f(array[i])
}
}

pub fun iterate(_ array: [AnyStruct], _ f: ((AnyStruct): Bool)): [AnyStruct] {
access(all)
fun iterate(_ array: [AnyStruct], _ f: fun(AnyStruct): Bool): [AnyStruct] {
var res: [AnyStruct] = []
for item in array {
if !f(item) {
Expand All @@ -42,23 +46,26 @@ pub contract ArrayUtils {
return res
}

pub fun map(_ array: [AnyStruct], _ f: ((AnyStruct): AnyStruct)): [AnyStruct] {
access(all)
fun map(_ array: [AnyStruct], _ f: fun(AnyStruct): AnyStruct): [AnyStruct] {
var res: [AnyStruct] = []
for item in array {
res.append(f(item))
}
return res
}

pub fun mapStrings(_ array: [String], _ f: ((String): String)): [String] {
access(all)
fun mapStrings(_ array: [String], _ f: fun(String): String): [String] {
var res: [String] = []
for item in array {
res.append(f(item))
}
return res
}

pub fun reduce(_ array: [AnyStruct], _ initial: AnyStruct, _ f: ((AnyStruct, AnyStruct): AnyStruct)): AnyStruct {
access(all)
fun reduce(_ array: [AnyStruct], _ initial: AnyStruct, _ f: fun(AnyStruct, AnyStruct): AnyStruct): AnyStruct {
var res: AnyStruct = f(initial, array[0])
for i in self.range(1, array.length) {
res = f(res, array[i])
Expand Down
10 changes: 6 additions & 4 deletions contracts/FooContract.cdc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub contract FooContract {
pub let specialNumbers: {Int: String}
access(all) contract FooContract {
access(all) let specialNumbers: {Int: String}

init() {
// https://sites.google.com/site/mathematicsmiscellany/very-special-numbers
Expand All @@ -10,11 +10,13 @@ pub contract FooContract {
}
}

pub fun addSpecialNumber(_ n: Int, _ trait: String) {
access(all)
fun addSpecialNumber(_ n: Int, _ trait: String) {
self.specialNumbers[n] = trait
}

pub fun getIntegerTrait(_ n: Int): String {
access(all)
fun getIntegerTrait(_ n: Int): String {
if n < 0 {
return "Negative"
} else if n == 0 {
Expand Down
41 changes: 27 additions & 14 deletions contracts/StringUtils.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,28 @@
import "ArrayUtils"

pub contract StringUtils {
access(all) contract StringUtils {

pub fun format(_ s: String, _ args: {String: String}): String {
access(all)
fun format(_ s: String, _ args: {String: String}): String {
var formatted = s
for key in args.keys {
formatted = self.replaceAll(formatted, "{".concat(key).concat("}"), args[key]!)
}
return formatted
}

pub fun explode(_ s: String): [String] {
access(all)
fun explode(_ s: String): [String] {
var chars: [String] = []
for i in ArrayUtils.range(0, s.length) {
chars.append(s[i].toString())
}
return chars
}

pub fun trimLeft(_ s: String): String {
access(all)
fun trimLeft(_ s: String): String {
for i in ArrayUtils.range(0, s.length) {
if s[i] != " " {
return s.slice(from: i, upTo: s.length)
Expand All @@ -29,23 +32,28 @@ pub contract StringUtils {
return ""
}

pub fun trim(_ s: String): String {
access(all)
fun trim(_ s: String): String {
return self.trimLeft(s)
}

pub fun replaceAll(_ s: String, _ search: String, _ replace: String): String {
access(all)
fun replaceAll(_ s: String, _ search: String, _ replace: String): String {
return self.join(self.split(s, search), replace)
}

pub fun hasPrefix(_ s: String, _ prefix: String): Bool {
access(all)
fun hasPrefix(_ s: String, _ prefix: String): Bool {
return s.length >= prefix.length && s.slice(from: 0, upTo: prefix.length) == prefix
}

pub fun hasSuffix(_ s: String, _ suffix: String): Bool {
access(all)
fun hasSuffix(_ s: String, _ suffix: String): Bool {
return s.length >= suffix.length && s.slice(from: s.length - suffix.length, upTo: s.length) == suffix
}

pub fun index(_ s: String, _ substr: String, _ startIndex: Int): Int? {
access(all)
fun index(_ s: String, _ substr: String, _ startIndex: Int): Int? {
for i in ArrayUtils.range(startIndex, s.length - substr.length + 1) {
if s[i] == substr[0] && s.slice(from: i, upTo: i + substr.length) == substr {
return i
Expand All @@ -54,29 +62,33 @@ pub contract StringUtils {
return nil
}

pub fun count(_ s: String, _ substr: String): Int {
access(all)
fun count(_ s: String, _ substr: String): Int {
var pos = [self.index(s, substr, 0)]
while pos[0] != nil {
pos.insert(at: 0, self.index(s, substr, pos[0]! + pos.length * substr.length + 1))
}
return pos.length - 1
}

pub fun contains(_ s: String, _ substr: String): Bool {
access(all)
fun contains(_ s: String, _ substr: String): Bool {
if let index = self.index(s, substr, 0) {
return true
}
return false
}

pub fun substringUntil(_ s: String, _ until: String, _ startIndex: Int): String {
access(all)
fun substringUntil(_ s: String, _ until: String, _ startIndex: Int): String {
if let index = self.index(s, until, startIndex) {
return s.slice(from: startIndex, upTo: index)
}
return s.slice(from: startIndex, upTo: s.length)
}

pub fun split(_ s: String, _ delimiter: String): [String] {
access(all)
fun split(_ s: String, _ delimiter: String): [String] {
let segments: [String] = []
var p = 0
while p <= s.length {
Expand All @@ -87,7 +99,8 @@ pub contract StringUtils {
return segments
}

pub fun join(_ strs: [String], _ separator: String): String {
access(all)
fun join(_ strs: [String], _ separator: String): String {
var joinedStr = ""
for s in strs {
joinedStr = joinedStr.concat(s).concat(separator)
Expand Down
3 changes: 2 additions & 1 deletion scripts/foo_contract_scripts.cdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import FooContract from "../contracts/FooContract.cdc"

pub fun main(): Bool {
access(all)
fun main(): Bool {
let testInputs: {Int: String} = {
-1: "Negative",
0: "Zero",
Expand Down
3 changes: 2 additions & 1 deletion scripts/view_votes.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import ApprovalVoting from "../contracts/ApprovalVoting.cdc"

// This script allows anyone to read the tallied votes for each proposal.
pub fun main(): {Int: Int} {
access(all)
fun main(): {Int: Int} {
return ApprovalVoting.votes
}
4 changes: 2 additions & 2 deletions tests/test_approval_voting.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ fun testCastVote() {
let events = Test.eventsOfType(Type<ApprovalVoting.VoteCasted>())
Test.assertEqual(1, events.length)

let event = events[0] as! ApprovalVoting.VoteCasted
Test.assertEqual("Trampolines instead of hardwood floors", event.proposal)
let evt = events[0] as! ApprovalVoting.VoteCasted
Test.assertEqual("Trampolines instead of hardwood floors", evt.proposal)
}

access(all)
Expand Down
18 changes: 14 additions & 4 deletions tests/test_array_utils.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,21 @@ fun testTransform() {
]

// Act
ArrayUtils.transform(&tokens as &[AnyStruct], fun (t: AnyStruct): AnyStruct {
let token = t as! Token
// ArrayUtils.transform(&tokens as auth(Mutate) &[AnyStruct], fun (t: AnyStruct): AnyStruct {
// let token = t as! &Token
// token.setBalance(token.balance * 2)
// return token
// })
// Fails with: error: invalid container update: expected a subtype of `Token`, found `&Token`
// fun transform(_ array: auth(Mutate) &[AnyStruct], _ f: fun(AnyStruct): AnyStruct) {
// for i in self.range(0, array.length) {
// array[i] = f(array[i]) // the error is here
// }
// }
let tokensRef: auth(Mutate) &[Token] = &tokens
for token in tokensRef {
token.setBalance(token.balance * 2)
return token
})
}

// Assert
let expected = [
Expand Down
4 changes: 2 additions & 2 deletions transactions/cast_vote.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import ApprovalVoting from "../contracts/ApprovalVoting.cdc"
// smart contract.
transaction(proposal: Int) {
prepare(voter: AuthAccount) {
prepare(voter: auth(LoadValue) &Account) {
// Take the voter's ballot our of storage
let ballot <- voter.load<@ApprovalVoting.Ballot>(
let ballot <- voter.storage.load<@ApprovalVoting.Ballot>(
from: /storage/Ballot
)!

Expand Down
4 changes: 2 additions & 2 deletions transactions/initialize_proposals.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import ApprovalVoting from "../contracts/ApprovalVoting.cdc"
// to create new proposals for voting and save them to the smart contract.
transaction(proposals: [String]) {
prepare(admin: AuthAccount) {
prepare(admin: auth(BorrowValue) &Account) {
// Borrow a reference to the admin Resource.
let adminRef = admin.borrow<&ApprovalVoting.Administrator>(
let adminRef = admin.storage.borrow<&ApprovalVoting.Administrator>(
from: /storage/VotingAdmin
)!

Expand Down
Loading

0 comments on commit 3fc5c0c

Please sign in to comment.