-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add remix #163
Merged
jrkhan
merged 25 commits into
dapperlabs:feature/add-subeditions
from
dapperlabs:feat/add-remix
Oct 27, 2022
Merged
Add remix #163
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
e2a65c4
add remix to contracts
anatoly256 d2c0c2c
add remix to transactions
anatoly256 0b57345
add remix to lib
anatoly256 2db2330
fix misprints
anatoly256 8eb6e28
add function to get moment's subedition
anatoly256 e256ec1
fix tests
anatoly256 a7c0307
fix tests
anatoly256 b3b30f7
refactor subEdition contract
anatoly256 41ba825
add subEdition tests
anatoly256 657413b
add new function to create subEdition resource
anatoly256 1b424e7
add documentation
anatoly256 959fc59
refactor SubeditionAdmin
anatoly256 cfbfb6d
add comments/transactions/tests
anatoly256 fb19870
add events
anatoly256 9452a2d
Revert spacings
anatoly256 c0aa841
Merge branch 'master' into feat/add-remix
anatoly256 247a860
Fix comments
anatoly256 5144246
use test abstractions in subedition_test.go
anatoly256 4cbdd70
fix comments
anatoly256 9e0735c
fix comments
anatoly256 7947542
add comment to SubeditionAdminStoragePath()
anatoly256 ab6f9c3
add subeditionId to MomentMinted event
anatoly256 71beb97
change SubeditionCreated event/add length check to MintMoment event
anatoly256 6472f17
change subeditionID to subeditionId
anatoly256 48ba382
Merge branch 'master' into feat/add-remix
anatoly256 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,6 +84,10 @@ pub contract TopShot: NonFungibleToken { | |
// Emitted when a Moment is destroyed | ||
pub event MomentDestroyed(id: UInt64) | ||
|
||
pub event SubeditionCreated(id: UInt32, name: String, metadata: {String:String}) | ||
|
||
pub event SubeditionAddedToMoment(momentID: UInt64, subeditionID: UInt32) | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// ----------------------------------------------------------------------- | ||
// TopShot contract-level fields. | ||
// These contain actual values that are stored in the smart contract. | ||
|
@@ -380,6 +384,70 @@ pub contract TopShot: NonFungibleToken { | |
return <-newCollection | ||
} | ||
|
||
// mintMomentWithSubedition mints a new Moment with subedition and returns the newly minted Moment | ||
// | ||
// Parameters: playID: The ID of the Play that the Moment references | ||
// subeditionID: The ID of the subedition within Edition that the Moment references | ||
// | ||
// Pre-Conditions: | ||
// The Play must exist in the Set and be allowed to mint new Moments | ||
// | ||
// Returns: The NFT that was minted | ||
// | ||
pub fun mintMomentWithSubedition(playID: UInt32, subeditionID: UInt32): @NFT { | ||
pre { | ||
self.retired[playID] != nil: "Cannot mint the moment: This play doesn't exist." | ||
!self.retired[playID]!: "Cannot mint the moment from this play: This play has been retired." | ||
} | ||
|
||
// Gets the number of Moments that have been minted for this subedition | ||
// to use as this Moment's serial number | ||
let subeditionRef = TopShot.account.borrow<&SubeditionAdmin>(from: /storage/TopShotSubeditionAdmin) | ||
?? panic("No subedition admin resource in storage") | ||
|
||
let numInSubedition = subeditionRef.getNumberMintedPerSubedition(setID: self.setID, | ||
playID: playID, | ||
subeditionID: subeditionID) | ||
|
||
// Mint the new moment | ||
let newMoment: @NFT <- create NFT(serialNumber: numInSubedition + UInt32(1), | ||
playID: playID, | ||
setID: self.setID) | ||
|
||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Increment the count of Moments minted for this subedition | ||
subeditionRef.addToNumberMintedPerSubedition(setID: self.setID, | ||
playID: playID, | ||
subeditionID: subeditionID) | ||
|
||
subeditionRef.setMomentsSubedition(nftID: newMoment.id, subeditionID: subeditionID) | ||
|
||
self.numberMintedPerPlay[playID] = self.numberMintedPerPlay[playID]! + UInt32(1) | ||
|
||
return <-newMoment | ||
} | ||
|
||
// batchMintMomentWithSubedition mints an arbitrary quantity of Moments with subedition | ||
// and returns them as a Collection | ||
// | ||
// Parameters: playID: the ID of the Play that the Moments are minted for | ||
// quantity: The quantity of Moments to be minted | ||
// subeditionID: The ID of the subedition within Edition that the Moments references | ||
// | ||
// Returns: Collection object that contains all the Moments that were minted | ||
// | ||
pub fun batchMintMomentWithSubedition(playID: UInt32, quantity: UInt64, subeditionID: UInt32): @Collection { | ||
let newCollection <- create Collection() | ||
|
||
var i: UInt64 = 0 | ||
while i < quantity { | ||
newCollection.deposit(token: <-self.mintMomentWithSubedition(playID: playID, | ||
subeditionID: subeditionID)) | ||
i = i + UInt64(1) | ||
} | ||
|
||
return <-newCollection | ||
} | ||
|
||
pub fun getPlays(): [UInt32] { | ||
return self.plays | ||
} | ||
|
@@ -750,6 +818,26 @@ pub contract TopShot: NonFungibleToken { | |
return TopShot.currentSeries | ||
} | ||
|
||
// createSubeditionResource creates new SubeditionMap resource that | ||
// will be used to mint Moments with Subeditions | ||
pub fun createSubeditionAdminResource() { | ||
TopShot.account.save<@SubeditionAdmin>(<- create SubeditionAdmin(), to: /storage/TopShotSubeditionAdmin) | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
pub fun setMomentsSubedition(nftID: UInt64, subeditionID: UInt32) { | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let subeditionAdmin = TopShot.account.borrow<&SubeditionAdmin>(from: /storage/TopShotSubeditionAdmin) | ||
?? panic("No subedition admin resource in storage") | ||
|
||
subeditionAdmin.setMomentsSubedition(nftID: nftID, subeditionID: subeditionID) | ||
} | ||
|
||
pub fun createSubedition(name:String, metadata:{String:String}): UInt32 { | ||
let subeditionAdmin = TopShot.account.borrow<&SubeditionAdmin>(from: /storage/TopShotSubeditionAdmin) | ||
?? panic("No subedition admin resource in storage") | ||
|
||
return subeditionAdmin.createSubedition(name:name, metadata:metadata) | ||
} | ||
|
||
// createNewAdmin creates a new Admin resource | ||
// | ||
pub fun createNewAdmin(): @Admin { | ||
|
@@ -1152,6 +1240,185 @@ pub contract TopShot: NonFungibleToken { | |
} | ||
} | ||
|
||
// getMomentsSubedition function that return's wich Subedition the Moment belongs to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
// | ||
// Parameters: nftID: The ID of the NFT | ||
// | ||
// returns: UInt32? Subedition's ID if exists | ||
// | ||
pub fun getMomentsSubedition(nftID: UInt64):UInt32? { | ||
let subeditionAdmin = self.account.borrow<&SubeditionAdmin>(from: /storage/TopShotSubeditionAdmin) | ||
?? panic("No subedition admin resource in storage") | ||
|
||
return subeditionAdmin.getMomentsSubedition(nftID: nftID) | ||
} | ||
|
||
// getAllSubeditions returns all the subeditions in topshot subeditionAdmin resource | ||
// | ||
// Returns: An array of all the subeditions that have been created | ||
pub fun getAllSubeditions():[TopShot.Subedition] { | ||
let subeditionAdmin = self.account.borrow<&SubeditionAdmin>(from: /storage/TopShotSubeditionAdmin) | ||
?? panic("No subedition admin resource in storage") | ||
return subeditionAdmin.subeditionDatas.values | ||
} | ||
|
||
// getSubeditionByID returns the subedition struct entity | ||
// | ||
// Parameters: subeditionID: The id of the Subedition that is being searched | ||
// | ||
// Returns: The Subedition struct | ||
pub fun getSubeditionByID(subeditionID: UInt32):TopShot.Subedition { | ||
let subeditionAdmin = self.account.borrow<&SubeditionAdmin>(from: /storage/TopShotSubeditionAdmin) | ||
?? panic("No subedition admin resource in storage") | ||
return subeditionAdmin.subeditionDatas[subeditionID]! | ||
} | ||
|
||
// This script reads the public nextSubeditionID from the SubeditionAdmin resource and | ||
// returns that number to the caller | ||
// | ||
// Returns: UInt32 | ||
// the next number in nextSubeditionID from the SubeditionAdmin resource | ||
pub fun getNextSubeditionID():UInt32 { | ||
let subeditionAdmin = self.account.borrow<&SubeditionAdmin>(from: /storage/TopShotSubeditionAdmin) | ||
?? panic("No subedition admin resource in storage") | ||
return subeditionAdmin.nextSubeditionID | ||
} | ||
// SubeditionAdmin is a resource that allows Set to mint Moments with Subeditions | ||
// | ||
pub struct Subedition { | ||
pub let subeditionID: UInt32 | ||
|
||
pub let name: String | ||
|
||
pub let metadata: {String: String} | ||
|
||
init(subeditionID: UInt32, name: String, metadata: {String: String}) { | ||
pre { | ||
name.length != 0: "New Subedition name cannot be empty" | ||
metadata.length != 0: "New Subedition metadata cannot be empty" | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
self.subeditionID = subeditionID | ||
self.name = name | ||
self.metadata = metadata | ||
} | ||
} | ||
|
||
pub resource SubeditionAdmin { | ||
|
||
// Map of number of already minted Moments using Subedition. | ||
// When a new Moment with Subedition is minted, 1 is added to the | ||
// number in this map by the key, formed by concatinating of | ||
// SetID, PlayID and SubeditionID | ||
access(contract) var numberMintedPerSubedition: {String:UInt32} | ||
|
||
//Map of Subedition which the Moment belongs to. | ||
//This map updates after each minting. | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
access(contract) var momentsSubedition: {UInt64:UInt32} | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// The ID that is used to create Subeditions. | ||
// Every time a Subeditions is created, subeditionID is assigned | ||
// to the new Subedition's ID and then is incremented by 1. | ||
access(contract) var nextSubeditionID: UInt32 | ||
|
||
// Variable size dictionary of Subedition structs | ||
access(contract) var subeditionDatas: {UInt32: Subedition} | ||
|
||
// createSubedition creates a new Subedition struct | ||
// and stores it in the Subeditions dictionary in the SubeditionAdmin resource | ||
// | ||
// Parameters: name: The name of the Subedition | ||
// metadata: A dictionary mapping metadata titles to their data | ||
// | ||
// Returns: the ID of the new Subedition object | ||
// | ||
pub fun createSubedition(name:String, metadata:{String:String}): UInt32 { | ||
|
||
let newID = self.nextSubeditionID | ||
|
||
var newSubedition = Subedition(subeditionID: newID, name: name, metadata: metadata) | ||
|
||
self.nextSubeditionID = self.nextSubeditionID + UInt32(1) | ||
|
||
emit SubeditionCreated(id: newID, name: name, metadata: metadata) | ||
|
||
self.subeditionDatas[newID] = newSubedition | ||
|
||
emit SubeditionCreated(id: newID, name: name, metadata: metadata) | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return newID | ||
} | ||
|
||
// getMomentsSubedition function that return's wich Subedition the Moment belongs to | ||
// | ||
// Parameters: nftID: The ID of the NFT | ||
// | ||
// returns: UInt32? Subedition's ID if exists | ||
// | ||
pub fun getMomentsSubedition( nftID: UInt64):UInt32? { | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return self.momentsSubedition[nftID] | ||
} | ||
|
||
// getNumberMintedPerSubedition function that return's | ||
// the number of Moments that have been minted for this subedition | ||
// to use as this Moment's serial number | ||
// | ||
// Parameters: setID: The ID of the Set Moment will be minted from | ||
// playID: The ID of the Play Moment will be minted from | ||
// subeditionID: The ID of the Subedition using which moment will be minted | ||
// | ||
// returns: UInt32 Number of Moments, already minted for this Subedition | ||
// | ||
pub fun getNumberMintedPerSubedition(setID: UInt32, playID: UInt32, subeditionID: UInt32): UInt32 { | ||
let setPlaySubedition = setID.toString().concat(playID.toString()).concat(subeditionID.toString()) | ||
if !self.numberMintedPerSubedition.containsKey(setPlaySubedition) { | ||
self.numberMintedPerSubedition.insert(key: setPlaySubedition,UInt32(0)) | ||
return UInt32(0) | ||
} | ||
return self.numberMintedPerSubedition[setPlaySubedition]! | ||
} | ||
|
||
// addToNumberMintedPerSubedition function that increments 1 to the | ||
// number of Moments that have been minted for this subedition | ||
// | ||
// Parameters: setID: The ID of the Set Moment will be minted from | ||
// playID: The ID of the Play Moment will be minted from | ||
// subeditionID: The ID of the Subedition using which moment will be minted | ||
// | ||
// | ||
pub fun addToNumberMintedPerSubedition(setID: UInt32, playID: UInt32, subeditionID: UInt32) { | ||
let setPlaySubedition = setID.toString().concat(playID.toString()).concat(subeditionID.toString()) | ||
|
||
if self.numberMintedPerSubedition.containsKey(setPlaySubedition) { | ||
self.numberMintedPerSubedition[setPlaySubedition]!= self.numberMintedPerSubedition[setPlaySubedition]! + UInt32(1) | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else { | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
panic("Could not find specified Subedition!") | ||
} | ||
} | ||
|
||
|
||
// setMomentsSubedition function that saves which Subedition the Moment belongs to | ||
// | ||
// Parameters: nftID: The ID of the NFT | ||
// subeditionID: The ID of the Subedition the Moment belongs to | ||
// | ||
pub fun setMomentsSubedition(nftID: UInt64, subeditionID: UInt32){ | ||
if self.momentsSubedition.containsKey(nftID) { | ||
jrkhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
panic("Subedition for this moment already exists!") | ||
} | ||
self.momentsSubedition.insert(key: nftID, subeditionID) | ||
|
||
emit SubeditionAddedToMoment(momentID: nftID, subeditionID: subeditionID) | ||
} | ||
|
||
init() { | ||
self.momentsSubedition = {} | ||
self.numberMintedPerSubedition = {} | ||
self.subeditionDatas = {} | ||
self.nextSubeditionID = 1 | ||
} | ||
} | ||
|
||
|
||
// ----------------------------------------------------------------------- | ||
// TopShot initialization function | ||
// ----------------------------------------------------------------------- | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package events | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/onflow/cadence" | ||
jsoncdc "github.com/onflow/cadence/encoding/json" | ||
) | ||
|
||
var ( | ||
EventSubeditionCreated = "TopShot.SubeditionCreated" | ||
) | ||
|
||
type SubeditionCreatedEvent interface { | ||
Id() uint32 | ||
Name() string | ||
MetaData() map[interface{}]interface{} | ||
} | ||
|
||
type subeditionCreatedEvent cadence.Event | ||
|
||
func (evt subeditionCreatedEvent) Id() uint32 { | ||
return evt.Fields[0].(cadence.UInt32).ToGoValue().(uint32) | ||
} | ||
|
||
func (evt subeditionCreatedEvent) Name() string { | ||
return evt.Fields[1].(cadence.String).ToGoValue().(string) | ||
} | ||
|
||
func (evt subeditionCreatedEvent) MetaData() map[interface{}]interface{} { | ||
return evt.Fields[2].(cadence.Dictionary).ToGoValue().(map[interface{}]interface{}) | ||
} | ||
|
||
func (evt subeditionCreatedEvent) validate() error { | ||
if evt.EventType.QualifiedIdentifier != EventSubeditionCreated { | ||
return fmt.Errorf("error validating event: event is not a valid subedition created event, expected type %s, got %s", | ||
EventSubeditionCreated, evt.EventType.QualifiedIdentifier) | ||
} | ||
return nil | ||
} | ||
|
||
func DecodeSubeditionCreatedEvent(b []byte) (SubeditionCreatedEvent, error) { | ||
value, err := jsoncdc.Decode(nil, b) | ||
if err != nil { | ||
return nil, err | ||
} | ||
event := subeditionCreatedEvent(value.(cadence.Event)) | ||
if err := event.validate(); err != nil { | ||
return nil, fmt.Errorf("error decoding event: %w", err) | ||
} | ||
return event, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package events | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/onflow/cadence" | ||
jsoncdc "github.com/onflow/cadence/encoding/json" | ||
) | ||
|
||
var ( | ||
EventSubeditionAddedToMoment = "TopShot.SubeditionAddedToMoment" | ||
) | ||
|
||
type SubeditionAddedToMomentEvent interface { | ||
MomentID() uint64 | ||
SubeditionID() uint32 | ||
} | ||
|
||
type subeditionAddedToMomentEvent cadence.Event | ||
|
||
func (evt subeditionAddedToMomentEvent) MomentID() uint64 { | ||
return evt.Fields[0].(cadence.UInt64).ToGoValue().(uint64) | ||
} | ||
|
||
func (evt subeditionAddedToMomentEvent) SubeditionID() uint32 { | ||
return evt.Fields[1].(cadence.UInt32).ToGoValue().(uint32) | ||
} | ||
|
||
func (evt subeditionAddedToMomentEvent) validate() error { | ||
if evt.EventType.QualifiedIdentifier != EventSubeditionAddedToMoment { | ||
return fmt.Errorf("error validating event: event is not a valid subedition added to moment event, expected type %s, got %s", | ||
EventSubeditionAddedToMoment, evt.EventType.QualifiedIdentifier) | ||
} | ||
return nil | ||
} | ||
|
||
func DecodeSubeditionAddedToMomentEvent(b []byte) (SubeditionAddedToMomentEvent, error) { | ||
value, err := jsoncdc.Decode(nil, b) | ||
if err != nil { | ||
return nil, err | ||
} | ||
event := subeditionAddedToMomentEvent(value.(cadence.Event)) | ||
if err := event.validate(); err != nil { | ||
return nil, fmt.Errorf("error decoding event: %w", err) | ||
} | ||
return event, nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't clear to me what the ID represents, considering you use
subeditionID
in the next event. Does it represent the subedition ID? Shouldn't we also have the play and set IDs in the event?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with consistent/more specific name for id.
In the current iteration, the subedition is intended to be reused across many sets/plays. (This will make it much easier to search for all 'diamond' moments if they share an id) -> so subedition created event will not have a set/play as the subedition itself does not have a set/play.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.