From e283c81025951f4580f8aabe2ffd0ca200b3f8a6 Mon Sep 17 00:00:00 2001 From: Austin Kline Date: Fri, 15 Dec 2023 21:36:47 -0800 Subject: [PATCH] rename contract (#5) --- README.md | 6 +- ...ffleSources.cdc => FlowtyRaffleSource.cdc} | 6 +- contracts/{Raffles.cdc => FlowtyRaffles.cdc} | 64 ++++++++++++++++++- flow.json | 10 +-- scripts/borrow_manager.cdc | 4 +- scripts/get_num_raffle_entries.cdc | 4 +- scripts/get_raffle_details.cdc | 6 +- scripts/get_raffle_entries.cdc | 4 +- scripts/get_raffle_source_identifier.cdc | 4 +- ...fles_tests.cdc => FlowtyRaffles_tests.cdc} | 24 +++---- transactions/add_entries_to_raffle.cdc | 4 +- transactions/add_entry_to_raffle.cdc | 4 +- transactions/create_raffle.cdc | 16 ++--- transactions/create_raffle_source.cdc | 4 +- transactions/draw_from_raffle.cdc | 4 +- transactions/setup_manager.cdc | 8 +-- 16 files changed, 118 insertions(+), 54 deletions(-) rename contracts/{RaffleSources.cdc => FlowtyRaffleSource.cdc} (89%) rename contracts/{Raffles.cdc => FlowtyRaffles.cdc} (56%) rename test/{Raffles_tests.cdc => FlowtyRaffles_tests.cdc} (80%) diff --git a/README.md b/README.md index 6a90bfc..c17f2cf 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -# flow-raffle \ No newline at end of file +# Flowty Raffles + +This repo contains an implementation of on-chain raffles on the [Flow Blockchain](https://developers.flow.com/). It makes use of +[on-chain randomness](https://developers.flow.com/build/advanced-concepts/randomness) and an array to select a random item and output it as an +event for everyone to see, making the outcome of a drawing verifiable for anyone to see. \ No newline at end of file diff --git a/contracts/RaffleSources.cdc b/contracts/FlowtyRaffleSource.cdc similarity index 89% rename from contracts/RaffleSources.cdc rename to contracts/FlowtyRaffleSource.cdc index 6db27b3..b7d682e 100644 --- a/contracts/RaffleSources.cdc +++ b/contracts/FlowtyRaffleSource.cdc @@ -1,7 +1,7 @@ -import "Raffles" +import "FlowtyRaffles" -pub contract RaffleSources { - pub resource GenericRaffleSource: Raffles.RaffleSource { +pub contract FlowtyRaffleSource { + pub resource GenericRaffleSource: FlowtyRaffles.RaffleSource { pub let entries: [AnyStruct] pub let entryType: Type diff --git a/contracts/Raffles.cdc b/contracts/FlowtyRaffles.cdc similarity index 56% rename from contracts/Raffles.cdc rename to contracts/FlowtyRaffles.cdc index d7f3eb7..c0f7bd1 100644 --- a/contracts/Raffles.cdc +++ b/contracts/FlowtyRaffles.cdc @@ -1,12 +1,33 @@ import "MetadataViews" -pub contract Raffles { +/* +FlowtyRaffles - The main contract which contains a definition for: + +1. Raffles - A resource which encapsulates an ongoing raffle +2. RaffleSource - A resource interface which specified how a raffle will attempt to select a winner +3. Manager - A container resource for raffles to be stored in + +The Raffles resource takes no view on what kind of item should be randomly drawn. Because of that, there is no +mechanism to distribute prizes when a drawing is made. This is intentional, and is meant to separate the act of +drawing an item from a raffle source, and sending it so that there are no restrictions on what kind of item might +need to be randomly drawn. + +For example, a raffle could be made which draws a random post from a social media platform. In that case, only the +post itself needs to be randomly drawn. Action based on that drawing would likely need to be done separately. + +Similarly one could make a raffle which distributes prizes in real-time by drawing a winner and then could: + +1. Distribute the prize in a second operation in the same transaction +2. Send the item to lost and found for the winner to redeem (https://github.com/Flowtyio/lost-and-found) +*/ +pub contract FlowtyRaffles { pub let ManagerStoragePath: StoragePath pub let ManagerPublicPath: PublicPath pub event RaffleCreated(address: Address?, raffleID: UInt64, sourceType: Type) pub event RaffleDrawn(address: Address?, raffleID: UInt64, sourceType: Type, index: Int, value: String, valueType: Type) + // Details - Info about the raffle. This currently includes when the raffle starts, ends, and how to display it. pub struct Details { pub let start: UInt64? pub let end: UInt64? @@ -24,6 +45,9 @@ pub contract Raffles { } } + // DrawingSelection - Returned when a raffle is drawn from. We will return the index that was selected and the + // value underneath it. This should assist with letting anyone using raffles to take action on them in the same transaction + // without the raffle itself needing to worry about those details. pub struct DrawingSelection { pub let index: Int pub let value: AnyStruct @@ -35,22 +59,58 @@ pub contract Raffles { } pub resource interface RafflePublic { + // Return the value of a raffle source at a given index pub fun getEntryAt(index: Int): AnyStruct + + // Return the details associated with this raffle pub fun getDetails(): Details + + // Return the number of entries in this raffle pub fun getNumEntries(): Int + + // Return all entries in this raffle + // NOTE: If there are too many entries in a raffle, this method will exceed computation limits pub fun getEntries(): [AnyStruct] + + // Draws a random item from the RaffleSource and returns the index that was selected along with the + // value of the item underneath. pub fun draw(): DrawingSelection } pub resource interface RaffleSource { + // Should return the entry of a raffle source at a given index. + // NOTE: There is no way to enforce this on this contract, whatever RaffleSource resource + // implementation you use, make sure you trust how it performs its drawing pub fun getEntryAt(index: Int): AnyStruct + + // Adds an entry to this RaffleSource resource + // NOTE: Some raffle sources might not permit this action. For instance, using a FLOAT + // as a raffle source would mean the only way to add an entry is to mint the FLOAT + // a raffle corresponds to pub fun addEntry(_ v: AnyStruct) + + // Adds many entries at once to a given raffle source. + // NOTE: Some raffle sources might not permit this action. For instance, using a FLOAT + // as a raffle source would mean the only way to add an entry is to mint the FLOAT + // a raffle corresponds to pub fun addEntries(_ v: [AnyStruct]) + + // Should return the number of entries on a RaffleSource resource. + // NOTE: There is no way to enforce this on this contract, whatever RaffleSource resource + // implementation you use, make sure you trust how it performs its drawing pub fun getNumEntries(): Int + + // Should return all entries in a RaffleSource resource + // NOTE: There is no way to enforce this on this contract, whatever RaffleSource resource + // implementation you use, make sure you trust how it performs its drawing pub fun getEntries(): [AnyStruct] } pub resource Raffle: RafflePublic, MetadataViews.Resolver { + // The source for drawing winners in a raffle. Anyone can implement their own version of a RaffleSource, + // or they can use the GenericRaffleSource implementation found in FlowtyRaffleSource which can handle any + // primitive type found in cadence documentation here: + // pub let source: @{RaffleSource} pub let details: Details @@ -72,7 +132,7 @@ pub contract Raffles { let index = Int(r % UInt64(numEntries)) let value = self.source.getEntryAt(index: index) - Raffles.emitDrawing(self.owner?.address, self.uuid, self.source.getType(), index, value) + FlowtyRaffles.emitDrawing(self.owner?.address, self.uuid, self.source.getType(), index, value) return DrawingSelection(index, value) } diff --git a/flow.json b/flow.json index 24d7a7f..174fa74 100644 --- a/flow.json +++ b/flow.json @@ -20,14 +20,14 @@ } }, "contracts": { - "Raffles": { - "source": "./contracts/Raffles.cdc", + "FlowtyRaffles": { + "source": "./contracts/FlowtyRaffles.cdc", "aliases": { "testing": "0x0000000000000007" } }, - "RaffleSources": { - "source": "./contracts/RaffleSources.cdc", + "FlowtyRaffleSource": { + "source": "./contracts/FlowtyRaffleSource.cdc", "aliases": { "testing": "0x0000000000000008" } @@ -105,7 +105,7 @@ "MetadataViews", "ViewResolver", "NonFungibleToken", - "Raffles" + "FlowtyRaffles" ], "emulator-ft": [ "FungibleToken", diff --git a/scripts/borrow_manager.cdc b/scripts/borrow_manager.cdc index 9ed79c8..43b013a 100644 --- a/scripts/borrow_manager.cdc +++ b/scripts/borrow_manager.cdc @@ -1,6 +1,6 @@ -import "Raffles" +import "FlowtyRaffles" pub fun main(addr: Address) { - getAccount(addr).getCapability<&Raffles.Manager{Raffles.ManagerPublic}>(Raffles.ManagerPublicPath).borrow() + getAccount(addr).getCapability<&FlowtyRaffles.Manager{FlowtyRaffles.ManagerPublic}>(FlowtyRaffles.ManagerPublicPath).borrow() ?? panic("unable to borrow manager") } \ No newline at end of file diff --git a/scripts/get_num_raffle_entries.cdc b/scripts/get_num_raffle_entries.cdc index f62f129..636fcd4 100644 --- a/scripts/get_num_raffle_entries.cdc +++ b/scripts/get_num_raffle_entries.cdc @@ -1,8 +1,8 @@ -import "Raffles" +import "FlowtyRaffles" pub fun main(addr: Address, id: UInt64): Int { let acct = getAuthAccount(addr) - let manager = acct.borrow<&Raffles.Manager{Raffles.ManagerPublic}>(from: Raffles.ManagerStoragePath) + let manager = acct.borrow<&FlowtyRaffles.Manager{FlowtyRaffles.ManagerPublic}>(from: FlowtyRaffles.ManagerStoragePath) ?? panic("raffles manager not found") let raffle = manager.borrowRafflePublic(id: id) ?? panic("raffle not found") diff --git a/scripts/get_raffle_details.cdc b/scripts/get_raffle_details.cdc index 6a828a5..43eccb9 100644 --- a/scripts/get_raffle_details.cdc +++ b/scripts/get_raffle_details.cdc @@ -1,8 +1,8 @@ -import "Raffles" +import "FlowtyRaffles" -pub fun main(addr: Address, id: UInt64): Raffles.Details? { +pub fun main(addr: Address, id: UInt64): FlowtyRaffles.Details? { let acct = getAuthAccount(addr) - let manager = acct.borrow<&Raffles.Manager>(from: Raffles.ManagerStoragePath) + let manager = acct.borrow<&FlowtyRaffles.Manager>(from: FlowtyRaffles.ManagerStoragePath) ?? panic("raffles manager not found") if let raffle = manager.borrowRafflePublic(id: id) { diff --git a/scripts/get_raffle_entries.cdc b/scripts/get_raffle_entries.cdc index 4f3218a..50301fc 100644 --- a/scripts/get_raffle_entries.cdc +++ b/scripts/get_raffle_entries.cdc @@ -1,8 +1,8 @@ -import "Raffles" +import "FlowtyRaffles" pub fun main(addr: Address, id: UInt64): [AnyStruct] { let acct = getAuthAccount(addr) - let manager = acct.borrow<&Raffles.Manager{Raffles.ManagerPublic}>(from: Raffles.ManagerStoragePath) + let manager = acct.borrow<&FlowtyRaffles.Manager{FlowtyRaffles.ManagerPublic}>(from: FlowtyRaffles.ManagerStoragePath) ?? panic("raffles manager not found") let raffle = manager.borrowRafflePublic(id: id) ?? panic("raffle not found") diff --git a/scripts/get_raffle_source_identifier.cdc b/scripts/get_raffle_source_identifier.cdc index ea4f349..63a0fb6 100644 --- a/scripts/get_raffle_source_identifier.cdc +++ b/scripts/get_raffle_source_identifier.cdc @@ -1,7 +1,7 @@ -import "Raffles" +import "FlowtyRaffles" pub fun main(addr: Address, path: StoragePath): String { let acct = getAuthAccount(addr) - let source = acct.borrow<&{Raffles.RaffleSource}>(from: path) + let source = acct.borrow<&{FlowtyRaffles.RaffleSource}>(from: path) return source!.getType().identifier } \ No newline at end of file diff --git a/test/Raffles_tests.cdc b/test/FlowtyRaffles_tests.cdc similarity index 80% rename from test/Raffles_tests.cdc rename to test/FlowtyRaffles_tests.cdc index 32eaa13..a21e7d5 100644 --- a/test/Raffles_tests.cdc +++ b/test/FlowtyRaffles_tests.cdc @@ -1,20 +1,20 @@ import Test import "test_helpers.cdc" -import "Raffles" -import "RaffleSources" +import "FlowtyRaffles" +import "FlowtyRaffleSource" import "MetadataViews" -pub let RafflesContractAddress = Address(0x0000000000000007) -pub let RaffleSourcesContractAddress = Address(0x0000000000000008) +pub let FlowtyRafflesContractAddress = Address(0x0000000000000007) +pub let FlowtyRaffleSourceContractAddress = Address(0x0000000000000008) -pub let GenericRaffleSourceIdentifier = "A.0000000000000008.RaffleSources.GenericRaffleSource" +pub let GenericRaffleSourceIdentifier = "A.0000000000000008.FlowtyRaffleSource.GenericRaffleSource" pub fun setup() { - var err = Test.deployContract(name: "Raffles", path: "../contracts/Raffles.cdc", arguments: []) + var err = Test.deployContract(name: "FlowtyRaffles", path: "../contracts/FlowtyRaffles.cdc", arguments: []) Test.expect(err, Test.beNil()) - err = Test.deployContract(name: "RaffleSources", path: "../contracts/RaffleSources.cdc", arguments: []) + err = Test.deployContract(name: "FlowtyRaffleSource", path: "../contracts/FlowtyRaffleSource.cdc", arguments: []) Test.expect(err, Test.beNil()) } @@ -41,7 +41,7 @@ pub fun testCreateRaffle() { let end: UInt64? = nil txExecutor("create_raffle.cdc", [acct], [Type
(), start, end, name, description, thumbnail], nil) - let createEvent = (Test.eventsOfType(Type()).removeLast() as! Raffles.RaffleCreated) + let createEvent = (Test.eventsOfType(Type()).removeLast() as! FlowtyRaffles.RaffleCreated) assert(acct.address == createEvent.address) let details = getRaffleDetails(acct, createEvent.raffleID) ?? panic("raffle not found") @@ -93,9 +93,9 @@ pub fun testDrawFromRaffle() { assert(accounts[drawing2] != nil) } -pub fun getRaffleDetails(_ acct: Test.Account, _ id: UInt64): Raffles.Details? { +pub fun getRaffleDetails(_ acct: Test.Account, _ id: UInt64): FlowtyRaffles.Details? { if let res = scriptExecutor("get_raffle_details.cdc", [acct.address, id]) { - return res as! Raffles.Details + return res as! FlowtyRaffles.Details } return nil } @@ -130,13 +130,13 @@ pub fun createAddressRaffle(_ acct: Test.Account): UInt64 { let end: UInt64? = nil txExecutor("create_raffle.cdc", [acct], [Type
(), start, end, name, description, thumbnail], nil) - let createEvent = (Test.eventsOfType(Type()).removeLast() as! Raffles.RaffleCreated) + let createEvent = (Test.eventsOfType(Type()).removeLast() as! FlowtyRaffles.RaffleCreated) return createEvent.raffleID } pub fun drawFromRaffle(_ signer: Test.Account, _ addr: Address, _ id: UInt64): String { txExecutor("draw_from_raffle.cdc", [signer], [addr, id], nil) - let drawingEvent = Test.eventsOfType(Type()).removeLast() as! Raffles.RaffleDrawn + let drawingEvent = Test.eventsOfType(Type()).removeLast() as! FlowtyRaffles.RaffleDrawn return drawingEvent.value } \ No newline at end of file diff --git a/transactions/add_entries_to_raffle.cdc b/transactions/add_entries_to_raffle.cdc index cb17a3f..20270bd 100644 --- a/transactions/add_entries_to_raffle.cdc +++ b/transactions/add_entries_to_raffle.cdc @@ -1,8 +1,8 @@ -import "Raffles" +import "FlowtyRaffles" transaction(raffleID: UInt64, entries: [AnyStruct]) { prepare(acct: AuthAccount) { - let manager = acct.borrow<&Raffles.Manager>(from: Raffles.ManagerStoragePath) + let manager = acct.borrow<&FlowtyRaffles.Manager>(from: FlowtyRaffles.ManagerStoragePath) ?? panic("raffles manager not found") let raffle = manager.borrowRaffle(id: raffleID) ?? panic("raffle not found") diff --git a/transactions/add_entry_to_raffle.cdc b/transactions/add_entry_to_raffle.cdc index 85a5050..f928dcd 100644 --- a/transactions/add_entry_to_raffle.cdc +++ b/transactions/add_entry_to_raffle.cdc @@ -1,8 +1,8 @@ -import "Raffles" +import "FlowtyRaffles" transaction(raffleID: UInt64, entry: AnyStruct) { prepare(acct: AuthAccount) { - let manager = acct.borrow<&Raffles.Manager>(from: Raffles.ManagerStoragePath) + let manager = acct.borrow<&FlowtyRaffles.Manager>(from: FlowtyRaffles.ManagerStoragePath) ?? panic("raffles manager not found") let raffle = manager.borrowRaffle(id: raffleID) ?? panic("raffle not found") diff --git a/transactions/create_raffle.cdc b/transactions/create_raffle.cdc index 958bff6..5d9f0a1 100644 --- a/transactions/create_raffle.cdc +++ b/transactions/create_raffle.cdc @@ -1,17 +1,17 @@ -import "Raffles" -import "RaffleSources" +import "FlowtyRaffles" +import "FlowtyRaffleSource" import "MetadataViews" transaction(type: Type, start: UInt64?, end: UInt64?, name: String, description: String, thumbnail: String) { prepare(acct: AuthAccount) { - let source <- RaffleSources.createRaffleSource(type) + let source <- FlowtyRaffleSource.createRaffleSource(type) - if acct.borrow<&AnyResource>(from: Raffles.ManagerStoragePath) == nil { - acct.save(<-Raffles.createManager(), to: Raffles.ManagerStoragePath) - acct.link<&Raffles.Manager{Raffles.ManagerPublic}>(Raffles.ManagerPublicPath, target: Raffles.ManagerStoragePath) + if acct.borrow<&AnyResource>(from: FlowtyRaffles.ManagerStoragePath) == nil { + acct.save(<-FlowtyRaffles.createManager(), to: FlowtyRaffles.ManagerStoragePath) + acct.link<&FlowtyRaffles.Manager{FlowtyRaffles.ManagerPublic}>(FlowtyRaffles.ManagerPublicPath, target: FlowtyRaffles.ManagerStoragePath) } - let manager = acct.borrow<&Raffles.Manager>(from: Raffles.ManagerStoragePath) + let manager = acct.borrow<&FlowtyRaffles.Manager>(from: FlowtyRaffles.ManagerStoragePath) ?? panic("raffles manager not found") let display = MetadataViews.Display( @@ -19,7 +19,7 @@ transaction(type: Type, start: UInt64?, end: UInt64?, name: String, description: description: description, thumbnail: MetadataViews.HTTPFile(thumbnail) ) - let details = Raffles.Details(start, end, display) + let details = FlowtyRaffles.Details(start, end, display) let id = manager.createRaffle(source: <-source, details: details) // make sure you can borrow the raffle back diff --git a/transactions/create_raffle_source.cdc b/transactions/create_raffle_source.cdc index e7e431e..25aaafa 100644 --- a/transactions/create_raffle_source.cdc +++ b/transactions/create_raffle_source.cdc @@ -1,8 +1,8 @@ -import "RaffleSources" +import "FlowtyRaffleSource" transaction(type: Type, path: StoragePath) { prepare(acct: AuthAccount) { - let source <- RaffleSources.createRaffleSource(type) + let source <- FlowtyRaffleSource.createRaffleSource(type) let t = source.getEntryType() assert(t == type) diff --git a/transactions/draw_from_raffle.cdc b/transactions/draw_from_raffle.cdc index 3725c04..516725d 100644 --- a/transactions/draw_from_raffle.cdc +++ b/transactions/draw_from_raffle.cdc @@ -1,9 +1,9 @@ -import "Raffles" +import "FlowtyRaffles" transaction(addr: Address, id: UInt64) { prepare(acct: AuthAccount) { } execute { - let manager = getAccount(addr).getCapability<&Raffles.Manager{Raffles.ManagerPublic}>(Raffles.ManagerPublicPath).borrow() + let manager = getAccount(addr).getCapability<&FlowtyRaffles.Manager{FlowtyRaffles.ManagerPublic}>(FlowtyRaffles.ManagerPublicPath).borrow() ?? panic("raffles manager not found") let raffle = manager.borrowRafflePublic(id: id) ?? panic("raffle not found") diff --git a/transactions/setup_manager.cdc b/transactions/setup_manager.cdc index 93371a8..75227ac 100644 --- a/transactions/setup_manager.cdc +++ b/transactions/setup_manager.cdc @@ -1,9 +1,9 @@ -import "Raffles" +import "FlowtyRaffles" transaction { prepare(acct: AuthAccount) { - let manager <- Raffles.createManager() - acct.save(<-manager, to: Raffles.ManagerStoragePath) - acct.link<&Raffles.Manager{Raffles.ManagerPublic}>(Raffles.ManagerPublicPath, target: Raffles.ManagerStoragePath) + let manager <- FlowtyRaffles.createManager() + acct.save(<-manager, to: FlowtyRaffles.ManagerStoragePath) + acct.link<&FlowtyRaffles.Manager{FlowtyRaffles.ManagerPublic}>(FlowtyRaffles.ManagerPublicPath, target: FlowtyRaffles.ManagerStoragePath) } } \ No newline at end of file