diff --git a/.env b/.env new file mode 100644 index 00000000..8f17f1b2 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +TESTNET_ACCOUNT='98ebfd2fa655cea228bd307e0e838cf3bdf08f8dde0b9baa6054c54b462b3acc' +MAINNET_FIND='98ebfd2fa655cea228bd307e0e838cf3bdf08f8dde0b9baa6054c54b462b3acc' +MAINNET_FIND_ADMIN='98ebfd2fa655cea228bd307e0e838cf3bdf08f8dde0b9baa6054c54b462b3acc' diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ef1d86be..c5e9fb08 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,17 +2,18 @@ on: push: branches: - main + - feat/stable-cadence name: ci jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v3 - with: - go-version: 1.18 - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.22" - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: @@ -21,21 +22,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: 1.18 - - uses: actions/cache@v2 + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: - path: | - ~/go/pkg/mod - ~/.cache/go-build - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + go-version: "1.22" - uses: zencargo/github-action-go-mod-tidy@v1 with: - go-version: 1.18 + go-version: "1.22" test: runs-on: ubuntu-latest @@ -46,18 +39,10 @@ jobs: MAINNET_FIND_ADMIN: "98ebfd2fa655cea228bd307e0e838cf3bdf08f8dde0b9baa6054c54b462b3acc" steps: - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: - go-version: 1.18 - - uses: actions/cache@v3 - with: - path: | - ~/go/pkg/mod - ~/.cache/go-build - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + go-version: "1.22" - name: run tests run: go test -timeout 30m -json ./... > test.json - name: Annotate tests @@ -65,4 +50,3 @@ jobs: uses: guyarb/golang-test-annotations@v0.5.0 with: test-results: test.json - diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 8bfd1d38..2ccc3964 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -1,42 +1,34 @@ on: - pull_request: + pull_request: branches: - - main + - feat/stable-cadence + - main name: pr jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v3 - with: - go-version: 1.18 - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: "1.22" - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: args: --timeout=3m - tidy: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: - go-version: 1.18 - - uses: actions/cache@v2 - with: - path: | - ~/go/pkg/mod - ~/.cache/go-build - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + go-version: "1.22" - uses: zencargo/github-action-go-mod-tidy@v1 with: - go-version: 1.18 + go-version: "1.22" test: runs-on: ubuntu-latest @@ -47,18 +39,10 @@ jobs: MAINNET_FIND_ADMIN: "98ebfd2fa655cea228bd307e0e838cf3bdf08f8dde0b9baa6054c54b462b3acc" steps: - name: Checkout code - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: 1.18 - - uses: actions/cache@v2 + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: - path: | - ~/go/pkg/mod - ~/.cache/go-build - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + go-version: "1.22" - name: run tests run: go test -timeout 30m -json ./... > test.json - name: Annotate tests diff --git a/.vscode/settings.json b/.vscode/settings.json index f9c3635d..b1b7e768 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "files.insertFinalNewline": true + "files.insertFinalNewline": true, + "cadence.flowCommand": "flow" } diff --git a/LICENSE b/LICENSE index 783ee012..d23602cf 100644 --- a/LICENSE +++ b/LICENSE @@ -5,7 +5,7 @@ Copyright (c) 2021 Find On FLow Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +to use, copy, modify, merge, access(all)lish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/Makefile b/Makefile index d85804d1..f1b441c4 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ emulator: flow emulator -v test: - gotessum -f testname + gotestsum -f testname dev: gotestsum -f testname --watch diff --git a/Overview.md b/Overview.md index d7ffc6d1..8187207b 100644 --- a/Overview.md +++ b/Overview.md @@ -1,31 +1,33 @@ # .find +TODO: we need to go through this + .find is a solution that aims to make it easier to .find people and their things on the flow blockchain. It is live on mainnet since Dec 13th 2021 at https://find.xyz If you have questions implementing .find services, please reach out to any of us in discord.gg/findonflow # Product.find - - Name Services - - Assets Browser - - Marketplace - - Launchpad - - Find Thoughts +- Name Services +- Assets Browser +- Marketplace +- Launchpad +- Find Thoughts Find out more by surfing find.xyz # Infrastructures.find - - Name services - - Asset Management - - Onchain Identity - - Profile - - Related Accounts - - Marketplace - - NFT Batch Minter - - NFT Pack - - Community Tools Wrapper - - Social Networking Tools (Thoughts) +- Name services +- Asset Management +- Onchain Identity + - Profile + - Related Accounts +- Marketplace +- NFT Batch Minter +- NFT Pack +- Community Tools Wrapper +- Social Networking Tools (Thoughts) # Name services Contracts @@ -35,9 +37,11 @@ It defines a name lease (which is not implementing NFT standard therefore it is A Lease is a permission to own and use the domain name within a period of time (in .find's case that would be an year since register in general.) Lease owner can link themselves and their wallet address with ${name}.find. Smart contracts that implement FIND can resolve the lease owner address and tell who that is without sending in the clumsy and unreadable length wallet address. ## Lease Attribute + Leases are created and handled as resource on flow. So that they are properly handled and stored. ### Attributes : + name - name of the lease networkCap - link to the network (In find we support multiple tenant, so lease can be connected to different network at creation, creating name services for different tenant) market information - sale / auction / offer prices and details @@ -47,43 +51,45 @@ addons - .find leases can support add ons to the name itself. ```cadence // resolve takes a string address or a find name and returns an address if valid - pub fun resolve(_ input:String) : Address? + access(all) fun resolve(_ input:String) : Address? // lookupAddress look up the address of a find name, and return the owner if there is one (and if the lease is still valid / active) - pub fun lookupAddress(_ name:String): Address? + access(all) fun lookupAddress(_ name:String): Address? // lookup looks up the find name owner's profile public interface if there is one - pub fun lookup(_ input:String): &{Profile.Public}? + access(all) fun lookup(_ input:String): &{Profile.Public}? // reverse lookup looks up the address for the user's find name // If they have set a find name, then return the find name // If they haven't set a find name, return the first name that comes up in the array - pub fun reverseLookup(_ address:Address): String? + access(all) fun reverseLookup(_ address:Address): String? // status returns the status of a find name // For find lease we have 3 states - // pub case FREE - It is not owned and free to take - // pub case TAKEN - It is already taken and in use by someone - // pub case LOCKED - The lease is expired now, but the lease will be locked only to the previous owner who has 3-month-time to renew it + // access(all) case FREE - It is not owned and free to take + // access(all) case TAKEN - It is already taken and in use by someone + // access(all) case LOCKED - The lease is expired now, but the lease will be locked only to the previous owner who has 3-month-time to renew it // - pub fun status(_ name: String): NameStatus + access(all) fun status(_ name: String): NameStatus // depositWithTagAndMessage sends fund from sender to user with / without profile and emit very good events // for users with profile, it supports as much FT as they've set up wallets in profile - // for users without profile, we support flow and FUSD at the moment but it can be extended pretty easily - pub fun depositWithTagAndMessage(to:String, message:String, tag: String, vault: @FungibleToken.Vault, from: &Sender.Token) + // for users without profile, we support flow at the moment but it can be extended pretty easily + access(all) fun depositWithTagAndMessage(to:String, message:String, tag: String, vault: @FungibleToken.Vault, from: &Sender.Token) ``` ## Interaction Templates Some example scripts to show how easy it is to implement FIND + - get the owner from an address or find name [resolve](scripts/resolve.cdc) + ```cadence import FIND -pub fun main(name: String) : Address? { +access(all) fun main(name: String) : Address? { return FIND.resolve(name) } ``` @@ -91,18 +97,19 @@ pub fun main(name: String) : Address? { - get the name of an account [reverseLookup](scripts/reverseLookup.cdc) + ```cadence -pub fun main(input: Address) : String? { +access(all) fun main(input: Address) : String? { return FIND.reverseLookup(input) } ``` # Identity (Profile) + Identity and Personalized descriptions are important assets and features to .find and users. They show how a User want themselves to look like on chain and identify who they are besides the lengthy address. The information is stored under Profile resource in [Profile](./contracts/Profile.cdc) contract. - We have a primary social tools which users can follow / unfollow / setPrivate or ban other users. ## Contract Functions @@ -110,45 +117,45 @@ We have a primary social tools which users can follow / unfollow / setPrivate or ```cadence // Identity and descriptions can be fetched from below functions - pub contract Profile { - pub resource interface Public { + access(all) contract Profile { + access(all) resource interface Public { // asReport is exposed in Public interface which Profile resource implement. // It can be called by getting Profile Public capability // asReport returns all User Profile information including // address, profile name, find name, description, tags etc. // and wallet information - pub fun asReport() : UserReport + access(all) fun asReport() : UserReport // Primary social graphing functions are also exposed under the interface - pub fun isBanned(_ val: Address): Bool - pub fun isPrivateModeEnabled() : Bool - pub fun getFollowers(): [FriendStatus] - pub fun getFollowing(): [FriendStatus] - pub fun getLinks() : [Link] + access(all) fun isBanned(_ val: Address): Bool + access(all) fun isPrivateModeEnabled() : Bool + access(all) fun getFollowers(): [FriendStatus] + access(all) fun getFollowing(): [FriendStatus] + access(all) fun getLinks() : [Link] } // User resource is the Profile that we are referring to. // Notice that User resource implments "FungibleToken.Receiver" // Which means that it can be passed elsewhere as a FungibleToken Switchboard - pub resource User: Public, Owner, FungibleToken.Receiver { + access(all) resource User: Public, Owner, FungibleToken.Receiver { // In deposit function, // The profile is smart enough to identify the vault type and deposit to corresponding FT vault. // Even if the wallet is not set to link with profile, we still tries to borrow vaults from standard path and deposit it. - pub fun deposit(from: @FungibleToken.Vault) + access(all) fun deposit(from: @FungibleToken.Vault) // Wallets related functions - pub fun hasWallet(_ name: String) : Bool - pub fun getWallets() : [Wallet] - pub fun addWallet(_ val: Wallet) - pub fun removeWallet(_ val: String) - pub fun setWallets(_ val: [Wallet]) + access(all) fun hasWallet(_ name: String) : Bool + access(all) fun getWallets() : [Wallet] + access(all) fun addWallet(_ val: Wallet) + access(all) fun removeWallet(_ val: String) + access(all) fun setWallets(_ val: [Wallet]) // Followers related functions - pub fun removeFollower(_ val: Address) - pub fun follows(_ address: Address) : Bool - pub fun follow(_ address: Address, tags:[String]) - pub fun unfollow(_ address: Address) + access(all) fun removeFollower(_ val: Address) + access(all) fun follows(_ address: Address) : Bool + access(all) fun follow(_ address: Address, tags:[String]) + access(all) fun unfollow(_ address: Address) } } ``` @@ -166,14 +173,15 @@ transaction( ``` [register](transactions/register.cdc) + ```cadence transaction( // This is the find name to be purchased name: String, // Amount needed : - // 3 characters : 500 FUSD, - // 4 characters : 100 FUSD, - // 5 characters or above : 5 FUSD + // 3 characters : 500 USD, + // 4 characters : 100 USD, + // 5 characters or above : 5 USD amount: UFix64 ) @@ -209,6 +217,7 @@ transaction( ``` [follow](transactions/follow.cdc) + ```cadence transaction( // map of {User in string (find name or address) : [tag]} @@ -218,6 +227,7 @@ transaction( ``` [unfollow](transactions/unfollow.cdc) + ```cadence transaction( // array of [User in string (find name or address)] @@ -226,34 +236,32 @@ transaction( ``` - # Identity (Related Account) Related Accounts enable user to build their own social networks and wallets on flow and on other chains. User can add their flow wallets / wallets on other chains by network and name. They can also add others wallet as "contact". Currently, if both accounts added each other as related wallet, we would take that as a "verified" trust. - ## Contract Functions ```cadence - pub contract FindRelatedAccounts { - pub resource interface Public{ + access(all) contract FindRelatedAccounts { + access(all) resource interface Public{ // get all registered related flow accounts - pub fun getFlowAccounts() : {String: [Address]} + access(all) fun getFlowAccounts() : {String: [Address]} // get all registered related accounts in specific network - pub fun getRelatedAccounts(_ network: String) : {String : [String]} + access(all) fun getRelatedAccounts(_ network: String) : {String : [String]} // get all registered related accounts : {Network : Addresses} - pub fun getAllRelatedAccounts() : {String : {String : [String]}} + access(all) fun getAllRelatedAccounts() : {String : {String : [String]}} // get all registered related accounts : {Network : AccountInfo struct} - pub fun getAllRelatedAccountInfo() : {String : AccountInformation} + access(all) fun getAllRelatedAccountInfo() : {String : AccountInformation} // verify ensure this wallet address exist under the network - pub fun verify(network: String, address: String) : Bool + access(all) fun verify(network: String, address: String) : Bool // linked ensure this wallet is linked in both wallet with the same name (but not socially linked only) // only supports flow for now - pub fun linked(name: String, network: String, address: Address) : Bool - pub fun getAccount(name: String, network: String, address: String) : AccountInformation? + access(all) fun linked(name: String, network: String, address: Address) : Bool + access(all) fun getAccount(name: String, network: String, address: String) : AccountInformation? } } @@ -325,8 +333,9 @@ transaction( ### Scripts [getAllRelatedAccounts](scripts/getAllRelatedAccounts.cdc) + ```cadence -pub fun main( +access(all) fun main( user: Address // @return : {Network : {Wallet : [wallet address]}} ) : {String : {String : [String]}} @@ -338,25 +347,26 @@ Related accounts are also exposed in getStatus script under accounts with Emeral Report -> FINDReport -> accounts [getAllRelatedAccounts](scripts/getAllRelatedAccounts.cdc) + ```cadence -pub fun main( +access(all) fun main( user: String ) : Report? -pub struct Report { - pub let FINDReport: FINDReport? +access(all) struct Report { + access(all) let FINDReport: FINDReport? } -pub struct FINDReport{ - pub let accounts : [AccountInformation]? +access(all) struct FINDReport{ + access(all) let accounts : [AccountInformation]? } -pub struct AccountInformation { - pub let name: String - pub let address: String - pub let network: String - pub let trusted: Bool - pub let node: String +access(all) struct AccountInformation { + access(all) let name: String + access(all) let address: String + access(all) let network: String + access(all) let trusted: Bool + access(all) let node: String } ``` @@ -364,11 +374,12 @@ pub struct AccountInformation { # Asset Management ## FungibleToken -FungibleTokens are exposed under Find Profile contracts. -As soon as a user adds his/her wallet to Profile, it can be viewable in Profile report. By default we always add FUSD / USDC / Flow token for non-Dapper Users if they initiate their account on .find page. +FungibleTokens are exposed under Find Profile contracts. +As soon as a user adds his/her wallet to Profile, it can be viewable in Profile report. ## NonFungibleToken + We fetch users NonFungibleTokens(NFT) by looking up registered collections on NFTCatalog. NFTCatalog is a collection book of NFTs created by the flow team and tells where a collection should be in the user storage. By iterating through the catalog, we can tell if user has that collection and fetch information from it. It is a little more complicated to handle NFT information because it can come in all sorts of format. But we have some scripts ready to help you on this. @@ -378,75 +389,76 @@ It is a little more complicated to handle NFT information because it can come in ```cadence // Identity and FT can be fetched from below functions - pub contract Profile { - pub resource interface Public { - // asReport is exposed in Public interface which Profile resource implement. + access(all) contract Profile { + access(all) resource interface access(all)lic { + // asReport is exposed in access(all)lic interface which Profile resource implement. // It can be called by getting Profile Public capability // asReport returns all User Profile information including // address, profile name, find name, description, tags etc. // and wallet information - pub fun asReport() : UserReport + access(all) fun asReport() : UserReport // Primary social graphing functions are also exposed under the interface - pub fun isBanned(_ val: Address): Bool - pub fun isPrivateModeEnabled() : Bool - pub fun getFollowers(): [FriendStatus] - pub fun getFollowing(): [FriendStatus] - pub fun getLinks() : [Link] + access(all) fun isBanned(_ val: Address): Bool + access(all) fun isPrivateModeEnabled() : Bool + access(all) fun getFollowers(): [FriendStatus] + access(all) fun getFollowing(): [FriendStatus] + access(all) fun getLinks() : [Link] } - pub struct UserReport { - pub let findName: String - pub let createdAt: String - pub let address: Address - pub let name: String - pub let gender: String - pub let description: String - pub let tags: [String] - pub let avatar: String - pub let links: {String:Link} + access(all) struct UserReport { + access(all) let findName: String + access(all) let createdAt: String + access(all) let address: Address + access(all) let name: String + access(all) let gender: String + access(all) let description: String + access(all) let tags: [String] + access(all) let avatar: String + access(all) let links: {String:Link} // wallet status are exposed in this field - pub let wallets: [WalletProfile] - pub let following: [FriendStatus] - pub let followers: [FriendStatus] - pub let allowStoringFollowers: Bool + access(all) let wallets: [WalletProfile] + access(all) let following: [FriendStatus] + access(all) let followers: [FriendStatus] + access(all) let allowStoringFollowers: Bool } } ``` ### Scripts + NFTs can be fetched from these scripts - NFT script to fetch user collection with only IDs -[getNFTCatalogIDs](./scripts/getNFTCatalogIDs.cdc) + [getNFTCatalogIDs](./scripts/getNFTCatalogIDs.cdc) ```cadence // User : String address or find name // collections : target collection or empty if no specific collection wanted // @return a map of collection to ids -pub fun main( +access(all) fun main( user: String, collections: [String] ) : {String : ItemReport} -pub struct ItemReport { +access(all) struct ItemReport { // Mapping of collection to no. of ids - pub let length : Int - pub let extraIDs : [UInt64] + access(all) let length : Int + access(all) let extraIDs : [UInt64] // Shard means which source we fetch information from. In this case it will always be NFTCatalog - pub let shard : String + access(all) let shard : String // This is needed when we would like to fetch further IDs - pub let extraIDsIdentifier : String + access(all) let extraIDsIdentifier : String // collectionName for display - pub let collectionName: String + access(all) let collectionName: String } ``` - NFT script to fetch user collection with only IDs -[getNFTDetailsNFTCatalog](./scripts/getNFTDetailsNFTCatalog.cdc) + [getNFTDetailsNFTCatalog](./scripts/getNFTDetailsNFTCatalog.cdc) ```cadence // User : String address or find name @@ -474,25 +486,25 @@ pub struct ItemReport { Find Market Doable actions Community Listings (Flovatar market, Flowty rental and borrow market, StoreFront market) */ -pub fun main( +access(all) fun main( user: String, project:String, id: UInt64, views: [String] ) : NFTDetailReport? -pub struct NFTDetailReport { - pub let findMarket: {String : FindMarket.SaleItemInformation} - pub let storefront: FindUserStatus.StorefrontListing? - pub let storefrontV2: FindUserStatus.StorefrontListing? - pub let flowty: FindUserStatus.FlowtyListing? - pub let flowtyRental: FindUserStatus.FlowtyRental? - pub let flovatar: FindUserStatus.FlovatarListing? - pub let flovatarComponent: FindUserStatus.FlovatarComponentListing? - pub let nftDetail: NFTDetail? - pub let allowedListingActions: {String : ListingTypeReport} - pub let dapperAllowedListingActions: {String : ListingTypeReport} - pub let linkedForMarket : Bool? +access(all) struct NFTDetailReport { + access(all) let findMarket: {String : FindMarket.SaleItemInformation} + access(all) let storefront: FindUserStatus.StorefrontListing? + access(all) let storefrontV2: FindUserStatus.StorefrontListing? + access(all) let flowty: FindUserStatus.FlowtyListing? + access(all) let flowtyRental: FindUserStatus.FlowtyRental? + access(all) let flovatar: FindUserStatus.FlovatarListing? + access(all) let flovatarComponent: FindUserStatus.FlovatarComponentListing? + access(all) let nftDetail: NFTDetail? + access(all) let allowedListingActions: {String : ListingTypeReport} + access(all) let dapperAllowedListingActions: {String : ListingTypeReport} + access(all) let linkedForMarket : Bool? } ``` @@ -521,37 +533,37 @@ The configuration enables us to add as many more as we want on top ```cadence // FindMarket defines all market related functinos and the tenant model - pub contract FindMarket { + access(all) contract FindMarket { // Tenant resource will be stored in FIND's main account storage. // It defines all the market rules / cut a tenant want. // Every tenant will have their unique tenant and they will not interfere each other - pub resource Tenant { - // in the tenant reference, call getStoragePath or getPublicPath by sending in the Market Option SaleItemCollection Type, will give you the path to SaleItemCollection + access(all) resource Tenant { + // in the tenant reference, call getStoragePath or getaccess(all)licPath by sending in the Market Option SaleItemCollection Type, will give you the path to SaleItemCollection // Example will demonstrate how to get the target saleItemCollection form a tenant name / address - pub fun getStoragePath(_ type: Type) : StoragePath - pub fun getPublicPath(_ type: Type) : PublicPath + access(all) fun getStoragePath(_ type: Type) : StoragePath + access(all) fun getPublicPath(_ type: Type) : PublicPath } // TenantClient resource will be stored in tenant account storage. // The capability access model is adopted so only accounts that get access to TenantClient resource with VALID tenant capability can operate and connect to dedicated tenant resource // i.e. if .find (as an Admin) set you up as the tenant admin to a particular tenant resource, only then the tenant can do admin operations - pub resource TenantClient { + access(all) resource TenantClient { access(self) var capability: Capability<&Tenant>? } // getTenantAddress can get tenant address from a tenant name // Please be reminded that this name IS NOT the find name and can be anything, .find team has exclusive control over tenant creation and therefore it will not be a problem // currently "find" will be the tenant name for find tenant or you can also call the beflow function to get "find" marketplace address - pub fun getTenantAddress(_ name: String) : Address? + access(all) fun getTenantAddress(_ name: String) : Address? - pub fun getFindTenantAddress() : Address + access(all) fun getFindTenantAddress() : Address // public function to get tenant referece with public interface // the tenant reference and address are vital to do market operations on that particular tenant - pub fun getTenant(_ tenant: Address) : &FindMarket.Tenant{FindMarket.TenantPublic} + access(all) fun getTenant(_ tenant: Address) : &FindMarket.Tenant{FindMarket.TenantPublic} } ``` @@ -561,10 +573,10 @@ To do operations with our contract market, we have to interact directly with the All our listings use NFT resource uuid as the unique identifier so it would be unique to each NFT and there wouldn't be duplicated listings for the same NFT in a user's listing collection ```cadence -pub contract FindMarketSale { +access(all) contract FindMarketSale { // SaleItems are declared in each of the market option contracts and they store all needed information of the listing to 1 particular NFT - pub resource SaleItem : FindMarket.SaleItem { + access(all) resource SaleItem : FindMarket.SaleItem { // buyer of the direct sale access(self) var buyer: Address? // vault type of the listing @@ -584,42 +596,42 @@ pub contract FindMarketSale { } // This is a public interface that expose needed information and required function to execute market interaction. - pub resource interface SaleItemCollectionPublic { + access(all) resource interface SaleItemCollectionPublic { // fetch all the tokens in the collection - pub fun getIds(): [UInt64] + access(all) getIds(): [UInt64] // borrow specific saleItem so as to get detail listing info - pub fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} + access(all) borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} // containsId is a gas efficient way to check if a listing is there. Other than getting all ids and check contains - pub fun containsId(_ id: UInt64): Bool + access(all) containsId(_ id: UInt64): Bool // buy function is exposed here so people can access the seller's saleItemCollection and buy the item. - pub fun buy(id: UInt64, vault: @FungibleToken.Vault, nftCap: Capability<&{NonFungibleToken.Receiver}>) + access(all) buy(id: UInt64, vault: @FungibleToken.Vault, nftCap: Capability<&{NonFungibleToken.Receiver}>) } // SaleItemCollection is similar to Collection to NFTs, it is a collection of all user's saleItmem in that market option type. - pub resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { // list for sale takes an AuthPointer, vaultType, price and valid timeStamp // AuthPointer is declared in FindViews. // It requires user to setup a provider private capability and store it in the AuthPointer struct. // The AuthPointer struct secures it and ensure it will only be used to withdraw the dedicated NFT - pub fun listForSale(pointer: FindViews.AuthNFTPointer, vaultType: Type, directSellPrice:UFix64, validUntil: UFix64?, extraField: {String:AnyStruct}) + access(all) fun listForSale(pointer: FindViews.AuthNFTPointer, vaultType: Type, directSellPrice:UFix64, validUntil: UFix64?, extraField: {String:AnyStruct}) // delist takes the listing id (NFT uuid) - pub fun delist(_ id: UInt64) + access(all) fun delist(_ id: UInt64) // relist is a helper function to revalidate the listing. // It only takes the listing id and will try to relist for you. // Cases that this would be useful and handy would be : // 1. royalty of the NFT changed // 2. listing expires and would like to relist - pub fun relist(_ id: UInt64) + access(all) fun relist(_ id: UInt64) } // contract level function // getSaleItemCapability takes the marketplace (tenant) address and the user address, and return the saleItemCapability for fetching information and call buy function - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? } ``` @@ -646,7 +658,7 @@ transaction(id: UInt64, directSellPrice:UFix64) { let saleItems : &FindMarketSale.SaleItemCollection? let pointer : FindViews.AuthNFTPointer - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { // Get tenant from marketplace address let marketplace = FindMarket.getFindTenantAddress() @@ -656,10 +668,10 @@ transaction(id: UInt64, directSellPrice:UFix64) { let tenant = tenantCapability.borrow()! // get saleItemCollection from tenant specific storage path and saleItemType (in this case FindMarketSale) - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) + self.saleItems= account.storage.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) // getProvider private capability of the selling NFT - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(${NFT_Provider_Private_Path}) + var providerCap=account.getCapability<&{NonFungibleToken.Provider, ViewResolver.ResolverCollection, NonFungibleToken.Collection}>(${NFT_Provider_Private_Path}) self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) self.vaultType= Type<@FlowToken.Vault>() @@ -683,23 +695,23 @@ More detailed version please refer to [buyNFTForSale](transactions/buyNFTForSale ```cadence -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FIND from "../contracts/FIND.cdc" +import "FindMarket" +import "FindMarketSale" +import "NonFungibleToken" +import "MetadataViews" +import "FINDNFTCatalog" +import "FTRegistry" +import "FungibleToken" +import "FIND" transaction(user: String, id: UInt64, amount: UFix64) { var targetCapability : Capability<&{NonFungibleToken.Receiver}> - let walletReference : &FungibleToken.Vault + let walletReference : auth(FungibleToken.Withdraw) &{FungibleToken.Vault} let saleItemsCap: Capability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic}> - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { let marketplace = FindMarket.getFindTenantAddress() // resolve user address here (it supports string address and find names) @@ -726,11 +738,11 @@ transaction(user: String, id: UInt64, amount: UFix64) { // get FT information from item let ft = FTRegistry.getFTInfoByTypeIdentifier(item.getFtType().identifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(item.getFtType().identifier)) - self.walletReference = account.borrow<&FungibleToken.Vault>(from: ft.vaultPath) ?? panic("No suitable wallet linked for this account") + self.walletReference = account.storage.borrow(from: ft.vaultPath) ?? panic("No suitable wallet linked for this account") } pre { - self.walletReference.balance > amount : "Your wallet does not have enough funds to pay for this item" + self.walletReference.getBalance() > amount : "Your wallet does not have enough funds to pay for this item" } execute { @@ -743,10 +755,10 @@ transaction(user: String, id: UInt64, amount: UFix64) { ``` - More Interaction templates can be found in the repo. ### FindMarketSale + [list](transactions/listNFTForSale.cdc) ```cadence @@ -762,6 +774,7 @@ transaction( ``` [buy](transactions/buyNFTForSale.cdc) + ```cadence transaction( user: String, @@ -774,6 +787,7 @@ transaction( ``` [delist](transactions/delistNFTSale.cdc) + ```cadence transaction( // This is the UUID of the NFT @@ -854,6 +868,7 @@ transaction( [cancelMarketAuctionEscrowed](transactions/cancelMarketAuctionEscrowed.cdc) [cancelMarketAuctionSoft](transactions/cancelMarketAuctionSoft.cdc) + ```cadence transaction( // This is the UUID of the NFT @@ -868,7 +883,6 @@ transaction( [bidMarketDirectOfferEscrowed](transactions/bidMarketDirectOfferEscrowed.cdc) - [bidMarketDirectOfferSoft](transactions/bidMarketDirectOfferSoft.cdc) ```cadence @@ -918,54 +932,55 @@ transaction( You can post thought (what we call Think like Tweet as to Twitter), share medias, reThink (quote and post on top), edit, delete, hide and react to thoughts. -Thoughts are still in alpha stage, we are still forging the ability to share and point to NFTs / any onchain assets, adding reply function, publish with tag and get fetched / categorized by the tags, etc. +Thoughts are still in alpha stage, we are still forging the ability to share and point to NFTs / any onchain assets, adding reply function, access(all)lish with tag and get fetched / categorized by the tags, etc. This will be very important part of social mapping ## Contract Function + ```cadence // ** Thoughts are NOT NFTs as they are not meant to be. // They should not be freely moved or regarded as NFT assets -pub contract FindThoughts { +access(all) contract FindThoughts { // These are the fields in the Thought and exposed through ThoughtPublic interface to enable the above mentinoned functions // One thing to mention is that Thought supports NFT views. // We implemented FindViews.ViewReadPointer in thoughts, therefore it can be used to point to NFTs (and fetch NFT information) - pub resource interface ThoughtPublic { - pub let id: UInt64 - pub let creator: Address - pub var header: String - pub var body: String - pub let created: UFix64 - pub var lastUpdated: UFix64? - pub let medias: [MetadataViews.Media] - pub let nft: [FindViews.ViewReadPointer] - pub var tags: [String] - pub var reacted: {Address : String} - pub var reactions: {String : Int} + access(all) resource interface ThoughtPublic { + access(all) let id: UInt64 + access(all) let creator: Address + access(all) var header: String + access(all) var body: String + access(all) let created: UFix64 + access(all) var lastUpdated: UFix64? + access(all) let medias: [MetadataViews.Media] + access(all) let nft: [FindViews.ViewReadPointer] + access(all) var tags: [String] + access(all) var reacted: {Address : String} + access(all) var reactions: {String : Int} access(contract) fun internal_react(user: Address, reaction: String?) - pub fun getQuotedThought() : ThoughtPointer? - pub fun getHide() : Bool + access(all) getQuotedThought() : ThoughtPointer? + access(all) getHide() : Bool } // CollectionPublic interface exposes below functions to the public - pub resource interface CollectionPublic { - pub fun contains(_ id: UInt64) : Bool - pub fun getIDs() : [UInt64] - pub fun borrowThoughtPublic(_ id: UInt64) : &FindThoughts.Thought{FindThoughts.ThoughtPublic} + access(all) resource interface CollectionPublic { + access(all) contains(_ id: UInt64) : Bool + access(all) getIDs() : [UInt64] + access(all) borrowThoughtPublic(_ id: UInt64) : &FindThoughts.Thought{FindThoughts.ThoughtPublic} } // Collection - pub resource Collection : CollectionPublic, MetadataViews.ResolverCollection { + access(all) resource Collection : CollectionPublic, ViewResolver.ResolverCollection { // Publish a thought with optional media, NFTPointer or quotes - pub fun publish(header: String , body: String , tags: [String], media: MetadataViews.Media?, nftPointer: FindViews.ViewReadPointer?, quote: FindThoughts.ThoughtPointer?) - pub fun delete(_ id: UInt64) - pub fun hide(id: UInt64, hide: Bool) + access(all) access(all)lish(header: String , body: String , tags: [String], media: MetadataViews.Media?, nftPointer: FindViews.ViewReadPointer?, quote: FindThoughts.ThoughtPointer?) + access(all) delete(_ id: UInt64) + access(all) hide(id: UInt64, hide: Bool) // react to OTHER user's thought - pub fun react(user: Address, id: UInt64, reaction: String?) + access(all) react(user: Address, id: UInt64, reaction: String?) } } @@ -1055,12 +1070,13 @@ transaction( ``` ### Scripts + Scripts to fetch different user's thoughts [getFindThoughts](scripts/getFindThoughts.cdc) ```cadence -pub fun main( +access(all) main( // owner of the thought addresses: [Address], // corresponding thought IDs @@ -1073,38 +1089,37 @@ Scripts to fetch one user's all thoughts [getOwnedFindThoughts](scripts/getOwnedFindThoughts.cdc) ```cadence -pub fun main( +access(all) main( // owner of the thought address: Address ) : [Thought] ``` - returning object + ```cadence -pub struct Thought { - pub let id: UInt64 - pub let creator: Address - pub let creatorName: String? - pub var creatorProfileName: String? - pub var creatorAvatar: String? - pub var header: String? - pub var body: String? - pub let created: UFix64? - pub var lastUpdated: UFix64? - pub let medias: {String : String} - pub let nft: [FindMarket.NFTInfo] - pub var tags: [String] - pub var reacted: {String : [User]} - pub var reactions: {String : Int} - pub var reactedUsers: {String : [String]} - pub var quotedThought: Thought? - pub let hidden: Bool? +access(all) struct Thought { + access(all) let id: UInt64 + access(all) let creator: Address + access(all) let creatorName: String? + access(all) var creatorProfileName: String? + access(all) var creatorAvatar: String? + access(all) var header: String? + access(all) var body: String? + access(all) let created: UFix64? + access(all) var lastUpdated: UFix64? + access(all) let medias: {String : String} + access(all) let nft: [FindMarket.NFTInfo] + access(all) var tags: [String] + access(all) var reacted: {String : [User]} + access(all) var reactions: {String : Int} + access(all) var reactedUsers: {String : [String]} + access(all) var quotedThought: Thought? + access(all) let hidden: Bool? } ``` - # Name Voucher Name voucher is an NFT that enables owner to register / renew / extend a .find name lease. @@ -1112,7 +1127,6 @@ They are restricted by the minimum number of characters E.g. voucher with 3-characters can renew any lease / register any FREE lease , voucher with 4-characters can only do so to 4-characters or above leases - ### Interaction Template [redeemNameVoucher](transactions/redeemNameVoucher.cdc) diff --git a/auction_test.go b/auction_test.go deleted file mode 100644 index 7cedd3dd..00000000 --- a/auction_test.go +++ /dev/null @@ -1,710 +0,0 @@ -package test_main - -import ( - "testing" - - . "github.com/bjartek/overflow" - "github.com/stretchr/testify/assert" -) - -/* -Tests must be in the same folder as flow.json with contracts and transactions/scripts in subdirectories in order for the path resolver to work correctly -*/ -func TestAuction(t *testing.T) { - - otu := NewOverflowTest(t). - setupFIND(). - createUser(100.0, "user1"). - registerUser("user1") - - otu.setUUID(400) - - findSaleEvent, err := otu.O.QualifiedIdentifier("FIND", "Sale") - assert.NoError(t, err) - - findAuctionEvent, err := otu.O.QualifiedIdentifier("FIND", "EnglishAuction") - assert.NoError(t, err) - - findDOEvent, err := otu.O.QualifiedIdentifier("FIND", "DirectOffer") - assert.NoError(t, err) - - FUSDDepositEvent, err := otu.O.QualifiedIdentifier("FUSD", "TokensDeposited") - assert.NoError(t, err) - - t.Run("Should list a name for sale", func(t *testing.T) { - - otu.listForSale("user1") - - }) - - t.Run("Should be able list names for sale and delist some", func(t *testing.T) { - - otu.registerUserWithName("user1", "name1"). - registerUserWithName("user1", "name2"). - listForSale("user1"). - listNameForSale("user1", "user1"). - listNameForSale("user1", "name1"). - setProfile("user1") - - otu.O.Tx("delistNameSale", - WithSigner("user1"), - WithArg("names", `["user1","name1"]`), - ). - AssertSuccess(t). - AssertEvent(t, findSaleEvent, map[string]interface{}{ - "amount": 10.0, - "name": "name1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "status": "cancel", - }). - AssertEvent(t, findSaleEvent, map[string]interface{}{ - "amount": 10.0, - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "status": "cancel", - }) - }) - - t.Run("Should be able list names for sale and delist them ALL", func(t *testing.T) { - - otu.listForSale("user1"). - listNameForSale("user1", "name1"). - listNameForSale("user1", "name2") - - otu.O.Tx("delistAllNameSale", - WithSigner("user1"), - ). - AssertSuccess(t). - AssertEvent(t, findSaleEvent, map[string]interface{}{ - "amount": 10.0, - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "status": "cancel", - }). - AssertEvent(t, findSaleEvent, map[string]interface{}{ - "amount": 10.0, - "name": "name1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "status": "cancel", - }). - AssertEvent(t, findSaleEvent, map[string]interface{}{ - "amount": 10.0, - "name": "name2", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "status": "cancel", - }) - }) - - t.Run("Should be able to direct offer on name for sale", func(t *testing.T) { - - otu.createUser(100.0, "user2"). - registerUser("user2"). - listForSale("user1"). - directOffer("user2", "user1", 4.0) - }) - - t.Run("Should be able to direct offer on name for sale and fulfill it", func(t *testing.T) { - - otu.setProfile("user2") - - otu.O.Tx("fulfillName", - WithSigner("user1"), - WithArg("name", "user1"), - ). - AssertSuccess(t). - AssertEvent(t, findDOEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "name1", - "buyerAvatar": "https://find.xyz/assets/img/avatars/avatar14.png", - "buyerName": "user2", - "status": "sold", - }). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 3.8, - "to": otu.O.Address("user1"), - }). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 0.2, - "to": otu.O.Address("find-admin"), - }) - - }) - - t.Run("Should be able to sell lease from auction buyer can fulfill auction", func(t *testing.T) { - - otu.moveNameTo("user2", "user1", "user1"). - createUser(100.0, "user3"). - registerUser("user3"). - listForAuction("user1"). - bid("user2", "user1", 8.0). - bid("user3", "user1", 20.0). - expireAuction(). - setProfile("user3") - - otu.O.Tx("fulfillNameAuction", - WithSigner("user3"), - WithArg("owner", "user1"), - WithArg("name", "user1"), - ). - AssertSuccess(t). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "name1", - "amount": 20.0, - "status": "sold", - "buyer": otu.O.Address("user3"), - "buyerAvatar": "https://find.xyz/assets/img/avatars/avatar14.png", - "buyerName": "user3", - }). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 19.0, - "to": otu.O.Address("user1"), - }). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 1.0, - "to": otu.O.Address("find-admin"), - }) - - }) - - t.Run("Should not allow auction bid lower then the current one", func(t *testing.T) { - - otu.moveNameTo("user3", "user1", "user1"). - listForAuction("user1"). - bid("user2", "user1", 8.0). - auctionBid("user3", "user1", 20.0) - - otu.O.Tx("bidName", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 10.0), - ). - AssertFailure(t, "bid must be larger then current bid. Current bid is : 20.00000000. New bid is at : 10.00000000") - - }) - - t.Run("Should be able to sell lease from offer directly", func(t *testing.T) { - - otu.cancelNameAuction("user1", "user1"). - listForSale("user1"). - setProfile("user2") - - buyer := "user2" - name := "user1" - amount := 11.0 - - otu.O.Tx("bidName", - WithSigner(buyer), - WithArg("name", name), - WithArg("amount", amount), - ). - AssertSuccess(t). - AssertEvent(t, findDOEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "name1", - "amount": 11.0, - "status": "sold", - "buyer": otu.O.Address(buyer), - "buyerAvatar": "https://find.xyz/assets/img/avatars/avatar14.png", - "buyerName": buyer, - }). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 10.45, - "to": otu.O.Address("user1"), - }). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 0.55, - "to": otu.O.Address("find-admin"), - }) - - otu.moveNameTo(buyer, name, name) - - }) - - t.Run("Should not start auction if bid lower then sale price", func(t *testing.T) { - - otu.listForAuction("user1"). - directOffer("user2", "user1", 4.0) - - otu.O.Tx("cancelNameBid", - WithSigner("user2"), - WithArg("names", []string{"user1"}), - ).AssertSuccess(t) - - otu.O.Tx("cancelNameAuction", - WithSigner("user1"), - WithArg("names", []string{"user1"}), - ).AssertSuccess(t) - - }) - - t.Run("Should not accept direct offer bid less then current one", func(t *testing.T) { - - otu.directOffer("user2", "user1", 10.0) - - otu.O.Tx("bidName", - WithSigner("user3"), - WithArg("name", "user1"), - WithArg("amount", 5.0), - ). - AssertFailure(t, "There is already a higher bid on this lease. Current bid is : 10.00000000 New bid is at : 5.00000000") - - otu.O.Tx("cancelNameBid", - WithSigner("user2"), - WithArg("names", []string{"user1"}), - ).AssertSuccess(t) - - }) - - t.Run("Should not be able to increase direct offer price less than increment", func(t *testing.T) { - - otu.directOffer("user2", "user1", 10.0) - - otu.O.Tx("increaseNameBid", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 0.0), - ). - AssertFailure(t, "Increment should be greater than 10.00000000") - - otu.O.Tx("cancelNameBid", - WithSigner("user2"), - WithArg("names", []string{"user1"}), - ).AssertSuccess(t) - - }) - - t.Run("Should start auction if we start out with smaller bid and then increase it with locked user", func(t *testing.T) { - - otu.expireLease(). - listForAuction("user1"). - directOffer("user2", "user1", 4.0) - - otu.O.Tx("increaseNameBid", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 10.0), - ). - AssertSuccess(t). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "amount": 14.0, - "status": "active_ongoing", - "buyerName": "user2", - }) - - otu.O.Tx("cancelNameAuction", - WithSigner("user1"), - WithArg("names", []string{"user1"}), - ).AssertSuccess(t) - - }) - - t.Run("Should be able to sell locked name at auction", func(t *testing.T) { - - otu.listForAuction("user1"). - auctionBid("user2", "user1", 20.0). - expireAuction(). - setProfile("user2") - - otu.O.Tx("fulfillNameAuction", - WithSigner("user2"), - WithArg("owner", "user1"), - WithArg("name", "user1"), - ).AssertSuccess(t). - AssertEvent(t, findAuctionEvent, - map[string]interface{}{ - "amount": 20.0, - "auctionReservePrice": 20.0, - "buyer": otu.O.Address("user2"), - "seller": otu.O.Address("user1"), - }, - ) - - }) - - t.Run("Should not allow double bid from same author", func(t *testing.T) { - - otu.moveNameTo("user2", "user1", "user1"). - renewUserWithName("user1", "user1"). - renewUserWithName("user2", "user2"). - renewUserWithName("user3", "user3"). - renewUserWithName("user1", "name1"). - renewUserWithName("user1", "name2"). - listForAuction("user1"). - bid("user2", "user1", 10.0) - - otu.O.Tx("bidName", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 15.0), - ). - AssertFailure(t, "You already have the latest bid on this item, use the incraseBid transaction") - - otu.O.Tx("cancelNameAuction", - WithSigner("user1"), - WithArg("names", []string{"user1"}), - ).AssertSuccess(t) - - }) - - t.Run("Should start auction if we start out with smaller bid and then increase it", func(t *testing.T) { - - otu.listForAuction("user1"). - directOffer("user2", "user1", 4.0) - - otu.O.Tx("increaseNameBid", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 10.0), - ). - AssertSuccess(t). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "amount": 14.0, - "status": "active_ongoing", - "buyerName": "user2", - }) - - }) - - t.Run("Should not be able to increase bid less than increment", func(t *testing.T) { - - otu.O.Tx("increaseNameBid", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 0.0), - ). - AssertFailure(t, "Increment should be greater than 10.00000000") - - }) - - t.Run("Should be able to increase auction bid", func(t *testing.T) { - - otu.O.Tx("increaseNameBid", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 10.0), - ). - AssertSuccess(t). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "status": "active_ongoing", - "buyerName": "user2", - }) - - }) - - t.Run("Should be able to manually start auction with lower bid", func(t *testing.T) { - - otu.cancelNameAuction("user1", "user1"). - listForAuction("user1"). - directOffer("user2", "user1", 4.0) - - otu.O.Tx("startNameAuction", - WithSigner("user1"), - WithArg("name", "user1"), - ). - AssertSuccess(t). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "amount": 4.0, - "status": "active_ongoing", - "buyerName": "user2", - }) - - }) - - //todo test when user is locked - t.Run("Should be able to cancel blind bid", func(t *testing.T) { - - otu.cancelNameAuction("user1", "user1"). - listForSale("user1"). - directOffer("user2", "user1", 4.0) - - otu.O.Tx("cancelNameBid", - WithSigner("user2"), - WithArg("names", `["user1"]`), - ). - AssertSuccess(t). - AssertEvent(t, findDOEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "amount": 4.0, - "status": "cancel_rejected", - "buyerName": "user2", - }) - - }) - - t.Run("Should be able to cancel blind bid when user locked", func(t *testing.T) { - - otu.listForSale("user1"). - directOffer("user2", "user1", 4.0). - expireLease() - - otu.assertLookupAddress("user2", nil) - - otu.O.Tx("cancelNameBid", - WithSigner("user2"), - WithArg("names", `["user1"]`), - ). - AssertSuccess(t). - AssertEvent(t, findDOEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "amount": 4.0, - "status": "cancel_rejected", - "buyerName": "user2", - }) - - }) - - t.Run("Should not be able to cancel bid when auction has started", func(t *testing.T) { - - otu.listForAuction("user1"). - bid("user2", "user1", 5.0) - - otu.O.Tx("cancelNameBid", - WithSigner("user2"), - WithArg("names", `["user1"]`), - ). - AssertFailure(t, "Cannot cancel a bid that is in an auction") - - otu.O.Tx("cancelNameAuction", - WithSigner("user1"), - WithArg("names", []string{"user1"}), - ).AssertSuccess(t) - - }) - - t.Run("Should return money if outbid", func(t *testing.T) { - - otu.listForAuction("user1"). - bid("user2", "user1", 5.0) - - otu.O.Tx("bidName", - WithSigner("user3"), - WithArg("name", "user1"), - WithArg("amount", 15.0), - ). - AssertSuccess(t). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 5.0, - "to": otu.O.Address("user2"), - }). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "amount": 15.0, - "status": "active_ongoing", - "buyerName": "user3", - "previousBuyer": otu.O.Address("user2"), - }) - - }) - - t.Run("Should extend auction on late bid", func(t *testing.T) { - - otu.cancelNameAuction("user1", "user1"). - listForAuction("user1"). - bid("user2", "user1", 5.0) - - otu.tickClock(86380.0) - - otu.O.Tx("bidName", - WithSigner("user3"), - WithArg("name", "user1"), - WithArg("amount", 15.0), - ). - AssertSuccess(t). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 5.0, - "to": otu.O.Address("user2"), - }). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "amount": 15.0, - "status": "active_ongoing", - "buyerName": "user3", - }) - - otu.cancelNameAuction("user1", "user1") - - }) - - t.Run("Should be able to cancel unfinished auction", func(t *testing.T) { - - otu.listForAuction("user1"). - bid("user2", "user1", 5.0) - - otu.O.Tx("cancelNameAuction", - WithSigner("user1"), - WithArg("names", `["user1"]`), - ). - AssertSuccess(t). - AssertEvent(t, FUSDDepositEvent, map[string]interface{}{ - "amount": 5.0, - "to": otu.O.Address("user2"), - }). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": "user1", - "seller": otu.O.Address("user1"), - "sellerName": "user1", - "amount": 5.0, - "status": "cancel_listing", - "buyerName": "user2", - }) - - }) - - t.Run("Should not be able to bid on lease that is free, and not cleaned up", func(t *testing.T) { - - otu.listForSale("user1") - - otu.expireLease().tickClock(2.0) - otu.expireLock().tickClock(2.0) - - otu.O.Tx("bidName", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 10.0), - ). - AssertFailure(t, "cannot bid on name that is free") - - }) - - t.Run("Should be able to cancel finished auction that did not meet reserve price", func(t *testing.T) { - - otu.registerUser("user1"). - listForAuction("user1"). - bid("user2", "user1", 15.0). - expireAuction().tickClock(2.0). - setProfile("user2") - - otu.O.Tx("cancelNameAuction", - WithSigner("user1"), - WithArg("names", `["user1"]`), - ).AssertSuccess(t). - AssertEvent(t, findAuctionEvent, - map[string]interface{}{ - "amount": 15.0, - "auctionReservePrice": 20.0, - "buyer": otu.O.Address("user2"), - "seller": otu.O.Address("user1"), - }, - ) - - }) - - t.Run("Should not be able to cancel finished auction", func(t *testing.T) { - - otu.listForAuction("user1"). - bid("user2", "user1", 25.0). - expireAuction().tickClock(2.0) - - otu.O.Tx("cancelNameAuction", - WithSigner("user1"), - WithArg("names", `["user1"]`), - ). - AssertFailure(t, "Cannot cancel finished auction") - - otu.O.Tx("fulfillNameAuction", - WithSigner("user2"), - WithArg("owner", "user1"), - WithArg("name", "user1"), - ).AssertSuccess(t) - - otu.moveNameTo("user2", "user1", "user1") - - }) - - t.Run("Should not be able to direct offer on your own name", func(t *testing.T) { - - otu.O.Tx("bidName", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("amount", 5.0), - ). - AssertFailure(t, "cannot bid on your own name") - - }) - - t.Run("Should cancel previous bid if put for auction", func(t *testing.T) { - - otu.directOffer("user2", "user1", 5.0) - - name := "user1" - - otu.O.Tx("listNameForAuction", - WithSigner(name), - WithArg("name", name), - WithArg("auctionStartPrice", 5.0), - WithArg("auctionReservePrice", 20.0), - WithArg("auctionDuration", auctionDurationFloat), - WithArg("auctionExtensionOnLateBid", 300.0), - ).AssertSuccess(t). - AssertEvent(t, findAuctionEvent, map[string]interface{}{ - "name": name, - "seller": otu.O.Address(name), - "sellerName": name, - "amount": 5.0, - "status": "active_listed", - }). - AssertEvent(t, findDOEvent, map[string]interface{}{ - "name": name, - "seller": otu.O.Address(name), - "sellerName": name, - "amount": 5.0, - "buyer": otu.O.Address("user2"), - "buyerName": "user2", - "status": "rejected", - }) - - otu.cancelNameAuction("user1", "user1") - - }) - - t.Run("Should register previousBuyer if direct offer outbid", func(t *testing.T) { - - otu.directOffer("user2", "user1", 4.0). - setProfile("user3") - - otu.O.Tx("bidName", - WithSigner("user3"), - WithArg("name", "user1"), - WithArg("amount", 10.0), - ).AssertSuccess(t). - AssertEvent(t, findDOEvent, - map[string]interface{}{ - "amount": 10.0, - "buyer": otu.O.Address("user3"), - "seller": otu.O.Address("user1"), - }, - ) - - otu.O.Tx("cancelNameBid", - WithSigner("user3"), - WithArg("names", []string{"user1"}), - ).AssertSuccess(t) - - }) -} diff --git a/collection_test.go b/collection_test.go index 166b43f6..ee71c1e1 100644 --- a/collection_test.go +++ b/collection_test.go @@ -4,92 +4,22 @@ import ( "fmt" "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCollectionScripts(t *testing.T) { + otu := &OverflowTestUtils{T: t, O: ot.O} - otu := NewOverflowTest(t) - - otu.setupFIND(). - createUser(10000.0, "user1"). - registerUser("user1"). - buyForge("user1"). - registerUserWithNameAndForge("user1", "neomotorcycle"). - registerUserWithNameAndForge("user1", "xtingles"). - registerUserWithNameAndForge("user1", "flovatar"). - registerUserWithNameAndForge("user1", "ufcstrike"). - registerUserWithNameAndForge("user1", "jambb"). - registerUserWithNameAndForge("user1", "bitku"). - registerUserWithNameAndForge("user1", "goatedgoats"). - registerUserWithNameAndForge("user1", "klktn") - - otu.setUUID(500) - - otu.O.Tx("devMintDandyTO", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("maxEdition", 1), - WithArg("artist", "Neo"), - WithArg("nftName", "Motorcycle"), - WithArg("nftDescription", `Bringing the motorcycle world into the 21st century with cutting edge EV technology and advanced performance in a great classic British style, all here in the UK`), - WithArg("nftUrl", "https://neomotorcycles.co.uk/assets/img/neo_motorcycle_side.webp"), - WithArg("rarity", "rare"), - WithArg("rarityNum", 50.0), - WithArg("to", "user1"), - ). - AssertSuccess(t) - - otu.registerDandyInNFTRegistry() - - t.Run("Should be able to get dandies by script", func(t *testing.T) { - result, err := otu.O.Script("getNFTCatalogItems", + ot.Run(t, "Should be able to get dandies by script", func(t *testing.T) { + var data []CollectionData + err := otu.O.Script("getNFTCatalogItems", WithArg("user", "user1"), - WithArg("collectionIDs", map[string][]uint64{dandyNFTType(otu): {504, 505, 503, 506, 502, 507}}), - ).GetWithPointer(fmt.Sprintf("/%s", dandyNFTType(otu))) - - if err != nil { - panic(err) - } - - autogold.Equal(t, result) - - }) - - t.Run("Should be able to get soul bounded items by script", func(t *testing.T) { - - otu.registerExampleNFTInNFTRegistry() - - exampleNFTIden := exampleNFTType(otu) - - ids, err := otu.O.Script("getNFTCatalogIDs", - WithArg("user", otu.O.Address("find")), - WithArg("collections", `[]`), - ). - GetWithPointer(fmt.Sprintf("/%s/extraIDs", exampleNFTIden)) - - assert.NoError(t, err) - - typedIds, ok := ids.([]interface{}) - - if !ok { - panic(ids) - } - - result, err := otu.O.Script("getNFTCatalogItems", - WithArg("user", otu.O.Address("find")), - WithArg("collectionIDs", map[string]interface{}{exampleNFTIden: typedIds}), - ). - GetWithPointer(fmt.Sprintf("/%s", exampleNFTIden)) - - if err != nil { - panic(err) - } - - autogold.Equal(t, result) + WithArg("collectionIDs", map[string][]uint64{dandyNFTType(otu): dandyIds}), + ).MarshalPointerAs(fmt.Sprintf("/%s", dandyNFTType(otu)), &data) + require.NoError(t, err) + autogold.Equal(t, data) }) - } diff --git a/contracts/Admin.cdc b/contracts/Admin.cdc index 5d6c0317..54d91bb8 100644 --- a/contracts/Admin.cdc +++ b/contracts/Admin.cdc @@ -1,372 +1,381 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import FlowToken from "./standard/FlowToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import Profile from "./Profile.cdc" -import FIND from "./FIND.cdc" -import Debug from "./Debug.cdc" -import Clock from "./Clock.cdc" -import FTRegistry from "./FTRegistry.cdc" -import FindForge from "./FindForge.cdc" -import FindForgeOrder from "./FindForgeOrder.cdc" -import FindPack from "./FindPack.cdc" -import NFTCatalog from "./standard/NFTCatalog.cdc" -import FINDNFTCatalogAdmin from "./FINDNFTCatalogAdmin.cdc" -import FindViews from "./FindViews.cdc" -import NameVoucher from "./NameVoucher.cdc" - -pub contract Admin { - - //store the proxy for the admin - pub let AdminProxyPublicPath: PublicPath - pub let AdminProxyStoragePath: StoragePath - - /// =================================================================================== - // Admin things - /// =================================================================================== - - //Admin client to use for capability receiver pattern - pub fun createAdminProxyClient() : @AdminProxy { - return <- create AdminProxy() - } - - //interface to use for capability receiver pattern - pub resource interface AdminProxyClient { - pub fun addCapability(_ cap: Capability<&FIND.Network>) - } - - //admin proxy with capability receiver - pub resource AdminProxy: AdminProxyClient { - - access(self) var capability: Capability<&FIND.Network>? - - pub fun addCapability(_ cap: Capability<&FIND.Network>) { - pre { - cap.check() : "Invalid server capablity" - self.capability == nil : "Server already set" - } - self.capability = cap - } - - pub fun addPublicForgeType(name: String, forgeType : Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - FindForge.addPublicForgeType(forgeType: forgeType) - } - - pub fun addPrivateForgeType(name: String, forgeType : Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - FindForge.addPrivateForgeType(name: name, forgeType: forgeType) - } - - pub fun removeForgeType(_ type : Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - FindForge.removeForgeType(type: type) - } - - pub fun addForgeContractData(lease: String, forgeType: Type , data: AnyStruct) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - FindForge.adminAddContractData(lease: lease, forgeType: forgeType , data: data) - } - - pub fun addForgeMintType(_ mintType: String) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - FindForgeOrder.addMintType(mintType) - } - - pub fun orderForge(leaseName: String, mintType: String, minterCut: UFix64?, collectionDisplay: MetadataViews.NFTCollectionDisplay) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - FindForge.adminOrderForge(leaseName: leaseName, mintType: mintType, minterCut: minterCut, collectionDisplay: collectionDisplay) - } - - pub fun cancelForgeOrder(leaseName: String, mintType: String){ - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindForge.cancelForgeOrder(leaseName: leaseName, mintType: mintType) - } - - pub fun fulfillForgeOrder(contractName: String, forgeType: Type) : MetadataViews.NFTCollectionDisplay { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - return FindForge.fulfillForgeOrder(contractName, forgeType: forgeType) - } - - /// Set the wallet used for the network - /// @param _ The FT receiver to send the money to - pub fun setWallet(_ wallet: Capability<&{FungibleToken.Receiver}>) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) - walletRef.setWallet(wallet) - } - - /// Enable or disable public registration - pub fun setPublicEnabled(_ enabled: Bool) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) - walletRef.setPublicEnabled(enabled) - } - - pub fun setAddonPrice(name: String, price: UFix64) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) - walletRef.setAddonPrice(name: name, price: price) - } - - pub fun setPrice(default: UFix64, additional : {Int: UFix64}) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) - walletRef.setPrice(default: default, additionalPrices: additional) - } - - pub fun register(name: String, profile: Capability<&{Profile.Public}>, leases: Capability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>){ - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - FIND.validateFindName(name) : "A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters" - } - - let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) - walletRef.internal_register(name:name, profile: profile, leases: leases) - } - - pub fun addAddon(name:String, addon:String){ - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - FIND.validateFindName(name) : "A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters" - } - - let user = FIND.lookupAddress(name) ?? panic("Cannot find lease owner. Lease : ".concat(name)) - let ref = getAccount(user).getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath).borrow() ?? panic("Cannot borrow reference to lease collection of user : ".concat(name)) - ref.adminAddAddon(name:name, addon:addon) - } - - pub fun adminSetMinterPlatform(name: String, forgeType: Type, minterCut: UFix64?, description: String, externalURL: String, squareImage: String, bannerImage: String, socials: {String : String}) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - FIND.validateFindName(name) : "A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters" - } - - FindForge.adminSetMinterPlatform(leaseName: name, forgeType: forgeType, minterCut: minterCut, description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials) - } - - pub fun mintForge(name: String, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver, MetadataViews.ResolverCollection}) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - FindForge.mintAdmin(leaseName: name, forgeType: forgeType, data: data, receiver: receiver) - } - - pub fun advanceClock(_ time: UFix64) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - Debug.enable(true) - Clock.enable() - Clock.tick(time) - } - - - pub fun debug(_ value: Bool) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - Debug.enable(value) - } - - /* - pub fun setViewConverters(from: Type, converters: [{Dandy.ViewConverter}]) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - Dandy.setViewConverters(from: from, converters: converters) - } - */ - - /// =================================================================================== - // Fungible Token Registry - /// =================================================================================== - - // Registry FungibleToken Information - pub fun setFTInfo(alias: String, type: Type, tag: [String], icon: String?, receiverPath: PublicPath, balancePath: PublicPath, vaultPath: StoragePath) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FTRegistry.setFTInfo(alias: alias, type: type, tag: tag, icon: icon, receiverPath: receiverPath, balancePath: balancePath, vaultPath:vaultPath) - - } - - // Remove FungibleToken Information by type identifier - pub fun removeFTInfoByTypeIdentifier(_ typeIdentifier: String) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FTRegistry.removeFTInfoByTypeIdentifier(typeIdentifier) - } - - - // Remove FungibleToken Information by alias - pub fun removeFTInfoByAlias(_ alias: String) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FTRegistry.removeFTInfoByAlias(alias) - } - - /// =================================================================================== - // Find Pack - /// =================================================================================== - - pub fun getAuthPointer(pathIdentifier: String, id: UInt64) : FindViews.AuthNFTPointer { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - - let privatePath = PrivatePath(identifier: pathIdentifier)! - var cap = Admin.account.getCapability<&{MetadataViews.ResolverCollection, NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>(privatePath) - if !cap.check() { - let storagePath = StoragePath(identifier: pathIdentifier)! - Admin.account.link<&{MetadataViews.ResolverCollection, NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>(privatePath , target: storagePath) - cap = Admin.account.getCapability<&{MetadataViews.ResolverCollection, NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>(privatePath) - } - return FindViews.AuthNFTPointer(cap: cap, id: id) - } - - pub fun getProviderCap(_ path: PrivatePath): Capability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}> { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - return Admin.account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}>(path) - } - - pub fun mintFindPack(packTypeName: String, typeId:UInt64,hash: String) { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - let pathIdentifier = FindPack.getPacksCollectionPath(packTypeName: packTypeName, packTypeId: typeId) - let path = PublicPath(identifier: pathIdentifier)! - let receiver = Admin.account.getCapability<&{NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(path).borrow() ?? panic("Cannot borrow reference to admin find pack collection public from Path : ".concat(pathIdentifier)) - let mintPackData = FindPack.MintPackData(packTypeName: packTypeName, typeId: typeId, hash: hash, verifierRef: FindForge.borrowVerifier()) - FindForge.adminMint(lease: packTypeName, forgeType: Type<@FindPack.Forge>() , data: mintPackData, receiver: receiver) - } - - pub fun fulfillFindPack(packId:UInt64, types:[Type], rewardIds: [UInt64], salt:String) { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - FindPack.fulfill(packId:packId, types:types, rewardIds:rewardIds, salt:salt) - } - - pub fun requeueFindPack(packId:UInt64) { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - - let cap= Admin.account.borrow<&FindPack.Collection>(from: FindPack.DLQCollectionStoragePath)! - cap.requeue(packId: packId) - } - - pub fun getFindRoyaltyCap() : Capability<&{FungibleToken.Receiver}> { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - - return Admin.account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - } - - /// =================================================================================== - // FINDNFTCatalog - /// =================================================================================== - - pub fun addCatalogEntry(collectionIdentifier : String, metadata : NFTCatalog.NFTCatalogMetadata) { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - - let FINDCatalogAdmin = Admin.account.borrow<&FINDNFTCatalogAdmin.Admin>(from: FINDNFTCatalogAdmin.AdminStoragePath) ?? panic("Cannot borrow reference to Find NFT Catalog admin resource") - FINDCatalogAdmin.addCatalogEntry(collectionIdentifier : collectionIdentifier, metadata : metadata) - } - - pub fun removeCatalogEntry(collectionIdentifier : String) { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - - let FINDCatalogAdmin = Admin.account.borrow<&FINDNFTCatalogAdmin.Admin>(from: FINDNFTCatalogAdmin.AdminStoragePath) ?? panic("Cannot borrow reference to Find NFT Catalog admin resource") - FINDCatalogAdmin.removeCatalogEntry(collectionIdentifier : collectionIdentifier) - } - - pub fun getSwitchboardReceiverPublic() : Capability<&{FungibleToken.Receiver}> { - // we hard code it here instead, to avoid importing just for path - return Admin.account.getCapability<&{FungibleToken.Receiver}>(/public/GenericFTReceiver) - } - - /// =================================================================================== - // Name Voucher - /// =================================================================================== - - pub fun mintNameVoucher(receiver : &{NonFungibleToken.Receiver}, minCharLength : UInt64) : UInt64 { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - - return NameVoucher.mintNFT(recipient: receiver, minCharLength: minCharLength) - } - - pub fun mintNameVoucherToFind(minCharLength : UInt64) : UInt64 { - pre { - self.capability != nil: "Cannot create Admin, capability is not set" - } - - let receiver = Admin.account.borrow<&NameVoucher.Collection{NonFungibleToken.Receiver}>(from: NameVoucher.CollectionStoragePath)! - return NameVoucher.mintNFT(recipient: receiver, minCharLength: minCharLength) - } - - init() { - self.capability = nil - } - - } - - - init() { - - self.AdminProxyPublicPath= /public/findAdminProxy - self.AdminProxyStoragePath=/storage/findAdminProxy - - } - +import "FungibleToken" +import "FlowToken" +import "NonFungibleToken" +import "MetadataViews" +import "Profile" +import "FIND" +import "Debug" +import "Clock" +import "FTRegistry" +import "FindForge" +import "FindForgeOrder" +import "FindPack" +import "NFTCatalog" +import "FINDNFTCatalogAdmin" +import "FindViews" +import "NameVoucher" +import "ViewResolver" + +access(all) contract Admin { + // Entitlements + access(all) entitlement Owner + + //store the proxy for the admin + access(all) let AdminProxyPublicPath: PublicPath + access(all) let AdminProxyStoragePath: StoragePath + + /// =================================================================================== + // Admin things + /// =================================================================================== + + //Admin client to use for capability receiver pattern + access(all) fun createAdminProxyClient() : @AdminProxy { + return <- create AdminProxy() + } + + //interface to use for capability receiver pattern + access(all) resource interface AdminProxyClient { + access(all) fun addCapability(_ cap: Capability<&FIND.Network>) + } + + //admin proxy with capability receiver + access(all) resource AdminProxy: AdminProxyClient { + + access(self) var capability: Capability<&FIND.Network>? + + access(all) fun addCapability(_ cap: Capability<&FIND.Network>) { + pre { + cap.check() : "Invalid server capablity" + self.capability == nil : "Server already set" + } + self.capability = cap + } + + access(Owner) fun addPublicForgeType(name: String, forgeType : Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + FindForge.addPublicForgeType(forgeType: forgeType) + } + + access(Owner) fun addPrivateForgeType(name: String, forgeType : Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + FindForge.addPrivateForgeType(name: name, forgeType: forgeType) + } + + access(Owner) fun removeForgeType(_ type : Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + FindForge.removeForgeType(type: type) + } + + access(Owner) fun addForgeContractData(lease: String, forgeType: Type , data: AnyStruct) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + FindForge.adminAddContractData(lease: lease, forgeType: forgeType , data: data) + } + + access(Owner) fun addForgeMintType(_ mintType: String) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + FindForgeOrder.addMintType(mintType) + } + + access(Owner) fun orderForge(leaseName: String, mintType: String, minterCut: UFix64?, collectionDisplay: MetadataViews.NFTCollectionDisplay) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + FindForge.adminOrderForge(leaseName: leaseName, mintType: mintType, minterCut: minterCut, collectionDisplay: collectionDisplay) + } + + access(Owner) fun cancelForgeOrder(leaseName: String, mintType: String){ + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindForge.cancelForgeOrder(leaseName: leaseName, mintType: mintType) + } + + access(Owner) fun fulfillForgeOrder(contractName: String, forgeType: Type) : MetadataViews.NFTCollectionDisplay { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + return FindForge.fulfillForgeOrder(contractName, forgeType: forgeType) + } + + /// Set the wallet used for the network + /// @param _ The FT receiver to send the money to + access(Owner) fun setWallet(_ wallet: Capability<&{FungibleToken.Receiver}>) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) + walletRef.setWallet(wallet) + } + + /// Enable or disable public registration + access(Owner) fun setPublicEnabled(_ enabled: Bool) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) + walletRef.setPublicEnabled(enabled) + } + + access(Owner) fun setAddonPrice(name: String, price: UFix64) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) + walletRef.setAddonPrice(name: name, price: price) + } + + access(Owner) fun setPrice(defaultPrice: UFix64, additional : {Int: UFix64}) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) + walletRef.setPrice(defaultPrice: defaultPrice, additionalPrices: additional) + } + + access(Owner) fun register(name: String, profile: Capability<&{Profile.Public}>, leases: Capability<&{FIND.LeaseCollectionPublic}>){ + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + if !FIND.validateFindName(name) { + panic("A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") + } + + let walletRef = self.capability!.borrow() ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(self.capability!.address.toString())) + walletRef.internal_register(name:name, profile: profile, leases: leases) + } + + access(Owner) fun addAddon(name:String, addon:String){ + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + if !FIND.validateFindName(name) { + panic("A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") + } + + let user = FIND.lookupAddress(name) ?? panic("Cannot find lease owner. Lease : ".concat(name)) + let ref = getAccount(user).capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)!.borrow() ?? panic("Cannot borrow reference to lease collection of user : ".concat(name)) + ref.adminAddAddon(name:name, addon:addon) + } + + access(Owner) fun adminSetMinterPlatform(name: String, forgeType: Type, minterCut: UFix64?, description: String, externalURL: String, squareImage: String, bannerImage: String, socials: {String : String}) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + if !FIND.validateFindName(name) { + panic("A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") + } + + FindForge.adminSetMinterPlatform(leaseName: name, forgeType: forgeType, minterCut: minterCut, description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials) + } + + access(Owner) fun mintForge(name: String, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver}) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + FindForge.mintAdmin(leaseName: name, forgeType: forgeType, data: data, receiver: receiver) + } + + access(Owner) fun advanceClock(_ time: UFix64) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + Debug.enable(true) + Clock.enable() + Clock.tick(time) + } + + + access(Owner) fun debug(_ value: Bool) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + Debug.enable(value) + } + + /* + access(all) fun setViewConverters(from: Type, converters: [{Dandy.ViewConverter}]) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + Dandy.setViewConverters(from: from, converters: converters) + } + */ + + /// =================================================================================== + // Fungible Token Registry + /// =================================================================================== + + // Registry FungibleToken Information + access(Owner) fun setFTInfo(alias: String, type: Type, tag: [String], icon: String?, receiverPath: PublicPath, balancePath: PublicPath, vaultPath: StoragePath) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FTRegistry.setFTInfo(alias: alias, type: type, tag: tag, icon: icon, receiverPath: receiverPath, balancePath: balancePath, vaultPath:vaultPath) + + } + + // Remove FungibleToken Information by type identifier + access(Owner) fun removeFTInfoByTypeIdentifier(_ typeIdentifier: String) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FTRegistry.removeFTInfoByTypeIdentifier(typeIdentifier) + } + + + // Remove FungibleToken Information by alias + access(Owner) fun removeFTInfoByAlias(_ alias: String) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FTRegistry.removeFTInfoByAlias(alias) + } + + /// =================================================================================== + // Find Pack + /// =================================================================================== + + access(Owner) fun getAuthPointer(pathIdentifier: String, id: UInt64) : FindViews.AuthNFTPointer { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + + let storagePath = StoragePath(identifier: pathIdentifier)! + let account=Admin.account + let providerIdentifier = pathIdentifier.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + //if this stores anything but this it will panic, why does it not return nil? + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(storagePath) + //we save it to storage to memoize it + account.storage.save(existingProvider!, to: providerStoragePath) + log("create new cap") + } + var providerCap = existingProvider! + + + return FindViews.AuthNFTPointer(cap: providerCap, id: id) + } + + access(Owner) fun mintFindPack(packTypeName: String, typeId:UInt64,hash: String) { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + let pathIdentifier = FindPack.getPacksCollectionPath(packTypeName: packTypeName, packTypeId: typeId) + let path = PublicPath(identifier: pathIdentifier)! + let receiver = Admin.account.capabilities.borrow<&{NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(path) ?? panic("Cannot borrow reference to receiver. receiver address: ".concat(path.toString())) + let mintPackData = FindPack.MintPackData(packTypeName: packTypeName, typeId: typeId, hash: hash, verifierRef: FindForge.borrowVerifier()) + FindForge.adminMint(lease: packTypeName, forgeType: Type<@FindPack.Forge>() , data: mintPackData, receiver: receiver) + } + + access(Owner) fun fulfillFindPack(packId:UInt64, types:[Type], rewardIds: [UInt64], salt:String) { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + FindPack.fulfill(packId:packId, types:types, rewardIds:rewardIds, salt:salt) + } + + access(Owner) fun requeueFindPack(packId:UInt64) { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + + let cap= Admin.account.storage.borrow(from: FindPack.DLQCollectionStoragePath)! + cap.requeue(packId: packId) + } + + access(Owner) fun getFindRoyaltyCap() : Capability<&{FungibleToken.Receiver}> { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + + return Admin.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)! + } + + /// =================================================================================== + // FINDNFTCatalog + /// =================================================================================== + + access(Owner) fun addCatalogEntry(collectionIdentifier : String, metadata : NFTCatalog.NFTCatalogMetadata) { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + + let FINDCatalogAdmin = Admin.account.storage.borrow<&FINDNFTCatalogAdmin.Admin>(from: FINDNFTCatalogAdmin.AdminStoragePath) ?? panic("Cannot borrow reference to Find NFT Catalog admin resource") + FINDCatalogAdmin.addCatalogEntry(collectionIdentifier : collectionIdentifier, metadata : metadata) + } + + access(Owner) fun removeCatalogEntry(collectionIdentifier : String) { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + + let FINDCatalogAdmin = Admin.account.storage.borrow<&FINDNFTCatalogAdmin.Admin>(from: FINDNFTCatalogAdmin.AdminStoragePath) ?? panic("Cannot borrow reference to Find NFT Catalog admin resource") + FINDCatalogAdmin.removeCatalogEntry(collectionIdentifier : collectionIdentifier) + } + + access(Owner) fun getSwitchboardReceiverPublic() : Capability<&{FungibleToken.Receiver}> { + // we hard code it here instead, to avoid importing just for path + return Admin.account.capabilities.get<&{FungibleToken.Receiver}>(/public/GenericFTReceiver)! + } + + /// =================================================================================== + // Name Voucher + /// =================================================================================== + + access(Owner) fun mintNameVoucher(receiver : &{NonFungibleToken.Receiver}, minCharLength : UInt64) : UInt64 { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + + return NameVoucher.mintNFT(recipient: receiver, minCharLength: minCharLength) + } + + access(Owner) fun mintNameVoucherToFind(minCharLength : UInt64) : UInt64 { + pre { + self.capability != nil: "Cannot create Admin, capability is not set" + } + + let receiver = Admin.account.storage.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath)! + return NameVoucher.mintNFT(recipient: receiver, minCharLength: minCharLength) + } + + init() { + self.capability = nil + } + } + + init() { + self.AdminProxyPublicPath= /public/findAdminProxy + self.AdminProxyStoragePath=/storage/findAdminProxy + } } diff --git a/contracts/Bl0x.cdc b/contracts/Bl0x.cdc index 3bd11a9b..957b8b34 100644 --- a/contracts/Bl0x.cdc +++ b/contracts/Bl0x.cdc @@ -1,448 +1,499 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -//import FindViews from "./FindViews.cdc" - -pub contract Bl0x: NonFungibleToken { - - pub var totalSupply: UInt64 - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id:UInt64, address:Address) - - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - pub let CollectionPrivatePath: PrivatePath - - access(self) var rarities : [String] - access(account) let royalties : [MetadataViews.Royalty] - - /* - Mythical - Legendary - Epic - Rare - Uncommon - Common - */ - - pub struct Metadata { - pub let nftId: UInt64 - pub let name: String - pub let serial:UInt64 - pub let rarity: String - pub let thumbnail: String - pub let image: String - pub let traits: [{String : String}] - - init(nftId: UInt64,name:String,rarity: String,thumbnail: String, image:String, serial:UInt64, traits: [{String : String}]) { - self.nftId=nftId - self.name=name - self.rarity=rarity - self.thumbnail=thumbnail - self.image=image - self.serial=serial - self.traits=traits - } - } - - //TODO: This can be removed before mainnet - pub struct Data { - pub let nftId: UInt64 - pub let name: String - pub let serial:UInt64 - pub let rarity: String - pub let thumbnail: String - pub let image: String - pub let traits: {String : Trait} - - init(nftId: UInt64,name:String,rarity: String,thumbnail: String, image:String, serial:UInt64, traits: {String : Trait}) { - self.nftId=nftId - self.name=name - self.rarity=rarity - self.thumbnail=thumbnail - self.image=image - self.serial=serial - self.traits=traits - } - } - - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - - pub let id:UInt64 - pub let serial:UInt64 - pub var nounce:UInt64 - pub let rootHash:String - pub let season:UInt64 - pub let traits: {String: UInt64} - pub let royalties: MetadataViews.Royalties - - init( - serial:UInt64, - rootHash:String, - season:UInt64, - traits: {String: UInt64} - ) { - self.nounce=0 - self.serial=serial - self.id=self.uuid - self.rootHash=rootHash - self.season=season - self.traits=traits - self.royalties=MetadataViews.Royalties(Bl0x.royalties) - } - - pub fun getViews(): [Type] { - return [ - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type() - ] - } - - pub fun resolveView(_ view: Type): AnyStruct? { - - let imageFile=MetadataViews.IPFSFile( url: self.rootHash, path: "thumbnail/".concat(self.serial.toString()).concat(".webp")) - - - var fullExtension=".png" - var fullMediaType="image/png" - - let traits = self.traits - if self.serial == 885 { - traits.remove(key: "Module") - } - - if self.serial == 855 { - traits["Module"] = 244 - } - - if traits.containsKey("Module") { - fullExtension=".gif" - fullMediaType="image/gif" - } - let fullFile=MetadataViews.IPFSFile( url: self.rootHash, path: "fullsize/".concat(self.serial.toString()).concat(fullExtension)) - let fullMedia=MetadataViews.Media(file:fullFile, mediaType: fullMediaType) - - let season=self.season - let name ="Bl0x Season".concat(season.toString()).concat(" #").concat(self.serial.toString()) - let description= "Bl0x Season".concat(season.toString()) - - switch view { - case Type(): - return MetadataViews.Display( - name: name, - description: description, - thumbnail: imageFile - ) - - case Type(): - return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/bl0x/").concat(self.id.toString())) - - case Type(): - return self.royalties - - case Type(): - return MetadataViews.Medias([fullMedia]) - - case Type(): - return Data( - nftId : self.id , - name : name , - rarity : self.getRarity() , - thumbnail : imageFile.uri(), - image : fullFile.uri(), - serial:self.serial, - traits:self.getAllTraitsMetadata() - ) - - case Type(): - return Metadata( - nftId : self.id , - name : name , - rarity : self.getRarity() , - thumbnail : imageFile.uri(), - image : fullFile.uri(), - serial:self.serial, - traits:self.getAllTraitsMetadataAsArray() - ) - case Type(): - let externalURL = MetadataViews.ExternalURL("https://find.xyz/mp/bl0x") - let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://bl0x.xyz/assets/home/Bl0xlogo.webp"), mediaType: "image") - let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1535883931777892352/1661105339/1500x500"), mediaType: "image") - return MetadataViews.NFTCollectionDisplay(name: "bl0x", description: "Minting a Bl0x triggers the catalyst moment of a big bang scenario. Generating a treasure that is designed to relate specifically to its holder.", externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: { "discord": MetadataViews.ExternalURL("https://t.co/iY7AhEumR9"), "twitter" : MetadataViews.ExternalURL("https://twitter.com/Bl0xNFT")}) - - case Type(): - return MetadataViews.NFTCollectionData(storagePath: Bl0x.CollectionStoragePath, - publicPath: Bl0x.CollectionPublicPath, - providerPath: Bl0x.CollectionPrivatePath, - publicCollection: Type<&Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: fun(): @NonFungibleToken.Collection {return <- Bl0x.createEmptyCollection()}) - - case Type(): - return MetadataViews.Rarity(score:nil, max:nil, description: self.getRarity()) - - case Type(): - return self.getTraitsAsTraits() - } - return nil - } - - pub fun increaseNounce() { - self.nounce=self.nounce+1 - } - - pub fun getRarity() : String { - var traitRarity : [String] = [] - for trait in self.getAllTraitsMetadata().values { - traitRarity.append(trait.metadata["rarity"]!) - } - - var rarity = "" - for rarityLevel in Bl0x.rarities { - if traitRarity.contains(rarityLevel) { - rarity = rarityLevel - break - } - } - - return rarity - } - - pub fun getTraitsAsTraits() : MetadataViews.Traits { - let traits=self.getAllTraitsMetadata() - - let mvt : [MetadataViews.Trait] = [] - for trait in traits.keys{ - let traitValue = traits[trait]! - mvt.append(MetadataViews.Trait(name:trait, value: traitValue.getName(), displayType: "String", rarity: MetadataViews.Rarity( - score:nil, max:nil, description: traitValue.getRarity() - ))) - } - - return MetadataViews.Traits(mvt) - } - - pub fun getAllTraitsMetadataAsArray() : [{String : String}] { - let traits = self.traits - if self.serial == 885 { - traits.remove(key: "Module") - } - - if self.serial == 855 { - traits["Module"] = 244 - - } - var traitMetadata : [{String : String}] = [] - for trait in traits.keys { - let traitId = traits[trait]! - - traitMetadata.append(Bl0x.traits[traitId]!.metadata) - } - return traitMetadata - } - - pub fun getAllTraitsMetadata() : {String : Trait} { - - let traits = self.traits - if self.serial == 885 { - traits.remove(key: "Module") - } - - if self.serial == 855 { - traits["Module"] = 244 - - } - var traitMetadata : {String : Trait} = {} - for trait in traits.keys { - let traitId = traits[trait]! - traitMetadata[trait] = Bl0x.traits[traitId]! - } - return traitMetadata - } - } - - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} - - init () { - self.ownedNFTs <- {} - } - - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") - - emit Withdraw(id: token.id, from: self.owner?.address) - - return <-token - } - - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { - let token <- token as! @NFT - - let id: UInt64 = token.id - //TODO: add nounce and emit better event the first time it is moved. - - token.increaseNounce() - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) - - - destroy oldToken - } - - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { - return self.ownedNFTs.keys - } - - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! - } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let bl0x = nft as! &NFT - return bl0x as &AnyResource{MetadataViews.Resolver} - } - - destroy() { - destroy self.ownedNFTs - } - } - - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } - - // mintNFT mints a new NFT with a new ID - // and deposit it in the recipients collection using their collection reference - //The distinction between sending in a reference and sending in a capability is that when you send in a reference it cannot be stored. So it can only be used in this method - //while a capability can be stored and used later. So in this case using a reference is the right choice, but it needs to be owned so that you can have a good event - access(account) fun mintNFT( - recipient: &{NonFungibleToken.Receiver}, - serial:UInt64, - rootHash:String, - season:UInt64, - traits: {String: UInt64} - ){ - pre { - recipient.owner != nil : "Recipients NFT collection is not owned" - } - - Bl0x.totalSupply = Bl0x.totalSupply + 1 - // create a new NFT - var newNFT <- create NFT( - serial:serial, - rootHash:rootHash, - season:season, - traits: traits) - - //Always emit events on state changes! always contain human readable and machine readable information - //TODO: discuss that fields we want in this event. Or do we prefer to use the richer deposit event, since this is really done in the backend - //emit Minted(id:newNFT.id, address:recipient.owner!.address) - // deposit it in the recipient's account using their reference - recipient.deposit(token: <-newNFT) - - } - - /// A trait contains information about a trait - pub struct Trait { - pub let id:UInt64 - pub let metadata : {String:String} - - init(id:UInt64, metadata:{String:String}) { - pre { - metadata.containsKey("rarity") : "metadata must contain rarity" - metadata.containsKey("name") : "metadata must contain name" - } - self.id=id - self.metadata=metadata - } - - pub fun getName() : String{ - return self.metadata["name"]! - } - - pub fun getRarity() : String{ - return self.metadata["rarity"]! - } - } - access(self) let traits : {UInt64: Trait} - - access(account) fun addTrait(_ trait:Trait) { - self.traits[trait.id]=trait - } - - pub fun getTraits() : {UInt64:Trait}{ - return self.traits - } - - pub fun getTrait(_ id:UInt64) : Trait? { - return self.traits[id] - } - - access(account) fun addRoyaltycut(_ cutInfo: MetadataViews.Royalty) { - var cutInfos = self.royalties - cutInfos.append(cutInfo) - // for validation only - let royalties = MetadataViews.Royalties(cutInfos) - self.royalties.append(cutInfo) - } - - init() { - //Rarity (Is there a need to update this?) - self.rarities = [ - "Mythic" , - "Legendary" , - "Epic" , - "Rare" , - "Uncommon" , - "Common" - ] - - self.traits={} - // Initialize the total supply - self.totalSupply = 0 - - // Set Royalty cuts in a transaction - self.royalties = [] - - // Set the named paths - self.CollectionStoragePath = /storage/bl0xNFTs - self.CollectionPublicPath = /public/bl0xNFTs - self.CollectionPrivatePath = /private/bl0xNFTs - - self.account.save<@NonFungibleToken.Collection>(<- Bl0x.createEmptyCollection(), to: Bl0x.CollectionStoragePath) - self.account.link<&Bl0x.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Bl0x.CollectionPublicPath, - target: Bl0x.CollectionStoragePath - ) - self.account.link<&Bl0x.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Bl0x.CollectionPrivatePath, - target: Bl0x.CollectionStoragePath - ) - - emit ContractInitialized() - } - } +import "NonFungibleToken" +import "MetadataViews" +import "ViewResolver" + +access(all) contract Bl0x: NonFungibleToken { + + access(all) var totalSupply: UInt64 + + access(all) event ContractInitialized() + access(all) event Minted(id:UInt64, address:Address) + + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + + access(self) var rarities : [String] + access(account) let royalties : [MetadataViews.Royalty] + + /* + Mythical + Legendary + Epic + Rare + Uncommon + Common + */ + + access(all) struct Metadata { + access(all) let nftId: UInt64 + access(all) let name: String + access(all) let serial:UInt64 + access(all) let rarity: String + access(all) let thumbnail: String + access(all) let image: String + access(all) let traits: [{String : String}] + + init(nftId: UInt64,name:String,rarity: String,thumbnail: String, image:String, serial:UInt64, traits: [{String : String}]) { + self.nftId=nftId + self.name=name + self.rarity=rarity + self.thumbnail=thumbnail + self.image=image + self.serial=serial + self.traits=traits + } + } + + access(all) struct Data { + access(all) let nftId: UInt64 + access(all) let name: String + access(all) let serial:UInt64 + access(all) let rarity: String + access(all) let thumbnail: String + access(all) let image: String + access(all) let traits: {String : Trait} + + init(nftId: UInt64,name:String,rarity: String,thumbnail: String, image:String, serial:UInt64, traits: {String : Trait}) { + self.nftId=nftId + self.name=name + self.rarity=rarity + self.thumbnail=thumbnail + self.image=image + self.serial=serial + self.traits=traits + } + } + + access(all) resource NFT: NonFungibleToken.NFT { + + access(all) let id:UInt64 + access(all) let serial:UInt64 + access(all) var nounce:UInt64 + access(all) let rootHash:String + access(all) let season:UInt64 + access(all) let traits: {String: UInt64} + access(all) let royalties: MetadataViews.Royalties + + init( + serial:UInt64, + rootHash:String, + season:UInt64, + traits: {String: UInt64} + ) { + self.nounce=0 + self.serial=serial + self.id=self.uuid + self.rootHash=rootHash + self.season=season + self.traits=traits + self.royalties=MetadataViews.Royalties(Bl0x.royalties) + } + + access(all) view fun getID(): UInt64 { + return self.id + } + + access(all) view fun getViews(): [Type] { + return [ + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + + let imageFile=MetadataViews.IPFSFile( cid: self.rootHash, path: "thumbnail/".concat(self.serial.toString()).concat(".webp")) + + + var fullExtension=".png" + var fullMediaType="image/png" + + let traits = self.traits + if self.serial == 885 { + traits.remove(key: "Module") + } + + if self.serial == 855 { + traits["Module"] = 244 + } + + if traits.containsKey("Module") { + fullExtension=".gif" + fullMediaType="image/gif" + } + let fullFile=MetadataViews.IPFSFile( cid: self.rootHash, path: "fullsize/".concat(self.serial.toString()).concat(fullExtension)) + let fullMedia=MetadataViews.Media(file:fullFile, mediaType: fullMediaType) + + let season=self.season + let name ="Bl0x Season".concat(season.toString()).concat(" #").concat(self.serial.toString()) + let description= "Bl0x Season".concat(season.toString()) + + switch view { + case Type(): + return MetadataViews.Display( + name: name, + description: description, + thumbnail: imageFile + ) + + case Type(): + return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/bl0x/").concat(self.id.toString())) + + case Type(): + return self.royalties + + case Type(): + return MetadataViews.Medias([fullMedia]) + + case Type(): + return Data( + nftId : self.id , + name : name , + rarity : self.getRarity() , + thumbnail : imageFile.uri(), + image : fullFile.uri(), + serial:self.serial, + traits:self.getAllTraitsMetadata() + ) + + case Type(): + return Metadata( + nftId : self.id , + name : name , + rarity : self.getRarity() , + thumbnail : imageFile.uri(), + image : fullFile.uri(), + serial:self.serial, + traits:self.getAllTraitsMetadataAsArray() + ) + case Type(): + let externalURL = MetadataViews.ExternalURL("https://find.xyz/mp/bl0x") + let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://bl0x.xyz/assets/home/Bl0xlogo.webp"), mediaType: "image") + let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1535883931777892352/1661105339/1500x500"), mediaType: "image") + return MetadataViews.NFTCollectionDisplay(name: "bl0x", description: "Minting a Bl0x triggers the catalyst moment of a big bang scenario. Generating a treasure that is designed to relate specifically to its holder.", externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: { "discord": MetadataViews.ExternalURL("https://t.co/iY7AhEumR9"), "twitter" : MetadataViews.ExternalURL("https://twitter.com/Bl0xNFT")}) + + case Type(): + return Bl0x.resolveContractView(resourceType: Type<@Bl0x.Collection>(), viewType: Type()) as! MetadataViews.NFTCollectionData + case Type(): + return MetadataViews.Rarity(score:nil, max:nil, description: self.getRarity()) + + case Type(): + return self.getTraitsAsTraits() + } + return nil + } + + access(contract) fun increaseNounce() { + self.nounce=self.nounce+1 + } + + access(all) fun getRarity() : String { + var traitRarity : [String] = [] + for trait in self.getAllTraitsMetadata().values { + traitRarity.append(trait.metadata["rarity"]!) + } + + var rarity = "" + for rarityLevel in Bl0x.rarities { + if traitRarity.contains(rarityLevel) { + rarity = rarityLevel + break + } + } + + return rarity + } + + access(all) fun getTraitsAsTraits() : MetadataViews.Traits { + let traits=self.getAllTraitsMetadata() + + let mvt : [MetadataViews.Trait] = [] + for trait in traits.keys{ + let traitValue = traits[trait]! + mvt.append(MetadataViews.Trait(name:trait, value: traitValue.getName(), displayType: "String", rarity: MetadataViews.Rarity( + score:nil, max:nil, description: traitValue.getRarity() + ))) + } + + return MetadataViews.Traits(mvt) + } + + access(all) fun getAllTraitsMetadataAsArray() : [{String : String}] { + let traits = self.traits + if self.serial == 885 { + traits.remove(key: "Module") + } + + if self.serial == 855 { + traits["Module"] = 244 + + } + var traitMetadata : [{String : String}] = [] + for trait in traits.keys { + let traitId = traits[trait]! + + traitMetadata.append(Bl0x.traits[traitId]!.metadata) + } + return traitMetadata + } + + access(all) fun getAllTraitsMetadata() : {String : Trait} { + + let traits = self.traits + if self.serial == 885 { + traits.remove(key: "Module") + } + + if self.serial == 855 { + traits["Module"] = 244 + + } + var traitMetadata : {String : Trait} = {} + for trait in traits.keys { + let traitId = traits[trait]! + traitMetadata[trait] = Bl0x.traits[traitId]! + } + return traitMetadata + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-Bl0x.createEmptyCollection(nftType: Type<@Bl0x.NFT>()) + } + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionRef = self.account.storage.borrow<&Bl0x.Collection>( + from: Bl0x.CollectionStoragePath + ) ?? panic("Could not borrow a reference to the stored collection") + let collectionData = MetadataViews.NFTCollectionData( + storagePath: Bl0x.CollectionStoragePath, + publicPath: Bl0x.CollectionPublicPath, + publicCollection: Type<&Bl0x.Collection>(), + publicLinkedType: Type<&Bl0x.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-Bl0x.createEmptyCollection(nftType: Type<@Bl0x.NFT>()) + }) + ) + return collectionData + } + return nil + } + + + access(all) resource Collection: NonFungibleToken.Collection, ViewResolver.ResolverCollection { + // dictionary of NFT conforming tokens + // NFT is a resource type with an `UInt64` ID field + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + + access(self) var storagePath: StoragePath + access(self) var publicPath: PublicPath + + init () { + self.ownedNFTs <- {} + let identifier = "bl0xNFTCollection" + self.storagePath = StoragePath(identifier: identifier)! + self.publicPath = PublicPath(identifier: identifier)! + } + // withdraw removes an NFT from the collection and moves it to the caller + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") + + return <-token + } + + // deposit takes a NFT and adds it to the collections dictionary + // and adds the ID to the id array + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { + let token <- token as! @NFT + + let id: UInt64 = token.id + //TODO: add nounce and emit better event the first time it is moved. + + token.increaseNounce() + // add the new token to the dictionary which removes the old one + let oldToken <- self.ownedNFTs[id] <- token + + + destroy oldToken + } + + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[Type<@Bl0x.NFT>()] = true + return supportedTypes + } + + /// Return the default storage path for the collection + access(all) view fun getDefaultStoragePath(): StoragePath? { + return self.storagePath + } + + /// Return the default public path for the collection + access(all) view fun getDefaultPublicPath(): PublicPath? { + return self.publicPath + } + + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + access(all) view fun isSupportedNFTType(type: Type): Bool { + if type == Type<@Bl0x.NFT>() { + return true + } else { + return false + } + } + + // getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { + return self.ownedNFTs.keys + } + + access(all) view fun getLength(): Int { + return self.ownedNFTs.keys.length + } + + // borrowNFT gets a reference to an NFT in the collection + // so that the caller can read its metadata and call its methods + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] + } + + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? { + if let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) as! &Bl0x.NFT? { + return nft as &{ViewResolver.Resolver} + } + return nil + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create Bl0x.Collection() + } + } + + access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} { + return <- create Collection() + } + + // mintNFT mints a new NFT with a new ID + // and deposit it in the recipients collection using their collection reference + //The distinction between sending in a reference and sending in a capability is that when you send in a reference it cannot be stored. So it can only be used in this method + //while a capability can be stored and used later. So in this case using a reference is the right choice, but it needs to be owned so that you can have a good event + access(account) fun mintNFT( + recipient: &{NonFungibleToken.Receiver}, + serial:UInt64, + rootHash:String, + season:UInt64, + traits: {String: UInt64} + ){ + pre { + recipient.owner != nil : "Recipients NFT collection is not owned" + } + + Bl0x.totalSupply = Bl0x.totalSupply + 1 + // create a new NFT + var newNFT <- create NFT( + serial:serial, + rootHash:rootHash, + season:season, + traits: traits) + recipient.deposit(token: <- (newNFT)) + + } + + /// A trait contains information about a trait + access(all) struct Trait { + access(all) let id:UInt64 + access(all) let metadata : {String:String} + + init(id:UInt64, metadata:{String:String}) { + pre { + metadata.containsKey("rarity") : "metadata must contain rarity" + metadata.containsKey("name") : "metadata must contain name" + } + self.id=id + self.metadata=metadata + } + + access(all) fun getName() : String{ + return self.metadata["name"]! + } + + access(all) fun getRarity() : String{ + return self.metadata["rarity"]! + } + } + + access(self) let traits : {UInt64: Trait} + + access(account) fun addTrait(_ trait:Trait) { + self.traits[trait.id]=trait + } + + access(all) fun getTraits() : {UInt64:Trait}{ + return self.traits + } + + access(all) fun getTrait(_ id:UInt64) : Trait? { + return self.traits[id] + } + + access(account) fun addRoyaltycut(_ cutInfo: MetadataViews.Royalty) { + var cutInfos = self.royalties + cutInfos.append(cutInfo) + // for validation only + let royalties = MetadataViews.Royalties(cutInfos) + self.royalties.append(cutInfo) + } + + init() { + //Rarity (Is there a need to update this?) + self.rarities = [ + "Mythic" , + "Legendary" , + "Epic" , + "Rare" , + "Uncommon" , + "Common" + ] + + self.traits={} + // Initialize the total supply + self.totalSupply = 0 + + // Set Royalty cuts in a transaction + self.royalties = [] + + // Set the named paths + self.CollectionStoragePath = /storage/bl0xNFTs + self.CollectionPublicPath = /public/bl0xNFTs + + + // Create a Collection resource and save it to storage + let collection <- create Collection() + self.account.storage.save(<-collection, to: self.CollectionStoragePath) + + // create a public capability for the collection + let collectionCap = self.account.capabilities.storage.issue<&Bl0x.Collection>(self.CollectionStoragePath) + self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath) + + emit ContractInitialized() + } + } diff --git a/contracts/Bl0xPack.cdc b/contracts/Bl0xPack.cdc index 130a2db6..d6c3850c 100644 --- a/contracts/Bl0xPack.cdc +++ b/contracts/Bl0xPack.cdc @@ -1,713 +1,771 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" import Crypto -import Clock from "../contracts/Clock.cdc" -import Debug from "./Debug.cdc" -import FLOAT from "../contracts/standard/FLOAT.cdc" -import Bl0x from "../contracts/Bl0x.cdc" +import "Clock" +import "Debug" +import "FLOAT" +import "Bl0x" +import "ViewResolver" -pub contract Bl0xPack: NonFungibleToken { - // Events - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id: UInt64, typeId:UInt64) +access(all) contract Bl0xPack: ViewResolver { + // Events + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Minted(id: UInt64, typeId:UInt64) - pub event Requeued(packId: UInt64, address:Address) + access(all) event Requeued(packId: UInt64, address:Address) - pub event Opened(packId: UInt64, address:Address) - pub event Fulfilled(packId:UInt64, address:Address) - pub event PackReveal(packId:UInt64, address:Address, packTypeId:UInt64, rewardId:UInt64, nftName:String, nftImage:String, nftRarity:String) + access(all) event Opened(packId: UInt64, address:Address) + access(all) event Fulfilled(packId:UInt64, address:Address) + access(all) event PackReveal(packId:UInt64, address:Address, packTypeId:UInt64, rewardId:UInt64, nftName:String, nftImage:String, nftRarity:String) - pub event Purchased(packId: UInt64, address: Address, amount:UFix64) - pub event MetadataRegistered(typeId:UInt64) - pub event FulfilledError(packId:UInt64, address:Address?, reason:String) - pub event OpenDebug(packId:UInt64, message:String) + access(all) event Purchased(packId: UInt64, address: Address, amount:UFix64) + access(all) event MetadataRegistered(typeId:UInt64) + access(all) event FulfilledError(packId:UInt64, address:Address?, reason:String) + access(all) event OpenDebug(packId:UInt64, message:String) - pub let PackMetadataStoragePath: StoragePath + access(all) let PackMetadataStoragePath: StoragePath - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath - pub let OpenedCollectionPublicPath: PublicPath - pub let OpenedCollectionStoragePath: StoragePath + access(all) let OpenedCollectionPublicPath: PublicPath + access(all) let OpenedCollectionStoragePath: StoragePath + access(all) let DLQCollectionPublicPath: PublicPath + access(all) let DLQCollectionStoragePath: StoragePath - pub let DLQCollectionPublicPath: PublicPath - pub let DLQCollectionStoragePath: StoragePath + access(all) var totalSupply: UInt64 - pub var totalSupply: UInt64 + access(contract) let packMetadata: {UInt64: Metadata} - access(contract) let packMetadata: {UInt64: Metadata} + access(all) struct Metadata { + access(all) let name: String + access(all) let description: String - pub struct Metadata { - pub let name: String - pub let description: String + access(all) let thumbnailHash: String? + access(all) let thumbnailUrl:String? - pub let thumbnailHash: String? - pub let thumbnailUrl:String? + access(all) let wallet: Capability<&{FungibleToken.Receiver}> + access(all) let walletType: Type + access(all) let price: UFix64 - pub let wallet: Capability<&{FungibleToken.Receiver}> - pub let walletType: Type - pub let price: UFix64 + access(all) let buyTime:UFix64 - pub let buyTime:UFix64 + access(all) let openTime:UFix64 + access(all) let whiteListTime:UFix64? - pub let openTime:UFix64 - pub let whiteListTime:UFix64? + access(all) let floatEventId: UInt64? - pub let floatEventId: UInt64? + access(all) let storageRequirement: UInt64 - pub let storageRequirement: UInt64 + access(contract) let providerCap: Capability - access(contract) let providerCap: Capability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}> + access(contract) let royaltyCap: Capability<&{FungibleToken.Receiver}>? + access(contract) let royaltyCut: UFix64 - access(contract) let royaltyCap: Capability<&{FungibleToken.Receiver}>? - access(contract) let royaltyCut: UFix64 + access(all) let requiresReservation: Bool - pub let requiresReservation: Bool + init(name: String, description: String, thumbnailUrl: String?,thumbnailHash: String?, wallet: Capability<&{FungibleToken.Receiver}>, price: UFix64, buyTime:UFix64, openTime:UFix64, walletType:Type, providerCap: Capability, requiresReservation:Bool, royaltyCut: UFix64, royaltyWallet: Capability<&{FungibleToken.Receiver}>, floatEventId:UInt64?, whiteListTime: UFix64?, storageRequirement: UInt64) { + self.name = name + self.description = description + self.thumbnailUrl = thumbnailUrl + self.thumbnailHash = thumbnailHash + self.wallet=wallet + self.walletType=walletType + self.price =price + self.buyTime=buyTime + self.openTime=openTime + self.providerCap=providerCap - init(name: String, description: String, thumbnailUrl: String?,thumbnailHash: String?, wallet: Capability<&{FungibleToken.Receiver}>, price: UFix64, buyTime:UFix64, openTime:UFix64, walletType:Type, providerCap: Capability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}>, requiresReservation:Bool, royaltyCut: UFix64, royaltyWallet: Capability<&{FungibleToken.Receiver}>, floatEventId:UInt64?, whiteListTime: UFix64?, storageRequirement: UInt64) { - self.name = name - self.description = description - self.thumbnailUrl = thumbnailUrl - self.thumbnailHash = thumbnailHash - self.wallet=wallet - self.walletType=walletType - self.price =price - self.buyTime=buyTime - self.openTime=openTime - self.providerCap=providerCap + //If this pack has royalties then they can be added here later. For the current implementations royalties appear to be handled offchain. + self.royaltyCap=royaltyWallet + self.royaltyCut=royaltyCut - //If this pack has royalties then they can be added here later. For the current implementations royalties appear to be handled offchain. - self.royaltyCap=royaltyWallet - self.royaltyCut=royaltyCut + self.floatEventId=floatEventId + self.whiteListTime=whiteListTime - self.floatEventId=floatEventId - self.whiteListTime=whiteListTime + self.storageRequirement= storageRequirement + + // 10000 //bytes needed for nfts of pack - pack size (since pack will be gone) + self.requiresReservation=requiresReservation + } + + access(all) view fun getThumbnail() : {MetadataViews.File} { + if let hash = self.thumbnailHash { + return MetadataViews.IPFSFile(cid: hash, path:nil) + } + return MetadataViews.HTTPFile(url:self.thumbnailUrl!) + } + + access(all) fun canBeOpened() : Bool { + return self.openTime >= Clock.time() + } + } + + access(account) fun registerMetadata(typeId: UInt64, metadata: Metadata) { + emit MetadataRegistered(typeId:typeId) + self.packMetadata[typeId]= metadata + } + + access(all) view fun getMetadata(typeId: UInt64): Metadata? { + return self.packMetadata[typeId] + } - self.storageRequirement= storageRequirement + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { + // The token's ID + access(all) let id: UInt64 + + // The token's typeId + access(self) var typeId: UInt64 + + //this is added to the NFT when it is opened + access(self) var openedBy: Capability<&{NonFungibleToken.Receiver}>? + + access(account) let hash: String + + // init + // + init(typeId: UInt64, hash:String) { + self.id = self.uuid + self.typeId = typeId + self.openedBy=nil + self.hash=hash + } + + access(all) fun getOpenedBy() : Capability<&{NonFungibleToken.Receiver}> { + if self.openedBy== nil { + panic("Pack is not opened") + } + return self.openedBy! + } + + access(all) fun getHash() : String{ + return self.hash + } + + access(all) view fun getID(): UInt64 { + return self.id + } + + access(contract) fun setTypeId(_ id: UInt64) { + self.typeId=id + } + + access(contract) fun resetOpendBy() : Address { + if self.openedBy==nil { + panic("Pack is not opened") + } + let cap = self.openedBy! + + self.openedBy=nil + return cap.address + } + + access(contract) fun setOpenedBy(_ cap:Capability<&{NonFungibleToken.Receiver}>) { + if self.openedBy!=nil { + panic("Pack has already been opened") + } + self.openedBy=cap + } + + access(all) fun getTypeID() :UInt64 { + return self.typeId + } + + access(all) view fun getMetadata(): Metadata { + return Bl0xPack.getMetadata(typeId: self.typeId)! + } + + access(all) view fun getViews(): [Type] { + return [ + Type(), + Type(), + Type() + ] + } + + access(all) view fun getThumbnail() : {MetadataViews.File} { + return self.getMetadata().getThumbnail() + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + let metadata = self.getMetadata() + switch view { + case Type(): + return MetadataViews.Display( + name: metadata.name, + description: metadata.description, + thumbnail: self.getThumbnail() + ) + case Type(): + return metadata.name + + case Type(): + return metadata + + case Type(): + return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/bl0xPack/").concat(self.id.toString())) + + case Type(): + return Bl0x.royalties + + case Type(): + return Bl0xPack.resolveContractView(resourceType: Type<@Bl0xPack.Collection>(), viewType: Type()) as! MetadataViews.NFTCollectionData + + case Type(): + let externalURL = MetadataViews.ExternalURL("https://find.xyz/mp/bl0xPack") + let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://bl0x.xyz/assets/home/Bl0xlogo.webp"), mediaType: "image") + let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1535883931777892352/1661105339/1500x500"), mediaType: "image") + return MetadataViews.NFTCollectionDisplay(name: "bl0x Pack", description: "Minting a Bl0x triggers the catalyst moment of a big bang scenario. Generating a treasure that is designed to relate specifically to its holder.", externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: { "discord": MetadataViews.ExternalURL("https://t.co/iY7AhEumR9"), "twitter" : MetadataViews.ExternalURL("https://twitter.com/Bl0xNFT")}) + } + return nil + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-Bl0xPack.createEmptyCollection() + } + } + + access(all) resource interface CollectionPublic { + access(all) fun deposit(token: @{NonFungibleToken.NFT}) + access(all) view fun getIDs(): [UInt64] + access(all) view fun getPacksLeftForType(_ type:UInt64) : UInt64 + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? + access(all) fun borrowBl0xPack(id: UInt64): &Bl0xPack.NFT? + access(all) fun buy(typeId: UInt64, vault: @{FungibleToken.Vault}, collectionCapability: Capability<&Collection>) + access(all) fun buyWithSignature(packId: UInt64, signature:String, vault: @{FungibleToken.Vault}, collectionCapability: Capability<&Collection>) + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionRef = self.account.storage.borrow<&Bl0xPack.Collection>( + from: Bl0xPack.CollectionStoragePath + ) ?? panic("Could not borrow a reference to the stored collection") + let collectionData = MetadataViews.NFTCollectionData( + storagePath: Bl0xPack.CollectionStoragePath, + publicPath: Bl0xPack.CollectionPublicPath, + publicCollection: Type<&Bl0xPack.Collection>(), + publicLinkedType: Type<&Bl0xPack.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-Bl0xPack.createEmptyCollection() + }) + ) + return collectionData + } + return nil + } + + access(all) entitlement Owner + + // Collection + // A collection of Bl0xPack NFTs owned by an account + // + access(all) resource Collection: NonFungibleToken.Collection, CollectionPublic, ViewResolver.ResolverCollection { + // dictionary of NFT conforming tokens + // NFT is a resource type with an `UInt64` ID field + // + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + + access(all) var nftsPerType: {UInt64:UInt64} + + access(self) var storagePath: StoragePath + + access(self) var publicPath: PublicPath + + + // since maps are not ordered in cadence this will pick any random key and that works really well + access(self) fun getPackIdForType(_ typeId: UInt64): UInt64? { + for key in self.ownedNFTs.keys { + if let pack= self.borrowBl0xPack(id: key) { + if pack.getTypeID() == typeId { + return key + } + } + } + return nil + } + + //this has to be called on the DLQ collection + access(Owner) fun requeue(packId:UInt64) { + let token <- self.withdraw(withdrawID: packId) as! @NFT + + let address=token.resetOpendBy() + let cap=getAccount(address).capabilities.get<&Collection>(Bl0xPack.CollectionPublicPath)! + let receiver = cap.borrow()! + receiver.deposit(token: <- token) + emit Requeued(packId:packId, address: cap.address) + } + + access(all) view fun getLength(): Int { + return self.ownedNFTs.keys.length + } + + access(Owner) fun open(packId: UInt64, receiverCap: Capability<&{NonFungibleToken.Receiver}>) { + if !receiverCap.check() { + panic("Receiver cap is not valid") + } + let pack=self.borrowBl0xPack(id:packId)! + + var time= pack.getMetadata().openTime + let timestamp=Clock.time() + if timestamp < time { + panic("You cannot open the pack yet") + } + + let token <- self.withdraw(withdrawID: packId) as! @Bl0xPack.NFT + token.setOpenedBy(receiverCap) + + // establish the receiver for Redeeming Bl0xPack + let receiver = Bl0xPack.account.capabilities.get<&{NonFungibleToken.Receiver}>(Bl0xPack.OpenedCollectionPublicPath)!.borrow()! + + // deposit for consumption + receiver.deposit(token: <- token) + + emit Opened(packId:packId, address: self.owner!.address) + } + + access(all) fun buyWithSignature(packId: UInt64, signature:String, vault: @{FungibleToken.Vault}, collectionCapability: Capability<&Collection>) { + pre { + self.owner!.address == Bl0xPack.account.address : "You can only buy pack directly from the Bl0xPack account" + } + + let nft <- self.withdraw(withdrawID: packId) as! @NFT + let metadata= nft.getMetadata() + + + if !metadata.requiresReservation { + panic("This pack type does not require reservation, use the open buy method") + } + + var time= metadata.buyTime + let timestamp=Clock.time() + if timestamp < time { + panic("You cannot buy the pack yet") + } + + if vault.getType() != metadata.walletType { + panic("The vault sent in is not of the desired type ".concat(metadata.walletType.identifier)) + } + + + if metadata.price != vault.balance { + panic("Vault does not contain required amount of FT ".concat(metadata.price.toString())) + } + + let keyList = Crypto.KeyList() + let accountKey = self.owner!.keys.get(keyIndex: 0)!.publicKey + + // Adds the public key to the keyList + keyList.add( + PublicKey( + publicKey: accountKey.publicKey, + signatureAlgorithm: accountKey.signatureAlgorithm + ), + hashAlgorithm: HashAlgorithm.SHA3_256, + weight: 1.0 + ) + + // Creates a Crypto.KeyListSignature from the signature provided in the parameters + let signatureSet: [Crypto.KeyListSignature] = [] + signatureSet.append( + Crypto.KeyListSignature( + keyIndex: 0, + signature: signature.decodeHex() + ) + ) + + // Verifies that the signature is valid and that it was generated from the + // owner of the collection + if(!keyList.verify(signatureSet: signatureSet, signedData: nft.hash.utf8, domainSeparationTag: "FLOW-V0.0-user")){ + panic("Unable to validate the signature for the pack!") + } + + if metadata.royaltyCut != 0.0 && metadata.royaltyCap != nil && metadata.royaltyCap!.check() { + metadata.royaltyCap!.borrow()!.deposit(from: <- vault.withdraw(amount: vault.balance * metadata.royaltyCut)) + } + + metadata.wallet.borrow()!.deposit(from: <- vault) + collectionCapability.borrow()!.deposit(token: <- nft) + + emit Purchased(packId: packId, address: collectionCapability.address, amount:metadata.price) + } + + access(all) fun buy(typeId: UInt64, vault: @{FungibleToken.Vault}, collectionCapability: Capability<&Collection>) { + pre { + self.owner!.address == Bl0xPack.account.address : "You can only buy pack directly from the Bl0xPack account" + } - // 10000 //bytes needed for nfts of pack - pack size (since pack will be gone) - self.requiresReservation=requiresReservation - } - - pub fun getThumbnail() : AnyStruct{MetadataViews.File} { - if let hash = self.thumbnailHash { - return MetadataViews.IPFSFile(cid: hash, path:nil) - } - return MetadataViews.HTTPFile(url:self.thumbnailUrl!) - } - - pub fun canBeOpened() : Bool { - return self.openTime >= Clock.time() - } - } - - access(account) fun registerMetadata(typeId: UInt64, metadata: Metadata) { - emit MetadataRegistered(typeId:typeId) - self.packMetadata[typeId]= metadata - } - - pub fun getMetadata(typeId: UInt64): Metadata? { - return self.packMetadata[typeId] - } - - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - // The token's ID - pub let id: UInt64 - - // The token's typeId - access(self) var typeId: UInt64 - - //this is added to the NFT when it is opened - access(self) var openedBy: Capability<&{NonFungibleToken.Receiver}>? - - access(account) let hash: String - - // init - // - init(typeId: UInt64, hash:String) { - self.id = self.uuid - self.typeId = typeId - self.openedBy=nil - self.hash=hash - } - - pub fun getOpenedBy() : Capability<&{NonFungibleToken.Receiver}> { - if self.openedBy== nil { - panic("Pack is not opened") - } - return self.openedBy! - } - - pub fun getHash() : String{ - return self.hash - } - - access(contract) fun setTypeId(_ id: UInt64) { - self.typeId=id - } - - access(contract) fun resetOpendBy() : Address { - if self.openedBy==nil { - panic("Pack is not opened") - } - let cap = self.openedBy! - - self.openedBy=nil - return cap.address - } - - access(contract) fun setOpenedBy(_ cap:Capability<&{NonFungibleToken.Receiver}>) { - if self.openedBy!=nil { - panic("Pack has already been opened") - } - self.openedBy=cap - } - - pub fun getTypeID() :UInt64 { - return self.typeId - } - - pub fun getMetadata(): Metadata { - return Bl0xPack.getMetadata(typeId: self.typeId)! - } - - pub fun getViews(): [Type] { - return [ - Type(), - Type(), - Type() - ] - } - - pub fun getThumbnail() : AnyStruct{MetadataViews.File} { - return self.getMetadata().getThumbnail() - } - - pub fun resolveView(_ view: Type): AnyStruct? { - let metadata = self.getMetadata() - switch view { - case Type(): - return MetadataViews.Display( - name: metadata.name, - description: metadata.description, - thumbnail: self.getThumbnail() - ) - case Type(): - return metadata.name - - case Type(): - return metadata - - case Type(): - return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/bl0xPack/").concat(self.id.toString())) - - case Type(): - return Bl0x.royalties - - case Type(): - return MetadataViews.NFTCollectionData( - storagePath: Bl0xPack.CollectionStoragePath, - publicPath: Bl0xPack.CollectionPublicPath, - providerPath: /private/Bl0xPackCollection, - publicCollection: Type<&Bl0xPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Bl0xPack.CollectionPublic}>(), - publicLinkedType: Type<&Bl0xPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Bl0xPack.CollectionPublic}>(), - providerLinkedType: Type<&Bl0xPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Bl0xPack.CollectionPublic}>(), - createEmptyCollectionFunction: fun () : @NonFungibleToken.Collection { - return <- Bl0xPack.createEmptyCollection() - } - ) - - case Type(): - let externalURL = MetadataViews.ExternalURL("https://find.xyz/mp/bl0xPack") - let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://bl0x.xyz/assets/home/Bl0xlogo.webp"), mediaType: "image") - let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1535883931777892352/1661105339/1500x500"), mediaType: "image") - return MetadataViews.NFTCollectionDisplay(name: "bl0x Pack", description: "Minting a Bl0x triggers the catalyst moment of a big bang scenario. Generating a treasure that is designed to relate specifically to its holder.", externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: { "discord": MetadataViews.ExternalURL("https://t.co/iY7AhEumR9"), "twitter" : MetadataViews.ExternalURL("https://twitter.com/Bl0xNFT")}) - } - return nil - } - - } - - pub resource interface CollectionPublic { - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun getPacksLeftForType(_ type:UInt64) : UInt64 - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowBl0xPack(id: UInt64): &Bl0xPack.NFT? - pub fun buy(typeId: UInt64, vault: @FungibleToken.Vault, collectionCapability: Capability<&Collection{NonFungibleToken.Receiver}>) - pub fun buyWithSignature(packId: UInt64, signature:String, vault: @FungibleToken.Vault, collectionCapability: Capability<&Collection{NonFungibleToken.Receiver}>) - } - - // Collection - // A collection of Bl0xPack NFTs owned by an account - // - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, CollectionPublic, MetadataViews.ResolverCollection { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - // - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} - - pub var nftsPerType: {UInt64:UInt64} - - // since maps are not ordered in cadence this will pick any random key and that works really well - access(self) fun getPackIdForType(_ typeId: UInt64): UInt64? { - for key in self.ownedNFTs.keys { - if let pack= self.borrowBl0xPack(id: key) { - if pack.getTypeID() == typeId { - return key - } - } - } - return nil - } - - //this has to be called on the DLQ collection - pub fun requeue(packId:UInt64) { - let token <- self.withdraw(withdrawID: packId) as! @NFT - - let address=token.resetOpendBy() - let cap=getAccount(address).getCapability<&Collection{NonFungibleToken.Receiver}>(Bl0xPack.CollectionPublicPath) - let receiver = cap.borrow()! - receiver.deposit(token: <- token) - emit Requeued(packId:packId, address: cap.address) - } - - pub fun open(packId: UInt64, receiverCap: Capability<&{NonFungibleToken.Receiver}>) { - if !receiverCap.check() { - panic("Receiver cap is not valid") - } - let pack=self.borrowBl0xPack(id:packId)! - - var time= pack.getMetadata().openTime - let timestamp=Clock.time() - if timestamp < time { - panic("You cannot open the pack yet") - } - - let token <- self.withdraw(withdrawID: packId) as! @Bl0xPack.NFT - token.setOpenedBy(receiverCap) - - // establish the receiver for Redeeming Bl0xPack - let receiver = Bl0xPack.account.getCapability<&{NonFungibleToken.Receiver}>(Bl0xPack.OpenedCollectionPublicPath).borrow()! - - // deposit for consumption - receiver.deposit(token: <- token) - - emit Opened(packId:packId, address: self.owner!.address) - } - - //TODO: pre that needs requiresReservation - pub fun buyWithSignature(packId: UInt64, signature:String, vault: @FungibleToken.Vault, collectionCapability: Capability<&Collection{NonFungibleToken.Receiver}>) { - pre { - self.owner!.address == Bl0xPack.account.address : "You can only buy pack directly from the Bl0xPack account" - } - - let nft <- self.withdraw(withdrawID: packId) as! @NFT - let metadata= nft.getMetadata() - - - if !metadata.requiresReservation { - panic("This pack type does not require reservation, use the open buy method") - } - - var time= metadata.buyTime - let timestamp=Clock.time() - if timestamp < time { - panic("You cannot buy the pack yet") - } - - if vault.getType() != metadata.walletType { - panic("The vault sent in is not of the desired type ".concat(metadata.walletType.identifier)) - } - - - if metadata.price != vault.balance { - panic("Vault does not contain required amount of FT ".concat(metadata.price.toString())) - } - - let keyList = Crypto.KeyList() - let accountKey = self.owner!.keys.get(keyIndex: 0)!.publicKey - - // Adds the public key to the keyList - keyList.add( - PublicKey( - publicKey: accountKey.publicKey, - signatureAlgorithm: accountKey.signatureAlgorithm - ), - hashAlgorithm: HashAlgorithm.SHA3_256, - weight: 1.0 - ) - - // Creates a Crypto.KeyListSignature from the signature provided in the parameters - let signatureSet: [Crypto.KeyListSignature] = [] - signatureSet.append( - Crypto.KeyListSignature( - keyIndex: 0, - signature: signature.decodeHex() - ) - ) - - // Verifies that the signature is valid and that it was generated from the - // owner of the collection - if(!keyList.verify(signatureSet: signatureSet, signedData: nft.hash.utf8)){ - panic("Unable to validate the signature for the pack!") - } - - if metadata.royaltyCut != 0.0 && metadata.royaltyCap != nil && metadata.royaltyCap!.check() { - metadata.royaltyCap!.borrow()!.deposit(from: <- vault.withdraw(amount: vault.balance * metadata.royaltyCut)) - } - - metadata.wallet.borrow()!.deposit(from: <- vault) - collectionCapability.borrow()!.deposit(token: <- nft) - - emit Purchased(packId: packId, address: collectionCapability.address, amount:metadata.price) - } - - pub fun buy(typeId: UInt64, vault: @FungibleToken.Vault, collectionCapability: Capability<&Collection{NonFungibleToken.Receiver}>) { - pre { - self.owner!.address == Bl0xPack.account.address : "You can only buy pack directly from the Bl0xPack account" - } - - let packId= self.getPackIdForType(typeId) - if packId == nil { - panic("No more packs of this type") - } - let key=packId! - let nft <- self.withdraw(withdrawID: key) as! @NFT - let metadata= nft.getMetadata() - - if metadata.requiresReservation { - panic("Cannot buy a pack that requires reservation without a reservation signature and id") - } - - let user=collectionCapability.address - let timestamp=Clock.time() - var whitelisted= false - if let whiteListTime = metadata.whiteListTime { - - //TODO: test - if timestamp < whiteListTime { - panic("You cannot buy the pack yet") - } - - //TODO: test - if let float=metadata.floatEventId { - whitelisted=Bl0xPack.hasFloat(floatEventId:float, user:collectionCapability.address) - } - } else { - - if let float=metadata.floatEventId { - //TODO:test - if !Bl0xPack.hasFloat(floatEventId:float, user:collectionCapability.address) { - panic("Your user does not have the required float with eventId ".concat(float.toString())) - } - } - } - - var time= metadata.buyTime - if !whitelisted && timestamp < time { - panic("You cannot buy the pack yet") - } - - if vault.getType() != metadata.walletType { - panic("The vault sent in is not of the desired type ".concat(metadata.walletType.identifier)) - } - - if metadata.price != vault.balance { - panic("Vault does not contain required amount of FT ".concat(metadata.price.toString())) - } - - //TODO: test - if metadata.royaltyCut != 0.0 && metadata.royaltyCap != nil && metadata.royaltyCap!.check() { - metadata.royaltyCap!.borrow()!.deposit(from: <- vault.withdraw(amount: vault.balance * metadata.royaltyCut)) - } - - metadata.wallet.borrow()!.deposit(from: <- vault) - collectionCapability.borrow()!.deposit(token: <- nft) - - emit Purchased(packId: key, address: collectionCapability.address, amount:metadata.price) - } - - - // withdraw - // Removes an NFT from the collection and moves it to the caller - // - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Could not withdraw nft") - - let nft <- token as! @NFT - - let oldNumber= self.nftsPerType[nft.getTypeID()]! - self.nftsPerType[nft.getTypeID()]=oldNumber-1 - - emit Withdraw(id: nft.id, from: self.owner?.address) - - - return <-nft - } - - // deposit - // Takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - // - pub fun deposit(token: @NonFungibleToken.NFT) { - let token <- token as! @Bl0xPack.NFT - - let id: UInt64 = token.id - - let oldNumber= self.nftsPerType[token.getTypeID()] ?? 0 - self.nftsPerType[token.getTypeID()]=oldNumber+1 - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) - - destroy oldToken - } - - // getIDs - // Returns an array of the IDs that are in the collection - // - pub fun getIDs(): [UInt64] { - return self.ownedNFTs.keys - } - - //return the number of packs left of a type - pub fun getPacksLeftForType(_ type:UInt64) : UInt64 { - return self.nftsPerType[type] ?? 0 - } - - // borrowNFT - // Gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - // - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! - } - - // borrowBl0xPack - // Gets a reference to an NFT in the collection as a Bl0xPack.NFT, - // exposing all of its fields. - // This is safe as there are no functions that can be called on the Bl0xPack. - // - pub fun borrowBl0xPack(id: UInt64): &Bl0xPack.NFT? { - if self.ownedNFTs[id] != nil { - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - return ref as! &Bl0xPack.NFT - } else { - return nil - } - } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let exampleNFT = nft as! &NFT - return exampleNFT - } - - // destructor - // - destroy() { - destroy self.ownedNFTs - } - - // initializer - // - init () { - self.ownedNFTs <- {} - self.nftsPerType= {} - } - } - - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } - - access(account) fun mintNFT(recipient: &{NonFungibleToken.Receiver}, typeId: UInt64, hash: String){ - - let nft <- create Bl0xPack.NFT(typeId: typeId, hash:hash) - emit Minted(id: nft.id, typeId:typeId) - - // deposit it in the recipient's account using their reference - recipient.deposit(token: <- nft) - } - - access(account) fun fulfill(packId: UInt64, rewardIds:[UInt64], salt:String) { - - let openedPacksCollection = Bl0xPack.account.borrow<&Bl0xPack.Collection>(from: Bl0xPack.OpenedCollectionStoragePath)! - let pack <- openedPacksCollection.withdraw(withdrawID: packId) as! @Bl0xPack.NFT - - let receiver= pack.getOpenedBy() - if !receiver.check() { - emit FulfilledError(packId:packId, address:receiver.address, reason: "The receiver registered in this pack is not valid") - self.transferToDLQ(<- pack) - return - } - - let hash= pack.getHash() - let rewards=pack.getMetadata().providerCap - - if !rewards.check() { - emit FulfilledError(packId:packId, address:receiver.address, reason: "Cannot borrow provider capability to withdraw nfts") - self.transferToDLQ(<- pack) - return - } - - let receiverAccount=getAccount(receiver.address) - let freeStorage=receiverAccount.storageCapacity - receiverAccount.storageUsed - Debug.log("Free capacity from account ".concat(freeStorage.toString())) - - if pack.getMetadata().storageRequirement > freeStorage { - emit FulfilledError(packId:packId, address:receiver.address, reason: "Not enough flow to hold the content of the pack. Please top up your account") - self.transferToDLQ(<- pack) - return - } - - var string=salt - for id in rewardIds { - var seperator="-" - if string!=salt { - seperator="," - } - string=string.concat(seperator).concat(id.toString()) - } - - let digest = HashAlgorithm.SHA3_384.hash(string.utf8) - let digestAsString=String.encodeHex(digest) - if digestAsString != hash { - emit FulfilledError(packId:packId, address:receiver.address, reason: "The content of the pack was not verified with the hash provided at mint") - self.transferToDLQ(<- pack) - return - } - - let target=receiver.borrow()! - let source=rewards.borrow()! - for reward in rewardIds { - - let metadata=source.borrowViewResolver(id: reward).resolveView(Type())! as! Bl0x.Metadata - emit PackReveal(packId:packId, address:receiver.address, packTypeId: pack.getTypeID(), rewardId: reward, nftName:metadata.name, nftImage:metadata.image, nftRarity: metadata.rarity) - let token <- source.withdraw(withdrawID: reward) - target.deposit(token: <-token) - } - emit Fulfilled(packId:packId, address:receiver.address) - - destroy pack - } - - access(account) fun transferToDLQ(_ pack: @NFT) { - let dlq = Bl0xPack.account.borrow<&Bl0xPack.Collection>(from: Bl0xPack.DLQCollectionStoragePath)! - dlq.deposit(token: <- pack) - } - - - pub fun getPacksCollection() : &Bl0xPack.Collection{CollectionPublic} { - return Bl0xPack.account.getCapability<&Bl0xPack.Collection{Bl0xPack.CollectionPublic}>(Bl0xPack.CollectionPublicPath).borrow() ?? panic("Could not borow Bl0xPack collection") - } - - pub fun canBuy(packTypeId:UInt64, user:Address) : Bool { - - let packs=Bl0xPack.getPacksCollection() - - let packsLeft= packs.getPacksLeftForType(packTypeId) - if packsLeft == 0 { - return false - } - - let packMetadata=Bl0xPack.getMetadata(typeId: packTypeId) - - if packMetadata==nil { - return false - } - let timestamp=Clock.time() - - let metadata=packMetadata! - var whitelisted= false - if let whiteListTime = metadata.whiteListTime { - if timestamp < whiteListTime { - return false - } - - if let float=metadata.floatEventId { - whitelisted=Bl0xPack.hasFloat(floatEventId:float, user:user) - } - } else { - if let float=metadata.floatEventId { - if !Bl0xPack.hasFloat(floatEventId:float, user:user) { - return false - } - } - } - - var time= metadata.buyTime - if !whitelisted && timestamp < time { - return false - } - return true - } - - pub fun hasFloat(floatEventId:UInt64, user:Address) : Bool { - - let float = getAccount(user).getCapability(FLOAT.FLOATCollectionPublicPath).borrow<&FLOAT.Collection{FLOAT.CollectionPublic}>() - - if float == nil { - return false - } - - let floatsCollection=float! - - let ids = floatsCollection.getIDs() - for id in ids { - let nft: &FLOAT.NFT = floatsCollection.borrowFLOAT(id: id)! - if nft.eventId==floatEventId { - return true - } - } - return false - } - - // initializer - // - init() { - self.CollectionStoragePath = /storage/Bl0xPackCollection - self.CollectionPublicPath = /public/Bl0xPackCollection - - self.OpenedCollectionStoragePath = /storage/Bl0xPackOpenedCollection - self.OpenedCollectionPublicPath = /public/Bl0xPackOpenedCollection - - self.DLQCollectionStoragePath = /storage/Bl0xPackDLQCollection - self.DLQCollectionPublicPath = /public/Bl0xPackDLQCollection + let packId= self.getPackIdForType(typeId) + if packId == nil { + panic("No more packs of this type") + } + let key=packId! + let nft <- self.withdraw(withdrawID: key) as! @NFT + let metadata= nft.getMetadata() + + if metadata.requiresReservation { + panic("Cannot buy a pack that requires reservation without a reservation signature and id") + } + + let user=collectionCapability.address + let timestamp=Clock.time() + var whitelisted= false + if let whiteListTime = metadata.whiteListTime { + + if timestamp < whiteListTime { + panic("You cannot buy the pack yet") + } + + if let float=metadata.floatEventId { + whitelisted=Bl0xPack.hasFloat(floatEventId:float, user:collectionCapability.address) + } + } else { + + if let float=metadata.floatEventId { + if !Bl0xPack.hasFloat(floatEventId:float, user:collectionCapability.address) { + panic("Your user does not have the required float with eventId ".concat(float.toString())) + } + } + } + + var time= metadata.buyTime + if !whitelisted && timestamp < time { + panic("You cannot buy the pack yet") + } + + if vault.getType() != metadata.walletType { + panic("The vault sent in is not of the desired type ".concat(metadata.walletType.identifier)) + } + + if metadata.price != vault.balance { + panic("Vault does not contain required amount of FT ".concat(metadata.price.toString())) + } + + if metadata.royaltyCut != 0.0 && metadata.royaltyCap != nil && metadata.royaltyCap!.check() { + metadata.royaltyCap!.borrow()!.deposit(from: <- vault.withdraw(amount: vault.balance * metadata.royaltyCut)) + } + + metadata.wallet.borrow()!.deposit(from: <- vault) + collectionCapability.borrow()!.deposit(token: <- nft) + + emit Purchased(packId: key, address: collectionCapability.address, amount:metadata.price) + } + + + // withdraw + // Removes an NFT from the collection and moves it to the caller + // + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Could not withdraw nft") + + let nft <- token as! @Bl0xPack.NFT + + let oldNumber= self.nftsPerType[nft.getTypeID()]! + self.nftsPerType[nft.getTypeID()]=oldNumber-1 + + emit Withdraw(id: nft.id, from: self.owner?.address) + + + return <-nft + } + + // deposit + // Takes a NFT and adds it to the collections dictionary + // and adds the ID to the id array + // + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { + let token <- token as! @Bl0xPack.NFT + + let id: UInt64 = token.id + + let oldNumber= self.nftsPerType[token.getTypeID()] ?? 0 + self.nftsPerType[token.getTypeID()]=oldNumber+1 + // add the new token to the dictionary which removes the old one + let oldToken <- self.ownedNFTs[id] <- token + + emit Deposit(id: id, to: self.owner?.address) + + destroy oldToken + } + + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create Bl0xPack.Collection() + } + + // getIDs + // Returns an array of the IDs that are in the collection + // + access(all) view fun getIDs(): [UInt64] { + return self.ownedNFTs.keys + } + + //return the number of packs left of a type + access(all) view fun getPacksLeftForType(_ type:UInt64) : UInt64 { + return self.nftsPerType[type] ?? 0 + } + + // borrowNFT + // Gets a reference to an NFT in the collection + // so that the caller can read its metadata and call its methods + // + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] + } + + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[Type<@Bl0xPack.NFT>()] = true + return supportedTypes + } + + /// Return the default storage path for the collection + access(all) view fun getDefaultStoragePath(): StoragePath? { + return self.storagePath + } + + /// Return the default public path for the collection + access(all) view fun getDefaultPublicPath(): PublicPath? { + return self.publicPath + } + + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + access(all) view fun isSupportedNFTType(type: Type): Bool { + if type == Type<@Bl0xPack.NFT>() { + return true + } else { + return false + } + } + + // borrowBl0xPack + // Gets a reference to an NFT in the collection as a Bl0xPack.NFT, + // exposing all of its fields. + // This is safe as there are no functions that can be called on the Bl0xPack. + // + access(all) fun borrowBl0xPack(id: UInt64): &Bl0xPack.NFT? { + if self.ownedNFTs[id] != nil { + let ref = ((&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) as! &Bl0xPack.NFT?) + return ref + } else { + return nil + } + } + + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? { + if let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) as!&Bl0xPack.NFT? { + return nft as &{ViewResolver.Resolver} + } + return nil + } + + // initializer + // + init () { + self.ownedNFTs <- {} + self.nftsPerType= {} + let identifier = "bl0xPackNFTCollection" + self.storagePath = StoragePath(identifier: identifier)! + self.publicPath = PublicPath(identifier: identifier)! + } + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create Collection() + } + + access(account) fun mintNFT(recipient: &{NonFungibleToken.Receiver}, typeId: UInt64, hash: String){ + + let nft <- create Bl0xPack.NFT(typeId: typeId, hash:hash) + emit Minted(id: nft.id, typeId:typeId) + + // deposit it in the recipient's account using their reference + recipient.deposit(token: <- nft) + } + + access(account) fun fulfill(packId: UInt64, rewardIds:[UInt64], salt:String) { + + let openedPacksCollection = Bl0xPack.account.storage.borrow(from: Bl0xPack.OpenedCollectionStoragePath)! + let pack <- openedPacksCollection.withdraw(withdrawID: packId) as! @Bl0xPack.NFT + + let receiver= pack.getOpenedBy() + if !receiver.check() { + emit FulfilledError(packId:packId, address:receiver.address, reason: "The receiver registered in this pack is not valid") + self.transferToDLQ(<- pack) + return + } + + let hash= pack.getHash() + let rewards=pack.getMetadata().providerCap + + if !rewards.check() { + emit FulfilledError(packId:packId, address:receiver.address, reason: "Cannot borrow provider capability to withdraw nfts") + self.transferToDLQ(<- pack) + return + } + + let receiverAccount=getAccount(receiver.address) + let freeStorage=receiverAccount.storage.capacity - receiverAccount.storage.used + Debug.log("Free capacity from account ".concat(freeStorage.toString())) + + if pack.getMetadata().storageRequirement > freeStorage { + emit FulfilledError(packId:packId, address:receiver.address, reason: "Not enough flow to hold the content of the pack. Please top up your account") + self.transferToDLQ(<- pack) + return + } + + var string=salt + for id in rewardIds { + var seperator="-" + if string!=salt { + seperator="," + } + string=string.concat(seperator).concat(id.toString()) + } + + let digest = HashAlgorithm.SHA3_384.hash(string.utf8) + let digestAsString=String.encodeHex(digest) + if digestAsString != hash { + emit FulfilledError(packId:packId, address:receiver.address, reason: "The content of the pack was not verified with the hash provided at mint") + self.transferToDLQ(<- pack) + return + } + + let target=receiver.borrow()! + let source=rewards.borrow()! + for reward in rewardIds { + + let metadata=source.borrowViewResolver(id: reward)!.resolveView(Type())! as! Bl0x.Metadata + emit PackReveal(packId:packId, address:receiver.address, packTypeId: pack.getTypeID(), rewardId: reward, nftName:metadata.name, nftImage:metadata.image, nftRarity: metadata.rarity) + let token <- source.withdraw(withdrawID: reward) + target.deposit(token: <-token) + } + emit Fulfilled(packId:packId, address:receiver.address) + + destroy pack + } + + access(account) fun transferToDLQ(_ pack: @NFT) { + let dlq = Bl0xPack.account.storage.borrow<&Bl0xPack.Collection>(from: Bl0xPack.DLQCollectionStoragePath)! + dlq.deposit(token: <- pack) + } + + + access(all) fun getPacksCollection() : &Bl0xPack.Collection { + return Bl0xPack.account.capabilities.borrow<&Bl0xPack.Collection>(Bl0xPack.CollectionPublicPath) ?? panic("Could not borow Bl0xPack collection") + } + + access(all) fun canBuy(packTypeId:UInt64, user:Address) : Bool { + + let packs=Bl0xPack.getPacksCollection() + + let packsLeft= packs.getPacksLeftForType(packTypeId) + if packsLeft == 0 { + return false + } + + let packMetadata=Bl0xPack.getMetadata(typeId: packTypeId) + + if packMetadata==nil { + return false + } + let timestamp=Clock.time() + + let metadata=packMetadata! + var whitelisted= false + if let whiteListTime = metadata.whiteListTime { + if timestamp < whiteListTime { + return false + } + + if let float=metadata.floatEventId { + whitelisted=Bl0xPack.hasFloat(floatEventId:float, user:user) + } + } else { + if let float=metadata.floatEventId { + if !Bl0xPack.hasFloat(floatEventId:float, user:user) { + return false + } + } + } + + var time= metadata.buyTime + if !whitelisted && timestamp < time { + return false + } + return true + } + + access(all) fun hasFloat(floatEventId:UInt64, user:Address) : Bool { + + let float = getAccount(user).capabilities.borrow<&FLOAT.Collection>(FLOAT.FLOATCollectionPublicPath) + + if float == nil { + return false + } + + let floatsCollection=float! + + let ids = floatsCollection.getIDs() + for id in ids { + let nft: &FLOAT.NFT = floatsCollection.borrowFLOAT(id: id)! + if nft.eventId==floatEventId { + return true + } + } + return false + } + + // initializer + // + init() { + self.CollectionStoragePath = /storage/Bl0xPackCollection + self.CollectionPublicPath = /public/Bl0xPackCollection + + self.OpenedCollectionStoragePath = /storage/Bl0xPackOpenedCollection + self.OpenedCollectionPublicPath = /public/Bl0xPackOpenedCollection + + self.DLQCollectionStoragePath = /storage/Bl0xPackDLQCollection + self.DLQCollectionPublicPath = /public/Bl0xPackDLQCollection + + self.PackMetadataStoragePath= /storage/Bl0xPackMetadata - self.PackMetadataStoragePath= /storage/Bl0xPackMetadata + //this will not be used, we use UUID as id + self.totalSupply = 0 + + self.packMetadata={} - //this will not be used, we use UUID as id - self.totalSupply = 0 + // this contract will hold a Collection that Bl0xPack can be deposited to and Admins can Consume them to transfer nfts to the depositing account + let openedCollection <- create Collection() + self.account.storage.save(<- openedCollection, to: self.OpenedCollectionStoragePath) + let openedCollectionCap = self.account.capabilities.storage.issue<&Bl0xPack.Collection>(self.OpenedCollectionStoragePath) + self.account.capabilities.publish(openedCollectionCap, at: self.OpenedCollectionPublicPath) - self.packMetadata={} - // this contract will hold a Collection that Bl0xPack can be deposited to and Admins can Consume them to transfer nfts to the depositing account - let openedCollection <- create Collection() - self.account.save(<- openedCollection, to: self.OpenedCollectionStoragePath) - self.account.link<&Bl0xPack.Collection{NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, Bl0xPack.CollectionPublic, MetadataViews.ResolverCollection}>(Bl0xPack.OpenedCollectionPublicPath, target: Bl0xPack.OpenedCollectionStoragePath) + //a DLQ storage slot so that the opener can put items that cannot be opened/transferred here. + let dlqCollection <- create Collection() + self.account.storage.save(<- dlqCollection, to: self.DLQCollectionStoragePath) + let dlqCollectionCap = self.account.capabilities.storage.issue<&Bl0xPack.Collection>(self.DLQCollectionStoragePath) + self.account.capabilities.publish(dlqCollectionCap, at: self.DLQCollectionPublicPath) - //a DLQ storage slot so that the opener can put items that cannot be opened/transferred here. - let dlqCollection <- create Collection() - self.account.save(<- dlqCollection, to: self.DLQCollectionStoragePath) - self.account.link<&Bl0xPack.Collection{NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, Bl0xPack.CollectionPublic, MetadataViews.ResolverCollection}>(Bl0xPack.DLQCollectionPublicPath, target: Bl0xPack.DLQCollectionStoragePath) - - self.account.save<@NonFungibleToken.Collection>( <- self.createEmptyCollection(), to: self.CollectionStoragePath) - - self.account.link<&Bl0xPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, Bl0xPack.CollectionPublic, MetadataViews.ResolverCollection}>( - Bl0xPack.CollectionPublicPath, - target: Bl0xPack.CollectionStoragePath - ) - - emit ContractInitialized() - - } -} + self.account.storage.save( <- self.createEmptyCollection(), to: self.CollectionStoragePath) + let collectionCap = self.account.capabilities.storage.issue<&Bl0xPack.Collection>(self.CollectionStoragePath) + self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath) + + emit ContractInitialized() + } + } diff --git a/contracts/CharityNFT.cdc b/contracts/CharityNFT.cdc index d2439a54..c9fdfcf0 100644 --- a/contracts/CharityNFT.cdc +++ b/contracts/CharityNFT.cdc @@ -1,254 +1,311 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" - -pub contract CharityNFT: NonFungibleToken { - - pub var totalSupply: UInt64 - - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id: UInt64, metadata: {String:String}, to:Address) - - pub resource NFT: NonFungibleToken.INFT, Public, MetadataViews.Resolver { - pub let id: UInt64 - - access(self) let metadata: {String: String} - - init(initID: UInt64, metadata: {String : String}) { - self.id = initID - self.metadata = metadata - } - - pub fun getMetadata() : { String : String} { - return self.metadata - } - - pub fun getViews(): [Type] { - return [ - Type() , - Type() , - Type() , - Type() , - Type() , - Type() - ] - } - - pub fun resolveView(_ view: Type): AnyStruct? { - switch view { - - case Type() : - // just in case there is no "image" key, return the general bronze image - let image = self.metadata["thumbnail"] ?? "ipfs://QmcxXHLADpcw5R7xi6WmPjnKAEayK3eiEh85gzjgdzfwN6" - return MetadataViews.Display( - name: self.metadata["name"] ?? "Neo Charity 2021" , - description: self.metadata["description"] ?? "Neo Charity 2021", - thumbnail: MetadataViews.IPFSFile( - cid: image.slice(from: "ipfs://".length, upTo: image.length) , - path: nil - ) - ) - - case Type() : - // No Royalties implemented - return MetadataViews.Royalties([]) - - case Type() : - return MetadataViews.ExternalURL("http://find.xyz/neoCharity") - - case Type() : - return MetadataViews.NFTCollectionDisplay( - name: "Neo Charity 2021", - description: "This collection is to show participation in the Neo Collectibles x Flowverse Charity Auction in 2021.", - externalURL: MetadataViews.ExternalURL("http://find.xyz/neoCharity"), - squareImage: MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_images/1467546091780550658/R1uc6dcq_400x400.jpg") , mediaType: "image"), - bannerImage: MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1448245049666510848/1652452073/1500x500") , mediaType: "image"), - socials: { - "Twitter" : MetadataViews.ExternalURL("https://twitter.com/findonflow") , - "Discord" : MetadataViews.ExternalURL("https://discord.gg/95P274mayM") - } - ) - - case Type() : - return MetadataViews.NFTCollectionData( - storagePath: CharityNFT.CollectionStoragePath, - publicPath: CharityNFT.CollectionPublicPath, - providerPath: /private/findCharityCollection, - publicCollection: Type<&CharityNFT.Collection{CharityNFT.CollectionPublic}>(), - publicLinkedType: Type<&CharityNFT.Collection{NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, CharityNFT.CollectionPublic, MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&CharityNFT.Collection{NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, CharityNFT.CollectionPublic, MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: fun () : @NonFungibleToken.Collection { - return <- CharityNFT.createEmptyCollection() - } - ) - - case Type() : - let edition = self.metadata["edition"] - let maxEdition = self.metadata["maxEdition"] - if edition == nil || maxEdition == nil { - return nil - } - let editionNumber = self.parseUInt64(edition!) - let maxEditionNumber = self.parseUInt64(maxEdition!) - if editionNumber == nil { - return nil - } - return MetadataViews.Edition( - name: nil, - number: editionNumber!, - max: editionNumber - ) - - } - return nil - - } - - pub fun parseUInt64(_ string: String) : UInt64? { - let chars : {Character : UInt64} = { - "0" : 0 , - "1" : 1 , - "2" : 2 , - "3" : 3 , - "4" : 4 , - "5" : 5 , - "6" : 6 , - "7" : 7 , - "8" : 8 , - "9" : 9 - } - var number : UInt64 = 0 - var i = 0 - while i < string.length { - if let n = chars[string[i]] { - number = number * 10 + n - } else { - return nil - } - i = i + 1 - } - return number - } - - } - - //The public interface can show metadata and the content for the Art piece - pub resource interface Public { - pub let id: UInt64 - pub fun getMetadata() : {String : String} - } - - //Standard NFT collectionPublic interface that can also borrowArt as the correct type - pub resource interface CollectionPublic { - - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowCharity(id: UInt64): &{Public}? - } - - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, CollectionPublic , MetadataViews.ResolverCollection{ - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} - - init () { - self.ownedNFTs <- {} - } - - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT. WithdrawID : ".concat(withdrawID.toString())) - - emit Withdraw(id: token.id, from: self.owner?.address) - - return <-token - } - - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { - let token <- token as! @CharityNFT.NFT - - let id: UInt64 = token.id - - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) - - destroy oldToken - } - - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { - return self.ownedNFTs.keys - } - - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! - } - - //borrow charity - pub fun borrowCharity(id: UInt64): &{CharityNFT.Public}? { - if self.ownedNFTs[id] != nil { - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - return ref as! &NFT - } else { - return nil - } - } - - //borrow view resolver - pub fun borrowViewResolver(id: UInt64): &{MetadataViews.Resolver} { - if self.ownedNFTs[id] == nil { - panic("NFT does not exist. ID : ".concat(id.toString())) - } - - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - return nft as! &CharityNFT.NFT - } - - destroy() { - destroy self.ownedNFTs - } - } - - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } - - - // mintNFT mints a new NFT with a new ID - // and deposit it in the recipients collection using their collection reference - access(account) fun mintCharity(metadata: {String:String}, recipient: Capability<&{NonFungibleToken.CollectionPublic}>) { - - // create a new NFT - var newNFT <- create NFT(initID: CharityNFT.totalSupply, metadata:metadata) - - // deposit it in the recipient's account using their reference - let collectionRef = recipient.borrow() ?? panic("Cannot borrow reference to collection public. ") - collectionRef.deposit(token: <-newNFT) - emit Minted(id: CharityNFT.totalSupply, metadata:metadata, to: recipient.address) - - CharityNFT.totalSupply = CharityNFT.totalSupply + 1 - } - - init() { - // Initialize the total supply - self.totalSupply = 0 - - emit ContractInitialized() - self.CollectionPublicPath=/public/findCharityCollection - self.CollectionStoragePath=/storage/findCharityCollection - } +import "NonFungibleToken" +import "MetadataViews" +import "ViewResolver" + +access(all) contract CharityNFT: NonFungibleToken { + + access(all) var totalSupply: UInt64 + + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Minted(id: UInt64, metadata: {String:String}, to:Address) + + access(all) resource NFT: NonFungibleToken.NFT, Public, ViewResolver.Resolver { + access(all) let id: UInt64 + + access(self) let metadata: {String: String} + + init(initID: UInt64, metadata: {String : String}) { + self.id = initID + self.metadata = metadata + } + + access(all) view fun getMetadata() : { String : String} { + return self.metadata + } + + access(all) view fun getID(): UInt64 { + return self.id + } + + access(all) view fun getViews(): [Type] { + return [ + Type() , + Type() , + Type() , + Type() , + Type() , + Type() + ] + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-CharityNFT.createEmptyCollection(nftType:Type<@CharityNFT.NFT>()) + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + + case Type() : + // just in case there is no "image" key, return the general bronze image + let image = self.metadata["thumbnail"] ?? "ipfs://QmcxXHLADpcw5R7xi6WmPjnKAEayK3eiEh85gzjgdzfwN6" + return MetadataViews.Display( + name: self.metadata["name"] ?? "Neo Charity 2021" , + description: self.metadata["description"] ?? "Neo Charity 2021", + thumbnail: MetadataViews.IPFSFile( + cid: image.slice(from: "ipfs://".length, upTo: image.length) , + path: nil + ) + ) + + case Type() : + // No Royalties implemented + return MetadataViews.Royalties([]) + + case Type() : + return MetadataViews.ExternalURL("http://find.xyz/neoCharity") + + case Type() : + return MetadataViews.NFTCollectionDisplay( + name: "Neo Charity 2021", + description: "This collection is to show participation in the Neo Collectibles x Flowverse Charity Auction in 2021.", + externalURL: MetadataViews.ExternalURL("http://find.xyz/neoCharity"), + squareImage: MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_images/1467546091780550658/R1uc6dcq_400x400.jpg") , mediaType: "image"), + bannerImage: MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1448245049666510848/1652452073/1500x500") , mediaType: "image"), + socials: { + "Twitter" : MetadataViews.ExternalURL("https://twitter.com/findonflow") , + "Discord" : MetadataViews.ExternalURL("https://discord.gg/95P274mayM") + } + ) + + case Type() : + return CharityNFT.resolveContractView(resourceType: Type<@CharityNFT.Collection>(), viewType: Type()) as! MetadataViews.NFTCollectionData + + case Type() : + let edition = self.metadata["edition"] + let maxEdition = self.metadata["maxEdition"] + if edition == nil || maxEdition == nil { + return nil + } + let editionNumber = self.parseUInt64(edition!) + let maxEditionNumber = self.parseUInt64(maxEdition!) + if editionNumber == nil { + return nil + } + return MetadataViews.Edition( + name: nil, + number: editionNumber!, + max: editionNumber + ) + + } + return nil + + } + + access(all) view fun parseUInt64(_ string: String) : UInt64? { + let chars : {Character : UInt64} = { + "0" : 0 , + "1" : 1 , + "2" : 2 , + "3" : 3 , + "4" : 4 , + "5" : 5 , + "6" : 6 , + "7" : 7 , + "8" : 8 , + "9" : 9 + } + var number : UInt64 = 0 + var i = 0 + while i < string.length { + if let n = chars[string[i]] { + number = number * 10 + n + } else { + return nil + } + i = i + 1 + } + return number + } + + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + + case Type() : + return MetadataViews.NFTCollectionDisplay( + name: "Neo Charity 2021", + description: "This collection is to show participation in the Neo Collectibles x Flowverse Charity Auction in 2021.", + externalURL: MetadataViews.ExternalURL("http://find.xyz/neoCharity"), + squareImage: MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_images/1467546091780550658/R1uc6dcq_400x400.jpg") , mediaType: "image"), + bannerImage: MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1448245049666510848/1652452073/1500x500") , mediaType: "image"), + socials: { + "Twitter" : MetadataViews.ExternalURL("https://twitter.com/findonflow") , + "Discord" : MetadataViews.ExternalURL("https://discord.gg/95P274mayM") + } + ) + + case Type(): + let collectionData = MetadataViews.NFTCollectionData( + storagePath: CharityNFT.CollectionStoragePath, + publicPath: CharityNFT.CollectionPublicPath, + publicCollection: Type<&CharityNFT.Collection>(), + publicLinkedType: Type<&CharityNFT.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-CharityNFT.createEmptyCollection(nftType:Type<@CharityNFT.NFT>()) + }) + ) + return collectionData + } + return nil + } + + //The public interface can show metadata and the content for the Art piece + access(all) resource interface Public { + access(all) let id: UInt64 + access(all) view fun getMetadata() : {String : String} + } + + //Standard NFT collectionPublic interface that can also borrowArt as the correct type + access(all) resource interface CollectionPublic { + access(all) fun deposit(token: @{NonFungibleToken.NFT}) + access(all) view fun getIDs(): [UInt64] + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? + access(all) fun borrowCharity(id: UInt64): &{Public}? + } + + access(all) resource Collection: NonFungibleToken.Collection, CollectionPublic , ViewResolver.ResolverCollection{ + // dictionary of NFT conforming tokens + // NFT is a resource type with an `UInt64` ID field + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + + init () { + self.ownedNFTs <- {} + let identifier = "charityNFTCollection" + } + + // withdraw removes an NFT from the collection and moves it to the caller + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT. WithdrawID : ".concat(withdrawID.toString())) + + emit Withdraw(id: token.id, from: self.owner?.address) + + return <-token + } + + // deposit takes a NFT and adds it to the collections dictionary + // and adds the ID to the id array + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { + let token <- token as! @CharityNFT.NFT + + let id: UInt64 = token.id + + // add the new token to the dictionary which removes the old one + let oldToken <- self.ownedNFTs[id] <- token + + emit Deposit(id: id, to: self.owner?.address) + + destroy oldToken + } + + // getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { + return self.ownedNFTs.keys + } + + // borrowNFT gets a reference to an NFT in the collection + // so that the caller can read its metadata and call its methods + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)! + } + + //borrow charity + access(all) fun borrowCharity(id: UInt64): &{CharityNFT.Public}? { + if self.ownedNFTs[id] != nil { + let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)! + return ref as! &NFT + } else { + return nil + } + } + + //borrow view resolver + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} { + if self.ownedNFTs[id] == nil { + panic("NFT does not exist. ID : ".concat(id.toString())) + } + + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)! + return nft as! &CharityNFT.NFT + } + + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[Type<@CharityNFT.NFT>()] = true + return supportedTypes + } + + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + access(all) view fun isSupportedNFTType(type: Type): Bool { + if type == Type<@CharityNFT.NFT>() { + return true + } else { + return false + } + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create CharityNFT.Collection() + } + + access(all) view fun getLength(): Int { + return self.ownedNFTs.keys.length + } + } + + // public function that anyone can call to create a new empty collection + access(all) fun createEmptyCollection(nftType:Type): @{NonFungibleToken.Collection} { + return <- create Collection() + } + + + // mintNFT mints a new NFT with a new ID + // and deposit it in the recipients collection using their collection reference + access(account) fun mintCharity(metadata: {String:String}, recipient: Capability<&{NonFungibleToken.Collection}>) { + // create a new NFT + var newNFT <- create NFT(initID: CharityNFT.totalSupply, metadata:metadata) + + // deposit it in the recipient's account using their reference + let collectionRef = recipient.borrow() ?? panic("Cannot borrow reference to collection public. ") + collectionRef.deposit(token: <-newNFT) + emit Minted(id: CharityNFT.totalSupply, metadata:metadata, to: recipient.address) + + CharityNFT.totalSupply = CharityNFT.totalSupply + 1 + } + + init() { + // Initialize the total supply + self.totalSupply = 0 + + emit ContractInitialized() + self.CollectionPublicPath=/public/findCharityCollection + self.CollectionStoragePath=/storage/findCharityCollection + } } diff --git a/contracts/Clock.cdc b/contracts/Clock.cdc index e692a2fd..822b8bb8 100644 --- a/contracts/Clock.cdc +++ b/contracts/Clock.cdc @@ -7,28 +7,28 @@ The clock will then start at block 0 use the tick method to tick the time. ``` - //this is used to mock the clock, NB! Should consider removing this before deploying to mainnet? - pub fun tickClock(_ time: UFix64) { - pre { - self.capability != nil: "Cannot use AdminProxy, ste capability first" - } - Clock.enable() - Clock.tick(time) - } +//this is used to mock the clock, NB! Should consider removing this before deploying to mainnet? +access(all) fun tickClock(_ time: UFix64) { + pre { + self.capability != nil: "Cannot use AdminProxy, ste capability first" + } + Clock.enable() + Clock.tick(time) +} ``` You can then call this from a transaction like this: ``` -import YourThing from "../contracts/YouThing.cdc" +import "YourThing" transaction(clock: UFix64) { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - let adminClient=account.borrow<&YourThing.AdminProxy>(from: YourThing.AdminProxyStoragePath)! - adminClient.tickClock(clock) + let adminClient=account.storage.borrow<&YourThing.AdminProxy>(from: YourThing.AdminProxyStoragePath)! + adminClient.tickClock(clock) - } + } } ``` @@ -39,36 +39,33 @@ Clock.time() ``` Limitations: - - all contracts must live in the same account to (ab)use this trick +- all contracts must live in the same account to (ab)use this trick */ -pub contract Clock{ - //want to mock time on emulator. - access(contract) var fakeClock:UFix64 - access(contract) var enabled:Bool - - - access(account) fun tick(_ duration: UFix64) { - self.fakeClock = self.fakeClock + duration - } - - - access(account) fun enable() { - self.enabled=true - } - - //mocking the time! Should probably remove self.fakeClock in mainnet? - pub fun time() : UFix64 { - if self.enabled { - return self.fakeClock - } - return getCurrentBlock().timestamp - } - - init() { - self.fakeClock=0.0 - self.enabled=false - } - +access(all) contract Clock{ + //want to mock time on emulator. + access(contract) var fakeClock:UFix64 + access(contract) var enabled:Bool + + access(account) fun tick(_ duration: UFix64) { + self.fakeClock = self.fakeClock + duration + } + + access(account) fun enable() { + self.enabled=true + } + + //mocking the time! Should probably remove self.fakeClock in mainnet? + access(all) fun time() : UFix64 { + if self.enabled { + return self.fakeClock + } + return getCurrentBlock().timestamp + } + + init() { + self.fakeClock=0.0 + self.enabled=false + } } diff --git a/contracts/CollectionFactory.cdc b/contracts/CollectionFactory.cdc deleted file mode 100644 index f44d8a28..00000000 --- a/contracts/CollectionFactory.cdc +++ /dev/null @@ -1,1012 +0,0 @@ -// /* Alchemy Mainnet Wrapper */ -// import AlchemyMetadataWrapperMainnetShard1 from 0xeb8cb4c3157d5dac -// import AlchemyMetadataWrapperMainnetShard2 from 0xeb8cb4c3157d5dac -// import AlchemyMetadataWrapperMainnetShard3 from 0xeb8cb4c3157d5dac -// import AlchemyMetadataWrapperMainnetShard4 from 0xeb8cb4c3157d5dac - -// /* Alchemy Testnet Wrapper */ - -// import AlchemyMetadataWrapperTestnetShard1 from 0x5ff2c7b4c40de11 -// import AlchemyMetadataWrapperTestnetShard2 from 0x5ff2c7b4c40de11 -// import AlchemyMetadataWrapperTestnetShard3 from 0x5ff2c7b4c40de11 - - -/* NFTRegistry */ -/* In order to deploy this contract on testnet/mainet you have to comment out the code above for the relevant network */ -/* Note that if this is changed there are code in tasks/collectionFactoryTest that also must be changed */ -import NFTRegistry from "../contracts/NFTRegistry.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FIND from "../contracts/FIND.cdc" - -pub contract CollectionFactory { - - pub let FlowverseSocksIds : [UInt64] - - pub struct CollectionReport { - pub let items : {String : [MetadataCollectionItem]} - pub let collections : {String : Int} // mapping of collection to no. of ids - pub let extraIDs : {String : [UInt64]} - - init(items: {String : [MetadataCollectionItem]}, collections : {String : Int}, extraIDs : {String : [UInt64]} ) { - self.items=items - self.collections=collections - self.extraIDs=extraIDs - } - } - - pub struct MetadataCollectionItem { - pub let id:UInt64 - pub let name: String - pub let collection: String // <- This will be Alias unless they want something else - pub let subCollection: String? // <- This will be Alias unless they want something else - - pub let media : String - pub let mediaType : String - pub let source : String - - init(id:UInt64, name: String, collection: String, subCollection: String?, media : String, mediaType : String, source : String) { - self.id=id - self.name=name - self.collection=collection - self.subCollection=subCollection - self.media=media - self.mediaType=mediaType - self.source=source - } - } - - /* - Raw Response from Alchemy getNFTs() - - [ - { - "contract": { - "address": "0xf6fcbef550d97aa5", - "external_domain": "", - "name": "Mynft", - "public_collection_name": "Mynft.MynftCollectionPublic", - "public_path": "Mynft.CollectionPublicPath", - "storage_path": "Mynft.CollectionStoragePath" - }, - "description": "\"Congratulations, you have won the S level Painting \\u{300c}Lightning\\u{300d}! You will be able to apply the painting to your own car after the game launch. This painting series is specifically designed for Flow Fest Mystery Pack event and no other copies will be made ever again. The owners of these NFTs will be regarded as the earliest supporters of the Racing Time. \"", - "external_domain_view_url": "", - "id": "27226", - "media": [ - { - "mimetype": "image/jpeg", - "uri": "https://bafybeiacezpbfkmspzkvtrim6ucdczqerzi4miectybtuhaskflov7gipq.ipfs.dweb.link/" - } - ], - "metadata": { - "MD5Hash": "", - "arLink": "", - "artist": "", - "description": "\"Congratulations, you have won the S level Painting \\u{300c}Lightning\\u{300d}! You will be able to apply the painting to your own car after the game launch. This painting series is specifically designed for Flow Fest Mystery Pack event and no other copies will be made ever again. The owners of these NFTs will be regarded as the earliest supporters of the Racing Time. \"", - "ipfsLink": "https://bafybeiacezpbfkmspzkvtrim6ucdczqerzi4miectybtuhaskflov7gipq.ipfs.dweb.link/", - "name": "Lightning", - "type": "image/jpeg" - }, - "title": "Lightning", - "token_uri": "", - "uuid": "60581263" - }, - { - "contract": { - "address": "0xf6fcbef550d97aa5", - "external_domain": "", - "name": "Mynft", - "public_collection_name": "Mynft.MynftCollectionPublic", - "public_path": "Mynft.CollectionPublicPath", - "storage_path": "Mynft.CollectionStoragePath" - }, - "description": "Mynft is a Flow-based NFT platform designed to connect east and west market, and Mynft specifically launched Chinese Four Symbols themes NFT for Flow Festival. Vermilion Bird is a red bird with a five-colored plumage and is perpetually covered in flames, represents the fire-element, the direction south, and the season summer correspondingly.", - "external_domain_view_url": "", - "id": "13958", - "media": [ - { - "mimetype": "image/jpg", - "uri": "" - } - ], - "metadata": { - "MD5Hash": "19e229e53893e156d6eb901ab75cb78b", - "arLink": "-MJ1l-82OrTWbye3HWJRAS8Y4UKQV9B6u4T73F4x51c", - "artist": "", - "description": "Mynft is a Flow-based NFT platform designed to connect east and west market, and Mynft specifically launched Chinese Four Symbols themes NFT for Flow Festival. Vermilion Bird is a red bird with a five-colored plumage and is perpetually covered in flames, represents the fire-element, the direction south, and the season summer correspondingly.", - "ipfsLink": "", - "name": "Vermilion Bird #114", - "type": "image/jpg" - }, - "title": "Vermilion Bird #114", - "token_uri": "", - "uuid": "60194724" - } -] - */ - - ////////////////////////////////////////////////////////////// - // Get all collections - ////////////////////////////////////////////////////////////// - pub fun getCollections(user: String, maxItems: Int, collections: [String], shard: String) : CollectionReport? { - switch shard { - - // case "Alchemy-shard1": - // return self.fetchAlchemyShard1(user: user, maxItems: maxItems, targetCollections:collections) - // case "Alchemy-shard2": - // return self.fetchAlchemyShard2(user: user, maxItems: maxItems, targetCollections:collections) - // case "Alchemy-shard3": - // return self.fetchAlchemyShard3(user: user, maxItems: maxItems, targetCollections:collections) - - // case "Alchemy-shard4": - // return self.fetchAlchemyShard4(user: user, maxItems: maxItems, targetCollections:collections) - case "NFTRegistry": - return self.fetchNFTRegistry(user: user, maxItems: maxItems, targetCollections:collections) - } - panic("Shard should only be : Alchemy-shard1, Alchemy-shard2,Alchemy-shard3 or NFTRegistry") - } - - ////////////////////////////////////////////////////////////// - // Get specific collections - ////////////////////////////////////////////////////////////// - pub fun getCollection(user: String, collectionIDs: {String : [UInt64]}, shard: String) : {String : [MetadataCollectionItem]} { - switch shard { - - // case "Alchemy-shard1": - // return self.fetchAlchemyCollectionShard1(user: user, collectionIDs: collectionIDs) - // case "Alchemy-shard2": - // return self.fetchAlchemyCollectionShard2(user: user, collectionIDs: collectionIDs) - // case "Alchemy-shard3": - // return self.fetchAlchemyCollectionShard3(user: user, collectionIDs: collectionIDs) - - // case "Alchemy-shard4": - // return self.fetchAlchemyCollectionShard4(user: user, collectionIDs: collectionIDs) - case "NFTRegistry": - return self.fetchNFTRegistryCollection(user: user, collectionIDs: collectionIDs) - - - } - panic("Shard should only be : Alchemy-shard1, Alchemy-shard2,Alchemy-shard3 or NFTRegistry") - } - - - // Helper function - - pub fun resolveAddress(user: String) : PublicAccount? { - let address = FIND.resolve(user) - if address == nil { - return nil - } - return getAccount(address!) - } - - ////////////////////////////////////////////////////////////// - // Fetch All Collections in NFTRegistry - ////////////////////////////////////////////////////////////// - pub fun fetchNFTRegistry(user: String, maxItems: Int, targetCollections:[String]) : CollectionReport? { - let source = "NFTRegistry" - let account = self.resolveAddress(user: user) - if account == nil { return nil } - - var counter = 0 - var fetchItem : Bool = true - - let items : {String : [MetadataCollectionItem]} = {} - let collections : {String : Int} = {} - let extraIDs : {String : [UInt64]} = {} - - for nftInfo in NFTRegistry.getNFTInfoAll().values { - let resolverCollectionCap= account!.getCapability<&{MetadataViews.ResolverCollection}>(nftInfo.publicPath) - if !resolverCollectionCap.check() { continue } - - let collectionRef = resolverCollectionCap.borrow()! - - let collectionID = collectionRef.getIDs() - - // by pass if this is not the target collection - if targetCollections.length >0 && !targetCollections.contains(nftInfo.alias) { - collections.insert(key: nftInfo.alias, collectionID.length) - extraIDs[nftInfo.alias] = collectionID - continue - } - - // insert collection - collections.insert(key: nftInfo.alias, collectionID.length) - - // if max items reached, will not fetch more items - if !fetchItem { - extraIDs[nftInfo.alias] = collectionID - continue - } - - let collectionItems : [MetadataCollectionItem] = [] - let collectionExtraIDs : [UInt64] = [] - - for id in collectionID { - - if !fetchItem { - collectionExtraIDs.append(id) - continue - } - - // Just for Rarible Flowverse Socks, can be moved to Alchemy Shard functions if needed - if nftInfo.alias == "RaribleNFT" { - if CollectionFactory.FlowverseSocksIds.contains(id) { - if !collections.containsKey("Flowverse Socks"){ - var j = 0 - for sockID in CollectionFactory.FlowverseSocksIds { - if collectionID.contains(sockID) { - j = j + 1 - } - } - collections.insert(key: "Flowverse Socks", counter) - } - - let image = "https://img.rarible.com/prod/video/upload/t_video_big/prod-itemAnimations/FLOW-A.01ab36aaf654a13e.RaribleNFT:15029/b1cedf3" - let item = MetadataCollectionItem( - id: id, - name: "Flowverse socks", - collection: "Rarible", - subCollection: "Flowverse socks", - media: image, - mediaType: "video", - source: source - ) - collectionItems.append(item) - - counter = counter + 1 - if counter >= maxItems { - fetchItem = false - } - } - } - - let nft = collectionRef.borrowViewResolver(id: id) - let display= MetadataViews.getDisplay(nft) - if display == nil { continue } - - var subCollection : String? = nil - if let sc= MetadataViews.getNFTCollectionDisplay(nft) { - subCollection=sc.name - } - - let item = MetadataCollectionItem( - id: id, - name: display!.name, - collection: nftInfo.alias, - subCollection: nftInfo.alias, - media: display!.thumbnail.uri(), - mediaType: "image", - source: source - ) - collectionItems.append(item) - - counter = counter + 1 - if counter >= maxItems { - fetchItem = false - } - } - if collectionExtraIDs.length > 0 { - extraIDs[nftInfo.alias] = collectionExtraIDs - } - - if collectionItems.length > 0 { - items[nftInfo.alias] = collectionItems - } - } - return CollectionReport(items: items, collections : collections, extraIDs : extraIDs) - } - - - ////////////////////////////////////////////////////////////// - // Fetch All Collections in Shard 1 - ////////////////////////////////////////////////////////////// - // pub fun fetchAlchemyShard1(user: String, maxItems: Int, targetCollections: [String]) : CollectionReport? { - // let source = "Alchemy-shard1" - // let account = self.resolveAddress(user: user) - // if account == nil { return nil } - - // let items : {String : [MetadataCollectionItem]} = {} - - // let extraIDs = AlchemyMetadataWrapperTestnetShard1.getNFTIDs(ownerAddress: account!.address) - - // for project in extraIDs.keys { - // if extraIDs[project]! == nil || extraIDs[project]!.length < 1{ - // extraIDs.remove(key: project) - // } - // } - - // for project in extraIDs.keys { - // // For passing bugs - // if project == "Xtingles_NFT" { - // extraIDs["Xtingles"] = extraIDs.remove(key: project) - // } - - // if project == "RCRDSHPNFT" { - // extraIDs.remove(key: project) - // } - // } - - // let collections : {String : Int} = {} - // for key in extraIDs.keys { - // collections[key] = extraIDs[key]!.length - // } - // let fetchingIDs : {String : [UInt64]} = {} - // var fetchedCount : Int = 0 - // for project in extraIDs.keys { - - // // by pass if this is not the target collection - // if targetCollections.length > 0 && !targetCollections.contains(project) { - // continue - // } - - // if extraIDs[project]!.length + fetchedCount > maxItems { - // let array : [UInt64] = [] - // while fetchedCount < maxItems { - // array.append(extraIDs[project]!.remove(at: 0)) - // fetchedCount = fetchedCount + 1 - // } - // if array.length > 0 { - // fetchingIDs[project] = array - // } - // break - // } - - // let array = extraIDs.remove(key: project)! - // fetchedCount = fetchedCount + array.length - // fetchingIDs[project] = array - // } - - - // for project in fetchingIDs.keys { - // let returnedNFTs = AlchemyMetadataWrapperTestnetShard1.getNFTs(ownerAddress: account!.address, ids: {project : fetchingIDs[project]!}) - - // var collectionItems : [MetadataCollectionItem] = [] - // for nft in returnedNFTs { - // if nft == nil { - // continue - // } - - // var media = "" - // var mediaType = "" - // if nft!.media.length > 0 && nft!.media[0]?.uri != nil { - // let m = nft!.media[0]! - // mediaType = m.mimetype ?? "" - // media = m.uri! - // } - - // let item = MetadataCollectionItem( - // id: nft!.id, - // name: nft!.title ?? "", - // collection: nft!.contract.name, - // subCollection: "", - // media: media, - // mediaType: mediaType, - // source: source - // ) - // collectionItems.append(item) - // } - - // if collectionItems.length > 0 { - // items[project] = collectionItems - // } - // } - // return CollectionReport(items: items, collections : collections, extraIDs : extraIDs) - // } - - // //////////////////////////////////////////////////////////// - // Fetch All Collections in Shard 2 - // //////////////////////////////////////////////////////////// - // pub fun fetchAlchemyShard2(user: String, maxItems: Int, targetCollections: [String]) : CollectionReport? { - // let source = "Alchemy-shard2" - // let account = self.resolveAddress(user: user) - // if account == nil { return nil } - - // let items : {String : [MetadataCollectionItem]} = {} - - // let extraIDs = AlchemyMetadataWrapperTestnetShard2.getNFTIDs(ownerAddress: account!.address) - - // for project in extraIDs.keys { - // if extraIDs[project]! == nil || extraIDs[project]!.length < 1{ - // extraIDs.remove(key: project) - // } - // } - - // for project in extraIDs.keys { - // // For passing bugs - // if project == "Xtingles_NFT" { - // extraIDs["Xtingles"] = extraIDs.remove(key: project) - // } - - // if project == "RCRDSHPNFT" { - // extraIDs.remove(key: project) - // } - // } - - // let collections : {String : Int} = {} - // for key in extraIDs.keys { - // collections[key] = extraIDs[key]!.length - // } - // let fetchingIDs : {String : [UInt64]} = {} - // var fetchedCount : Int = 0 - // for project in extraIDs.keys { - - // // by pass if this is not the target collection - // if targetCollections.length > 0 && !targetCollections.contains(project) { - // continue - // } - - // if extraIDs[project]!.length + fetchedCount > maxItems { - // let array : [UInt64] = [] - // while fetchedCount < maxItems { - // array.append(extraIDs[project]!.remove(at: 0)) - // fetchedCount = fetchedCount + 1 - // } - // if array.length > 0 { - // fetchingIDs[project] = array - // } - // break - // } - - // let array = extraIDs.remove(key: project)! - // fetchedCount = fetchedCount + array.length - // fetchingIDs[project] = array - // } - - - // for project in fetchingIDs.keys { - // let returnedNFTs = AlchemyMetadataWrapperTestnetShard2.getNFTs(ownerAddress: account!.address, ids: {project : fetchingIDs[project]!}) - - // var collectionItems : [MetadataCollectionItem] = [] - // for nft in returnedNFTs { - // if nft == nil { - // continue - // } - - // var media = "" - // var mediaType = "" - // if nft!.media.length > 0 && nft!.media[0]?.uri != nil { - // let m = nft!.media[0]! - // mediaType = m.mimetype ?? "" - // media = m.uri! - // } - - // let item = MetadataCollectionItem( - // id: nft!.id, - // name: nft!.title ?? "", - // collection: nft!.contract.name, - // subCollection: "", - // media: media, - // mediaType: mediaType, - // source: source - // ) - // collectionItems.append(item) - // } - - // if collectionItems.length > 0 { - // items[project] = collectionItems - // } - // } - // return CollectionReport(items: items, collections : collections, extraIDs : extraIDs) - // } - - ////////////////////////////////////////////////////////////// - // Fetch All Collections in Shard 3 - ////////////////////////////////////////////////////////////// - // pub fun fetchAlchemyShard3(user: String, maxItems: Int, targetCollections: [String]) : CollectionReport? { - // let source = "Alchemy-shard3" - // let account = self.resolveAddress(user: user) - // if account == nil { return nil } - - // let items : {String : [MetadataCollectionItem]} = {} - - // let extraIDs = AlchemyMetadataWrapperTestnetShard3.getNFTIDs(ownerAddress: account!.address) - - // for project in extraIDs.keys { - // if extraIDs[project]! == nil || extraIDs[project]!.length < 1{ - // extraIDs.remove(key: project) - // } - // } - - // for project in extraIDs.keys { - // // For passing bugs - // if project == "Xtingles_NFT" { - // extraIDs["Xtingles"] = extraIDs.remove(key: project) - // } - - // if project == "RCRDSHPNFT" { - // extraIDs.remove(key: project) - // } - // } - - // let collections : {String : Int} = {} - // for key in extraIDs.keys { - // collections[key] = extraIDs[key]!.length - // } - // let fetchingIDs : {String : [UInt64]} = {} - // var fetchedCount : Int = 0 - // for project in extraIDs.keys { - - // // by pass if this is not the target collection - // if targetCollections.length > 0 && !targetCollections.contains(project) { - // continue - // } - - // if extraIDs[project]!.length + fetchedCount > maxItems { - // let array : [UInt64] = [] - // while fetchedCount < maxItems { - // array.append(extraIDs[project]!.remove(at: 0)) - // fetchedCount = fetchedCount + 1 - // } - // if array.length > 0 { - // fetchingIDs[project] = array - // } - // break - // } - - // let array = extraIDs.remove(key: project)! - // fetchedCount = fetchedCount + array.length - // fetchingIDs[project] = array - // } - - - // for project in fetchingIDs.keys { - // let returnedNFTs = AlchemyMetadataWrapperTestnetShard3.getNFTs(ownerAddress: account!.address, ids: {project : fetchingIDs[project]!}) - - // var collectionItems : [MetadataCollectionItem] = [] - // for nft in returnedNFTs { - // if nft == nil { - // continue - // } - - // var media = "" - // var mediaType = "" - // if nft!.media.length > 0 && nft!.media[0]?.uri != nil { - // let m = nft!.media[0]! - // mediaType = m.mimetype ?? "" - // media = m.uri! - // } - - // let item = MetadataCollectionItem( - // id: nft!.id, - // name: nft!.title ?? "", - // collection: nft!.contract.name, - // subCollection: "", - // media: media, - // mediaType: mediaType, - // source: source - // ) - // collectionItems.append(item) - // } - - // if collectionItems.length > 0 { - // items[project] = collectionItems - // } - // } - // return CollectionReport(items: items, collections : collections, extraIDs : extraIDs) - // } - - - /* - ////////////////////////////////////////////////////////////// - // Fetch All Collections in Shard 4 - ////////////////////////////////////////////////////////////// - pub fun fetchAlchemyShard4(user: String, maxItems: Int, targetCollections: [String]) : CollectionReport? { - let source = "Alchemy-shard4" - let account = self.resolveAddress(user: user) - if account == nil { return nil } - - let items : {String : [MetadataCollectionItem]} = {} - - let extraIDs = AlchemyMetadataWrapperTestnetShard4.getNFTIDs(ownerAddress: account!.address) - - for project in extraIDs.keys { - if extraIDs[project]! == nil || extraIDs[project]!.length < 1{ - extraIDs.remove(key: project) - } - } - - for project in extraIDs.keys { - // For passing bugs - if project == "Xtingles_NFT" { - extraIDs["Xtingles"] = extraIDs.remove(key: project) - } - - if project == "RCRDSHPNFT" { - extraIDs.remove(key: project) - } - } - - let collections : {String : Int} = {} - for key in extraIDs.keys { - collections[key] = extraIDs[key]!.length - } - let fetchingIDs : {String : [UInt64]} = {} - var fetchedCount : Int = 0 - for project in extraIDs.keys { - - // by pass if this is not the target collection - if targetCollections.length > 0 && !targetCollections.contains(project) { - continue - } - - if extraIDs[project]!.length + fetchedCount > maxItems { - let array : [UInt64] = [] - while fetchedCount < maxItems { - array.append(extraIDs[project]!.remove(at: 0)) - fetchedCount = fetchedCount + 1 - } - if array.length > 0 { - fetchingIDs[project] = array - } - break - } - - let array = extraIDs.remove(key: project)! - fetchedCount = fetchedCount + array.length - fetchingIDs[project] = array - } - - - for project in fetchingIDs.keys { - let returnedNFTs = AlchemyMetadataWrapperTestnetShard4.getNFTs(ownerAddress: account!.address, ids: {project : fetchingIDs[project]!}) - - var collectionItems : [MetadataCollectionItem] = [] - for nft in returnedNFTs { - if nft == nil { - continue - } - - var media = "" - var mediaType = "" - if nft!.media.length > 0 && nft!.media[0]?.uri != nil { - let m = nft!.media[0]! - mediaType = m.mimetype ?? "" - media = m.uri! - } - - let item = MetadataCollectionItem( - id: nft!.id, - name: nft!.title ?? "", - collection: nft!.contract.name, - subCollection: "", - media: media, - mediaType: mediaType, - source: source - ) - collectionItems.append(item) - } - - if collectionItems.length > 0 { - items[project] = collectionItems - } - } - return CollectionReport(items: items, collections : collections, extraIDs : extraIDs) - } - */ - - - - ////////////////////////////////////////////////////////////// - // Fetch Specific Collections in NFTRegistry - ////////////////////////////////////////////////////////////// - pub fun fetchNFTRegistryCollection(user: String, collectionIDs: {String : [UInt64]}) : {String : [MetadataCollectionItem]} { - let source = "NFTRegistry" - let account = self.resolveAddress(user: user) - if account == nil { return {} } - - let items : {String : [MetadataCollectionItem]} = {} - - for project in collectionIDs.keys { - - let nftInfo = NFTRegistry.getNFTInfo(project) - - if nftInfo == nil { - continue - } - - let collectionItems : [MetadataCollectionItem] = [] - - let resolverCollectionCap= account!.getCapability<&{MetadataViews.ResolverCollection}>(nftInfo!.publicPath) - if !resolverCollectionCap.check() { continue } - - let collectionRef = resolverCollectionCap.borrow()! - - for id in collectionRef.getIDs() { - - if !collectionIDs[project]!.contains(id) { - continue - } - - // Just for Rarible Flowverse Socks, can be moved to Alchemy Shard functions if needed - if nftInfo!.alias == "RaribleNFT" { - if CollectionFactory.FlowverseSocksIds.contains(id) { - - let image = "https://img.rarible.com/prod/video/upload/t_video_big/prod-itemAnimations/FLOW-A.01ab36aaf654a13e.RaribleNFT:15029/b1cedf3" - let item = MetadataCollectionItem( - id: id, - name: "Flowverse socks", - collection: "Rarible", - subCollection: "Flowverse socks", - media: image, - mediaType: "video", - source: source - ) - collectionItems.append(item) - - } - } - - let nft = collectionRef.borrowViewResolver(id: id) - let display= MetadataViews.getDisplay(nft) - if display == nil { continue } - - var subCollection : String? = nil - if let sc= MetadataViews.getNFTCollectionDisplay(nft) { - subCollection=sc.name - } - - let item = MetadataCollectionItem( - id: id, - name: display!.name, - collection: nftInfo!.alias, - subCollection: subCollection, - media: display!.thumbnail.uri(), - mediaType: "image", - source: source - ) - collectionItems.append(item) - - } - - if collectionItems.length > 0 { - items[nftInfo!.alias] = collectionItems - } - } - return items - } - - - ////////////////////////////////////////////////////////////// - // Fetch Specific Collections in Shard 1 - ////////////////////////////////////////////////////////////// - // pub fun fetchAlchemyCollectionShard1(user: String, collectionIDs: {String : [UInt64]}) : {String : [MetadataCollectionItem]} { - // let source = "Alchemy-shard1" - // let account = self.resolveAddress(user: user) - // if account == nil { return {} } - - // let items : {String : [MetadataCollectionItem]} = {} - - // let fetchingIDs = collectionIDs - - // for project in fetchingIDs.keys { - // // For passing bugs - // if project == "Xtingles_NFT" { - // fetchingIDs["Xtingles"] = fetchingIDs.remove(key: project) - // } - - // if project == "RCRDSHPNFT" { - // fetchingIDs.remove(key: project) - // } - // } - - // for project in fetchingIDs.keys { - // let returnedNFTs = AlchemyMetadataWrapperTestnetShard1.getNFTs(ownerAddress: account!.address, ids: {project : fetchingIDs[project]!}) - - // var collectionItems : [MetadataCollectionItem] = [] - // for nft in returnedNFTs { - // if nft == nil { - // continue - // } - - // var media = "" - // var mediaType = "" - // if nft!.media.length > 0 && nft!.media[0]?.uri != nil { - // let m = nft!.media[0]! - // mediaType = m.mimetype ?? "" - // media = m.uri! - // } - - // let item = MetadataCollectionItem( - // id: nft!.id, - // name: nft!.title ?? "", - // collection: nft!.contract.name, - // subCollection: "", - // media: media, - // mediaType: mediaType, - // source: source - // ) - // collectionItems.append(item) - // } - - // if collectionItems.length > 0 { - // items[project] = collectionItems - // } - // } - // return items - // } - - ////////////////////////////////////////////////////////////// - // Fetch Specific Collections in Shard 2 - ////////////////////////////////////////////////////////////// - // pub fun fetchAlchemyCollectionShard2(user: String, collectionIDs: {String : [UInt64]}) : {String : [MetadataCollectionItem]} { - // let source = "Alchemy-shard2" - // let account = self.resolveAddress(user: user) - // if account == nil { return {} } - - // let items : {String : [MetadataCollectionItem]} = {} - - // let fetchingIDs = collectionIDs - - // for project in fetchingIDs.keys { - // // For passing bugs - // if project == "Xtingles_NFT" { - // fetchingIDs["Xtingles"] = fetchingIDs.remove(key: project) - // } - - // if project == "RCRDSHPNFT" { - // fetchingIDs.remove(key: project) - // } - // } - - // for project in fetchingIDs.keys { - // let returnedNFTs = AlchemyMetadataWrapperTestnetShard2.getNFTs(ownerAddress: account!.address, ids: {project : fetchingIDs[project]!}) - - // var collectionItems : [MetadataCollectionItem] = [] - // for nft in returnedNFTs { - // if nft == nil { - // continue - // } - - // var media = "" - // var mediaType = "" - // if nft!.media.length > 0 && nft!.media[0]?.uri != nil { - // let m = nft!.media[0]! - // mediaType = m.mimetype ?? "" - // media = m.uri! - // } - - // let item = MetadataCollectionItem( - // id: nft!.id, - // name: nft!.title ?? "", - // collection: nft!.contract.name, - // subCollection: "", - // media: media, - // mediaType: mediaType, - // source: source - // ) - // collectionItems.append(item) - // } - - // if collectionItems.length > 0 { - // items[project] = collectionItems - // } - // } - // return items - // } - - ////////////////////////////////////////////////////////////// - // Fetch Specific Collections in Shard 3 - ////////////////////////////////////////////////////////////// - // pub fun fetchAlchemyCollectionShard3(user: String, collectionIDs: {String : [UInt64]}) : {String : [MetadataCollectionItem]} { - // let source = "Alchemy-shard3" - // let account = self.resolveAddress(user: user) - // if account == nil { return {} } - - // let items : {String : [MetadataCollectionItem]} = {} - - // let fetchingIDs = collectionIDs - - // for project in fetchingIDs.keys { - // // For passing bugs - // if project == "Xtingles_NFT" { - // fetchingIDs["Xtingles"] = fetchingIDs.remove(key: project) - // } - - // if project == "RCRDSHPNFT" { - // fetchingIDs.remove(key: project) - // } - // } - - // for project in fetchingIDs.keys { - // let returnedNFTs = AlchemyMetadataWrapperTestnetShard3.getNFTs(ownerAddress: account!.address, ids: {project : fetchingIDs[project]!}) - - // var collectionItems : [MetadataCollectionItem] = [] - // for nft in returnedNFTs { - // if nft == nil { - // continue - // } - - // var media = "" - // var mediaType = "" - // if nft!.media.length > 0 && nft!.media[0]?.uri != nil { - // let m = nft!.media[0]! - // mediaType = m.mimetype ?? "" - // media = m.uri! - // } - - // let item = MetadataCollectionItem( - // id: nft!.id, - // name: nft!.title ?? "", - // collection: nft!.contract.name, - // subCollection: "", - // media: media, - // mediaType: mediaType, - // source: source - // ) - // collectionItems.append(item) - // } - - // if collectionItems.length > 0 { - // items[project] = collectionItems - // } - // } - // return items - // } - - - /* - ////////////////////////////////////////////////////////////// - // Fetch Specific Collections in Shard 4 - ////////////////////////////////////////////////////////////// - pub fun fetchAlchemyCollectionShard4(user: String, collectionIDs: {String : [UInt64]}) : {String : [MetadataCollectionItem]} { - let source = "Alchemy-shard4" - let account = self.resolveAddress(user: user) - if account == nil { return {} } - - let items : {String : [MetadataCollectionItem]} = {} - - let fetchingIDs = collectionIDs - - for project in fetchingIDs.keys { - // For passing bugs - if project == "Xtingles_NFT" { - fetchingIDs["Xtingles"] = fetchingIDs.remove(key: project) - } - - if project == "RCRDSHPNFT" { - fetchingIDs.remove(key: project) - } - } - - for project in fetchingIDs.keys { - let returnedNFTs = AlchemyMetadataWrapperTestnetShard4.getNFTs(ownerAddress: account!.address, ids: {project : fetchingIDs[project]!}) - - var collectionItems : [MetadataCollectionItem] = [] - for nft in returnedNFTs { - if nft == nil { - continue - } - - var media = "" - var mediaType = "" - if nft!.media.length > 0 && nft!.media[0]?.uri != nil { - let m = nft!.media[0]! - mediaType = m.mimetype ?? "" - media = m.uri! - } - - let item = MetadataCollectionItem( - id: nft!.id, - name: nft!.title ?? "", - collection: nft!.contract.name, - subCollection: "", - media: media, - mediaType: mediaType, - source: source - ) - collectionItems.append(item) - } - - if collectionItems.length > 0 { - items[project] = collectionItems - } - } - return items - } - */ - - init() { - self.FlowverseSocksIds = [14813, 15013, 14946, 14808, 14899, 14792, 15016, 14961, 14816, 14796, 14992, 14977, 14815, 14863, 14817, 14814, 14875, 14960, 14985, 14850, 14849, 14966, 14826, 14972, 14795, 15021, 14950, 14847, 14970, 14833, 14786, 15010, 14953, 14799, 14883, 14947, 14844, 14801, 14886, 15015, 15023, 15027, 15029, 14802, 14810, 14948, 14955, 14957, 14988, 15007, 15009, 14837, 15024, 14803, 14973, 14969, 15002, 15017, 14797, 14894, 14881, 15025, 14791, 14979, 14789, 14993, 14873, 14939, 15005, 15006, 14869, 14889, 15004, 15008, 15026, 14990, 14998, 14898, 14819, 14840, 14974, 15019, 14856, 14838, 14787, 14876, 14996, 14798, 14855, 14824, 14843, 14959, 15020, 14862, 14822, 14897, 14830, 14790, 14867, 14878, 14991, 14835, 14818, 14892, 14800, 15000, 14857, 14986, 14805, 14812, 14962] - } - -} diff --git a/contracts/Dandy.cdc b/contracts/Dandy.cdc index 558b49c8..82392779 100644 --- a/contracts/Dandy.cdc +++ b/contracts/Dandy.cdc @@ -1,399 +1,392 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindViews from "./FindViews.cdc" -import FindForge from "./FindForge.cdc" - -pub contract Dandy: NonFungibleToken { - - pub let CollectionStoragePath: StoragePath - pub let CollectionPrivatePath: PrivatePath - pub let CollectionPublicPath: PublicPath - pub var totalSupply: UInt64 - - /*store all valid type converters for Dandys - This is to be able to make the contract compatible with the forthcomming NFT standard. - - If a Dandy supports a type with the same Identifier as a key here all the ViewConverters convertTo types are added to the list of available types - When resolving a type if the Dandy does not itself support this type check if any viewConverters do - */ - access(account) var viewConverters: {String: [{ViewConverter}]} - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id:UInt64, minter:String, name:String, description:String) - - pub struct ViewInfo { - access(contract) let typ: Type - access(contract) let result: AnyStruct - - init(typ:Type, result:AnyStruct) { - self.typ=typ - self.result=result - } - } - - pub struct DandyInfo { - pub let name: String - pub let description: String - pub let thumbnail: MetadataViews.Media - pub let schemas: [AnyStruct] - pub let externalUrlPrefix:String? - - init(name: String, description: String, thumbnail: MetadataViews.Media, schemas: [AnyStruct], externalUrlPrefix:String?) { - self.name=name - self.description=description - self.thumbnail=thumbnail - self.schemas=schemas - self.externalUrlPrefix=externalUrlPrefix - } - } - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - pub let id: UInt64 - access(self) var nounce: UInt64 - - access(self) var primaryCutPaid: Bool - access(contract) let schemas: {String : ViewInfo} - access(contract) let name: String - access(contract) let description: String - access(contract) let thumbnail: MetadataViews.Media - access(contract) let platform: FindForge.MinterPlatform - - init(name: String, description: String, thumbnail: MetadataViews.Media, schemas: {String: ViewInfo}, platform: FindForge.MinterPlatform, externalUrlPrefix: String?) { - self.id = self.uuid - self.schemas=schemas - self.thumbnail=thumbnail - self.name=name - self.description=description - self.nounce=0 - self.primaryCutPaid=false - self.platform=platform - if externalUrlPrefix != nil { - let mvt = Type() - self.schemas[mvt.identifier] = ViewInfo(typ:mvt, result: MetadataViews.ExternalURL(externalUrlPrefix!.concat("/").concat(self.id.toString()))) - } - } - - pub fun increaseNounce() { - self.nounce=self.nounce+1 - } - - pub fun getMinterPlatform() : FindForge.MinterPlatform { - if let fetch = FindForge.getMinterPlatform(name: self.platform.name, forgeType: Dandy.getForgeType()) { - - let platform = &self.platform as &FindForge.MinterPlatform - platform.updateExternalURL(fetch.externalURL) - platform.updateDesription(fetch.description) - platform.updateSquareImagen(fetch.squareImage) - platform.updateBannerImage(fetch.bannerImage) - platform.updateSocials(fetch.socials) - - } - - return self.platform - } - - pub fun getViews() : [Type] { - - var views : [Type]=[] - views.append(Type()) - views.append(Type()) - views.append(Type()) - views.append(Type()) - views.append(Type()) - - //if any specific here they will override - for s in self.schemas.keys { - if !views.contains(self.schemas[s]!.typ) { - views.append(self.schemas[s]!.typ) - } - } - - //ViewConverter: If there are any viewconverters that add new types that can be resolved add them - // for v in views { - // if Dandy.viewConverters.containsKey(v.identifier) { - // for converter in Dandy.viewConverters[v.identifier]! { - // //I wants sets in cadence... - // if !views.contains(converter.to){ - // views.append(converter.to) - // } - // } - // } - // } - - return views - } - - access(self) fun resolveRoyalties() : MetadataViews.Royalties { - let royalties : [MetadataViews.Royalty] = [] - - if self.schemas.containsKey(Type().identifier) { - let multipleRoylaties=self.schemas[Type().identifier]!.result as! MetadataViews.Royalties - royalties.appendAll(multipleRoylaties.getRoyalties()) - } - - if self.platform.minterCut != nil && self.platform.minterCut! != 0.0 { - let royalty = MetadataViews.Royalty(receiver: self.platform.getMinterFTReceiver(), cut: self.platform.minterCut!, description: "creator") - royalties.append(royalty) - } - - if self.platform.platformPercentCut != 0.0 { - let royalty = MetadataViews.Royalty(receiver: self.platform.platform, cut: self.platform.platformPercentCut, description: "find forge") - royalties.append(royalty) - } - - return MetadataViews.Royalties(royalties) - } - - pub fun resolveDisplay() : MetadataViews.Display { - return MetadataViews.Display( - name: self.name, - description: self.description, - thumbnail: self.thumbnail.file - ) - } - - //Note that when resolving schemas shared data are loaded last, so use schema names that are unique. ie prefix with shared/ or something - //NB! This will _not_ error out if it does not return Optional! - pub fun resolveView(_ type: Type): AnyStruct? { - - if type == Type() { - let minterPlatform = self.getMinterPlatform() - let externalURL = MetadataViews.ExternalURL(minterPlatform.externalURL) - let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: minterPlatform.squareImage), mediaType: "image") - let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: minterPlatform.bannerImage), mediaType: "image") - - let socialMap : {String : MetadataViews.ExternalURL} = {} - for social in minterPlatform.socials.keys { - socialMap[social] = MetadataViews.ExternalURL(minterPlatform.socials[social]!) - } - return MetadataViews.NFTCollectionDisplay(name: minterPlatform.name, description: minterPlatform.description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socialMap) - } - - - if type == Type() { - return FindViews.Nounce(self.nounce) - } - - if type == Type() { - return self.resolveRoyalties() - } - - if type == Type() { - return self.resolveDisplay() - } - - if self.schemas.keys.contains(type.identifier) { - return self.schemas[type.identifier]!.result - } - - if type == Type() { - return MetadataViews.NFTCollectionData( - storagePath: Dandy.CollectionStoragePath, - publicPath: Dandy.CollectionPublicPath, - providerPath: Dandy.CollectionPrivatePath, - publicCollection: Type<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(), - publicLinkedType: Type<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(), - providerLinkedType: Type<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(), - createEmptyCollectionFunction: fun(): @NonFungibleToken.Collection {return <- Dandy.createEmptyCollection()} - ) - } - //Viewconverter: This is an example on how you as the last step in resolveView can check if there are converters for your type and run them - // for converterValue in Dandy.viewConverters.keys { - // for converter in Dandy.viewConverters[converterValue]! { - // if converter.to == type { - // let value= self.resolveView(converter.from) - // return converter.convert(value) - // } - // } - // } - return nil - } - - } - - - pub resource interface CollectionPublic { - pub fun getIDsFor(minter: String): [UInt64] - pub fun getMinters(): [String] - } - - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection, CollectionPublic { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} - - // Mapping of {Minter Platform Name : [NFT ID]} - access(self) let nftIndex: {String : {UInt64 : Bool}} - - - init () { - self.ownedNFTs <- {} - self.nftIndex = {} - } - - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT. withdrawID : ".concat(withdrawID.toString())) - - let dandyToken <- token as! @NFT - let minterPlatform = dandyToken.getMinterPlatform() - let minterName = minterPlatform.name - if self.nftIndex.containsKey(minterName) { - self.nftIndex[minterName]!.remove(key: withdrawID) - if self.nftIndex[minterName]!.length < 1 { - self.nftIndex.remove(key: minterName) - } - } - - emit Withdraw(id: dandyToken.id, from: self.owner?.address) - - return <-dandyToken - } - - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { - let token <- token as! @NFT - - let minterPlatform = token.getMinterPlatform() - let minterName = minterPlatform.name - if self.nftIndex.containsKey(minterName) { - self.nftIndex[minterName]!.insert(key: token.id, false) - } else { - self.nftIndex[minterName] = {} - self.nftIndex[minterName]!.insert(key: token.id, false) - } - - token.increaseNounce() - - let id: UInt64 = token.id - - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) - - destroy oldToken - } - - pub fun getMinters(): [String] { - return self.nftIndex.keys - } - - pub fun getIDsFor(minter: String): [UInt64] { - return self.nftIndex[minter]?.keys ?? [] - } - - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { - return self.ownedNFTs.keys - } - - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - if self.ownedNFTs[id] == nil { - panic("NFT does not exist. ID : ".concat(id.toString())) - } - - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! - } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - if self.ownedNFTs[id] == nil { - panic("NFT does not exist. ID : ".concat(id.toString())) - } - - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - return nft as! &Dandy.NFT - } - - pub fun borrow(_ id: UInt64): &NFT { - if self.ownedNFTs[id] == nil { - panic("NFT does not exist. ID : ".concat(id.toString())) - } - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - return nft as! &Dandy.NFT - } - - destroy() { - destroy self.ownedNFTs - } - } - - access(account) fun mintNFT(name: String, description: String, thumbnail: MetadataViews.Media, platform:FindForge.MinterPlatform, schemas: [AnyStruct], externalUrlPrefix:String?) : @NFT { - let views : {String: ViewInfo} = {} - for s in schemas { - //if you send in display we ignore it, this will be made for you - if s.getType() != Type() { - views[s.getType().identifier]=ViewInfo(typ:s.getType(), result: s) - } - } - - let nft <- create NFT(name: name, description:description,thumbnail: thumbnail, schemas:views, platform: platform, externalUrlPrefix:externalUrlPrefix) - - //TODO: remove this - emit Minted(id:nft.id, minter:nft.platform.name, name: name, description:description) - return <- nft - } - - /* - access(account) fun setViewConverters(from: Type, converters: [AnyStruct{ViewConverter}]) { - Dandy.viewConverters[from.identifier] = converters - } - */ - - //TODO: do we want to store minter - pub resource Forge: FindForge.Forge { - pub fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @NonFungibleToken.NFT { - let info = data as? DandyInfo ?? panic("The data passed in is not in form of DandyInfo.") - return <- Dandy.mintNFT(name: info.name, description: info.description, thumbnail: info.thumbnail, platform: platform, schemas: info.schemas, externalUrlPrefix:info.externalUrlPrefix) - } - - pub fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { - // not used here - - panic("Not supported for Dandy Contract") +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "FindViews" +import "FindForge" +import "ViewResolver" + +access(all) contract Dandy :NonFungibleToken{ + + // Paths + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + access(all) var totalSupply: UInt64 + + /*store all valid type converters for Dandys + This is to be able to make the contract compatible with the forthcomming NFT standard. + + If a Dandy supports a type with the same Identifier as a key here all the ViewConverters convertTo types are added to the list of available types + When resolving a type if the Dandy does not itself support this type check if any viewConverters do + */ + access(account) var viewConverters: {String: [{ViewConverter}]} + + // Events + access(all) event ContractInitialized() + access(all) event Minted(id:UInt64, minter:String, name:String, description:String) + + access(all) struct ViewInfo { + access(contract) let typ: Type + access(contract) let result: AnyStruct + + init(typ:Type, result:AnyStruct) { + self.typ=typ + self.result=result } - } + } + + access(all) struct DandyInfo { + access(all) let name: String + access(all) let description: String + access(all) let thumbnail: MetadataViews.Media + access(all) let schemas: [AnyStruct] + access(all) let externalUrlPrefix:String? + + init(name: String, description: String, thumbnail: MetadataViews.Media, schemas: [AnyStruct], externalUrlPrefix:String?) { + self.name=name + self.description=description + self.thumbnail=thumbnail + self.schemas=schemas + self.externalUrlPrefix=externalUrlPrefix + } + } + access(all) resource NFT: NonFungibleToken.NFT { + access(all) let id: UInt64 + access(self) var nounce: UInt64 + + access(self) var primaryCutPaid: Bool + access(contract) let schemas: {String : ViewInfo} + access(contract) let name: String + access(contract) let description: String + access(contract) let thumbnail: MetadataViews.Media + access(contract) let platform: FindForge.MinterPlatform + + init(name: String, description: String, thumbnail: MetadataViews.Media, schemas: {String: ViewInfo}, platform: FindForge.MinterPlatform, externalUrlPrefix: String?) { + self.id = self.uuid + self.schemas=schemas + self.thumbnail=thumbnail + self.name=name + self.description=description + self.nounce=0 + self.primaryCutPaid=false + self.platform=platform + if externalUrlPrefix != nil { + let mvt = Type() + self.schemas[mvt.identifier] = ViewInfo(typ:mvt, result: MetadataViews.ExternalURL(externalUrlPrefix!.concat("/").concat(self.id.toString()))) + } + } + + + access(all) view fun getID() : UInt64{ + return self.id + } + + access(contract) fun increaseNounce() { + self.nounce=self.nounce+1 + } + + access(all) fun getMinterPlatform() : FindForge.MinterPlatform { + if let fetch = FindForge.getMinterPlatform(name: self.platform.name, forgeType: Dandy.getForgeType()) { + let platform = &self.platform as &FindForge.MinterPlatform + platform.updateExternalURL(fetch.externalURL) + platform.updateDesription(fetch.description) + platform.updateSquareImagen(fetch.squareImage) + platform.updateBannerImage(fetch.bannerImage) + platform.updateSocials(fetch.socials) + } + + return self.platform + } + + access(all) view fun getViews() : [Type] { + + let views = [ + Type(), + Type(), + Type(), + Type(), + Type()] + + for s in self.schemas.keys { + if !views.contains(self.schemas[s]!.typ) { + views.concat([self.schemas[s]!.typ]) + } + } + + return views + } + + access(self) fun resolveRoyalties() : MetadataViews.Royalties { + let royalties : [MetadataViews.Royalty] = [] + + if self.schemas.containsKey(Type().identifier) { + let multipleRoylaties=self.schemas[Type().identifier]!.result as! MetadataViews.Royalties + royalties.appendAll(multipleRoylaties.getRoyalties()) + } + + if self.platform.minterCut != nil && self.platform.minterCut! != 0.0 { + let royalty = MetadataViews.Royalty(receiver: self.platform.getMinterFTReceiver(), cut: self.platform.minterCut!, description: "creator") + royalties.append(royalty) + } + + if self.platform.platformPercentCut != 0.0 { + let royalty = MetadataViews.Royalty(receiver: self.platform.platform, cut: self.platform.platformPercentCut, description: "find forge") + royalties.append(royalty) + } + + return MetadataViews.Royalties(royalties) + } + + access(all) fun resolveDisplay() : MetadataViews.Display { + return MetadataViews.Display( + name: self.name, + description: self.description, + thumbnail: self.thumbnail.file + ) + } + + //Note that when resolving schemas shared data are loaded last, so use schema names that are unique. ie prefix with shared/ or something + //NB! This will _not_ error out if it does not return Optional! + access(all) fun resolveView(_ type: Type): AnyStruct? { + + if type == Type() { + let minterPlatform = self.getMinterPlatform() + let externalURL = MetadataViews.ExternalURL(minterPlatform.externalURL) + let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: minterPlatform.squareImage), mediaType: "image") + let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: minterPlatform.bannerImage), mediaType: "image") + + let socialMap : {String : MetadataViews.ExternalURL} = {} + for social in minterPlatform.socials.keys { + socialMap[social] = MetadataViews.ExternalURL(minterPlatform.socials[social]!) + } + return MetadataViews.NFTCollectionDisplay(name: minterPlatform.name, description: minterPlatform.description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socialMap) + } + + + if type == Type() { + return FindViews.Nounce(self.nounce) + } + + if type == Type() { + return self.resolveRoyalties() + } + + if type == Type() { + return self.resolveDisplay() + } + + + if type == Type() { + return Dandy.resolveContractView(resourceType: Type<@NFT>(), viewType: Type()) + } + + if self.schemas.keys.contains(type.identifier) { + return self.schemas[type.identifier]!.result + } + return nil + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-Dandy.createEmptyCollection(nftType: Type<@Dandy.NFT>()) + } + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionData = MetadataViews.NFTCollectionData( + storagePath: Dandy.CollectionStoragePath, + publicPath: Dandy.CollectionPublicPath, + publicCollection: Type<&Dandy.Collection>(), + publicLinkedType: Type<&Dandy.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-Dandy.createEmptyCollection(nftType: Type<@Dandy.NFT>()) + }) + ) + return collectionData + } + return nil + } + + + access(all) resource interface CollectionPublic { + access(all) fun getIDsFor(minter: String): [UInt64] + access(all) fun getMinters(): [String] + } + + access(all) resource Collection: NonFungibleToken.Collection, CollectionPublic, ViewResolver.ResolverCollection { + // dictionary of NFT conforming tokens + // NFT is a resource type with an `UInt64` ID field + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + + // Mapping of {Minter Platform Name : [NFT ID]} + access(self) let nftIndex: {String : {UInt64 : Bool}} + + + init () { + self.ownedNFTs <- {} + self.nftIndex = {} + } + + + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT. withdrawID : ".concat(withdrawID.toString())) + let dandyToken <- token as! @NFT + let minterPlatform = dandyToken.getMinterPlatform() + let minterName = minterPlatform.name + if self.nftIndex.containsKey(minterName) { + self.nftIndex[minterName]!.remove(key: withdrawID) + if self.nftIndex[minterName]!.length < 1 { + self.nftIndex.remove(key: minterName) + } + } + + return <- dandyToken + } + + // deposit takes a NFT and adds it to the collections dictionary + // and adds the ID to the id array + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { + let token <- token as! @Dandy.NFT + + let minterPlatform = token.getMinterPlatform() + let minterName = minterPlatform.name + if self.nftIndex.containsKey(minterName) { + self.nftIndex[minterName]!.insert(key: token.id, false) + } else { + self.nftIndex[minterName] = {} + self.nftIndex[minterName]!.insert(key: token.id, false) + } + + token.increaseNounce() + + let id: UInt64 = token.id + + // add the new token to the dictionary which removes the old one + let oldToken <- self.ownedNFTs[id] <- token + + destroy oldToken + } + + access(all) fun getMinters(): [String] { + return self.nftIndex.keys + } + + access(all) fun getIDsFor(minter: String): [UInt64] { + return self.nftIndex[minter]?.keys ?? [] + } + + // getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { + return self.ownedNFTs.keys + } + + // borrowNFT gets a reference to an NFT in the collection + // so that the caller can read its metadata and call its methods + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] + } + + /// Borrow the view resolver for the specified NFT ID + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? { + return &self.ownedNFTs[id] + } + + access(all) view fun getDefaultStoragePath() : StoragePath { + return Dandy.CollectionStoragePath + } + + access(all) view fun getDefaultPublicPath() : PublicPath { + return Dandy.CollectionPublicPath + } + + access(all) view fun getIDsWithTypes(): {Type: [UInt64]} { + return { Type<@NFT>() : self.ownedNFTs.keys} + } + + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + return { Type<@NFT>() : true} + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create Collection() + } + + access(all) view fun getLength() : Int { + return self.ownedNFTs.length + } + + access(all) view fun isSupportedNFTType(type: Type) : Bool { + return type == Type<@NFT>() + } + + } + + access(account) fun mintNFT(name: String, description: String, thumbnail: MetadataViews.Media, platform:FindForge.MinterPlatform, schemas: [AnyStruct], externalUrlPrefix:String?) : @NFT { + let views : {String: ViewInfo} = {} + for s in schemas { + //if you send in display we ignore it, this will be made for you + if s.getType() != Type() { + views[s.getType().identifier]=ViewInfo(typ:s.getType(), result: s) + } + } + + let nft <- create NFT(name: name, description:description,thumbnail: thumbnail, schemas:views, platform: platform, externalUrlPrefix:externalUrlPrefix) + + emit Minted(id:nft.id, minter:nft.platform.name, name: name, description:description) + return <- nft + } + + access(all) resource Forge: FindForge.Forge { + access(FindForge.ForgeOwner) fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @{NonFungibleToken.NFT} { + let info = data as? DandyInfo ?? panic("The data passed in is not in form of DandyInfo.") + return <- Dandy.mintNFT(name: info.name, description: info.description, thumbnail: info.thumbnail, platform: platform, schemas: info.schemas, externalUrlPrefix:info.externalUrlPrefix) + } + + access(FindForge.ForgeOwner) fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { + // not used here + panic("Not supported for Dandy Contract") + } + } + + access(account) fun createForge() : @{FindForge.Forge} { + return <- create Forge() + } - access(account) fun createForge() : @{FindForge.Forge} { - return <- create Forge() - } - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } + access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} { - pub fun getForgeType() : Type { - return Type<@Forge>() - } + return <- create Collection() + } - /// This struct interface is used on a contract level to convert from one View to another. - /// See Dandy nft for an example on how to convert one type to another - pub struct interface ViewConverter { - pub let to: Type - pub let from: Type + access(all) fun getForgeType() : Type { + return Type<@Forge>() + } - pub fun convert(_ value:AnyStruct) : AnyStruct - } + /// This struct interface is used on a contract level to convert from one View to another. + /// See Dandy nft for an example on how to convert one type to another + access(all) struct interface ViewConverter { + access(all) let to: Type + access(all) let from: Type + access(all) fun convert(_ value:AnyStruct) : AnyStruct + } - init() { - // Initialize the total supply - self.totalSupply=0 - self.CollectionPublicPath = /public/findDandy - self.CollectionPrivatePath = /private/findDandy - self.CollectionStoragePath = /storage/findDandy - self.viewConverters={} + init() { + // Initialize the total supply + self.totalSupply=0 + self.CollectionPublicPath = /public/findDandy + self.CollectionStoragePath = /storage/findDandy + self.viewConverters={} - FindForge.addForgeType(<- create Forge()) + FindForge.addForgeType(<- create Forge()) - //TODO: Add the Forge resource aswell - FindForge.addPublicForgeType(forgeType: Type<@Forge>()) + FindForge.addPublicForgeType(forgeType: Type<@Forge>()) - emit ContractInitialized() - } + emit ContractInitialized() + } } diff --git a/contracts/Debug.cdc b/contracts/Debug.cdc index 9728f707..2129f525 100644 --- a/contracts/Debug.cdc +++ b/contracts/Debug.cdc @@ -1,10 +1,9 @@ -pub contract Debug { +access(all) contract Debug { - pub event Log(msg: String) - + access(all) event Log(msg: String) access(account) var enabled :Bool - pub fun log(_ msg: String) { + access(all) fun log(_ msg: String) { if self.enabled { emit Log(msg: msg) } @@ -17,6 +16,4 @@ pub contract Debug { init() { self.enabled=false } - - } diff --git a/contracts/Dev.cdc b/contracts/Dev.cdc index a52bf48e..43933d51 100644 --- a/contracts/Dev.cdc +++ b/contracts/Dev.cdc @@ -1,15 +1,15 @@ // This contract is for Development purpose only // DO NOT DEPLOY TO TESTNET OR MAINNET -import FindMarket from "../contracts/FindMarket.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" +import "FindMarket" +import "FTRegistry" +import "FungibleToken" -pub contract Dev { - pub fun getPaymentWallet(addr: Address, ftType: String, path: PublicPath, panicOnFailCheck: Bool) : &{FungibleToken.Receiver} { - let account = getAccount(addr) - let ftInfo = FTRegistry.getFTInfo(ftType)! - let cap = account.getCapability<&{FungibleToken.Receiver}>(path) - return FindMarket.getPaymentWallet(cap, ftInfo, panicOnFailCheck: panicOnFailCheck) - } +access(all) contract Dev { + access(all) fun getPaymentWallet(addr: Address, ftType: String, path: PublicPath, panicOnFailCheck: Bool) : &{FungibleToken.Receiver} { + let account = getAccount(addr) + let ftInfo = FTRegistry.getFTInfo(ftType)! + let cap = account.capabilities.get<&{FungibleToken.Receiver}>(path)! + return FindMarket.getPaymentWallet(cap, ftInfo, panicOnFailCheck: panicOnFailCheck) + } } diff --git a/contracts/FIND.cdc b/contracts/FIND.cdc index 76734aed..7285f2d4 100644 --- a/contracts/FIND.cdc +++ b/contracts/FIND.cdc @@ -1,21 +1,21 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import FUSD from "./standard/FUSD.cdc" -import FiatToken from "./standard/FiatToken.cdc" -import FlowToken from "./standard/FlowToken.cdc" -import DapperUtilityCoin from "./standard/DapperUtilityCoin.cdc" -import Profile from "./Profile.cdc" -import Debug from "./Debug.cdc" -import Clock from "./Clock.cdc" -import Sender from "./Sender.cdc" -import ProfileCache from "./ProfileCache.cdc" -import FindUtils from "./FindUtils.cdc" -/* +import "FungibleToken" +import "FlowToken" +import "DapperUtilityCoin" +import "Profile" +import "Debug" +import "Clock" +import "Sender" +import "ProfileCache" +import "FindUtils" +import "PublicPriceOracle" +import "BandOracle" +/* ///FIND ///Flow Integrated Name Directory - A naming service on flow, -/// Lease a name in the network for as little as 5 FUSD a year, (4 characters cost 100, 3 cost 500) +/// Lease a name in the network for as little as 5 USD a year, (4 characters cost 100, 3 cost 500) Taxonomy: @@ -25,91 +25,126 @@ Taxonomy: - leaseCollection: Collection of the leases an account holds - leaseStatus: FREE|TAKEN|LOCKED, a LOCKED lease can be reopend by the owner. A lease will be locked for 90 days before it is freed */ -pub contract FIND { - - - //Old events not in use anymore we cannot remove - pub event Sold() - pub event SoldAuction() - pub event DirectOfferRejected() - pub event DirectOfferCanceled() - pub event AuctionStarted() - pub event AuctionCanceled() - pub event AuctionBid() - pub event AuctionCanceledReservePrice() - pub event ForSale() - pub event ForAuction() - - // Deprecated in testnet - pub event TokensRewarded() - pub event TokensCanNotBeRewarded() - +access(all) contract FIND { //event when FT is sent - pub event FungibleTokenSent(from:Address, fromName:String?, name:String, toAddress:Address, message:String, tag:String, amount: UFix64, ftType:String) + access(all) event FungibleTokenSent(from:Address, fromName:String?, name:String, toAddress:Address, message:String, tag:String, amount: UFix64, ftType:String) /// An event to singla that there is a name in the network - pub event Name(name: String) + access(all) event Name(name: String) - pub event AddonActivated(name: String, addon:String) + access(all) event AddonActivated(name: String, addon:String) /// Emitted when a name is registred in FIND - pub event Register(name: String, owner: Address, validUntil: UFix64, lockedUntil: UFix64) + access(all) event Register(name: String, owner: Address, validUntil: UFix64, lockedUntil: UFix64) /// Emitted when a name is moved to a new owner - pub event Moved(name: String, previousOwner: Address, newOwner: Address, validUntil: UFix64, lockedUntil: UFix64) + access(all) event Moved(name: String, previousOwner: Address, newOwner: Address, validUntil: UFix64, lockedUntil: UFix64) - /// Emitted when a name is explicistly put up for sale - pub event Sale(name: String, uuid:UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, buyer:Address?, buyerName:String?, buyerAvatar: String?, validUntil: UFix64, lockedUntil: UFix64) + //store the network itself + access(all) let NetworkStoragePath: StoragePath - /// Emitted when an name is put up for on-demand auction - pub event EnglishAuction(name: String, uuid:UInt64, seller: Address, sellerName:String?, amount: UFix64, auctionReservePrice: UFix64, status: String, vaultType:String, buyer:Address?, buyerName:String?, buyerAvatar: String?, endsAt: UFix64?, validUntil: UFix64, lockedUntil: UFix64, previousBuyer:Address?, previousBuyerName:String?) + //store the leases you own + access(all) let LeaseStoragePath: StoragePath + access(all) let LeasePublicPath: PublicPath - /// Emitted if a bid occurs at a name that is too low or not for sale - pub event DirectOffer(name: String, uuid:UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, buyer:Address?, buyerName:String?, buyerAvatar: String?, validUntil: UFix64, lockedUntil: UFix64, previousBuyer:Address?, previousBuyerName:String?) + access(all) fun getLeases() : &[NetworkLease] { + if let network = self.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) { + return network.profiles.values + } + panic("Network is not set up") + } - pub event RoyaltyPaid(name: String, uuid: UInt64, address: Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, saleType: String) + ////////////////////////////////////////// + // ORACLE + ////////////////////////////////////////// + // Get the latest FLOW/USD price + //This uses the FLOW/USD increment.fi oracle + access(all) fun getLatestPrice(): UFix64 { + let lastResult = PublicPriceOracle.getLatestPrice(oracleAddr: self.getFlowUSDOracleAddress()) + let lastBlockNum = PublicPriceOracle.getLatestBlockHeight(oracleAddr: self.getFlowUSDOracleAddress()) - //store bids made by a bidder to somebody elses leases - pub let BidPublicPath: PublicPath - pub let BidStoragePath: StoragePath + // Make sure the price is not expired + if getCurrentBlock().height - lastBlockNum > 2000 { + return FIND.getLatestPriceBand() + } - //store the network itself - pub let NetworkStoragePath: StoragePath - pub let NetworkPrivatePath: PrivatePath + return lastResult + } - //store the leases you own - pub let LeaseStoragePath: StoragePath - pub let LeasePublicPath: PublicPath + //this uses band oracle, we use this as backup + access(all) fun getLatestPriceBand(): UFix64 { - pub fun getLeases() : [NetworkLease] { - if let network = self.account.borrow<&Network>(from: FIND.NetworkStoragePath) { - return network.profiles.values + let acct = FIND.account + let vaultRef = acct.storage.borrow(from: /storage/flowTokenVault) ?? panic("Cannot borrow reference to signer's FLOW vault") + let payment <- vaultRef.withdraw(amount: BandOracle.getFee()) + let baseSymbol="FLOW" + let quoteSymbol="USDC" + let quote =BandOracle.getReferenceData (baseSymbol: baseSymbol, quoteSymbol: quoteSymbol, payment: <- payment) + + return quote.fixedPointRate + } + + + + access(all) fun convertFLOWToUSD(_ amount: UFix64): UFix64 { + return amount * self.getLatestPrice() + } + + access(all) fun convertUSDToFLOW(_ amount: UFix64): UFix64 { + return amount / self.getLatestPrice() + } + + ////////////////////////////////////////// + // HELPER FUNCTIONS + ////////////////////////////////////////// + + //These methods are basically just here for convenience + + access(all) fun calculateCostInFlow(_ name:String) : UFix64 { + if !FIND.validateFindName(name) { + panic("A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") } + + if let network = FIND.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) { + return self.convertUSDToFLOW(network.calculateCost(name)) + } panic("Network is not set up") } + access(all) fun calculateAddonCostInFlow(_ addon: String) : UFix64 { + let network=FIND.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath)! - //These methods are basically just here for convenience + if !network.publicEnabled { + panic("Public registration is not enabled yet") + } + + if network.addonPrices[addon] == nil { + panic("This addon is not available. addon : ".concat(addon)) + } + var addonPrice = network.addonPrices[addon]! + let cost= FIND.convertUSDToFLOW(addonPrice) + return cost + } /// Calculate the cost of an name /// @param _ the name to calculate the cost for - pub fun calculateCost(_ name:String) : UFix64 { + access(all) fun calculateCost(_ name:String) : UFix64 { if !FIND.validateFindName(name) { panic("A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") } - if let network = self.account.borrow<&Network>(from: FIND.NetworkStoragePath) { + if let network = self.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) { return network.calculateCost(name) } panic("Network is not set up") } - pub fun resolve(_ input:String) : Address? { + access(all) fun resolve(_ input:String) : Address? { let trimmedInput = FIND.trimFindSuffix(input) if FIND.validateFindName(trimmedInput) { - if let network = self.account.borrow<&Network>(from: FIND.NetworkStoragePath) { + if let network = self.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) { return network.lookup(trimmedInput)?.owner?.address } @@ -131,7 +166,7 @@ pub contract FIND { } /// Lookup the address registered for a name - pub fun lookupAddress(_ name:String): Address? { + access(all) fun lookupAddress(_ name:String): Address? { let trimmedName = FIND.trimFindSuffix(name) @@ -139,47 +174,42 @@ pub contract FIND { panic("A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") } - if let network = self.account.borrow<&Network>(from: FIND.NetworkStoragePath) { + if let network = self.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) { return network.lookup(trimmedName)?.owner?.address } return nil } /// Lookup the profile registered for a name - pub fun lookup(_ input:String): &{Profile.Public}? { + access(all) fun lookup(_ input:String): &{Profile.Public}? { if let address = FIND.resolve(input) { let account = getAccount(address) - let cap = account.getCapability<&{Profile.Public}>(Profile.publicPath) - if cap.check() { - return cap.borrow() - } + return account.capabilities.borrow<&{Profile.Public}>(Profile.publicPath) } return nil } - - pub fun reverseLookupFN() : ((Address) : String?) { + access(all) fun reverseLookupFN() : fun(Address) : String? { return fun(address:Address): String? { return FIND.reverseLookup(address) } } /// lookup if an address has a .find name, if it does pick either the default one or the first registered - pub fun reverseLookup(_ address:Address): String? { + access(all) fun reverseLookup(_ address:Address): String? { let leaseNameCache = ProfileCache.getAddressLeaseName(address) if leaseNameCache == nil { - let account=getAccount(address) - let leaseCap = account.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) + let leaseOptCol = getAccount(address).capabilities.borrow<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !leaseCap.check() { + if leaseOptCol == nil { return nil } let profileFindName= Profile.find(address).getFindName() - let network = self.account.borrow<&Network>(from: FIND.NetworkStoragePath) ?? panic("Network is not set up") + let network = self.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) ?? panic("Network is not set up") if profileFindName != "" { let status = network.readStatus(profileFindName) @@ -191,7 +221,7 @@ pub contract FIND { } } - let leaseCol = leaseCap.borrow()! + let leaseCol = leaseOptCol! let nameLeases = leaseCol.getNames() for nameLease in nameLeases { @@ -219,7 +249,7 @@ pub contract FIND { /// @param tag: The tag to add to the event /// @param vault: The vault to send too /// @param from: The sender that sent the funds - pub fun depositWithTagAndMessage(to:String, message:String, tag: String, vault: @FungibleToken.Vault, from: &Sender.Token){ + access(all) fun depositWithTagAndMessage(to:String, message:String, tag: String, vault: @{FungibleToken.Vault}, from: &Sender.Token){ let fromAddress= from.owner!.address let maybeAddress = FIND.resolve(to) @@ -229,9 +259,7 @@ pub contract FIND { let address=maybeAddress! let account = getAccount(address) - let cap = account.getCapability<&{Profile.Public}>(Profile.publicPath) - if cap.check() { - let profile= cap.borrow()! + if let profile = account.capabilities.borrow<&{Profile.Public}>(Profile.publicPath) { emit FungibleTokenSent(from: fromAddress, fromName: FIND.reverseLookup(fromAddress), name: to, toAddress: profile.getAddress(), message:message, tag:tag, amount:vault.balance, ftType:vault.getType().identifier) profile.deposit(from: <- vault) return @@ -240,12 +268,12 @@ pub contract FIND { var path = "" if vault.getType() == Type<@FlowToken.Vault>() { path ="flowTokenReceiver" - } else if vault.getType() == Type<@FUSD.Vault>() { - path="fusdReceiver" + } else { + panic("Could not find a valid receiver for this vault type") } if path != "" { emit FungibleTokenSent(from: fromAddress, fromName: FIND.reverseLookup(fromAddress), name: "", toAddress: address, message:message, tag:tag, amount:vault.balance, ftType:vault.getType().identifier) - account.getCapability<&{FungibleToken.Receiver}>(PublicPath(identifier: path)!).borrow()!.deposit(from: <- vault) + account.capabilities.borrow<&{FungibleToken.Receiver}>(PublicPath(identifier: path)!)!.deposit(from: <- vault) return } panic("Could not find a valid receiver for this vault type") @@ -256,12 +284,12 @@ pub contract FIND { /// Deposit FT to name /// @param to: The name to send money too /// @param from: The vault to send too - pub fun deposit(to:String, from: @FungibleToken.Vault) { + access(all) fun deposit(to:String, from: @{FungibleToken.Vault}) { if !FIND.validateFindName(to) { panic("A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") } - if let network = self.account.borrow<&Network>(from: FIND.NetworkStoragePath) { + if let network = self.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) { let profile=network.lookup(to) ?? panic("could not find name") profile.deposit(from: <- from) return @@ -271,12 +299,12 @@ pub contract FIND { /// Return the status for a given name /// @return The Name status of a name - pub fun status(_ name: String): NameStatus { + access(all) fun status(_ name: String): NameStatus { if !FIND.validateFindName(name) { panic("A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") } - if let network = self.account.borrow<&Network>(from: FIND.NetworkStoragePath) { + if let network = self.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) { return network.readStatus(name) } panic("Network is not set up") @@ -284,9 +312,9 @@ pub contract FIND { /// Struct holding information about a lease. Contains both the internal status the owner of the lease and if the state is persisted or not. - pub struct NameStatus{ - pub let status: LeaseStatus - pub let owner: Address? + access(all) struct NameStatus{ + access(all) let status: LeaseStatus + access(all) let owner: Address? init(status:LeaseStatus, owner:Address?) { self.status=status @@ -303,22 +331,26 @@ pub contract FIND { ============================================================= */ + access(all) entitlement LeaseOwner + /* Lease is a resource you get back when you register a lease. You can use methods on it to renew the lease or to move to another profile */ - pub resource Lease { + access(all) resource Lease { access(contract) let name: String access(contract) let networkCap: Capability<&Network> + access(contract) var addons: {String: Bool} + + //These fields are here, but they are not in use anymore access(contract) var salePrice: UFix64? access(contract) var auctionStartPrice: UFix64? access(contract) var auctionReservePrice: UFix64? access(contract) var auctionDuration: UFix64 access(contract) var auctionMinBidIncrement: UFix64 access(contract) var auctionExtensionOnLateBid: UFix64 - access(contract) var offerCallback: Capability<&BidCollection{BidCollectionPublic}>? - access(contract) var addons: {String: Bool} + access(contract) var offerCallback: Capability<&BidCollection>? init(name:String, networkCap: Capability<&Network>) { self.name=name @@ -333,15 +365,15 @@ pub contract FIND { self.addons={} } - pub fun getName() : String { + access(all) fun getName() : String { return self.name } - pub fun getAddon() : [String] { + access(all) fun getAddon() : [String] { return self.addons.keys } - pub fun checkAddon(addon: String) : Bool { + access(all) fun checkAddon(addon: String) : Bool { if !self.addons.containsKey(addon) { return false } @@ -352,40 +384,12 @@ pub contract FIND { self.addons[addon]=true } - pub fun setExtentionOnLateBid(_ time: UFix64) { - self.auctionExtensionOnLateBid=time - } - - pub fun setAuctionDuration(_ duration: UFix64) { - self.auctionDuration=duration - } - - pub fun setSalePrice(_ price: UFix64?) { - self.salePrice=price - } - - pub fun setReservePrice(_ price: UFix64?) { - self.auctionReservePrice=price - } - - pub fun setMinBidIncrement(_ price: UFix64) { - self.auctionMinBidIncrement=price - } - - pub fun setStartAuctionPrice(_ price: UFix64?) { - self.auctionStartPrice=price - } - - pub fun setCallback(_ callback: Capability<&BidCollection{BidCollectionPublic}>?) { - self.offerCallback=callback - } - - pub fun extendLease(_ vault: @FUSD.Vault) { + access(LeaseOwner) fun extendLease(_ vault: @FlowToken.Vault) { let network= self.networkCap.borrow() ?? panic("The network is not up") network.renew(name: self.name, vault:<- vault) } - pub fun extendLeaseDapper(merchAccount: Address, vault: @DapperUtilityCoin.Vault) { + access(LeaseOwner) fun extendLeaseDapper(merchAccount: Address, vault: @DapperUtilityCoin.Vault) { let network= self.networkCap.borrow() ?? panic("The network is not up") network.renewDapper(merchAccount: merchAccount, name: self.name, vault:<- vault) } @@ -406,8 +410,9 @@ pub contract FIND { // sender let sender = Profile.find(senderAddress) if sender.getFindName() == self.name { - let network = FIND.account.borrow<&Network>(from: FIND.NetworkStoragePath) ?? panic("Network is not set up") - let leaseCol = getAccount(senderAddress).getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath).borrow()! + let network = FIND.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) ?? panic("Network is not set up") + let leaseCol = getAccount(senderAddress).capabilities.borrow<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) ?? panic("Could not borrow lease collection") + let nameLeases = leaseCol.getNames() for nameLease in nameLeases { @@ -425,26 +430,26 @@ pub contract FIND { } } - pub fun getLeaseExpireTime() : UFix64 { + access(all) fun getLeaseExpireTime() : UFix64 { let network = self.networkCap.borrow() ?? panic("The network is not up") return network.getLeaseExpireTime(self.name) } - pub fun getLeaseLockedUntil() : UFix64 { + access(all) fun getLeaseLockedUntil() : UFix64 { let network = self.networkCap.borrow() ?? panic("The network is not up") return network.getLeaseLockedUntil(self.name) } - pub fun getProfile():&{Profile.Public}? { + access(all) fun getProfile():&{Profile.Public}? { let network = self.networkCap.borrow() ?? panic("The network is not up") return network.profile(self.name) } - pub fun getLeaseStatus() : LeaseStatus { + access(all) fun getLeaseStatus() : LeaseStatus { return FIND.status(self.name).status } - pub fun validate() : Bool { + access(all) fun validate() : Bool { // if network is not there anymore, it is not valid if !self.networkCap.check() { return false @@ -453,102 +458,45 @@ pub contract FIND { let lease = network.getLease(self.name) // if the network lease is nil, it is definitely not validated if lease == nil { + Debug.log("no lease") return false } + // regardless of the status (FREE / LOCKED / TAKEN) - // (because other functions checks that) + //TODO: these comments here are wrong... + // (because other functions checks that) // if this lease is not the current / latest owner, this lease is not valid anymore let registeredOwner = lease!.profile.address if registeredOwner == self.owner?.address { + if lease!.status() == LeaseStatus.FREE { + return false + } return true } + return false } } - /* An Auction for a lease */ - pub resource Auction { - access(contract) var endsAt: UFix64 - access(contract) var startedAt: UFix64 - access(contract) let extendOnLateBid: UFix64 - access(contract) var latestBidCallback: Capability<&BidCollection{BidCollectionPublic}> - access(contract) let name: String - - init(endsAt: UFix64, startedAt: UFix64, extendOnLateBid: UFix64, latestBidCallback: Capability<&BidCollection{BidCollectionPublic}>, name: String) { - - if startedAt >= endsAt { - panic("Cannot start before it will end") - } - if extendOnLateBid == 0.0 { - panic("Extends on late bid must be a non zero value") - } - self.endsAt=endsAt - self.startedAt=startedAt - self.extendOnLateBid=extendOnLateBid - self.latestBidCallback=latestBidCallback - self.name=name - } - pub fun getBalance() : UFix64 { - let cb = self.latestBidCallback.borrow() ?? panic("The bidder has unlinked the capability. bidder address: ".concat(self.latestBidCallback.address.toString())) - return cb.getBalance(self.name) - } - - pub fun addBid(callback: Capability<&BidCollection{BidCollectionPublic}>, timestamp: UFix64, lease: &Lease) { - let offer=callback.borrow()! - offer.setBidType(name: self.name, type: "auction") - - var previousBuyer: Address?=nil - if callback.address != self.latestBidCallback.address { - if offer.getBalance(self.name) <= self.getBalance() { - panic("bid must be larger then current bid. Current bid is : ".concat(self.getBalance().toString()).concat(". New bid is at : ").concat(offer.getBalance(self.name).toString())) - } - previousBuyer=self.latestBidCallback.address - //we send the money back - self.latestBidCallback.borrow()!.cancel(self.name) - } - self.latestBidCallback=callback - let suggestedEndTime=timestamp+self.extendOnLateBid - if suggestedEndTime > self.endsAt { - self.endsAt=suggestedEndTime - } - - let bidder= callback.address - let profile=getAccount(bidder).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() - if profile == nil { - panic("Create a profile before you make a bid") - } - let bidderName= profile!.getName() - let bidderAvatar= profile!.getAvatar() - let owner=lease.owner!.address - let ownerName=self.name - - var previousBuyerName:String?=nil - if let pb = previousBuyer { - previousBuyerName=FIND.reverseLookup(pb) - } - - emit EnglishAuction(name: self.name, uuid: lease.uuid, seller: owner, sellerName:ownerName, amount: offer.getBalance(self.name), auctionReservePrice: lease.auctionReservePrice!, status: "active_ongoing", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar:bidderAvatar, endsAt: self.endsAt ,validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - } - } //struct to expose information about leases - pub struct LeaseInformation { - pub let name: String - pub let address: Address - pub let cost: UFix64 - pub let status: String - pub let validUntil: UFix64 - pub let lockedUntil: UFix64 - pub let latestBid: UFix64? - pub let auctionEnds: UFix64? - pub let salePrice: UFix64? - pub let latestBidBy: Address? - pub let currentTime: UFix64 - pub let auctionStartPrice: UFix64? - pub let auctionReservePrice: UFix64? - pub let extensionOnLateBid: UFix64? - pub let addons: [String] + access(all) struct LeaseInformation { + access(all) let name: String + access(all) let address: Address + access(all) let cost: UFix64 + access(all) let status: String + access(all) let validUntil: UFix64 + access(all) let lockedUntil: UFix64 + access(all) let latestBid: UFix64? + access(all) let auctionEnds: UFix64? + access(all) let salePrice: UFix64? + access(all) let latestBidBy: Address? + access(all) let currentTime: UFix64 + access(all) let auctionStartPrice: UFix64? + access(all) let auctionReservePrice: UFix64? + access(all) let extensionOnLateBid: UFix64? + access(all) let addons: [String] init(name: String, status:LeaseStatus, validUntil: UFix64, lockedUntil:UFix64, latestBid: UFix64?, auctionEnds: UFix64?, salePrice: UFix64?, latestBidBy: Address?, auctionStartPrice: UFix64?, auctionReservePrice: UFix64?, extensionOnLateBid:UFix64?, address:Address, addons: [String]){ @@ -575,48 +523,41 @@ pub contract FIND { self.addons=addons } + access(all) fun getAddons() : [String] { + return self.addons + } } /* Since a single account can own more then one name there is a collecition of them This collection has build in support for direct sale of a FIND leaseToken. The network owner till take 2.5% cut */ - pub resource interface LeaseCollectionPublic { + access(all) resource interface LeaseCollectionPublic { //fetch all the tokens in the collection - pub fun getLeases(): [String] - pub fun getInvalidatedLeases(): [String] + access(all) fun getLeases(): [String] + access(all) fun getInvalidatedLeases(): [String] //fetch all names that are for sale - pub fun getLeaseInformation() : [LeaseInformation] - pub fun getLease(_ name: String) :LeaseInformation? + access(all) fun getLeaseInformation() : [LeaseInformation] + access(all) fun getLease(_ name: String) :LeaseInformation? //add a new lease token to the collection, can only be called in this contract access(contract) fun deposit(token: @FIND.Lease) - access(contract)fun cancelUserBid(_ name: String) - access(contract) fun increaseBid(_ name: String, balance: UFix64) - - //place a bid on a token - access(contract) fun registerBid(name: String, callback: Capability<&BidCollection{BidCollectionPublic}>) - - //anybody should be able to fulfill an auction as long as it is done - pub fun fulfillAuction(_ name: String) - pub fun buyAddon(name:String, addon: String, vault: @FUSD.Vault) - pub fun buyAddonDapper(merchAccount: Address, name:String, addon:String, vault: @DapperUtilityCoin.Vault) + access(all) fun buyAddon(name:String, addon: String, vault: @FlowToken.Vault) + access(all) fun buyAddonDapper(merchAccount: Address, name:String, addon:String, vault: @DapperUtilityCoin.Vault) access(account) fun adminAddAddon(name:String, addon: String) - pub fun getAddon(name:String) : [String] - pub fun checkAddon(name:String, addon: String) : Bool + access(all) fun getAddon(name:String) : [String] + access(all) fun checkAddon(name:String, addon: String) : Bool access(account) fun getNames() : [String] access(account) fun containsName(_ name: String) : Bool - access(account) fun move(name: String, profile: Capability<&{Profile.Public}>, to: Capability<&LeaseCollection{LeaseCollectionPublic}>) - pub fun getLeaseUUID(_ name: String) : UInt64 + access(LeaseOwner) fun move(name: String, profile: Capability<&{Profile.Public}>, to: Capability<&LeaseCollection>) + access(all) fun getLeaseUUID(_ name: String) : UInt64 } - - pub resource LeaseCollection: LeaseCollectionPublic { + access(all) resource LeaseCollection: LeaseCollectionPublic { // dictionary of NFT conforming tokens // NFT is a resource type with an `UInt64` ID field access(contract) var leases: @{String: FIND.Lease} - access(contract) var auctions: @{String: Auction} //the cut the network will take, default 2.5% @@ -632,23 +573,13 @@ pub contract FIND { self.networkWallet=networkWallet } - pub fun buyAddon(name:String, addon:String, vault: @FUSD.Vault) { + access(all) fun buyAddon(name:String, addon:String, vault: @FlowToken.Vault) { if !self.leases.containsKey(name) { panic("Invalid name=".concat(name)) } + let cost=FIND.calculateAddonCostInFlow(addon) - let network=FIND.account.borrow<&Network>(from: FIND.NetworkStoragePath)! - - if !network.publicEnabled { - panic("Public registration is not enabled yet") - } - - if network.addonPrices[addon] == nil { - panic("This addon is not available. addon : ".concat(addon)) - } - let addonPrice = network.addonPrices[addon]! - - let lease = self.borrow(name) + let lease = self.borrowAuth(name) if !lease.validate() { panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) @@ -658,8 +589,8 @@ pub contract FIND { panic("You already have this addon : ".concat(addon)) } - if vault.balance != addonPrice { - panic("Expect ".concat(addonPrice.toString()).concat(" FUSD for ").concat(addon).concat(" addon")) + if vault.balance != cost { + panic("Expect ".concat(cost.toString()).concat(" FLOW for ").concat(addon).concat(" addon")) } lease.addAddon(addon) @@ -670,14 +601,14 @@ pub contract FIND { networkWallet.deposit(from: <- vault) } - pub fun buyAddonDapper(merchAccount: Address, name:String, addon:String, vault: @DapperUtilityCoin.Vault) { + access(all) fun buyAddonDapper(merchAccount: Address, name:String, addon:String, vault: @DapperUtilityCoin.Vault) { FIND.checkMerchantAddress(merchAccount) if !self.leases.containsKey(name) { panic("Invalid name=".concat(name)) } - let network=FIND.account.borrow<&Network>(from: FIND.NetworkStoragePath)! + let network=FIND.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath)! if !network.publicEnabled { panic("Public registration is not enabled yet") @@ -688,7 +619,7 @@ pub contract FIND { } let addonPrice = network.addonPrices[addon]! - let lease = self.borrow(name) + let lease = self.borrowAuth(name) if !lease.validate() { panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) @@ -710,10 +641,8 @@ pub contract FIND { // This is here just to check if the network is up let networkWallet = self.networkWallet.borrow() ?? panic("The network is not up") - let wallet = getAccount(merchAccount).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) - - let walletRef = wallet.borrow() ?? panic("Cannot borrow reference to Dapper Merch Account receiver. Address : ".concat(merchAccount.toString())) - walletRef.deposit(from: <- vault) + let wallet = getAccount(merchAccount).capabilities.borrow<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) ?? panic("Cannot borrow reference to Dapper Merch Account receiver. Address : ".concat(merchAccount.toString())) + wallet.deposit(from: <- vault) } access(account) fun adminAddAddon(name:String, addon:String) { @@ -721,7 +650,7 @@ pub contract FIND { panic("Invalid name=".concat(name)) } - let network=FIND.account.borrow<&Network>(from: FIND.NetworkStoragePath)! + let network=FIND.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath)! if !network.publicEnabled { panic("Public registration is not enabled yet") @@ -732,7 +661,7 @@ pub contract FIND { } let addonPrice = network.addonPrices[addon]! - let lease = self.borrow(name) + let lease = self.borrowAuth(name) if !lease.validate() { panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) @@ -748,31 +677,31 @@ pub contract FIND { emit AddonActivated(name: name, addon: addon) } - pub fun getAddon(name: String) : [String] { - let lease = self.borrow(name) + access(all) fun getAddon(name: String) : [String] { + let lease = self.borrowAuth(name) if !lease.validate() { return [] } return lease.getAddon() } - pub fun checkAddon(name:String, addon: String) : Bool { - let lease = self.borrow(name) + access(all) fun checkAddon(name:String, addon: String) : Bool { + let lease = self.borrowAuth(name) if !lease.validate() { return false } return lease.checkAddon(addon: addon) } - pub fun getLeaseUUID(_ name: String) : UInt64 { - return self.borrow(name).uuid + access(all) fun getLeaseUUID(_ name: String) : UInt64 { + return self.borrowAuth(name).uuid } - pub fun getLease(_ name: String) : LeaseInformation? { + access(all) fun getLease(_ name: String) : LeaseInformation? { if !self.leases.containsKey(name) { return nil } - let token=self.borrow(name) + let token=self.borrowAuth(name) if !token.validate() { return nil @@ -783,19 +712,7 @@ pub contract FIND { var auctionEnds: UFix64?= nil var latestBidBy: Address?=nil - if self.auctions.containsKey(name) { - let auction = self.borrowAuction(name) - auctionEnds= auction.endsAt - latestBid= auction.getBalance() - latestBidBy= auction.latestBidCallback.address - } else { - if let callback = token.offerCallback { - latestBid= callback.borrow()!.getBalance(name) - latestBidBy=callback.address - } - } - - return LeaseInformation(name: name, status: token.getLeaseStatus(), validUntil: token.getLeaseExpireTime(), lockedUntil: token.getLeaseLockedUntil(), latestBid: latestBid, auctionEnds: auctionEnds, salePrice: token.salePrice, latestBidBy: latestBidBy, auctionStartPrice: token.auctionStartPrice, auctionReservePrice: token.auctionReservePrice, extensionOnLateBid: token.auctionExtensionOnLateBid, address: token.owner!.address, addons: token.addons.keys) + return LeaseInformation(name: name, status: token.getLeaseStatus(), validUntil: token.getLeaseExpireTime(), lockedUntil: token.getLeaseLockedUntil(), latestBid: latestBid, auctionEnds: auctionEnds, salePrice: token.salePrice, latestBidBy: latestBidBy, auctionStartPrice: token.auctionStartPrice, auctionReservePrice: token.auctionReservePrice, extensionOnLateBid: token.auctionExtensionOnLateBid, address: token.owner!.address, addons: token.getAddon()) } access(account) fun getNames() : [String] { @@ -806,7 +723,7 @@ pub contract FIND { return self.leases.containsKey(name) } - pub fun getLeaseInformation() : [LeaseInformation] { + access(all) fun getLeaseInformation() : [LeaseInformation] { var info: [LeaseInformation]=[] for name in self.leases.keys { // if !FIND.validateFindName(name) { @@ -820,463 +737,10 @@ pub contract FIND { return info } - //call this to start an auction for this lease - pub fun startAuction(_ name: String) { - let timestamp=Clock.time() - let lease = self.borrow(name) - - if !lease.validate() { - panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) - } - - let duration=lease.auctionDuration - let extensionOnLateBid=lease.auctionExtensionOnLateBid - if lease.offerCallback == nil { - panic("cannot start an auction on a name without a bid, set salePrice") - } - - let callback=lease.offerCallback! - let offer=callback.borrow()! - offer.setBidType(name: name, type: "auction") - - - - let bidder= callback.address - let bidderProfile= getAccount(bidder).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() ?? panic("Bidder unlinked the profile capability. bidder address : ".concat(bidder.toString())) - let bidderName= bidderProfile.getName() - let bidderAvatar= bidderProfile.getAvatar() - let owner=lease.owner!.address - let ownerName=lease.name - - let endsAt=timestamp + duration - emit EnglishAuction(name: name, uuid:lease.uuid, seller: owner, sellerName:FIND.reverseLookup(owner), amount: offer.getBalance(name), auctionReservePrice: lease.auctionReservePrice!, status: "active_ongoing", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar:bidderAvatar, endsAt: endsAt, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - - let oldAuction <- self.auctions[name] <- create Auction(endsAt:endsAt, startedAt: timestamp, extendOnLateBid: extensionOnLateBid, latestBidCallback: callback, name: name) - lease.setCallback(nil) - - if lease.offerCallback == nil { - Debug.log("offer callback is empty") - }else { - Debug.log("offer callback is NOT empty") - } - - destroy oldAuction - } - - access(contract) fun cancelUserBid(_ name: String) { - - if !self.leases.containsKey(name) { - panic("Invalid name=".concat(name)) - } - - if self.auctions.containsKey(name) { - panic("Cannot cancel a bid that is in an auction=".concat(name)) - } - - let lease= self.borrow(name) - - if let callback = lease.offerCallback { - - let bidder= callback.address - let bidderProfile= getAccount(bidder).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() - let bidderName=bidderProfile?.getName() - let bidderAvatar=bidderProfile?.getAvatar() - let owner=lease.owner!.address - let ownerName=lease.name - var amount : UFix64 = 0.0 - if callback.check() { - amount = callback.borrow()!.getBalance(name) - } - emit DirectOffer(name: name, uuid: lease.uuid, seller: owner, sellerName: ownerName, amount: amount, status: "cancel_rejected", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - } - - lease.setCallback(nil) - } - - access(contract) fun increaseBid(_ name: String, balance: UFix64) { - if !self.leases.containsKey(name) { - panic("Invalid name=".concat(name)) - } - - let lease = self.borrow(name) - - if !lease.validate() { - panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) - } - - let timestamp=Clock.time() - - if balance < lease.auctionMinBidIncrement { - panic("Increment should be greater than ".concat(lease.auctionMinBidIncrement.toString())) - } - if self.auctions.containsKey(name) { - let auction = self.borrowAuction(name) - if auction.endsAt < timestamp { - panic("Auction has ended") - } - auction.addBid(callback:auction.latestBidCallback, timestamp:timestamp, lease: lease) - return - } - - - let bidder= lease.offerCallback!.address - let bidderProfile= getAccount(bidder).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() ?? panic("Create a profile before you make a bid") - let bidderName= bidderProfile.getName() - let bidderAvatar= bidderProfile.getAvatar() - let owner=lease.owner!.address - let ownerName=lease.name - - let balance=lease.offerCallback!.borrow()?.getBalance(name) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(bidder.toString())) - Debug.log("Offer is at ".concat(balance.toString())) - if lease.salePrice == nil && lease.auctionStartPrice == nil{ - - emit DirectOffer(name: name, uuid: lease.uuid, seller: owner, sellerName: ownerName, amount: balance, status: "active_offered", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - return - } - - - if lease.salePrice != nil && lease.salePrice != nil && balance >= lease.salePrice! { - self.fulfill(name) - } else if lease.auctionStartPrice != nil && balance >= lease.auctionStartPrice! { - self.startAuction(name) - } else { - emit DirectOffer(name: name, uuid: lease.uuid, seller: owner, sellerName: ownerName, amount: balance, status: "active_offered", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - } - - } - - access(contract) fun registerBid(name: String, callback: Capability<&BidCollection{BidCollectionPublic}>) { - - if !self.leases.containsKey(name) { - panic("Invalid name=".concat(name)) - } - - let timestamp=Clock.time() - let lease = self.borrow(name) - - if !lease.validate() { - panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) - } - - if self.auctions.containsKey(name) { - let auction = self.borrowAuction(name) - - if auction.latestBidCallback.address == callback.address { - panic("You already have the latest bid on this item, use the incraseBid transaction") - } - if auction.endsAt < timestamp { - panic("Auction has ended") - } - auction.addBid(callback:callback, timestamp:timestamp, lease: lease) - return - } - - let balance=callback.borrow()?.getBalance(name) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) - var previousBuyer:Address?=nil - if let cb= lease.offerCallback { - if cb.address == callback.address { - panic("You already have the latest bid on this item, use the incraseBid transaction") - } - let cbRef = cb.borrow() ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(cb.address.toString())) - let currentBalance=cbRef.getBalance(name) - - Debug.log("currentBalance=".concat(currentBalance.toString()).concat(" new bid is at=").concat(balance.toString())) - if currentBalance >= balance { - panic("There is already a higher bid on this lease. Current bid is : ".concat(currentBalance.toString()).concat(" New bid is at : ").concat(balance.toString())) - } - previousBuyer=cb.address - cbRef.cancel(name) - } - - lease.setCallback(callback) - - - - let bidder= callback.address - let profile=getAccount(bidder).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() - if profile == nil { - panic("Create a profile before you make a bid") - } - let bidderName= profile!.getName() - let bidderAvatar= profile!.getAvatar() - let owner=lease.owner!.address - let ownerName=lease.name - - var previousBuyerName:String?=nil - if let pb=previousBuyer { - previousBuyerName=FIND.reverseLookup(pb) - } - Debug.log("Balance of lease is at ".concat(balance.toString())) - if lease.salePrice == nil && lease.auctionStartPrice == nil { - Debug.log("Sale price not set") - emit DirectOffer(name: name, uuid:lease.uuid, seller: owner, sellerName: ownerName, amount: balance, status: "active_offered", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - return - } - - if lease.salePrice != nil && balance >= lease.salePrice! { - Debug.log("Direct sale!") - self.fulfill(name) - } else if lease.auctionStartPrice != nil && balance >= lease.auctionStartPrice! { - self.startAuction(name) - } else { - emit DirectOffer(name: name, uuid: lease.uuid, seller: owner, sellerName: ownerName, amount: balance, status: "active_offered", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - } - } - - //cancel will cancel and auction or reject a bid if no auction has started - pub fun cancel(_ name: String) { - - if !self.leases.containsKey(name) { - panic("Invalid name=".concat(name)) - } - - let lease = self.borrow(name) - //if we have a callback there is no auction and it is a blind bid - if let cb= lease.offerCallback { - - let bidder= cb.address - let bidderProfile= getAccount(bidder).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() - let bidderName= bidderProfile?.getName() - let bidderAvatar= bidderProfile?.getAvatar() - let owner=lease.owner!.address - let ownerName=lease.name - Debug.log("we have a blind bid so we cancel that") - let cbRef = cb.borrow() ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(cb.address.toString())) - emit DirectOffer(name: name, uuid:lease.uuid, seller: owner, sellerName: ownerName, amount: cbRef.getBalance(name), status: "rejected", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - - cbRef.cancel(name) - lease.setCallback(nil) - } - - if self.auctions.containsKey(name) { - - let auction=self.borrowAuction(name) - let balance=auction.getBalance() - - let auctionEnded= auction.endsAt <= Clock.time() - var hasMetReservePrice= false - if lease.auctionReservePrice != nil && lease.auctionReservePrice! <= balance { - hasMetReservePrice=true - } - let price= lease.auctionReservePrice?.toString() ?? "" - //the auction has ended - Debug.log("Latest bid is ".concat(balance.toString()).concat(" reserve price is ").concat(price)) - if auctionEnded && hasMetReservePrice { - //&& lease.auctionReservePrice != nil && lease.auctionReservePrice! < balance { - panic("Cannot cancel finished auction, fulfill it instead") - } - - let bidder= auction.latestBidCallback.address - let bidderProfile= getAccount(bidder).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() - let bidderName= bidderProfile?.getName() - let bidderAvatar= bidderProfile?.getAvatar() - let owner=lease.owner!.address - let ownerName=lease.name - - - let leaseInfo = self.getLease(name)! - - if auctionEnded { - emit EnglishAuction(name: name, uuid:lease.uuid, seller: owner, sellerName:ownerName, amount: balance, auctionReservePrice: lease.auctionReservePrice!, status: "cancel_reserved_not_met", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, endsAt: auction.endsAt, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - } else { - emit EnglishAuction(name: name, uuid:lease.uuid, seller: owner, sellerName:ownerName, amount: balance, auctionReservePrice: lease.auctionReservePrice!, status: "cancel_listing", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, endsAt: auction.endsAt, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - } - let cbRef = auction.latestBidCallback.borrow() ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(bidder.toString())) - cbRef.cancel(name) - destroy <- self.auctions.remove(key: name)! - return - } - let owner=lease.owner!.address - let ownerName=lease.name - emit EnglishAuction(name: name, uuid:lease.uuid, seller: owner, sellerName:ownerName, amount: 0.0, auctionReservePrice: lease.auctionReservePrice!, status: "cancel_listing", vaultType:Type<@FUSD.Vault>().identifier, buyer:nil, buyerName:nil, buyerAvatar: nil, endsAt: nil, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - - } - - /// fulfillAuction wraps the fulfill method and ensure that only a finished auction can be fulfilled by anybody - pub fun fulfillAuction(_ name: String) { - if !self.leases.containsKey(name) { - panic("Invalid name=".concat(name)) - } - - if !self.auctions.containsKey(name) { - panic("Cannot fulfill sale that is not an auction=".concat(name)) - } - - return self.fulfill(name) - } - - pub fun fulfill(_ name: String) { - if !self.leases.containsKey(name) { - panic( "Invalid name=".concat(name)) - } - let lease = self.borrow(name) + access(LeaseOwner) fun move(name: String, profile: Capability<&{Profile.Public}>, to: Capability<&LeaseCollection>) { - if !lease.validate() { - panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) - } - - if lease.getLeaseStatus() == LeaseStatus.FREE { - panic("cannot fulfill sale name is now free") - } - - let oldProfile=lease.getProfile()! - - if let cb= lease.offerCallback { - let offer= cb.borrow()! - let newProfile= getAccount(cb.address).getCapability<&{Profile.Public}>(Profile.publicPath) - let avatar= newProfile.borrow()?.getAvatar() ?? panic("Create a profile before you fulfill a bid") - let soldFor=offer.getBalance(name) - - //move the token to the new profile - lease.move(profile: newProfile) - if lease.salePrice == nil || lease.salePrice != soldFor { - emit DirectOffer(name: name, uuid: lease.uuid, seller: lease.owner!.address, sellerName: FIND.reverseLookup(lease.owner!.address), amount: soldFor, status: "sold", vaultType:Type<@FUSD.Vault>().identifier, buyer:newProfile.address, buyerName:FIND.reverseLookup(newProfile.address), buyerAvatar: avatar, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - } else { - emit Sale(name: name, uuid: lease.uuid, seller: lease.owner!.address, sellerName: FIND.reverseLookup(lease.owner!.address), amount: soldFor, status: "sold", vaultType:Type<@FUSD.Vault>().identifier, buyer:newProfile.address, buyerName:FIND.reverseLookup(newProfile.address), buyerAvatar: avatar, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil()) - } - - let token <- self.leases.remove(key: name)! - let vault <- offer.fulfillLease(<- token) - if self.networkCut != 0.0 { - let cutAmount= soldFor * self.networkCut - let networkWallet = self.networkWallet.borrow() ?? panic("The network wallet is not set up properly. Wallet address : ".concat(self.networkWallet.address.toString())) - networkWallet.deposit(from: <- vault.withdraw(amount: cutAmount)) - if lease.salePrice == nil || lease.salePrice != soldFor { - emit RoyaltyPaid(name: name, uuid: lease.uuid, address: self.networkWallet.address, findName:FIND.reverseLookup(self.networkWallet.address), royaltyName:"Network", amount: cutAmount, vaultType:vault.getType().identifier, saleType: "DirectOffer") - } else { - emit RoyaltyPaid(name: name, uuid: lease.uuid, address: self.networkWallet.address, findName:FIND.reverseLookup(self.networkWallet.address), royaltyName:"Network", amount: cutAmount, vaultType:vault.getType().identifier, saleType: "Sale") - } - } - - //why not use Profile to send money :P - oldProfile.deposit(from: <- vault) - return - } - - if !self.auctions.containsKey(name) { - panic("Name is not for auction name=".concat(name)) - } - - if self.borrowAuction(name).endsAt > Clock.time() { - panic("Auction has not ended yet") - } - - - let auctionRef=self.borrowAuction(name) - let soldFor=auctionRef.getBalance() - let reservePrice=lease.auctionReservePrice ?? 0.0 - - if reservePrice > soldFor { - self.cancel(name) - return - } - let newProfile= getAccount(auctionRef.latestBidCallback.address).getCapability<&{Profile.Public}>(Profile.publicPath) - let avatar= newProfile.borrow()?.getAvatar() ?? panic("Create a profile before you fulfill a bid") - - - - //move the token to the new profile - lease.move(profile: newProfile) - emit EnglishAuction(name: name, uuid:lease.uuid, seller: lease.owner!.address, sellerName:FIND.reverseLookup(lease.owner!.address), amount: soldFor, auctionReservePrice: lease.auctionReservePrice!, status: "sold", vaultType:Type<@FUSD.Vault>().identifier, buyer:newProfile.address, buyerName:FIND.reverseLookup(newProfile.address), buyerAvatar: avatar, endsAt: self.borrowAuction(name).endsAt, validUntil: lease.getLeaseExpireTime(), lockedUntil: lease.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - let auction <- self.auctions.remove(key: name)! - - let token <- self.leases.remove(key: name)! - - let cbRef = auction.latestBidCallback.borrow() ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(auction.latestBidCallback.address.toString())) - - let vault <- cbRef.fulfillLease(<- token) - if self.networkCut != 0.0 { - let cutAmount= soldFor * self.networkCut - let networkWallet = self.networkWallet.borrow() ?? panic("The network wallet is not set up properly. Wallet address : ".concat(self.networkWallet.address.toString())) - networkWallet.deposit(from: <- vault.withdraw(amount: cutAmount)) - emit RoyaltyPaid(name: name, uuid: lease.uuid, address: self.networkWallet.address, findName:FIND.reverseLookup(self.networkWallet.address), royaltyName:"Network", amount: cutAmount, vaultType:vault.getType().identifier, saleType: "EnglishAuction") - } - - //why not use FIND to send money :P - oldProfile.deposit(from: <- vault) - destroy auction - - } - - pub fun listForAuction(name :String, auctionStartPrice: UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64) { - - if !self.leases.containsKey(name) { - panic("Cannot list name for sale that is not registered to you name=".concat(name)) - } - - let tokenRef = self.borrow(name) - - if !tokenRef.validate() { - panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) - } - - //if we have a callback there is no auction and it is a blind bid - if let cb= tokenRef.offerCallback { - let bidder= cb.address - let bidderProfile= getAccount(bidder).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() - let bidderName= bidderProfile?.getName() - let bidderAvatar= bidderProfile?.getAvatar() - let owner=tokenRef.owner!.address - let ownerName=tokenRef.name - Debug.log("we have a blind bid so we cancel that") - let cbRef = cb.borrow() ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(bidder.toString())) - emit DirectOffer(name: name, uuid:tokenRef.uuid, seller: owner, sellerName: ownerName, amount: cbRef.getBalance(name), status: "rejected", vaultType:Type<@FUSD.Vault>().identifier, buyer:bidder, buyerName:bidderName, buyerAvatar: bidderAvatar, validUntil: tokenRef.getLeaseExpireTime(), lockedUntil: tokenRef.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - cbRef.cancel(name) - tokenRef.setCallback(nil) - } - - tokenRef.setStartAuctionPrice(auctionStartPrice) - tokenRef.setReservePrice(auctionReservePrice) - tokenRef.setAuctionDuration(auctionDuration) - tokenRef.setExtentionOnLateBid(auctionExtensionOnLateBid) - emit EnglishAuction(name: name, uuid: tokenRef.uuid, seller: self.owner!.address, sellerName:FIND.reverseLookup(self.owner!.address), amount: tokenRef.auctionStartPrice!, auctionReservePrice: tokenRef.auctionReservePrice!, status: "active_listed", vaultType:Type<@FUSD.Vault>().identifier, buyer:nil, buyerName:nil, buyerAvatar: nil, endsAt: nil, validUntil: tokenRef.getLeaseExpireTime(), lockedUntil: tokenRef.getLeaseLockedUntil(), previousBuyer:nil, previousBuyerName:nil) - } - - pub fun listForSale(name :String, directSellPrice:UFix64) { - - if !self.leases.containsKey(name) { - panic("Cannot list name for sale that is not registered to you name=".concat(name)) - } - - let tokenRef = self.borrow(name) - - if !tokenRef.validate() { - panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) - } - - tokenRef.setSalePrice(directSellPrice) - emit Sale(name: name, uuid: tokenRef.uuid, seller: self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: tokenRef.salePrice!, status: "active_listed", vaultType:Type<@FUSD.Vault>().identifier, buyer:nil, buyerName:nil, buyerAvatar: nil, validUntil: tokenRef.getLeaseExpireTime(), lockedUntil: tokenRef.getLeaseLockedUntil()) - } - - - pub fun delistAuction(_ name: String) { - - if !self.leases.containsKey(name) { - panic("Cannot delist name for sale that is not registered to you name=".concat(name)) - } - - let tokenRef = self.borrow(name) - - tokenRef.setStartAuctionPrice(nil) - tokenRef.setReservePrice(nil) - } - - - pub fun delistSale(_ name: String) { - if !self.leases.containsKey(name) { - panic("Cannot list name for sale that is not registered to you name=".concat(name)) - } - - let tokenRef = self.borrow(name) - emit Sale(name: name, uuid:tokenRef.uuid, seller: self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: tokenRef.salePrice!, status: "cancel", vaultType:Type<@FUSD.Vault>().identifier, buyer:nil, buyerName:nil, buyerAvatar: nil, validUntil: tokenRef.getLeaseExpireTime(), lockedUntil: tokenRef.getLeaseLockedUntil()) - tokenRef.setSalePrice(nil) - } - - //note that when moving a name - pub fun move(name: String, profile: Capability<&{Profile.Public}>, to: Capability<&LeaseCollection{LeaseCollectionPublic}>) { - - let lease = self.borrow(name) + let lease = self.borrowAuth(name) if !lease.validate() { panic("This is not a valid lease. Lease already expires and some other user registered it. Lease : ".concat(name)) } @@ -1298,7 +762,7 @@ pub contract FIND { } // getIDs returns an array of the IDs that are in the collection - pub fun getLeases(): [String] { + access(all) fun getLeases(): [String] { var list : [String] = [] for key in self.leases.keys { let lease = self.borrow(key) @@ -1310,7 +774,7 @@ pub contract FIND { return list } - pub fun getInvalidatedLeases(): [String] { + access(all) fun getInvalidatedLeases(): [String] { var list : [String] = [] for key in self.leases.keys { let lease = self.borrow(key) @@ -1324,37 +788,26 @@ pub contract FIND { // borrowNFT gets a reference to an NFT in the collection // so that the caller can read its metadata and call its methods - pub fun borrow(_ name: String): &FIND.Lease { - return (&self.leases[name] as &FIND.Lease?)! + access(all) fun borrow(_ name: String): &FIND.Lease { + return (&self.leases[name])! } - //borrow the auction - pub fun borrowAuction(_ name: String): &FIND.Auction { - return (&self.auctions[name] as &FIND.Auction?)! + access(LeaseOwner) fun borrowAuth(_ name: String): auth(LeaseOwner) &FIND.Lease { + return (&self.leases[name])! } - - //This has to be here since you can only get this from a auth account and thus we ensure that you cannot use wrong paths - pub fun registerUSDC(name: String, vault: @FiatToken.Vault){ - let profileCap = self.owner!.getCapability<&{Profile.Public}>(Profile.publicPath) - let leases= self.owner!.getCapability<&LeaseCollection{LeaseCollectionPublic}>(FIND.LeasePublicPath) - - let network=FIND.account.borrow<&Network>(from: FIND.NetworkStoragePath)! - - if !network.publicEnabled { - panic("Public registration is not enabled yet") - } - - network.registerUSDC(name:name, vault: <- vault, profile: profileCap, leases: leases) + //borrow the auction + access(all) fun borrowAuction(_ name: String): &FIND.Auction { + return (&self.auctions[name])! } //This has to be here since you can only get this from a auth account and thus we ensure that you cannot use wrong paths - pub fun register(name: String, vault: @FUSD.Vault){ - let profileCap = self.owner!.getCapability<&{Profile.Public}>(Profile.publicPath) - let leases= self.owner!.getCapability<&LeaseCollection{LeaseCollectionPublic}>(FIND.LeasePublicPath) + access(LeaseOwner) fun register(name: String, vault: @FlowToken.Vault){ + let profileCap = self.owner!.capabilities.get<&{Profile.Public}>(Profile.publicPath) + let leases= self.owner!.capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - let network=FIND.account.borrow<&Network>(from: FIND.NetworkStoragePath)! + let network=FIND.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath)! if !network.publicEnabled { panic("Public registration is not enabled yet") @@ -1364,11 +817,11 @@ pub contract FIND { } //This has to be here since you can only get this from a auth account and thus we ensure that you cannot use wrong paths - pub fun registerDapper(merchAccount: Address, name: String, vault: @DapperUtilityCoin.Vault){ - let profileCap = self.owner!.getCapability<&{Profile.Public}>(Profile.publicPath) - let leases= self.owner!.getCapability<&LeaseCollection{LeaseCollectionPublic}>(FIND.LeasePublicPath) + access(LeaseOwner) fun registerDapper(merchAccount: Address, name: String, vault: @DapperUtilityCoin.Vault){ + let profileCap = self.owner!.capabilities.get<&{Profile.Public}>(Profile.publicPath) + let leases= self.owner!.capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - let network=FIND.account.borrow<&Network>(from: FIND.NetworkStoragePath)! + let network=FIND.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath)! if !network.publicEnabled { panic("Public registration is not enabled yet") @@ -1377,23 +830,18 @@ pub contract FIND { network.registerDapper(merchAccount: merchAccount, name:name, vault: <- vault, profile: profileCap, leases: leases) } - pub fun cleanUpInvalidatedLease(_ name: String) { - let lease = self.borrow(name) + access(LeaseOwner) fun cleanUpInvalidatedLease(_ name: String) { + let lease = self.borrowAuth(name) if lease.validate() { panic("This is a valid lease. You cannot clean this up. Lease : ".concat(name)) } destroy <- self.leases.remove(key: name)! } - - destroy() { - destroy self.leases - destroy self.auctions - } } //Create an empty lease collection that store your leases to a name - pub fun createEmptyLeaseCollection(): @FIND.LeaseCollection { - if let network = self.account.borrow<&Network>(from: FIND.NetworkStoragePath) { + access(all) fun createEmptyLeaseCollection(): @FIND.LeaseCollection { + if let network = self.account.storage.borrow<&Network>(from: FIND.NetworkStoragePath) { return <- create LeaseCollection(networkCut:network.secondaryCut, networkWallet: network.wallet) } panic("Network is not set up") @@ -1406,14 +854,14 @@ pub contract FIND { //=================================================================================================================== */ //a struct that represents a lease of a name in the network. - pub struct NetworkLease { - pub let registeredTime: UFix64 - pub var validUntil: UFix64 - pub var lockedUntil: UFix64 - pub(set) var profile: Capability<&{Profile.Public}> + access(all) struct NetworkLease { + access(all) let registeredTime: UFix64 + access(all) var validUntil: UFix64 + access(all) var lockedUntil: UFix64 + access(all) var profile: Capability<&{Profile.Public}> // This address is wrong for some account and can never be refered - pub var address: Address - pub var name: String + access(all) var address: Address + access(all) var name: String init( validUntil:UFix64, lockedUntil:UFix64, profile: Capability<&{Profile.Public}>, name: String) { self.validUntil=validUntil @@ -1424,15 +872,15 @@ pub contract FIND { self.name=name } - pub fun setValidUntil(_ unit: UFix64) { + access(all) fun setValidUntil(_ unit: UFix64) { self.validUntil=unit } - pub fun setLockedUntil(_ unit: UFix64) { + access(all) fun setLockedUntil(_ unit: UFix64) { self.lockedUntil=unit } - pub fun status() : LeaseStatus { + access(all) fun status() : LeaseStatus { let time=Clock.time() if time >= self.lockedUntil { @@ -1444,6 +892,10 @@ pub contract FIND { } return LeaseStatus.TAKEN } + + access(all) fun setProfile (_ profile: Capability<&{Profile.Public}>) { + self.profile=profile + } } @@ -1454,16 +906,16 @@ pub contract FIND { */ - pub enum LeaseStatus: UInt8 { - pub case FREE - pub case TAKEN - pub case LOCKED + access(all) enum LeaseStatus: UInt8 { + access(all) case FREE + access(all) case TAKEN + access(all) case LOCKED } /* The main network resource that holds the state of the names in the network */ - pub resource Network { + access(all) resource Network { access(contract) var wallet: Capability<&{FungibleToken.Receiver}> access(contract) let leasePeriod: UFix64 access(contract) let lockPeriod: UFix64 @@ -1494,26 +946,24 @@ pub contract FIND { self.publicEnabled=publicEnabled } - pub fun getLease(_ name: String) : NetworkLease? { + access(all) fun getLease(_ name: String) : NetworkLease? { return self.profiles[name] } - pub fun setAddonPrice(name:String, price:UFix64) { + access(account) fun setAddonPrice(name:String, price:UFix64) { self.addonPrices[name]=price } - pub fun setPrice(default: UFix64, additionalPrices: {Int: UFix64}) { - self.defaultPrice=default + access(account) fun setPrice(defaultPrice: UFix64, additionalPrices: {Int: UFix64}) { + self.defaultPrice=defaultPrice self.lengthPrices=additionalPrices } - - //this method is only called from a lease, and only the owner has that capability - access(contract) fun renew(name: String, vault: @FUSD.Vault) { + access(contract) fun renew(name: String, vault: @FlowToken.Vault) { if let lease= self.profiles[name] { - let cost= self.calculateCost(name) + let cost= FIND.calculateCostInFlow(name) if vault.balance != cost { - panic("Vault did not contain ".concat(cost.toString()).concat(" amount of FUSD")) + panic("Vault did not contain ".concat(cost.toString()).concat(" amount of Flow")) } let walletRef = self.wallet.borrow() ?? panic("The receiver capability is invalid. Wallet address : ".concat(self.wallet.address.toString())) walletRef.deposit(from: <- vault) @@ -1532,9 +982,7 @@ pub contract FIND { if vault.balance != cost { panic("Vault did not contain ".concat(cost.toString()).concat(" amount of Dapper Credit")) } - let wallet = getAccount(merchAccount).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) - - let walletRef = wallet.borrow() ?? panic("Cannot borrow reference to Dapper Merch Account receiver. Address : ".concat(merchAccount.toString())) + let walletRef = getAccount(merchAccount).capabilities.borrow<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) ?? panic("Cannot borrow reference to Dapper Merch Account receiver. Address : ".concat(merchAccount.toString())) walletRef.deposit(from: <- vault) self.internal_renew(name: name) return @@ -1579,46 +1027,15 @@ pub contract FIND { //moving leases are done from the lease collection access(contract) fun move(name: String, profile: Capability<&{Profile.Public}>) { if let lease= self.profiles[name] { - lease.profile=profile + lease.setProfile(profile) self.profiles[name] = lease return } panic("Could not find profile with name=".concat(name)) } - - //everybody can call register, normally done through the convenience method in the contract - pub fun registerUSDC(name: String, vault: @FiatToken.Vault, profile: Capability<&{Profile.Public}>, leases: Capability<&LeaseCollection{LeaseCollectionPublic}>) { - - if name.length < 3 { - panic( "A FIND name has to be minimum 3 letters long") - } - - let nameStatus=self.readStatus(name) - if nameStatus.status == LeaseStatus.TAKEN { - panic("Name already registered") - } - - //if we have a locked profile that is not owned by the same identity then panic - if nameStatus.status == LeaseStatus.LOCKED { - panic("Name is locked") - } - - let cost= self.calculateCost(name) - if vault.balance != cost { - panic("Vault did not contain ".concat(cost.toString()).concat(" amount of FUSD")) - } - - let address=self.wallet.address - let account=getAccount(address) - let usdcCap = account.getCapability<&{FungibleToken.Receiver}>(FiatToken.VaultReceiverPubPath) - let usdcReceiver = usdcCap.borrow() ?? panic("cound not find usdc vault receiver for address".concat(self.wallet.address.toString())) - usdcReceiver.deposit(from: <- vault) - - self.internal_register(name: name, profile: profile, leases: leases) - } //everybody can call register, normally done through the convenience method in the contract - pub fun register(name: String, vault: @FUSD.Vault, profile: Capability<&{Profile.Public}>, leases: Capability<&LeaseCollection{LeaseCollectionPublic}>) { + access(all) fun register(name: String, vault: @FlowToken.Vault, profile: Capability<&{Profile.Public}>, leases: Capability<&{LeaseCollectionPublic}>) { if name.length < 3 { panic( "A FIND name has to be minimum 3 letters long") @@ -1634,9 +1051,9 @@ pub contract FIND { panic("Name is locked") } - let cost= self.calculateCost(name) + let cost= FIND.calculateCostInFlow(name) if vault.balance != cost { - panic("Vault did not contain ".concat(cost.toString()).concat(" amount of FUSD")) + panic("Vault did not contain ".concat(cost.toString()).concat(" amount of Flow")) } self.wallet.borrow()!.deposit(from: <- vault) @@ -1644,7 +1061,7 @@ pub contract FIND { } //everybody can call register, normally done through the convenience method in the contract - pub fun registerDapper(merchAccount: Address, name: String, vault: @DapperUtilityCoin.Vault, profile: Capability<&{Profile.Public}>, leases: Capability<&LeaseCollection{LeaseCollectionPublic}>) { + access(all) fun registerDapper(merchAccount: Address, name: String, vault: @DapperUtilityCoin.Vault, profile: Capability<&{Profile.Public}>, leases: Capability<&{LeaseCollectionPublic}>) { FIND.checkMerchantAddress(merchAccount) if name.length < 3 { @@ -1666,14 +1083,12 @@ pub contract FIND { panic("Vault did not contain ".concat(cost.toString()).concat(" amount of Dapper Credit")) } - let wallet = getAccount(merchAccount).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) - - let walletRef = wallet.borrow() ?? panic("Cannot borrow reference to Dapper Merch Account receiver. Address : ".concat(merchAccount.toString())) + let walletRef = getAccount(merchAccount).capabilities.borrow<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) ?? panic("Cannot borrow reference to Dapper Merch Account receiver. Address : ".concat(merchAccount.toString())) walletRef.deposit(from: <- vault) self.internal_register(name: name, profile: profile, leases: leases) } - access(account) fun internal_register(name: String, profile: Capability<&{Profile.Public}>, leases: Capability<&LeaseCollection{LeaseCollectionPublic}>) { + access(account) fun internal_register(name: String, profile: Capability<&{Profile.Public}>, leases: Capability<&{LeaseCollectionPublic}>) { if name.length < 3 { panic("A FIND name has to be minimum 3 letters long") @@ -1713,11 +1128,11 @@ pub contract FIND { self.profiles[name] = lease - leases.borrow()!.deposit(token: <- create Lease(name: name, networkCap: FIND.account.getCapability<&Network>(FIND.NetworkPrivatePath))) + leases.borrow()!.deposit(token: <- create Lease(name: name, networkCap: FIND.account.capabilities.storage.issue<&Network>(FIND.NetworkStoragePath))) } - pub fun readStatus(_ name: String): NameStatus { + access(all) fun readStatus(_ name: String): NameStatus { let currentTime=Clock.time() if let lease= self.profiles[name] { if !lease.profile.check() { @@ -1741,9 +1156,8 @@ pub contract FIND { return nil } - //lookup a name that is not locked - pub fun lookup(_ name: String) : &{Profile.Public}? { + access(all) fun lookup(_ name: String) : &{Profile.Public}? { let nameStatus=self.readStatus(name) if nameStatus.status != LeaseStatus.TAKEN { return nil @@ -1755,7 +1169,7 @@ pub contract FIND { return nil } - pub fun calculateCost(_ name: String) : UFix64 { + access(all) fun calculateCost(_ name: String) : UFix64 { if self.lengthPrices[name.length] != nil { return self.lengthPrices[name.length]! } else { @@ -1763,227 +1177,30 @@ pub contract FIND { } } - pub fun setWallet(_ wallet: Capability<&{FungibleToken.Receiver}>) { + access(account) fun setWallet(_ wallet: Capability<&{FungibleToken.Receiver}>) { self.wallet=wallet } - pub fun setPublicEnabled(_ enabled: Bool) { + access(account) fun setPublicEnabled(_ enabled: Bool) { self.publicEnabled=enabled } - pub fun getSecondaryCut() : UFix64 { + access(all) fun getSecondaryCut() : UFix64 { return self.secondaryCut } - pub fun getWallet() : Capability<&{FungibleToken.Receiver}> { + access(all) fun getWallet() : Capability<&{FungibleToken.Receiver}> { return self.wallet } } - pub fun getFindNetworkAddress() : Address { + access(all) fun getFindNetworkAddress() : Address { return self.account.address } - /* - ========================================================================== - Bids are a collection/resource for storing the bids bidder made on leases - ========================================================================== - */ - //Struct that is used to return information about bids - pub struct BidInfo{ - pub let name: String - pub let type: String - pub let amount: UFix64 - pub let timestamp: UFix64 - pub let lease: LeaseInformation? - - init(name: String, amount: UFix64, timestamp: UFix64, type: String, lease: LeaseInformation?) { - self.name=name - self.amount=amount - self.timestamp=timestamp - self.type=type - self.lease=lease - } - } - - - pub resource Bid { - access(contract) let from: Capability<&LeaseCollection{LeaseCollectionPublic}> - access(contract) let name: String - access(contract) var type: String - access(contract) let vault: @FUSD.Vault - access(contract) var bidAt: UFix64 - - init(from: Capability<&LeaseCollection{LeaseCollectionPublic}>, name: String, vault: @FUSD.Vault){ - self.vault <- vault - self.name=name - self.from=from - self.type="blind" - self.bidAt=Clock.time() - } - - access(contract) fun setType(_ type: String) { - self.type=type - } - access(contract) fun setBidAt(_ time: UFix64) { - self.bidAt=time - } - - destroy() { - //This is kinda bad. find FUSD vault of owner and deploy to that? - destroy self.vault - } - } - - pub resource interface BidCollectionPublic { - pub fun getBids() : [BidInfo] - pub fun getBalance(_ name: String) : UFix64 - access(contract) fun fulfillLease(_ token: @FIND.Lease) : @FungibleToken.Vault - access(contract) fun cancel(_ name: String) - access(contract) fun setBidType(name: String, type: String) - } - - //A collection stored for bidders/buyers - pub resource BidCollection: BidCollectionPublic { - - access(contract) var bids : @{String: Bid} - access(contract) let receiver: Capability<&{FungibleToken.Receiver}> - access(contract) let leases: Capability<&LeaseCollection{LeaseCollectionPublic}> - - init(receiver: Capability<&{FungibleToken.Receiver}>, leases: Capability<&LeaseCollection{LeaseCollectionPublic}>) { - self.bids <- {} - self.receiver=receiver - self.leases=leases - } - - //called from lease when auction is ended - //if purchase if fulfilled then we deposit money back into vault we get passed along and token into your own leases collection - access(contract) fun fulfillLease(_ token: @FIND.Lease) : @FungibleToken.Vault{ - if !self.leases.check() { - panic("The lease collection capability is invalid.") - } - let bid <- self.bids.remove(key: token.name) ?? panic("missing bid") - - let vaultRef = &bid.vault as &FungibleToken.Vault - - token.setSalePrice(nil) - token.setCallback(nil) - token.setReservePrice(nil) - token.setStartAuctionPrice(nil) - self.leases.borrow()!.deposit(token: <- token) - let vault <- vaultRef.withdraw(amount: vaultRef.balance) - destroy bid - return <- vault - } - - //called from lease when things are canceled - //if the bid is canceled from seller then we move the vault tokens back into your vault - access(contract) fun cancel(_ name: String) { - if !self.receiver.check() { - panic("This user does not have receiving vault set up. User: ".concat(self.owner!.address.toString())) - } - let bid <- self.bids.remove(key: name) ?? panic("missing bid") - let vaultRef = &bid.vault as &FungibleToken.Vault - self.receiver.borrow()!.deposit(from: <- vaultRef.withdraw(amount: vaultRef.balance)) - destroy bid - } - - pub fun getBids() : [BidInfo] { - var bidInfo: [BidInfo] = [] - for id in self.bids.keys { - let bid = self.borrowBid(id) - let leaseCollection= bid.from.borrow() ?? panic("Could not borrow lease bid from owner of name=".concat(bid.name)) - bidInfo.append(BidInfo(name: bid.name, amount: bid.vault.balance, timestamp: bid.bidAt, type: bid.type, lease: leaseCollection.getLease(bid.name))) - } - return bidInfo - } - - //make a bid on a name - pub fun bid(name: String, vault: @FUSD.Vault) { - let nameStatus=FIND.status(name) - if nameStatus.status == LeaseStatus.FREE { - panic("cannot bid on name that is free") - } - - if self.owner!.address == nameStatus.owner { - panic("cannot bid on your own name") - } - - let from=getAccount(nameStatus.owner!).getCapability<&LeaseCollection{LeaseCollectionPublic}>(FIND.LeasePublicPath) - - let bid <- create Bid(from: from, name:name, vault: <- vault) - let leaseCollection= from.borrow() ?? panic("Could not borrow lease bid from owner of name=".concat(name)) - - - let callbackCapability =self.owner!.getCapability<&BidCollection{BidCollectionPublic}>(FIND.BidPublicPath) - let oldToken <- self.bids[bid.name] <- bid - //send info to leaseCollection - destroy oldToken - leaseCollection.registerBid(name: name, callback: callbackCapability) - } - - - //increase a bid, will not work if the auction has already started - pub fun increaseBid(name: String, vault: @FungibleToken.Vault) { - let nameStatus=FIND.status(name) - if nameStatus.status == LeaseStatus.FREE { - panic("cannot increaseBid on name that is free") - } - let seller=getAccount(nameStatus.owner!).getCapability<&LeaseCollection{LeaseCollectionPublic}>(FIND.LeasePublicPath) - let balance = vault.balance - let bid =self.borrowBid(name) - bid.setBidAt(Clock.time()) - bid.vault.deposit(from: <- vault) - - let from=getAccount(nameStatus.owner!).getCapability<&LeaseCollection{LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !from.check() { - panic("The seller unlinked the lease collection capability. seller address : ".concat(nameStatus.owner!.toString())) - } - from.borrow()!.increaseBid(name, balance: balance) - } - - //cancel a bid, will panic if called after auction has started - pub fun cancelBid(_ name: String) { - - let nameStatus=FIND.status(name) - if nameStatus.status == LeaseStatus.FREE { - self.cancel(name) - return - } - let from=getAccount(nameStatus.owner!).getCapability<&LeaseCollection{LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !from.check() { - panic("The seller unlinked the lease collection capability. seller address : ".concat(nameStatus.owner!.toString())) - } - from.borrow()!.cancelUserBid(name) - self.cancel(name) - } - - pub fun borrowBid(_ name: String): &Bid { - return (&self.bids[name] as &Bid?)! - } - - access(contract) fun setBidType(name: String, type: String) { - let bid= self.borrowBid(name) - bid.setType(type) - } - - pub fun getBalance(_ name: String) : UFix64 { - let bid= self.borrowBid(name) - return bid.vault.balance - } - - destroy() { - destroy self.bids - } - } - - pub fun createEmptyBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, leases: Capability<&LeaseCollection{LeaseCollectionPublic}>) : @BidCollection { - return <- create BidCollection(receiver: receiver, leases: leases) - } - - pub fun validateFindName(_ value: String) : Bool { + access(all) fun validateFindName(_ value: String) : Bool { if value.length < 3 || value.length > 16 { return false } @@ -1998,7 +1215,7 @@ pub contract FIND { return true } - pub fun validateAlphanumericLowerDash(_ value:String) : Bool { + access(all) fun validateAlphanumericLowerDash(_ value:String) : Bool { let lowerA: UInt8=97 let lowerZ: UInt8=122 @@ -2025,7 +1242,7 @@ pub contract FIND { } - pub fun validateHex(_ value:String) : Bool { + access(all) fun validateHex(_ value:String) : Bool { let lowerA: UInt8=97 let lowerF: UInt8=102 @@ -2047,7 +1264,7 @@ pub contract FIND { } - pub fun trimFindSuffix(_ name: String) : String { + access(all) fun trimFindSuffix(_ name: String) : String { return FindUtils.trimSuffix(name, suffix: ".find") } @@ -2067,12 +1284,28 @@ pub contract FIND { } } else { // otherwise falls into emulator and user dapper - if merchAccount != 0x01cf0e2f2f715450{ + if merchAccount != 0x179b6b1cb6755e31 { panic("Merch Account address does not match with expected ".concat(merchAccount.toString())) } } } + + access(account) fun getFlowUSDOracleAddress() : Address { + // If only find can sign the trxns and call this function, then we do not have to check the address passed in. + // Otherwise, would it be wiser if we hard code the address here? + if FIND.account.address == 0x097bafa4e0b48eef { + // This is for mainnet + return 0xe385412159992e11 + } else if FIND.account.address == 0x35717efbbce11c74 { + // This is for testnet + return 0xcbdb5a7b89c3c844 + } else { + //otherwise on emulator we use same account as FIND + return self.account.address + } + } + access(account) fun getMerchantAddress() : Address { // If only find can sign the trxns and call this function, then we do not have to check the address passed in. // Otherwise, would it be wiser if we hard code the address here? @@ -2085,21 +1318,18 @@ pub contract FIND { return 0x4748780c8bf65e19 } else { // otherwise falls into emulator and user dapper - return 0x01cf0e2f2f715450 + return 0x179b6b1cb6755e31 } } init() { - self.NetworkPrivatePath= /private/FIND self.NetworkStoragePath= /storage/FIND self.LeasePublicPath=/public/findLeases self.LeaseStoragePath=/storage/findLeases - self.BidPublicPath=/public/findBids - self.BidStoragePath=/storage/findBids - - let wallet=self.account.getCapability<&{FungibleToken.Receiver}>(/public/fusdReceiver) + // Get + let wallet=self.account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) // these values are hardcoded here for a reason. Then plan is to throw away the key and not have setters for them so that people can trust the contract to be the same let network <- create Network( @@ -2111,8 +1341,14 @@ pub contract FIND { wallet: wallet, publicEnabled: false ) - self.account.save(<-network, to: FIND.NetworkStoragePath) - self.account.link<&Network>( FIND.NetworkPrivatePath, target: FIND.NetworkStoragePath) - + self.account.storage.save(<-network, to: FIND.NetworkStoragePath) } + + //These are deprecated resources that we cannot have remove + access(all) struct BidInfo{} + access(all) resource Auction { } + access(all) resource Bid { } + access(all) resource interface BidCollectionPublic { } + access(all) resource BidCollection: BidCollectionPublic { } + } diff --git a/contracts/FINDNFTCatalog.cdc b/contracts/FINDNFTCatalog.cdc index 6b04272d..5be58c28 100644 --- a/contracts/FINDNFTCatalog.cdc +++ b/contracts/FINDNFTCatalog.cdc @@ -1,5 +1,5 @@ -import NFTCatalog from "./standard/NFTCatalog.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" +import "NFTCatalog" +import "MetadataViews" // NFTCatalog // @@ -11,19 +11,17 @@ import MetadataViews from "./standard/MetadataViews.cdc" // To make an addition to the catalog you can propose an NFT and provide its metadata. // An Admin can approve a proposal which would add the NFT to the catalog -pub contract FINDNFTCatalog { +access(all) contract FINDNFTCatalog { // EntryAdded // An NFT collection has been added to the catalog - pub event EntryAdded( + access(all) event EntryAdded( collectionIdentifier : String, contractName : String, contractAddress : Address, nftType : Type, storagePath: StoragePath, publicPath: PublicPath, - privatePath: PrivatePath, publicLinkedType : Type, - privateLinkedType : Type, displayName : String, description: String, externalURL : String @@ -31,16 +29,14 @@ pub contract FINDNFTCatalog { // EntryUpdated // An NFT Collection has been updated in the catalog - pub event EntryUpdated( + access(all) event EntryUpdated( collectionIdentifier : String, contractName : String, contractAddress : Address, nftType : Type, storagePath: StoragePath, publicPath: PublicPath, - privatePath: PrivatePath, publicLinkedType : Type, - privateLinkedType : Type, displayName : String, description: String, externalURL : String @@ -48,23 +44,22 @@ pub contract FINDNFTCatalog { // EntryRemoved // An NFT Collection has been removed from the catalog - pub event EntryRemoved(collectionIdentifier : String) + access(all) event EntryRemoved(collectionIdentifier : String) // ProposalEntryAdded // A new proposal to make an addtion to the catalog has been made - pub event ProposalEntryAdded(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address) + access(all) event ProposalEntryAdded(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address) // ProposalEntryUpdated // A proposal has been updated - pub event ProposalEntryUpdated(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address) + access(all) event ProposalEntryUpdated(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address) // ProposalEntryRemoved // A proposal has been removed from storage - pub event ProposalEntryRemoved(proposalID : UInt64) + access(all) event ProposalEntryRemoved(proposalID : UInt64) - pub let ProposalManagerStoragePath: StoragePath - - pub let ProposalManagerPublicPath: PublicPath + access(all) let ProposalManagerStoragePath: StoragePath + access(all) let ProposalManagerPublicPath: PublicPath access(self) let catalog: {String : NFTCatalog.NFTCatalogMetadata} // { collectionIdentifier -> Metadata } access(self) let catalogTypeData: {String : {String : Bool}} // Additional view to go from { NFT Type Identifier -> {Collection Identifier : Bool } } @@ -74,7 +69,7 @@ pub contract FINDNFTCatalog { access(self) var totalProposals : UInt64 // Get FIND and Dapper NFTCatalog - pub fun getCatalog() : {String : NFTCatalog.NFTCatalogMetadata} { + access(all) fun getCatalog() : {String : NFTCatalog.NFTCatalogMetadata} { let find = self.catalog let dapper = NFTCatalog.getCatalog() for item in dapper.keys { @@ -83,14 +78,14 @@ pub contract FINDNFTCatalog { return find } - pub fun getCatalogEntry(collectionIdentifier : String) : NFTCatalog.NFTCatalogMetadata? { + access(all) fun getCatalogEntry(collectionIdentifier : String) : NFTCatalog.NFTCatalogMetadata? { if let dapper = NFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier) { return dapper } return self.catalog[collectionIdentifier] } - pub fun getCollectionsForType(nftTypeIdentifier: String) : {String : Bool}? { + access(all) fun getCollectionsForType(nftTypeIdentifier: String) : {String : Bool}? { if let dapper = NFTCatalog.getCollectionsForType(nftTypeIdentifier: nftTypeIdentifier) { // If there's dappers input and Find input, dappers will overwrite what's on find if let find = self.catalogTypeData[nftTypeIdentifier] { @@ -102,11 +97,11 @@ pub contract FINDNFTCatalog { // If there's only dapper input, return it return dapper } - // Else return what's on find + // Else return what's on find return self.catalogTypeData[nftTypeIdentifier] } - pub fun getCatalogTypeData() : {String : {String : Bool}} { + access(all) fun getCatalogTypeData() : {String : {String : Bool}} { let find = self.catalogTypeData let dapper = NFTCatalog.getCatalogTypeData() for item in dapper.keys { @@ -116,7 +111,7 @@ pub contract FINDNFTCatalog { } // A helper function to get CollectionData directly from NFTIdentifier - pub fun getCollectionDataForType(nftTypeIdentifier: String) : NFTCatalog.NFTCollectionData? { + access(all) fun getCollectionDataForType(nftTypeIdentifier: String) : NFTCatalog.NFTCollectionData? { if let collections = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftTypeIdentifier) { if collections.length < 1 { return nil @@ -129,7 +124,7 @@ pub contract FINDNFTCatalog { } // helper function to get Paths - pub fun getMetadataFromType(_ t: Type) : NFTCatalog.NFTCatalogMetadata? { + access(all) fun getMetadataFromType(_ t: Type) : NFTCatalog.NFTCatalogMetadata? { let collectionIdentifier = self.getCollectionsForType(nftTypeIdentifier: t.identifier) if collectionIdentifier == nil || collectionIdentifier!.length < 1 { return nil @@ -138,19 +133,19 @@ pub contract FINDNFTCatalog { } // Get only FIND NFTCatalog - pub fun getFINDCatalog() : {String : NFTCatalog.NFTCatalogMetadata} { + access(all) fun getFINDCatalog() : {String : NFTCatalog.NFTCatalogMetadata} { return self.catalog } - pub fun getFINDCatalogEntry(collectionIdentifier : String) : NFTCatalog.NFTCatalogMetadata? { + access(all) fun getFINDCatalogEntry(collectionIdentifier : String) : NFTCatalog.NFTCatalogMetadata? { return self.catalog[collectionIdentifier] } - pub fun getFINDCollectionsForType(nftTypeIdentifier: String) : {String : Bool}? { + access(all) fun getFINDCollectionsForType(nftTypeIdentifier: String) : {String : Bool}? { return self.catalogTypeData[nftTypeIdentifier] } - pub fun getFINDCatalogTypeData() : {String : {String : Bool}} { + access(all) fun getFINDCatalogTypeData() : {String : {String : Bool}} { return self.catalogTypeData } @@ -159,8 +154,8 @@ pub contract FINDNFTCatalog { // @param metadata: The Metadata for the NFT collection that will be stored in the catalog // @param message: A message to the catalog owners // @param proposer: Who is making the proposition(the address needs to be verified) - pub fun proposeNFTMetadata(collectionIdentifier : String, metadata : NFTCatalog.NFTCatalogMetadata, message : String, proposer : Address) : UInt64 { - let proposerManagerCap = getAccount(proposer).getCapability<&NFTCatalog.NFTCatalogProposalManager{NFTCatalog.NFTCatalogProposalManagerPublic}>(NFTCatalog.ProposalManagerPublicPath) + access(all) fun proposeNFTMetadata(collectionIdentifier : String, metadata : NFTCatalog.NFTCatalogMetadata, message : String, proposer : Address) : UInt64 { + let proposerManagerCap = getAccount(proposer).capabilities.get<&NFTCatalog.NFTCatalogProposalManager>(NFTCatalog.ProposalManagerPublicPath)! assert(proposerManagerCap.check(), message : "Proposer needs to set up a manager") @@ -178,14 +173,14 @@ pub contract FINDNFTCatalog { // Withdraw a proposal from the catalog // @param proposalID: The ID of proposal you want to withdraw - pub fun withdrawNFTProposal(proposalID : UInt64) { + access(all) fun withdrawNFTProposal(proposalID : UInt64) { pre { self.catalogProposals[proposalID] != nil : "Invalid Proposal ID" } let proposal = self.catalogProposals[proposalID]! let proposer = proposal.proposer - let proposerManagerCap = getAccount(proposer).getCapability<&NFTCatalog.NFTCatalogProposalManager{NFTCatalog.NFTCatalogProposalManagerPublic}>(NFTCatalog.ProposalManagerPublicPath) + let proposerManagerCap = getAccount(proposer).capabilities.get<&NFTCatalog.NFTCatalogProposalManager>(NFTCatalog.ProposalManagerPublicPath)! assert(proposerManagerCap.check(), message : "Proposer needs to set up a manager") @@ -196,15 +191,15 @@ pub contract FINDNFTCatalog { self.removeCatalogProposal(proposalID : proposalID) } - pub fun getCatalogProposals() : {UInt64 : NFTCatalog.NFTCatalogProposal} { + access(all) fun getCatalogProposals() : {UInt64 : NFTCatalog.NFTCatalogProposal} { return self.catalogProposals } - pub fun getCatalogProposalEntry(proposalID : UInt64) : NFTCatalog.NFTCatalogProposal? { + access(all) fun getCatalogProposalEntry(proposalID : UInt64) : NFTCatalog.NFTCatalogProposal? { return self.catalogProposals[proposalID] } - pub fun createNFTCatalogProposalManager(): @NFTCatalog.NFTCatalogProposalManager { + access(all) fun createNFTCatalogProposalManager(): @NFTCatalog.NFTCatalogProposalManager { return <- NFTCatalog.createNFTCatalogProposalManager() } @@ -224,9 +219,7 @@ pub contract FINDNFTCatalog { nftType: metadata.nftType, storagePath: metadata.collectionData.storagePath, publicPath: metadata.collectionData.publicPath, - privatePath: metadata.collectionData.privatePath, publicLinkedType : metadata.collectionData.publicLinkedType, - privateLinkedType : metadata.collectionData.privateLinkedType, displayName : metadata.collectionDisplay.name, description: metadata.collectionDisplay.description, externalURL : metadata.collectionDisplay.externalURL.url @@ -253,9 +246,7 @@ pub contract FINDNFTCatalog { nftType: metadata.nftType, storagePath: metadata.collectionData.storagePath, publicPath: metadata.collectionData.publicPath, - privatePath: metadata.collectionData.privatePath, publicLinkedType : metadata.collectionData.publicLinkedType, - privateLinkedType : metadata.collectionData.privateLinkedType, displayName : metadata.collectionDisplay.name, description: metadata.collectionDisplay.description, externalURL : metadata.collectionDisplay.externalURL.url @@ -319,5 +310,4 @@ pub contract FINDNFTCatalog { self.catalogProposals = {} } - -} \ No newline at end of file +} diff --git a/contracts/FINDNFTCatalogAdmin.cdc b/contracts/FINDNFTCatalogAdmin.cdc index 3790871a..18a0130d 100644 --- a/contracts/FINDNFTCatalogAdmin.cdc +++ b/contracts/FINDNFTCatalogAdmin.cdc @@ -1,5 +1,5 @@ -import FINDNFTCatalog from "./FINDNFTCatalog.cdc" -import NFTCatalog from "./standard/NFTCatalog.cdc" +import "FINDNFTCatalog" +import "NFTCatalog" // NFTCatalogAdmin // @@ -7,34 +7,34 @@ import NFTCatalog from "./standard/NFTCatalog.cdc" // a proxy resource to receive a capability that lets you make changes to the NFT Catalog // and manage proposals -pub contract FINDNFTCatalogAdmin { +access(all) contract FINDNFTCatalogAdmin { - pub let AdminPrivatePath: PrivatePath - pub let AdminStoragePath: StoragePath + access(all) let AdminStoragePath: StoragePath - pub let AdminProxyPublicPath: PublicPath - pub let AdminProxyStoragePath: StoragePath + access(all) let AdminProxyPublicPath: PublicPath + access(all) let AdminProxyStoragePath: StoragePath // Admin // Admin resource to manage NFT Catalog - pub resource Admin { - - pub fun addCatalogEntry(collectionIdentifier: String, metadata : NFTCatalog.NFTCatalogMetadata) { + access(all) resource Admin { + access(all) fun addCatalogEntry(collectionIdentifier: String, metadata : NFTCatalog.NFTCatalogMetadata) { FINDNFTCatalog.addCatalogEntry(collectionIdentifier: collectionIdentifier, metadata : metadata) } - pub fun updateCatalogEntry(collectionIdentifier : String , metadata : NFTCatalog.NFTCatalogMetadata) { + access(all) fun updateCatalogEntry(collectionIdentifier : String , metadata : NFTCatalog.NFTCatalogMetadata) { FINDNFTCatalog.updateCatalogEntry(collectionIdentifier: collectionIdentifier, metadata : metadata) } - pub fun removeCatalogEntry(collectionIdentifier : String) { + access(all) fun removeCatalogEntry(collectionIdentifier : String) { FINDNFTCatalog.removeCatalogEntry(collectionIdentifier : collectionIdentifier) } - pub fun approveCatalogProposal(proposalID : UInt64) { - pre { - FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID" - FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.status == "IN_REVIEW" : "Invalid Proposal" + access(all) fun approveCatalogProposal(proposalID : UInt64) { + if (FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID) == nil) { + panic("Invalid Proposal ID") + } + if (FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.status != "IN_REVIEW") { + panic("Invalid Proposal") } let catalogProposalEntry = FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID)! let newCatalogProposalEntry = NFTCatalog.NFTCatalogProposal(collectionIdentifier : catalogProposalEntry.collectionIdentifier, metadata : catalogProposalEntry.metadata, message : catalogProposalEntry.message, status: "APPROVED", proposer: catalogProposalEntry.proposer) @@ -47,19 +47,21 @@ pub contract FINDNFTCatalogAdmin { } } - pub fun rejectCatalogProposal(proposalID : UInt64) { - pre { - FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID" - FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.status == "IN_REVIEW" : "Invalid Proposal" + access(all) fun rejectCatalogProposal(proposalID : UInt64) { + if (FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID) == nil) { + panic("Invalid Proposal ID") + } + if (FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.status != "IN_REVIEW") { + panic("Invalid Proposal") } let catalogProposalEntry = FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID)! let newCatalogProposalEntry = NFTCatalog.NFTCatalogProposal(collectionIdentifier : catalogProposalEntry.collectionIdentifier, metadata : catalogProposalEntry.metadata, message : catalogProposalEntry.message, status: "REJECTED", proposer: catalogProposalEntry.proposer) FINDNFTCatalog.updateCatalogProposal(proposalID : proposalID, proposalMetadata : newCatalogProposalEntry) } - pub fun removeCatalogProposal(proposalID : UInt64) { - pre { - FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID" + access(all) fun removeCatalogProposal(proposalID : UInt64) { + if (FINDNFTCatalog.getCatalogProposalEntry(proposalID : proposalID) == nil) { + panic("Invalid Proposal ID") } FINDNFTCatalog.removeCatalogProposal(proposalID : proposalID) } @@ -71,16 +73,16 @@ pub contract FINDNFTCatalogAdmin { // AdminProxy // A proxy resource that can store // a capability to admin controls - pub resource interface IAdminProxy { - pub fun addCapability(capability : Capability<&Admin>) - pub fun hasCapability() : Bool + access(all) resource interface IAdminProxy { + access(all) fun addCapability(capability : Capability<&Admin>) + access(all) fun hasCapability() : Bool } - pub resource AdminProxy : IAdminProxy { + access(all) resource AdminProxy : IAdminProxy { access(self) var capability : Capability<&Admin>? - pub fun addCapability(capability : Capability<&Admin>) { + access(all) fun addCapability(capability : Capability<&Admin>) { pre { capability.check() : "Invalid Admin Capability" self.capability == nil : "Admin Proxy already set" @@ -88,11 +90,11 @@ pub contract FINDNFTCatalogAdmin { self.capability = capability } - pub fun getCapability() : Capability<&Admin>? { + access(all) fun getCapability() : Capability<&Admin>? { return self.capability } - pub fun hasCapability() : Bool { + access(all) fun hasCapability() : Bool { return self.capability != nil } @@ -102,7 +104,7 @@ pub contract FINDNFTCatalogAdmin { } - pub fun createAdminProxy() : @AdminProxy { + access(all) fun createAdminProxy() : @AdminProxy { return <- create AdminProxy() } @@ -110,13 +112,11 @@ pub contract FINDNFTCatalogAdmin { self.AdminProxyPublicPath = /public/FINDnftCatalogAdminProxy self.AdminProxyStoragePath = /storage/FINDnftCatalogAdminProxy - self.AdminPrivatePath = /private/FINDnftCatalogAdmin self.AdminStoragePath = /storage/FINDnftCatalogAdmin let admin <- create Admin() - self.account.save(<-admin, to: self.AdminStoragePath) - self.account.link<&Admin>(self.AdminPrivatePath, target: self.AdminStoragePath) - + self.account.storage.save(<-admin, to: self.AdminStoragePath) + let adminCap = self.account.capabilities.storage.issue<&Admin>(self.AdminStoragePath) } -} \ No newline at end of file +} diff --git a/contracts/FTRegistry.cdc b/contracts/FTRegistry.cdc index 823423ef..0c40ff2d 100644 --- a/contracts/FTRegistry.cdc +++ b/contracts/FTRegistry.cdc @@ -1,9 +1,9 @@ -pub contract FTRegistry { +access(all) contract FTRegistry { /* Event */ - pub event ContractInitialized() - pub event FTInfoRegistered(alias: String, typeIdentifier: String) - pub event FTInfoRemoved(alias: String, typeIdentifier: String) + access(all) event ContractInitialized() + access(all) event FTInfoRegistered(alias: String, typeIdentifier: String) + access(all) event FTInfoRemoved(alias: String, typeIdentifier: String) /* Variables */ // Mapping of {Type Identifier : FT Info Struct} @@ -12,19 +12,19 @@ pub contract FTRegistry { access(contract) var aliasMap : {String : String} /* Struct */ - pub struct FTInfo { - pub let alias : String - pub let type : Type - pub let typeIdentifier : String + access(all) struct FTInfo { + access(all) let alias : String + access(all) let type : Type + access(all) let typeIdentifier : String // Whether it is stable coin or other type of coins. - pub let tag : [String ] - pub let icon : String? - pub let receiverPath : PublicPath - pub let receiverPathIdentifier : String - pub let balancePath : PublicPath - pub let balancePathIdentifier : String - pub let vaultPath : StoragePath - pub let vaultPathIdentifier : String + access(all) let tag : [String ] + access(all) let icon : String? + access(all) let receiverPath : PublicPath + access(all) let receiverPathIdentifier : String + access(all) let balancePath : PublicPath + access(all) let balancePathIdentifier : String + access(all) let vaultPath : StoragePath + access(all) let vaultPathIdentifier : String init(alias : String, type: Type, typeIdentifier: String, tag:[String], icon: String?, receiverPath: PublicPath, balancePath: PublicPath, vaultPath: StoragePath) { self.alias = alias @@ -43,18 +43,18 @@ pub contract FTRegistry { } /* getters */ - pub fun getFTInfoByTypeIdentifier(_ typeIdentifier: String) : FTInfo? { + access(all) fun getFTInfoByTypeIdentifier(_ typeIdentifier: String) : FTInfo? { return FTRegistry.fungibleTokenList[typeIdentifier] } - pub fun getFTInfoByAlias(_ alias: String) : FTInfo? { + access(all) fun getFTInfoByAlias(_ alias: String) : FTInfo? { if let identifier = FTRegistry.aliasMap[alias] { return FTRegistry.fungibleTokenList[identifier] } return nil } - pub fun getFTInfo(_ input: String) : FTInfo? { + access(all) fun getFTInfo(_ input: String) : FTInfo? { if let info = self.getFTInfoByAlias(input) { return info } @@ -64,19 +64,19 @@ pub contract FTRegistry { return nil } - pub fun getTypeIdentifier(_ alias: String) : String? { + access(all) fun getTypeIdentifier(_ alias: String) : String? { return FTRegistry.aliasMap[alias] } - pub fun getFTInfoAll() : {String : FTInfo} { + access(all) fun getFTInfoAll() : {String : FTInfo} { return FTRegistry.fungibleTokenList } - pub fun getSupportedFTAlias() : [String] { + access(all) fun getSupportedFTAlias() : [String] { return FTRegistry.aliasMap.keys } - pub fun getSupportedFTTypeIdentifier() : [String] { + access(all) fun getSupportedFTTypeIdentifier() : [String] { return FTRegistry.aliasMap.values } @@ -102,7 +102,7 @@ pub contract FTRegistry { access(account) fun removeFTInfoByTypeIdentifier(_ typeIdentifier: String) : FTInfo { let info = FTRegistry.fungibleTokenList.remove(key: typeIdentifier) ?? panic("Cannot find this Fungible Token Registry. Type : ".concat(typeIdentifier)) FTRegistry.aliasMap.remove(key: info.alias) - emit FTInfoRemoved(alias:info!.alias, typeIdentifier: info!.typeIdentifier) + emit FTInfoRemoved(alias:info.alias, typeIdentifier: info.typeIdentifier) return info } diff --git a/contracts/FindAirdropper.cdc b/contracts/FindAirdropper.cdc index a1f25cd5..69138d93 100644 --- a/contracts/FindAirdropper.cdc +++ b/contracts/FindAirdropper.cdc @@ -1,21 +1,20 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FIND from "./FIND.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import FlowToken from "./standard/FlowToken.cdc" -import FindMarket from "./FindMarket.cdc" -import FindViews from "./FindViews.cdc" -import FindLostAndFoundWrapper from "./FindLostAndFoundWrapper.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" - -pub contract FindAirdropper { - - pub event Airdropped(from: Address ,fromName: String?, to: Address, toName: String?,uuid: UInt64, nftInfo: FindMarket.NFTInfo, context: {String : String}, remark: String?) - pub event AirdroppedToLostAndFound(from: Address, fromName: String? , to: Address, toName: String?, uuid: UInt64, nftInfo: FindMarket.NFTInfo, context: {String : String}, remark: String?, ticketID: UInt64) - pub event AirdropFailed(from: Address, fromName: String? , to: Address, toName: String?, uuid: UInt64, id: UInt64, type: String, context: {String : String}, reason: String) +import "NonFungibleToken" +import "FIND" +import "FungibleToken" +import "FlowToken" +import "FindMarket" +import "FindViews" +import "FindLostAndFoundWrapper" +import "MetadataViews" + +access(all) contract FindAirdropper { + // Events + access(all) event Airdropped(from: Address ,fromName: String?, to: Address, toName: String?,uuid: UInt64, nftInfo: FindMarket.NFTInfo, context: {String : String}, remark: String?) + access(all) event AirdroppedToLostAndFound(from: Address, fromName: String? , to: Address, toName: String?, uuid: UInt64, nftInfo: FindMarket.NFTInfo, context: {String : String}, remark: String?, ticketID: UInt64) + access(all) event AirdropFailed(from: Address, fromName: String? , to: Address, toName: String?, uuid: UInt64, id: UInt64, type: String, context: {String : String}, reason: String) // The normal way of airdrop. If the user didn't init account, they cannot receive it - pub fun safeAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, deepValidation: Bool) { - + access(all) fun safeAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, deepValidation: Bool) { let toName = FIND.reverseLookup(receiver) let from = pointer.owner() let fromName = FIND.reverseLookup(from) @@ -27,14 +26,14 @@ pub contract FindAirdropper { let vr = pointer.getViewResolver() let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true) - let receiverCap = getAccount(receiver).getCapability<&{NonFungibleToken.Receiver}>(path) + let receiverCap = getAccount(receiver).capabilities.get<&{NonFungibleToken.Receiver}>(path) // calculate the required storage and check sufficient balance - let senderStorageBeforeSend = getAccount(from).storageUsed + let senderStorageBeforeSend = getAccount(from).storage.used let item <- pointer.withdraw() - let requiredStorage = senderStorageBeforeSend - getAccount(from).storageUsed - let receiverAvailableStorage = getAccount(receiver).storageCapacity - getAccount(receiver).storageUsed + let requiredStorage = senderStorageBeforeSend - getAccount(from).storage.used + let receiverAvailableStorage = getAccount(receiver).storage.capacity - getAccount(receiver).storage.used // If requiredStorage > receiverAvailableStorage, deposit will not be successful, we will emit fail event and deposit back to the sender's collection if receiverAvailableStorage < requiredStorage { emit AirdropFailed(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, id: pointer.id, type: pointer.itemType.identifier, context: context, reason: "Insufficient User Storage") @@ -42,20 +41,18 @@ pub contract FindAirdropper { return } - if receiverCap.check() { - + if receiverCap.check() { emit Airdropped(from: from , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, nftInfo: nftInfo, context: context, remark: nil) - receiverCap.borrow()!.deposit(token: <- item) return } else { - let collectionPublicCap = getAccount(receiver).getCapability<&{NonFungibleToken.CollectionPublic}>(path) - if collectionPublicCap.check() { + let collectionPublic = getAccount(receiver).capabilities.borrow<&{NonFungibleToken.Collection}>(path) + if collectionPublic !=nil { let from = pointer.owner() emit Airdropped(from: from , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, nftInfo: nftInfo, context: context, remark: "Receiver Not Linked") - collectionPublicCap.borrow()!.deposit(token: <- item) + collectionPublic!.deposit(token: <- item) return } } @@ -64,7 +61,7 @@ pub contract FindAirdropper { pointer.deposit(<- item) } - pub fun forcedAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, storagePayment: &FungibleToken.Vault, flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>, deepValidation: Bool) { + access(all) fun forcedAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: Capability<&FlowToken.Vault>, deepValidation: Bool) { let toName = FIND.reverseLookup(receiver) let from = pointer.owner() @@ -78,8 +75,6 @@ pub contract FindAirdropper { let vr = pointer.getViewResolver() let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true) - let receiverCap = getAccount(receiver).getCapability<&{NonFungibleToken.Receiver}>(path) - // use LostAndFound for dropping let ticketID = FindLostAndFoundWrapper.depositNFT( receiver: receiver, @@ -98,7 +93,7 @@ pub contract FindAirdropper { emit AirdroppedToLostAndFound(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, nftInfo: nftInfo, context: context, remark: nil, ticketID: ticketID!) } - pub fun subsidizedAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, storagePayment: &FungibleToken.Vault, flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>, deepValidation: Bool) { + access(all) fun subsidizedAirdrop(pointer: FindViews.AuthNFTPointer, receiver: Address, path: PublicPath, context: {String : String}, storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: Capability<&FlowToken.Vault>, deepValidation: Bool) { let toName = FIND.reverseLookup(receiver) let from = pointer.owner() @@ -112,7 +107,7 @@ pub contract FindAirdropper { let vr = pointer.getViewResolver() let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true) - let receiverCap = getAccount(receiver).getCapability<&{NonFungibleToken.Receiver}>(path) + let receiverCap = getAccount(receiver).capabilities.get<&{NonFungibleToken.Receiver}>(path) // use LostAndFound for dropping let ticketID = FindLostAndFoundWrapper.depositNFT( @@ -131,7 +126,5 @@ pub contract FindAirdropper { } emit AirdroppedToLostAndFound(from: pointer.owner() , fromName: fromName, to: receiver, toName: toName, uuid: pointer.uuid, nftInfo: nftInfo, context: context, remark: nil, ticketID: ticketID!) } - - } diff --git a/contracts/FindFooDIM.cdc b/contracts/FindFooDIM.cdc deleted file mode 100644 index 6af783ca..00000000 --- a/contracts/FindFooDIM.cdc +++ /dev/null @@ -1,278 +0,0 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindForge from "./FindForge.cdc" -import FindForgeOrder from "./FindForgeOrder.cdc" -import FindForgeStruct from "./FindForgeStruct.cdc" -import FindUtils from "./FindUtils.cdc" - -// DIM stands for Direct Immuatble Minting, cannot mutate minted NFT states. So all nfts has to be minted in one go. -pub contract FindFooDIM: NonFungibleToken { - - pub var totalSupply: UInt64 - pub let nftCollectionDisplay: MetadataViews.NFTCollectionDisplay - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id: UInt64, name: String, description: String, image: String, edition: UInt64, maxEdition: UInt64, medias: {String: String}) - pub event Burned(id: UInt64, name: String, description: String, image: String, edition: UInt64, maxEdition: UInt64, medias: {String: String}) - - pub let CollectionStoragePath: StoragePath - pub let CollectionPrivatePath: PrivatePath - pub let CollectionPublicPath: PublicPath - pub let MinterStoragePath: StoragePath - - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - pub let id: UInt64 - - pub let info: FindForgeStruct.FindDIM - access(self) let royalties: MetadataViews.Royalties - - init( - info: FindForgeStruct.FindDIM, - royalties: MetadataViews.Royalties - ) { - self.id = self.uuid - self.info=info - self.royalties = royalties - - let i = info - emit Minted(id: self.id, name: i.name, description: i.description, image: "ipfs://".concat(i.thumbnailHash), edition: i.edition, maxEdition: i.maxEdition, medias: i.medias) - FindFooDIM.totalSupply = FindFooDIM.totalSupply + 1 - } - - destroy (){ - let i = self.info - emit Burned(id: self.id, name: i.name, description: i.description, image: "ipfs://".concat(i.thumbnailHash), edition: i.edition, maxEdition: i.maxEdition, medias: i.medias) - FindFooDIM.totalSupply = FindFooDIM.totalSupply - 1 - } - - pub fun getViews(): [Type] { - return [ - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type() - ] - } - - pub fun resolveView(_ view: Type): AnyStruct? { - switch view { - case Type(): - let traits = MetadataViews.Traits([]) - //scalars - for value in self.info.scalars.keys { - if FindUtils.hasSuffix(value, suffix: "_max"){ - continue - } - var r : MetadataViews.Rarity? = nil - if self.info.scalars[value.concat("_max")] != nil || self.info.descriptions["scalars".concat(value)] != nil { - r = MetadataViews.Rarity(score: nil, max: self.info.scalars[value.concat("_max")], description: self.info.descriptions["scalars".concat(value)] ) - } - traits.addTrait(MetadataViews.Trait(name: value, value: self.info.scalars[value], displayType: "Number", rarity: r)) - } - - //boosts - for value in self.info.boosts.keys { - if FindUtils.hasSuffix(value, suffix: "_max"){ - continue - } - var r : MetadataViews.Rarity? = nil - if self.info.boosts[value.concat("_max")] != nil || self.info.descriptions["boosts_".concat(value)] != nil { - r = MetadataViews.Rarity(score: nil, max: self.info.boosts[value.concat("_max")], description: self.info.descriptions["boosts_".concat(value)] ) - } - traits.addTrait(MetadataViews.Trait(name: value, value: self.info.boosts[value], displayType: "Boost", rarity: r)) - } - - //boostPercents - for value in self.info.boostPercents.keys { - var r : MetadataViews.Rarity? = nil - if self.info.descriptions["boostPercents_".concat(value)] != nil { - r = MetadataViews.Rarity(score: nil, max: self.info.boostPercents[value.concat("_max")], description: self.info.descriptions["boostPercents_".concat(value)] ) - } - traits.addTrait(MetadataViews.Trait(name: value, value: self.info.boostPercents[value], displayType: "BoostPercentage", rarity: r)) - } - - //levels - for value in self.info.levels.keys { - if FindUtils.hasSuffix(value, suffix: "_max"){ - continue - } - var r : MetadataViews.Rarity? = nil - if self.info.levels[value.concat("_max")] != nil || self.info.descriptions["levels_".concat(value)] != nil { - r = MetadataViews.Rarity(score: nil, max: self.info.levels[value.concat("_max")], description: self.info.descriptions["levels_".concat(value)] ) - } - traits.addTrait(MetadataViews.Trait(name: value, value: self.info.levels[value], displayType: "Level", rarity: r)) - } - - //dates - for value in self.info.dates.keys { - var r : MetadataViews.Rarity? = nil - if self.info.descriptions["dates_".concat(value)] != nil { - r = MetadataViews.Rarity(score: nil, max: self.info.dates[value.concat("_max")], description: self.info.descriptions["dates_".concat(value)] ) - } - traits.addTrait(MetadataViews.Trait(name: value, value: self.info.dates[value], displayType: "Date", rarity: r)) - } - return traits - case Type(): - return MetadataViews.Display( - name: self.info.name, - description: self.info.description, - thumbnail: MetadataViews.IPFSFile( - cid: self.info.thumbnailHash, path: nil - ) - ) - case Type(): - let editionInfo = MetadataViews.Edition(name: "set", number: self.info.edition, max: self.info.maxEdition) - let editionList: [MetadataViews.Edition] = [editionInfo] - return MetadataViews.Editions( - editionList - ) - case Type(): - return self.royalties - - case Type(): - return MetadataViews.ExternalURL(self.info.externalURL) - - case Type(): - return MetadataViews.NFTCollectionData( - storagePath: FindFooDIM.CollectionStoragePath, - publicPath: FindFooDIM.CollectionPublicPath, - providerPath: FindFooDIM.CollectionPrivatePath, - publicCollection: Type<&FindFooDIM.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&FindFooDIM.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&FindFooDIM.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { - return <-FindFooDIM.createEmptyCollection() - }) - ) - case Type(): - return FindFooDIM.nftCollectionDisplay - } - return nil - } - } - - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} - - init () { - self.ownedNFTs <- {} - } - - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT. ID : ".concat(withdrawID.toString())) - - emit Withdraw(id: token.id, from: self.owner?.address) - - return <-token - } - - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { - let token <- token as! @FindFooDIM.NFT - - let id: UInt64 = token.id - - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) - - destroy oldToken - } - - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { - return self.ownedNFTs.keys - } - - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! - } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let nfgNFT = nft as! &FindFooDIM.NFT - return nfgNFT as &AnyResource{MetadataViews.Resolver} - } - - destroy() { - destroy self.ownedNFTs - } - } - - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } - - pub resource Forge: FindForge.Forge { - pub fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @NonFungibleToken.NFT { - let info = data as? FindForgeStruct.FindDIM ?? panic("The data passed in is not in form of Generic Info Struct.") - let royalties : [MetadataViews.Royalty] = [] - royalties.append(MetadataViews.Royalty(receiver:platform.platform, cut: platform.platformPercentCut, description: "find forge")) - if platform.minterCut != nil { - royalties.append(MetadataViews.Royalty(receiver:platform.getMinterFTReceiver(), cut: platform.minterCut!, description: "creator")) - } - - // create a new NFT - var newNFT <- create NFT( - info: info, - royalties: MetadataViews.Royalties(royalties) - ) - - return <- newNFT - } - - pub fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { - // not used here - - panic("Not supported for FindFooDIM Contract") - } - } - - pub fun getForgeType() : Type { - return Type<@Forge>() - } - - init() { - - let contractName = "FindFooDIM" - - - // Initialize the total supply - self.totalSupply = 0 - - // Set the named paths - self.CollectionStoragePath = /storage/FindFooDIM - self.CollectionPrivatePath = /private/FindFooDIM - self.CollectionPublicPath = /public/FindFooDIM - self.MinterStoragePath = /storage/FindFooDIMMinter - - // Create a Collection resource and save it to storage - let collection <- create Collection() - self.account.save(<-collection, to: self.CollectionStoragePath) - - // create a public capability for the collection - self.account.link<&FindFooDIM.Collection{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>( - self.CollectionPublicPath, - target: self.CollectionStoragePath - ) - FindForge.addForgeType(<- create Forge()) - let admin = FindFooDIM.account.borrow<&FindForge.ForgeAdminProxy>(from: /storage/findForgeAdminProxy)! - self.nftCollectionDisplay = admin.fulfillForgeOrder(contractName, forgeType: Type<@Forge>()) - emit ContractInitialized() - } -} - diff --git a/contracts/FindForge.cdc b/contracts/FindForge.cdc index 78e3ec21..a2fd3ffc 100644 --- a/contracts/FindForge.cdc +++ b/contracts/FindForge.cdc @@ -1,14 +1,15 @@ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FIND from "../contracts/FIND.cdc" -import FindForgeOrder from "../contracts/FindForgeOrder.cdc" -import Profile from "../contracts/Profile.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "FIND" +import "FindForgeOrder" +import "Profile" +import "ViewResolver" -pub contract FindForge { +access(all) contract FindForge { - pub event Minted(nftType: String, id: UInt64, uuid: UInt64, nftName: String, nftThumbnail: String, from: Address, fromName: String, to: Address, toName: String?) + access(all) event Minted(nftType: String, id: UInt64, uuid: UInt64, nftName: String, nftThumbnail: String, from: Address, fromName: String, to: Address, toName: String?) access(contract) let minterPlatforms : {Type : {String: MinterPlatform}} access(contract) let verifier : @Verifier @@ -17,18 +18,18 @@ pub contract FindForge { access(contract) let publicForges : [Type] access(contract) var platformCut: UFix64 - pub struct MinterPlatform { - pub let platform: Capability<&{FungibleToken.Receiver}> - pub let platformPercentCut: UFix64 - pub let name: String - pub let minter: Address + access(all) struct MinterPlatform { + access(all) let platform: Capability<&{FungibleToken.Receiver}> + access(all) let platformPercentCut: UFix64 + access(all) let name: String + access(all) let minter: Address - pub var description: String - pub var externalURL: String - pub var squareImage: String - pub var bannerImage: String - pub let minterCut: UFix64? - pub var socials: {String : String} + access(all) var description: String + access(all) var externalURL: String + access(all) var squareImage: String + access(all) var bannerImage: String + access(all) let minterCut: UFix64? + access(all) var socials: {String : String} init(name: String, platform:Capability<&{FungibleToken.Receiver}>, platformPercentCut: UFix64, minterCut: UFix64? ,description: String, externalURL: String, squareImage: String, bannerImage: String, socials: {String : String}) { self.name=name @@ -43,59 +44,58 @@ pub contract FindForge { self.socials=socials } - pub fun getMinterFTReceiver() : Capability<&{FungibleToken.Receiver}> { - return getAccount(self.minter).getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + access(all) fun getMinterFTReceiver() : Capability<&{FungibleToken.Receiver}> { + return getAccount(self.minter).capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)! } - pub fun updateExternalURL(_ d: String) { + access(all) fun updateExternalURL(_ d: String) { self.externalURL = d } - pub fun updateDesription(_ d: String) { + access(all) fun updateDesription(_ d: String) { self.description = d } - pub fun updateSquareImagen(_ d: String) { + access(all) fun updateSquareImagen(_ d: String) { self.squareImage = d } - pub fun updateBannerImage(_ d: String) { + access(all) fun updateBannerImage(_ d: String) { self.bannerImage = d } - pub fun updateSocials(_ d: {String : String}) { + access(all) fun updateSocials(_ d: {String : String}) { self.socials = d } } // This is an empty resource that is created and passed into mint methods to verify that it comes from .find - pub resource Verifier { - + access(all) resource Verifier { } // ForgeMinter Interface - pub resource interface Forge{ - pub fun mint(platform: MinterPlatform, data: AnyStruct, verifier: &Verifier) : @NonFungibleToken.NFT - pub fun addContractData(platform: MinterPlatform, data: AnyStruct, verifier: &Verifier) + access(all) resource interface Forge{ + access(ForgeOwner) fun mint(platform: MinterPlatform, data: AnyStruct, verifier: &Verifier) : @{NonFungibleToken.NFT} + access(ForgeOwner) fun addContractData(platform: MinterPlatform, data: AnyStruct, verifier: &Verifier) } - access(contract) fun borrowForge(_ type: Type) : &{Forge}? { - return &FindForge.forgeTypes[type] as &{Forge}? + access(contract) fun borrowForge(_ type: Type) : auth(ForgeOwner) &{Forge}? { + return &FindForge.forgeTypes[type] } - pub fun getMinterPlatform(name: String, forgeType: Type) : MinterPlatform? { + access(all) fun getMinterPlatform(name: String, forgeType: Type) : MinterPlatform? { if FindForge.minterPlatforms[forgeType] == nil { return nil } return FindForge.minterPlatforms[forgeType]![name] } - pub fun getMinterPlatformsByName() : {Type : {String : MinterPlatform}} { + access(all) fun getMinterPlatformsByName() : {Type : {String : MinterPlatform}} { return FindForge.minterPlatforms } - pub fun checkMinterPlatform(name: String, forgeType: Type) : Bool { + access(all) fun checkMinterPlatform(name: String, forgeType: Type) : Bool { if FindForge.minterPlatforms[forgeType] == nil { return false } @@ -107,7 +107,7 @@ pub contract FindForge { return true } - pub fun setMinterPlatform(lease: &FIND.Lease, forgeType: Type, minterCut: UFix64?, description: String, externalURL: String, squareImage: String, bannerImage: String, socials: {String : String}) { + access(all) fun setMinterPlatform(lease: &FIND.Lease, forgeType: Type, minterCut: UFix64?, description: String, externalURL: String, squareImage: String, bannerImage: String, socials: {String : String}) { if !FindForge.minterPlatforms.containsKey(forgeType) { panic("This forge type is not supported. type : ".concat(forgeType.identifier)) } @@ -125,7 +125,7 @@ pub contract FindForge { // If they have a premium forge, platform will not take any royalty if lease.checkAddon(addon: "premiumForge") { - let receiverCap=FindForge.account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)! let minterPlatform = MinterPlatform(name:name, platform:receiverCap, platformPercentCut: 0.0, minterCut: minterCut ,description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials) FindForge.minterPlatforms[forgeType]!.insert(key: name, minterPlatform) @@ -133,7 +133,7 @@ pub contract FindForge { } if lease.checkAddon(addon: "forge") { - let receiverCap=FindForge.account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)! let minterPlatform = MinterPlatform(name:name, platform:receiverCap, platformPercentCut: FindForge.platformCut, minterCut: minterCut ,description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials) FindForge.minterPlatforms[forgeType]!.insert(key: name, minterPlatform) @@ -153,11 +153,11 @@ pub contract FindForge { } let user = FIND.lookupAddress(leaseName) ?? panic("Cannot find lease owner. Lease : ".concat(leaseName)) - let leaseCollection = getAccount(user).getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath).borrow() ?? panic("Cannot borrow reference to lease collection of user : ".concat(leaseName)) + let leaseCollection = getAccount(user).capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)!.borrow() ?? panic("Cannot borrow reference to lease collection of user : ".concat(leaseName)) // If they have a premium forge, platform will not take any royalty if leaseCollection.checkAddon(name: leaseName, addon: "premiumForge") { - let receiverCap=FindForge.account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)! let minterPlatform = MinterPlatform(name:leaseName, platform:receiverCap, platformPercentCut: 0.0, minterCut: minterCut ,description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials) FindForge.minterPlatforms[forgeType]!.insert(key: leaseName, minterPlatform) @@ -165,7 +165,7 @@ pub contract FindForge { } if leaseCollection.checkAddon(name: leaseName, addon: "forge") { - let receiverCap=FindForge.account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)! let minterPlatform = MinterPlatform(name:leaseName, platform:receiverCap, platformPercentCut: FindForge.platformCut, minterCut: minterCut ,description: description, externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socials) FindForge.minterPlatforms[forgeType]!.insert(key: leaseName, minterPlatform) @@ -175,7 +175,7 @@ pub contract FindForge { panic("Please give the user forge addon to start forging. Name: ".concat(leaseName)) } - pub fun removeMinterPlatform(lease: &FIND.Lease, forgeType: Type) { + access(all) fun removeMinterPlatform(lease: &FIND.Lease, forgeType: Type) { if FindForge.minterPlatforms[forgeType] == nil { panic("This minter platform does not exist. Forge Type : ".concat(forgeType.identifier)) } @@ -188,7 +188,7 @@ pub contract FindForge { FindForge.minterPlatforms[forgeType]!.remove(key: name) } - access(account) fun mintAdmin(leaseName: String, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver, MetadataViews.ResolverCollection}) { + access(account) fun mintAdmin(leaseName: String, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver}) { if !FindForge.minterPlatforms.containsKey(forgeType) { panic("The minter platform is not set. Please set up properly before mint.") } @@ -205,13 +205,13 @@ pub contract FindForge { let nft <- forge.mint(platform: minterPlatform, data: data, verifier: verifier) - let id = nft.id + let id = nft.id let uuid = nft.uuid let nftType = nft.getType().identifier receiver.deposit(token: <- nft) /* - let vr = receiver.borrowViewResolver(id: id) + let vr = receiver.borrowNFT(id) let view = vr.resolveView(Type()) ?? panic("The minting nft should implement MetadataViews Display view.") let display = view as! MetadataViews.Display let nftName = display.name @@ -226,7 +226,7 @@ pub contract FindForge { } - pub fun orderForge(lease: &FIND.Lease, mintType: String, minterCut: UFix64?, collectionDisplay: MetadataViews.NFTCollectionDisplay){ + access(all) fun orderForge(lease: &FIND.Lease, mintType: String, minterCut: UFix64?, collectionDisplay: MetadataViews.NFTCollectionDisplay){ if !lease.checkAddon(addon: "forge") && !lease.checkAddon(addon: "premiumForge") { panic("Please purchase forge addon to start forging. Name: ".concat(lease.getName())) } @@ -244,14 +244,14 @@ pub contract FindForge { access(account) fun fulfillForgeOrder(_ contractName: String, forgeType: Type) : MetadataViews.NFTCollectionDisplay { let order = FindForgeOrder.fulfillForgeOrder(contractName, forgeType: forgeType) - let c = order.collectionDisplay + let c = order.getCollectionDisplay() let s : {String : String} = {} for social in c.socials.keys { s[social] = c.socials[social]!.url } - FindForge.adminSetMinterPlatform(leaseName: order.leaseName, + FindForge.adminSetMinterPlatform(leaseName: order.getLeaseName(), forgeType: forgeType, - minterCut: order.minterCut, + minterCut: order.getMinterCut(), description: c.description, externalURL: c.externalURL.url, squareImage: c.squareImage.file.uri(), @@ -260,17 +260,17 @@ pub contract FindForge { return c } - pub fun mint (lease: &FIND.Lease, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver, MetadataViews.ResolverCollection}) { + access(all) fun mint (lease: &FIND.Lease, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver, ViewResolver.ResolverCollection}) { let leaseName = lease.getName() FindForge.adminMint(lease: leaseName, forgeType: forgeType , data: data, receiver: receiver) } - access(account) fun adminMint(lease: String, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver, MetadataViews.ResolverCollection}){ + access(account) fun adminMint(lease: String, forgeType: Type , data: AnyStruct, receiver: &{NonFungibleToken.Receiver, ViewResolver.ResolverCollection}){ if !FindForge.minterPlatforms.containsKey(forgeType) { panic("The minter platform is not set. Please set up properly before adding contract data.") } let address = FIND.lookupAddress(lease) ?? panic("This name is not owned by anyone. Name : ".concat(lease)) - let leaseCol = getAccount(address).getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath).borrow() ?? panic("Cannot borrow lease collection to lease owner. Owner : ".concat(address.toString())) + let leaseCol = getAccount(address).capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)!.borrow() ?? panic("Cannot borrow lease collection to lease owner. Owner : ".concat(address.toString())) if !leaseCol.checkAddon(name:lease, addon: "forge") && !leaseCol.checkAddon(name:lease, addon: "premiumForge") { panic("Please purchase forge addon to start forging. Name: ".concat(lease)) @@ -288,12 +288,12 @@ pub contract FindForge { let nft <- forge.mint(platform: minterPlatform, data: data, verifier: verifier) - let id = nft.id + let id = nft.id let uuid = nft.uuid let nftType = nft.getType().identifier receiver.deposit(token: <- nft) - let vr = receiver.borrowViewResolver(id: id) + let vr = (receiver as &{ViewResolver.ResolverCollection}).borrowViewResolver(id: id)! let view = vr.resolveView(Type()) ?? panic("The minting nft should implement MetadataViews Display view.") let display = view as! MetadataViews.Display let nftName = display.name @@ -307,7 +307,7 @@ pub contract FindForge { } - pub fun addContractData(lease: &FIND.Lease, forgeType: Type , data: AnyStruct) { + access(all) fun addContractData(lease: &FIND.Lease, forgeType: Type , data: AnyStruct) { FindForge.adminAddContractData(lease: lease.getName(), forgeType: forgeType , data: data) } @@ -317,7 +317,7 @@ pub contract FindForge { panic("The minter platform is not set. Please set up properly before adding contract data.") } let address = FIND.lookupAddress(lease) ?? panic("This name is not owned by anyone. Name : ".concat(lease)) - let leaseCol = getAccount(address).getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath).borrow() ?? panic("Cannot borrow lease collection to lease owner. Owner : ".concat(address.toString())) + let leaseCol = getAccount(address).capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)!.borrow() ?? panic("Cannot borrow lease collection to lease owner. Owner : ".concat(address.toString())) if !leaseCol.checkAddon(name:lease, addon: "forge") && !leaseCol.checkAddon(name:lease, addon: "premiumForge") { panic("Please purchase forge addon to start forging. Name: ".concat(lease)) @@ -335,7 +335,7 @@ pub contract FindForge { forge.addContractData(platform: minterPlatform, data: data, verifier: verifier) } - pub fun addForgeType(_ forge: @{Forge}) { + access(all) fun addForgeType(_ forge: @{Forge}) { if FindForge.forgeTypes.containsKey(forge.getType()) { panic("This type is already registered to the registry. Type : ".concat(forge.getType().identifier)) } @@ -364,7 +364,7 @@ pub contract FindForge { if !FindForge.minterPlatforms.containsKey(forgeType) { FindForge.minterPlatforms[forgeType] = {} } - let receiverCap=FindForge.account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let receiverCap=FindForge.account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)! let minterPlatform = MinterPlatform(name:name, platform:receiverCap, platformPercentCut: FindForge.platformCut, minterCut: nil ,description: "", externalURL: "", squareImage: "", bannerImage: "", socials: {}) FindForge.minterPlatforms[forgeType]!.insert(key: name, minterPlatform) } @@ -401,20 +401,22 @@ pub contract FindForge { } access(account) fun borrowVerifier() : &Verifier { - return &self.verifier as &Verifier + return &self.verifier } - pub fun createForgeAdminProxyClient() : @ForgeAdminProxy { + access(all) fun createForgeAdminProxyClient() : @ForgeAdminProxy { return <- create ForgeAdminProxy() } //interface to use for capability receiver pattern - pub resource interface ForgeAdminProxyClient { - pub fun addCapability(_ cap: Capability<&FIND.Network>) + access(all) resource interface ForgeAdminProxyClient { + access(all) fun addCapability(_ cap: Capability<&FIND.Network>) } + access(all) entitlement ForgeOwner + //admin proxy with capability receiver - pub resource ForgeAdminProxy: ForgeAdminProxyClient { + access(all) resource ForgeAdminProxy: ForgeAdminProxyClient { access(self) var capability: Capability<&FIND.Network>? @@ -422,7 +424,7 @@ pub contract FindForge { self.capability = nil } - pub fun addCapability(_ cap: Capability<&FIND.Network>) { + access(all) fun addCapability(_ cap: Capability<&FIND.Network>) { pre { cap.check() : "Invalid server capablity" self.capability == nil : "Server already set" @@ -430,11 +432,10 @@ pub contract FindForge { self.capability = cap } - pub fun fulfillForgeOrder(_ contractName: String, forgeType: Type) : MetadataViews.NFTCollectionDisplay { + access(ForgeOwner) fun fulfillForgeOrder(_ contractName: String, forgeType: Type) : MetadataViews.NFTCollectionDisplay { pre { self.capability != nil: "Cannot create FIND, capability is not set" } - return FindForge.fulfillForgeOrder(contractName, forgeType: forgeType) } } diff --git a/contracts/FindForgeOrder.cdc b/contracts/FindForgeOrder.cdc index bcac932b..46066cce 100644 --- a/contracts/FindForgeOrder.cdc +++ b/contracts/FindForgeOrder.cdc @@ -1,233 +1,260 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FIND from "./FIND.cdc" -import FindUtils from "./FindUtils.cdc" - -pub contract FindForgeOrder { - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event ForgeOrdered(lease: String, mintType: String, collectionDescription: String, collectionExternalURL: String, collectionSquareImage: String , collectionBannerImage: String, collectionSocials: {String : String}) - pub event ForgeOrderCompleted(lease: String, mintType: String, collectionDescription: String, collectionExternalURL: String, collectionSquareImage: String , collectionBannerImage: String, collectionSocials: {String : String}, contractName: String) - pub event ForgeOrderCancelled(lease: String, mintType: String, collectionDescription: String, collectionExternalURL: String, collectionSquareImage: String , collectionBannerImage: String, collectionSocials: {String : String}, contractName: String) - - pub let QueuedCollectionStoragePath: StoragePath - pub let QueuedCollectionPublicPath: PublicPath - pub let CompletedCollectionStoragePath: StoragePath - pub let CompletedCollectionPublicPath: PublicPath - - pub let mintTypes : [String] - // contractName : Resource UUID - pub let contractNames : {String : UInt64} - - pub resource Order: MetadataViews.Resolver { - pub let id: UInt64 - pub let leaseName: String - pub let mintType: String - pub let contractName: String - pub let minterCut: UFix64? - pub let collectionDisplay : MetadataViews.NFTCollectionDisplay - - init( - lease: String, - mintType: String, - minterCut: UFix64?, - collectionDisplay : MetadataViews.NFTCollectionDisplay - ) { - pre{ - collectionDisplay.name.toLower() == lease : "Collection Display Name must equal to lease Name" - FindForgeOrder.mintTypes.contains(mintType) : "MintType is not supported at the moment" - } - self.id = self.uuid - self.leaseName=lease - self.mintType=mintType - self.contractName="Find".concat(FindUtils.firstUpperLetter(self.leaseName)).concat(mintType) - self.minterCut=minterCut - self.collectionDisplay = collectionDisplay - } - - pub fun getViews(): [Type] { - return [ - Type() - ] - } - - pub fun resolveView(_ view: Type): AnyStruct? { - switch view { - case Type(): - return MetadataViews.Display( - name: self.collectionDisplay.name, - description: self.collectionDisplay.description, - thumbnail: self.collectionDisplay.squareImage.file - ) - - // This can be implemented when borrow contract is implemented - //case Type(): - // return MetadataViews.NFTCollectionData( - // storagePath: NFGv3.CollectionStoragePath, - // publicPath: NFGv3.CollectionPublicPath, - // providerPath: NFGv3.CollectionPrivatePath, - // publicCollection: Type<&NFGv3.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - // publicLinkedType: Type<&NFGv3.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - // providerLinkedType: Type<&NFGv3.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(), - // createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { - // return <-NFGv3.createEmptyCollection() - // }) - // ) - case Type(): - return self.collectionDisplay - } - return nil - } - } - - pub resource Collection : MetadataViews.ResolverCollection { - pub let orders: @{UInt64: FindForgeOrder.Order} - - init () { - self.orders <- {} - } - - destroy () { - destroy self.orders - } - - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @FindForgeOrder.Order { - let token <- self.orders.remove(key: withdrawID) ?? panic("missing Order : ".concat(withdrawID.toString())) - - emit Withdraw(id: token.id, from: self.owner?.address) - - return <-token - } - - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @FindForgeOrder.Order) { - - emit Deposit(id: token.id, to: self.owner?.address) - - self.orders[token.id] <-! token - } - - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { - return self.orders.keys - } - - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrow(_ id: UInt64): &FindForgeOrder.Order { - return (&self.orders[id] as &FindForgeOrder.Order?)! - } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.orders[id] as auth &FindForgeOrder.Order?)! - return nft as &AnyResource{MetadataViews.Resolver} - } - - } - - access(account) fun orderForge(leaseName: String, mintType: String, minterCut: UFix64?, collectionDisplay: MetadataViews.NFTCollectionDisplay) { - - let order <- create FindForgeOrder.Order(lease: leaseName, mintType: mintType, minterCut: minterCut, collectionDisplay: collectionDisplay) - let c = collectionDisplay - let s : {String : String} = {} - for social in c.socials.keys { - s[social] = c.socials[social]!.url - } - emit ForgeOrdered(lease: leaseName, mintType: mintType, collectionDescription: c.description, collectionExternalURL: c.externalURL.url, collectionSquareImage: c.squareImage.file.uri() , collectionBannerImage: c.bannerImage.file.uri(), collectionSocials: s) - FindForgeOrder.contractNames[order.contractName] = order.id - let col = FindForgeOrder.account.borrow<&FindForgeOrder.Collection>(from: FindForgeOrder.QueuedCollectionStoragePath)! - col.deposit(token: <- order) - } - - access(account) fun cancelForgeOrder(leaseName: String, mintType: String) { - let contractName = "Find".concat(FindUtils.firstUpperLetter(leaseName)).concat(mintType) - let id = FindForgeOrder.contractNames[contractName] ?? panic("Forge is not ordered. identifier : ".concat(contractName)) - let queuedCol = FindForgeOrder.account.borrow<&FindForgeOrder.Collection>(from: FindForgeOrder.QueuedCollectionStoragePath)! - let order <- queuedCol.withdraw(withdrawID: id) - let c = order.collectionDisplay - let s : {String : String} = {} - for social in c.socials.keys { - s[social] = c.socials[social]!.url - } - emit ForgeOrderCancelled(lease: order.leaseName, mintType: order.mintType, collectionDescription: c.description, collectionExternalURL: c.externalURL.url, collectionSquareImage: c.squareImage.file.uri() , collectionBannerImage: c.bannerImage.file.uri(), collectionSocials: s, contractName : contractName) - destroy order - } - - access(account) fun fulfillForgeOrder(_ contractName: String, forgeType: Type) : &FindForgeOrder.Order { - let id = FindForgeOrder.contractNames[contractName] ?? panic("Forge is not ordered. identifier : ".concat(contractName)) - - let queuedCol = FindForgeOrder.account.borrow<&FindForgeOrder.Collection>(from: FindForgeOrder.QueuedCollectionStoragePath)! - let order <- queuedCol.withdraw(withdrawID: id) - let c = order.collectionDisplay - let s : {String : String} = {} - for social in c.socials.keys { - s[social] = c.socials[social]!.url - } - emit ForgeOrderCompleted(lease: order.leaseName, mintType: order.mintType, collectionDescription: c.description, collectionExternalURL: c.externalURL.url, collectionSquareImage: c.squareImage.file.uri() , collectionBannerImage: c.bannerImage.file.uri(), collectionSocials: s, contractName : contractName) - - let completedCol = FindForgeOrder.account.borrow<&FindForgeOrder.Collection>(from: FindForgeOrder.CompletedCollectionStoragePath)! - completedCol.deposit(token: <- order) - let ref = completedCol.borrow(id) - return ref - } - - access(account) fun addMintType(_ mintType: String) { - pre{ - !self.mintTypes.contains(mintType) : "Mint type is already there : ".concat(mintType) - } - self.mintTypes.append(mintType) - } - - access(account) fun removeMintType(_ mintType: String) { - pre{ - self.mintTypes.contains(mintType) : "Mint type not there : ".concat(mintType) - } - self.mintTypes.remove(at: self.mintTypes.firstIndex(of: mintType)!) - } - - - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @FindForgeOrder.Collection { - return <- create Collection() - } - - init() { - // Initialize the total supply - self.mintTypes = [] - self.contractNames = {} - - // Set the named paths - self.QueuedCollectionStoragePath = /storage/queuedFindForgeOrder - self.QueuedCollectionPublicPath = /public/queuedFindForgeOrder - self.CompletedCollectionStoragePath = /storage/completedFindForgeOrder - self.CompletedCollectionPublicPath = /public/completedFindForgeOrder - - // Create a Collection resource and save it to storage - let queuedCollection <- create Collection() - self.account.save(<-queuedCollection, to: self.QueuedCollectionStoragePath) - - // create a public capability for the collection - self.account.link<&FindForgeOrder.Collection{MetadataViews.ResolverCollection}>( - self.QueuedCollectionPublicPath, - target: self.QueuedCollectionStoragePath - ) - - // Create a Collection resource and save it to storage - let completedCollection <- create Collection() - self.account.save(<-completedCollection, to: self.CompletedCollectionStoragePath) - - // create a public capability for the collection - self.account.link<&FindForgeOrder.Collection{MetadataViews.ResolverCollection}>( - self.CompletedCollectionPublicPath, - target: self.CompletedCollectionStoragePath - ) - - } +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "ViewResolver" +import "FIND" +import "FindUtils" + +access(all) contract FindForgeOrder { + + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event ForgeOrdered(lease: String, mintType: String, collectionDescription: String, collectionExternalURL: String, collectionSquareImage: String , collectionBannerImage: String, collectionSocials: {String : String}) + access(all) event ForgeOrderCompleted(lease: String, mintType: String, collectionDescription: String, collectionExternalURL: String, collectionSquareImage: String , collectionBannerImage: String, collectionSocials: {String : String}, contractName: String) + access(all) event ForgeOrderCancelled(lease: String, mintType: String, collectionDescription: String, collectionExternalURL: String, collectionSquareImage: String , collectionBannerImage: String, collectionSocials: {String : String}, contractName: String) + + access(all) let QueuedCollectionStoragePath: StoragePath + access(all) let QueuedCollectionPublicPath: PublicPath + access(all) let CompletedCollectionStoragePath: StoragePath + access(all) let CompletedCollectionPublicPath: PublicPath + + access(all) let mintTypes : [String] + // contractName : Resource UUID + access(all) let contractNames : {String : UInt64} + + access(all) resource interface OrderPublic { + access(all) fun getID(): UInt64 + access(all) fun getLeaseName(): String + access(all) fun getMintType(): String + access(all) fun getContractName(): String + access(all) fun getMinterCut(): UFix64? + access(all) fun getCollectionDisplay(): MetadataViews.NFTCollectionDisplay + } + + access(all) resource Order: OrderPublic, ViewResolver.Resolver { + access(all) let id: UInt64 + access(all) let leaseName: String + access(all) let mintType: String + access(all) let contractName: String + access(all) let minterCut: UFix64? + access(all) let collectionDisplay : MetadataViews.NFTCollectionDisplay + + init( + lease: String, + mintType: String, + minterCut: UFix64?, + collectionDisplay : MetadataViews.NFTCollectionDisplay + ) { + pre{ + collectionDisplay.name.toLower() == lease : "Collection Display Name must equal to lease Name" + FindForgeOrder.mintTypes.contains(mintType) : "MintType is not supported at the moment" + } + self.id = self.uuid + self.leaseName=lease + self.mintType=mintType + self.contractName="Find".concat(FindUtils.firstUpperLetter(self.leaseName)).concat(mintType) + self.minterCut=minterCut + self.collectionDisplay = collectionDisplay + } + + access(all) view fun getViews(): [Type] { + return [ + Type() + ] + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + case Type(): + return MetadataViews.Display( + name: self.collectionDisplay.name, + description: self.collectionDisplay.description, + thumbnail: self.collectionDisplay.squareImage.file + ) + + // This can be implemented when borrow contract is implemented + //case Type(): + // return MetadataViews.NFTCollectionData( + // storagePath: NFGv3.CollectionStoragePath, + // publicPath: NFGv3.CollectionPublicPath, + // providerPath: NFGv3.CollectionPrivatePath, + // publicCollection: Type<&NFGv3.Collection>(), + // publicLinkedType: Type<&NFGv3.Collection>(), + // providerLinkedType: Type<&NFGv3.Collection{NonFungibleToken.Collection,NonFungibleToken.Provider,ViewResolver.ResolverCollection}>(), + // createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { + // return <-NFGv3.createEmptyCollection() + // }) + // ) + case Type(): + return self.collectionDisplay + } + return nil + } + + access(all) fun getID(): UInt64 { + return self.id + } + access(all) fun getLeaseName(): String { + return self.leaseName + } + access(all) fun getMintType(): String { + return self.mintType + } + access(all) fun getContractName(): String { + return self.contractName + } + access(all) fun getMinterCut(): UFix64? { + return self.minterCut + } + access(all) fun getCollectionDisplay(): MetadataViews.NFTCollectionDisplay { + return self.collectionDisplay + } + } + + access(all) resource interface OrderCollection { + access(all) fun borrow(_ id: UInt64): &FindForgeOrder.Order? + access(all) fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} + access(all) view fun getIDs(): [UInt64] + access(all) fun deposit(token: @FindForgeOrder.Order) + } + + access(all) entitlement Owner + + access(all) resource Collection : OrderCollection, ViewResolver.ResolverCollection { + access(all) let orders: @{UInt64: FindForgeOrder.Order} + + init () { + self.orders <- {} + } + + // withdraw removes an NFT from the collection and moves it to the caller + access(Owner) fun withdraw(withdrawID: UInt64): @FindForgeOrder.Order { + let token <- self.orders.remove(key: withdrawID) ?? panic("missing Order : ".concat(withdrawID.toString())) + + emit Withdraw(id: token.getID(), from: self.owner?.address) + + return <-token + } + + // deposit takes a NFT and adds it to the collections dictionary + // and adds the ID to the id array + access(all) fun deposit(token: @FindForgeOrder.Order) { + + emit Deposit(id: token.getID(), to: self.owner?.address) + + self.orders[token.getID()] <-! token + } + + // getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { + return self.orders.keys + } + + // borrowNFT gets a reference to an NFT in the collection + // so that the caller can read its metadata and call its methods + access(all) fun borrow(_ id: UInt64): &FindForgeOrder.Order? { + return &self.orders[id] + } + + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} { + let nft = &self.orders[id] as &{ViewResolver.Resolver}? + return nft! + } + + } + + access(account) fun orderForge(leaseName: String, mintType: String, minterCut: UFix64?, collectionDisplay: MetadataViews.NFTCollectionDisplay) { + let order <- create FindForgeOrder.Order(lease: leaseName, mintType: mintType, minterCut: minterCut, collectionDisplay: collectionDisplay) + let c = collectionDisplay + let s : {String : String} = {} + for social in c.socials.keys { + s[social] = c.socials[social]!.url + } + emit ForgeOrdered(lease: leaseName, mintType: mintType, collectionDescription: c.description, collectionExternalURL: c.externalURL.url, collectionSquareImage: c.squareImage.file.uri() , collectionBannerImage: c.bannerImage.file.uri(), collectionSocials: s) + FindForgeOrder.contractNames[order.contractName] = order.id + let col = FindForgeOrder.account.storage.borrow(from: FindForgeOrder.QueuedCollectionStoragePath)! + col.deposit(token: <- order) + } + + access(account) fun cancelForgeOrder(leaseName: String, mintType: String) { + let contractName = "Find".concat(FindUtils.firstUpperLetter(leaseName)).concat(mintType) + let id = FindForgeOrder.contractNames[contractName] ?? panic("Forge is not ordered. identifier : ".concat(contractName)) + let queuedCol = FindForgeOrder.account.storage.borrow(from: FindForgeOrder.QueuedCollectionStoragePath)! + let order <- queuedCol.withdraw(withdrawID: id) + let c = order.getCollectionDisplay() + let s : {String : String} = {} + for social in c.socials.keys { + s[social] = c.socials[social]!.url + } + emit ForgeOrderCancelled(lease: order.getLeaseName(), mintType: order.getMintType(), collectionDescription: c.description, collectionExternalURL: c.externalURL.url, collectionSquareImage: c.squareImage.file.uri() , collectionBannerImage: c.bannerImage.file.uri(), collectionSocials: s, contractName : contractName) + destroy order + } + + access(account) fun fulfillForgeOrder(_ contractName: String, forgeType: Type) : &FindForgeOrder.Order { + let id = FindForgeOrder.contractNames[contractName] ?? panic("Forge is not ordered. identifier : ".concat(contractName)) + let queuedCol = FindForgeOrder.account.storage.borrow(from: FindForgeOrder.QueuedCollectionStoragePath)! + let order <- queuedCol.withdraw(withdrawID: id) + let c = order.getCollectionDisplay() + let s : {String : String} = {} + for social in c.socials.keys { + s[social] = c.socials[social]!.url + } + emit ForgeOrderCompleted(lease: order.getLeaseName(), mintType: order.getMintType(), collectionDescription: c.description, collectionExternalURL: c.externalURL.url, collectionSquareImage: c.squareImage.file.uri() , collectionBannerImage: c.bannerImage.file.uri(), collectionSocials: s, contractName : contractName) + + let completedCol = FindForgeOrder.account.storage.borrow(from: FindForgeOrder.CompletedCollectionStoragePath)! + completedCol.deposit(token: <- order) + let ref = completedCol.borrow(id) + return ref! + } + + access(account) fun addMintType(_ mintType: String) { + pre{ + !self.mintTypes.contains(mintType) : "Mint type is already there : ".concat(mintType) + } + self.mintTypes.append(mintType) + } + + access(account) fun removeMintType(_ mintType: String) { + pre{ + self.mintTypes.contains(mintType) : "Mint type not there : ".concat(mintType) + } + self.mintTypes.remove(at: self.mintTypes.firstIndex(of: mintType)!) + } + + + // public function that anyone can call to create a new empty collection + access(all) fun createEmptyCollection(): @{FindForgeOrder.OrderCollection} { + return <- create Collection() + } + + init() { + // Initialize the total supply + self.mintTypes = [] + self.contractNames = {} + + // Set the named paths + self.QueuedCollectionStoragePath = /storage/queuedFindForgeOrder + self.QueuedCollectionPublicPath = /public/queuedFindForgeOrder + self.CompletedCollectionStoragePath = /storage/completedFindForgeOrder + self.CompletedCollectionPublicPath = /public/completedFindForgeOrder + + // Create a Collection resource and save it to storage + let queuedCollection <- create Collection() + self.account.storage.save(<-queuedCollection, to: self.QueuedCollectionStoragePath) + + // create a public capability for the collection + let cap = self.account.capabilities.storage.issue<&{FindForgeOrder.OrderCollection}>(self.QueuedCollectionStoragePath) + self.account.capabilities.publish(cap, at: self.QueuedCollectionPublicPath) + + // Create a Collection resource and save it to storage + let completedCollection <- create Collection() + self.account.storage.save(<-completedCollection, to: self.CompletedCollectionStoragePath) + + // create a public capability for the collection + let cap2 = self.account.capabilities.storage.issue<&{FindForgeOrder.OrderCollection}>(self.CompletedCollectionStoragePath) + self.account.capabilities.publish(cap2, at: self.CompletedCollectionPublicPath) + } } - \ No newline at end of file + diff --git a/contracts/FindForgeStruct.cdc b/contracts/FindForgeStruct.cdc index 184b441e..169c75cb 100644 --- a/contracts/FindForgeStruct.cdc +++ b/contracts/FindForgeStruct.cdc @@ -1,8 +1,8 @@ -import MetadataViews from "./standard/MetadataViews.cdc" +import "MetadataViews" -pub contract FindForgeStruct { +access(all) contract FindForgeStruct { - pub event ContractInitialized() + access(all) event ContractInitialized() // for all traits in info : /* @@ -10,28 +10,28 @@ pub contract FindForgeStruct { if descriptions are added, we put that in description with prefix of the map variable, e.g. : scalar_key */ - pub struct FindDIM { - pub let name: String - pub let description: String - pub let thumbnailHash: String - pub let externalURL: String - pub let edition: UInt64 - pub let maxEdition: UInt64 - pub let descriptions: {String: String} + access(all) struct FindDIM { + access(all) let name: String + access(all) let description: String + access(all) let thumbnailHash: String + access(all) let externalURL: String + access(all) let edition: UInt64 + access(all) let maxEdition: UInt64 + access(all) let descriptions: {String: String} // stores number traits, max can be added - pub let scalars: {String: UFix64} + access(all) let scalars: {String: UFix64} // stores boost traits, max can be added - pub let boosts: {String: UFix64} + access(all) let boosts: {String: UFix64} // stores boost percentage traits - pub let boostPercents: {String: UFix64} + access(all) let boostPercents: {String: UFix64} // stores level traits, max can be stored - pub let levels: {String: UFix64} + access(all) let levels: {String: UFix64} // stores string traits - pub let traits: {String: String} + access(all) let traits: {String: String} // stores date traits - pub let dates: {String: UFix64} - pub let medias: {String: String} - pub let extras: {String: AnyStruct} + access(all) let dates: {String: UFix64} + access(all) let medias: {String: String} + access(all) let extras: {String: AnyStruct} init(name: String, description: String, thumbnailHash: String, edition:UInt64, maxEdition:UInt64, externalURL:String, descriptions: {String: String}, scalars: {String: UFix64},boosts: {String: UFix64}, boostPercents: {String: UFix64}, levels: {String: UFix64}, traits: {String: String}, dates: {String: UFix64}, medias: {String: String}) { self.name=name diff --git a/contracts/FindFurnace.cdc b/contracts/FindFurnace.cdc index e450410d..83e45ab1 100644 --- a/contracts/FindFurnace.cdc +++ b/contracts/FindFurnace.cdc @@ -1,31 +1,28 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FindMarket from "./FindMarket.cdc" -import FindViews from "./FindViews.cdc" -import FIND from "./FIND.cdc" +import "NonFungibleToken" +import "FindMarket" +import "FindViews" +import "FIND" -pub contract FindFurnace { +access(all) contract FindFurnace { + access(all) event Burned(from: Address, fromName: String?, uuid: UInt64, nftInfo: FindMarket.NFTInfo, context: {String : String}) - pub event Burned(from: Address, fromName: String?, uuid: UInt64, nftInfo: FindMarket.NFTInfo, context: {String : String}) - - pub fun burn(pointer: FindViews.AuthNFTPointer, context: {String : String}) { - if !pointer.valid() { - panic("Invalid NFT Pointer. Type : ".concat(pointer.itemType.identifier).concat(" ID : ").concat(pointer.uuid.toString())) - } - - let vr = pointer.getViewResolver() - let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true) - let owner = pointer.owner() - emit Burned(from: owner, fromName: FIND.reverseLookup(owner) , uuid: pointer.uuid, nftInfo: nftInfo, context: context) - destroy pointer.withdraw() - } - - pub fun burnWithoutValidation(pointer: FindViews.AuthNFTPointer, context: {String : String}) { - let vr = pointer.getViewResolver() - let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true) - let owner = pointer.owner() - emit Burned(from: owner, fromName: FIND.reverseLookup(owner) , uuid: pointer.uuid, nftInfo: nftInfo, context: context) - destroy pointer.withdraw() - } + access(all) fun burn(pointer: FindViews.AuthNFTPointer, context: {String : String}) { + if !pointer.valid() { + panic("Invalid NFT Pointer. Type : ".concat(pointer.itemType.identifier).concat(" ID : ").concat(pointer.uuid.toString())) + } + let vr = pointer.getViewResolver() + let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true) + let owner = pointer.owner() + emit Burned(from: owner, fromName: FIND.reverseLookup(owner) , uuid: pointer.uuid, nftInfo: nftInfo, context: context) + destroy pointer.withdraw() + } + access(all) fun burnWithoutValidation(pointer: FindViews.AuthNFTPointer, context: {String : String}) { + let vr = pointer.getViewResolver() + let nftInfo = FindMarket.NFTInfo(vr, id: pointer.id, detail: true) + let owner = pointer.owner() + emit Burned(from: owner, fromName: FIND.reverseLookup(owner) , uuid: pointer.uuid, nftInfo: nftInfo, context: context) + destroy pointer.withdraw() + } } diff --git a/contracts/FindLeaseMarket.cdc b/contracts/FindLeaseMarket.cdc index f9bcefd4..2d75ba41 100644 --- a/contracts/FindLeaseMarket.cdc +++ b/contracts/FindLeaseMarket.cdc @@ -1,750 +1,741 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FIND from "./FIND.cdc" -import Profile from "./Profile.cdc" -import Clock from "./Clock.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindMarket from "../contracts/FindMarket.cdc" -import FindRulesCache from "../contracts/FindRulesCache.cdc" -import FindMarketCutStruct from "../contracts/FindMarketCutStruct.cdc" -import FindUtils from "../contracts/FindUtils.cdc" - -pub contract FindLeaseMarket { - - access(contract) let saleItemTypes : [Type] - access(contract) let saleItemCollectionTypes : [Type] - access(contract) let marketBidTypes : [Type] - access(contract) let marketBidCollectionTypes : [Type] - - pub event RoyaltyPaid(tenant:String, leaseName: String, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, leaseInfo:LeaseInfo) - pub event RoyaltyCouldNotBePaid(tenant:String, leaseName: String, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, leaseInfo:LeaseInfo, residualAddress: Address) - pub event FindBlockRules(tenant: String, ruleName: String, ftTypes:[String], listingTypes:[String], status:String) - pub event TenantAllowRules(tenant: String, ruleName: String, ftTypes:[String], listingTypes:[String], status:String) - pub event FindCutRules(tenant: String, ruleName: String, cut:UFix64, ftTypes:[String], listingTypes:[String], status:String) - - // ======================================== - - /* Get Tenant */ - pub fun getTenant(_ tenant: Address) : &FindMarket.Tenant{FindMarket.TenantPublic} { - return FindMarket.getTenantCapability(tenant)!.borrow()! - } - - pub fun getSaleItemTypes() : [Type] { - return self.saleItemTypes - } - - /* Get SaleItemCollections */ - pub fun getSaleItemCollectionTypes() : [Type] { - return self.saleItemCollectionTypes - } - - pub fun getSaleItemCollectionCapabilities(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindLeaseMarket.SaleItemCollectionPublic}>] { - var caps : [Capability<&{FindLeaseMarket.SaleItemCollectionPublic}>] = [] - for type in self.getSaleItemCollectionTypes() { - if type != nil { - let cap = getAccount(address).getCapability<&{FindLeaseMarket.SaleItemCollectionPublic}>(tenantRef.getPublicPath(type)) - if cap.check() { - caps.append(cap) - } - } - } - return caps - } - - pub fun getSaleItemCollectionCapability(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindLeaseMarket.SaleItemCollectionPublic}> { - for type in self.getSaleItemCollectionTypes() { - if FindMarket.getMarketOptionFromType(type) == marketOption{ - let cap = getAccount(address).getCapability<&{FindLeaseMarket.SaleItemCollectionPublic}>(tenantRef.getPublicPath(type)) - return cap - } - } - panic("Cannot find market option : ".concat(marketOption)) - } - - - - /* Get Sale Reports and Sale Item */ - pub fun assertOperationValid(tenant: Address, name: String, marketOption: String) : &{SaleItem} { - - let tenantRef=self.getTenant(tenant) - let address=FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name)) - let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - let optRef = collectionCap.borrow() - if optRef == nil { - panic("Account not properly set up, cannot borrow sale item collection") - } - let ref=optRef! - let item=ref.borrowSaleItem(name) - if !item.checkPointer() { - panic("this is a ghost listing") - } - - return item - } - - /* Get Sale Reports and Sale Item */ - pub fun getSaleInformation(tenant: Address, name: String, marketOption: String, getLeaseInfo: Bool) : FindLeaseMarket.SaleItemInformation? { - let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name)) - let tenantRef=self.getTenant(tenant) - let info = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: false, getLeaseInfo: getLeaseInfo) - if info.items.length > 0 { - return info.items[0] - } - return nil - } - - pub fun getSaleItemReport(tenant:Address, address: Address, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemCollectionReport} { - let tenantRef = self.getTenant(tenant) - var report : {String : FindLeaseMarket.SaleItemCollectionReport} = {} - for type in self.getSaleItemCollectionTypes() { - let marketOption = FindMarket.getMarketOptionFromType(type) - let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: nil, getGhost: true, getLeaseInfo: getLeaseInfo) - if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 { - report[marketOption] = returnedReport - } - } - return report - } - - pub fun getSaleItems(tenant:Address, name: String, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemCollectionReport} { - let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name)) - let tenantRef = self.getTenant(tenant) - var report : {String : FindLeaseMarket.SaleItemCollectionReport} = {} - for type in self.getSaleItemCollectionTypes() { - let marketOption = FindMarket.getMarketOptionFromType(type) - let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: true, getLeaseInfo: getLeaseInfo) - if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 { - report[marketOption] = returnedReport - } - } - return report - } - - pub fun getLeaseListing(tenant:Address, name: String, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemInformation} { - let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name)) - let tenantRef = self.getTenant(tenant) - var report : {String : FindLeaseMarket.SaleItemInformation} = {} - for type in self.getSaleItemCollectionTypes() { - let marketOption = FindMarket.getMarketOptionFromType(type) - let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: true, getLeaseInfo: getLeaseInfo) - if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 { - report[marketOption] = returnedReport.items[0] - } - } - return report - } - - access(contract) fun checkSaleInformation(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, marketOption: String, address: Address, name: String?, getGhost: Bool, getLeaseInfo: Bool) : FindLeaseMarket.SaleItemCollectionReport { - let ghost: [FindLeaseMarket.GhostListing] =[] - let info: [FindLeaseMarket.SaleItemInformation] =[] - let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - let optRef = collectionCap.borrow() - if optRef == nil { - return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost) - } - let ref=optRef! - - var listName : [String]= [] - if let leaseName = name{ - if !ref.containsNameSale(leaseName) { - return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost) - } - listName=[leaseName] - } else { - listName = ref.getNameSales() - } - - let listingType = ref.getListingType() - - for leaseName in listName { - //if this id is not present in this Market option then we just skip it - let item=ref.borrowSaleItem(leaseName) - if !item.checkPointer() { - if getGhost { - ghost.append(FindLeaseMarket.GhostListing(listingType: listingType, name:leaseName)) - } - continue - } - let stopped=tenantRef.allowedAction(listingType: listingType, nftType: item.getItemType(), ftType: item.getFtType(), action: FindMarket.MarketAction(listing:false, name:"delist item for sale"), seller: address, buyer: nil) - var status="active" - - if !stopped.allowed && stopped.message == "Seller banned by Tenant" { - status="banned" - info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: false)) - continue - } - - if !stopped.allowed { - status="stopped" - info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: false)) - continue - } - - let deprecated=tenantRef.allowedAction(listingType: listingType, nftType: item.getItemType(), ftType: item.getFtType(), action: FindMarket.MarketAction(listing:true, name:"delist item for sale"), seller: address, buyer: nil) - - if !deprecated.allowed { - status="deprecated" - info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: getLeaseInfo)) - continue - } - - if let validTime = item.getValidUntil() { - if validTime <= Clock.time() { - status="ended" - } - } - info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: getLeaseInfo)) - } - - return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost) - } - - /* Get Bid Collections */ - pub fun getMarketBidTypes() : [Type] { - return self.marketBidTypes - } - - pub fun getMarketBidCollectionTypes() : [Type] { - return self.marketBidCollectionTypes - } - - pub fun getMarketBidCollectionCapabilities(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindLeaseMarket.MarketBidCollectionPublic}>] { - var caps : [Capability<&{FindLeaseMarket.MarketBidCollectionPublic}>] = [] - for type in self.getMarketBidCollectionTypes() { - let cap = getAccount(address).getCapability<&{FindLeaseMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type)) - if cap.check() { - caps.append(cap) - } - } - return caps - } - - pub fun getMarketBidCollectionCapability(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindLeaseMarket.MarketBidCollectionPublic}> { - for type in self.getMarketBidCollectionTypes() { - if FindMarket.getMarketOptionFromType(type) == marketOption{ - let cap = getAccount(address).getCapability<&{FindLeaseMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type)) - return cap - } - } - panic("Cannot find market option : ".concat(marketOption)) - } - - pub fun getBid(tenant: Address, address: Address, marketOption: String, name:String, getLeaseInfo: Bool) : FindLeaseMarket.BidInfo? { - let tenantRef=self.getTenant(tenant) - let bidInfo = self.checkBidInformation(tenantRef: tenantRef, marketOption: marketOption, address: address, name: name, getGhost: false, getLeaseInfo: getLeaseInfo) - if bidInfo.items.length > 0 { - return bidInfo.items[0] - } - return nil - } - - pub fun getBidsReport(tenant:Address, address: Address, getLeaseInfo: Bool) : {String : FindLeaseMarket.BidItemCollectionReport} { - let tenantRef = self.getTenant(tenant) - var report : {String : FindLeaseMarket.BidItemCollectionReport} = {} - for type in self.getMarketBidCollectionTypes() { - let marketOption = FindMarket.getMarketOptionFromType(type) - let returnedReport = self.checkBidInformation(tenantRef: tenantRef, marketOption: marketOption, address: address, name: nil, getGhost: true, getLeaseInfo: getLeaseInfo) - if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 { - report[marketOption] = returnedReport - } - } - return report - } - - access(contract) fun checkBidInformation(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, marketOption: String, address: Address, name: String?, getGhost:Bool, getLeaseInfo: Bool) : FindLeaseMarket.BidItemCollectionReport { - let ghost: [FindLeaseMarket.GhostListing] =[] - let info: [FindLeaseMarket.BidInfo] =[] - let collectionCap = self.getMarketBidCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - - let optRef = collectionCap.borrow() - if optRef==nil { - return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost) - } - - let ref=optRef! - - let listingType = ref.getBidType() - var listName : [String]= [] - if let leaseName = name{ - if !ref.containsNameBid(leaseName) { - return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost) - } - listName=[leaseName] - } else { - listName = ref.getNameBids() - } - - for leaseName in listName { - - let bid=ref.borrowBidItem(leaseName) - let item=self.getSaleInformation(tenant: tenantRef.owner!.address, name: leaseName, marketOption: marketOption, getLeaseInfo: getLeaseInfo) - if item == nil { - if getGhost { - ghost.append(FindLeaseMarket.GhostListing(listingType: listingType, name:leaseName)) - } - continue - } - let bidInfo = FindLeaseMarket.BidInfo(name: leaseName, bidTypeIdentifier: listingType.identifier, bidAmount: bid.getBalance(), timestamp: Clock.time(), item:item!) - info.append(bidInfo) - - } - return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost) - } - - pub fun assertBidOperationValid(tenant: Address, address: Address, marketOption: String, name:String) : &{SaleItem} { - - let tenantRef=self.getTenant(tenant) - let collectionCap = self.getMarketBidCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - let optRef = collectionCap.borrow() - if optRef == nil { - panic("Account not properly set up, cannot borrow bid item collection. Account address : ".concat(collectionCap.address.toString())) - } - let ref=optRef! - let bidItem=ref.borrowBidItem(name) - - let saleItemCollectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: bidItem.getSellerAddress()) - let saleRef = saleItemCollectionCap.borrow() - if saleRef == nil { - panic("Seller account is not properly set up, cannot borrow sale item collection. Seller address : ".concat(saleItemCollectionCap.address.toString())) - } - let sale=saleRef! - let item=sale.borrowSaleItem(name) - if !item.checkPointer() { - panic("this is a ghost listing") - } - - return item - } - - /////// Pointer Section - - pub struct interface LeasePointer { - pub let name: String - pub let uuid: UInt64 - - pub fun valid() : Bool - pub fun getUUID() :UInt64 - pub fun getLease() : FIND.LeaseInformation - pub fun owner() : Address - access(contract) fun borrow() : &FIND.LeaseCollection{FIND.LeaseCollectionPublic} - } - - pub struct ReadLeasePointer : LeasePointer { - access(self) let cap: Capability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}> - pub let name: String - pub let uuid: UInt64 - - // Passing in the reference here to ensure that is the owner - init(name: String) { - - let address = FIND.lookupAddress(name) ?? panic("This lease name is not owned") - - self.cap=getAccount(address).getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - self.name=name - - if !self.cap.check() { - panic("The capability is not valid.") - } - - self.uuid = self.cap.borrow()!.getLeaseUUID(name) - - } - - access(contract) fun borrow() : &FIND.LeaseCollection{FIND.LeaseCollectionPublic} { - return self.cap.borrow() ?? panic("The capability of pointer is not linked.") - } - - pub fun getLease() : FIND.LeaseInformation { - return self.borrow().getLease(self.name) ?? panic("The owner doesn't hold the lease anymore".concat(self.name)) - } - - pub fun getUUID() :UInt64{ - return self.uuid - } - - pub fun owner() : Address { - return self.cap.address - } - - pub fun valid() : Bool { - if !self.cap.check() || !self.cap.borrow()!.getNames().contains(self.name) { - return false - } - - if Clock.time() > FindLeaseMarket.getNetwork().getLeaseExpireTime(self.name) { - return false - } - return true - } - } - - pub struct AuthLeasePointer : LeasePointer { - access(self) let cap: Capability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}> - pub let name: String - pub let uuid: UInt64 - - // Passing in the reference here to ensure that is the owner - init(ref:&FIND.LeaseCollection, name: String) { - self.cap=getAccount(ref.owner!.address).getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - self.name=name - - if !ref.getNames().contains(name) { - panic("Please pass in the corresponding lease collection reference.") - } - - if !self.cap.check() { - panic("The capability is not valid.") - } - - self.uuid = self.cap.borrow()!.getLeaseUUID(name) - } - - access(contract) fun borrow() : &FIND.LeaseCollection{FIND.LeaseCollectionPublic} { - return self.cap.borrow() ?? panic("The capability of pointer is not linked.") - } - - pub fun getLease() : FIND.LeaseInformation { - return self.borrow().getLease(self.name) ?? panic("The owner doesn't hold the lease anymore".concat(self.name)) - } - - pub fun getUUID() :UInt64{ - return self.uuid - } - - pub fun valid() : Bool { - if !self.cap.check() || !self.cap.borrow()!.getNames().contains(self.name) { - return false - } - - if Clock.time() > FindLeaseMarket.getNetwork().getLeaseExpireTime(self.name) { - return false - } - return true - } - - access(account) fun move(to: Address) { - pre{ - self.valid() : "The lease capability is not valid" - } - let receiver = getAccount(to) - let profile = receiver.getCapability<&{Profile.Public}>(Profile.publicPath) - let leases = receiver.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - self.borrow().move(name: self.name, profile: profile, to: leases) - } - - pub fun owner() : Address { - return self.cap.address - } - - } - - access(account) fun pay(tenant: String, leaseName: String, saleItem: &{SaleItem}, vault: @FungibleToken.Vault, leaseInfo: LeaseInfo, cuts:{String : FindMarketCutStruct.Cuts}) { - let buyer=saleItem.getBuyer() - let seller=saleItem.getSeller() - let soldFor=vault.balance - let ftType=vault.getType() - let ftInfo = FTRegistry.getFTInfoByTypeIdentifier(ftType.identifier)! // If this panic, there is sth wrong in FT set up - let oldProfileCap= getAccount(seller).getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - let oldProfile = FindMarket.getPaymentWallet(oldProfileCap, ftInfo, panicOnFailCheck: true) - - for key in cuts.keys { - let allCuts = cuts[key]! - for cut in allCuts.cuts { - if var cutAmount= cut.getAmountPayable(soldFor) { - let findName = FIND.reverseLookup(cut.getAddress()) - emit RoyaltyPaid(tenant: tenant, leaseName: leaseName, saleID: saleItem.uuid, address:cut.getAddress(), findName: findName , royaltyName: cut.getName(), amount: cutAmount, vaultType: ftType.identifier, leaseInfo:leaseInfo) - let vaultRef = cut.getReceiverCap().borrow() ?? panic("Royalty receiving account is not set up properly. Royalty account address : ".concat(cut.getAddress().toString()).concat(" Royalty Name : ").concat(cut.getName())) - vaultRef.deposit(from: <- vault.withdraw(amount: cutAmount)) - } - } - } - - - oldProfile.deposit(from: <- vault) - } - - //struct to expose information about leases - pub struct LeaseInfo { - pub let name: String - pub let address: Address - pub let cost: UFix64 - pub let status: String - pub let validUntil: UFix64 - pub let lockedUntil: UFix64 - pub let addons: [String] - - init(_ pointer: AnyStruct{FindLeaseMarket.LeasePointer}){ - let network = FindLeaseMarket.getNetwork() - let name = pointer.name - let status= network.readStatus(name) - self.name=name - var s="TAKEN" - if status.status == FIND.LeaseStatus.FREE { - s="FREE" - } else if status.status == FIND.LeaseStatus.LOCKED { - s="LOCKED" - } - self.status=s - self.validUntil=network.getLeaseExpireTime(name) - self.lockedUntil=network.getLeaseLockedUntil(name) - self.address=status.owner! - self.cost=network.calculateCost(name) - if pointer.valid() { - let lease = pointer.borrow() - self.addons=lease.getAddon(name: name) - } else { - self.addons=[] - } - } - - } - - pub resource interface SaleItem { - //this is the type of sale this is, active, cancelled etc - pub fun getSaleType(): String - pub fun getSeller(): Address - pub fun getBuyer(): Address? - - pub fun getSellerName() : String? - pub fun getBuyerName() : String? - - pub fun toLeaseInfo() : FindLeaseMarket.LeaseInfo - pub fun checkPointer() : Bool - pub fun getListingType() : Type - pub fun getListingTypeIdentifier(): String - - //the Type of the item for sale - pub fun getItemType(): Type - //The id of the nft for sale - pub fun getLeaseName() : String - - pub fun getBalance(): UFix64 - pub fun getAuction(): AuctionItem? - pub fun getFtType() : Type //The type of FT used for this sale item - pub fun getValidUntil() : UFix64? //A timestamp that says when this item is valid until - - pub fun getSaleItemExtraField() : {String : AnyStruct} - pub fun getId() : UInt64 - } - - pub resource interface Bid { - pub fun getBalance() : UFix64 - pub fun getSellerAddress() : Address - pub fun getBidExtraField() : {String : AnyStruct} - } - - pub struct SaleItemInformation { - pub let leaseIdentifier: String - pub let leaseName: String - pub let seller: Address - pub let sellerName: String? - pub let amount: UFix64? - pub let bidder: Address? - pub var bidderName: String? - pub let listingId: UInt64 - - pub let saleType: String - pub let listingTypeIdentifier: String - pub let ftAlias: String - pub let ftTypeIdentifier: String - pub let listingValidUntil: UFix64? - - pub var lease: LeaseInfo? - pub let auction: AuctionItem? - pub let listingStatus:String - pub let saleItemExtraField: {String : AnyStruct} - - init(item: &{SaleItem}, status:String, leaseInfo: Bool) { - self.leaseIdentifier= item.getItemType().identifier - self.leaseName=item.getLeaseName() - self.listingStatus=status - self.saleType=item.getSaleType() - self.listingTypeIdentifier=item.getListingTypeIdentifier() - self.listingId=item.getId() - self.amount=item.getBalance() - self.bidder=item.getBuyer() - self.bidderName=item.getBuyerName() - self.seller=item.getSeller() - self.sellerName=item.getSellerName() - self.listingValidUntil=item.getValidUntil() - self.lease=nil - if leaseInfo { - if status != "stopped" { - self.lease=item.toLeaseInfo() - } - } - let ftIdentifier=item.getFtType().identifier - self.ftTypeIdentifier=ftIdentifier - let ftInfo=FTRegistry.getFTInfoByTypeIdentifier(ftIdentifier) - self.ftAlias=ftInfo?.alias ?? "" - - self.auction=item.getAuction() - self.saleItemExtraField=item.getSaleItemExtraField() - } - } - - pub struct BidInfo{ - pub let name: String - pub let bidAmount: UFix64 - pub let bidTypeIdentifier: String - pub let timestamp: UFix64 - pub let item: SaleItemInformation - - init(name: String, bidTypeIdentifier: String, bidAmount: UFix64, timestamp: UFix64, item:SaleItemInformation) { - self.name=name - self.bidAmount=bidAmount - self.bidTypeIdentifier=bidTypeIdentifier - self.timestamp=timestamp - self.item=item - } - } - - pub struct AuctionItem { - //end time - //current time - pub let startPrice: UFix64 - pub let currentPrice: UFix64 - pub let minimumBidIncrement: UFix64 - pub let reservePrice: UFix64 - pub let extentionOnLateBid: UFix64 - pub let auctionEndsAt: UFix64? - pub let timestamp: UFix64 - - init(startPrice: UFix64, currentPrice: UFix64, minimumBidIncrement: UFix64, reservePrice: UFix64, extentionOnLateBid: UFix64, auctionEndsAt: UFix64? , timestamp: UFix64){ - self.startPrice = startPrice - self.currentPrice = currentPrice - self.minimumBidIncrement = minimumBidIncrement - self.reservePrice = reservePrice - self.extentionOnLateBid = extentionOnLateBid - self.auctionEndsAt = auctionEndsAt - self.timestamp = timestamp - } - } - - pub resource interface SaleItemCollectionPublic { - pub fun getNameSales(): [String] - pub fun containsNameSale(_ name: String): Bool - access(account) fun borrowSaleItem(_ name: String) : &{SaleItem} - pub fun getListingType() : Type - } - - pub resource interface MarketBidCollectionPublic { - pub fun getNameBids() : [String] - pub fun containsNameBid(_ name: String): Bool - pub fun getBidType() : Type - access(account) fun borrowBidItem(_ name: String) : &{Bid} - } - - pub struct GhostListing{ - // pub let listingType: Type - pub let listingTypeIdentifier: String - pub let name: String - - - init(listingType:Type, name:String) { - // self.listingType=listingType - self.listingTypeIdentifier=listingType.identifier - self.name=name - } - } - - pub struct SaleItemCollectionReport { - pub let items : [FindLeaseMarket.SaleItemInformation] - pub let ghosts: [FindLeaseMarket.GhostListing] - - init(items: [SaleItemInformation], ghosts: [GhostListing]) { - self.items=items - self.ghosts=ghosts - } - } - - pub struct BidItemCollectionReport { - pub let items : [FindLeaseMarket.BidInfo] - pub let ghosts: [FindLeaseMarket.GhostListing] - - init(items: [BidInfo], ghosts: [GhostListing]) { - self.items=items - self.ghosts=ghosts - } - } - - access(contract) fun getNetwork() : &FIND.Network { - return FindLeaseMarket.account.borrow<&FIND.Network>(from : FIND.NetworkStoragePath) ?? panic("Network is not up") - } - - /* Admin Function */ - access(account) fun addSaleItemType(_ type: Type) { - self.saleItemTypes.append(type) - FindMarket.addPathMap(type) - FindMarket.addListingName(type) - } - - access(account) fun addMarketBidType(_ type: Type) { - self.marketBidTypes.append(type) - FindMarket.addPathMap(type) - FindMarket.addListingName(type) - } - - access(account) fun addSaleItemCollectionType(_ type: Type) { - self.saleItemCollectionTypes.append(type) - FindMarket.addPathMap(type) - FindMarket.addListingName(type) - } - - access(account) fun addMarketBidCollectionType(_ type: Type) { - self.marketBidCollectionTypes.append(type) - FindMarket.addPathMap(type) - FindMarket.addListingName(type) - } - - access(account) fun removeSaleItemType(_ type: Type) { - var counter = 0 - while counter < self.saleItemTypes.length { - if type == self.saleItemTypes[counter] { - self.saleItemTypes.remove(at: counter) - } - counter = counter + 1 - } - } - - access(account) fun removeMarketBidType(_ type: Type) { - var counter = 0 - while counter < self.marketBidTypes.length { - if type == self.marketBidTypes[counter] { - self.marketBidTypes.remove(at: counter) - } - counter = counter + 1 - } - } - - access(account) fun removeSaleItemCollectionType(_ type: Type) { - var counter = 0 - while counter < self.saleItemCollectionTypes.length { - if type == self.saleItemCollectionTypes[counter] { - self.saleItemCollectionTypes.remove(at: counter) - } - counter = counter + 1 - } - } - - access(account) fun removeMarketBidCollectionType(_ type: Type) { - var counter = 0 - while counter < self.marketBidCollectionTypes.length { - if type == self.marketBidCollectionTypes[counter] { - self.marketBidCollectionTypes.remove(at: counter) - } - counter = counter + 1 - } - } - - init() { - - self.saleItemTypes = [] - self.saleItemCollectionTypes = [] - self.marketBidTypes = [] - self.marketBidCollectionTypes = [] - - } - +import "FungibleToken" +import "FindViews" +import "FIND" +import "Profile" +import "Clock" +import "FTRegistry" +import "MetadataViews" +import "FindMarket" +import "FindRulesCache" +import "FindMarketCutStruct" +import "FindUtils" + +access(all) contract FindLeaseMarket { + + access(contract) let saleItemTypes : [Type] + access(contract) let saleItemCollectionTypes : [Type] + access(contract) let marketBidTypes : [Type] + access(contract) let marketBidCollectionTypes : [Type] + + access(all) event RoyaltyPaid(tenant:String, leaseName: String, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, leaseInfo:LeaseInfo) + access(all) event RoyaltyCouldNotBePaid(tenant:String, leaseName: String, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, leaseInfo:LeaseInfo, residualAddress: Address) + access(all) event FindBlockRules(tenant: String, ruleName: String, ftTypes:[String], listingTypes:[String], status:String) + access(all) event TenantAllowRules(tenant: String, ruleName: String, ftTypes:[String], listingTypes:[String], status:String) + access(all) event FindCutRules(tenant: String, ruleName: String, cut:UFix64, ftTypes:[String], listingTypes:[String], status:String) + + // ======================================== + + /* Get Tenant */ + access(all) fun getTenant(_ tenant: Address) : &{FindMarket.TenantPublic} { + return FindMarket.getTenantCapability(tenant)!.borrow()! + } + + access(all) fun getSaleItemTypes() : [Type] { + return self.saleItemTypes + } + + /* Get SaleItemCollections */ + access(all) fun getSaleItemCollectionTypes() : [Type] { + return self.saleItemCollectionTypes + } + + access(all) fun getSaleItemCollectionCapabilities(tenantRef: &{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindLeaseMarket.SaleItemCollectionPublic}>] { + var caps : [Capability<&{FindLeaseMarket.SaleItemCollectionPublic}>] = [] + for type in self.getSaleItemCollectionTypes() { + if type != nil { + let cap = getAccount(address).capabilities.get<&{FindLeaseMarket.SaleItemCollectionPublic}>(tenantRef.getPublicPath(type)) + if cap.check() { + caps.append(cap) + } + } + } + return caps + } + + access(all) fun getSaleItemCollectionCapability(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindLeaseMarket.SaleItemCollectionPublic}>? { + for type in self.getSaleItemCollectionTypes() { + if FindMarket.getMarketOptionFromType(type) == marketOption{ + let path=tenantRef.getPublicPath(type) + let cap = getAccount(address).capabilities.get<&{FindLeaseMarket.SaleItemCollectionPublic}>(path) + return cap + } + } + panic("Cannot find market option : ".concat(marketOption)) + } + + /* Get Sale Reports and Sale Item */ + access(all) fun assertOperationValid(tenant: Address, name: String, marketOption: String) : &{SaleItem} { + let tenantRef=self.getTenant(tenant) + let address=FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name)) + let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) + let optRef = collectionCap?.borrow() + if optRef == nil { + panic("Account not properly set up, cannot borrow sale item collection") + } + let ref=optRef!! + let item=ref.borrowSaleItem(name) + if !item.checkPointer() { + panic("this is a ghost listing") + } + + return item + } + + /* Get Sale Reports and Sale Item */ + access(all) fun getSaleInformation(tenant: Address, name: String, marketOption: String, getLeaseInfo: Bool) : FindLeaseMarket.SaleItemInformation? { + let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name)) + let tenantRef=self.getTenant(tenant) + let info = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: false, getLeaseInfo: getLeaseInfo) + if info.items.length > 0 { + return info.items[0] + } + return nil + } + + access(all) fun getSaleItemReport(tenant:Address, address: Address, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemCollectionReport} { + let tenantRef = self.getTenant(tenant) + var report : {String : FindLeaseMarket.SaleItemCollectionReport} = {} + for type in self.getSaleItemCollectionTypes() { + let marketOption = FindMarket.getMarketOptionFromType(type) + let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: nil, getGhost: true, getLeaseInfo: getLeaseInfo) + if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 { + report[marketOption] = returnedReport + } + } + return report + } + + access(all) fun getSaleItems(tenant:Address, name: String, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemCollectionReport} { + let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name)) + let tenantRef = self.getTenant(tenant) + var report : {String : FindLeaseMarket.SaleItemCollectionReport} = {} + for type in self.getSaleItemCollectionTypes() { + let marketOption = FindMarket.getMarketOptionFromType(type) + let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: true, getLeaseInfo: getLeaseInfo) + if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 { + report[marketOption] = returnedReport + } + } + return report + } + + access(all) fun getLeaseListing(tenant:Address, name: String, getLeaseInfo: Bool) : {String : FindLeaseMarket.SaleItemInformation} { + let address = FIND.lookupAddress(name) ?? panic("Name is not owned by anyone. Name : ".concat(name)) + let tenantRef = self.getTenant(tenant) + var report : {String : FindLeaseMarket.SaleItemInformation} = {} + for type in self.getSaleItemCollectionTypes() { + let marketOption = FindMarket.getMarketOptionFromType(type) + let returnedReport = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, name: name, getGhost: true, getLeaseInfo: getLeaseInfo) + if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 { + report[marketOption] = returnedReport.items[0] + } + } + return report + } + + access(contract) fun checkSaleInformation(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address, name: String?, getGhost: Bool, getLeaseInfo: Bool) : FindLeaseMarket.SaleItemCollectionReport { + let ghost: [FindLeaseMarket.GhostListing] =[] + let info: [FindLeaseMarket.SaleItemInformation] =[] + let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) + let optRef = collectionCap?.borrow() + if optRef == nil { + return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost) + } + let ref=optRef!! + + var listName : [String]= [] + if let leaseName = name{ + if !ref.containsNameSale(leaseName) { + return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost) + } + listName=[leaseName] + } else { + listName = ref.getNameSales() + } + + let listingType = ref.getListingType() + + for leaseName in listName { + //if this id is not present in this Market option then we just skip it + let item=ref.borrowSaleItem(leaseName) + if !item.checkPointer() { + if getGhost { + ghost.append(FindLeaseMarket.GhostListing(listingType: listingType, name:leaseName)) + } + continue + } + let stopped=tenantRef.allowedAction(listingType: listingType, nftType: item.getItemType(), ftType: item.getFtType(), action: FindMarket.MarketAction(listing:false, name:"delist item for sale"), seller: address, buyer: nil) + var status="active" + + if !stopped.allowed && stopped.message == "Seller banned by Tenant" { + status="banned" + info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: false)) + continue + } + + if !stopped.allowed { + status="stopped" + info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: false)) + continue + } + + let deprecated=tenantRef.allowedAction(listingType: listingType, nftType: item.getItemType(), ftType: item.getFtType(), action: FindMarket.MarketAction(listing:true, name:"delist item for sale"), seller: address, buyer: nil) + + if !deprecated.allowed { + status="deprecated" + info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: getLeaseInfo)) + continue + } + + if let validTime = item.getValidUntil() { + if validTime <= Clock.time() { + status="ended" + } + } + info.append(FindLeaseMarket.SaleItemInformation(item: item, status: status, leaseInfo: getLeaseInfo)) + } + + return FindLeaseMarket.SaleItemCollectionReport(items: info, ghosts: ghost) + } + + /* Get Bid Collections */ + access(all) fun getMarketBidTypes() : [Type] { + return self.marketBidTypes + } + + access(all) fun getMarketBidCollectionTypes() : [Type] { + return self.marketBidCollectionTypes + } + + access(all) fun getMarketBidCollectionCapabilities(tenantRef: &{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindLeaseMarket.MarketBidCollectionPublic}>] { + var caps : [Capability<&{FindLeaseMarket.MarketBidCollectionPublic}>] = [] + for type in self.getMarketBidCollectionTypes() { + let cap = getAccount(address).capabilities.get<&{FindLeaseMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type)) + if cap.check() { + caps.append(cap) + } + } + return caps + } + + access(all) fun getMarketBidCollectionCapability(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindLeaseMarket.MarketBidCollectionPublic}>? { + for type in self.getMarketBidCollectionTypes() { + if FindMarket.getMarketOptionFromType(type) == marketOption{ + let cap = getAccount(address).capabilities.get<&{FindLeaseMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type)) + return cap + } + } + panic("Cannot find market option : ".concat(marketOption)) + } + + access(all) fun getBid(tenant: Address, address: Address, marketOption: String, name:String, getLeaseInfo: Bool) : FindLeaseMarket.BidInfo? { + let tenantRef=self.getTenant(tenant) + let bidInfo = self.checkBidInformation(tenantRef: tenantRef, marketOption: marketOption, address: address, name: name, getGhost: false, getLeaseInfo: getLeaseInfo) + if bidInfo.items.length > 0 { + return bidInfo.items[0] + } + return nil + } + + access(all) fun getBidsReport(tenant:Address, address: Address, getLeaseInfo: Bool) : {String : FindLeaseMarket.BidItemCollectionReport} { + let tenantRef = self.getTenant(tenant) + var report : {String : FindLeaseMarket.BidItemCollectionReport} = {} + for type in self.getMarketBidCollectionTypes() { + let marketOption = FindMarket.getMarketOptionFromType(type) + let returnedReport = self.checkBidInformation(tenantRef: tenantRef, marketOption: marketOption, address: address, name: nil, getGhost: true, getLeaseInfo: getLeaseInfo) + if returnedReport.items.length > 0 || returnedReport.ghosts.length > 0 { + report[marketOption] = returnedReport + } + } + return report + } + + access(contract) fun checkBidInformation(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address, name: String?, getGhost:Bool, getLeaseInfo: Bool) : FindLeaseMarket.BidItemCollectionReport { + let ghost: [FindLeaseMarket.GhostListing] =[] + let info: [FindLeaseMarket.BidInfo] =[] + let collectionCap = self.getMarketBidCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) + + let optRef = collectionCap?.borrow() + if optRef==nil { + return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost) + } + + let ref=optRef!! + + let listingType = ref.getBidType() + var listName : [String]= [] + if let leaseName = name{ + if !ref.containsNameBid(leaseName) { + return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost) + } + listName=[leaseName] + } else { + listName = ref.getNameBids() + } + + for leaseName in listName { + + let bid=ref.borrowBidItem(leaseName) + let item=self.getSaleInformation(tenant: tenantRef.owner!.address, name: leaseName, marketOption: marketOption, getLeaseInfo: getLeaseInfo) + if item == nil { + if getGhost { + ghost.append(FindLeaseMarket.GhostListing(listingType: listingType, name:leaseName)) + } + continue + } + let bidInfo = FindLeaseMarket.BidInfo(name: leaseName, bidTypeIdentifier: listingType.identifier, bidAmount: bid.getBalance(), timestamp: Clock.time(), item:item!) + info.append(bidInfo) + + } + return FindLeaseMarket.BidItemCollectionReport(items: info, ghosts: ghost) + } + + access(all) fun assertBidOperationValid(tenant: Address, address: Address, marketOption: String, name:String) : &{SaleItem} { + let tenantRef=self.getTenant(tenant) + let collectionCap = self.getMarketBidCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) + let optRef = collectionCap?.borrow() + if optRef == nil { + panic("Account not properly set up, cannot borrow bid item collection") + } + let ref=optRef!! + let bidItem=ref.borrowBidItem(name) + + let saleItemCollectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: bidItem.getSellerAddress()) + let saleRef = saleItemCollectionCap?.borrow() + if saleRef == nil { + panic("Seller account is not properly set up, cannot borrow sale item collection") + } + let sale=saleRef!! + let item=sale.borrowSaleItem(name) + if !item.checkPointer() { + panic("this is a ghost listing") + } + + return item + } + + /////// Pointer Section + + access(all) struct interface LeasePointer { + access(all) let name: String + access(all) let uuid: UInt64 + access(all) fun valid() : Bool + access(all) fun getUUID() :UInt64 + access(all) fun getLease() : FIND.LeaseInformation + access(all) fun owner() : Address + access(contract) fun borrow() : &FIND.LeaseCollection + } + + access(all) struct ReadLeasePointer : LeasePointer { + access(self) let cap: Capability<&FIND.LeaseCollection> + access(all) let name: String + access(all) let uuid: UInt64 + + // Passing in the reference here to ensure that is the owner + init(name: String) { + let address = FIND.lookupAddress(name) ?? panic("This lease name is not owned") + self.cap=getAccount(address).capabilities.get<&FIND.LeaseCollection>(FIND.LeasePublicPath) + self.name=name + + if !self.cap.check() { + panic("The capability is not valid.") + } + + self.uuid = self.cap.borrow()!.getLeaseUUID(name) + } + + access(contract) fun borrow() : &FIND.LeaseCollection { + return self.cap.borrow() ?? panic("The capability of pointer is not linked.") + } + + access(all) fun getLease() : FIND.LeaseInformation { + return self.borrow().getLease(self.name) ?? panic("The owner doesn't hold the lease anymore".concat(self.name)) + } + + access(all) fun getUUID() :UInt64{ + return self.uuid + } + + access(all) fun owner() : Address { + return self.cap.address + } + + access(all) fun valid() : Bool { + if !self.cap.check() || !self.cap.borrow()!.getNames().contains(self.name) { + return false + } + + if Clock.time() > FindLeaseMarket.getNetwork().getLeaseExpireTime(self.name) { + return false + } + return true + } + } + + access(all) struct AuthLeasePointer : LeasePointer { + access(self) let cap: Capability + access(all) let name: String + access(all) let uuid: UInt64 + + // Passing in the reference here to ensure that is the owner + init(cap:Capability, name: String) { + self.cap=cap + self.name=name + + if !self.cap.borrow()!.getNames().contains(name) { + panic("Please pass in the corresponding lease collection reference.") + } + + if !self.cap.check() { + panic("The capability is not valid.") + } + + self.uuid = self.cap.borrow()!.getLeaseUUID(name) + } + + access(contract) fun borrow() : auth(FIND.LeaseOwner) &FIND.LeaseCollection { + return self.cap.borrow() ?? panic("The capability of pointer is not linked.") + } + + access(all) fun getLease() : FIND.LeaseInformation { + return self.borrow().getLease(self.name) ?? panic("The owner doesn't hold the lease anymore".concat(self.name)) + } + + access(all) fun getUUID() :UInt64{ + return self.uuid + } + + access(all) fun valid() : Bool { + if !self.cap.check() || !self.cap.borrow()!.getNames().contains(self.name) { + return false + } + + if Clock.time() > FindLeaseMarket.getNetwork().getLeaseExpireTime(self.name) { + return false + } + return true + } + + access(account) fun move(to: Address) { + if !self.valid() { + panic("The lease capability is not valid") + } + let receiver = getAccount(to) + let profile = receiver.capabilities.get<&{Profile.Public}>(Profile.publicPath) + let leases = receiver.capabilities.get<&FIND.LeaseCollection>(FIND.LeasePublicPath) + self.borrow().move(name: self.name, profile: profile, to: leases) + } + + access(all) fun owner() : Address { + return self.cap.address + } + + } + + access(account) fun pay(tenant: String, leaseName: String, saleItem: &{SaleItem}, vault: @{FungibleToken.Vault}, leaseInfo: LeaseInfo, cuts:{String : FindMarketCutStruct.Cuts}) { + let buyer=saleItem.getBuyer() + let seller=saleItem.getSeller() + let soldFor=vault.balance + let ftType=vault.getType() + let ftInfo = FTRegistry.getFTInfoByTypeIdentifier(ftType.identifier)! // If this panic, there is sth wrong in FT set up + let oldProfileCap= getAccount(seller).capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let oldProfile = FindMarket.getPaymentWallet(oldProfileCap, ftInfo, panicOnFailCheck: true) + + for key in cuts.keys { + let allCuts = cuts[key]! + for cut in allCuts.cuts { + if var cutAmount= cut.getAmountPayable(soldFor) { + let findName = FIND.reverseLookup(cut.getAddress()) + emit RoyaltyPaid(tenant: tenant, leaseName: leaseName, saleID: saleItem.uuid, address:cut.getAddress(), findName: findName , royaltyName: cut.getName(), amount: cutAmount, vaultType: ftType.identifier, leaseInfo:leaseInfo) + let vaultRef = cut.getReceiverCap().borrow() ?? panic("Royalty receiving account is not set up properly. Royalty account address : ".concat(cut.getAddress().toString()).concat(" Royalty Name : ").concat(cut.getName())) + vaultRef.deposit(from: <- vault.withdraw(amount: cutAmount)) + } + } + } + + + oldProfile.deposit(from: <- vault) + } + + //struct to expose information about leases + access(all) struct LeaseInfo { + access(all) let name: String + access(all) let address: Address + access(all) let cost: UFix64 + access(all) let status: String + access(all) let validUntil: UFix64 + access(all) let lockedUntil: UFix64 + access(all) let addons: [String] + + init(_ pointer: {FindLeaseMarket.LeasePointer}){ + let network = FindLeaseMarket.getNetwork() + let name = pointer.name + let status= network.readStatus(name) + self.name=name + var s="TAKEN" + if status.status == FIND.LeaseStatus.FREE { + s="FREE" + } else if status.status == FIND.LeaseStatus.LOCKED { + s="LOCKED" + } + self.status=s + self.validUntil=network.getLeaseExpireTime(name) + self.lockedUntil=network.getLeaseLockedUntil(name) + self.address=status.owner! + self.cost=network.calculateCost(name) + if pointer.valid() { + let lease = pointer.borrow() + self.addons=lease.getAddon(name: name) + } else { + self.addons=[] + } + } + + } + + access(all) resource interface SaleItem { + //this is the type of sale this is, active, cancelled etc + access(all) fun getSaleType(): String + access(all) fun getSeller(): Address + access(all) fun getBuyer(): Address? + + access(all) fun getSellerName() : String? + access(all) fun getBuyerName() : String? + + access(all) fun toLeaseInfo() : FindLeaseMarket.LeaseInfo + access(all) fun checkPointer() : Bool + access(all) fun getListingType() : Type + access(all) fun getListingTypeIdentifier(): String + + //the Type of the item for sale + access(all) fun getItemType(): Type + //The id of the nft for sale + access(all) fun getLeaseName() : String + + access(all) fun getBalance(): UFix64 + access(all) fun getAuction(): AuctionItem? + access(all) fun getFtType() : Type //The type of FT used for this sale item + access(all) fun getValidUntil() : UFix64? //A timestamp that says when this item is valid until + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} + access(all) fun getId() : UInt64 + } + + access(all) resource interface Bid { + access(all) fun getBalance() : UFix64 + access(all) fun getSellerAddress() : Address + access(all) fun getBidExtraField() : {String : AnyStruct} + } + + access(all) struct SaleItemInformation { + access(all) let leaseIdentifier: String + access(all) let leaseName: String + access(all) let seller: Address + access(all) let sellerName: String? + access(all) let amount: UFix64? + access(all) let bidder: Address? + access(all) var bidderName: String? + access(all) let listingId: UInt64 + + access(all) let saleType: String + access(all) let listingTypeIdentifier: String + access(all) let ftAlias: String + access(all) let ftTypeIdentifier: String + access(all) let listingValidUntil: UFix64? + + access(all) var lease: LeaseInfo? + access(all) let auction: AuctionItem? + access(all) let listingStatus:String + access(all) let saleItemExtraField: {String : AnyStruct} + + init(item: &{SaleItem}, status:String, leaseInfo: Bool) { + self.leaseIdentifier= item.getItemType().identifier + self.leaseName=item.getLeaseName() + self.listingStatus=status + self.saleType=item.getSaleType() + self.listingTypeIdentifier=item.getListingTypeIdentifier() + self.listingId=item.getId() + self.amount=item.getBalance() + self.bidder=item.getBuyer() + self.bidderName=item.getBuyerName() + self.seller=item.getSeller() + self.sellerName=item.getSellerName() + self.listingValidUntil=item.getValidUntil() + self.lease=nil + if leaseInfo { + if status != "stopped" { + self.lease=item.toLeaseInfo() + } + } + let ftIdentifier=item.getFtType().identifier + self.ftTypeIdentifier=ftIdentifier + let ftInfo=FTRegistry.getFTInfoByTypeIdentifier(ftIdentifier) + self.ftAlias=ftInfo?.alias ?? "" + + self.auction=item.getAuction() + self.saleItemExtraField=item.getSaleItemExtraField() + } + } + + access(all) struct BidInfo{ + access(all) let name: String + access(all) let bidAmount: UFix64 + access(all) let bidTypeIdentifier: String + access(all) let timestamp: UFix64 + access(all) let item: SaleItemInformation + + init(name: String, bidTypeIdentifier: String, bidAmount: UFix64, timestamp: UFix64, item:SaleItemInformation) { + self.name=name + self.bidAmount=bidAmount + self.bidTypeIdentifier=bidTypeIdentifier + self.timestamp=timestamp + self.item=item + } + } + + access(all) struct AuctionItem { + //end time + //current time + access(all) let startPrice: UFix64 + access(all) let currentPrice: UFix64 + access(all) let minimumBidIncrement: UFix64 + access(all) let reservePrice: UFix64 + access(all) let extentionOnLateBid: UFix64 + access(all) let auctionEndsAt: UFix64? + access(all) let timestamp: UFix64 + + init(startPrice: UFix64, currentPrice: UFix64, minimumBidIncrement: UFix64, reservePrice: UFix64, extentionOnLateBid: UFix64, auctionEndsAt: UFix64? , timestamp: UFix64){ + self.startPrice = startPrice + self.currentPrice = currentPrice + self.minimumBidIncrement = minimumBidIncrement + self.reservePrice = reservePrice + self.extentionOnLateBid = extentionOnLateBid + self.auctionEndsAt = auctionEndsAt + self.timestamp = timestamp + } + } + + access(all) resource interface SaleItemCollectionPublic { + access(all) fun getNameSales(): [String] + access(all) fun containsNameSale(_ name: String): Bool + //TODO: verify this? + access(all) fun borrowSaleItem(_ name: String) : &{SaleItem} + access(all) fun getListingType() : Type + } + + access(all) resource interface MarketBidCollectionPublic { + access(all) fun getNameBids() : [String] + access(all) fun containsNameBid(_ name: String): Bool + access(all) fun getBidType() : Type + access(all) fun borrowBidItem(_ name: String) : &{Bid} + } + + access(all) struct GhostListing{ + // access(all) let listingType: Type + access(all) let listingTypeIdentifier: String + access(all) let name: String + + + init(listingType:Type, name:String) { + // self.listingType=listingType + self.listingTypeIdentifier=listingType.identifier + self.name=name + } + } + + access(all) struct SaleItemCollectionReport { + access(all) let items : [FindLeaseMarket.SaleItemInformation] + access(all) let ghosts: [FindLeaseMarket.GhostListing] + + init(items: [SaleItemInformation], ghosts: [GhostListing]) { + self.items=items + self.ghosts=ghosts + } + } + + access(all) struct BidItemCollectionReport { + access(all) let items : [FindLeaseMarket.BidInfo] + access(all) let ghosts: [FindLeaseMarket.GhostListing] + + init(items: [BidInfo], ghosts: [GhostListing]) { + self.items=items + self.ghosts=ghosts + } + } + + access(contract) fun getNetwork() : &FIND.Network { + return FindLeaseMarket.account.storage.borrow<&FIND.Network>(from : FIND.NetworkStoragePath) ?? panic("Network is not up") + } + + /* Admin Function */ + access(account) fun addSaleItemType(_ type: Type) { + self.saleItemTypes.append(type) + FindMarket.addPathMap(type) + FindMarket.addListingName(type) + } + + access(account) fun addMarketBidType(_ type: Type) { + self.marketBidTypes.append(type) + FindMarket.addPathMap(type) + FindMarket.addListingName(type) + } + + access(account) fun addSaleItemCollectionType(_ type: Type) { + self.saleItemCollectionTypes.append(type) + FindMarket.addPathMap(type) + FindMarket.addListingName(type) + } + + access(account) fun addMarketBidCollectionType(_ type: Type) { + self.marketBidCollectionTypes.append(type) + FindMarket.addPathMap(type) + FindMarket.addListingName(type) + } + + access(account) fun removeSaleItemType(_ type: Type) { + var counter = 0 + while counter < self.saleItemTypes.length { + if type == self.saleItemTypes[counter] { + self.saleItemTypes.remove(at: counter) + } + counter = counter + 1 + } + } + + access(account) fun removeMarketBidType(_ type: Type) { + var counter = 0 + while counter < self.marketBidTypes.length { + if type == self.marketBidTypes[counter] { + self.marketBidTypes.remove(at: counter) + } + counter = counter + 1 + } + } + + access(account) fun removeSaleItemCollectionType(_ type: Type) { + var counter = 0 + while counter < self.saleItemCollectionTypes.length { + if type == self.saleItemCollectionTypes[counter] { + self.saleItemCollectionTypes.remove(at: counter) + } + counter = counter + 1 + } + } + + access(account) fun removeMarketBidCollectionType(_ type: Type) { + var counter = 0 + while counter < self.marketBidCollectionTypes.length { + if type == self.marketBidCollectionTypes[counter] { + self.marketBidCollectionTypes.remove(at: counter) + } + counter = counter + 1 + } + } + + init() { + self.saleItemTypes = [] + self.saleItemCollectionTypes = [] + self.marketBidTypes = [] + self.marketBidCollectionTypes = [] + } } diff --git a/contracts/FindLeaseMarketAuctionSoft.cdc b/contracts/FindLeaseMarketAuctionSoft.cdc index da8a4fe6..f6828011 100644 --- a/contracts/FindLeaseMarketAuctionSoft.cdc +++ b/contracts/FindLeaseMarketAuctionSoft.cdc @@ -1,727 +1,732 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import Clock from "./Clock.cdc" -import FIND from "./FIND.cdc" -import FindMarket from "./FindMarket.cdc" -import FindLeaseMarket from "./FindLeaseMarket.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "Clock" +import "FIND" +import "FindMarket" +import "FindLeaseMarket" // An auction saleItem contract that escrows the FT, does _not_ escrow the NFT -pub contract FindLeaseMarketAuctionSoft { - - pub event EnglishAuction(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName:String?, amount: UFix64, auctionReservePrice: UFix64, status: String, vaultType:String, leaseInfo:FindLeaseMarket.LeaseInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) - - pub resource SaleItem : FindLeaseMarket.SaleItem { - access(contract) var pointer: FindLeaseMarket.AuthLeasePointer - access(contract) var vaultType: Type - access(contract) var auctionStartPrice: UFix64 - access(contract) var auctionReservePrice: UFix64 - access(contract) var auctionDuration: UFix64 - access(contract) var auctionMinBidIncrement: UFix64 - access(contract) var auctionExtensionOnLateBid: UFix64 - access(contract) var auctionStartedAt: UFix64? - access(contract) var auctionValidUntil: UFix64? - access(contract) var auctionEndsAt: UFix64? - access(contract) var offerCallback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>? - access(contract) var saleItemExtraField: {String : AnyStruct} - - init(pointer: FindLeaseMarket.AuthLeasePointer, vaultType: Type, auctionStartPrice:UFix64, auctionReservePrice:UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - self.vaultType=vaultType - self.pointer=pointer - self.auctionStartPrice=auctionStartPrice - self.auctionReservePrice=auctionReservePrice - self.auctionDuration=86400.0 - self.auctionExtensionOnLateBid=300.0 - self.auctionMinBidIncrement=10.0 - self.offerCallback=nil - self.auctionStartedAt=nil - self.auctionValidUntil=auctionValidUntil - self.auctionEndsAt=nil - self.saleItemExtraField=saleItemExtraField - } - - //Here we do not get a vault back, it is sent in to the method itself - pub fun acceptNonEscrowedBid() { - pre{ - self.offerCallback != nil : "There is no bid offer to the item." - self.offerCallback!.check() : "Bidder unlinked bid collection capability." - } - self.offerCallback!.borrow()!.accept(self.getLeaseName()) - self.pointer.move(to: self.offerCallback!.address) - } - - pub fun getBalance() : UFix64 { - if let cb= self.offerCallback { - return cb.borrow()?.getBalance(self.getLeaseName()) ?? panic("Bidder unlinked bid collection capability. bidder address : ".concat(cb.address.toString())) - } - return self.auctionStartPrice - } - - pub fun getSeller() : Address { - return self.pointer.owner() - } - - pub fun getSellerName() : String? { - let address = self.pointer.owner() - return FIND.reverseLookup(address) - } - - pub fun getBuyer() : Address? { - if let cb= self.offerCallback { - return cb.address - } - return nil - } - - pub fun getId() : UInt64{ - return self.pointer.getUUID() - } - - pub fun getBuyerName() : String? { - if let cb= self.offerCallback { - return FIND.reverseLookup(cb.address) - } - return nil - } - - pub fun toLeaseInfo() : FindLeaseMarket.LeaseInfo { - return FindLeaseMarket.LeaseInfo(self.pointer) - } - - pub fun setAuctionStarted(_ startedAt: UFix64) { - self.auctionStartedAt=startedAt - } - - pub fun setAuctionEnds(_ endsAt: UFix64){ - self.auctionEndsAt=endsAt - } - - pub fun hasAuctionStarted() : Bool { - if let starts = self.auctionStartedAt { - return starts <= Clock.time() - } - return false - } - - pub fun hasAuctionEnded() : Bool { - if let ends = self.auctionEndsAt { - return ends < Clock.time() - } - panic("Not a live auction") - } - - pub fun hasAuctionMetReservePrice() : Bool { - - let balance=self.getBalance() - - if self.auctionReservePrice== nil { - return false - } - - return balance >= self.auctionReservePrice - } - - pub fun setExtentionOnLateBid(_ time: UFix64) { - self.auctionExtensionOnLateBid=time - } - - pub fun setAuctionDuration(_ duration: UFix64) { - self.auctionDuration=duration - } - - pub fun setReservePrice(_ price: UFix64) { - self.auctionReservePrice=price - } - - pub fun setMinBidIncrement(_ price: UFix64) { - self.auctionMinBidIncrement=price - } - - pub fun setStartAuctionPrice(_ price: UFix64) { - self.auctionStartPrice=price - } - - pub fun setCallback(_ callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>?) { - self.offerCallback=callback - } - - pub fun getSaleType(): String { - if self.auctionStartedAt != nil { - if self.hasAuctionEnded() { - if self.hasAuctionMetReservePrice() { - return "finished_completed" - } - return "finished_failed" - } - return "active_ongoing" - } - return "active_listed" - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun getListingTypeIdentifier() : String { - return Type<@SaleItem>().identifier - } - - pub fun getLeaseName() : String { - return self.pointer.name - } - - pub fun getItemType() : Type { - return Type<@FIND.Lease>() - } - - pub fun getAuction(): FindLeaseMarket.AuctionItem? { - return FindLeaseMarket.AuctionItem(startPrice: self.auctionStartPrice, - currentPrice: self.getBalance(), - minimumBidIncrement: self.auctionMinBidIncrement , - reservePrice: self.auctionReservePrice, - extentionOnLateBid: self.auctionExtensionOnLateBid , - auctionEndsAt: self.auctionEndsAt , - timestamp: Clock.time()) - } - - pub fun getFtType() : Type { - return self.vaultType - } - - pub fun setValidUntil(_ time: UFix64?) { - self.auctionValidUntil=time - } - - pub fun getValidUntil() : UFix64? { - if self.hasAuctionStarted() { - return self.auctionEndsAt - } - return self.auctionValidUntil - } - - pub fun checkPointer() : Bool { - return self.pointer.valid() - } - - pub fun getSaleItemExtraField() : {String : AnyStruct} { - return self.saleItemExtraField - } - - } - - pub resource interface SaleItemCollectionPublic { - //fetch all the tokens in the collection - pub fun getNameSales(): [String] - pub fun containsNameSale(_ name: String): Bool - access(contract) fun registerIncreasedBid(_ name: String, oldBalance: UFix64) - - //place a bid on a token - access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, vaultType:Type) - - //only buyer can fulfill auctions since he needs to send funds for this type - access(contract) fun fulfillAuction(name: String, vault: @FungibleToken.Vault) - } - - pub resource SaleItemCollection: SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic { - //is this the best approach now or just put the NFT inside the saleItem? - access(contract) var items: @{String: SaleItem} - - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - init (_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.items <- {} - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - pre{ - self.tenantCapability.check() : "Tenant client is not linked anymore" - } - return self.tenantCapability.borrow()! - } - - access(self) fun emitEvent(saleItem: &SaleItem, status: String,previousBuyer:Address?) { - let owner=saleItem.getSeller() - let ftType=saleItem.getFtType() - let balance=saleItem.getBalance() - let seller=saleItem.getSeller() - let name=saleItem.getLeaseName() - let buyer=saleItem.getBuyer() - - var leaseInfo:FindLeaseMarket.LeaseInfo?=nil - if saleItem.checkPointer() { - leaseInfo=saleItem.toLeaseInfo() - } - - var previousBuyerName : String?=nil - if let pb= previousBuyer { - previousBuyerName = FIND.reverseLookup(pb) - } +access(all) contract FindLeaseMarketAuctionSoft { + + // A seller can list,delist and relist leases for auction + access(all) entitlement Seller + + access(all) event EnglishAuction(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName:String?, amount: UFix64, auctionReservePrice: UFix64, status: String, vaultType:String, leaseInfo:FindLeaseMarket.LeaseInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) + + access(all) resource SaleItem : FindLeaseMarket.SaleItem { + access(contract) var pointer: FindLeaseMarket.AuthLeasePointer + access(contract) var vaultType: Type + access(contract) var auctionStartPrice: UFix64 + access(contract) var auctionReservePrice: UFix64 + access(contract) var auctionDuration: UFix64 + access(contract) var auctionMinBidIncrement: UFix64 + access(contract) var auctionExtensionOnLateBid: UFix64 + access(contract) var auctionStartedAt: UFix64? + access(contract) var auctionValidUntil: UFix64? + access(contract) var auctionEndsAt: UFix64? + access(contract) var offerCallback: Capability<&MarketBidCollection>? + access(contract) var saleItemExtraField: {String : AnyStruct} + + init(pointer: FindLeaseMarket.AuthLeasePointer, vaultType: Type, auctionStartPrice:UFix64, auctionReservePrice:UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + self.vaultType=vaultType + self.pointer=pointer + self.auctionStartPrice=auctionStartPrice + self.auctionReservePrice=auctionReservePrice + self.auctionDuration=86400.0 + self.auctionExtensionOnLateBid=300.0 + self.auctionMinBidIncrement=10.0 + self.offerCallback=nil + self.auctionStartedAt=nil + self.auctionValidUntil=auctionValidUntil + self.auctionEndsAt=nil + self.saleItemExtraField=saleItemExtraField + } + + //Here we do not get a vault back, it is sent in to the method itself + access(contract) fun acceptNonEscrowedBid() { + pre{ + self.offerCallback != nil : "There is no bid offer to the item." + self.offerCallback!.check() : "Bidder unlinked bid collection capability." + } + self.offerCallback!.borrow()!.accept(self.getLeaseName()) + self.pointer.move(to: self.offerCallback!.address) + } + + access(all) fun getBalance() : UFix64 { + if let cb= self.offerCallback { + return cb.borrow()?.getBalance(self.getLeaseName()) ?? panic("Bidder unlinked bid collection capability. bidder address : ".concat(cb.address.toString())) + } + return self.auctionStartPrice + } + + access(all) fun getSeller() : Address { + return self.pointer.owner() + } + + access(all) fun getSellerName() : String? { + let address = self.pointer.owner() + return FIND.reverseLookup(address) + } + + access(all) fun getBuyer() : Address? { + if let cb= self.offerCallback { + return cb.address + } + return nil + } + + access(all) fun getId() : UInt64{ + return self.pointer.getUUID() + } + + access(all) fun getBuyerName() : String? { + if let cb= self.offerCallback { + return FIND.reverseLookup(cb.address) + } + return nil + } + + access(all) fun toLeaseInfo() : FindLeaseMarket.LeaseInfo { + return FindLeaseMarket.LeaseInfo(self.pointer) + } + + access(contract) fun setAuctionStarted(_ startedAt: UFix64) { + self.auctionStartedAt=startedAt + } + + access(contract) fun setAuctionEnds(_ endsAt: UFix64){ + self.auctionEndsAt=endsAt + } + + access(all) fun hasAuctionStarted() : Bool { + if let starts = self.auctionStartedAt { + return starts <= Clock.time() + } + return false + } + + access(all) fun hasAuctionEnded() : Bool { + if let ends = self.auctionEndsAt { + return ends < Clock.time() + } + panic("Not a live auction") + } + + access(all) fun hasAuctionMetReservePrice() : Bool { + + let balance=self.getBalance() + + if self.auctionReservePrice== nil { + return false + } + + return balance >= self.auctionReservePrice + } + + access(contract) fun setExtentionOnLateBid(_ time: UFix64) { + self.auctionExtensionOnLateBid=time + } + + access(contract) fun setAuctionDuration(_ duration: UFix64) { + self.auctionDuration=duration + } + + access(contract) fun setReservePrice(_ price: UFix64) { + self.auctionReservePrice=price + } + + access(contract) fun setMinBidIncrement(_ price: UFix64) { + self.auctionMinBidIncrement=price + } + + access(contract) fun setStartAuctionPrice(_ price: UFix64) { + self.auctionStartPrice=price + } + + access(contract) fun setCallback(_ callback: Capability<&MarketBidCollection>?) { + self.offerCallback=callback + } + + access(all) fun getSaleType(): String { + if self.auctionStartedAt != nil { + if self.hasAuctionEnded() { + if self.hasAuctionMetReservePrice() { + return "finished_completed" + } + return "finished_failed" + } + return "active_ongoing" + } + return "active_listed" + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun getListingTypeIdentifier() : String { + return Type<@SaleItem>().identifier + } + + access(all) fun getLeaseName() : String { + return self.pointer.name + } + + access(all) fun getItemType() : Type { + return Type<@FIND.Lease>() + } + + access(all) fun getAuction(): FindLeaseMarket.AuctionItem? { + return FindLeaseMarket.AuctionItem(startPrice: self.auctionStartPrice, + currentPrice: self.getBalance(), + minimumBidIncrement: self.auctionMinBidIncrement , + reservePrice: self.auctionReservePrice, + extentionOnLateBid: self.auctionExtensionOnLateBid , + auctionEndsAt: self.auctionEndsAt , + timestamp: Clock.time()) + } + + access(all) fun getFtType() : Type { + return self.vaultType + } + + access(contract) fun setValidUntil(_ time: UFix64?) { + self.auctionValidUntil=time + } + + access(all) fun getValidUntil() : UFix64? { + if self.hasAuctionStarted() { + return self.auctionEndsAt + } + return self.auctionValidUntil + } + + access(all) fun checkPointer() : Bool { + return self.pointer.valid() + } + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} { + return self.saleItemExtraField + } + } + + access(all) resource interface SaleItemCollectionPublic { + //fetch all the tokens in the collection + access(all) fun getNameSales(): [String] + access(all) fun containsNameSale(_ name: String): Bool + access(contract) fun registerIncreasedBid(_ name: String, oldBalance: UFix64) + + //place a bid on a token + access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection>, vaultType:Type) + + //only buyer can fulfill auctions since he needs to send funds for this type + access(contract) fun fulfillAuction(name: String, vault: @{FungibleToken.Vault}) + } + + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic { + //is this the best approach now or just put the NFT inside the saleItem? + access(contract) var items: @{String: SaleItem} + + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + init (_ tenantCapability: Capability<&FindMarket.Tenant>) { + self.items <- {} + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + pre{ + self.tenantCapability.check() : "Tenant client is not linked anymore" + } + return self.tenantCapability.borrow()! + } + + access(self) fun emitEvent(saleItem: &SaleItem, status: String,previousBuyer:Address?) { + let owner=saleItem.getSeller() + let ftType=saleItem.getFtType() + let balance=saleItem.getBalance() + let seller=saleItem.getSeller() + let name=saleItem.getLeaseName() + let buyer=saleItem.getBuyer() + + var leaseInfo:FindLeaseMarket.LeaseInfo?=nil + if saleItem.checkPointer() { + leaseInfo=saleItem.toLeaseInfo() + } + + var previousBuyerName : String?=nil + if let pb= previousBuyer { + previousBuyerName = FIND.reverseLookup(pb) + } + + if buyer != nil { + let buyerName=FIND.reverseLookup(buyer!) + let profile = FIND.lookup(buyer!.toString()) + emit EnglishAuction(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, leaseInfo: leaseInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile?.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) + } else { + emit EnglishAuction(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, leaseInfo: leaseInfo, buyer: nil, buyerName: nil, buyerAvatar: nil, endsAt: saleItem.auctionEndsAt, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) + } + } - if buyer != nil { - let buyerName=FIND.reverseLookup(buyer!) - let profile = FIND.lookup(buyer!.toString()) - emit EnglishAuction(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, leaseInfo: leaseInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile?.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - } else { - emit EnglishAuction(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, leaseInfo: leaseInfo, buyer: nil, buyerName: nil, buyerAvatar: nil, endsAt: saleItem.auctionEndsAt, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - } - } + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } - pub fun getListingType() : Type { - return Type<@SaleItem>() - } + access(self) fun addBid(name:String, newOffer: Capability<&MarketBidCollection>, oldBalance: UFix64) { + let saleItem=self.borrowAuth(name) + + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"add bit in soft-auction"), seller: self.owner!.address ,buyer: newOffer.address) + + if !actionResult.allowed { + panic(actionResult.message) + } - access(self) fun addBid(name:String, newOffer: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, oldBalance: UFix64) { - let saleItem=self.borrow(name) + let timestamp=Clock.time() + let newOfferBalance=newOffer.borrow()?.getBalance(name) ?? panic("The new offer bid capability is invalid.") - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"add bit in soft-auction"), seller: self.owner!.address ,buyer: newOffer.address) - - if !actionResult.allowed { - panic(actionResult.message) - } + let previousOffer = saleItem.offerCallback! - let timestamp=Clock.time() - let newOfferBalance=newOffer.borrow()?.getBalance(name) ?? panic("The new offer bid capability is invalid.") - let previousOffer = saleItem.offerCallback! + var minBid=oldBalance + saleItem.auctionMinBidIncrement + if newOffer.address != previousOffer.address { + let previousBalance = previousOffer.borrow()?.getBalance(name) ?? panic("Previous bidder unlinked the bid ccollection capability. bidder address : ".concat(previousOffer.address.toString())) + minBid = previousBalance + saleItem.auctionMinBidIncrement + } + if newOfferBalance < minBid { + panic("bid ".concat(newOfferBalance.toString()).concat(" must be larger then previous bid+bidIncrement ").concat(minBid.toString())) + } - var minBid=oldBalance + saleItem.auctionMinBidIncrement - if newOffer.address != previousOffer.address { - let previousBalance = previousOffer.borrow()?.getBalance(name) ?? panic("Previous bidder unlinked the bid ccollection capability. bidder address : ".concat(previousOffer.address.toString())) - minBid = previousBalance + saleItem.auctionMinBidIncrement - } + var previousBuyer:Address?=nil + if newOffer.address != previousOffer.address { + previousOffer.borrow()!.cancelBidFromSaleItem(name) + previousBuyer=previousOffer.address + } - if newOfferBalance < minBid { - panic("bid ".concat(newOfferBalance.toString()).concat(" must be larger then previous bid+bidIncrement ").concat(minBid.toString())) - } + saleItem.setCallback(newOffer) - var previousBuyer:Address?=nil - if newOffer.address != previousOffer.address { - previousOffer.borrow()!.cancelBidFromSaleItem(name) - previousBuyer=previousOffer.address - } + let suggestedEndTime=timestamp+saleItem.auctionExtensionOnLateBid - saleItem.setCallback(newOffer) + if suggestedEndTime > saleItem.auctionEndsAt! { + saleItem.setAuctionEnds(suggestedEndTime) + } + self.emitEvent(saleItem: saleItem, status: "active_ongoing", previousBuyer:previousBuyer) - let suggestedEndTime=timestamp+saleItem.auctionExtensionOnLateBid + } - if suggestedEndTime > saleItem.auctionEndsAt! { - saleItem.setAuctionEnds(suggestedEndTime) - } - self.emitEvent(saleItem: saleItem, status: "active_ongoing", previousBuyer:previousBuyer) + access(contract) fun registerIncreasedBid(_ name: String, oldBalance:UFix64) { + pre { + self.items.containsKey(name) : "Invalid lease name=".concat(name) + } - } + let saleItem=self.borrow(name) - access(contract) fun registerIncreasedBid(_ name: String, oldBalance:UFix64) { - pre { - self.items.containsKey(name) : "Invalid lease name=".concat(name) - } + if !saleItem.hasAuctionStarted() { + panic("Auction is not started") + } - let saleItem=self.borrow(name) + if saleItem.hasAuctionEnded() { + panic("Auction has ended") + } - if !saleItem.hasAuctionStarted() { - panic("Auction is not started") - } + self.addBid(name: name, newOffer: saleItem.offerCallback!, oldBalance: oldBalance) - if saleItem.hasAuctionEnded() { - panic("Auction has ended") - } + } - self.addBid(name: name, newOffer: saleItem.offerCallback!, oldBalance: oldBalance) + //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller + access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection>, vaultType: Type) { - } + let timestamp=Clock.time() - //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller - access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, vaultType: Type) { + let name = name - let timestamp=Clock.time() + let saleItem=self.borrowAuth(name) + if saleItem.hasAuctionStarted() { + if saleItem.hasAuctionEnded() { + panic("Auction has ended") + } - let name = name + if let cb = saleItem.offerCallback { + if cb.address == callback.address { + panic("You already have the latest bid on this item, use the incraseBid transaction") + } + } - let saleItem=self.borrow(name) - if saleItem.hasAuctionStarted() { - if saleItem.hasAuctionEnded() { - panic("Auction has ended") - } + self.addBid(name: name, newOffer: callback, oldBalance: 0.0) + return + } - if let cb = saleItem.offerCallback { - if cb.address == callback.address { - panic("You already have the latest bid on this item, use the incraseBid transaction") - } - } + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"bid item in soft-auction"), seller: self.owner!.address, buyer: callback.address) - self.addBid(name: name, newOffer: callback, oldBalance: 0.0) - return - } + if !actionResult.allowed { + panic(actionResult.message) + } - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"bid item in soft-auction"), seller: self.owner!.address, buyer: callback.address) + let balance=callback.borrow()?.getBalance(name) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) - if !actionResult.allowed { - panic(actionResult.message) - } + if saleItem.auctionStartPrice > balance { + panic("You need to bid more then the starting price of ".concat(saleItem.auctionStartPrice.toString())) + } - let balance=callback.borrow()?.getBalance(name) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) + if let valid = saleItem.getValidUntil() { + assert( valid >= Clock.time(), message: "This auction listing is already expired") + } - if saleItem.auctionStartPrice > balance { - panic("You need to bid more then the starting price of ".concat(saleItem.auctionStartPrice.toString())) - } + saleItem.setCallback(callback) + let duration=saleItem.auctionDuration + let endsAt=timestamp + duration + saleItem.setAuctionStarted(timestamp) + saleItem.setAuctionEnds(endsAt) - if let valid = saleItem.getValidUntil() { - assert( valid >= Clock.time(), message: "This auction listing is already expired") - } + self.emitEvent(saleItem: saleItem, status: "active_ongoing", previousBuyer:nil) + } - saleItem.setCallback(callback) - let duration=saleItem.auctionDuration - let endsAt=timestamp + duration - saleItem.setAuctionStarted(timestamp) - saleItem.setAuctionEnds(endsAt) + access(Seller) fun cancel(_ name: String) { + pre { + self.items.containsKey(name) : "Invalid lease name=".concat(name) + } - self.emitEvent(saleItem: saleItem, status: "active_ongoing", previousBuyer:nil) - } + let saleItem=self.borrow(name) - pub fun cancel(_ name: String) { - pre { - self.items.containsKey(name) : "Invalid lease name=".concat(name) - } + var status="cancel" + if saleItem.checkPointer() { + if saleItem.hasAuctionStarted() && saleItem.hasAuctionEnded() { + if saleItem.hasAuctionMetReservePrice() { + panic("Cannot cancel finished auction, fulfill it instead") + } + status="cancel_reserved_not_met" - let saleItem=self.borrow(name) + } + } else { + status="cancel_ghostlisting" + } + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"delist item from soft-auction"), seller: nil, buyer: nil) - var status="cancel" - if saleItem.checkPointer() { - if saleItem.hasAuctionStarted() && saleItem.hasAuctionEnded() { - if saleItem.hasAuctionMetReservePrice() { - panic("Cannot cancel finished auction, fulfill it instead") - } - status="cancel_reserved_not_met" + if !actionResult.allowed { + panic(actionResult.message) + } - } - } else { - status="cancel_ghostlisting" - } - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"delist item from soft-auction"), seller: nil, buyer: nil) + self.emitEvent(saleItem: saleItem, status: status, previousBuyer:nil) - if !actionResult.allowed { - panic(actionResult.message) - } + if saleItem.offerCallback != nil && saleItem.offerCallback!.check() { + saleItem.offerCallback!.borrow()!.cancelBidFromSaleItem(name) + } - self.emitEvent(saleItem: saleItem, status: status, previousBuyer:nil) + destroy <- self.items.remove(key: name) + } - if saleItem.offerCallback != nil && saleItem.offerCallback!.check() { - saleItem.offerCallback!.borrow()!.cancelBidFromSaleItem(name) - } + access(contract) fun fulfillAuction(name: String, vault: @{FungibleToken.Vault}) { + pre { + self.items.containsKey(name) : "Invalid lease name=".concat(name) + } - destroy <- self.items.remove(key: name) - } + let saleItem = self.borrowAuth(name) + if !saleItem.hasAuctionStarted() { + panic("This auction is not live") + } - access(contract) fun fulfillAuction(name: String, vault: @FungibleToken.Vault) { - pre { - self.items.containsKey(name) : "Invalid lease name=".concat(name) - } + if !saleItem.hasAuctionEnded() { + panic("Auction has not ended yet") + } - let saleItem = self.borrow(name) + if vault.getType() != saleItem.vaultType { + panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.vaultType.identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier))) + } - if !saleItem.hasAuctionStarted() { - panic("This auction is not live") - } + if vault.balance < saleItem.auctionReservePrice { + panic("cannot fulfill auction reserve price was not met, cancel it without a vault ".concat(vault.balance.toString()).concat(" < ").concat(saleItem.auctionReservePrice.toString())) + } - if !saleItem.hasAuctionEnded() { - panic("Auction has not ended yet") - } + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"buy item for soft-auction"), seller: self.owner!.address,buyer: saleItem.offerCallback!.address) - if vault.getType() != saleItem.vaultType { - panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.vaultType.identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier))) - } + if !actionResult.allowed { + panic(actionResult.message) + } - if vault.balance < saleItem.auctionReservePrice { - panic("cannot fulfill auction reserve price was not met, cancel it without a vault ".concat(vault.balance.toString()).concat(" < ").concat(saleItem.auctionReservePrice.toString())) - } + let cuts= self.getTenant().getCuts(name: actionResult.name, listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType()) - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"buy item for soft-auction"), seller: self.owner!.address,buyer: saleItem.offerCallback!.address) - if !actionResult.allowed { - panic(actionResult.message) - } + let leaseInfo=saleItem.toLeaseInfo() - let cuts= self.getTenant().getCuts(name: actionResult.name, listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType()) + self.emitEvent(saleItem: saleItem, status: "sold", previousBuyer:nil) + saleItem.acceptNonEscrowedBid() + FindLeaseMarket.pay(tenant:self.getTenant().name, leaseName:name, saleItem: saleItem, vault: <- vault, leaseInfo:leaseInfo, cuts:cuts) - let leaseInfo=saleItem.toLeaseInfo() + destroy <- self.items.remove(key: name) - self.emitEvent(saleItem: saleItem, status: "sold", previousBuyer:nil) - saleItem.acceptNonEscrowedBid() + } - FindLeaseMarket.pay(tenant:self.getTenant().name, leaseName:name, saleItem: saleItem, vault: <- vault, leaseInfo:leaseInfo, cuts:cuts) + access(Seller) fun listForAuction(pointer: FindLeaseMarket.AuthLeasePointer, vaultType: Type, auctionStartPrice: UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - destroy <- self.items.remove(key: name) + // ensure it is not a 0 dollar listing + if auctionStartPrice <= 0.0 { + panic("Auction start price should be greater than 0") + } - } + // ensure it is not a 0 dollar listing + if auctionReservePrice < auctionStartPrice { + panic("Auction reserve price should be greater than Auction start price") + } - pub fun listForAuction(pointer: FindLeaseMarket.AuthLeasePointer, vaultType: Type, auctionStartPrice: UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + // ensure validUntil is valid + if auctionValidUntil != nil && auctionValidUntil! < Clock.time() { + panic("Valid until is before current time") + } - // ensure it is not a 0 dollar listing - if auctionStartPrice <= 0.0 { - panic("Auction start price should be greater than 0") - } + let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice:auctionReservePrice, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) - // ensure it is not a 0 dollar listing - if auctionReservePrice < auctionStartPrice { - panic("Auction reserve price should be greater than Auction start price") - } - - // ensure validUntil is valid - if auctionValidUntil != nil && auctionValidUntil! < Clock.time() { - panic("Valid until is before current time") - } - - let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice:auctionReservePrice, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) - - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"list item for soft-auction"), seller: self.owner!.address, buyer: nil) - - if !actionResult.allowed { - panic(actionResult.message) - } - - assert(self.items[pointer.name] == nil , message: "Auction listing for this item is already created.") - - saleItem.setAuctionDuration(auctionDuration) - saleItem.setExtentionOnLateBid(auctionExtensionOnLateBid) - saleItem.setMinBidIncrement(minimumBidIncrement) - self.items[pointer.name] <-! saleItem - let saleItemRef = self.borrow(pointer.name) - self.emitEvent(saleItem: saleItemRef, status: "active_listed", previousBuyer:nil) - } - - pub fun getNameSales(): [String] { - return self.items.keys - } - - pub fun containsNameSale(_ name: String): Bool { - return self.items.containsKey(name) - } - - pub fun borrow(_ name: String): &SaleItem { - pre{ - self.items.containsKey(name) : "This name sale does not exist.".concat(name) - } - return (&self.items[name] as &SaleItem?)! - } - - pub fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} { - pre{ - self.items.containsKey(name) : "This name sale does not exist.".concat(name) - } - return (&self.items[name] as &SaleItem{FindLeaseMarket.SaleItem}?)! - } - - destroy() { - destroy self.items - } - } - - pub resource Bid : FindLeaseMarket.Bid { - access(contract) let from: Capability<&SaleItemCollection{SaleItemCollectionPublic}> - access(contract) let leaseName: String - - access(contract) let vaultType: Type - access(contract) var bidAt: UFix64 - access(contract) var balance: UFix64 - access(contract) let bidExtraField: {String : AnyStruct} - - init(from: Capability<&SaleItemCollection{SaleItemCollectionPublic}>, leaseName: String, vaultType:Type, balance:UFix64, bidExtraField: {String : AnyStruct}){ - self.vaultType= vaultType - self.balance=balance - self.leaseName=leaseName - self.from=from - self.bidAt=Clock.time() - self.bidExtraField=bidExtraField - } - - access(contract) fun setBalance(_ balance:UFix64) { - self.balance=balance - } - - access(contract) fun setBidAt(_ time: UFix64) { - self.bidAt=time - } - - pub fun getBalance() : UFix64 { - return self.balance - } - - pub fun getSellerAddress() : Address { - return self.from.address - } - - pub fun getBidExtraField() : {String : AnyStruct} { - return self.bidExtraField - } - } - - pub resource interface MarketBidCollectionPublic { - pub fun getBalance(_ name: String) : UFix64 - pub fun containsNameBid(_ name: String): Bool - access(contract) fun accept(_ name: String) - access(contract) fun cancelBidFromSaleItem(_ name: String) - } - - //A collection stored for bidders/buyers - pub resource MarketBidCollection: MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic { - - access(contract) var bids : @{String: Bid} - access(contract) let receiver: Capability<&{FungibleToken.Receiver}> - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - //not sure we can store this here anymore. think it needs to be in every bid - init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.bids <- {} - self.receiver=receiver - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - pre{ - self.tenantCapability.check() : "Tenant client is not linked anymore" - } - return self.tenantCapability.borrow()! - } - - //called from lease when auction is ended - access(contract) fun accept(_ name: String) { - pre { - self.bids[name] != nil : "You need to have a bid here already" - } - - let bid <- self.bids.remove(key: name) ?? panic("missing bid") - destroy bid - } - - pub fun getNameBids() : [String] { - return self.bids.keys - } - - pub fun containsNameBid(_ name: String) : Bool { - return self.bids.containsKey(name) - } - - pub fun getBidType() : Type { - return Type<@Bid>() - } - - pub fun bid(name: String, amount:UFix64, vaultType:Type, bidExtraField: {String : AnyStruct}) { - pre { - self.owner!.address != FIND.status(name).owner! : "You cannot bid on your own resource" - self.bids[name] == nil : "You already have an bid for this item, use increaseBid on that bid" - } - - let from=getAccount(FIND.status(name).owner!).getCapability<&SaleItemCollection{SaleItemCollectionPublic}>(self.getTenant().getPublicPath(Type<@SaleItemCollection>())) - - let bid <- create Bid(from: from, leaseName:name, vaultType: vaultType, balance:amount, bidExtraField: bidExtraField) - let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for lease name=".concat(name)) - - let callbackCapability =self.owner!.getCapability<&MarketBidCollection{MarketBidCollectionPublic}>(self.getTenant().getPublicPath(Type<@MarketBidCollection>())) - let oldToken <- self.bids[name] <- bid - saleItemCollection.registerBid(name: name, callback: callbackCapability, vaultType: vaultType) - destroy oldToken - } - - pub fun fulfillAuction(name:String, vault: @FungibleToken.Vault) { - pre { - self.bids[name] != nil : "You need to have a bid here already" - } - let bid =self.borrowBid(name) - let saleItem=bid.from.borrow()! - saleItem.fulfillAuction(name:name, vault: <- vault) - } - - //increase a bid, will not work if the auction has already started - pub fun increaseBid(name: String, increaseBy: UFix64) { - pre { - self.bids[name] != nil : "You need to have a bid here already" - } - let bid =self.borrowBid(name) - - let oldBalance=bid.balance - - bid.setBidAt(Clock.time()) - bid.setBalance(bid.balance + increaseBy) - - if !bid.from.check(){ - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) - } - bid.from.borrow()!.registerIncreasedBid(name, oldBalance: oldBalance) - } - - //called from saleItem when things are cancelled - //if the bid is canceled from seller then we move the vault tokens back into your vault - access(contract) fun cancelBidFromSaleItem(_ name: String) { - let bid <- self.bids.remove(key: name) ?? panic("missing bid") - destroy bid - } - - pub fun borrowBid(_ name: String): &Bid { - pre{ - self.bids.containsKey(name) : "This name lease bid does not exist.".concat(name) - } - return (&self.bids[name] as &Bid?)! - } - - pub fun borrowBidItem(_ name: String): &{FindLeaseMarket.Bid} { - pre{ - self.bids.containsKey(name) : "This name lease bid does not exist.".concat(name) - } - return (&self.bids[name] as &Bid{FindLeaseMarket.Bid}?)! - } - - pub fun getBalance(_ name: String) : UFix64 { - pre { - self.bids[name] != nil : "You need to have a bid here already" - } - let bid= self.borrowBid(name) - return bid.balance - } - - destroy() { - destroy self.bids - } - } - - //Create an empty lease collection that store your leases to a name - pub fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>): @SaleItemCollection { - return <- create SaleItemCollection(tenantCapability) - } - - pub fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) : @MarketBidCollection { - return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) - } - - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>? { - pre{ - FindMarket.getTenantCapability(marketplace) != nil : "Invalid tenant" - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&SaleItemCollection{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - } - return nil - } - - pub fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>? { - pre{ - FindMarket.getTenantCapability(marketplace) != nil : "Invalid tenant" - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&MarketBidCollection{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - } - return nil - } - - init() { - FindLeaseMarket.addSaleItemType(Type<@SaleItem>()) - FindLeaseMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) - FindLeaseMarket.addMarketBidType(Type<@Bid>()) - FindLeaseMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) - } + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"list item for soft-auction"), seller: self.owner!.address, buyer: nil) + if !actionResult.allowed { + panic(actionResult.message) + } + + assert(self.items[pointer.name] == nil , message: "Auction listing for this item is already created.") + + saleItem.setAuctionDuration(auctionDuration) + saleItem.setExtentionOnLateBid(auctionExtensionOnLateBid) + saleItem.setMinBidIncrement(minimumBidIncrement) + self.items[pointer.name] <-! saleItem + let saleItemRef = self.borrow(pointer.name) + self.emitEvent(saleItem: saleItemRef, status: "active_listed", previousBuyer:nil) + } + + access(all) fun getNameSales(): [String] { + return self.items.keys + } + + access(all) fun containsNameSale(_ name: String): Bool { + return self.items.containsKey(name) + } + + access(all) fun borrow(_ name: String): &SaleItem { + pre{ + self.items.containsKey(name) : "This name sale does not exist.".concat(name) + } + return (&self.items[name])! + } + + access(Seller) fun borrowAuth(_ name: String): auth(Seller) &SaleItem { + pre{ + self.items.containsKey(name) : "This name sale does not exist.".concat(name) + } + return (&self.items[name])! + } + + access(all) fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} { + pre{ + self.items.containsKey(name) : "This name sale does not exist.".concat(name) + } + return (&self.items[name])! + } + + } + + access(all) resource Bid : FindLeaseMarket.Bid { + access(contract) let from: Capability<&SaleItemCollection> + access(contract) let leaseName: String + + access(contract) let vaultType: Type + access(contract) var bidAt: UFix64 + access(contract) var balance: UFix64 + access(contract) let bidExtraField: {String : AnyStruct} + + init(from: Capability<&SaleItemCollection>, leaseName: String, vaultType:Type, balance:UFix64, bidExtraField: {String : AnyStruct}){ + self.vaultType= vaultType + self.balance=balance + self.leaseName=leaseName + self.from=from + self.bidAt=Clock.time() + self.bidExtraField=bidExtraField + } + + access(contract) fun setBalance(_ balance:UFix64) { + self.balance=balance + } + + access(contract) fun setBidAt(_ time: UFix64) { + self.bidAt=time + } + + access(all) fun getBalance() : UFix64 { + return self.balance + } + + access(all) fun getSellerAddress() : Address { + return self.from.address + } + + access(all) fun getBidExtraField() : {String : AnyStruct} { + return self.bidExtraField + } + } + + access(all) resource interface MarketBidCollectionPublic { + access(all) fun getBalance(_ name: String) : UFix64 + access(all) fun containsNameBid(_ name: String): Bool + access(contract) fun accept(_ name: String) + access(contract) fun cancelBidFromSaleItem(_ name: String) + } + + // A Buyer can bid, increase bid and fulfill auctions + access(all) entitlement Buyer + + //A collection stored for bidders/buyers + access(all) resource MarketBidCollection: MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic { + access(contract) var bids : @{String: Bid} + access(contract) let receiver: Capability<&{FungibleToken.Receiver}> + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + //not sure we can store this here anymore. think it needs to be in every bid + init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) { + self.bids <- {} + self.receiver=receiver + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + pre{ + self.tenantCapability.check() : "Tenant client is not linked anymore" + } + return self.tenantCapability.borrow()! + } + + //called from lease when auction is ended + access(contract) fun accept(_ name: String) { + pre { + self.bids[name] != nil : "You need to have a bid here already" + } + + let bid <- self.bids.remove(key: name) ?? panic("missing bid") + destroy bid + } + + access(all) fun getNameBids() : [String] { + return self.bids.keys + } + + access(all) fun containsNameBid(_ name: String) : Bool { + return self.bids.containsKey(name) + } + + access(all) fun getBidType() : Type { + return Type<@Bid>() + } + + access(Buyer) fun bid(name: String, amount:UFix64, vaultType:Type, bidExtraField: {String : AnyStruct}) { + if self.owner!.address == FIND.status(name).owner! { + panic("You cannot bid on your own resource") + } + + if self.bids[name] !=nil{ + panic("You already have an bid for this item, use increaseBid on that bid") + } + + let from=getAccount(FIND.status(name).owner!).capabilities.get<&SaleItemCollection>(self.getTenant().getPublicPath(Type<@SaleItemCollection>())) + + let bid <- create Bid(from: from, leaseName:name, vaultType: vaultType, balance:amount, bidExtraField: bidExtraField) + let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for lease name=".concat(name)) + + let callbackCapability =self.owner!.capabilities.get<&MarketBidCollection>(self.getTenant().getPublicPath(Type<@MarketBidCollection>())) + let oldToken <- self.bids[name] <- bid + saleItemCollection.registerBid(name: name, callback: callbackCapability, vaultType: vaultType) + destroy oldToken + } + + access(Buyer) fun fulfillAuction(name:String, vault: @{FungibleToken.Vault}) { + pre { + self.bids[name] != nil : "You need to have a bid here already" + } + let bid =self.borrowBid(name) + let saleItem=bid.from.borrow()! + saleItem.fulfillAuction(name:name, vault: <- vault) + } + + //increase a bid, will not work if the auction has already started + access(Buyer) fun increaseBid(name: String, increaseBy: UFix64) { + pre { + self.bids[name] != nil : "You need to have a bid here already" + } + let bid =self.borrowBid(name) + + let oldBalance=bid.balance + + bid.setBidAt(Clock.time()) + bid.setBalance(bid.balance + increaseBy) + + if !bid.from.check(){ + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) + } + bid.from.borrow()!.registerIncreasedBid(name, oldBalance: oldBalance) + } + + //called from saleItem when things are cancelled + //if the bid is canceled from seller then we move the vault tokens back into your vault + access(contract) fun cancelBidFromSaleItem(_ name: String) { + let bid <- self.bids.remove(key: name) ?? panic("missing bid") + destroy bid + } + + access(all) fun borrowBid(_ name: String): &Bid { + pre{ + self.bids.containsKey(name) : "This name lease bid does not exist.".concat(name) + } + return (&self.bids[name])! + } + + access(all) fun borrowBidItem(_ name: String): &{FindLeaseMarket.Bid} { + pre{ + self.bids.containsKey(name) : "This name lease bid does not exist.".concat(name) + } + return (&self.bids[name])! + } + + access(all) fun getBalance(_ name: String) : UFix64 { + pre { + self.bids[name] != nil : "You need to have a bid here already" + } + let bid= self.borrowBid(name) + return bid.balance + } + } + + //Create an empty lease collection that store your leases to a name + access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>) : @SaleItemCollection { + return <- create SaleItemCollection(tenantCapability) + } + + access(all) fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) : @MarketBidCollection { + return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) + } + + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) + } + return nil + } + + access(all) fun getBidCapability( marketplace:Address, user:Address) : Capability<&{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) + } + return nil + } + + init() { + FindLeaseMarket.addSaleItemType(Type<@SaleItem>()) + FindLeaseMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) + FindLeaseMarket.addMarketBidType(Type<@Bid>()) + FindLeaseMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) + } } diff --git a/contracts/FindLeaseMarketDirectOfferSoft.cdc b/contracts/FindLeaseMarketDirectOfferSoft.cdc index ffd831c6..c69cb05a 100644 --- a/contracts/FindLeaseMarketDirectOfferSoft.cdc +++ b/contracts/FindLeaseMarketDirectOfferSoft.cdc @@ -1,634 +1,641 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import FlowToken from "./standard/FlowToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import Clock from "./Clock.cdc" -import Debug from "./Debug.cdc" -import FIND from "./FIND.cdc" -import FindMarket from "./FindMarket.cdc" -import FindLeaseMarket from "./FindLeaseMarket.cdc" - -pub contract FindLeaseMarketDirectOfferSoft { - - pub event DirectOffer(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, leaseInfo: FindLeaseMarket.LeaseInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) - - pub resource SaleItem : FindLeaseMarket.SaleItem { - - access(contract) var pointer: AnyStruct{FindLeaseMarket.LeasePointer} - access(contract) var offerCallback: Capability<&MarketBidCollection{MarketBidCollectionPublic}> - - access(contract) var directOfferAccepted:Bool - access(contract) var validUntil: UFix64? - access(contract) var saleItemExtraField: {String : AnyStruct} - - init(pointer: FindLeaseMarket.ReadLeasePointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - self.offerCallback=callback - self.directOfferAccepted=false - self.validUntil=validUntil - self.saleItemExtraField=saleItemExtraField - self.pointer=pointer - } - - pub fun getName() : String { - return self.pointer.name - } - - pub fun acceptDirectOffer() { - self.directOfferAccepted=true - } - - //Here we do not get a vault back, it is sent in to the method itself - pub fun acceptNonEscrowedBid() { - pre{ - self.offerCallback.check() : "Bidder unlinked the bid collection capability." - self.pointer != nil : "Please accept offer" - } - self.offerCallback.borrow()!.acceptNonEscrowed(self.getLeaseName()) - let pointer = self.pointer as! FindLeaseMarket.AuthLeasePointer - pointer.move(to: self.offerCallback.address) - } - - pub fun getFtType() : Type { - pre{ - self.offerCallback.check() : "Bidder unlinked the bid collection capability." - } - return self.offerCallback.borrow()!.getVaultType(self.getLeaseName()) - } - - pub fun getLeaseName() : String { - return self.pointer.name - } - - pub fun getItemType() : Type { - return Type<@FIND.Lease>() - } - - pub fun getAuction(): FindLeaseMarket.AuctionItem? { - return nil - } - - pub fun getId() : UInt64 { - return self.pointer.getUUID() - } - - pub fun getSaleType() : String { - if self.directOfferAccepted { - return "active_finished" - } - return "active_ongoing" - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun getListingTypeIdentifier() : String { - return Type<@SaleItem>().identifier - } - - pub fun getBalance() : UFix64 { - pre{ - self.offerCallback.check() : "Bidder unlinked the bid collection capability." - } - return self.offerCallback.borrow()!.getBalance(self.getLeaseName()) - } - - pub fun getSeller() : Address { - return self.pointer.owner() - } - - pub fun getSellerName() : String? { - let address = self.pointer.owner() - return FIND.reverseLookup(address) - } - - pub fun getBuyer() : Address? { - return self.offerCallback.address - } - - pub fun getBuyerName() : String? { - if let name = FIND.reverseLookup(self.offerCallback.address) { - return name - } - return nil - } - - pub fun toLeaseInfo() : FindLeaseMarket.LeaseInfo{ - return FindLeaseMarket.LeaseInfo(self.pointer) - } - - pub fun setValidUntil(_ time: UFix64?) { - self.validUntil=time - } - - pub fun getValidUntil() : UFix64? { - return self.validUntil - } - - pub fun setPointer(_ pointer: FindLeaseMarket.AuthLeasePointer) { - self.pointer=pointer - } - - pub fun setCallback(_ callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>) { - self.offerCallback=callback - } - - pub fun checkPointer() : Bool { - return self.pointer.valid() - } - - pub fun getSaleItemExtraField() : {String : AnyStruct} { - return self.saleItemExtraField - } - - access(contract) fun setSaleItemExtraField(_ field: {String : AnyStruct}) { - self.saleItemExtraField = field - } - - } - - pub resource interface SaleItemCollectionPublic { - //fetch all the tokens in the collection - pub fun getNameSales(): [String] - pub fun containsNameSale(_ name: String): Bool - access(contract) fun cancelBid(_ name: String) - access(contract) fun registerIncreasedBid(_ name: String) +import "FungibleToken" +import "FlowToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "Clock" +import "Debug" +import "FIND" +import "FindMarket" +import "FindLeaseMarket" + +access(all) contract FindLeaseMarketDirectOfferSoft { + + access(all) entitlement Seller + + access(all) event DirectOffer(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, leaseInfo: FindLeaseMarket.LeaseInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) + + access(all) resource SaleItem : FindLeaseMarket.SaleItem { + + access(contract) var pointer: {FindLeaseMarket.LeasePointer} + access(contract) var offerCallback: Capability<&MarketBidCollection> + + access(contract) var directOfferAccepted:Bool + access(contract) var validUntil: UFix64? + access(contract) var saleItemExtraField: {String : AnyStruct} + + init(pointer: FindLeaseMarket.ReadLeasePointer, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + self.offerCallback=callback + self.directOfferAccepted=false + self.validUntil=validUntil + self.saleItemExtraField=saleItemExtraField + self.pointer=pointer + } + + access(all) fun getName() : String { + return self.pointer.name + } + + access(contract) fun acceptDirectOffer() { + self.directOfferAccepted=true + } + + //Here we do not get a vault back, it is sent in to the method itself + access(contract) fun acceptNonEscrowedBid() { + pre{ + self.offerCallback.check() : "Bidder unlinked the bid collection capability." + self.pointer != nil : "Please accept offer" + } + self.offerCallback.borrow()!.acceptNonEscrowed(self.getLeaseName()) + let pointer = self.pointer as! FindLeaseMarket.AuthLeasePointer + pointer.move(to: self.offerCallback.address) + } + + access(all) fun getFtType() : Type { + pre{ + self.offerCallback.check() : "Bidder unlinked the bid collection capability." + } + return self.offerCallback.borrow()!.getVaultType(self.getLeaseName()) + } + + access(all) fun getLeaseName() : String { + return self.pointer.name + } + + access(all) fun getItemType() : Type { + return Type<@FIND.Lease>() + } + + access(all) fun getAuction(): FindLeaseMarket.AuctionItem? { + return nil + } + + access(all) fun getId() : UInt64 { + return self.pointer.getUUID() + } + + access(all) fun getSaleType() : String { + if self.directOfferAccepted { + return "active_finished" + } + return "active_ongoing" + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun getListingTypeIdentifier() : String { + return Type<@SaleItem>().identifier + } + + access(all) fun getBalance() : UFix64 { + pre{ + self.offerCallback.check() : "Bidder unlinked the bid collection capability." + } + return self.offerCallback.borrow()!.getBalance(self.getLeaseName()) + } + + access(all) fun getSeller() : Address { + return self.pointer.owner() + } + + access(all) fun getSellerName() : String? { + let address = self.pointer.owner() + return FIND.reverseLookup(address) + } + + access(all) fun getBuyer() : Address? { + return self.offerCallback.address + } + + access(all) fun getBuyerName() : String? { + if let name = FIND.reverseLookup(self.offerCallback.address) { + return name + } + return nil + } + + access(all) fun toLeaseInfo() : FindLeaseMarket.LeaseInfo{ + return FindLeaseMarket.LeaseInfo(self.pointer) + } + + access(contract) fun setValidUntil(_ time: UFix64?) { + self.validUntil=time + } + + access(all) fun getValidUntil() : UFix64? { + return self.validUntil + } + + access(contract) fun setPointer(_ pointer: FindLeaseMarket.AuthLeasePointer) { + self.pointer=pointer + } + + access(contract) fun setCallback(_ callback: Capability<&MarketBidCollection>) { + self.offerCallback=callback + } + + access(all) fun checkPointer() : Bool { + return self.pointer.valid() + } + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} { + return self.saleItemExtraField + } + + access(contract) fun setSaleItemExtraField(_ field: {String : AnyStruct}) { + self.saleItemExtraField = field + } + + } + + access(all) resource interface SaleItemCollectionPublic { + //fetch all the tokens in the collection + access(all) fun getNameSales(): [String] + access(all) fun containsNameSale(_ name: String): Bool + access(contract) fun cancelBid(_ name: String) + access(contract) fun registerIncreasedBid(_ name: String) - //place a bid on a token - access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) - - access(contract) fun isAcceptedDirectOffer(_ name:String) : Bool - - access(contract) fun fulfillDirectOfferNonEscrowed(name:String, vault: @FungibleToken.Vault) - - } - - pub resource SaleItemCollection: SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic { - //is this the best approach now or just put the NFT inside the saleItem? - access(contract) var items: @{String: SaleItem} - - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - init (_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.items <- {} - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - pre{ - self.tenantCapability.check() : "Tenant client is not linked anymore" - } - return self.tenantCapability.borrow()! - } + //place a bid on a token + access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) + + access(contract) fun isAcceptedDirectOffer(_ name:String) : Bool + + access(contract) fun fulfillDirectOfferNonEscrowed(name:String, vault: @{FungibleToken.Vault}) + + } + + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic { + //is this the best approach now or just put the NFT inside the saleItem? + access(contract) var items: @{String: SaleItem} + + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + init (_ tenantCapability: Capability<&FindMarket.Tenant>) { + self.items <- {} + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + pre{ + self.tenantCapability.check() : "Tenant client is not linked anymore" + } + return self.tenantCapability.borrow()! + } - pub fun isAcceptedDirectOffer(_ name:String) : Bool{ - pre { - self.items.containsKey(name) : "Invalid name sale=".concat(name) - } - let saleItem = self.borrow(name) - - return saleItem.directOfferAccepted - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - //this is called when a buyer cancel a direct offer - access(contract) fun cancelBid(_ name: String) { - pre { - self.items.containsKey(name) : "Invalid name sale=".concat(name) - } - let saleItem=self.borrow(name) + access(contract) fun isAcceptedDirectOffer(_ name:String) : Bool{ + pre { + self.items.containsKey(name) : "Invalid name sale=".concat(name) + } + let saleItem = self.borrow(name) + + return saleItem.directOfferAccepted + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + //this is called when a buyer cancel a direct offer + access(contract) fun cancelBid(_ name: String) { + pre { + self.items.containsKey(name) : "Invalid name sale=".concat(name) + } + let saleItem=self.borrow(name) - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"cancel bid in direct offer soft"), seller: nil, buyer: nil) + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"cancel bid in direct offer soft"), seller: nil, buyer: nil) - if !actionResult.allowed { - panic(actionResult.message) - } + if !actionResult.allowed { + panic(actionResult.message) + } - self.emitEvent(saleItem: saleItem, status: "cancel", previousBuyer: nil) - destroy <- self.items.remove(key: name) - } + self.emitEvent(saleItem: saleItem, status: "cancel", previousBuyer: nil) + destroy <- self.items.remove(key: name) + } - access(self) fun emitEvent(saleItem: &SaleItem, status: String, previousBuyer:Address?) { - let owner=saleItem.getSeller() - let ftType=saleItem.getFtType() - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = FIND.lookup(buyer.toString()) + access(self) fun emitEvent(saleItem: &SaleItem, status: String, previousBuyer:Address?) { + let owner=saleItem.getSeller() + let ftType=saleItem.getFtType() + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = FIND.lookup(buyer.toString()) - var leaseInfo:FindLeaseMarket.LeaseInfo?=nil - if saleItem.checkPointer() { - leaseInfo=saleItem.toLeaseInfo() - } + var leaseInfo:FindLeaseMarket.LeaseInfo?=nil + if saleItem.checkPointer() { + leaseInfo=saleItem.toLeaseInfo() + } - var previousBuyerName : String?=nil - if let pb= previousBuyer { - previousBuyerName = FIND.reverseLookup(pb) - } + var previousBuyerName : String?=nil + if let pb= previousBuyer { + previousBuyerName = FIND.reverseLookup(pb) + } - emit DirectOffer(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, leaseInfo:leaseInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile?.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - } + emit DirectOffer(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, leaseInfo:leaseInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile?.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) + } - //The only thing we do here is basically register an event - access(contract) fun registerIncreasedBid(_ name: String) { - pre { - self.items.containsKey(name) : "Invalid name sale=".concat(name) - } - let saleItem=self.borrow(name) + //The only thing we do here is basically register an event + access(contract) fun registerIncreasedBid(_ name: String) { + pre { + self.items.containsKey(name) : "Invalid name sale=".concat(name) + } + let saleItem=self.borrowAuth(name) - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"increase bid in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"increase bid in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - if !actionResult.allowed { - panic(actionResult.message) - } + if !actionResult.allowed { + panic(actionResult.message) + } - self.emitEvent(saleItem: saleItem, status: "active_offered", previousBuyer:nil) - } + self.emitEvent(saleItem: saleItem, status: "active_offered", previousBuyer:nil) + } - //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller - access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller + access(contract) fun registerBid(name: String, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - //If there are no bids from anybody else before we need to make the item - if !self.items.containsKey(name) { - let item = FindLeaseMarket.ReadLeasePointer(name: name) - let saleItem <- create SaleItem(pointer: item, callback: callback, validUntil: validUntil, saleItemExtraField: saleItemExtraField) - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address) + //If there are no bids from anybody else before we need to make the item + if !self.items.containsKey(name) { + let item = FindLeaseMarket.ReadLeasePointer(name: name) + let saleItem <- create SaleItem(pointer: item, callback: callback, validUntil: validUntil, saleItemExtraField: saleItemExtraField) + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address) - if !actionResult.allowed { - panic(actionResult.message) - } - self.items[name] <-! saleItem - let saleItemRef=self.borrow(name) - self.emitEvent(saleItem: saleItemRef, status: "active_offered", previousBuyer:nil) - return - } + if !actionResult.allowed { + panic(actionResult.message) + } + self.items[name] <-! saleItem + let saleItemRef=self.borrow(name) + self.emitEvent(saleItem: saleItemRef, status: "active_offered", previousBuyer:nil) + return + } - let saleItem=self.borrow(name) - if self.borrow(name).getBuyer()! == callback.address { - panic("You already have the latest bid on this item, use the incraseBid transaction") - } - - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address) - - if !actionResult.allowed { - panic(actionResult.message) - } + let saleItem=self.borrowAuth(name) + if self.borrow(name).getBuyer()! == callback.address { + panic("You already have the latest bid on this item, use the incraseBid transaction") + } + + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address) + + if !actionResult.allowed { + panic(actionResult.message) + } - let balance=callback.borrow()?.getBalance(name) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) + let balance=callback.borrow()?.getBalance(name) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) - let currentBalance=saleItem.getBalance() - Debug.log("currentBalance=".concat(currentBalance.toString()).concat(" new bid is at=").concat(balance.toString())) - if currentBalance >= balance { - panic("There is already a higher bid on this item. Current bid : ".concat(currentBalance.toString()).concat(" . New bid is at : ").concat(balance.toString())) - } - let previousBuyer=saleItem.offerCallback.address - //somebody else has the highest item so we cancel it - saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(name) - saleItem.setValidUntil(validUntil) - saleItem.setSaleItemExtraField(saleItemExtraField) - saleItem.setCallback(callback) - - self.emitEvent(saleItem: saleItem, status: "active_offered", previousBuyer:previousBuyer) - - } + let currentBalance=saleItem.getBalance() + Debug.log("currentBalance=".concat(currentBalance.toString()).concat(" new bid is at=").concat(balance.toString())) + if currentBalance >= balance { + panic("There is already a higher bid on this item. Current bid : ".concat(currentBalance.toString()).concat(" . New bid is at : ").concat(balance.toString())) + } + let previousBuyer=saleItem.offerCallback.address + //somebody else has the highest item so we cancel it + saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(name) + saleItem.setValidUntil(validUntil) + saleItem.setSaleItemExtraField(saleItemExtraField) + saleItem.setCallback(callback) + + self.emitEvent(saleItem: saleItem, status: "active_offered", previousBuyer:previousBuyer) + + } - //cancel will reject a direct offer - pub fun cancel(_ name: String) { - pre { - self.items.containsKey(name) : "Invalid name sale=".concat(name) - } - - let saleItem=self.borrow(name) - - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"reject offer in direct offer soft"), seller: nil, buyer: nil) - - if !actionResult.allowed { - panic(actionResult.message) - } - - self.emitEvent(saleItem: saleItem, status: "cancel_rejected", previousBuyer:nil) - if !saleItem.offerCallback.check() { - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(saleItem.offerCallback.address.toString())) - } - saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(name) - destroy <- self.items.remove(key: name) - } - - pub fun acceptOffer(_ pointer: FindLeaseMarket.AuthLeasePointer) { - pre { - self.items.containsKey(pointer.name) : "Invalid name sale=".concat(pointer.name) - } - - let saleItem = self.borrow(pointer.name) - - if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { - panic("This direct offer is already expired") - } - - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"accept offer in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - - if !actionResult.allowed { - panic(actionResult.message) - } - - //Set the auth pointer in the saleItem so that it now can be fulfilled - saleItem.setPointer(pointer) - saleItem.acceptDirectOffer() - - self.emitEvent(saleItem: saleItem, status: "active_accepted", previousBuyer:nil) - } - - /// this is called from a bid when a seller accepts - access(contract) fun fulfillDirectOfferNonEscrowed(name:String, vault: @FungibleToken.Vault) { - pre { - self.items.containsKey(name) : "Invalid name sale=".concat(name) - } - - let saleItem = self.borrow(name) - if !saleItem.directOfferAccepted { - panic("cannot fulfill a direct offer that is not accepted yet") - } - - if vault.getType() != saleItem.getFtType() { - panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.getFtType().identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier))) - } - let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"fulfill directOffer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - - if !actionResult.allowed { - panic(actionResult.message) - } - - let cuts= self.getTenant().getCuts(name: actionResult.name, listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType()) - - self.emitEvent(saleItem: saleItem, status: "sold", previousBuyer:nil) - let leaseInfo=saleItem.toLeaseInfo() - saleItem.acceptNonEscrowedBid() - FindLeaseMarket.pay(tenant: self.getTenant().name, leaseName:name, saleItem: saleItem, vault: <- vault, leaseInfo: leaseInfo, cuts:cuts) - - destroy <- self.items.remove(key: name) - } - - pub fun getNameSales(): [String] { - return self.items.keys - } - - pub fun containsNameSale(_ name: String): Bool { - return self.items.containsKey(name) - } - - pub fun borrow(_ name: String): &SaleItem { - pre{ - self.items.containsKey(name) : "This name sale does not exist.".concat(name) - } - return (&self.items[name] as &SaleItem?)! - } - - pub fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} { - pre{ - self.items.containsKey(name) : "This name sale does not exist.".concat(name) - } - return (&self.items[name] as &SaleItem{FindLeaseMarket.SaleItem}?)! - } - - destroy() { - destroy self.items - } - } - - /* - ========================================================================== - Bids are a collection/resource for storing the bids bidder made on leases - ========================================================================== - */ - - pub resource Bid : FindLeaseMarket.Bid { - access(contract) let from: Capability<&SaleItemCollection{SaleItemCollectionPublic}> - access(contract) let leaseName: String - - //this should reflect on what the above uuid is for - access(contract) let vaultType: Type - access(contract) var bidAt: UFix64 - access(contract) var balance: UFix64 //This is what you bid for non escrowed bids - access(contract) let bidExtraField: {String : AnyStruct} - - init(from: Capability<&SaleItemCollection{SaleItemCollectionPublic}>, leaseName: String, vaultType:Type, nonEscrowedBalance:UFix64, bidExtraField: {String : AnyStruct}){ - self.vaultType= vaultType - self.balance=nonEscrowedBalance - self.leaseName=leaseName - self.from=from - self.bidAt=Clock.time() - self.bidExtraField=bidExtraField - } - - access(contract) fun setBidAt(_ time: UFix64) { - self.bidAt=time - } - - access(contract) fun increaseBid(_ amount:UFix64) { - self.balance=self.balance+amount - } - - pub fun getBalance() : UFix64 { - return self.balance - } - - pub fun getSellerAddress() : Address { - return self.from.address - } - - pub fun getBidExtraField() : {String : AnyStruct} { - return self.bidExtraField - } - } - - pub resource interface MarketBidCollectionPublic { - pub fun getBalance(_ name: String) : UFix64 - pub fun getVaultType(_ name: String) : Type - pub fun containsNameBid(_ name: String): Bool - pub fun getNameBids() : [String] - access(contract) fun acceptNonEscrowed(_ name: String) - access(contract) fun cancelBidFromSaleItem(_ name: String) - } - - //A collection stored for bidders/buyers - pub resource MarketBidCollection: MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic { - - access(contract) var bids : @{String: Bid} - access(contract) let receiver: Capability<&{FungibleToken.Receiver}> - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - //not sure we can store this here anymore. think it needs to be in every bid - init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.bids <- {} - self.receiver=receiver - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - pre{ - self.tenantCapability.check() : "Tenant client is not linked anymore" - } - return self.tenantCapability.borrow()! - } - - //called from lease when auction is ended - access(contract) fun acceptNonEscrowed(_ name: String) { - let bid <- self.bids.remove(key: name) ?? panic("missing bid") - destroy bid - } - - pub fun getVaultType(_ name:String) : Type { - return self.borrowBid(name).vaultType - } - - pub fun getNameBids() : [String] { - return self.bids.keys - } - - pub fun containsNameBid(_ name: String) : Bool { - return self.bids.containsKey(name) - } - - pub fun getBidType() : Type { - return Type<@Bid>() - } - - - pub fun bid(name: String, amount:UFix64, vaultType:Type, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}, bidExtraField: {String : AnyStruct}) { - pre { - self.owner!.address != FIND.status(name).owner! : "You cannot bid on your own resource" - self.bids[name] == nil : "You already have an bid for this item, use increaseBid on that bid" - } - - // ensure it is not a 0 dollar listing - if amount <= 0.0 { - panic("Offer price should be greater than 0") - } - - // ensure validUntil is valid - if validUntil != nil && validUntil! < Clock.time() { - panic("Valid until is before current time") - } - - let from=getAccount(FIND.status(name).owner!).getCapability<&SaleItemCollection{SaleItemCollectionPublic}>(self.getTenant().getPublicPath(Type<@SaleItemCollection>())) - - let bid <- create Bid(from: from, leaseName: name, vaultType: vaultType, nonEscrowedBalance:amount, bidExtraField: bidExtraField) - let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for name=".concat(name)) - let callbackCapability =self.owner!.getCapability<&MarketBidCollection{MarketBidCollectionPublic}>(self.getTenant().getPublicPath(Type<@MarketBidCollection>())) - - let oldToken <- self.bids[name] <- bid - saleItemCollection.registerBid(name: name, callback: callbackCapability, validUntil: validUntil, saleItemExtraField: saleItemExtraField) - destroy oldToken - } - - pub fun fulfillDirectOffer(name:String, vault: @FungibleToken.Vault) { - pre { - self.bids[name] != nil : "You need to have a bid here already" - } - - let bid =self.borrowBid(name) - let saleItem=bid.from.borrow()! - - if !saleItem.isAcceptedDirectOffer(name) { - panic("offer is not accepted yet") - } - - saleItem.fulfillDirectOfferNonEscrowed(name:name, vault: <- vault) - } - - pub fun increaseBid(name: String, increaseBy: UFix64) { - let bid =self.borrowBid(name) - bid.setBidAt(Clock.time()) - bid.increaseBid(increaseBy) - if !bid.from.check() { - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) - } - bid.from.borrow()!.registerIncreasedBid(name) - } - - /// The users cancel a bid himself - pub fun cancelBid(_ name: String) { - let bid= self.borrowBid(name) - if !bid.from.check() { - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) - } - bid.from.borrow()!.cancelBid(name) - self.cancelBidFromSaleItem(name) - } - - //called from saleItem when things are cancelled - //if the bid is canceled from seller then we move the vault tokens back into your vault - access(contract) fun cancelBidFromSaleItem(_ name: String) { - let bid <- self.bids.remove(key: name) ?? panic("missing bid") - destroy bid - } - - pub fun borrowBid(_ name: String): &Bid { - pre{ - self.bids.containsKey(name) : "This name bid does not exist.".concat(name) - } - return (&self.bids[name] as &Bid?)! - } - - pub fun borrowBidItem(_ name: String): &{FindLeaseMarket.Bid} { - pre{ - self.bids.containsKey(name) : "This name bid does not exist.".concat(name) - } - return (&self.bids[name] as &Bid{FindLeaseMarket.Bid}?)! - } - - pub fun getBalance(_ name: String) : UFix64 { - let bid= self.borrowBid(name) - return bid.balance - } - - destroy() { - destroy self.bids - } - } - - //Create an empty lease collection that store your leases to a name - pub fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>): @SaleItemCollection { - return <- create SaleItemCollection(tenantCapability) - } - - pub fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) : @MarketBidCollection { - return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) - } - - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>? { - pre{ - FindMarket.getTenantCapability(marketplace) != nil : "Invalid tenant" - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&SaleItemCollection{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - } - return nil - } - - pub fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>? { - pre{ - FindMarket.getTenantCapability(marketplace) != nil : "Invalid tenant" - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&MarketBidCollection{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - } - return nil - } - - init() { - FindLeaseMarket.addSaleItemType(Type<@SaleItem>()) - FindLeaseMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) - FindLeaseMarket.addMarketBidType(Type<@Bid>()) - FindLeaseMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) - } + //cancel will reject a direct offer + access(Seller) fun cancel(_ name: String) { + pre { + self.items.containsKey(name) : "Invalid name sale=".concat(name) + } + + let saleItem=self.borrowAuth(name) + + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"reject offer in direct offer soft"), seller: nil, buyer: nil) + + if !actionResult.allowed { + panic(actionResult.message) + } + + self.emitEvent(saleItem: saleItem, status: "cancel_rejected", previousBuyer:nil) + if !saleItem.offerCallback.check() { + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(saleItem.offerCallback.address.toString())) + } + saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(name) + destroy <- self.items.remove(key: name) + } + + access(Seller) fun acceptOffer(_ pointer: FindLeaseMarket.AuthLeasePointer) { + pre { + self.items.containsKey(pointer.name) : "Invalid name sale=".concat(pointer.name) + } + + let saleItem = self.borrowAuth(pointer.name) + + if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { + panic("This direct offer is already expired") + } + + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"accept offer in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) + + if !actionResult.allowed { + panic(actionResult.message) + } + + //Set the auth pointer in the saleItem so that it now can be fulfilled + saleItem.setPointer(pointer) + saleItem.acceptDirectOffer() + + self.emitEvent(saleItem: saleItem, status: "active_accepted", previousBuyer:nil) + } + + /// this is called from a bid when a seller accepts + access(contract) fun fulfillDirectOfferNonEscrowed(name:String, vault: @{FungibleToken.Vault}) { + pre { + self.items.containsKey(name) : "Invalid name sale=".concat(name) + } + + let saleItem = self.borrowAuth(name) + if !saleItem.directOfferAccepted { + panic("cannot fulfill a direct offer that is not accepted yet") + } + + if vault.getType() != saleItem.getFtType() { + panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.getFtType().identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier))) + } + let actionResult=self.getTenant().allowedAction(listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"fulfill directOffer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) + + if !actionResult.allowed { + panic(actionResult.message) + } + + let cuts= self.getTenant().getCuts(name: actionResult.name, listingType: self.getListingType(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType()) + + self.emitEvent(saleItem: saleItem, status: "sold", previousBuyer:nil) + let leaseInfo=saleItem.toLeaseInfo() + saleItem.acceptNonEscrowedBid() + FindLeaseMarket.pay(tenant: self.getTenant().name, leaseName:name, saleItem: saleItem, vault: <- vault, leaseInfo: leaseInfo, cuts:cuts) + + destroy <- self.items.remove(key: name) + } + + access(all) fun getNameSales(): [String] { + return self.items.keys + } + + access(all) fun containsNameSale(_ name: String): Bool { + return self.items.containsKey(name) + } + + access(all) fun borrow(_ name: String): &SaleItem { + pre{ + self.items.containsKey(name) : "This name sale does not exist.".concat(name) + } + return (&self.items[name])! + } + + access(Seller) fun borrowAuth(_ name: String): auth(Seller) &SaleItem { + pre{ + self.items.containsKey(name) : "This name sale does not exist.".concat(name) + } + return (&self.items[name])! + } + + access(all) fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} { + pre{ + self.items.containsKey(name) : "This name sale does not exist.".concat(name) + } + return (&self.items[name])! + } + } + + /* + ========================================================================== + Bids are a collection/resource for storing the bids bidder made on leases + ========================================================================== + */ + + access(all) resource Bid : FindLeaseMarket.Bid { + access(contract) let from: Capability<&SaleItemCollection> + access(contract) let leaseName: String + + //this should reflect on what the above uuid is for + access(contract) let vaultType: Type + access(contract) var bidAt: UFix64 + access(contract) var balance: UFix64 //This is what you bid for non escrowed bids + access(contract) let bidExtraField: {String : AnyStruct} + + init(from: Capability<&SaleItemCollection>, leaseName: String, vaultType:Type, nonEscrowedBalance:UFix64, bidExtraField: {String : AnyStruct}){ + self.vaultType= vaultType + self.balance=nonEscrowedBalance + self.leaseName=leaseName + self.from=from + self.bidAt=Clock.time() + self.bidExtraField=bidExtraField + } + + access(contract) fun setBidAt(_ time: UFix64) { + self.bidAt=time + } + + access(contract) fun increaseBid(_ amount:UFix64) { + self.balance=self.balance+amount + } + + access(all) fun getBalance() : UFix64 { + return self.balance + } + + access(all) fun getSellerAddress() : Address { + return self.from.address + } + + access(all) fun getBidExtraField() : {String : AnyStruct} { + return self.bidExtraField + } + } + + access(all) resource interface MarketBidCollectionPublic { + access(all) fun getBalance(_ name: String) : UFix64 + access(all) fun getVaultType(_ name: String) : Type + access(all) fun containsNameBid(_ name: String): Bool + access(all) fun getNameBids() : [String] + access(contract) fun acceptNonEscrowed(_ name: String) + access(contract) fun cancelBidFromSaleItem(_ name: String) + } + + access(all) entitlement Buyer + + //A collection stored for bidders/buyers + access(all) resource MarketBidCollection: MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic { + + access(contract) var bids : @{String: Bid} + access(contract) let receiver: Capability<&{FungibleToken.Receiver}> + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + //not sure we can store this here anymore. think it needs to be in every bid + init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) { + self.bids <- {} + self.receiver=receiver + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + pre{ + self.tenantCapability.check() : "Tenant client is not linked anymore" + } + return self.tenantCapability.borrow()! + } + + //called from lease when auction is ended + access(contract) fun acceptNonEscrowed(_ name: String) { + let bid <- self.bids.remove(key: name) ?? panic("missing bid") + destroy bid + } + + access(all) fun getVaultType(_ name:String) : Type { + return self.borrowBid(name).vaultType + } + + access(all) fun getNameBids() : [String] { + return self.bids.keys + } + + access(all) fun containsNameBid(_ name: String) : Bool { + return self.bids.containsKey(name) + } + + access(all) fun getBidType() : Type { + return Type<@Bid>() + } + + + access(Buyer) fun bid(name: String, amount:UFix64, vaultType:Type, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}, bidExtraField: {String : AnyStruct}) { + if self.owner!.address == FIND.status(name).owner! { + panic("You cannot bid on your own resource") + } + + if self.bids[name] !=nil{ + panic("You already have an bid for this item, use increaseBid on that bid") + } + + // ensure it is not a 0 dollar listing + if amount <= 0.0 { + panic("Offer price should be greater than 0") + } + + // ensure validUntil is valid + if validUntil != nil && validUntil! < Clock.time() { + panic("Valid until is before current time") + } + + let from=getAccount(FIND.status(name).owner!).capabilities.get<&SaleItemCollection>(self.getTenant().getPublicPath(Type<@SaleItemCollection>())) + + let bid <- create Bid(from: from, leaseName: name, vaultType: vaultType, nonEscrowedBalance:amount, bidExtraField: bidExtraField) + let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for name=".concat(name)) + let callbackCapability =self.owner!.capabilities.get<&MarketBidCollection>(self.getTenant().getPublicPath(Type<@MarketBidCollection>())) + + let oldToken <- self.bids[name] <- bid + saleItemCollection.registerBid(name: name, callback: callbackCapability, validUntil: validUntil, saleItemExtraField: saleItemExtraField) + destroy oldToken + } + + access(all) fun fulfillDirectOffer(name:String, vault: @{FungibleToken.Vault}) { + pre { + self.bids[name] != nil : "You need to have a bid here already" + } + + let bid =self.borrowBid(name) + let saleItem=bid.from.borrow()! + + if !saleItem.isAcceptedDirectOffer(name) { + panic("offer is not accepted yet") + } + + saleItem.fulfillDirectOfferNonEscrowed(name:name, vault: <- vault) + } + + access(Buyer) fun increaseBid(name: String, increaseBy: UFix64) { + let bid =self.borrowBid(name) + bid.setBidAt(Clock.time()) + bid.increaseBid(increaseBy) + if !bid.from.check() { + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) + } + bid.from.borrow()!.registerIncreasedBid(name) + } + + /// The users cancel a bid himself + access(Buyer) fun cancelBid(_ name: String) { + let bid= self.borrowBid(name) + if !bid.from.check() { + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) + } + bid.from.borrow()!.cancelBid(name) + self.cancelBidFromSaleItem(name) + } + + //called from saleItem when things are cancelled + //if the bid is canceled from seller then we move the vault tokens back into your vault + access(contract) fun cancelBidFromSaleItem(_ name: String) { + let bid <- self.bids.remove(key: name) ?? panic("missing bid") + destroy bid + } + + access(all) fun borrowBid(_ name: String): &Bid { + pre{ + self.bids.containsKey(name) : "This name bid does not exist.".concat(name) + } + return (&self.bids[name])! + } + + access(all) fun borrowBidItem(_ name: String): &{FindLeaseMarket.Bid} { + pre{ + self.bids.containsKey(name) : "This name bid does not exist.".concat(name) + } + return (&self.bids[name])! + } + + access(all) fun getBalance(_ name: String) : UFix64 { + let bid= self.borrowBid(name) + return bid.balance + } + } + + //Create an empty lease collection that store your leases to a name + access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>) : @SaleItemCollection { + return <- create SaleItemCollection(tenantCapability) + } + + access(all) fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) : @MarketBidCollection { + return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) + } + + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + + return getAccount(user).capabilities.get<&{SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) + } + return nil + } + + access(all) fun getBidCapability( marketplace:Address, user:Address) : Capability<&{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&{MarketBidCollectionPublic, FindLeaseMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) + } + return nil + } + + init() { + FindLeaseMarket.addSaleItemType(Type<@SaleItem>()) + FindLeaseMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) + FindLeaseMarket.addMarketBidType(Type<@Bid>()) + FindLeaseMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) + } } diff --git a/contracts/FindLeaseMarketSale.cdc b/contracts/FindLeaseMarketSale.cdc index a53e1409..eb51bb67 100644 --- a/contracts/FindLeaseMarketSale.cdc +++ b/contracts/FindLeaseMarketSale.cdc @@ -1,297 +1,297 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import FindViews from "../contracts/FindViews.cdc" -import Clock from "./Clock.cdc" -import FIND from "./FIND.cdc" -import FindLeaseMarket from "./FindLeaseMarket.cdc" -import FindMarket from "./FindMarket.cdc" +import "FungibleToken" +import "FindViews" +import "Clock" +import "FIND" +import "FindLeaseMarket" +import "FindMarket" +import "Debug" /* - A Find Market for direct sales */ -pub contract FindLeaseMarketSale { - - pub event Sale(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, leaseInfo: FindLeaseMarket.LeaseInfo?, buyer:Address?, buyerName:String?, buyerAvatar: String?, endsAt:UFix64?) - - //A sale item for a direct sale - pub resource SaleItem : FindLeaseMarket.SaleItem{ - - //this is set when bought so that pay will work - access(self) var buyer: Address? - - access(contract) let vaultType: Type //The type of vault to use for this sale Item - access(contract) var pointer: FindLeaseMarket.AuthLeasePointer - - //this field is set if this is a saleItem - access(contract) var salePrice: UFix64 - access(contract) var validUntil: UFix64? - access(contract) let saleItemExtraField: {String : AnyStruct} - - init(pointer: FindLeaseMarket.AuthLeasePointer, vaultType: Type, price:UFix64, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - self.vaultType=vaultType - self.pointer=pointer - self.salePrice=price - self.buyer=nil - self.validUntil=validUntil - self.saleItemExtraField=saleItemExtraField - } - - pub fun getSaleType() : String { - return "active_listed" - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun getListingTypeIdentifier(): String { - return Type<@SaleItem>().identifier - } - - pub fun setBuyer(_ address:Address) { - self.buyer=address - } - - pub fun getBuyer(): Address? { - return self.buyer - } - - pub fun getBuyerName() : String? { - if let address = self.buyer { - return FIND.reverseLookup(address) - } - return nil - } - - pub fun getLeaseName() : String { - return self.pointer.name - } - - pub fun getItemType() : Type { - return Type<@FIND.Lease>() - } - - pub fun getId() : UInt64 { - return self.pointer.getUUID() - } - - pub fun getSeller() : Address { - return self.pointer.owner() - } - - pub fun getSellerName() : String? { - let address = self.pointer.owner() - return FIND.reverseLookup(address) - } - - pub fun getBalance() : UFix64 { - return self.salePrice - } - - pub fun getAuction(): FindLeaseMarket.AuctionItem? { - return nil - } - - pub fun getFtType() : Type { - return self.vaultType - } - - pub fun setValidUntil(_ time: UFix64?) { - self.validUntil=time - } - pub fun getValidUntil() : UFix64? { - return self.validUntil - } +access(all) contract FindLeaseMarketSale { + + // A seller can list, delist and relist leases for sale + access(all) entitlement Seller + + access(all) event Sale(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, leaseInfo: FindLeaseMarket.LeaseInfo?, buyer:Address?, buyerName:String?, buyerAvatar: String?, endsAt:UFix64?) + + // A sale item for a direct sale + access(all) resource SaleItem : FindLeaseMarket.SaleItem{ + //this is set when bought so that pay will work + access(self) var buyer: Address? + + access(contract) let vaultType: Type //The type of vault to use for this sale Item + access(contract) var pointer: FindLeaseMarket.AuthLeasePointer + + //this field is set if this is a saleItem + access(contract) var salePrice: UFix64 + access(contract) var validUntil: UFix64? + access(contract) let saleItemExtraField: {String : AnyStruct} + + init(pointer: FindLeaseMarket.AuthLeasePointer, vaultType: Type, price:UFix64, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + self.vaultType=vaultType + self.pointer=pointer + self.salePrice=price + self.buyer=nil + self.validUntil=validUntil + self.saleItemExtraField=saleItemExtraField + } + + access(all) fun getSaleType() : String { + return "active_listed" + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun getListingTypeIdentifier(): String { + return Type<@SaleItem>().identifier + } + + access(account) fun setBuyer(_ address:Address) { + self.buyer=address + } + + access(all) fun getBuyer(): Address? { + return self.buyer + } + + access(all) fun getBuyerName() : String? { + if let address = self.buyer { + return FIND.reverseLookup(address) + } + return nil + } + + access(all) fun getLeaseName() : String { + return self.pointer.name + } + + access(all) fun getItemType() : Type { + return Type<@FIND.Lease>() + } + + access(all) fun getId() : UInt64 { + return self.pointer.getUUID() + } + + access(all) fun getSeller() : Address { + return self.pointer.owner() + } + + access(all) fun getSellerName() : String? { + let address = self.pointer.owner() + return FIND.reverseLookup(address) + } + + access(all) fun getBalance() : UFix64 { + return self.salePrice + } + + access(all) fun getAuction(): FindLeaseMarket.AuctionItem? { + return nil + } - pub fun toLeaseInfo() : FindLeaseMarket.LeaseInfo { - return FindLeaseMarket.LeaseInfo(self.pointer) - } + access(all) fun getFtType() : Type { + return self.vaultType + } - pub fun checkPointer() : Bool { - return self.pointer.valid() - } + access(contract) fun setValidUntil(_ time: UFix64?) { + self.validUntil=time + } - pub fun getSaleItemExtraField() : {String : AnyStruct} { - return self.saleItemExtraField - } + access(all) fun getValidUntil() : UFix64? { + return self.validUntil + } - } + access(all) fun toLeaseInfo() : FindLeaseMarket.LeaseInfo { + return FindLeaseMarket.LeaseInfo(self.pointer) + } + + access(all) fun checkPointer() : Bool { + return self.pointer.valid() + } - pub resource interface SaleItemCollectionPublic { - //fetch all the tokens in the collection - pub fun getNameSales(): [String] - pub fun containsNameSale(_ name: String): Bool - pub fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} - pub fun buy(name: String, vault: @FungibleToken.Vault, to: Address) - } + access(all) fun getSaleItemExtraField() : {String : AnyStruct} { + return self.saleItemExtraField + } - pub resource SaleItemCollection: SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic { - //is this the best approach now or just put the NFT inside the saleItem? - access(contract) var items: @{String: SaleItem} + } - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> + access(all) resource interface SaleItemCollectionPublic { + //fetch all the tokens in the collection + access(all) fun getNameSales(): [String] + access(all) fun containsNameSale(_ name: String): Bool + access(all) fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} + access(all) fun buy(name: String, vault: @{FungibleToken.Vault}, to: Address) + } - init (_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.items <- {} - self.tenantCapability=tenantCapability - } + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic { + //is this the best approach now or just put the NFT inside the saleItem? + access(contract) var items: @{String: SaleItem} - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - pre{ - self.tenantCapability.check() : "Tenant client is not linked anymore" - } - return self.tenantCapability.borrow()! - } + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> - pub fun getListingType() : Type { - return Type<@SaleItem>() - } + init (_ tenantCapability: Capability<&FindMarket.Tenant>) { + self.items <- {} + self.tenantCapability=tenantCapability + } - pub fun buy(name: String, vault: @FungibleToken.Vault, to: Address) { - pre { - self.items.containsKey(name) : "Invalid name=".concat(name) - self.owner!.address != to : "You cannot buy your own listing" - } + access(self) fun getTenant() : &FindMarket.Tenant { + pre{ + self.tenantCapability.check() : "Tenant client is not linked anymore" + } + return self.tenantCapability.borrow()! + } - let saleItem=self.borrow(name) + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } - if saleItem.salePrice != vault.balance { - panic("Incorrect balance sent in vault. Expected ".concat(saleItem.salePrice.toString()).concat(" got ").concat(vault.balance.toString())) - } + access(all) fun buy(name: String, vault: @{FungibleToken.Vault}, to: Address) { + pre { + self.items.containsKey(name) : "Invalid name=".concat(name) + self.owner!.address != to : "You cannot buy your own listing" + } + + let saleItem=self.borrow(name) - if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { - panic("This sale item listing is already expired") - } + if saleItem.salePrice != vault.balance { + panic("Incorrect balance sent in vault. Expected ".concat(saleItem.salePrice.toString()).concat(" got ").concat(vault.balance.toString())) + } - if saleItem.vaultType != vault.getType() { - panic("This item can be baught using ".concat(saleItem.vaultType.identifier).concat(" you have sent in ").concat(vault.getType().identifier)) - } - - let actionResult=self.getTenant().allowedAction(listingType: Type<@FindLeaseMarketSale.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"buy lease for sale"), seller: self.owner!.address, buyer: to) + if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { + panic("This sale item listing is already expired") + } - if !actionResult.allowed { - panic(actionResult.message) - } + if saleItem.vaultType != vault.getType() { + panic("This item can be baught using ".concat(saleItem.vaultType.identifier).concat(" you have sent in ").concat(vault.getType().identifier)) + } + + let actionResult=self.getTenant().allowedAction(listingType: Type<@FindLeaseMarketSale.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"buy lease for sale"), seller: self.owner!.address, buyer: to) - let cuts= self.getTenant().getCuts(name: actionResult.name, listingType: Type<@FindLeaseMarketSale.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType()) - - let ftType=saleItem.vaultType - let owner=saleItem.getSeller() - let leaseInfo= saleItem.toLeaseInfo() - - let soldFor=saleItem.getBalance() - saleItem.setBuyer(to) - let buyer=to - let buyerName=FIND.reverseLookup(buyer) - let profile = FIND.lookup(buyer.toString()) - - saleItem.pointer.move(to: to) - - FindLeaseMarket.pay(tenant:self.getTenant().name, leaseName:name, saleItem: saleItem, vault: <- vault, leaseInfo:leaseInfo, cuts:cuts) - - emit Sale(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: soldFor, status:"sold", vaultType: ftType.identifier, leaseInfo:leaseInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile?.getAvatar() ,endsAt:saleItem.validUntil) - - destroy <- self.items.remove(key: name) - } - - pub fun listForSale(pointer: FindLeaseMarket.AuthLeasePointer, vaultType: Type, directSellPrice:UFix64, validUntil: UFix64?, extraField: {String:AnyStruct}) { - - // ensure it is not a 0 dollar listing - if directSellPrice <= 0.0 { - panic("Listing price should be greater than 0") - } - - if validUntil != nil && validUntil! < Clock.time() { - panic("Valid until is before current time") - } - - // What happends if we relist - let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, price: directSellPrice, validUntil: validUntil, saleItemExtraField:extraField) - - let actionResult=self.getTenant().allowedAction(listingType: Type<@FindLeaseMarketSale.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"list lease for sale"), seller: self.owner!.address, buyer: nil) - - if !actionResult.allowed { - panic(actionResult.message) - } - - let owner=self.owner!.address - emit Sale(tenant: self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "active_listed", vaultType: vaultType.identifier, leaseInfo:saleItem.toLeaseInfo(), buyer: nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) - let old <- self.items[pointer.name] <- saleItem - destroy old - - } - - pub fun delist(_ name: String) { - pre { - self.items.containsKey(name) : "Unknown name lease=".concat(name) - } - - let saleItem <- self.items.remove(key: name)! - - if saleItem.checkPointer() { - let actionResult=self.getTenant().allowedAction(listingType: Type<@FindLeaseMarketSale.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"delist lease for sale"), seller: nil, buyer: nil) - - if !actionResult.allowed { - panic(actionResult.message) - } - let owner=self.owner!.address - emit Sale(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName:FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "cancel", vaultType: saleItem.vaultType.identifier,leaseInfo: saleItem.toLeaseInfo(), buyer:nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) - destroy saleItem - return - } - - let owner=self.owner!.address - if !saleItem.checkPointer() { - emit Sale(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName:FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "cancel", vaultType: saleItem.vaultType.identifier,leaseInfo: nil, buyer:nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) - } else { - emit Sale(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName:FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "cancel", vaultType: saleItem.vaultType.identifier,leaseInfo: saleItem.toLeaseInfo(), buyer:nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) - } - destroy saleItem - } - - pub fun getNameSales(): [String] { - return self.items.keys - } + if !actionResult.allowed { + panic(actionResult.message) + } - pub fun containsNameSale(_ name: String): Bool { - return self.items.containsKey(name) - } - - pub fun borrow(_ name: String): &SaleItem { - return (&self.items[name] as &SaleItem?)! - } - - pub fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} { - pre{ - self.items.containsKey(name) : "This name sale does not exist : ".concat(name) - } - return (&self.items[name] as &SaleItem{FindLeaseMarket.SaleItem}?)! - } - - destroy() { - destroy self.items - } - } - - //Create an empty lease collection that store your leases to a name - pub fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>): @SaleItemCollection { - return <- create SaleItemCollection(tenantCapability) - } - - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>? { - pre{ - FindMarket.getTenantCapability(marketplace) != nil : "Invalid tenant" - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - } - return nil - } - - - init() { - FindLeaseMarket.addSaleItemType(Type<@SaleItem>()) - FindLeaseMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) - } + let cuts= self.getTenant().getCuts(name: actionResult.name, listingType: Type<@FindLeaseMarketSale.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType()) + + let ftType=saleItem.vaultType + let owner=saleItem.getSeller() + let leaseInfo= saleItem.toLeaseInfo() + + let soldFor=saleItem.getBalance() + saleItem.setBuyer(to) + let buyer=to + let buyerName=FIND.reverseLookup(buyer) + let profile = FIND.lookup(buyer.toString()) + + saleItem.pointer.move(to: to) + + FindLeaseMarket.pay(tenant:self.getTenant().name, leaseName:name, saleItem: saleItem, vault: <- vault, leaseInfo:leaseInfo, cuts:cuts) + + emit Sale(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: soldFor, status:"sold", vaultType: ftType.identifier, leaseInfo:leaseInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile?.getAvatar() ,endsAt:saleItem.validUntil) + + destroy <- self.items.remove(key: name) + } + + access(Seller) fun listForSale(pointer: FindLeaseMarket.AuthLeasePointer, vaultType: Type, directSellPrice:UFix64, validUntil: UFix64?, extraField: {String:AnyStruct}) { + Debug.log("foo") + + // ensure it is not a 0 dollar listing + if directSellPrice <= 0.0 { + panic("Listing price should be greater than 0") + } + + if validUntil != nil && validUntil! < Clock.time() { + panic("Valid until is before current time") + } + + // What happends if we relist + let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, price: directSellPrice, validUntil: validUntil, saleItemExtraField:extraField) + + let actionResult=self.getTenant().allowedAction(listingType: Type<@FindLeaseMarketSale.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name:"list lease for sale"), seller: self.owner!.address, buyer: nil) + + if !actionResult.allowed { + panic(actionResult.message) + } + + let owner=self.owner!.address + emit Sale(tenant: self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "active_listed", vaultType: vaultType.identifier, leaseInfo:saleItem.toLeaseInfo(), buyer: nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) + let old <- self.items[pointer.name] <- saleItem + destroy old + + } + + access(Seller) fun delist(_ name: String) { + pre { + self.items.containsKey(name) : "Unknown name lease=".concat(name) + } + + let saleItem <- self.items.remove(key: name)! + + if saleItem.checkPointer() { + let actionResult=self.getTenant().allowedAction(listingType: Type<@FindLeaseMarketSale.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:false, name:"delist lease for sale"), seller: nil, buyer: nil) + + if !actionResult.allowed { + panic(actionResult.message) + } + let owner=self.owner!.address + emit Sale(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName:FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "cancel", vaultType: saleItem.vaultType.identifier,leaseInfo: saleItem.toLeaseInfo(), buyer:nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) + destroy saleItem + return + } + + let owner=self.owner!.address + if !saleItem.checkPointer() { + emit Sale(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName:FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "cancel", vaultType: saleItem.vaultType.identifier,leaseInfo: nil, buyer:nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) + } else { + emit Sale(tenant:self.getTenant().name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName:FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "cancel", vaultType: saleItem.vaultType.identifier,leaseInfo: saleItem.toLeaseInfo(), buyer:nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) + } + destroy saleItem + } + + access(all) fun getNameSales(): [String] { + return self.items.keys + } + + access(all) fun containsNameSale(_ name: String): Bool { + return self.items.containsKey(name) + } + + access(all) fun borrow(_ name: String): &SaleItem { + return (&self.items[name])! + } + + access(all) fun borrowSaleItem(_ name: String) : &{FindLeaseMarket.SaleItem} { + pre{ + self.items.containsKey(name) : "This name sale does not exist : ".concat(name) + } + return (&self.items[name])! + } + + } + + //Create an empty lease collection that store your leases to a name + access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>) : @SaleItemCollection { + return <- create SaleItemCollection(tenantCapability) + } + + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>()))! + } + return nil + } + + init() { + FindLeaseMarket.addSaleItemType(Type<@SaleItem>()) + FindLeaseMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) + } } diff --git a/contracts/FindLegacyCollectionc.cdc b/contracts/FindLegacyCollectionc.cdc index 11512659..b44f72d6 100644 --- a/contracts/FindLegacyCollectionc.cdc +++ b/contracts/FindLegacyCollectionc.cdc @@ -2,7 +2,7 @@ This is a legacy contract that we will use as a last resort to fetch data that is not present in either the Metadata form or from the Alchemy onChain Registry */ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" +import "NonFungibleToken" //mainnet import Beam from 0x86b4a0010a71cfc3 @@ -37,8 +37,8 @@ import Art from 0xd796ff17107bbff6 import Marketplace from 0xd796ff17107bbff6 import Flovatar from 0x921ea449dffec68a import FlovatarMarketplace from 0x921ea449dffec68a -import CharityNFT from "../contracts/CharityNFT.cdc" -import FIND from "../contracts/FIND.cdc" +import "CharityNFT" +import "FIND" import MatrixWorldAssetsNFT from 0xf20df769e658c257 @@ -61,13 +61,13 @@ import Momentables from 0x9d21537544d9123d import ZeedzINO from 0x62b3063fbe672fc8 import PartyMansionDrinksContract from 0x34f2bf4a80bb0f69 -pub contract FindLegacyCollectionc { +access(all) contract FindLegacyCollectionc { - pub struct MetadataCollections { + access(all) struct MetadataCollections { - pub let items: {String : MetadataCollectionItem} - pub let collections: {String : [String]} - pub let curatedCollections: {String : [String]} + access(all) let items: {String : MetadataCollectionItem} + access(all) let collections: {String : [String]} + access(all) let curatedCollections: {String : [String]} init(items: {String : MetadataCollectionItem}, collections: {String : [String]}, curatedCollections: {String: [String]}) { self.items=items @@ -77,9 +77,9 @@ pub contract FindLegacyCollectionc { } - pub struct MetadataCollection{ - pub let type: String - pub let items: [MetadataCollectionItem] + access(all) struct MetadataCollection{ + access(all) let type: String + access(all) let items: [MetadataCollectionItem] init(type:String, items: [MetadataCollectionItem]) { self.type=type @@ -88,15 +88,15 @@ pub contract FindLegacyCollectionc { } - pub struct MetadataCollectionItem { - pub let id:UInt64 - pub let name: String - pub let image: String - pub let url: String - pub let listPrice: UFix64? - pub let listToken: String? - pub let contentType:String - pub let rarity:String + access(all) struct MetadataCollectionItem { + access(all) let id:UInt64 + access(all) let name: String + access(all) let image: String + access(all) let url: String + access(all) let listPrice: UFix64? + access(all) let listToken: String? + access(all) let contentType:String + access(all) let rarity:String init(id:UInt64, name:String, image:String, url:String, listPrice: UFix64?, listToken:String?, contentType: String, rarity: String) { @@ -111,13 +111,13 @@ pub contract FindLegacyCollectionc { } } - pub fun getNFTs(ownerAddress: Address, ids: {String:[UInt64]}): [MetadataCollectionItem] { + access(all) getNFTs(ownerAddress: Address, ids: {String:[UInt64]}): [MetadataCollectionItem] { return [] } - pub fun getNFTIDs(ownerAddress: Address): {String: [UInt64]} { + access(all) getNFTIDs(ownerAddress: Address): {String: [UInt64]} { let account = getAccount(ownerAddress) let ids: {String: [UInt64]} = {} @@ -142,7 +142,7 @@ pub contract FindLegacyCollectionc { ids["Versus"]=versusArtCap.borrow()!.getIDs() } - let goobersCap = account.getCapability<&GooberXContract.Collection{NonFungibleToken.CollectionPublic, GooberXContract.GooberCollectionPublic}>(GooberXContract.CollectionPublicPath) + let goobersCap = account.getCapability<&GooberXContract.Collection{NonFungibleToken.Collection, GooberXContract.GooberCollectionPublic}>(GooberXContract.CollectionPublicPath) if goobersCap.check() { ids["Gooberz"] = goobersCap.borrow()!.getIDs() } @@ -204,7 +204,7 @@ pub contract FindLegacyCollectionc { ids["JambbVoucher"] = voucherCap.borrow()!.getIDs() } - let mwaCap = account.getCapability<&{MatrixWorldAssetsNFT.Metadata, NonFungibleToken.CollectionPublic}>(MatrixWorldAssetsNFT.collectionPublicPath) + let mwaCap = account.getCapability<&{MatrixWorldAssetsNFT.Metadata, NonFungibleToken.Collection}>(MatrixWorldAssetsNFT.collectionPublicPath) if mwaCap.check() { ids["MatrixWorldAssets"] = mwaCap.borrow()!.getIDs() } @@ -229,7 +229,7 @@ pub contract FindLegacyCollectionc { ids["Evolution"] = evolutionCap.borrow()!.getIDs() } - let geniaceCap = account.getCapability<&GeniaceNFT.Collection{NonFungibleToken.CollectionPublic, GeniaceNFT.GeniaceNFTCollectionPublic}>(GeniaceNFT.CollectionPublicPath) + let geniaceCap = account.getCapability<&GeniaceNFT.Collection{NonFungibleToken.Collection, GeniaceNFT.GeniaceNFTCollectionPublic}>(GeniaceNFT.CollectionPublicPath) if geniaceCap.check() { ids["Geniace"] = geniaceCap.borrow()!.getIDs() } @@ -259,17 +259,17 @@ pub contract FindLegacyCollectionc { ids["GoatedGoatsTraitVoucher"] = goatsTraitVoucherCap.borrow()!.getIDs() } - let goatsCap = account.getCapability<&{MetadataViews.ResolverCollection}>(GoatedGoats.CollectionPublicPath) + let goatsCap = account.getCapability<&{ViewResolver.ResolverCollection}>(GoatedGoats.CollectionPublicPath) if goatsCap.check() { ids["GoatedGoats"] = goatsCap.borrow()!.getIDs() } - let goatsTraitCap = account.getCapability<&{MetadataViews.ResolverCollection}>(GoatedGoatsTrait.CollectionPublicPath) + let goatsTraitCap = account.getCapability<&{ViewResolver.ResolverCollection}>(GoatedGoatsTrait.CollectionPublicPath) if goatsTraitCap.check() { ids["GoatedGoatsTrait"] = goatsTraitCap.borrow()!.getIDs() } - let goatsTraitPackCap = account.getCapability<&{MetadataViews.ResolverCollection}>(GoatedGoatsTraitPack.CollectionPublicPath) + let goatsTraitPackCap = account.getCapability<&{ViewResolver.ResolverCollection}>(GoatedGoatsTraitPack.CollectionPublicPath) if goatsTraitPackCap.check() { ids["GoatedGoatsTraitPack"] = goatsTraitPackCap.borrow()!.getIDs() } @@ -290,17 +290,17 @@ pub contract FindLegacyCollectionc { ids["mynft"] = mynftCap.borrow()!.getIDs() } - let neoAvatarCap = account.getCapability<&{MetadataViews.ResolverCollection}>(NeoAvatar.CollectionPublicPath) + let neoAvatarCap = account.getCapability<&{ViewResolver.ResolverCollection}>(NeoAvatar.CollectionPublicPath) if neoAvatarCap.check() { ids["NeoAvatar"] = neoAvatarCap.borrow()!.getIDs() } - let neoVoucherCap = account.getCapability<&{MetadataViews.ResolverCollection}>(NeoVoucher.CollectionPublicPath) + let neoVoucherCap = account.getCapability<&{ViewResolver.ResolverCollection}>(NeoVoucher.CollectionPublicPath) if neoVoucherCap.check() { ids["NeoVoucher"] = neoVoucherCap.borrow()!.getIDs() } - let neoMemberCap = account.getCapability<&{MetadataViews.ResolverCollection}>(NeoVoucher.CollectionPublicPath) + let neoMemberCap = account.getCapability<&{ViewResolver.ResolverCollection}>(NeoVoucher.CollectionPublicPath) if neoMemberCap.check() { ids["NeoMember"] = neoVoucherCap.borrow()!.getIDs() } @@ -310,7 +310,7 @@ pub contract FindLegacyCollectionc { ids["BarterYardClubPack"] = barterYardPackCap.borrow()!.getIDs() } - let byCap = account.getCapability<&{MetadataViews.ResolverCollection}>(BarterYardClubWerewolf.CollectionPublicPath) + let byCap = account.getCapability<&{ViewResolver.ResolverCollection}>(BarterYardClubWerewolf.CollectionPublicPath) if byCap.check() { ids["BarterYardClubWerewolf"] = byCap.borrow()!.getIDs() } @@ -332,7 +332,7 @@ pub contract FindLegacyCollectionc { -pub fun main(user: String) : MetadataCollections? { +access(all) main(user: String) : MetadataCollections? { let resolvingAddress = FIND.resolve(user) if resolvingAddress == nil { @@ -462,7 +462,7 @@ pub fun main(user: String) : MetadataCollections? { let partyMansion: [String] = [] - let goobersCap = account.getCapability<&GooberXContract.Collection{NonFungibleToken.CollectionPublic, GooberXContract.GooberCollectionPublic}>(GooberXContract.CollectionPublicPath) + let goobersCap = account.getCapability<&GooberXContract.Collection{NonFungibleToken.Collection, GooberXContract.GooberCollectionPublic}>(GooberXContract.CollectionPublicPath) if goobersCap.check() { let goobers = goobersCap.borrow()!.listUsersGoobers() for id in goobers.keys { @@ -936,7 +936,7 @@ pub fun main(user: String) : MetadataCollections? { } - let matrixworldAsset = account.getCapability<&{MatrixWorldAssetsNFT.Metadata, NonFungibleToken.CollectionPublic}>(MatrixWorldAssetsNFT.collectionPublicPath) + let matrixworldAsset = account.getCapability<&{MatrixWorldAssetsNFT.Metadata, NonFungibleToken.Collection}>(MatrixWorldAssetsNFT.collectionPublicPath) if matrixworldAsset.check() { let collection = matrixworldAsset.borrow()! for id in collection.getIDs() { @@ -1059,7 +1059,7 @@ pub fun main(user: String) : MetadataCollections? { } - let geniaceCap = account.getCapability<&GeniaceNFT.Collection{NonFungibleToken.CollectionPublic, GeniaceNFT.GeniaceNFTCollectionPublic}>(GeniaceNFT.CollectionPublicPath) + let geniaceCap = account.getCapability<&GeniaceNFT.Collection{NonFungibleToken.Collection, GeniaceNFT.GeniaceNFTCollectionPublic}>(GeniaceNFT.CollectionPublicPath) if geniaceCap.check() { let geniace=geniaceCap.borrow()! let nfts = geniace.getIDs() @@ -1561,9 +1561,9 @@ return MetadataCollections(items: resultMap, collections:results, curatedCollect } //This uses a view from Neo until we agree on another for ExternalDomainViewUrl -pub fun getItemForMetadataStandard(path: PublicPath, account:PublicAccount, externalFixedUrl: String) : [MetadataCollectionItem] { +access(all) getItemForMetadataStandard(path: PublicPath, account:PublicAccount, externalFixedUrl: String) : [MetadataCollectionItem] { let items: [MetadataCollectionItem] = [] - let resolverCollectionCap= account.getCapability<&{MetadataViews.ResolverCollection}>(path) + let resolverCollectionCap= account.getCapability<&{ViewResolver.ResolverCollection}>(path) if resolverCollectionCap.check() { let collection = resolverCollectionCap.borrow()! for id in collection.getIDs() { diff --git a/contracts/FindLostAndFoundWrapper.cdc b/contracts/FindLostAndFoundWrapper.cdc index f92879d6..46e8dbf9 100644 --- a/contracts/FindLostAndFoundWrapper.cdc +++ b/contracts/FindLostAndFoundWrapper.cdc @@ -1,21 +1,23 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import FlowToken from "./standard/FlowToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import LostAndFound from "./standard/LostAndFound.cdc" -import LostAndFoundHelper from "./standard/LostAndFoundHelper.cdc" -import FlowStorageFees from "./standard/FlowStorageFees.cdc" -import FIND from "./FIND.cdc" -import FindViews from "./FindViews.cdc" - - -pub contract FindLostAndFoundWrapper { - - pub event NFTDeposited(receiver: Address, receiverName: String?, sender: Address?, senderName: String?, type: String, id: UInt64?, uuid: UInt64?, memo: String?, name: String?, description: String?, thumbnail: String?, collectionName: String?, collectionImage: String?) - pub event UserStorageSubsidized(receiver: Address, receiverName: String?, sender: Address, senderName: String?, forUUID: UInt64, storageFee: UFix64) - pub event TicketDeposited(receiver: Address, receiverName: String?, sender: Address, senderName: String?, ticketID: UInt64, type: String, id: UInt64, uuid: UInt64?, memo: String?, name: String?, description: String?, thumbnail: String?, collectionName: String?, collectionImage: String?, flowStorageFee: UFix64) - pub event TicketRedeemed(receiver: Address, receiverName: String?, ticketID: UInt64, type: String) - pub event TicketRedeemFailed(receiver: Address, receiverName: String?, ticketID: UInt64, type: String, remark: String) +import "FungibleToken" +import "FlowToken" +import "NonFungibleToken" +import "MetadataViews" +import "ViewResolver" +import "LostAndFound" +import "LostAndFoundHelper" +import "FlowStorageFees" +import "FIND" +import "Debug" +import "FindViews" + + +access(all) contract FindLostAndFoundWrapper { + // Events + access(all) event NFTDeposited(receiver: Address, receiverName: String?, sender: Address?, senderName: String?, type: String, id: UInt64?, uuid: UInt64?, memo: String?, name: String?, description: String?, thumbnail: String?, collectionName: String?, collectionImage: String?) + access(all) event UserStorageSubsidized(receiver: Address, receiverName: String?, sender: Address, senderName: String?, forUUID: UInt64, storageFee: UFix64) + access(all) event TicketDeposited(receiver: Address, receiverName: String?, sender: Address, senderName: String?, ticketID: UInt64, type: String, id: UInt64, uuid: UInt64?, memo: String?, name: String?, description: String?, thumbnail: String?, collectionName: String?, collectionImage: String?, flowStorageFee: UFix64) + access(all) event TicketRedeemed(receiver: Address, receiverName: String?, ticketID: UInt64, type: String) + access(all) event TicketRedeemFailed(receiver: Address, receiverName: String?, ticketID: UInt64, type: String, remark: String) // check if they have that storage // npm module for NFT catalog, that can init the storage of the users. @@ -25,16 +27,16 @@ pub contract FindLostAndFoundWrapper { // Mapping of vault uuid to vault. // A method to get around passing the "Vault" reference to Lost and Found to ensure it cannot be hacked. // All vaults should be destroyed after deposit function - pub let storagePaymentVaults : @{UInt64 : FungibleToken.Vault} + access(all) let storagePaymentVaults : @{UInt64 : {FungibleToken.Vault}} // Deposit - pub fun depositNFT( + access(all) fun depositNFT( receiver: Address, collectionPublicPath: PublicPath, item: FindViews.AuthNFTPointer, memo: String?, - storagePayment: &FungibleToken.Vault, - flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}> , + storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, + flowTokenRepayment: Capability<&FlowToken.Vault> , subsidizeReceiverStorage: Bool ) : UInt64? { @@ -50,15 +52,15 @@ pub contract FindLostAndFoundWrapper { let type = item.getItemType() // calculate the required storage and check sufficient balance - let senderStorageBeforeSend = getAccount(sender).storageUsed + let senderStorageBeforeSend = getAccount(sender).storage.used let item <- item.withdraw() - let requiredStorage = senderStorageBeforeSend - getAccount(sender).storageUsed - let receiverAvailableStorage = getAccount(receiverAddress).storageCapacity - getAccount(receiverAddress).storageUsed + let requiredStorage = senderStorageBeforeSend - getAccount(sender).storage.used + let receiverAvailableStorage = getAccount(receiverAddress).storage.capacity- getAccount(receiverAddress).storage.used // Try to send before using Lost & FIND - let receiverCap = getAccount(receiverAddress).getCapability<&{NonFungibleToken.Receiver}>(collectionPublicPath) + let receiverCap = getAccount(receiverAddress).capabilities.get<&{NonFungibleToken.Receiver}>(collectionPublicPath) if receiverCap.check() { // If the receiver has sufficient storage, then subsidize it var readyToSend = true @@ -76,7 +78,7 @@ pub contract FindLostAndFoundWrapper { } } - let collectionPublicCap = getAccount(receiverAddress).getCapability<&{NonFungibleToken.CollectionPublic}>(collectionPublicPath) + let collectionPublicCap = getAccount(receiverAddress).capabilities.get<&{NonFungibleToken.Collection}>(collectionPublicPath) if collectionPublicCap.check() { // If the receiver has sufficient storage, then subsidize it var readyToSend = true @@ -89,18 +91,18 @@ pub contract FindLostAndFoundWrapper { if readyToSend { collectionPublicCap.borrow()!.deposit(token: <- item) - emit NFTDeposited(receiver: receiverCap.address, receiverName: FIND.reverseLookup(receiverAddress), sender: sender, senderName: senderName, type: type.identifier, id: id, uuid: uuid, memo: memo, name: display.name, description: display.description, thumbnail: display.thumbnail.uri(), collectionName: collectionDisplay?.name, collectionImage: collectionDisplay?.squareImage?.file?.uri()) + emit NFTDeposited(receiver: receiverAddress, receiverName: FIND.reverseLookup(receiverAddress), sender: sender, senderName: senderName, type: type.identifier, id: id, uuid: uuid, memo: memo, name: display.name, description: display.description, thumbnail: display.thumbnail.uri(), collectionName: collectionDisplay?.name, collectionImage: collectionDisplay?.squareImage?.file?.uri()) return nil } } // Calculate storage fees required let estimate <- LostAndFound.estimateDeposit( - redeemer: receiverAddress, - item: <- item, - memo: memo, - display: display - ) + redeemer: receiverAddress, + item: <- item, + memo: memo, + display: display + ) // we add 0.00005 here just incase it falls below // extra fees will be deposited back to the sender let vault <- storagePayment.withdraw(amount: estimate.storageFee + 0.00005) @@ -129,14 +131,10 @@ pub contract FindLostAndFoundWrapper { } // Redeem - pub fun redeemNFT(type: Type, ticketID: UInt64, receiverAddress: Address, collectionPublicPath: PublicPath) { + access(all) fun redeemNFT(type: Type, ticketID: UInt64, receiverAddress: Address, collectionPublicPath: PublicPath) { - let metadataViewsCap = getAccount(receiverAddress).getCapability<&{MetadataViews.ResolverCollection}>(collectionPublicPath) - - let receiverCap = getAccount(receiverAddress).getCapability<&{NonFungibleToken.Receiver}>(collectionPublicPath) - let collectionPublicCap = getAccount(receiverAddress).getCapability<&{NonFungibleToken.CollectionPublic}>(collectionPublicPath) - - if !receiverCap.check() && !collectionPublicCap.check() { + let cap= getAccount(receiverAddress).capabilities.get<&{NonFungibleToken.Collection}>(collectionPublicPath) + if !cap.check() { emit TicketRedeemFailed(receiver: receiverAddress, receiverName: FIND.reverseLookup(receiverAddress), ticketID: ticketID, type: type.identifier, remark: "invalid capability") return } @@ -151,28 +149,23 @@ pub contract FindLostAndFoundWrapper { let memo = ticket.memo // if receiverCap is valid, pass that in, otherwise pass collectionPublicCap - shelf.redeem(type: type, ticketID: ticketID, receiver: receiverCap.check() ? receiverCap : collectionPublicCap) - var item : FindViews.ViewReadPointer? = nil - var display : MetadataViews.Display? = nil - var collectionDisplay : MetadataViews.NFTCollectionDisplay? = nil - - if metadataViewsCap.check() { - item = FindViews.ViewReadPointer(cap: metadataViewsCap, id: nftID) - display = item!.getDisplay() - collectionDisplay = MetadataViews.getNFTCollectionDisplay(item!.getViewResolver()) - } + shelf.redeem(type: type, ticketID: ticketID, receiver: cap) + + let viewResolver=cap.borrow()!.borrowNFT(nftID)! + let display = MetadataViews.getDisplay(viewResolver) + let collectionDisplay= MetadataViews.getNFTCollectionDisplay(viewResolver) var senderName : String? = nil if sender != nil { senderName = FIND.reverseLookup(sender!) } - emit NFTDeposited(receiver: receiverAddress, receiverName: FIND.reverseLookup(receiverAddress), sender: sender, senderName: senderName, type: type.identifier, id: nftID, uuid: item?.uuid, memo: memo, name: display?.name, description: display?.description, thumbnail: display?.thumbnail?.uri(), collectionName: collectionDisplay?.name, collectionImage: collectionDisplay?.squareImage?.file?.uri()) + emit NFTDeposited(receiver: receiverAddress, receiverName: FIND.reverseLookup(receiverAddress), sender: sender, senderName: senderName, type: type.identifier, id: nftID, uuid: viewResolver.uuid, memo: memo, name: display?.name, description: display?.description, thumbnail: display?.thumbnail?.uri(), collectionName: collectionDisplay?.name, collectionImage: collectionDisplay?.squareImage?.file?.uri()) emit TicketRedeemed(receiver: receiverAddress, receiverName: FIND.reverseLookup(receiverAddress), ticketID: ticketID, type: type.identifier) } // Check - pub fun getTickets(user: Address, specificType: Type?) : {String : [LostAndFoundHelper.Ticket]} { + access(all) fun getTickets(user: Address, specificType: Type?) : {String : [LostAndFoundHelper.Ticket]} { let allTickets : {String : [LostAndFoundHelper.Ticket]} = {} @@ -192,7 +185,7 @@ pub contract FindLostAndFoundWrapper { let bin = shelf.borrowBin(type: type)! let ids = bin.getTicketIDs() for id in ids { - let ticket = bin.borrowTicket(id: id)! + let ticket = bin.borrowTicket(id: id)! ticketInfo.append(LostAndFoundHelper.Ticket(ticket, id: id)) } allTickets[type.identifier] = ticketInfo @@ -201,7 +194,7 @@ pub contract FindLostAndFoundWrapper { return allTickets } - pub fun getTicketIDs(user: Address, specificType: Type?) : {String : [UInt64]} { + access(all) fun getTicketIDs(user: Address, specificType: Type?) : {String : [UInt64]} { let allTickets : {String : [UInt64]} = {} @@ -228,7 +221,7 @@ pub contract FindLostAndFoundWrapper { } // Check for all types that are in Lost and found which are NFTs - pub fun getSpecificRedeemableTypes(user: Address, specificType: Type?) : [Type] { + access(all) fun getSpecificRedeemableTypes(user: Address, specificType: Type?) : [Type] { let allTypes : [Type] = [] if specificType != nil { for type in LostAndFound.getRedeemableTypes(user) { @@ -241,13 +234,13 @@ pub contract FindLostAndFoundWrapper { } // Helper function - access(contract) fun depositVault(_ vault: @FungibleToken.Vault) : &FungibleToken.Vault { + access(contract) fun depositVault(_ vault: @{FungibleToken.Vault}) : auth (FungibleToken.Withdraw) &{FungibleToken.Vault} { let uuid = vault.uuid self.storagePaymentVaults[uuid] <-! vault - return (&self.storagePaymentVaults[uuid] as &FungibleToken.Vault?)! + return (&self.storagePaymentVaults[uuid])! } - access(contract) fun destroyVault(_ uuid: UInt64, cap: Capability<&FlowToken.Vault{FungibleToken.Receiver}>) { + access(contract) fun destroyVault(_ uuid: UInt64, cap: Capability<&{FungibleToken.Receiver}>) { let vault <- self.storagePaymentVaults.remove(key: uuid) ?? panic("Invalid vault UUID. UUID: ".concat(uuid.toString())) if vault.balance != nil { let ref = cap.borrow() ?? panic("The flow repayment capability is not valid") @@ -257,10 +250,11 @@ pub contract FindLostAndFoundWrapper { destroy vault } - access(contract) fun subsidizeUserStorage(requiredStorage: UInt64, receiverAvailableStorage: UInt64, receiver: Address, vault: &FungibleToken.Vault, sender: Address, uuid: UInt64) : Bool { + access(contract) fun subsidizeUserStorage(requiredStorage: UInt64, receiverAvailableStorage: UInt64, receiver: Address, vault: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, sender: Address, uuid: UInt64) : Bool { let subsidizeCapacity = requiredStorage - receiverAvailableStorage let subsidizeAmount = FlowStorageFees.storageCapacityToFlow(FlowStorageFees.convertUInt64StorageBytesToUFix64Megabytes(subsidizeCapacity)) - let flowReceiverCap = getAccount(receiver).getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let flowReceiverCap = getAccount(receiver).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + if !flowReceiverCap.check() { return false } @@ -279,4 +273,4 @@ pub contract FindLostAndFoundWrapper { } } - + diff --git a/contracts/FindMarket.cdc b/contracts/FindMarket.cdc index a0ae385d..12a18077 100644 --- a/contracts/FindMarket.cdc +++ b/contracts/FindMarket.cdc @@ -1,16 +1,18 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import Profile from "./Profile.cdc" -import Clock from "./Clock.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FindRulesCache from "../contracts/FindRulesCache.cdc" -import FindMarketCut from "../contracts/FindMarketCut.cdc" -import FindMarketCutStruct from "../contracts/FindMarketCutStruct.cdc" -import FindUtils from "../contracts/FindUtils.cdc" -import FungibleTokenSwitchboard from "../contracts/standard/FungibleTokenSwitchboard.cdc" -import TokenForwarding from "../contracts/standard/TokenForwarding.cdc" - -pub contract FindMarket { +import "FungibleToken" +import "MetadataViews" +import "Profile" +import "Clock" +import "FTRegistry" +import "FindRulesCache" +import "FindMarketCut" +import "FindMarketCutStruct" +import "FindUtils" +import "ViewResolver" +import "FungibleTokenSwitchboard" +import "TokenForwarding" + +access(all) contract FindMarket { + // Variables access(account) let pathMap : {String: String} access(account) let listingName : {String: String} access(contract) let saleItemTypes : [Type] @@ -18,29 +20,28 @@ pub contract FindMarket { access(contract) let marketBidTypes : [Type] access(contract) let marketBidCollectionTypes : [Type] - pub event RoyaltyPaid(tenant:String, id: UInt64, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, nft:NFTInfo) - pub event RoyaltyCouldNotBePaid(tenant:String, id: UInt64, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, nft:NFTInfo, residualAddress: Address) - pub event FindBlockRules(tenant: String, ruleName: String, ftTypes:[String], nftTypes:[String], listingTypes:[String], status:String) - pub event TenantAllowRules(tenant: String, ruleName: String, ftTypes:[String], nftTypes:[String], listingTypes:[String], status:String) - pub event FindCutRules(tenant: String, ruleName: String, cut:UFix64, ftTypes:[String], nftTypes:[String], listingTypes:[String], status:String) - pub event FindTenantRemoved(tenant: String, address: Address) + // Events + access(all) event RoyaltyPaid(tenant:String, id: UInt64, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, nft:NFTInfo) + access(all) event RoyaltyCouldNotBePaid(tenant:String, id: UInt64, saleID: UInt64, address:Address, findName:String?, royaltyName:String, amount: UFix64, vaultType:String, nft:NFTInfo, residualAddress: Address) + access(all) event FindBlockRules(tenant: String, ruleName: String, ftTypes:[String], nftTypes:[String], listingTypes:[String], status:String) + access(all) event TenantAllowRules(tenant: String, ruleName: String, ftTypes:[String], nftTypes:[String], listingTypes:[String], status:String) + access(all) event FindCutRules(tenant: String, ruleName: String, cut:UFix64, ftTypes:[String], nftTypes:[String], listingTypes:[String], status:String) + access(all) event FindTenantRemoved(tenant: String, address: Address) - //Residual Royalty - pub var residualAddress : Address + // Residual Royalty + access(all) var residualAddress : Address // Tenant information - pub let TenantClientPublicPath: PublicPath - pub let TenantClientStoragePath: StoragePath - + access(all) let TenantClientPublicPath: PublicPath + access(all) let TenantClientStoragePath: StoragePath access(contract) let tenantPathPrefix :String - access(account) let tenantNameAddress : {String:Address} access(account) let tenantAddressName : {Address:String} // Deprecated in testnet - pub struct TenantCuts { - pub let findCut:MetadataViews.Royalty? - pub let tenantCut:MetadataViews.Royalty? + access(all) struct TenantCuts { + access(all) let findCut:MetadataViews.Royalty? + access(all) let tenantCut:MetadataViews.Royalty? init(findCut:MetadataViews.Royalty?, tenantCut:MetadataViews.Royalty?) { self.findCut=findCut @@ -49,10 +50,10 @@ pub contract FindMarket { } // Deprecated in testnet - pub struct ActionResult { - pub let allowed:Bool - pub let message:String - pub let name:String + access(all) struct ActionResult { + access(all) let allowed:Bool + access(all) let message:String + access(all) let name:String init(allowed:Bool, message:String, name:String) { self.allowed=allowed @@ -62,7 +63,7 @@ pub contract FindMarket { } // ======================================== - pub fun getPublicPath(_ type: Type, name:String) : PublicPath { + access(all) fun getPublicPath(_ type: Type, name:String) : PublicPath { let pathPrefix=self.pathMap[type.identifier]! let path=pathPrefix.concat("_").concat(name) @@ -70,36 +71,36 @@ pub contract FindMarket { return PublicPath(identifier: path) ?? panic("Cannot find public path for type ".concat(type.identifier)) } - pub fun getStoragePath(_ type: Type, name:String) : StoragePath { + access(all) fun getStoragePath(_ type: Type, name:String) : StoragePath { let pathPrefix=self.pathMap[type.identifier]! let path=pathPrefix.concat("_").concat(name) return StoragePath(identifier: path) ?? panic("Cannot find public path for type ".concat(type.identifier)) } - pub fun getFindTenantAddress() : Address { + access(all) fun getFindTenantAddress() : Address { return FindMarket.account.address } /* Get Tenant */ - pub fun getTenant(_ tenant: Address) : &FindMarket.Tenant{FindMarket.TenantPublic} { + access(all) fun getTenant(_ tenant: Address) : &{FindMarket.TenantPublic} { return FindMarket.getTenantCapability(tenant)!.borrow()! } - pub fun getSaleItemTypes() : [Type] { + access(all) fun getSaleItemTypes() : [Type] { return self.saleItemTypes } /* Get SaleItemCollections */ - pub fun getSaleItemCollectionTypes() : [Type] { + access(all) fun getSaleItemCollectionTypes() : [Type] { return self.saleItemCollectionTypes } - pub fun getSaleItemCollectionCapabilities(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindMarket.SaleItemCollectionPublic}>] { + access(all) fun getSaleItemCollectionCapabilities(tenantRef: &{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindMarket.SaleItemCollectionPublic}>] { var caps : [Capability<&{FindMarket.SaleItemCollectionPublic}>] = [] for type in self.getSaleItemCollectionTypes() { if type != nil { - let cap = getAccount(address).getCapability<&{FindMarket.SaleItemCollectionPublic}>(tenantRef.getPublicPath(type)) + let cap = getAccount(address).capabilities.get<&{FindMarket.SaleItemCollectionPublic}>(tenantRef.getPublicPath(type)) if cap.check() { caps.append(cap) } @@ -108,30 +109,32 @@ pub contract FindMarket { return caps } - pub fun getSaleItemCollectionCapability(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindMarket.SaleItemCollectionPublic}> { + access(all) fun getSaleItemCollectionCapability(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindMarket.SaleItemCollectionPublic}>? { for type in self.getSaleItemCollectionTypes() { if self.getMarketOptionFromType(type) == marketOption{ - let cap = getAccount(address).getCapability<&{FindMarket.SaleItemCollectionPublic}>(tenantRef.getPublicPath(type)) - return cap + let path=tenantRef.getPublicPath(type) + return getAccount(address).capabilities.get<&{FindMarket.SaleItemCollectionPublic}>(path) } } + panic("Cannot find market option : ".concat(marketOption)) } /* Get Sale Reports and Sale Item */ - pub fun assertOperationValid(tenant: Address, address: Address, marketOption: String, id:UInt64) : &{SaleItem} { + access(all) fun assertOperationValid(tenant: Address, address: Address, marketOption: String, id:UInt64) : &{SaleItem} { let tenantRef=self.getTenant(tenant) let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - let optRef = collectionCap.borrow() + + let optRef = collectionCap?.borrow() if optRef == nil { panic("Account not properly set up, cannot borrow sale item collection") } let ref=optRef! - let item=ref.borrowSaleItem(id) + let item=ref!.borrowSaleItem(id)! if !item.checkPointer() { panic("this is a ghost listing. SaleItem id : ".concat(id.toString())) } @@ -141,15 +144,15 @@ pub contract FindMarket { // Get Royalties Changed Items - pub fun getRoyaltiesChangedIds(tenant:Address, address: Address) : {String : [UInt64]} { + access(all) fun getRoyaltiesChangedIds(tenant:Address, address: Address) : {String : [UInt64]} { let tenantRef = self.getTenant(tenant) var report : {String : [UInt64]} = {} for type in self.getSaleItemCollectionTypes() { let marketOption = self.getMarketOptionFromType(type) let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - if let optRef = collectionCap.borrow() { - let ids = optRef.getRoyaltyChangedIds() + if let optRef = collectionCap?.borrow() { + let ids = optRef!.getRoyaltyChangedIds() if ids.length > 0 { report[marketOption] = ids } @@ -158,7 +161,7 @@ pub contract FindMarket { return report } - pub fun getRoyaltiesChangedItems(tenant:Address, address: Address) : {String : FindMarket.SaleItemCollectionReport} { + access(all) fun getRoyaltiesChangedItems(tenant:Address, address: Address) : {String : FindMarket.SaleItemCollectionReport} { let tenantRef = self.getTenant(tenant) var report : {String : FindMarket.SaleItemCollectionReport} = {} for type in self.getSaleItemCollectionTypes() { @@ -172,8 +175,7 @@ pub contract FindMarket { } /* Get Sale Reports and Sale Item */ - pub fun getSaleInformation(tenant: Address, address: Address, marketOption: String, id:UInt64, getNFTInfo: Bool) : FindMarket.SaleItemInformation? { - + access(all) fun getSaleInformation(tenant: Address, address: Address, marketOption: String, id:UInt64, getNFTInfo: Bool) : FindMarket.SaleItemInformation? { let tenantRef=self.getTenant(tenant) let info = self.checkSaleInformation(tenantRef: tenantRef, marketOption:marketOption, address: address, itemId: id, getGhost: false, getNFTInfo: getNFTInfo, getRoyaltyChanged: true ) if info.items.length > 0 { @@ -182,7 +184,7 @@ pub contract FindMarket { return nil } - pub fun getSaleItemReport(tenant:Address, address: Address, getNFTInfo: Bool) : {String : FindMarket.SaleItemCollectionReport} { + access(all) fun getSaleItemReport(tenant:Address, address: Address, getNFTInfo: Bool) : {String : FindMarket.SaleItemCollectionReport} { let tenantRef = self.getTenant(tenant) var report : {String : FindMarket.SaleItemCollectionReport} = {} for type in self.getSaleItemCollectionTypes() { @@ -195,7 +197,7 @@ pub contract FindMarket { return report } - pub fun getSaleItems(tenant:Address, address: Address, id: UInt64, getNFTInfo: Bool) : {String : FindMarket.SaleItemCollectionReport} { + access(all) fun getSaleItems(tenant:Address, address: Address, id: UInt64, getNFTInfo: Bool) : {String : FindMarket.SaleItemCollectionReport} { let tenantRef = self.getTenant(tenant) var report : {String : FindMarket.SaleItemCollectionReport} = {} for type in self.getSaleItemCollectionTypes() { @@ -208,7 +210,7 @@ pub contract FindMarket { return report } - pub fun getNFTListing(tenant:Address, address: Address, id: UInt64, getNFTInfo: Bool) : {String : FindMarket.SaleItemInformation} { + access(all) fun getNFTListing(tenant:Address, address: Address, id: UInt64, getNFTInfo: Bool) : {String : FindMarket.SaleItemInformation} { let tenantRef = self.getTenant(tenant) var report : {String : FindMarket.SaleItemInformation} = {} for type in self.getSaleItemCollectionTypes() { @@ -221,15 +223,15 @@ pub contract FindMarket { return report } - access(contract) fun checkSaleInformation(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, marketOption: String, address: Address, itemId: UInt64?, getGhost: Bool, getNFTInfo: Bool, getRoyaltyChanged: Bool ) : FindMarket.SaleItemCollectionReport { + access(contract) fun checkSaleInformation(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address, itemId: UInt64?, getGhost: Bool, getNFTInfo: Bool, getRoyaltyChanged: Bool ) : FindMarket.SaleItemCollectionReport { let ghost: [FindMarket.GhostListing] =[] let info: [FindMarket.SaleItemInformation] =[] let collectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - let optRef = collectionCap.borrow() + let optRef = collectionCap?.borrow() if optRef == nil { return FindMarket.SaleItemCollectionReport(items: info, ghosts: ghost) } - let ref=optRef! + let ref=optRef!! var listID : [UInt64]= [] if let id = itemId{ @@ -245,7 +247,7 @@ pub contract FindMarket { for id in listID { //if this id is not present in this Market option then we just skip it - let item=ref.borrowSaleItem(id) + let item=ref.borrowSaleItem(id)! if !item.checkPointer() { if getGhost { ghost.append(FindMarket.GhostListing(listingType: listingType, id:id)) @@ -299,18 +301,18 @@ pub contract FindMarket { } /* Get Bid Collections */ - pub fun getMarketBidTypes() : [Type] { + access(all) fun getMarketBidTypes() : [Type] { return self.marketBidTypes } - pub fun getMarketBidCollectionTypes() : [Type] { + access(all) fun getMarketBidCollectionTypes() : [Type] { return self.marketBidCollectionTypes } - pub fun getMarketBidCollectionCapabilities(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindMarket.MarketBidCollectionPublic}>] { + access(all) fun getMarketBidCollectionCapabilities(tenantRef: &{FindMarket.TenantPublic}, address: Address) : [Capability<&{FindMarket.MarketBidCollectionPublic}>] { var caps : [Capability<&{FindMarket.MarketBidCollectionPublic}>] = [] for type in self.getMarketBidCollectionTypes() { - let cap = getAccount(address).getCapability<&{FindMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type)) + let cap = getAccount(address).capabilities.get<&{FindMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type)) if cap.check() { caps.append(cap) } @@ -318,17 +320,16 @@ pub contract FindMarket { return caps } - pub fun getMarketBidCollectionCapability(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindMarket.MarketBidCollectionPublic}> { + access(all) fun getMarketBidCollectionCapability(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address) : Capability<&{FindMarket.MarketBidCollectionPublic}>? { for type in self.getMarketBidCollectionTypes() { if self.getMarketOptionFromType(type) == marketOption{ - let cap = getAccount(address).getCapability<&{FindMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type)) - return cap + return getAccount(address).capabilities.get<&{FindMarket.MarketBidCollectionPublic}>(tenantRef.getPublicPath(type)) } } panic("Cannot find market option : ".concat(marketOption)) } - pub fun getBid(tenant: Address, address: Address, marketOption: String, id:UInt64, getNFTInfo: Bool) : FindMarket.BidInfo? { + access(all) fun getBid(tenant: Address, address: Address, marketOption: String, id:UInt64, getNFTInfo: Bool) : FindMarket.BidInfo? { let tenantRef=self.getTenant(tenant) let bidInfo = self.checkBidInformation(tenantRef: tenantRef, marketOption: marketOption, address: address, itemId: id, getGhost: false, getNFTInfo: getNFTInfo) if bidInfo.items.length > 0 { @@ -337,7 +338,7 @@ pub contract FindMarket { return nil } - pub fun getBidsReport(tenant:Address, address: Address, getNFTInfo: Bool) : {String : FindMarket.BidItemCollectionReport} { + access(all) fun getBidsReport(tenant:Address, address: Address, getNFTInfo: Bool) : {String : FindMarket.BidItemCollectionReport} { let tenantRef = self.getTenant(tenant) var report : {String : FindMarket.BidItemCollectionReport} = {} for type in self.getMarketBidCollectionTypes() { @@ -350,17 +351,17 @@ pub contract FindMarket { return report } - access(contract) fun checkBidInformation(tenantRef: &FindMarket.Tenant{FindMarket.TenantPublic}, marketOption: String, address: Address, itemId: UInt64?, getGhost:Bool, getNFTInfo: Bool) : FindMarket.BidItemCollectionReport { + access(contract) fun checkBidInformation(tenantRef: &{FindMarket.TenantPublic}, marketOption: String, address: Address, itemId: UInt64?, getGhost:Bool, getNFTInfo: Bool) : FindMarket.BidItemCollectionReport { let ghost: [FindMarket.GhostListing] =[] let info: [FindMarket.BidInfo] =[] let collectionCap = self.getMarketBidCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - let optRef = collectionCap.borrow() + let optRef = collectionCap?.borrow() if optRef==nil { return FindMarket.BidItemCollectionReport(items: info, ghosts: ghost) } - let ref=optRef! + let ref=optRef!! let listingType = ref.getBidType() var listID : [UInt64]= [] @@ -390,24 +391,24 @@ pub contract FindMarket { return FindMarket.BidItemCollectionReport(items: info, ghosts: ghost) } - pub fun assertBidOperationValid(tenant: Address, address: Address, marketOption: String, id:UInt64) : &{SaleItem} { + access(all) fun assertBidOperationValid(tenant: Address, address: Address, marketOption: String, id:UInt64) : &{SaleItem} { let tenantRef=self.getTenant(tenant) let collectionCap = self.getMarketBidCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: address) - let optRef = collectionCap.borrow() + let optRef = collectionCap?.borrow() if optRef == nil { - panic("Account not properly set up, cannot borrow bid item collection. Account address : ".concat(collectionCap.address.toString())) + panic("Account not properly set up, cannot borrow bid item collection") } - let ref=optRef! + let ref=optRef!! let bidItem=ref.borrowBidItem(id) let saleItemCollectionCap = self.getSaleItemCollectionCapability(tenantRef: tenantRef, marketOption: marketOption, address: bidItem.getSellerAddress()) - let saleRef = saleItemCollectionCap.borrow() + let saleRef = saleItemCollectionCap?.borrow() if saleRef == nil { - panic("Seller account is not properly set up, cannot borrow sale item collection. Seller address : ".concat(saleItemCollectionCap.address.toString())) + panic("Seller account is not properly set up, cannot borrow sale item collection") } let sale=saleRef! - let item=sale.borrowSaleItem(id) + let item=sale!.borrowSaleItem(id)! if !item.checkPointer() { panic("this is a ghost listing. SaleItem id : ".concat(id.toString())) } @@ -416,11 +417,11 @@ pub contract FindMarket { } /* Helper Function */ - pub fun getMarketOptionFromType(_ type:Type) : String { + access(all) fun getMarketOptionFromType(_ type:Type) : String { return self.listingName[type.identifier]! } - pub fun typeToListingName(_ type: Type) : String { + access(all) fun typeToListingName(_ type: Type) : String { let identifier = type.identifier var dots = 0 var start = 0 @@ -522,7 +523,7 @@ pub contract FindMarket { } } - pub fun typeToPathIdentifier(_ type:Type) : String { + access(all) fun typeToPathIdentifier(_ type:Type) : String { let identifier=type.identifier var i=0 @@ -542,10 +543,10 @@ pub contract FindMarket { // ======================================== /// A struct to return what action an NFT can execute - pub struct AllowedListing { - pub let listingType: Type - pub let ftTypes: [Type] - pub let status: String + access(all) struct AllowedListing { + access(all) let listingType: Type + access(all) let ftTypes: [Type] + access(all) let status: String init(listingType: Type, ftTypes: [Type], status: String) { self.listingType=listingType @@ -554,10 +555,9 @@ pub contract FindMarket { } } - /// If this is a listing action it will not be allowed if deprecated - pub struct MarketAction{ - pub let listing:Bool - pub let name:String + access(all) struct MarketAction{ + access(all) let listing:Bool + access(all) let name:String init(listing:Bool, name:String){ self.listing=listing @@ -565,11 +565,11 @@ pub contract FindMarket { } } - pub struct TenantRule{ - pub let name:String - pub let types:[Type] - pub let ruleType:String - pub let allow:Bool + access(all) struct TenantRule{ + access(all) let name:String + access(all) let types:[Type] + access(all) let ruleType:String + access(all) let allow:Bool init(name:String, types:[Type], ruleType:String, allow:Bool){ @@ -583,7 +583,7 @@ pub contract FindMarket { } - pub fun accept(_ relevantType: Type): Bool { + access(all) fun accept(_ relevantType: Type): Bool { let contains=self.types.contains(relevantType) if self.allow && contains{ @@ -597,11 +597,11 @@ pub contract FindMarket { } } - pub struct TenantSaleItem { - pub let name:String - pub let cut:MetadataViews.Royalty? - pub let rules:[TenantRule] - pub var status:String + access(all) struct TenantSaleItem { + access(all) let name:String + access(all) let cut:MetadataViews.Royalty? + access(all) let rules:[TenantRule] + access(all) var status:String init(name:String, cut:MetadataViews.Royalty?, rules:[TenantRule], status:String){ self.name=name @@ -640,24 +640,24 @@ pub contract FindMarket { } } - pub resource interface TenantPublic { - pub fun getStoragePath(_ type: Type) : StoragePath - pub fun getPublicPath(_ type: Type) : PublicPath - pub fun allowedAction(listingType: Type, nftType:Type, ftType:Type, action: MarketAction, seller: Address? , buyer: Address?) : FindRulesCache.ActionResult - pub fun getCuts(name:String, listingType: Type, nftType:Type, ftType:Type) : {String : FindMarketCutStruct.Cuts} - pub fun getAllowedListings(nftType: Type, marketType: Type) : AllowedListing? - pub fun getBlockedNFT(marketType: Type) : [Type] - pub let name:String + access(all) resource interface TenantPublic { + access(all) fun getStoragePath(_ type: Type) : StoragePath + access(all) fun getPublicPath(_ type: Type) : PublicPath + access(all) fun allowedAction(listingType: Type, nftType:Type, ftType:Type, action: MarketAction, seller: Address? , buyer: Address?) : FindRulesCache.ActionResult + access(all) fun getCuts(name:String, listingType: Type, nftType:Type, ftType:Type) : {String : FindMarketCutStruct.Cuts} + access(all) fun getAllowedListings(nftType: Type, marketType: Type) : AllowedListing? + access(all) fun getBlockedNFT(marketType: Type) : [Type] + access(all) let name:String } //this needs to be a resource so that nobody else can make it. - pub resource Tenant : TenantPublic{ + access(all) resource Tenant : TenantPublic{ access(self) let findSaleItems : {String : TenantSaleItem} access(self) let tenantSaleItems : {String : TenantSaleItem} access(self) let findCuts : {String : TenantSaleItem} - pub let name: String + access(all) let name: String init(_ name:String) { self.name=name @@ -673,7 +673,7 @@ pub contract FindMarket { for key in self.findSaleItems.keys { let val = self.findSaleItems[key]! if val.cut != nil { - let newReceiver = getAccount(val.cut!.receiver.address).getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath) + let newReceiver = getAccount(val.cut!.receiver.address).capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath) let newCut = MetadataViews.Royalty( receiver: newReceiver, cut: val.cut!.cut, @@ -692,7 +692,7 @@ pub contract FindMarket { for key in self.tenantSaleItems.keys { let val = self.tenantSaleItems[key]! if val.cut != nil { - let newReceiver = getAccount(val.cut!.receiver.address).getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath) + let newReceiver = getAccount(val.cut!.receiver.address).capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath) let newCut = MetadataViews.Royalty( receiver: newReceiver, cut: val.cut!.cut, @@ -711,7 +711,7 @@ pub contract FindMarket { for key in self.findCuts.keys { let val = self.findCuts[key]! if val.cut != nil { - let newReceiver = getAccount(val.cut!.receiver.address).getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath) + let newReceiver = getAccount(val.cut!.receiver.address).capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath) let newCut = MetadataViews.Royalty( receiver: newReceiver, cut: val.cut!.cut, @@ -749,7 +749,7 @@ pub contract FindMarket { FindMarketCut.setTenantCuts(tenant: self.name, types: types, category: category, cuts: cuts) } - pub fun getCuts(name:String, listingType: Type, nftType:Type, ftType:Type) : {String : FindMarketCutStruct.Cuts} { + access(all) fun getCuts(name:String, listingType: Type, nftType:Type, ftType:Type) : {String : FindMarketCutStruct.Cuts} { let cuts = FindMarketCut.getCuts(tenant: self.name, listingType: listingType, nftType: nftType, ftType: ftType) @@ -760,22 +760,19 @@ pub contract FindMarket { return cuts } - pub fun getFindCut(name:String, listingType: Type, nftType:Type, ftType:Type) : FindMarketCutStruct.Cuts? { + access(all) fun getFindCut(name:String, listingType: Type, nftType:Type, ftType:Type) : FindMarketCutStruct.Cuts? { let ruleId = FindMarketCut.getRuleId(listingType: listingType, nftType: nftType, ftType: ftType) let findRuleId = ruleId.concat("-find") if let cache = FindRulesCache.getTenantCut(tenant: self.name, ruleId: findRuleId) { var returningCut : FindMarketCutStruct.Cuts? = nil if let findCut = cache.findCut { - returningCut = FindMarketCutStruct.Cuts( - [ - FindMarketCutStruct.GeneralCut( - name : findCut.description, - cap: findCut.receiver, - cut: findCut.cut, - description: findCut.description - ) - ] - ) + returningCut = FindMarketCutStruct.Cuts(cuts:[ + FindMarketCutStruct.GeneralCut( + name : findCut.description, + cap: findCut.receiver, + cut: findCut.cut, + description: findCut.description + )]) } return returningCut } @@ -786,16 +783,13 @@ pub contract FindMarket { let valid = findCut.isValid(nftType: nftType, ftType: ftType, listingType: listingType) if valid && findCut.cut != nil { cacheFindCut = findCut.cut - returningCut = FindMarketCutStruct.Cuts( - [ - FindMarketCutStruct.GeneralCut( - name : findCut.cut!.description, - cap: findCut.cut!.receiver, - cut: findCut.cut!.cut, - description: findCut.cut!.description - ) - ] - ) + returningCut = FindMarketCutStruct.Cuts(cuts:[ + FindMarketCutStruct.GeneralCut( + name : findCut.cut!.description, + cap: findCut.cut!.receiver, + cut: findCut.cut!.cut, + description: findCut.cut!.description + )]) break } } @@ -810,22 +804,19 @@ pub contract FindMarket { return returningCut } - pub fun getTenantCut(name:String, listingType: Type, nftType:Type, ftType:Type) : FindMarketCutStruct.Cuts? { + access(all) fun getTenantCut(name:String, listingType: Type, nftType:Type, ftType:Type) : FindMarketCutStruct.Cuts? { let ruleId = FindMarketCut.getRuleId(listingType: listingType, nftType: nftType, ftType: ftType) let tenantRuleId = ruleId.concat("-tenant") if let cache = FindRulesCache.getTenantCut(tenant: self.name, ruleId: tenantRuleId) { var returningCut : FindMarketCutStruct.Cuts? = nil if let tenantCut = cache.tenantCut { - returningCut = FindMarketCutStruct.Cuts( - [ - FindMarketCutStruct.GeneralCut( - name : tenantCut.description, - cap: tenantCut.receiver, - cut: tenantCut.cut, - description: tenantCut.description - ) - ] - ) + returningCut = FindMarketCutStruct.Cuts(cuts: [ + FindMarketCutStruct.GeneralCut( + name : tenantCut.description, + cap: tenantCut.receiver, + cut: tenantCut.cut, + description: tenantCut.description + )]) } return returningCut } @@ -837,16 +828,13 @@ pub contract FindMarket { if valid && item.cut != nil{ cacheTenantCut = item.cut - returningCut = FindMarketCutStruct.Cuts( - [ - FindMarketCutStruct.GeneralCut( - name : item.cut!.description, - cap: item.cut!.receiver, - cut: item.cut!.cut, - description: item.cut!.description - ) - ] - ) + returningCut = FindMarketCutStruct.Cuts(cuts: [ + FindMarketCutStruct.GeneralCut( + name : item.cut!.description, + cap: item.cut!.receiver, + cut: item.cut!.cut, + description: item.cut!.description + )]) break } } @@ -952,9 +940,9 @@ pub contract FindMarket { panic("Panic executing emitRulesEvent, Must be nft/ft/listing") } - pub fun allowedAction(listingType: Type, nftType:Type, ftType:Type, action: MarketAction, seller: Address?, buyer: Address?) : FindRulesCache.ActionResult{ + access(all) fun allowedAction(listingType: Type, nftType:Type, ftType:Type, action: MarketAction, seller: Address?, buyer: Address?) : FindRulesCache.ActionResult{ /* Check for Honour Banning */ - let profile = getAccount(FindMarket.tenantNameAddress[self.name]!).getCapability<&Profile.User{Profile.Public}>(Profile.publicPath).borrow() ?? panic("Cannot get reference to Profile to check honour banning. Tenant Name : ".concat(self.name)) + let profile = getAccount(FindMarket.tenantNameAddress[self.name]!).capabilities.borrow<&{Profile.Public}>(Profile.publicPath) ?? panic("Cannot get reference to Profile to check honour banning. Tenant Name : ".concat(self.name)) if seller != nil && profile.isBanned(seller!) { return FindRulesCache.ActionResult(allowed:false, message: "Seller banned by Tenant", name: "Profile Ban") } @@ -1038,15 +1026,15 @@ pub contract FindMarket { } - pub fun getPublicPath(_ type: Type) : PublicPath { + access(all) fun getPublicPath(_ type: Type) : PublicPath { return FindMarket.getPublicPath(type, name: self.name) } - pub fun getStoragePath(_ type: Type) : StoragePath { + access(all) fun getStoragePath(_ type: Type) : StoragePath { return FindMarket.getStoragePath(type, name: self.name) } - pub fun getAllowedListings(nftType: Type, marketType: Type) : AllowedListing? { + access(all) fun getAllowedListings(nftType: Type, marketType: Type) : AllowedListing? { // Find Rules have to be deny rules var containsNFTType = false @@ -1100,7 +1088,7 @@ pub contract FindMarket { return AllowedListing(listingType: marketType, ftTypes: returningFTTypes, status: "active") } - pub fun getBlockedNFT(marketType: Type) : [Type] { + access(all) fun getBlockedNFT(marketType: Type) : [Type] { // Find Rules have to be deny rules let list : [Type] = [] var containsListingType = true @@ -1158,16 +1146,18 @@ pub contract FindMarket { // Tenant admin stuff //Admin client to use for capability receiver pattern - pub fun createTenantClient() : @TenantClient { + access(all) fun createTenantClient() : @TenantClient { return <- create TenantClient() } //interface to use for capability receiver pattern - pub resource interface TenantClientPublic { - pub fun addCapability(_ cap: Capability<&Tenant>) + access(all) resource interface TenantClientPublic { + access(all) fun addCapability(_ cap: Capability<&Tenant>) } + access(all) entitlement TenantClientOwner + /* A tenantClient should be able to: @@ -1175,11 +1165,11 @@ pub contract FindMarket { */ //admin proxy with capability receiver - pub resource TenantClient: TenantClientPublic { + access(all) resource TenantClient: TenantClientPublic { access(self) var capability: Capability<&Tenant>? - pub fun addCapability(_ cap: Capability<&Tenant>) { + access(all) fun addCapability(_ cap: Capability<&Tenant>) { if !cap.check() { panic("Invalid tenant") @@ -1194,32 +1184,32 @@ pub contract FindMarket { self.capability = nil } - pub fun setMarketOption(saleItem: TenantSaleItem) { + access(TenantClientOwner) fun setMarketOption(saleItem: TenantSaleItem) { let tenant = self.getTenantRef() tenant.addSaleItem(saleItem, type: "tenant") } - pub fun removeMarketOption(name: String) { + access(TenantClientOwner) fun removeMarketOption(name: String) { let tenant = self.getTenantRef() tenant.removeSaleItem(name, type: "tenant") } - pub fun enableMarketOption(_ name: String) { + access(TenantClientOwner) fun enableMarketOption(_ name: String) { let tenant = self.getTenantRef() tenant.alterMarketOption(name: name, status: "active") } - pub fun deprecateMarketOption(_ name: String) { + access(TenantClientOwner) fun deprecateMarketOption(_ name: String) { let tenant = self.getTenantRef() tenant.alterMarketOption(name: name, status: "deprecated") } - pub fun stopMarketOption(_ name: String) { + access(TenantClientOwner) fun stopMarketOption(_ name: String) { let tenant = self.getTenantRef() tenant.alterMarketOption(name: name, status: "stopped") } - pub fun getTenantRef() : &Tenant { + access(TenantClientOwner) fun getTenantRef() : &Tenant { if self.capability == nil { panic("TenantClient is not present") } @@ -1230,7 +1220,7 @@ pub contract FindMarket { return self.capability!.borrow()! } - pub fun setExtraCut(types: [Type], category: String, cuts: FindMarketCutStruct.Cuts) { + access(TenantClientOwner) fun setExtraCut(types: [Type], category: String, cuts: FindMarketCutStruct.Cuts) { let tenant = self.getTenantRef() tenant.setExtraCut(types: types, category: category, cuts: cuts) } @@ -1246,12 +1236,9 @@ pub contract FindMarket { let account=FindMarket.account let tenantPath=self.getTenantPathForName(name) let sp=StoragePath(identifier: tenantPath)! - let pp=PrivatePath(identifier: tenantPath)! let pubp=PublicPath(identifier:tenantPath)! - destroy account.load<@Tenant>(from: sp) - account.unlink(pp) - account.unlink(pubp) - + destroy account.storage.load<@Tenant>(from: sp) + account.capabilities.unpublish(pubp) self.tenantAddressName.remove(key: tenant) self.tenantNameAddress.remove(key: name) emit FindTenantRemoved(tenant: name, address: tenant) @@ -1277,16 +1264,16 @@ pub contract FindMarket { let tenantPath=self.getTenantPathForName(name) let sp=StoragePath(identifier: tenantPath)! - let pp=PrivatePath(identifier: tenantPath)! let pubp=PublicPath(identifier:tenantPath)! - - account.save(<- tenant, to: sp) - account.link<&Tenant>(pp, target:sp) - account.link<&Tenant{TenantPublic}>(pubp, target:sp) - return account.getCapability<&Tenant>(pp) + account.storage.save(<- tenant, to: sp) + //TODO:: What path to store here... + let cap = account.capabilities.storage.issue<&Tenant>(sp) + account.capabilities.publish(cap, at: pubp) + let tenantCap = account.capabilities.storage.issue<&Tenant>(sp) + return tenantCap } - pub fun getTenantPathForName(_ name:String) : String { + access(all) fun getTenantPathForName(_ name:String) : String { if !self.tenantNameAddress.containsKey(name) { panic("tenant is not registered in registry") } @@ -1294,7 +1281,7 @@ pub contract FindMarket { return self.tenantPathPrefix.concat("_").concat(name) } - pub fun getTenantPathForAddress(_ address:Address) : String { + access(all) fun getTenantPathForAddress(_ address:Address) : String { if !self.tenantAddressName.containsKey(address) { panic("tenant is not registered in registry") } @@ -1302,17 +1289,21 @@ pub contract FindMarket { return self.getTenantPathForName(self.tenantAddressName[address]!) } - pub fun getTenantCapability(_ marketplace:Address) : Capability<&Tenant{TenantPublic}>? { + access(all) fun getTenantCapability(_ marketplace:Address) : Capability<&Tenant>? { if !self.tenantAddressName.containsKey(marketplace) { "tenant is not registered in registry" } - return FindMarket.account.getCapability<&Tenant{TenantPublic}>(PublicPath(identifier:self.getTenantPathForAddress(marketplace))!) + let cap= FindMarket.account.capabilities.get<&Tenant>(PublicPath(identifier:self.getTenantPathForAddress(marketplace))!) + if !cap.check() { + return nil + } + return cap } - access(account) fun pay(tenant: String, id: UInt64, saleItem: &{SaleItem}, vault: @FungibleToken.Vault, royalty: MetadataViews.Royalties, nftInfo:NFTInfo, cuts:{String : FindMarketCutStruct.Cuts}, resolver: ((Address) : String?), resolvedAddress: {Address: String}) { + access(account) fun pay(tenant: String, id: UInt64, saleItem: &{SaleItem}, vault: @{FungibleToken.Vault}, royalty: MetadataViews.Royalties, nftInfo:NFTInfo, cuts:{String : FindMarketCutStruct.Cuts}, resolver: (fun (Address) : String?), resolvedAddress: {Address: String}) { let resolved : {Address : String} = resolvedAddress fun resolveName(_ addr: Address ) : String? { @@ -1343,7 +1334,7 @@ pub contract FindMarket { var payInFUT = false var payInDUC = false let ftInfo = FTRegistry.getFTInfoByTypeIdentifier(ftType.identifier)! // If this panic, there is sth wrong in FT set up - let oldProfileCap= getAccount(seller).getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let oldProfileCap= getAccount(seller).capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) let oldProfile = self.getPaymentWallet(oldProfileCap, ftInfo, panicOnFailCheck: true) /* Check the total royalty to prevent changing of royalties */ @@ -1413,7 +1404,7 @@ pub contract FindMarket { // If the underlying is a profile, we check if the wallet type is registered in profile wallet and then return // If it is not registered, it falls through and be handled by residual case Type<@Profile.User>(): - if let ProfileRef = getAccount(cap.address).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() { + if let ProfileRef = getAccount(cap.address).capabilities.borrow<&{Profile.Public}>(Profile.publicPath) { if ProfileRef.hasWallet(ftInfo.type.identifier) { return ref } @@ -1421,8 +1412,8 @@ pub contract FindMarket { // If the underlying is a switchboard, we check if the wallet type is registered in switchboard wallet and then return // If it is not registered, it falls through and be handled by residual case Type<@FungibleTokenSwitchboard.Switchboard>() : - if let sbRef = getAccount(cap.address).getCapability<&{FungibleTokenSwitchboard.SwitchboardPublic}>(FungibleTokenSwitchboard.PublicPath).borrow() { - if sbRef.getVaultTypes().contains(ftInfo.type) { + if let sbRef = getAccount(cap.address).capabilities.borrow<&{FungibleTokenSwitchboard.SwitchboardPublic}>(FungibleTokenSwitchboard.PublicPath) { + if sbRef.isSupportedVaultType(type: ftInfo.type) { return ref } } @@ -1438,43 +1429,40 @@ pub contract FindMarket { } // if capability is not valid, or if the above cases are fell through, we will try to get one with "standard" path - tempCap = getAccount(cap.address).getCapability<&{FungibleToken.Receiver}>(ftInfo.receiverPath) - if tempCap.check() { - return tempCap.borrow()! + if let tempCap = getAccount(cap.address).capabilities.borrow<&{FungibleToken.Receiver}>(ftInfo.receiverPath) { + return tempCap } if !panicOnFailCheck { // If it all falls throught, these edge cases will be handled by a residual account that has switchboard set up - let residualVault = getAccount(FindMarket.residualAddress).getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath) - return residualVault.borrow() ?? panic("Cannot borrow residual vault in address : ".concat(FindMarket.residualAddress.toString()).concat(" type : ").concat(ftInfo.typeIdentifier)) + return getAccount(FindMarket.residualAddress).capabilities.borrow<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath) ?? panic("Cannot borrow residual vault in address : ".concat(FindMarket.residualAddress.toString()).concat(" type : ").concat(ftInfo.typeIdentifier)) } let msg = "User ".concat(cap.address.toString()).concat(" does not have any usable links set up for vault type ").concat(ftInfo.typeIdentifier) panic(msg) } - pub struct NFTInfo { - pub let id: UInt64 - pub let name:String - pub let thumbnail:String - pub let type: String - pub var rarity:String? - pub var editionNumber: UInt64? - pub var totalInEdition: UInt64? - pub var scalars: {String:UFix64} - pub var tags : {String:String} - pub var collectionName: String? - pub var collectionDescription: String? + access(all) struct NFTInfo { + access(all) let id: UInt64 + access(all) let name:String + access(all) let thumbnail:String + access(all) let type: String + access(all) var rarity:String? + access(all) var editionNumber: UInt64? + access(all) var totalInEdition: UInt64? + access(all) var scalars: {String:UFix64} + access(all) var tags : {String:String} + access(all) var collectionName: String? + access(all) var collectionDescription: String? - init(_ item: &{MetadataViews.Resolver}, id: UInt64, detail: Bool){ + init(_ item: &{ViewResolver.Resolver}, id: UInt64, detail: Bool){ + self.tags = { "uuid" : item.uuid.toString()} self.collectionName=nil self.collectionDescription=nil - self.tags = { - "uuid" : item.uuid.toString() - } - self.scalars = {} + //uuid is not here anymore + self.scalars = { } self.rarity= nil self.editionNumber=nil self.totalInEdition=nil @@ -1598,11 +1586,10 @@ pub contract FindMarket { } } - pub struct GhostListing{ - // pub let listingType: Type - pub let listingTypeIdentifier: String - pub let id: UInt64 - + access(all) struct GhostListing{ + // access(all) let listingType: Type + access(all) let listingTypeIdentifier: String + access(all) let id: UInt64 init(listingType:Type, id:UInt64) { // self.listingType=listingType @@ -1611,16 +1598,16 @@ pub contract FindMarket { } } - pub struct AuctionItem { + access(all) struct AuctionItem { //end time //current time - pub let startPrice: UFix64 - pub let currentPrice: UFix64 - pub let minimumBidIncrement: UFix64 - pub let reservePrice: UFix64 - pub let extentionOnLateBid: UFix64 - pub let auctionEndsAt: UFix64? - pub let timestamp: UFix64 + access(all) let startPrice: UFix64 + access(all) let currentPrice: UFix64 + access(all) let minimumBidIncrement: UFix64 + access(all) let reservePrice: UFix64 + access(all) let extentionOnLateBid: UFix64 + access(all) let auctionEndsAt: UFix64? + access(all) let timestamp: UFix64 init(startPrice: UFix64, currentPrice: UFix64, minimumBidIncrement: UFix64, reservePrice: UFix64, extentionOnLateBid: UFix64, auctionEndsAt: UFix64? , timestamp: UFix64){ self.startPrice = startPrice @@ -1633,17 +1620,17 @@ pub contract FindMarket { } } - pub resource interface SaleItemCollectionPublic { - pub fun getIds(): [UInt64] - pub fun getRoyaltyChangedIds(): [UInt64] - pub fun containsId(_ id: UInt64): Bool - pub fun borrowSaleItem(_ id: UInt64) : &{SaleItem} - pub fun getListingType() : Type + access(all) resource interface SaleItemCollectionPublic { + access(all) fun getIds(): [UInt64] + access(all) fun getRoyaltyChangedIds(): [UInt64] + access(all) fun containsId(_ id: UInt64): Bool + access(all) fun borrowSaleItem(_ id: UInt64) : &{SaleItem}? + access(all) fun getListingType() : Type } - pub struct SaleItemCollectionReport { - pub let items : [FindMarket.SaleItemInformation] - pub let ghosts: [FindMarket.GhostListing] + access(all) struct SaleItemCollectionReport { + access(all) let items : [FindMarket.SaleItemInformation] + access(all) let ghosts: [FindMarket.GhostListing] init(items: [SaleItemInformation], ghosts: [GhostListing]) { self.items=items @@ -1651,16 +1638,17 @@ pub contract FindMarket { } } - pub resource interface MarketBidCollectionPublic { - pub fun getIds() : [UInt64] - pub fun containsId(_ id: UInt64): Bool - pub fun getBidType() : Type - access(account) fun borrowBidItem(_ id: UInt64) : &{Bid} + access(all) resource interface MarketBidCollectionPublic { + access(all) fun getIds() : [UInt64] + access(all) fun containsId(_ id: UInt64): Bool + access(all) fun getBidType() : Type + //TODO: this used to be access account, look ino this, because now we can downcast + access(all) fun borrowBidItem(_ id: UInt64) : &{Bid} } - pub struct BidItemCollectionReport { - pub let items : [FindMarket.BidInfo] - pub let ghosts: [FindMarket.GhostListing] + access(all) struct BidItemCollectionReport { + access(all) let items : [FindMarket.BidInfo] + access(all) let ghosts: [FindMarket.GhostListing] init(items: [BidInfo], ghosts: [GhostListing]) { self.items=items @@ -1668,70 +1656,69 @@ pub contract FindMarket { } } - pub resource interface Bid { - pub fun getBalance() : UFix64 - pub fun getSellerAddress() : Address - pub fun getBidExtraField() : {String : AnyStruct} + access(all) resource interface Bid { + access(all) fun getBalance() : UFix64 + access(all) fun getSellerAddress() : Address + access(all) fun getBidExtraField() : {String : AnyStruct} } - pub resource interface SaleItem { - + access(all) resource interface SaleItem { //this is the type of sale this is, auction, direct offer etc - pub fun getSaleType(): String - pub fun getListingTypeIdentifier(): String + access(all) fun getSaleType(): String + access(all) fun getListingTypeIdentifier(): String - pub fun getSeller(): Address - pub fun getBuyer(): Address? + access(all) fun getSeller(): Address + access(all) fun getBuyer(): Address? - pub fun getSellerName() : String? - pub fun getBuyerName() : String? + access(all) fun getSellerName() : String? + access(all) fun getBuyerName() : String? - pub fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo - pub fun checkPointer() : Bool - pub fun checkSoulBound() : Bool - pub fun getListingType() : Type + access(all) fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo + access(all) fun checkPointer() : Bool + access(all) fun checkSoulBound() : Bool + access(all) fun getListingType() : Type - // pub fun getFtAlias(): String + // access(all) getFtAlias(): String //the Type of the item for sale - pub fun getItemType(): Type - //The id of the nft for sale - pub fun getItemID() : UInt64 - //The id of this sale item, ie the UUID of the item listed for sale - pub fun getId() : UInt64 - - pub fun getBalance(): UFix64 - pub fun getAuction(): AuctionItem? - pub fun getFtType() : Type //The type of FT used for this sale item - pub fun getValidUntil() : UFix64? //A timestamp that says when this item is valid until - - pub fun getSaleItemExtraField() : {String : AnyStruct} - - pub fun getTotalRoyalties() : UFix64 - pub fun validateRoyalties() : Bool - pub fun getDisplay() : MetadataViews.Display - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData - } - - pub struct SaleItemInformation { - pub let nftIdentifier: String - pub let nftId: UInt64 - pub let seller: Address - pub let sellerName: String? - pub let amount: UFix64? - pub let bidder: Address? - pub var bidderName: String? - pub let listingId: UInt64 - - pub let saleType: String - pub let listingTypeIdentifier: String - pub let ftAlias: String - pub let ftTypeIdentifier: String - pub let listingValidUntil: UFix64? - - pub var nft: NFTInfo? - pub let auction: AuctionItem? - pub let listingStatus:String - pub let saleItemExtraField: {String : AnyStruct} + access(all) fun getItemType(): Type + //The id of fun the nft for sale + access(all) fun getItemID() : UInt64 + //The id of fun this sale item, ie the UUID of the item listed for sale + access(all) fun getId() : UInt64 + + access(all) fun getBalance(): UFix64 + access(all) fun getAuction(): AuctionItem? + access(all) fun getFtType() : Type //The type of FT used for this sale item + access(all) fun getValidUntil() : UFix64? //A timestamp that says when this item is valid until + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} + + access(all) fun getTotalRoyalties() : UFix64 + access(all) fun validateRoyalties() : Bool + access(all) fun getDisplay() : MetadataViews.Display + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData + } + + access(all) struct SaleItemInformation { + access(all) let nftIdentifier: String + access(all) let nftId: UInt64 + access(all) let seller: Address + access(all) let sellerName: String? + access(all) let amount: UFix64? + access(all) let bidder: Address? + access(all) var bidderName: String? + access(all) let listingId: UInt64 + + access(all) let saleType: String + access(all) let listingTypeIdentifier: String + access(all) let ftAlias: String + access(all) let ftTypeIdentifier: String + access(all) let listingValidUntil: UFix64? + + access(all) var nft: NFTInfo? + access(all) let auction: AuctionItem? + access(all) let listingStatus:String + access(all) let saleItemExtraField: {String : AnyStruct} init(item: &{SaleItem}, status:String, nftInfo: Bool) { self.nftIdentifier= item.getItemType().identifier @@ -1762,12 +1749,12 @@ pub contract FindMarket { } } - pub struct BidInfo{ - pub let id: UInt64 - pub let bidAmount: UFix64 - pub let bidTypeIdentifier: String - pub let timestamp: UFix64 - pub let item: SaleItemInformation + access(all) struct BidInfo { + access(all) let id: UInt64 + access(all) let bidAmount: UFix64 + access(all) let bidTypeIdentifier: String + access(all) let timestamp: UFix64 + access(all) let item: SaleItemInformation init(id: UInt64, bidTypeIdentifier: String, bidAmount: UFix64, timestamp: UFix64, item:SaleItemInformation) { self.id=id @@ -1778,7 +1765,7 @@ pub contract FindMarket { } } - pub fun getTenantAddress(_ name: String) : Address? { + access(all) fun getTenantAddress(_ name: String) : Address? { return FindMarket.tenantNameAddress[name] } @@ -1801,9 +1788,6 @@ pub contract FindMarket { self.listingName={} self.marketBidTypes = [] self.marketBidCollectionTypes = [] - self.residualAddress = self.account.address // This has to be changed - } - } diff --git a/contracts/FindMarketAdmin.cdc b/contracts/FindMarketAdmin.cdc index b996fbbb..b7114cc0 100644 --- a/contracts/FindMarketAdmin.cdc +++ b/contracts/FindMarketAdmin.cdc @@ -1,249 +1,248 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FIND from "./FIND.cdc" -import FindMarket from "./FindMarket.cdc" -import FindMarketCutStruct from "./FindMarketCutStruct.cdc" - -pub contract FindMarketAdmin { - - //store the proxy for the admin - pub let AdminProxyPublicPath: PublicPath - pub let AdminProxyStoragePath: StoragePath - - /// =================================================================================== - // Admin things - /// =================================================================================== - - //Admin client to use for capability receiver pattern - pub fun createAdminProxyClient() : @AdminProxy { - return <- create AdminProxy() - } - - //interface to use for capability receiver pattern - pub resource interface AdminProxyClient { - pub fun addCapability(_ cap: Capability<&FIND.Network>) - } - - //admin proxy with capability receiver - pub resource AdminProxy: AdminProxyClient { - - access(self) var capability: Capability<&FIND.Network>? - - pub fun addCapability(_ cap: Capability<&FIND.Network>) { - pre { - cap.check() : "Invalid server capablity" - self.capability == nil : "Server already set" - } - self.capability = cap - } - - pub fun createFindMarket(name: String, address:Address, findCutSaleItem: FindMarket.TenantSaleItem?) : Capability<&FindMarket.Tenant> { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - return FindMarket.createFindMarket(name:name, address:address, findCutSaleItem: findCutSaleItem) - } - - pub fun removeFindMarketTenant(tenant: Address) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - FindMarket.removeFindMarketTenant(tenant: tenant) - } - - pub fun getFindMarketClient(): &FindMarket.TenantClient{ - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - - let path = FindMarket.TenantClientStoragePath - return FindMarketAdmin.account.borrow<&FindMarket.TenantClient>(from: path) ?? panic("Cannot borrow Find market tenant client Reference.") - } - - /// =================================================================================== - // Find Market Options - /// =================================================================================== - pub fun addSaleItemType(_ type: Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.addSaleItemType(type) - } - - pub fun addMarketBidType(_ type: Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.addMarketBidType(type) - } - - pub fun addSaleItemCollectionType(_ type: Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.addSaleItemCollectionType(type) - } - - pub fun addMarketBidCollectionType(_ type: Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.addMarketBidCollectionType(type) - } - - pub fun removeSaleItemType(_ type: Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.removeSaleItemType(type) - } - - pub fun removeMarketBidType(_ type: Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.removeMarketBidType(type) - } - - pub fun removeSaleItemCollectionType(_ type: Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.removeSaleItemCollectionType(type) - } - - pub fun removeMarketBidCollectionType(_ type: Type) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.removeMarketBidCollectionType(type) - } - - /// =================================================================================== - // Tenant Rules Management - /// =================================================================================== - pub fun getTenantRef(_ tenant: Address) : &FindMarket.Tenant { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let string = FindMarket.getTenantPathForAddress(tenant) - let pp = PrivatePath(identifier: string) ?? panic("Cannot generate storage path from string : ".concat(string)) - let cap = FindMarketAdmin.account.getCapability<&FindMarket.Tenant>(pp) - return cap.borrow() ?? panic("Cannot borrow tenant reference from path. Path : ".concat(pp.toString()) ) - } - - pub fun addFindBlockItem(tenant: Address, item: FindMarket.TenantSaleItem) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.addSaleItem(item, type: "find") - } - - pub fun removeFindBlockItem(tenant: Address, name: String) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.removeSaleItem(name, type: "find") - } - - pub fun setFindCut(tenant: Address, saleItem: FindMarket.TenantSaleItem) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.addSaleItem(saleItem, type: "cut") - } - - pub fun setExtraCut(tenant: Address, types: [Type], category: String, cuts: FindMarketCutStruct.Cuts) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.setExtraCut(types: types, category: category, cuts: cuts) - } - - pub fun setMarketOption(tenant: Address, saleItem: FindMarket.TenantSaleItem) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.addSaleItem(saleItem, type: "tenant") - //Emit Event here - } - - pub fun removeMarketOption(tenant: Address, name: String) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.removeSaleItem(name, type: "tenant") - } - - pub fun enableMarketOption(tenant: Address, name: String) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.alterMarketOption(name: name, status: "active") - } - - pub fun deprecateMarketOption(tenant: Address, name: String) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.alterMarketOption(name: name, status: "deprecated") - } - - pub fun stopMarketOption(tenant: Address, name: String) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.alterMarketOption(name: name, status: "stopped") - } - - pub fun setupSwitchboardCut(tenant: Address) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - let tenant = self.getTenantRef(tenant) - tenant.setupSwitchboardCut() - } - - /// =================================================================================== - // Royalty Residual - /// =================================================================================== - - pub fun setResidualAddress(_ address: Address) { - pre { - self.capability != nil: "Cannot create FIND, capability is not set" - } - FindMarket.setResidualAddress(address) - } - - pub fun getSwitchboardReceiverPublic() : Capability<&{FungibleToken.Receiver}> { - // we hard code it here instead, to avoid importing just for path - return FindMarketAdmin.account.getCapability<&{FungibleToken.Receiver}>(/public/GenericFTReceiver) - } - - init() { - self.capability = nil - } - - } - - - init() { - - self.AdminProxyPublicPath= /public/findMarketAdminProxy - self.AdminProxyStoragePath=/storage/findMarketAdminProxy - - } +import "FungibleToken" +import "MetadataViews" +import "FIND" +import "FindMarket" +import "FindMarketCutStruct" + +access(all) contract FindMarketAdmin { + // Entitlements + access(all) entitlement Owner + + //store the proxy for the admin + access(all) let AdminProxyPublicPath: PublicPath + access(all) let AdminProxyStoragePath: StoragePath + + /// =================================================================================== + // Admin things + /// =================================================================================== + + //Admin client to use for capability receiver pattern + access(all) fun createAdminProxyClient() : @AdminProxy { + return <- create AdminProxy() + } + + //interface to use for capability receiver pattern + access(all) resource interface AdminProxyClient { + access(all) fun addCapability(_ cap: Capability<&FIND.Network>) + } + + //admin proxy with capability receiver + access(all) resource AdminProxy: AdminProxyClient { + + access(self) var capability: Capability<&FIND.Network>? + + access(all) fun addCapability(_ cap: Capability<&FIND.Network>) { + pre { + cap.check() : "Invalid server capablity" + self.capability == nil : "Server already set" + } + self.capability = cap + } + + access(Owner) fun createFindMarket(name: String, address:Address, findCutSaleItem: FindMarket.TenantSaleItem?) : Capability<&FindMarket.Tenant> { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + return FindMarket.createFindMarket(name:name, address:address, findCutSaleItem: findCutSaleItem) + } + + access(Owner) fun removeFindMarketTenant(tenant: Address) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + FindMarket.removeFindMarketTenant(tenant: tenant) + } + + access(Owner) fun getFindMarketClient(): &FindMarket.TenantClient{ + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + + let path = FindMarket.TenantClientStoragePath + return FindMarketAdmin.account.storage.borrow(from: path) ?? panic("Cannot borrow Find market tenant client Reference.") + } + + /// =================================================================================== + // Find Market Options + /// =================================================================================== + access(Owner) fun addSaleItemType(_ type: Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.addSaleItemType(type) + } + + access(Owner) fun addMarketBidType(_ type: Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.addMarketBidType(type) + } + + access(Owner) fun addSaleItemCollectionType(_ type: Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.addSaleItemCollectionType(type) + } + + access(Owner) fun addMarketBidCollectionType(_ type: Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.addMarketBidCollectionType(type) + } + + access(Owner) fun removeSaleItemType(_ type: Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.removeSaleItemType(type) + } + + access(Owner) fun removeMarketBidType(_ type: Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.removeMarketBidType(type) + } + + access(Owner) fun removeSaleItemCollectionType(_ type: Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.removeSaleItemCollectionType(type) + } + + access(Owner) fun removeMarketBidCollectionType(_ type: Type) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.removeMarketBidCollectionType(type) + } + + /// =================================================================================== + // Tenant Rules Management + /// =================================================================================== + access(Owner) fun getTenantRef(_ tenant: Address) : &FindMarket.Tenant { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let string = FindMarket.getTenantPathForAddress(tenant) + let pp = PublicPath(identifier: string) ?? panic("Cannot generate storage path from string : ".concat(string)) + let cap = FindMarketAdmin.account.capabilities.borrow<&FindMarket.Tenant>(pp) ?? panic("Cannot borrow tenant reference from path. Path : ".concat(pp.toString()) ) + return cap + } + + access(Owner) fun addFindBlockItem(tenant: Address, item: FindMarket.TenantSaleItem) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.addSaleItem(item, type: "find") + } + + access(Owner) fun removeFindBlockItem(tenant: Address, name: String) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.removeSaleItem(name, type: "find") + } + + access(Owner) fun setFindCut(tenant: Address, saleItem: FindMarket.TenantSaleItem) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.addSaleItem(saleItem, type: "cut") + } + + access(Owner) fun setExtraCut(tenant: Address, types: [Type], category: String, cuts: FindMarketCutStruct.Cuts) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.setExtraCut(types: types, category: category, cuts: cuts) + } + + access(Owner) fun setMarketOption(tenant: Address, saleItem: FindMarket.TenantSaleItem) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.addSaleItem(saleItem, type: "tenant") + //Emit Event here + } + + access(Owner) fun removeMarketOption(tenant: Address, name: String) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.removeSaleItem(name, type: "tenant") + } + + access(Owner) fun enableMarketOption(tenant: Address, name: String) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.alterMarketOption(name: name, status: "active") + } + + access(Owner) fun deprecateMarketOption(tenant: Address, name: String) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.alterMarketOption(name: name, status: "deprecated") + } + + access(Owner) fun stopMarketOption(tenant: Address, name: String) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.alterMarketOption(name: name, status: "stopped") + } + + access(Owner) fun setupSwitchboardCut(tenant: Address) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + let tenant = self.getTenantRef(tenant) + tenant.setupSwitchboardCut() + } + + /// =================================================================================== + // Royalty Residual + /// =================================================================================== + + access(Owner) fun setResidualAddress(_ address: Address) { + pre { + self.capability != nil: "Cannot create FIND, capability is not set" + } + FindMarket.setResidualAddress(address) + } + + access(all) fun getSwitchboardReceiverPublic() : Capability<&{FungibleToken.Receiver}> { + // we hard code it here instead, to avoid importing just for path + return FindMarketAdmin.account.capabilities.get<&{FungibleToken.Receiver}>(/public/GenericFTReceiver)! + } + + init() { + self.capability = nil + } + + } + + init() { + self.AdminProxyPublicPath= /public/findMarketAdminProxy + self.AdminProxyStoragePath=/storage/findMarketAdminProxy + } } diff --git a/contracts/FindMarketAuctionEscrow.cdc b/contracts/FindMarketAuctionEscrow.cdc index 8173b29c..bc251ad8 100644 --- a/contracts/FindMarketAuctionEscrow.cdc +++ b/contracts/FindMarketAuctionEscrow.cdc @@ -1,927 +1,926 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindViews from "./FindViews.cdc" -import Clock from "./Clock.cdc" -import FIND from "./FIND.cdc" -import FindMarket from "./FindMarket.cdc" -import Profile from "./Profile.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "Clock" +import "FIND" +import "FindMarket" +import "Profile" // An auction saleItem contract that escrows the FT, does _not_ escrow the NFT -pub contract FindMarketAuctionEscrow { - - pub event EnglishAuction(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName:String?, amount: UFix64, auctionReservePrice: UFix64, status: String, vaultType:String, nft:FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, startsAt: UFix64?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) - - pub resource SaleItem : FindMarket.SaleItem { - access(contract) var pointer: FindViews.AuthNFTPointer - - access(contract) var vaultType: Type - access(contract) var auctionStartPrice: UFix64 - access(contract) var auctionReservePrice: UFix64 - access(contract) var auctionDuration: UFix64 - access(contract) var auctionMinBidIncrement: UFix64 - access(contract) var auctionExtensionOnLateBid: UFix64 - access(contract) var auctionStartedAt: UFix64? - access(contract) var auctionValidUntil: UFix64? - access(contract) var auctionEndsAt: UFix64? - access(contract) var offerCallback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>? - access(contract) let totalRoyalties: UFix64 - access(contract) let saleItemExtraField: {String : AnyStruct} - - init(pointer: FindViews.AuthNFTPointer, vaultType: Type, auctionStartPrice:UFix64, auctionReservePrice:UFix64, auctionDuration: UFix64, extentionOnLateBid:UFix64, minimumBidIncrement:UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - self.vaultType=vaultType - self.pointer=pointer - self.auctionStartPrice=auctionStartPrice - self.auctionReservePrice=auctionReservePrice - self.auctionDuration=auctionDuration - self.auctionExtensionOnLateBid=extentionOnLateBid - self.auctionMinBidIncrement=minimumBidIncrement - self.offerCallback=nil - self.auctionStartedAt=nil - self.auctionEndsAt=nil - self.auctionValidUntil=auctionValidUntil - self.saleItemExtraField=saleItemExtraField - self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() - } - - pub fun getId() : UInt64{ - return self.pointer.getUUID() - } - - pub fun acceptEscrowedBid() : @FungibleToken.Vault { - if !self.offerCallback!.check() { - panic("bidder unlinked the bid collection capability. bidder address : ".concat(self.offerCallback!.address.toString())) - } - let path = self.pointer.getNFTCollectionData().publicPath - let vault <- self.offerCallback!.borrow()!.accept(<- self.pointer.withdraw(), path: path) - return <- vault - } - - pub fun getRoyalty() : MetadataViews.Royalties { - return self.pointer.getRoyalty() - } - - pub fun getBalance() : UFix64 { - if let cb= self.offerCallback { - if !cb.check() { - panic("Bidder unlinked the bid collection capability. bidder address : ".concat(cb.address.toString())) - } - return cb.borrow()!.getBalance(self.getId()) - } - return self.auctionStartPrice - } - - pub fun getSeller() : Address { - return self.pointer.owner() - } - - pub fun getSellerName() : String? { - let address = self.pointer.owner() - return FIND.reverseLookup(address) - } - - pub fun getBuyer() : Address? { - if let cb= self.offerCallback { - return cb.address - } - return nil - } - - pub fun getBuyerName() : String? { - if let cb= self.offerCallback { - return FIND.reverseLookup(cb.address) - } - return nil - } - - pub fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ - return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) - } - - pub fun setAuctionStarted(_ startedAt: UFix64) { - self.auctionStartedAt=startedAt - } - - pub fun setAuctionEnds(_ endsAt: UFix64){ - self.auctionEndsAt=endsAt - } - - pub fun hasAuctionStarted() : Bool { - if let starts = self.auctionStartedAt { - return starts <= Clock.time() - } - return false - } - - pub fun hasAuctionEnded() : Bool { - if let ends = self.auctionEndsAt { - return ends < Clock.time() - } - panic("Not a live auction") - } - - pub fun hasAuctionMetReservePrice() : Bool { - - let balance=self.getBalance() - - if self.auctionReservePrice== nil { - return false - } - - return balance >= self.auctionReservePrice - } - - pub fun setExtentionOnLateBid(_ time: UFix64) { - self.auctionExtensionOnLateBid=time - } - - pub fun setAuctionDuration(_ duration: UFix64) { - self.auctionDuration=duration - } - - pub fun setReservePrice(_ price: UFix64) { - self.auctionReservePrice=price - } - - pub fun setMinBidIncrement(_ price: UFix64) { - self.auctionMinBidIncrement=price - } - - pub fun setStartAuctionPrice(_ price: UFix64) { - self.auctionStartPrice=price - } - - pub fun setCallback(_ callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>?) { - self.offerCallback=callback - } - - - pub fun getSaleType(): String { - if self.auctionStartedAt != nil { - if self.hasAuctionEnded() { - if self.hasAuctionMetReservePrice() { - return "finished_completed" - } - return "finished_failed" - } - return "active_ongoing" - } - return "active_listed" - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun getListingTypeIdentifier(): String { - return Type<@SaleItem>().identifier - } - - - pub fun getItemID() : UInt64 { - return self.pointer.id - } - - pub fun getItemType() : Type { - return self.pointer.getItemType() - } - - pub fun getAuction(): FindMarket.AuctionItem? { - return FindMarket.AuctionItem(startPrice: self.auctionStartPrice, - currentPrice: self.getBalance(), - minimumBidIncrement: self.auctionMinBidIncrement , - reservePrice: self.auctionReservePrice, - extentionOnLateBid: self.auctionExtensionOnLateBid , - auctionEndsAt: self.auctionEndsAt , - timestamp: Clock.time()) - } +access(all) contract FindMarketAuctionEscrow { + + // A seller can list,delist and relist leases for auction + access(all) entitlement Seller + + access(all) event EnglishAuction(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName:String?, amount: UFix64, auctionReservePrice: UFix64, status: String, vaultType:String, nft:FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, startsAt: UFix64?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) + + access(all) resource SaleItem : FindMarket.SaleItem { + access(contract) var pointer: FindViews.AuthNFTPointer + access(contract) var vaultType: Type + access(contract) var auctionStartPrice: UFix64 + access(contract) var auctionReservePrice: UFix64 + access(contract) var auctionDuration: UFix64 + access(contract) var auctionMinBidIncrement: UFix64 + access(contract) var auctionExtensionOnLateBid: UFix64 + access(contract) var auctionStartedAt: UFix64? + access(contract) var auctionValidUntil: UFix64? + access(contract) var auctionEndsAt: UFix64? + access(contract) var offerCallback: Capability<&MarketBidCollection>? + access(contract) let totalRoyalties: UFix64 + access(contract) let saleItemExtraField: {String : AnyStruct} + + init(pointer: FindViews.AuthNFTPointer, vaultType: Type, auctionStartPrice:UFix64, auctionReservePrice:UFix64, auctionDuration: UFix64, extentionOnLateBid:UFix64, minimumBidIncrement:UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + self.vaultType=vaultType + self.pointer=pointer + self.auctionStartPrice=auctionStartPrice + self.auctionReservePrice=auctionReservePrice + self.auctionDuration=auctionDuration + self.auctionExtensionOnLateBid=extentionOnLateBid + self.auctionMinBidIncrement=minimumBidIncrement + self.offerCallback=nil + self.auctionStartedAt=nil + self.auctionEndsAt=nil + self.auctionValidUntil=auctionValidUntil + self.saleItemExtraField=saleItemExtraField + self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getExtraFields() : {String:AnyStruct}{ + return self.saleItemExtraField + } + + access(all) fun getPointer() : FindViews.AuthNFTPointer { + return self.pointer + } + access(all) fun getId() : UInt64{ + return self.pointer.getUUID() + } + + access(contract) fun acceptEscrowedBid() : @{FungibleToken.Vault} { + if !self.offerCallback!.check() { + panic("bidder unlinked the bid collection capability. bidder address : ".concat(self.offerCallback!.address.toString())) + } + let path = self.pointer.getNFTCollectionData().publicPath + let vault <- self.offerCallback!.borrow()!.accept(<- self.pointer.withdraw(), path: path) + return <- vault + } + + access(all) fun getRoyalty() : MetadataViews.Royalties { + return self.pointer.getRoyalty() + } + + access(all) fun getBalance() : UFix64 { + if let cb= self.offerCallback { + if !cb.check() { + panic("Bidder unlinked the bid collection capability. bidder address : ".concat(cb.address.toString())) + } + return cb.borrow()!.getBalance(self.getId()) + } + return self.auctionStartPrice + } + + access(all) fun getSeller() : Address { + return self.pointer.owner() + } + + access(all) fun getSellerName() : String? { + let address = self.pointer.owner() + return FIND.reverseLookup(address) + } + + access(all) fun getBuyer() : Address? { + if let cb= self.offerCallback { + return cb.address + } + return nil + } + + access(all) fun getBuyerName() : String? { + if let cb= self.offerCallback { + return FIND.reverseLookup(cb.address) + } + return nil + } + + access(all) fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ + return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) + } + + access(contract) fun setAuctionStarted(_ startedAt: UFix64) { + self.auctionStartedAt=startedAt + } + + access(contract) fun setAuctionEnds(_ endsAt: UFix64){ + self.auctionEndsAt=endsAt + } + + access(all) fun hasAuctionStarted() : Bool { + if let starts = self.auctionStartedAt { + return starts <= Clock.time() + } + return false + } + + access(all) fun hasAuctionEnded() : Bool { + if let ends = self.auctionEndsAt { + return ends < Clock.time() + } + panic("Not a live auction") + } + + access(all) fun hasAuctionMetReservePrice() : Bool { + + let balance=self.getBalance() + + if self.auctionReservePrice== nil { + return false + } + + return balance >= self.auctionReservePrice + } + + access(contract) fun setExtentionOnLateBid(_ time: UFix64) { + self.auctionExtensionOnLateBid=time + } + + access(contract) fun setAuctionDuration(_ duration: UFix64) { + self.auctionDuration=duration + } + + access(contract) fun setReservePrice(_ price: UFix64) { + self.auctionReservePrice=price + } + + access(contract) fun setMinBidIncrement(_ price: UFix64) { + self.auctionMinBidIncrement=price + } + + access(contract) fun setStartAuctionPrice(_ price: UFix64) { + self.auctionStartPrice=price + } + + access(contract) fun setCallback(_ callback: Capability<&MarketBidCollection>?) { + self.offerCallback=callback + } + + access(all) fun getSaleType(): String { + if self.auctionStartedAt != nil { + if self.hasAuctionEnded() { + if self.hasAuctionMetReservePrice() { + return "finished_completed" + } + return "finished_failed" + } + return "active_ongoing" + } + return "active_listed" + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun getListingTypeIdentifier(): String { + return Type<@SaleItem>().identifier + } + + + access(all) fun getItemID() : UInt64 { + return self.pointer.id + } + + access(all) fun getItemType() : Type { + return self.pointer.getItemType() + } + + access(all) fun getAuction(): FindMarket.AuctionItem? { + return FindMarket.AuctionItem(startPrice: self.auctionStartPrice, + currentPrice: self.getBalance(), + minimumBidIncrement: self.auctionMinBidIncrement , + reservePrice: self.auctionReservePrice, + extentionOnLateBid: self.auctionExtensionOnLateBid , + auctionEndsAt: self.auctionEndsAt , + timestamp: Clock.time()) + } + + access(all) fun getFtType() : Type { + return self.vaultType + } + + access(contract) fun setValidUntil(_ time: UFix64?) { + self.auctionValidUntil=time + } + + access(all) fun getValidUntil() : UFix64? { + if self.hasAuctionStarted() { + return self.auctionEndsAt + } + return self.auctionValidUntil + } + + access(all) fun checkPointer() : Bool { + return self.pointer.valid() + } + + access(all) fun checkSoulBound() : Bool { + return self.pointer.checkSoulBound() + } + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} { + return self.saleItemExtraField + } + + access(all) fun getTotalRoyalties() : UFix64 { + return self.totalRoyalties + } + + access(all) fun validateRoyalties() : Bool { + return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getDisplay() : MetadataViews.Display { + return self.pointer.getDisplay() + } + + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData { + return self.pointer.getNFTCollectionData() + } + } + + + access(all) resource interface SaleItemCollectionPublic { + //fetch all the tokens in the collection + access(all) fun getIds(): [UInt64] + access(all) fun containsId(_ id: UInt64): Bool + access(contract) fun registerIncreasedBid(_ id: UInt64, oldBalance:UFix64) + //place a bid on a tokenƒ + access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection>, vaultType:Type) + + //anybody should be able to fulfill an auction as long as it is done + access(all) fun fulfillAuction(_ id: UInt64) + } + + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { + //is this the best approach now or just put the NFT inside the saleItem? + access(contract) var items: @{UInt64: SaleItem} + + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> - pub fun getFtType() : Type { - return self.vaultType - } - - pub fun setValidUntil(_ time: UFix64?) { - self.auctionValidUntil=time - } - - pub fun getValidUntil() : UFix64? { - if self.hasAuctionStarted() { - return self.auctionEndsAt - } - return self.auctionValidUntil - } - - pub fun checkPointer() : Bool { - return self.pointer.valid() - } - - pub fun checkSoulBound() : Bool { - return self.pointer.checkSoulBound() - } + init (_ tenantCapability: Capability<&FindMarket.Tenant>) { + self.items <- {} + self.tenantCapability=tenantCapability + } - pub fun getSaleItemExtraField() : {String : AnyStruct} { - return self.saleItemExtraField - } + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } - pub fun getTotalRoyalties() : UFix64 { - return self.totalRoyalties - } + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } - pub fun validateRoyalties() : Bool { - return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() - } + access(self) fun addBid(id:UInt64, newOffer: Capability<&MarketBidCollection>, oldBalance:UFix64) { + let saleItem=self.borrowAuth(id) + let tenant=self.getTenant() + let nftType=saleItem.getItemType() + let ftType=saleItem.getFtType() - pub fun getDisplay() : MetadataViews.Display { - return self.pointer.getDisplay() - } + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name:"add bid in auction"), seller: self.owner!.address, buyer: newOffer.address) - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData { - return self.pointer.getNFTCollectionData() - } - } + if !actionResult.allowed { + panic(actionResult.message) + } + let timestamp=Clock.time() + let newOfferBalance=newOffer.borrow()?.getBalance(id) ?? panic("The new offer bid capability is invalid.") - pub resource interface SaleItemCollectionPublic { - //fetch all the tokens in the collection - pub fun getIds(): [UInt64] - pub fun containsId(_ id: UInt64): Bool - access(contract) fun registerIncreasedBid(_ id: UInt64, oldBalance:UFix64) + let previousOffer = saleItem.offerCallback - //place a bid on a token - access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, vaultType:Type) + var minBid=oldBalance + saleItem.auctionMinBidIncrement + if previousOffer != nil && newOffer.address != previousOffer!.address { + minBid = previousOffer!.borrow()!.getBalance(id) + saleItem.auctionMinBidIncrement + } - //anybody should be able to fulfill an auction as long as it is done - pub fun fulfillAuction(_ id: UInt64) - } + if newOfferBalance < minBid { + panic("bid ".concat(newOfferBalance.toString()).concat(" must be larger then previous bid+bidIncrement ").concat(minBid.toString())) + } - pub resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { - //is this the best approach now or just put the NFT inside the saleItem? - access(contract) var items: @{UInt64: SaleItem} + var previousBuyer:Address?=nil + if previousOffer != nil && newOffer.address != previousOffer!.address { + if !previousOffer!.check() { + panic("Previous bidder unlinked the bid collection capability. bidder address : ".concat(previousOffer!.address.toString())) + } + previousOffer!.borrow()!.cancelBidFromSaleItem(id) + previousBuyer=previousOffer!.address + } - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> + saleItem.setCallback(newOffer) - init (_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.items <- {} - self.tenantCapability=tenantCapability - } + let suggestedEndTime=timestamp+saleItem.auctionExtensionOnLateBid + if suggestedEndTime > saleItem.auctionEndsAt! { + saleItem.setAuctionEnds(suggestedEndTime) + } - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } + let status="active_ongoing" - pub fun getListingType() : Type { - return Type<@SaleItem>() - } + let seller=self.owner!.address - access(self) fun addBid(id:UInt64, newOffer: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, oldBalance:UFix64) { - let saleItem=self.borrow(id) + let nftInfo=saleItem.toNFTInfo(true) + var previousBuyerName : String?=nil + if let pb= previousBuyer { + previousBuyerName = FIND.reverseLookup(pb) + } - let tenant=self.getTenant() - let nftType=saleItem.getItemType() - let ftType=saleItem.getFtType() + let buyer=newOffer.address - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name:"add bid in auction"), seller: self.owner!.address, buyer: newOffer.address) + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: newOfferBalance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(),startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer: previousBuyer, previousBuyerName:previousBuyerName) - if !actionResult.allowed { - panic(actionResult.message) - } - let timestamp=Clock.time() - let newOfferBalance=newOffer.borrow()?.getBalance(id) ?? panic("The new offer bid capability is invalid.") + } - let previousOffer = saleItem.offerCallback + access(contract) fun registerIncreasedBid(_ id: UInt64, oldBalance:UFix64) { + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } - var minBid=oldBalance + saleItem.auctionMinBidIncrement - if previousOffer != nil && newOffer.address != previousOffer!.address { - minBid = previousOffer!.borrow()!.getBalance(id) + saleItem.auctionMinBidIncrement - } + let saleItem=self.borrow(id) - if newOfferBalance < minBid { - panic("bid ".concat(newOfferBalance.toString()).concat(" must be larger then previous bid+bidIncrement ").concat(minBid.toString())) - } + if !saleItem.hasAuctionStarted() { + panic("Auction is not started") + } - var previousBuyer:Address?=nil - if previousOffer != nil && newOffer.address != previousOffer!.address { - if !previousOffer!.check() { - panic("Previous bidder unlinked the bid collection capability. bidder address : ".concat(previousOffer!.address.toString())) - } - previousOffer!.borrow()!.cancelBidFromSaleItem(id) - previousBuyer=previousOffer!.address - } + if saleItem.hasAuctionEnded() { + panic("Auction has ended") + } - saleItem.setCallback(newOffer) + self.addBid(id: id, newOffer: saleItem.offerCallback!, oldBalance:oldBalance) + } - let suggestedEndTime=timestamp+saleItem.auctionExtensionOnLateBid + //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller + access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection>, vaultType: Type) { - if suggestedEndTime > saleItem.auctionEndsAt! { - saleItem.setAuctionEnds(suggestedEndTime) - } + let timestamp=Clock.time() - let status="active_ongoing" + let id = item.getUUID() - let seller=self.owner!.address + let saleItem=self.borrowAuth(id) - let nftInfo=saleItem.toNFTInfo(true) + if saleItem.hasAuctionStarted() { + if saleItem.hasAuctionEnded() { + panic("Auction has ended") + } - var previousBuyerName : String?=nil - if let pb= previousBuyer { - previousBuyerName = FIND.reverseLookup(pb) - } + if let cb = saleItem.offerCallback { + if cb.address == callback.address { + panic("You already have the latest bid on this item, use the incraseBid transaction") + } + } - let buyer=newOffer.address + self.addBid(id: id, newOffer: callback, oldBalance: saleItem.auctionStartPrice) + return + } - let buyerName=FIND.reverseLookup(buyer!) - let profile = Profile.find(buyer!) - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: newOfferBalance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(),startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer: previousBuyer, previousBuyerName:previousBuyerName) + // If the auction is not started but the start time is set, it falls in here + if let startTime = saleItem.auctionStartedAt { + panic("Auction is not yet started, please place your bid after ".concat(startTime.toString())) + } + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - } + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "bid in auction"), seller: self.owner!.address, buyer: callback.address) - access(contract) fun registerIncreasedBid(_ id: UInt64, oldBalance:UFix64) { + if !actionResult.allowed { + panic(actionResult.message) + } - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } + let balance=callback.borrow()?.getBalance(id) ?? panic("Bidder unlinked bid collection capability. bidder address : ".concat(callback.address.toString())) - let saleItem=self.borrow(id) + if saleItem.auctionStartPrice > balance { + panic("You need to bid more then the starting price of ".concat(saleItem.auctionStartPrice.toString())) + } - if !saleItem.hasAuctionStarted() { - panic("Auction is not started") - } + if let valid = saleItem.getValidUntil() { + if valid < Clock.time() { + panic("This auction listing is already expired") + } + } + saleItem.setCallback(callback) + let duration=saleItem.auctionDuration + let endsAt=timestamp + duration + saleItem.setAuctionStarted(timestamp) + saleItem.setAuctionEnds(endsAt) - if saleItem.hasAuctionEnded() { - panic("Auction has ended") - } + let status="active_ongoing" + let seller=self.owner!.address + let buyer=callback.address + + let nftInfo=saleItem.toNFTInfo(true) - self.addBid(id: id, newOffer: saleItem.offerCallback!, oldBalance:oldBalance) - } - - //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller - access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, vaultType: Type) { - - let timestamp=Clock.time() - - let id = item.getUUID() - - let saleItem=self.borrow(id) - - if saleItem.hasAuctionStarted() { - if saleItem.hasAuctionEnded() { - panic("Auction has ended") - } - - if let cb = saleItem.offerCallback { - if cb.address == callback.address { - panic("You already have the latest bid on this item, use the incraseBid transaction") - } - } - - self.addBid(id: id, newOffer: callback, oldBalance: saleItem.auctionStartPrice) - return - } - - // If the auction is not started but the start time is set, it falls in here - if let startTime = saleItem.auctionStartedAt { - panic("Auction is not yet started, please place your bid after ".concat(startTime.toString())) - } - - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() - - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "bid in auction"), seller: self.owner!.address, buyer: callback.address) - - if !actionResult.allowed { - panic(actionResult.message) - } - - let balance=callback.borrow()?.getBalance(id) ?? panic("Bidder unlinked bid collection capability. bidder address : ".concat(callback.address.toString())) - - if saleItem.auctionStartPrice > balance { - panic("You need to bid more then the starting price of ".concat(saleItem.auctionStartPrice.toString())) - } - - if let valid = saleItem.getValidUntil() { - if valid < Clock.time() { - panic("This auction listing is already expired") - } - } - saleItem.setCallback(callback) - let duration=saleItem.auctionDuration - let endsAt=timestamp + duration - saleItem.setAuctionStarted(timestamp) - saleItem.setAuctionEnds(endsAt) - - let status="active_ongoing" - let seller=self.owner!.address - let buyer=callback.address - - let nftInfo=saleItem.toNFTInfo(true) - - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(),startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer: nil, previousBuyerName:nil) - - } - - pub fun cancel(_ id: UInt64) { - - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - - let saleItem=self.borrow(id) - - var status = "cancel_listing" - if saleItem.checkPointer() { - if !saleItem.validateRoyalties() { - // this has to be here otherwise people cannot delist - status="cancel_royalties_changed" - } else if saleItem.hasAuctionStarted() && saleItem.hasAuctionEnded() { - if saleItem.hasAuctionMetReservePrice() { - panic("Cannot cancel finished auction, fulfill it instead") - } - status="cancel_reserved_not_met" - } - } else { - status = "cancel_ghostlisting" - } - - self.internalCancelAuction(saleItem: saleItem, status: status) - - } - - pub fun relist(_ id: UInt64) { - let saleItem = self.borrow(id) - let pointer= saleItem.pointer - let vaultType= saleItem.vaultType - let auctionStartPrice= saleItem.auctionStartPrice - let auctionReservePrice= saleItem.auctionReservePrice - let auctionDuration = saleItem.auctionDuration - let auctionExtensionOnLateBid = saleItem.auctionExtensionOnLateBid - let minimumBidIncrement = saleItem.auctionMinBidIncrement - var auctionValidUntil= saleItem.auctionValidUntil - let currentTime = Clock.time() - if auctionValidUntil != nil && auctionValidUntil! <= currentTime { - auctionValidUntil = nil - } - var auctionStartedAt = saleItem.auctionStartedAt - if auctionStartedAt != nil && auctionStartedAt! <= currentTime { - auctionStartedAt = nil - } - let saleItemExtraField= saleItem.saleItemExtraField - - self.cancel(id) - self.listForAuction(pointer: pointer, vaultType: vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionStartTime: auctionStartedAt, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) - - } - - access(self) fun internalCancelAuction(saleItem: &SaleItem, status:String) { - - let status=status - let ftType=saleItem.getFtType() - let balance=saleItem.getBalance() - let seller=saleItem.getSeller() - let id=saleItem.getId() - - let tenant=self.getTenant() - - var nftInfo:FindMarket.NFTInfo?=nil - if saleItem.checkPointer() { - nftInfo=saleItem.toNFTInfo(false) - } - - let buyer=saleItem.getBuyer() - if buyer != nil { - let buyerName=FIND.reverseLookup(buyer!) - let profile = Profile.find(buyer!) - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(),startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer: nil, previousBuyerName:nil) - } else { - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: nil, buyerName: nil, buyerAvatar:nil,startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) - } - - if saleItem.offerCallback != nil && saleItem.offerCallback!.check() { - saleItem.offerCallback!.borrow()!.cancelBidFromSaleItem(id) - } - destroy <- self.items.remove(key: id) - } - - - /// fulfillAuction wraps the fulfill method and ensure that only a finished auction can be fulfilled by anybody - pub fun fulfillAuction(_ id: UInt64) { - - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - if self.borrow(id).auctionStartPrice == nil { - panic("Cannot fulfill sale that is not an auction=".concat(id.toString())) - } - - let saleItem = self.borrow(id) - - if saleItem.hasAuctionStarted() { - if !saleItem.hasAuctionEnded() { - panic("Auction has not ended yet") - } - - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() - - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "fulfill auction"), seller: self.owner!.address, buyer: saleItem.offerCallback!.address) - - if !actionResult.allowed { - panic(actionResult.message) - } - - let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType) - - if !saleItem.hasAuctionMetReservePrice() { - self.internalCancelAuction(saleItem: saleItem, status: "cancel_reserved_not_met") - return - } - - let nftInfo= saleItem.toNFTInfo(true) - let royalty=saleItem.getRoyalty() - - let status="sold" - let balance=saleItem.getBalance() - let seller=self.owner!.address - - let buyer=saleItem.getBuyer()! - - let buyerName=FIND.reverseLookup(buyer) - let sellerName = FIND.reverseLookup(seller) - let profile = Profile.find(buyer) - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: sellerName, amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:ftType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer: nil, previousBuyerName:nil) - - let vault <- saleItem.acceptEscrowedBid() - - let resolved : {Address : String} = {} - resolved[buyer] = buyerName ?? "" - resolved[seller] = sellerName ?? "" - resolved[FindMarketAuctionEscrow.account.address] = "find" - // Have to make sure the tenant always have the valid find name - resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name - - FindMarket.pay(tenant:tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:royalty, nftInfo:nftInfo, cuts:cuts, resolver: fun(address:Address): String? { return FIND.reverseLookup(address) }, resolvedAddress: resolved) - - destroy <- self.items.remove(key: id) - return - } - panic("This auction is not live") - - } - - pub fun listForAuction(pointer: FindViews.AuthNFTPointer, vaultType: Type, auctionStartPrice: UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionStartTime: UFix64?, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - - // ensure it is not a 0 dollar listing - if auctionStartPrice <= 0.0 { - panic("Auction start price should be greater than 0") - } - - // ensure it is not a 0 dollar listing - if auctionReservePrice < auctionStartPrice { - panic("Auction reserve price should be greater than Auction start price") - } - - let currentTime = Clock.time() - // ensure validUntil is valid - if auctionValidUntil != nil && auctionValidUntil! < currentTime { - panic("Valid until is before current time") - } - - // if we do this, the auctionStartTime variable from arg is gone - var auctionStartTime = auctionStartTime - // ensure startTime is valid, if auctionStartTime is < currentTime, make it currentTIme (might not be easy to pass in exact time) - if auctionStartTime != nil && auctionStartTime! < currentTime { - auctionStartTime = currentTime - } - - // check soul bound - if pointer.checkSoulBound() { - panic("This item is soul bounded and cannot be traded") - } - - let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice:auctionReservePrice, auctionDuration: auctionDuration, extentionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement:minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) - - // if startTime is set, start the auction at the specified time with intended auction duration - if auctionStartTime != nil { - saleItem.setAuctionStarted(auctionStartTime!) - let endTime = auctionStartTime! + auctionDuration - saleItem.setAuctionEnds(endTime) - } - - let tenant=self.getTenant() - - // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) - if tenant.name == "onefootball" { - // ensure it is not a 0 dollar listing - if auctionStartPrice <= 0.65 { - panic("Auction start price should be greater than 0.65") - } - } - - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() - - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "list item for auction"), seller: self.owner!.address, buyer: nil) - - if !actionResult.allowed { - panic(actionResult.message) - } - let id=pointer.getUUID() - - if self.items[id] != nil { - panic("Auction listing for this item is already created.") - } - - self.items[id] <-! saleItem - let saleItemRef = self.borrow(id) - - var status = "active_listed" - let balance=auctionStartPrice - let seller=self.owner!.address - if auctionStartTime != nil { - if auctionStartTime == currentTime { - status = "active_ongoing" - } else { - status = "inactive_listed" - } - } - - let nftInfo=saleItemRef.toNFTInfo(true) - - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItemRef.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItemRef.auctionReservePrice, status: status, vaultType:ftType.identifier, nft: nftInfo, buyer: nil, buyerName: nil, buyerAvatar:nil, startsAt: saleItemRef.auctionStartedAt, endsAt: saleItemRef.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) - - } - - pub fun getIds(): [UInt64] { - return self.items.keys - } - - pub fun getRoyaltyChangedIds(): [UInt64] { - let ids : [UInt64] = [] - for id in self.getIds() { - let item = self.borrow(id) - if !item.validateRoyalties() { - ids.append(id) - } - } - return ids - } - - pub fun containsId(_ id: UInt64): Bool { - return self.items.containsKey(id) - } - - pub fun borrow(_ id: UInt64): &SaleItem { - if !self.items.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.items[id] as &SaleItem?)! - } - - pub fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { - if !self.items.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.items[id] as &SaleItem{FindMarket.SaleItem}?)! - } - - destroy() { - destroy self.items - } - } - - pub resource Bid : FindMarket.Bid { - access(contract) let from: Capability<&SaleItemCollection{SaleItemCollectionPublic}> - access(contract) let nftCap: Capability<&{NonFungibleToken.Receiver}> - access(contract) let itemUUID: UInt64 - - //this should reflect on what the above uuid is for - access(contract) let vault: @FungibleToken.Vault - access(contract) let vaultType: Type - access(contract) var bidAt: UFix64 - access(contract) let bidExtraField: {String : AnyStruct} - - init(from: Capability<&SaleItemCollection{SaleItemCollectionPublic}>, itemUUID: UInt64, vault: @FungibleToken.Vault, nftCap: Capability<&{NonFungibleToken.Receiver}> , bidExtraField: {String : AnyStruct}) { - self.vaultType= vault.getType() - self.vault <- vault - self.itemUUID=itemUUID - self.from=from - self.bidAt=Clock.time() - self.nftCap=nftCap - self.bidExtraField=bidExtraField - } - - access(contract) fun setBidAt(_ time: UFix64) { - self.bidAt=time - } - - pub fun getBalance() : UFix64 { - return self.vault.balance - } - - pub fun getSellerAddress() : Address { - return self.from.address - } - - pub fun getBidExtraField() : {String : AnyStruct} { - return self.bidExtraField - } - - destroy() { - destroy self.vault - } - } - - pub resource interface MarketBidCollectionPublic { - pub fun getBalance(_ id: UInt64) : UFix64 - pub fun containsId(_ id: UInt64): Bool - access(contract) fun accept(_ nft: @NonFungibleToken.NFT, path:PublicPath) : @FungibleToken.Vault - access(contract) fun cancelBidFromSaleItem(_ id: UInt64) - } - - //A collection stored for bidders/buyers - pub resource MarketBidCollection: MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic { - - access(contract) var bids : @{UInt64: Bid} - access(contract) let receiver: Capability<&{FungibleToken.Receiver}> - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - //not sure we can store this here anymore. think it needs to be in every bid - init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.bids <- {} - self.receiver=receiver - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } - - //called from lease when auction is ended - access(contract) fun accept(_ nft: @NonFungibleToken.NFT, path:PublicPath) : @FungibleToken.Vault { - let id= nft.id - let bid <- self.bids.remove(key: nft.uuid) ?? panic("missing bid") - let vaultRef = &bid.vault as &FungibleToken.Vault - let nftCap = bid.nftCap - if !nftCap.check() { - let cpCap =getAccount(nftCap.address).getCapability<&{NonFungibleToken.CollectionPublic}>(path) - if !cpCap.check() { - panic("Bidder unlinked the nft receiver capability. bidder address : ".concat(bid.nftCap.address.toString())) - } else { - bid.nftCap.borrow()!.deposit(token: <- nft) - } - } else { - bid.nftCap.borrow()!.deposit(token: <- nft) - } - let vault <- vaultRef.withdraw(amount: vaultRef.balance) - destroy bid - return <- vault - } - - pub fun getIds() : [UInt64] { - return self.bids.keys - } - - pub fun containsId(_ id: UInt64) : Bool { - return self.bids.containsKey(id) - } - - pub fun getBidType() : Type { - return Type<@Bid>() - } - - pub fun bid(item: FindViews.ViewReadPointer, vault: @FungibleToken.Vault, nftCap: Capability<&{NonFungibleToken.Receiver}>, bidExtraField: {String : AnyStruct}) { - - if self.owner!.address == item.owner() { - panic("You cannot bid on your own resource") - } - - let uuid=item.getUUID() - - if self.bids[uuid] != nil { - panic("You already have an bid for this item, use increaseBid on that bid") - } - - let tenant=self.getTenant() - let from=getAccount(item.owner()).getCapability<&SaleItemCollection{SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - let vaultType=vault.getType() - - let bid <- create Bid(from: from, itemUUID:uuid, vault: <- vault, nftCap: nftCap, bidExtraField: bidExtraField) - let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for id=".concat(uuid.toString())) - - let callbackCapability =self.owner!.getCapability<&MarketBidCollection{MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - let oldToken <- self.bids[uuid] <- bid - saleItemCollection.registerBid(item: item, callback: callbackCapability, vaultType: vaultType) - destroy oldToken - } - - pub fun fulfillAuction(_ id:UInt64) { - - if self.bids[id] == nil { - panic("You need to have a bid here already") - } - let bid =self.borrowBid(id) - let saleItem=bid.from.borrow()! - saleItem.fulfillAuction(id) - } - - pub fun increaseBid(id: UInt64, vault: @FungibleToken.Vault) { - if self.bids[id] == nil { - panic("You need to have a bid here already") - } - let bid =self.borrowBid(id) - - let oldBalance=bid.vault.balance - - bid.setBidAt(Clock.time()) - bid.vault.deposit(from: <- vault) - if !bid.from.check() { - panic("Seller unlinked SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) - } - bid.from.borrow()!.registerIncreasedBid(id, oldBalance:oldBalance) - } - - //called from saleItem when things are cancelled - //if the bid is canceled from seller then we move the vault tokens back into your vault - access(contract) fun cancelBidFromSaleItem(_ id: UInt64) { - let bid <- self.bids.remove(key: id) ?? panic("missing bid") - let vaultRef = &bid.vault as &FungibleToken.Vault - if !self.receiver.check() { - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(self.receiver.address.toString())) - } - self.receiver.borrow()!.deposit(from: <- vaultRef.withdraw(amount: vaultRef.balance)) - destroy bid - } - - pub fun borrowBid(_ id: UInt64): &Bid { - if !self.bids.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.bids[id] as &Bid?)! - } - - pub fun borrowBidItem(_ id: UInt64): &{FindMarket.Bid} { - if !self.bids.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.bids[id] as &Bid{FindMarket.Bid}?)! - } - - pub fun getBalance(_ id: UInt64) : UFix64 { - let bid= self.borrowBid(id) - return bid.vault.balance - } - - destroy() { - destroy self.bids - } - } - - //Create an empty lease collection that store your leases to a name - pub fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>): @SaleItemCollection { - return <- create SaleItemCollection(tenantCapability) - } - - pub fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) : @MarketBidCollection { - return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) - } - - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? { - if FindMarket.getTenantCapability(marketplace) == nil { - panic("Invalid tenant") - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&SaleItemCollection{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - } - return nil - } - - pub fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>? { - if FindMarket.getTenantCapability(marketplace) == nil { - panic("Invalid tenant") - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&MarketBidCollection{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - } - return nil - } - - init() { - FindMarket.addSaleItemType(Type<@SaleItem>()) - FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) - FindMarket.addMarketBidType(Type<@Bid>()) - FindMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) - } + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(),startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer: nil, previousBuyerName:nil) + + } + + access(Seller) fun cancel(_ id: UInt64) { + + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + + let saleItem=self.borrow(id) + + var status = "cancel_listing" + if saleItem.checkPointer() { + if !saleItem.validateRoyalties() { + // this has to be here otherwise people cannot delist + status="cancel_royalties_changed" + } else if saleItem.hasAuctionStarted() && saleItem.hasAuctionEnded() { + if saleItem.hasAuctionMetReservePrice() { + panic("Cannot cancel finished auction, fulfill it instead") + } + status="cancel_reserved_not_met" + } + } else { + status = "cancel_ghostlisting" + } + + self.internalCancelAuction(saleItem: saleItem, status: status) + + } + + access(Seller) fun relist(_ id: UInt64) { + let saleItem = self.borrow(id) + let pointer= saleItem.getPointer() + let vaultType= saleItem.vaultType + let auctionStartPrice= saleItem.auctionStartPrice + let auctionReservePrice= saleItem.auctionReservePrice + let auctionDuration = saleItem.auctionDuration + let auctionExtensionOnLateBid = saleItem.auctionExtensionOnLateBid + let minimumBidIncrement = saleItem.auctionMinBidIncrement + var auctionValidUntil= saleItem.auctionValidUntil + let currentTime = Clock.time() + if auctionValidUntil != nil && auctionValidUntil! <= currentTime { + auctionValidUntil = nil + } + var auctionStartedAt = saleItem.auctionStartedAt + if auctionStartedAt != nil && auctionStartedAt! <= currentTime { + auctionStartedAt = nil + } + let saleItemExtraField= saleItem.getExtraFields() + + self.cancel(id) + self.listForAuction(pointer: pointer, vaultType: vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionStartTime: auctionStartedAt, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) + + } + + access(self) fun internalCancelAuction(saleItem: &SaleItem, status:String) { + + let status=status + let ftType=saleItem.getFtType() + let balance=saleItem.getBalance() + let seller=saleItem.getSeller() + let id=saleItem.getId() + + let tenant=self.getTenant() + + var nftInfo:FindMarket.NFTInfo?=nil + if saleItem.checkPointer() { + nftInfo=saleItem.toNFTInfo(false) + } + + let buyer=saleItem.getBuyer() + if buyer != nil { + let buyerName=FIND.reverseLookup(buyer!) + let profile = Profile.find(buyer!) + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(),startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer: nil, previousBuyerName:nil) + } else { + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: nil, buyerName: nil, buyerAvatar:nil,startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) + } + + if saleItem.offerCallback != nil && saleItem.offerCallback!.check() { + saleItem.offerCallback!.borrow()!.cancelBidFromSaleItem(id) + } + destroy <- self.items.remove(key: id) + } + + /// fulfillAuction wraps the fulfill method and ensure that only a finished auction can be fulfilled by anybody + access(all) fun fulfillAuction(_ id: UInt64) { + + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + if self.borrow(id).auctionStartPrice == nil { + panic("Cannot fulfill sale that is not an auction=".concat(id.toString())) + } + + let saleItem = self.borrow(id) + + if saleItem.hasAuctionStarted() { + if !saleItem.hasAuctionEnded() { + panic("Auction has not ended yet") + } + + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() + + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "fulfill auction"), seller: self.owner!.address, buyer: saleItem.offerCallback!.address) + + if !actionResult.allowed { + panic(actionResult.message) + } + + let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType) + + if !saleItem.hasAuctionMetReservePrice() { + self.internalCancelAuction(saleItem: saleItem, status: "cancel_reserved_not_met") + return + } + + let nftInfo= saleItem.toNFTInfo(true) + let royalty=saleItem.getRoyalty() + + let status="sold" + let balance=saleItem.getBalance() + let seller=self.owner!.address + + let buyer=saleItem.getBuyer()! + + let buyerName=FIND.reverseLookup(buyer) + let sellerName = FIND.reverseLookup(seller) + let profile = Profile.find(buyer) + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: sellerName, amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:ftType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), startsAt: saleItem.auctionStartedAt, endsAt: saleItem.auctionEndsAt, previousBuyer: nil, previousBuyerName:nil) + + let vault <- saleItem.acceptEscrowedBid() + + let resolved : {Address : String} = {} + resolved[buyer] = buyerName ?? "" + resolved[seller] = sellerName ?? "" + resolved[FindMarketAuctionEscrow.account.address] = "find" + // Have to make sure the tenant always have the valid find name + resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name + + FindMarket.pay(tenant:tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:royalty, nftInfo:nftInfo, cuts:cuts, resolver: fun(address:Address): String? { return FIND.reverseLookup(address) }, resolvedAddress: resolved) + + destroy <- self.items.remove(key: id) + return + } + panic("This auction is not live") + + } + + access(Seller) fun listForAuction(pointer: FindViews.AuthNFTPointer, vaultType: Type, auctionStartPrice: UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionStartTime: UFix64?, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + + // ensure it is not a 0 dollar listing + if auctionStartPrice <= 0.0 { + panic("Auction start price should be greater than 0") + } + + // ensure it is not a 0 dollar listing + if auctionReservePrice < auctionStartPrice { + panic("Auction reserve price should be greater than Auction start price") + } + + let currentTime = Clock.time() + // ensure validUntil is valid + if auctionValidUntil != nil && auctionValidUntil! < currentTime { + panic("Valid until is before current time") + } + + // if we do this, the auctionStartTime variable from arg is gone + var auctionStartTime = auctionStartTime + // ensure startTime is valid, if auctionStartTime is < currentTime, make it currentTIme (might not be easy to pass in exact time) + if auctionStartTime != nil && auctionStartTime! < currentTime { + auctionStartTime = currentTime + } + + // check soul bound + if pointer.checkSoulBound() { + panic("This item is soul bounded and cannot be traded") + } + + let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice:auctionReservePrice, auctionDuration: auctionDuration, extentionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement:minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) + + // if startTime is set, start the auction at the specified time with intended auction duration + if auctionStartTime != nil { + saleItem.setAuctionStarted(auctionStartTime!) + let endTime = auctionStartTime! + auctionDuration + saleItem.setAuctionEnds(endTime) + } + + let tenant=self.getTenant() + + // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) + if tenant.name == "onefootball" { + // ensure it is not a 0 dollar listing + if auctionStartPrice <= 0.65 { + panic("Auction start price should be greater than 0.65") + } + } + + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() + + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "list item for auction"), seller: self.owner!.address, buyer: nil) + + if !actionResult.allowed { + panic(actionResult.message) + } + let id=pointer.getUUID() + + if self.items[id] != nil { + panic("Auction listing for this item is already created.") + } + + self.items[id] <-! saleItem + let saleItemRef = self.borrow(id) + + var status = "active_listed" + let balance=auctionStartPrice + let seller=self.owner!.address + if auctionStartTime != nil { + if auctionStartTime == currentTime { + status = "active_ongoing" + } else { + status = "inactive_listed" + } + } + + let nftInfo=saleItemRef.toNFTInfo(true) + + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItemRef.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItemRef.auctionReservePrice, status: status, vaultType:ftType.identifier, nft: nftInfo, buyer: nil, buyerName: nil, buyerAvatar:nil, startsAt: saleItemRef.auctionStartedAt, endsAt: saleItemRef.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) + + } + + access(all) fun getIds(): [UInt64] { + return self.items.keys + } + + access(all) fun getRoyaltyChangedIds(): [UInt64] { + let ids : [UInt64] = [] + for id in self.getIds() { + let item = self.borrow(id) + if !item.validateRoyalties() { + ids.append(id) + } + } + return ids + } + + access(all) fun containsId(_ id: UInt64): Bool { + return self.items.containsKey(id) + } + + access(all) fun borrow(_ id: UInt64): &SaleItem { + if !self.items.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.items[id])! + } + + access(Seller) fun borrowAuth(_ id: UInt64): auth(Seller) &SaleItem { + if !self.items.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.items[id])! + } + + access(all) fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { + if !self.items.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.items[id])! + } + } + + access(all) resource Bid : FindMarket.Bid { + access(contract) let from: Capability<&SaleItemCollection> + access(contract) let nftCap: Capability<&{NonFungibleToken.Receiver}> + access(contract) let itemUUID: UInt64 + + //this should reflect on what the above uuid is for + access(contract) let vault: @{FungibleToken.Vault} + access(contract) let vaultType: Type + access(contract) var bidAt: UFix64 + access(contract) let bidExtraField: {String : AnyStruct} + + init(from: Capability<&SaleItemCollection>, itemUUID: UInt64, vault: @{FungibleToken.Vault}, nftCap: Capability<&{NonFungibleToken.Receiver}> , bidExtraField: {String : AnyStruct}) { + self.vaultType= vault.getType() + self.vault <- vault + self.itemUUID=itemUUID + self.from=from + self.bidAt=Clock.time() + self.nftCap=nftCap + self.bidExtraField=bidExtraField + } + + access(contract) fun setBidAt(_ time: UFix64) { + self.bidAt=time + } + + access(all) fun getBalance() : UFix64 { + return self.vault.balance + } + + access(all) fun getSellerAddress() : Address { + return self.from.address + } + + access(all) fun getBidExtraField() : {String : AnyStruct} { + return self.bidExtraField + } + } + + access(all) resource interface MarketBidCollectionPublic { + access(all) fun getBalance(_ id: UInt64) : UFix64 + access(all) fun containsId(_ id: UInt64): Bool + access(contract) fun accept(_ nft: @{NonFungibleToken.NFT}, path:PublicPath) : @{FungibleToken.Vault} + access(contract) fun cancelBidFromSaleItem(_ id: UInt64) + } + + // A Buyer can bid, increase bid and fulfill auctions + access(all) entitlement Buyer + + //A collection stored for bidders/buyers + access(all) resource MarketBidCollection: MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic { + + access(contract) var bids : @{UInt64: Bid} + access(contract) let receiver: Capability<&{FungibleToken.Receiver}> + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + //not sure we can store this here anymore. think it needs to be in every bid + init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) { + self.bids <- {} + self.receiver=receiver + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } + + //called from lease when auction is ended + access(contract) fun accept(_ nft: @{NonFungibleToken.NFT}, path:PublicPath) : @{FungibleToken.Vault} { + let id= nft.id + let bid <- self.bids.remove(key: nft.uuid) ?? panic("missing bid") + let vaultRef = &bid.vault as auth(FungibleToken.Withdraw) &{FungibleToken.Vault} + let nftCap = bid.nftCap + if !nftCap.check() { + let cpCap =getAccount(nftCap.address).capabilities.get<&{NonFungibleToken.Collection}>(path)! + if !cpCap.check() { + panic("Bidder unlinked the nft receiver capability. bidder address : ".concat(bid.nftCap.address.toString())) + } else { + bid.nftCap.borrow()!.deposit(token: <- nft) + } + } else { + bid.nftCap.borrow()!.deposit(token: <- nft) + } + let vault <- vaultRef.withdraw(amount: vaultRef.balance) + destroy bid + return <- vault + } + + access(all) fun getIds() : [UInt64] { + return self.bids.keys + } + + access(all) fun containsId(_ id: UInt64) : Bool { + return self.bids.containsKey(id) + } + + access(all) fun getBidType() : Type { + return Type<@Bid>() + } + + access(Buyer) fun bid(item: FindViews.ViewReadPointer, vault: @{FungibleToken.Vault}, nftCap: Capability<&{NonFungibleToken.Receiver}>, bidExtraField: {String : AnyStruct}) { + + if self.owner!.address == item.owner() { + panic("You cannot bid on your own resource") + } + + let uuid=item.getUUID() + + if self.bids[uuid] != nil { + panic("You already have an bid for this item, use increaseBid on that bid") + } + + let tenant=self.getTenant() + let from=getAccount(item.owner()).capabilities.get<&SaleItemCollection>(tenant.getPublicPath(Type<@SaleItemCollection>()))! + let vaultType=vault.getType() + + let bid <- create Bid(from: from, itemUUID:uuid, vault: <- vault, nftCap: nftCap, bidExtraField: bidExtraField) + let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for id=".concat(uuid.toString())) + + let callbackCapability =self.owner!.capabilities.get<&MarketBidCollection>(tenant.getPublicPath(Type<@MarketBidCollection>()))! + let oldToken <- self.bids[uuid] <- bid + saleItemCollection.registerBid(item: item, callback: callbackCapability, vaultType: vaultType) + destroy oldToken + } + + access(all) fun fulfillAuction(_ id:UInt64) { + if self.bids[id] == nil { + panic("You need to have a bid here already") + } + let bid =self.borrowBid(id) + let saleItem=bid.from.borrow()! + saleItem.fulfillAuction(id) + } + + access(Buyer) fun increaseBid(id: UInt64, vault: @{FungibleToken.Vault}) { + if self.bids[id] == nil { + panic("You need to have a bid here already") + } + let bid =self.borrowBid(id) + + let oldBalance=bid.vault.balance + + bid.setBidAt(Clock.time()) + bid.vault.deposit(from: <- vault) + if !bid.from.check() { + panic("Seller unlinked SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) + } + bid.from.borrow()!.registerIncreasedBid(id, oldBalance:oldBalance) + } + + //called from saleItem when things are cancelled + //if the bid is canceled from seller then we move the vault tokens back into your vault + access(contract) fun cancelBidFromSaleItem(_ id: UInt64) { + let bid <- self.bids.remove(key: id) ?? panic("missing bid") + let vaultRef = &bid.vault as auth(FungibleToken.Withdraw) &{FungibleToken.Vault} + if !self.receiver.check() { + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(self.receiver.address.toString())) + } + self.receiver.borrow()!.deposit(from: <- vaultRef.withdraw(amount: vaultRef.balance)) + destroy bid + } + + access(all) fun borrowBid(_ id: UInt64): &Bid { + if !self.bids.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.bids[id])! + } + + access(all) fun borrowBidItem(_ id: UInt64): &{FindMarket.Bid} { + if !self.bids.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.bids[id])! + } + + access(all) fun getBalance(_ id: UInt64) : UFix64 { + let bid= self.borrowBid(id) + return bid.vault.balance + } + } + + //Create an empty lease collection that store your leases to a name + access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>) : @SaleItemCollection { + return <- create SaleItemCollection(tenantCapability) + } + + access(all) fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) : @MarketBidCollection { + return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) + } + + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) + } + return nil + } + + access(all) fun getBidCapability( marketplace:Address, user:Address) : Capability<&{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) + } + return nil + } + + init() { + FindMarket.addSaleItemType(Type<@SaleItem>()) + FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) + FindMarket.addMarketBidType(Type<@Bid>()) + FindMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) + } } diff --git a/contracts/FindMarketAuctionSoft.cdc b/contracts/FindMarketAuctionSoft.cdc index 4f107f0b..047f6e9c 100644 --- a/contracts/FindMarketAuctionSoft.cdc +++ b/contracts/FindMarketAuctionSoft.cdc @@ -1,864 +1,869 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import Clock from "./Clock.cdc" -import FIND from "./FIND.cdc" -import FindMarket from "./FindMarket.cdc" -import Profile from "./Profile.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "Clock" +import "FIND" +import "FindMarket" +import "Profile" // An auction saleItem contract that escrows the FT, does _not_ escrow the NFT -pub contract FindMarketAuctionSoft { - - pub event EnglishAuction(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName:String?, amount: UFix64, auctionReservePrice: UFix64, status: String, vaultType:String, nft:FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) - - pub resource SaleItem : FindMarket.SaleItem { - access(contract) var pointer: FindViews.AuthNFTPointer - access(contract) var vaultType: Type - access(contract) var auctionStartPrice: UFix64 - access(contract) var auctionReservePrice: UFix64 - access(contract) var auctionDuration: UFix64 - access(contract) var auctionMinBidIncrement: UFix64 - access(contract) var auctionExtensionOnLateBid: UFix64 - access(contract) var auctionStartedAt: UFix64? - access(contract) var auctionValidUntil: UFix64? - access(contract) var auctionEndsAt: UFix64? - access(contract) var offerCallback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>? - access(contract) var saleItemExtraField: {String : AnyStruct} - access(contract) let totalRoyalties: UFix64 - - init(pointer: FindViews.AuthNFTPointer, vaultType: Type, auctionStartPrice:UFix64, auctionReservePrice:UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - self.vaultType=vaultType - self.pointer=pointer - self.auctionStartPrice=auctionStartPrice - self.auctionReservePrice=auctionReservePrice - self.auctionDuration=86400.0 - self.auctionExtensionOnLateBid=300.0 - self.auctionMinBidIncrement=10.0 - self.offerCallback=nil - self.auctionStartedAt=nil - self.auctionValidUntil=auctionValidUntil - self.auctionEndsAt=nil - self.saleItemExtraField=saleItemExtraField - self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() - } - - pub fun getId() : UInt64{ - return self.pointer.getUUID() - } - - //Here we do not get a vault back, it is sent in to the method itself - pub fun acceptNonEscrowedBid() { - if self.offerCallback == nil { - panic("There is no bid offer to the item.") - } - if !self.offerCallback!.check() { - panic("Bidder unlinked bid collection capability.") - } - self.offerCallback!.borrow()!.accept(<- self.pointer.withdraw()) - } - - pub fun getRoyalty() : MetadataViews.Royalties { - return self.pointer.getRoyalty() - } - - pub fun getBalance() : UFix64 { - if let cb= self.offerCallback { - return cb.borrow()?.getBalance(self.getId()) ?? panic("Bidder unlinked bid collection capability. bidder address : ".concat(cb.address.toString())) - } - return self.auctionStartPrice - } - - pub fun getSeller() : Address { - return self.pointer.owner() - } - - pub fun getSellerName() : String? { - let address = self.pointer.owner() - return FIND.reverseLookup(address) - } - - pub fun getBuyer() : Address? { - if let cb= self.offerCallback { - return cb.address - } - return nil - } - - pub fun getBuyerName() : String? { - if let cb= self.offerCallback { - return FIND.reverseLookup(cb.address) - } - return nil - } - - pub fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ - return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) - } - - pub fun setAuctionStarted(_ startedAt: UFix64) { - self.auctionStartedAt=startedAt - } - - pub fun setAuctionEnds(_ endsAt: UFix64){ - self.auctionEndsAt=endsAt - } - - pub fun hasAuctionStarted() : Bool { - if let starts = self.auctionStartedAt { - return starts <= Clock.time() - } - return false - } - - pub fun hasAuctionEnded() : Bool { - if let ends = self.auctionEndsAt { - return ends < Clock.time() - } - panic("Not a live auction") - } - - pub fun hasAuctionMetReservePrice() : Bool { - - let balance=self.getBalance() - - if self.auctionReservePrice== nil { - return false - } - - - return balance >= self.auctionReservePrice - } - - pub fun setExtentionOnLateBid(_ time: UFix64) { - self.auctionExtensionOnLateBid=time - } - - pub fun setAuctionDuration(_ duration: UFix64) { - self.auctionDuration=duration - } - - pub fun setReservePrice(_ price: UFix64) { - self.auctionReservePrice=price - } - - pub fun setMinBidIncrement(_ price: UFix64) { - self.auctionMinBidIncrement=price - } - - pub fun setStartAuctionPrice(_ price: UFix64) { - self.auctionStartPrice=price - } - - pub fun setCallback(_ callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>?) { - self.offerCallback=callback - } - - pub fun getSaleType(): String { - if self.auctionStartedAt != nil { - if self.hasAuctionEnded() { - if self.hasAuctionMetReservePrice() { - return "finished_completed" - } - return "finished_failed" - } - return "active_ongoing" - } - return "active_listed" - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun getListingTypeIdentifier() : String { - return Type<@SaleItem>().identifier - } - - pub fun getItemID() : UInt64 { - return self.pointer.id - } - - pub fun getItemType() : Type { - return self.pointer.getItemType() - } - - pub fun getAuction(): FindMarket.AuctionItem? { - return FindMarket.AuctionItem(startPrice: self.auctionStartPrice, - currentPrice: self.getBalance(), - minimumBidIncrement: self.auctionMinBidIncrement , - reservePrice: self.auctionReservePrice, - extentionOnLateBid: self.auctionExtensionOnLateBid , - auctionEndsAt: self.auctionEndsAt , - timestamp: Clock.time()) - } - - pub fun getFtType() : Type { - return self.vaultType - } - - pub fun setValidUntil(_ time: UFix64?) { - self.auctionValidUntil=time - } - - pub fun getValidUntil() : UFix64? { - if self.hasAuctionStarted() { - return self.auctionEndsAt - } - return self.auctionValidUntil - } - - pub fun checkPointer() : Bool { - return self.pointer.valid() - } - - pub fun checkSoulBound() : Bool { - return self.pointer.checkSoulBound() - } - - pub fun getSaleItemExtraField() : {String : AnyStruct} { - return self.saleItemExtraField - } - - pub fun getTotalRoyalties() : UFix64 { - return self.totalRoyalties - } - - pub fun validateRoyalties() : Bool { - return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() - } - - pub fun getDisplay() : MetadataViews.Display { - return self.pointer.getDisplay() - } - - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData { - return self.pointer.getNFTCollectionData() - } - } - - pub resource interface SaleItemCollectionPublic { - //fetch all the tokens in the collection - pub fun getIds(): [UInt64] - pub fun containsId(_ id: UInt64): Bool - access(contract) fun registerIncreasedBid(_ id: UInt64, oldBalance: UFix64) - - //place a bid on a token - access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, vaultType:Type) - - //only buyer can fulfill auctions since he needs to send funds for this type - access(contract) fun fulfillAuction(id: UInt64, vault: @FungibleToken.Vault) - } - - pub resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { - //is this the best approach now or just put the NFT inside the saleItem? - access(contract) var items: @{UInt64: SaleItem} +access(all) contract FindMarketAuctionSoft { + + // A seller can list,delist and relist leases for auction + access(all) entitlement Seller + + access(all) event EnglishAuction(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName:String?, amount: UFix64, auctionReservePrice: UFix64, status: String, vaultType:String, nft:FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) + + access(all) resource SaleItem : FindMarket.SaleItem { + access(contract) var pointer: FindViews.AuthNFTPointer + access(contract) var vaultType: Type + access(contract) var auctionStartPrice: UFix64 + access(contract) var auctionReservePrice: UFix64 + access(contract) var auctionDuration: UFix64 + access(contract) var auctionMinBidIncrement: UFix64 + access(contract) var auctionExtensionOnLateBid: UFix64 + access(contract) var auctionStartedAt: UFix64? + access(contract) var auctionValidUntil: UFix64? + access(contract) var auctionEndsAt: UFix64? + access(contract) var offerCallback: Capability<&MarketBidCollection>? + access(contract) var saleItemExtraField: {String : AnyStruct} + access(contract) let totalRoyalties: UFix64 + + init(pointer: FindViews.AuthNFTPointer, vaultType: Type, auctionStartPrice:UFix64, auctionReservePrice:UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + self.vaultType=vaultType + self.pointer=pointer + self.auctionStartPrice=auctionStartPrice + self.auctionReservePrice=auctionReservePrice + self.auctionDuration=86400.0 + self.auctionExtensionOnLateBid=300.0 + self.auctionMinBidIncrement=10.0 + self.offerCallback=nil + self.auctionStartedAt=nil + self.auctionValidUntil=auctionValidUntil + self.auctionEndsAt=nil + self.saleItemExtraField=saleItemExtraField + self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getId() : UInt64{ + return self.pointer.getUUID() + } + + access(all) fun getPointer() : FindViews.AuthNFTPointer { + return self.pointer + } + + //Here we do not get a vault back, it is sent in to the method itself + access(contract) fun acceptNonEscrowedBid() { + if self.offerCallback == nil { + panic("There is no bid offer to the item.") + } + if !self.offerCallback!.check() { + panic("Bidder unlinked bid collection capability.") + } + self.offerCallback!.borrow()!.accept(<- self.pointer.withdraw()) + } + + access(all) fun getRoyalty() : MetadataViews.Royalties { + return self.pointer.getRoyalty() + } + + access(all) fun getBalance() : UFix64 { + if let cb= self.offerCallback { + return cb.borrow()?.getBalance(self.getId()) ?? panic("Bidder unlinked bid collection capability. bidder address : ".concat(cb.address.toString())) + } + return self.auctionStartPrice + } + + access(all) fun getSeller() : Address { + return self.pointer.owner() + } + + access(all) fun getSellerName() : String? { + let address = self.pointer.owner() + return FIND.reverseLookup(address) + } + + access(all) fun getBuyer() : Address? { + if let cb= self.offerCallback { + return cb.address + } + return nil + } + + access(all) fun getBuyerName() : String? { + if let cb= self.offerCallback { + return FIND.reverseLookup(cb.address) + } + return nil + } + + access(all) fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ + return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) + } + + access(contract) fun setAuctionStarted(_ startedAt: UFix64) { + self.auctionStartedAt=startedAt + } + + access(contract) fun setAuctionEnds(_ endsAt: UFix64){ + self.auctionEndsAt=endsAt + } + + access(all) fun hasAuctionStarted() : Bool { + if let starts = self.auctionStartedAt { + return starts <= Clock.time() + } + return false + } + + access(all) fun hasAuctionEnded() : Bool { + if let ends = self.auctionEndsAt { + return ends < Clock.time() + } + panic("Not a live auction") + } + + access(all) fun hasAuctionMetReservePrice() : Bool { + + let balance=self.getBalance() + + if self.auctionReservePrice== nil { + return false + } + + + return balance >= self.auctionReservePrice + } + + access(contract) fun setExtentionOnLateBid(_ time: UFix64) { + self.auctionExtensionOnLateBid=time + } + + access(contract) fun setAuctionDuration(_ duration: UFix64) { + self.auctionDuration=duration + } + + access(contract) fun setReservePrice(_ price: UFix64) { + self.auctionReservePrice=price + } + + access(contract) fun setMinBidIncrement(_ price: UFix64) { + self.auctionMinBidIncrement=price + } + + access(contract) fun setStartAuctionPrice(_ price: UFix64) { + self.auctionStartPrice=price + } + + access(contract) fun setCallback(_ callback: Capability<&MarketBidCollection>?) { + self.offerCallback=callback + } + + access(all) fun getSaleType(): String { + if self.auctionStartedAt != nil { + if self.hasAuctionEnded() { + if self.hasAuctionMetReservePrice() { + return "finished_completed" + } + return "finished_failed" + } + return "active_ongoing" + } + return "active_listed" + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun getListingTypeIdentifier() : String { + return Type<@SaleItem>().identifier + } + + access(all) fun getItemID() : UInt64 { + return self.pointer.id + } + + access(all) fun getItemType() : Type { + return self.pointer.getItemType() + } + + access(all) fun getAuction(): FindMarket.AuctionItem? { + return FindMarket.AuctionItem(startPrice: self.auctionStartPrice, + currentPrice: self.getBalance(), + minimumBidIncrement: self.auctionMinBidIncrement , + reservePrice: self.auctionReservePrice, + extentionOnLateBid: self.auctionExtensionOnLateBid , + auctionEndsAt: self.auctionEndsAt , + timestamp: Clock.time()) + } + + access(all) fun getFtType() : Type { + return self.vaultType + } + + access(Seller) fun setValidUntil(_ time: UFix64?) { + self.auctionValidUntil=time + } + + access(all) fun getValidUntil() : UFix64? { + if self.hasAuctionStarted() { + return self.auctionEndsAt + } + return self.auctionValidUntil + } + + access(all) fun checkPointer() : Bool { + return self.pointer.valid() + } + + access(all) fun checkSoulBound() : Bool { + return self.pointer.checkSoulBound() + } + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} { + return self.saleItemExtraField + } + + access(all) fun getTotalRoyalties() : UFix64 { + return self.totalRoyalties + } + + access(all) fun validateRoyalties() : Bool { + return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getDisplay() : MetadataViews.Display { + return self.pointer.getDisplay() + } + + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData { + return self.pointer.getNFTCollectionData() + } + } + + access(all) resource interface SaleItemCollectionPublic { + //fetch all the tokens in the collection + access(all) fun getIds(): [UInt64] + access(all) fun containsId(_ id: UInt64): Bool + access(contract) fun registerIncreasedBid(_ id: UInt64, oldBalance: UFix64) + + //place a bid on a token + access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection>, vaultType:Type) + + //only buyer can fulfill auctions since he needs to send funds for this type + access(contract) fun fulfillAuction(id: UInt64, vault: @{FungibleToken.Vault}) + } + + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { + //is this the best approach now or just put the NFT inside the saleItem? + access(contract) var items: @{UInt64: SaleItem} - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> - init (_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.items <- {} - self.tenantCapability=tenantCapability - } + init (_ tenantCapability: Capability<&FindMarket.Tenant>) { + self.items <- {} + self.tenantCapability=tenantCapability + } - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } - pub fun getListingType() : Type { - return Type<@SaleItem>() - } + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } - access(self) fun addBid(id:UInt64, newOffer: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, oldBalance: UFix64) { - let saleItem=self.borrow(id) + access(self) fun addBid(id:UInt64, newOffer: Capability<&MarketBidCollection>, oldBalance: UFix64) { + let saleItem=self.borrowAuth(id) - let ftType=saleItem.getFtType() - let nftType=saleItem.getItemType() - let buyer=newOffer.address + let ftType=saleItem.getFtType() + let nftType=saleItem.getItemType() + let buyer=newOffer.address - let tenant = self.getTenant() - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: nftType , ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "add bit in soft-auction"), seller: self.owner!.address ,buyer: buyer) + let tenant = self.getTenant() + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: nftType , ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "add bit in soft-auction"), seller: self.owner!.address ,buyer: buyer) - if !actionResult.allowed { - panic(actionResult.message) - } + if !actionResult.allowed { + panic(actionResult.message) + } - let timestamp=Clock.time() - let newOfferBalance=newOffer.borrow()?.getBalance(id) ?? panic("The new offer bid capability is invalid.") + let timestamp=Clock.time() + let newOfferBalance=newOffer.borrow()?.getBalance(id) ?? panic("The new offer bid capability is invalid.") - let previousOffer = saleItem.offerCallback! + let previousOffer = saleItem.offerCallback! - var minBid=oldBalance + saleItem.auctionMinBidIncrement - if newOffer.address != previousOffer.address { - let previousBalance = previousOffer.borrow()?.getBalance(id) ?? panic("Previous bidder unlinked the bid ccollection capability. bidder address : ".concat(previousOffer.address.toString())) - minBid = previousBalance + saleItem.auctionMinBidIncrement - } + var minBid=oldBalance + saleItem.auctionMinBidIncrement + if newOffer.address != previousOffer.address { + let previousBalance = previousOffer.borrow()?.getBalance(id) ?? panic("Previous bidder unlinked the bid ccollection capability. bidder address : ".concat(previousOffer.address.toString())) + minBid = previousBalance + saleItem.auctionMinBidIncrement + } - if newOfferBalance < minBid { - panic("bid ".concat(newOfferBalance.toString()).concat(" must be larger then previous bid+bidIncrement ").concat(minBid.toString())) - } + if newOfferBalance < minBid { + panic("bid ".concat(newOfferBalance.toString()).concat(" must be larger then previous bid+bidIncrement ").concat(minBid.toString())) + } - var previousBuyer:Address?=nil - if newOffer.address != previousOffer.address { - previousOffer.borrow()!.cancelBidFromSaleItem(id) - previousBuyer=previousOffer.address - } + var previousBuyer:Address?=nil + if newOffer.address != previousOffer.address { + previousOffer.borrow()!.cancelBidFromSaleItem(id) + previousBuyer=previousOffer.address + } - saleItem.setCallback(newOffer) + saleItem.setCallback(newOffer) - let suggestedEndTime=timestamp+saleItem.auctionExtensionOnLateBid + let suggestedEndTime=timestamp+saleItem.auctionExtensionOnLateBid - if suggestedEndTime > saleItem.auctionEndsAt! { - saleItem.setAuctionEnds(suggestedEndTime) - } + if suggestedEndTime > saleItem.auctionEndsAt! { + saleItem.setAuctionEnds(suggestedEndTime) + } - let status = "active_ongoing" - let seller=self.owner!.address + let status = "active_ongoing" + let seller=self.owner!.address - let nftInfo=saleItem.toNFTInfo(true) + let nftInfo=saleItem.toNFTInfo(true) - var previousBuyerName : String?=nil - if let pb= previousBuyer { - previousBuyerName = FIND.reverseLookup(pb) - } + var previousBuyerName : String?=nil + if let pb= previousBuyer { + previousBuyerName = FIND.reverseLookup(pb) + } - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: newOfferBalance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: newOfferBalance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - } + } - access(contract) fun registerIncreasedBid(_ id: UInt64, oldBalance:UFix64) { - if !self.items.containsKey(id) { - panic( "Invalid id=".concat(id.toString())) - } + access(contract) fun registerIncreasedBid(_ id: UInt64, oldBalance:UFix64) { + if !self.items.containsKey(id) { + panic( "Invalid id=".concat(id.toString())) + } - let saleItem=self.borrow(id) + let saleItem=self.borrow(id) - if !saleItem.hasAuctionStarted() { - panic("Auction is not started") - } + if !saleItem.hasAuctionStarted() { + panic("Auction is not started") + } - if saleItem.hasAuctionEnded() { - panic("Auction has ended") - } + if saleItem.hasAuctionEnded() { + panic("Auction has ended") + } - self.addBid(id: id, newOffer: saleItem.offerCallback!, oldBalance: oldBalance) + self.addBid(id: id, newOffer: saleItem.offerCallback!, oldBalance: oldBalance) - } + } - //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller - access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, vaultType: Type) { + //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller + access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection>, vaultType: Type) { - let timestamp=Clock.time() + let timestamp=Clock.time() - let id = item.getUUID() + let id = item.getUUID() - let saleItem=self.borrow(id) - if saleItem.hasAuctionStarted() { - if saleItem.hasAuctionEnded() { - panic("Auction has ended") - } + let saleItem=self.borrowAuth(id) + if saleItem.hasAuctionStarted() { + if saleItem.hasAuctionEnded() { + panic("Auction has ended") + } - if let cb = saleItem.offerCallback { - if cb.address == callback.address { - panic("You already have the latest bid on this item, use the incraseBid transaction") - } - } + if let cb = saleItem.offerCallback { + if cb.address == callback.address { + panic("You already have the latest bid on this item, use the incraseBid transaction") + } + } - self.addBid(id: id, newOffer: callback, oldBalance: 0.0) - return - } + self.addBid(id: id, newOffer: callback, oldBalance: 0.0) + return + } - let ftType=saleItem.getFtType() - let nftType=saleItem.getItemType() + let ftType=saleItem.getFtType() + let nftType=saleItem.getItemType() - let tenant = self.getTenant() - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "bid item in soft-auction"), seller: self.owner!.address, buyer: callback.address) + let tenant = self.getTenant() + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "bid item in soft-auction"), seller: self.owner!.address, buyer: callback.address) - if !actionResult.allowed { - panic(actionResult.message) - } + if !actionResult.allowed { + panic(actionResult.message) + } - let balance=callback.borrow()?.getBalance(id) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) + let balance=callback.borrow()?.getBalance(id) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) - if saleItem.auctionStartPrice > balance { - panic("You need to bid more then the starting price of ".concat(saleItem.auctionStartPrice.toString())) - } + if saleItem.auctionStartPrice > balance { + panic("You need to bid more then the starting price of ".concat(saleItem.auctionStartPrice.toString())) + } - if let valid = saleItem.getValidUntil() { - if valid < Clock.time() { - panic("This auction listing is already expired") - } - } + if let valid = saleItem.getValidUntil() { + if valid < Clock.time() { + panic("This auction listing is already expired") + } + } - saleItem.setCallback(callback) - let duration=saleItem.auctionDuration - let endsAt=timestamp + duration - saleItem.setAuctionStarted(timestamp) - saleItem.setAuctionEnds(endsAt) + saleItem.setCallback(callback) + let duration=saleItem.auctionDuration + let endsAt=timestamp + duration + saleItem.setAuctionStarted(timestamp) + saleItem.setAuctionEnds(endsAt) - let status= "active_ongoing" + let status= "active_ongoing" - let nftInfo=saleItem.toNFTInfo(true) + let nftInfo=saleItem.toNFTInfo(true) - let buyerName=FIND.reverseLookup(callback.address) - let profile = Profile.find(callback.address) - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: callback.address, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) + let buyerName=FIND.reverseLookup(callback.address) + let profile = Profile.find(callback.address) + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: callback.address, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) - } + } - pub fun cancel(_ id: UInt64) { + access(Seller) fun cancel(_ id: UInt64) { - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } - let saleItem=self.borrow(id) + let saleItem=self.borrowAuth(id) - var status="cancel" - if saleItem.checkPointer() { - if !saleItem.validateRoyalties() { - // this has to be here otherwise people cannot delist - status="cancel_royalties_changed" - } else if saleItem.hasAuctionStarted() && saleItem.hasAuctionEnded() { - if saleItem.hasAuctionMetReservePrice() { - panic("Cannot cancel finished auction, fulfill it instead") - } - status="cancel_reserved_not_met" + var status="cancel" + if saleItem.checkPointer() { + if !saleItem.validateRoyalties() { + // this has to be here otherwise people cannot delist + status="cancel_royalties_changed" + } else if saleItem.hasAuctionStarted() && saleItem.hasAuctionEnded() { + if saleItem.hasAuctionMetReservePrice() { + panic("Cannot cancel finished auction, fulfill it instead") + } + status="cancel_reserved_not_met" + + } + } else { + status="cancel_ghostlisting" + } + let ftType=saleItem.getFtType() + let tenant=self.getTenant() + + let balance=saleItem.getBalance() + let seller=self.owner!.address + let buyer=saleItem.getBuyer() - } - } else { - status="cancel_ghostlisting" - } - let ftType=saleItem.getFtType() - let tenant=self.getTenant() + var nftInfo:FindMarket.NFTInfo?=nil + if saleItem.checkPointer() { + nftInfo=saleItem.toNFTInfo(false) + } - let balance=saleItem.getBalance() - let seller=self.owner!.address - let buyer=saleItem.getBuyer() + if buyer != nil { + let buyerName=FIND.reverseLookup(buyer!) + let profile = Profile.find(buyer!) + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:ftType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) + } else { + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:ftType.identifier, nft: nftInfo, buyer: nil, buyerName: nil, buyerAvatar: nil, endsAt: saleItem.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) + } - var nftInfo:FindMarket.NFTInfo?=nil - if saleItem.checkPointer() { - nftInfo=saleItem.toNFTInfo(false) - } + if saleItem.offerCallback != nil && saleItem.offerCallback!.check() { + saleItem.offerCallback!.borrow()!.cancelBidFromSaleItem(id) + } + + destroy <- self.items.remove(key: id) + } + + access(Seller) fun relist(_ id: UInt64) { + let saleItem = self.borrowAuth(id) + let pointer= saleItem.getPointer() + let vaultType= saleItem.vaultType + let auctionStartPrice= saleItem.auctionStartPrice + let auctionReservePrice= saleItem.auctionReservePrice + let auctionDuration = saleItem.auctionDuration + let auctionExtensionOnLateBid = saleItem.auctionExtensionOnLateBid + let minimumBidIncrement = saleItem.auctionMinBidIncrement + var auctionValidUntil= saleItem.auctionValidUntil + if auctionValidUntil != nil && saleItem.auctionValidUntil! <= Clock.time() { + auctionValidUntil = nil + } + let saleItemExtraField= saleItem.getSaleItemExtraField() - if buyer != nil { - let buyerName=FIND.reverseLookup(buyer!) - let profile = Profile.find(buyer!) - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:ftType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) - } else { - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:ftType.identifier, nft: nftInfo, buyer: nil, buyerName: nil, buyerAvatar: nil, endsAt: saleItem.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) - } + self.cancel(id) + self.listForAuction(pointer: pointer, vaultType: vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) + + } + + access(contract) fun fulfillAuction(id: UInt64, vault: @{FungibleToken.Vault}) { + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + + let saleItem = self.borrowAuth(id) + + if !saleItem.hasAuctionStarted() { + panic("This auction is not live") + } + + if !saleItem.hasAuctionEnded() { + panic("Auction has not ended yet") + } + + if vault.getType() != saleItem.vaultType { + panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.vaultType.identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier))) + } - if saleItem.offerCallback != nil && saleItem.offerCallback!.check() { - saleItem.offerCallback!.borrow()!.cancelBidFromSaleItem(id) - } + if vault.balance < saleItem.auctionReservePrice { + panic("cannot fulfill auction reserve price was not met, cancel it without a vault ".concat(vault.balance.toString()).concat(" < ").concat(saleItem.auctionReservePrice.toString())) + } - destroy <- self.items.remove(key: id) - } - - pub fun relist(_ id: UInt64) { - let saleItem = self.borrow(id) - let pointer= saleItem.pointer - let vaultType= saleItem.vaultType - let auctionStartPrice= saleItem.auctionStartPrice - let auctionReservePrice= saleItem.auctionReservePrice - let auctionDuration = saleItem.auctionDuration - let auctionExtensionOnLateBid = saleItem.auctionExtensionOnLateBid - let minimumBidIncrement = saleItem.auctionMinBidIncrement - var auctionValidUntil= saleItem.auctionValidUntil - if auctionValidUntil != nil && saleItem.auctionValidUntil! <= Clock.time() { - auctionValidUntil = nil - } - let saleItemExtraField= saleItem.saleItemExtraField - - self.cancel(id) - self.listForAuction(pointer: pointer, vaultType: vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) - - } - - access(contract) fun fulfillAuction(id: UInt64, vault: @FungibleToken.Vault) { - - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - - let saleItem = self.borrow(id) - - if !saleItem.hasAuctionStarted() { - panic("This auction is not live") - } - - if !saleItem.hasAuctionEnded() { - panic("Auction has not ended yet") - } - - if vault.getType() != saleItem.vaultType { - panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.vaultType.identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier))) - } - - if vault.balance < saleItem.auctionReservePrice { - panic("cannot fulfill auction reserve price was not met, cancel it without a vault ".concat(vault.balance.toString()).concat(" < ").concat(saleItem.auctionReservePrice.toString())) - } - - let ftType=saleItem.getFtType() - let nftType=saleItem.getItemType() - let tenant = self.getTenant() - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name:"buy item for soft-auction"), seller: self.owner!.address,buyer: saleItem.offerCallback!.address) - - if !actionResult.allowed { - panic(actionResult.message) - } - - let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: nftType, ftType: ftType) - - let nftInfo=saleItem.toNFTInfo(true) - let royalty=saleItem.getRoyalty() - - let balance=saleItem.getBalance() - let seller=self.owner!.address - let buyer=saleItem.getBuyer() ?? panic("Buyer is not set.") - - let previousBuyer : Address?=nil - var previousBuyerName : String?=nil - - let status="sold" - let buyerName=FIND.reverseLookup(buyer) - let sellerName=FIND.reverseLookup(seller) - let profile = Profile.find(buyer) - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - - saleItem.acceptNonEscrowedBid() - - let resolved : {Address : String} = {} - resolved[buyer] = buyerName ?? "" - resolved[seller] = sellerName ?? "" - resolved[FindMarketAuctionSoft.account.address] = "find" - // Have to make sure the tenant always have the valid find name - resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name - - - FindMarket.pay(tenant:tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:royalty, nftInfo:nftInfo, cuts:cuts, resolver: FIND.reverseLookupFN(), resolvedAddress: resolved) - - destroy <- self.items.remove(key: id) - - } - - - pub fun listForAuction(pointer: FindViews.AuthNFTPointer, vaultType: Type, auctionStartPrice: UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - - // ensure it is not a 0 dollar listing - if auctionStartPrice <= 0.0 { - panic("Auction start price should be greater than 0") - } - - // ensure it is not a 0 dollar listing - if auctionReservePrice < auctionStartPrice { - panic("Auction reserve price should be greater than Auction start price") - } - - // ensure validUntil is valid - if auctionValidUntil != nil && auctionValidUntil! < Clock.time() { - panic("Valid until is before current time") - } - - // check soul bound - if pointer.checkSoulBound() { - panic("This item is soul bounded and cannot be traded") - } - - let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice:auctionReservePrice, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) - - let tenant = self.getTenant() - - // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) - if tenant.name == "onefootball" { - // ensure it is not a 0 dollar listing - if auctionStartPrice <= 0.65 { - panic("Auction start price should be greater than 0.65") - } - } - - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: pointer.getItemType(), ftType: vaultType, action: FindMarket.MarketAction(listing:true, name:"list item for soft-auction"), seller: self.owner!.address, buyer: nil) - - if !actionResult.allowed { - panic(actionResult.message) - } - - let id = pointer.getUUID() - - if self.items[id] != nil { - panic("Auction listing for this item is already created.") - } - - saleItem.setAuctionDuration(auctionDuration) - saleItem.setExtentionOnLateBid(auctionExtensionOnLateBid) - saleItem.setMinBidIncrement(minimumBidIncrement) - self.items[id] <-! saleItem - let saleItemRef = self.borrow(id) - - let nftInfo=saleItemRef.toNFTInfo(true) - - emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItemRef.uuid, seller:self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: auctionStartPrice, auctionReservePrice: saleItemRef.auctionReservePrice, status: "active_listed", vaultType:vaultType.identifier, nft: nftInfo, buyer: nil, buyerName: nil, buyerAvatar: nil, endsAt: saleItemRef.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) - - } - - pub fun getIds(): [UInt64] { - return self.items.keys - } - - pub fun getRoyaltyChangedIds(): [UInt64] { - let ids : [UInt64] = [] - for id in self.getIds() { - let item = self.borrow(id) - if !item.validateRoyalties() { - ids.append(id) - } - } - return ids - } - - pub fun containsId(_ id: UInt64): Bool { - return self.items.containsKey(id) - } - - pub fun borrow(_ id: UInt64): &SaleItem { - if !self.items.containsKey(id) { - panic( "This id does not exist.".concat(id.toString())) - } - return (&self.items[id] as &SaleItem?)! - } - - pub fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { - if !self.items.containsKey(id) { - panic( "This id does not exist.".concat(id.toString())) - } - return (&self.items[id] as &SaleItem{FindMarket.SaleItem}?)! - } - - destroy() { - destroy self.items - } - } - - pub resource Bid : FindMarket.Bid { - access(contract) let from: Capability<&SaleItemCollection{SaleItemCollectionPublic}> - access(contract) let nftCap: Capability<&{NonFungibleToken.Receiver}> - access(contract) let itemUUID: UInt64 - - access(contract) let vaultType: Type - access(contract) var bidAt: UFix64 - access(contract) var balance: UFix64 - access(contract) let bidExtraField: {String : AnyStruct} - - init(from: Capability<&SaleItemCollection{SaleItemCollectionPublic}>, itemUUID: UInt64, nftCap: Capability<&{NonFungibleToken.Receiver}>, vaultType:Type, balance:UFix64, bidExtraField: {String : AnyStruct}){ - self.vaultType= vaultType - self.balance=balance - self.itemUUID=itemUUID - self.from=from - self.bidAt=Clock.time() - self.nftCap=nftCap - self.bidExtraField=bidExtraField - } - - access(contract) fun setBalance(_ balance:UFix64) { - self.balance=balance - } - - access(contract) fun setBidAt(_ time: UFix64) { - self.bidAt=time - } - - pub fun getBalance() : UFix64 { - return self.balance - } - - pub fun getSellerAddress() : Address { - return self.from.address - } - - pub fun getBidExtraField() : {String : AnyStruct} { - return self.bidExtraField - } - } - - pub resource interface MarketBidCollectionPublic { - pub fun getBalance(_ id: UInt64) : UFix64 - pub fun containsId(_ id: UInt64): Bool - access(contract) fun accept(_ nft: @NonFungibleToken.NFT) - access(contract) fun cancelBidFromSaleItem(_ id: UInt64) - } - - //A collection stored for bidders/buyers - pub resource MarketBidCollection: MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic { - - access(contract) var bids : @{UInt64: Bid} - access(contract) let receiver: Capability<&{FungibleToken.Receiver}> - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - //not sure we can store this here anymore. think it needs to be in every bid - init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.bids <- {} - self.receiver=receiver - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } - - //called from lease when auction is ended - access(contract) fun accept(_ nft: @NonFungibleToken.NFT) { - if self.bids[nft.uuid] == nil { - panic("You need to have a bid here already") - } - let bid <- self.bids.remove(key: nft.uuid) ?? panic("missing bid") - if !bid.nftCap.check() { - panic("Bidder unlinked the nft receiver capability. bidder address : ".concat(bid.nftCap.address.toString())) - } - bid.nftCap.borrow()!.deposit(token: <- nft) - destroy bid - } - - pub fun getIds() : [UInt64] { - return self.bids.keys - } - - pub fun containsId(_ id: UInt64) : Bool { - return self.bids.containsKey(id) - } - - pub fun getBidType() : Type { - return Type<@Bid>() - } - - pub fun bid(item: FindViews.ViewReadPointer, amount:UFix64, vaultType:Type, nftCap: Capability<&{NonFungibleToken.Receiver}>, bidExtraField: {String : AnyStruct}) { - - if self.owner!.address == item.owner() { - panic("You cannot bid on your own resource") - } - - let uuid=item.getUUID() - - if self.bids[uuid] != nil { - panic("You already have an bid for this item, use increaseBid on that bid") - } - let tenant=self.getTenant() - let from=getAccount(item.owner()).getCapability<&SaleItemCollection{SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - - let bid <- create Bid(from: from, itemUUID:uuid, nftCap: nftCap, vaultType: vaultType, balance:amount, bidExtraField: bidExtraField) - let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for id=".concat(uuid.toString())) - - let callbackCapability =self.owner!.getCapability<&MarketBidCollection{MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - let oldToken <- self.bids[uuid] <- bid - saleItemCollection.registerBid(item: item, callback: callbackCapability, vaultType: vaultType) - destroy oldToken - } - - pub fun fulfillAuction(id:UInt64, vault: @FungibleToken.Vault) { - - if self.bids[id] == nil { - panic("You need to have a bid here already") - } - let bid =self.borrowBid(id) - let saleItem=bid.from.borrow()! - saleItem.fulfillAuction(id:id, vault: <- vault) - } - - //increase a bid, will not work if the auction has already started - pub fun increaseBid(id: UInt64, increaseBy: UFix64) { - if self.bids[id] == nil { - panic("You need to have a bid here already") - } - let bid =self.borrowBid(id) - - let oldBalance=bid.balance - - bid.setBidAt(Clock.time()) - bid.setBalance(bid.balance + increaseBy) - - if !bid.from.check(){ - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) - } - bid.from.borrow()!.registerIncreasedBid(id, oldBalance: oldBalance) - } - - //called from saleItem when things are cancelled - //if the bid is canceled from seller then we move the vault tokens back into your vault - access(contract) fun cancelBidFromSaleItem(_ id: UInt64) { - let bid <- self.bids.remove(key: id) ?? panic("missing bid") - destroy bid - } - - pub fun borrowBid(_ id: UInt64): &Bid { - if !self.bids.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.bids[id] as &Bid?)! - } - - pub fun borrowBidItem(_ id: UInt64): &{FindMarket.Bid} { - if !self.bids.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.bids[id] as &Bid{FindMarket.Bid}?)! - } - - pub fun getBalance(_ id: UInt64) : UFix64 { - if self.bids[id] == nil { - panic("You need to have a bid here already") - } - let bid= self.borrowBid(id) - return bid.balance - } - - destroy() { - destroy self.bids - } - } - - //Create an empty lease collection that store your leases to a name - pub fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>): @SaleItemCollection { - return <- create SaleItemCollection(tenantCapability) - } - - pub fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) : @MarketBidCollection { - return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) - } - - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? { - if FindMarket.getTenantCapability(marketplace) == nil { - panic("Invalid tenant") - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&SaleItemCollection{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - } - return nil - } - - pub fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>? { - if FindMarket.getTenantCapability(marketplace) == nil { - panic("Invalid tenant") - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&MarketBidCollection{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - } - return nil - } - - init() { - FindMarket.addSaleItemType(Type<@SaleItem>()) - FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) - FindMarket.addMarketBidType(Type<@Bid>()) - FindMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) - } + let ftType=saleItem.getFtType() + let nftType=saleItem.getItemType() + let tenant = self.getTenant() + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name:"buy item for soft-auction"), seller: self.owner!.address,buyer: saleItem.offerCallback!.address) + if !actionResult.allowed { + panic(actionResult.message) + } + + let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: nftType, ftType: ftType) + + let nftInfo=saleItem.toNFTInfo(true) + let royalty=saleItem.getRoyalty() + + let balance=saleItem.getBalance() + let seller=self.owner!.address + let buyer=saleItem.getBuyer() ?? panic("Buyer is not set.") + + let previousBuyer : Address?=nil + var previousBuyerName : String?=nil + + let status="sold" + let buyerName=FIND.reverseLookup(buyer) + let sellerName=FIND.reverseLookup(seller) + let profile = Profile.find(buyer) + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:seller, sellerName: FIND.reverseLookup(seller), amount: balance, auctionReservePrice: saleItem.auctionReservePrice, status: status, vaultType:saleItem.vaultType.identifier, nft: nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.auctionEndsAt, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) + + saleItem.acceptNonEscrowedBid() + + let resolved : {Address : String} = {} + resolved[buyer] = buyerName ?? "" + resolved[seller] = sellerName ?? "" + resolved[FindMarketAuctionSoft.account.address] = "find" + // Have to make sure the tenant always have the valid find name + resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name + + + FindMarket.pay(tenant:tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:royalty, nftInfo:nftInfo, cuts:cuts, resolver: FIND.reverseLookupFN(), resolvedAddress: resolved) + + destroy <- self.items.remove(key: id) + + } + + + access(Seller) fun listForAuction(pointer: FindViews.AuthNFTPointer, vaultType: Type, auctionStartPrice: UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionValidUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + // ensure it is not a 0 dollar listing + if auctionStartPrice <= 0.0 { + panic("Auction start price should be greater than 0") + } + + // ensure it is not a 0 dollar listing + if auctionReservePrice < auctionStartPrice { + panic("Auction reserve price should be greater than Auction start price") + } + + // ensure validUntil is valid + if auctionValidUntil != nil && auctionValidUntil! < Clock.time() { + panic("Valid until is before current time") + } + + // check soul bound + if pointer.checkSoulBound() { + panic("This item is soul bounded and cannot be traded") + } + + let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, auctionStartPrice: auctionStartPrice, auctionReservePrice:auctionReservePrice, auctionValidUntil: auctionValidUntil, saleItemExtraField: saleItemExtraField) + + let tenant = self.getTenant() + + // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) + if tenant.name == "onefootball" { + // ensure it is not a 0 dollar listing + if auctionStartPrice <= 0.65 { + panic("Auction start price should be greater than 0.65") + } + } + + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketAuctionSoft.SaleItem>(), nftType: pointer.getItemType(), ftType: vaultType, action: FindMarket.MarketAction(listing:true, name:"list item for soft-auction"), seller: self.owner!.address, buyer: nil) + + if !actionResult.allowed { + panic(actionResult.message) + } + + let id = pointer.getUUID() + + if self.items[id] != nil { + panic("Auction listing for this item is already created.") + } + + saleItem.setAuctionDuration(auctionDuration) + saleItem.setExtentionOnLateBid(auctionExtensionOnLateBid) + saleItem.setMinBidIncrement(minimumBidIncrement) + self.items[id] <-! saleItem + let saleItemRef = self.borrow(id) + + let nftInfo=saleItemRef.toNFTInfo(true) + + emit EnglishAuction(tenant:tenant.name, id: id, saleID: saleItemRef.uuid, seller:self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: auctionStartPrice, auctionReservePrice: saleItemRef.auctionReservePrice, status: "active_listed", vaultType:vaultType.identifier, nft: nftInfo, buyer: nil, buyerName: nil, buyerAvatar: nil, endsAt: saleItemRef.auctionEndsAt, previousBuyer:nil, previousBuyerName:nil) + + } + + access(all) fun getIds(): [UInt64] { + return self.items.keys + } + + access(all) fun getRoyaltyChangedIds(): [UInt64] { + let ids : [UInt64] = [] + for id in self.getIds() { + let item = self.borrow(id) + if !item.validateRoyalties() { + ids.append(id) + } + } + return ids + } + + access(all) fun containsId(_ id: UInt64): Bool { + return self.items.containsKey(id) + } + + access(all) fun borrow(_ id: UInt64): &SaleItem { + if !self.items.containsKey(id) { + panic( "This id does not exist.".concat(id.toString())) + } + return (&self.items[id])! + } + + access(Seller) fun borrowAuth(_ id: UInt64): auth(Seller) &SaleItem { + if !self.items.containsKey(id) { + panic( "This id does not exist.".concat(id.toString())) + } + return (&self.items[id])! + } + + access(all) fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { + if !self.items.containsKey(id) { + panic( "This id does not exist.".concat(id.toString())) + } + return (&self.items[id])! + } + } + + access(all) resource Bid : FindMarket.Bid { + access(contract) let from: Capability<&SaleItemCollection> + access(contract) let nftCap: Capability<&{NonFungibleToken.Receiver}> + access(contract) let itemUUID: UInt64 + + access(contract) let vaultType: Type + access(contract) var bidAt: UFix64 + access(contract) var balance: UFix64 + access(contract) let bidExtraField: {String : AnyStruct} + + init(from: Capability<&SaleItemCollection>, itemUUID: UInt64, nftCap: Capability<&{NonFungibleToken.Receiver}>, vaultType:Type, balance:UFix64, bidExtraField: {String : AnyStruct}){ + self.vaultType= vaultType + self.balance=balance + self.itemUUID=itemUUID + self.from=from + self.bidAt=Clock.time() + self.nftCap=nftCap + self.bidExtraField=bidExtraField + } + + access(contract) fun setBalance(_ balance:UFix64) { + self.balance=balance + } + + access(contract) fun setBidAt(_ time: UFix64) { + self.bidAt=time + } + + access(all) fun getBalance() : UFix64 { + return self.balance + } + + access(all) fun getSellerAddress() : Address { + return self.from.address + } + + access(all) fun getBidExtraField() : {String : AnyStruct} { + return self.bidExtraField + } + } + + access(all) resource interface MarketBidCollectionPublic { + access(all) fun getBalance(_ id: UInt64) : UFix64 + access(all) fun containsId(_ id: UInt64): Bool + access(contract) fun accept(_ nft: @{NonFungibleToken.NFT}) + access(contract) fun cancelBidFromSaleItem(_ id: UInt64) + } + + access(all) entitlement Buyer + + //A collection stored for bidders/buyers + access(all) resource MarketBidCollection: MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic { + + access(contract) var bids : @{UInt64: Bid} + access(contract) let receiver: Capability<&{FungibleToken.Receiver}> + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + //not sure we can store this here anymore. think it needs to be in every bid + init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) { + self.bids <- {} + self.receiver=receiver + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } + + //called from lease when auction is ended + access(contract) fun accept(_ nft: @{NonFungibleToken.NFT}) { + if self.bids[nft.uuid] == nil { + panic("You need to have a bid here already") + } + let bid <- self.bids.remove(key: nft.uuid) ?? panic("missing bid") + if !bid.nftCap.check() { + panic("Bidder unlinked the nft receiver capability. bidder address : ".concat(bid.nftCap.address.toString())) + } + bid.nftCap.borrow()!.deposit(token: <- nft) + destroy bid + } + + access(all) fun getIds() : [UInt64] { + return self.bids.keys + } + + access(all) fun containsId(_ id: UInt64) : Bool { + return self.bids.containsKey(id) + } + + access(all) fun getBidType() : Type { + return Type<@Bid>() + } + + access(Buyer) fun bid(item: FindViews.ViewReadPointer, amount:UFix64, vaultType:Type, nftCap: Capability<&{NonFungibleToken.Receiver}>, bidExtraField: {String : AnyStruct}) { + + if self.owner!.address == item.owner() { + panic("You cannot bid on your own resource") + } + + let uuid=item.getUUID() + + if self.bids[uuid] != nil { + panic("You already have an bid for this item, use increaseBid on that bid") + } + let tenant=self.getTenant() + let from=getAccount(item.owner()).capabilities.get<&SaleItemCollection>(tenant.getPublicPath(Type<@SaleItemCollection>()))! + + let bid <- create Bid(from: from, itemUUID:uuid, nftCap: nftCap, vaultType: vaultType, balance:amount, bidExtraField: bidExtraField) + let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for id=".concat(uuid.toString())) + + let callbackCapability =self.owner!.capabilities.get<&MarketBidCollection>(tenant.getPublicPath(Type<@MarketBidCollection>()))! + let oldToken <- self.bids[uuid] <- bid + saleItemCollection.registerBid(item: item, callback: callbackCapability, vaultType: vaultType) + destroy oldToken + } + + access(all) fun fulfillAuction(id:UInt64, vault: @{FungibleToken.Vault}) { + + if self.bids[id] == nil { + panic("You need to have a bid here already") + } + let bid =self.borrowBid(id) + let saleItem=bid.from.borrow()! + saleItem.fulfillAuction(id:id, vault: <- vault) + } + + //increase a bid, will not work if the auction has already started + access(Buyer) fun increaseBid(id: UInt64, increaseBy: UFix64) { + if self.bids[id] == nil { + panic("You need to have a bid here already") + } + let bid =self.borrowBid(id) + + let oldBalance=bid.balance + + bid.setBidAt(Clock.time()) + bid.setBalance(bid.balance + increaseBy) + + if !bid.from.check(){ + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) + } + bid.from.borrow()!.registerIncreasedBid(id, oldBalance: oldBalance) + } + + //called from saleItem when things are cancelled + //if the bid is canceled from seller then we move the vault tokens back into your vault + access(contract) fun cancelBidFromSaleItem(_ id: UInt64) { + let bid <- self.bids.remove(key: id) ?? panic("missing bid") + destroy bid + } + + access(all) fun borrowBid(_ id: UInt64): &Bid { + if !self.bids.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.bids[id])! + } + + access(all) fun borrowBidItem(_ id: UInt64): &{FindMarket.Bid} { + if !self.bids.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.bids[id])! + } + + access(all) fun getBalance(_ id: UInt64) : UFix64 { + if self.bids[id] == nil { + panic("You need to have a bid here already") + } + let bid= self.borrowBid(id) + return bid.balance + } + } + + //Create an empty lease collection that store your leases to a name + access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>) : @SaleItemCollection { + return <- create SaleItemCollection(tenantCapability) + } + + access(all) fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) : @MarketBidCollection { + return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) + } + + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&SaleItemCollection>(tenant.getPublicPath(Type<@SaleItemCollection>())) + } + return nil + } + + access(all) fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&MarketBidCollection>(tenant.getPublicPath(Type<@MarketBidCollection>())) + } + return nil + } + + init() { + FindMarket.addSaleItemType(Type<@SaleItem>()) + FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) + FindMarket.addMarketBidType(Type<@Bid>()) + FindMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) + } } diff --git a/contracts/FindMarketCut.cdc b/contracts/FindMarketCut.cdc index 990138f6..21c93c22 100644 --- a/contracts/FindMarketCut.cdc +++ b/contracts/FindMarketCut.cdc @@ -1,88 +1,88 @@ -import FindMarketCutStruct from "../contracts/FindMarketCutStruct.cdc" -import FindMarketCutInterface from "../contracts/FindMarketCutInterface.cdc" -import FindUtils from "../contracts/FindUtils.cdc" +import "FindMarketCutStruct" +import "FindMarketCutInterface" +import "FindUtils" -pub contract FindMarketCut { +access(all) contract FindMarketCut { - pub let categoryToContractName: {String : String} + access(all) let categoryToContractName: {String : String} - pub event Cut(tenant: String, type: String, category: String, contractName: String, cutInfo: [FindMarketCutStruct.EventSafeCut], action: String, remark: String?) + access(all) event Cut(tenant: String, type: String, category: String, contractName: String, cutInfo: [FindMarketCutStruct.EventSafeCut], action: String, remark: String?) - pub fun getRuleId(listingType: Type, nftType:Type, ftType:Type) : String { - let s : [String] = [listingType.identifier, nftType.identifier, ftType.identifier] - return FindUtils.joinString(s, sep: "-") - } + access(all) fun getRuleId(listingType: Type, nftType:Type, ftType:Type) : String { + let s : [String] = [listingType.identifier, nftType.identifier, ftType.identifier] + return FindUtils.joinString(s, sep: "-") + } - pub fun getCuts(tenant: String, listingType: Type, nftType:Type, ftType:Type): {String : FindMarketCutStruct.Cuts} { - let res : {String : FindMarketCutStruct.Cuts} = {} - for category in self.categoryToContractName.keys { - let contractName = self.categoryToContractName[category]! - let con = self.borrowContract(contractName) - if let cut = con.getCut(tenant: tenant, listingType: listingType, nftType: nftType, ftType: ftType) { - res[category] = cut - } - } - return res - } + access(all) fun getCuts(tenant: String, listingType: Type, nftType:Type, ftType:Type): {String : FindMarketCutStruct.Cuts} { + let res : {String : FindMarketCutStruct.Cuts} = {} + for category in self.categoryToContractName.keys { + let contractName = self.categoryToContractName[category]! + let con = self.borrowContract(contractName) + if let cut = con.getCut(tenant: tenant, listingType: listingType, nftType: nftType, ftType: ftType) { + res[category] = cut + } + } + return res + } - // Helper functions for setting up cuts - access(contract) fun borrowContract(_ contractName: String) : &FindMarketCutInterface { - var identifier = contractName - if let category = self.categoryToContractName[contractName] { - identifier = category - } - return self.account.contracts.borrow<&FindMarketCutInterface>(name: identifier) ?? panic("Cannor borrow contract with identifier : ".concat(identifier)) - } + // Helper functions for setting up cuts + access(contract) fun borrowContract(_ contractName: String) : &{FindMarketCutInterface} { + var identifier = contractName + if let category = self.categoryToContractName[contractName] { + identifier = category + } + //TODO:deploy + return self.account.contracts.borrow<&{FindMarketCutInterface}>(name: identifier) ?? panic("Cannor borrow contract with identifier : ".concat(identifier)) + } - access(account) fun setTenantCuts(tenant: String, types: [Type], category: String, cuts: FindMarketCutStruct.Cuts) { - let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) - let con = self.borrowContract(contractName) - con.setTenantCuts(tenant: tenant, types: types, cuts: cuts) - let cutInfo = cuts.getEventSafeCuts() - for t in types { - emit Cut(tenant: tenant, type: t.identifier, category: category, contractName: contractName, cutInfo: cutInfo, action: "add", remark: nil) - } - } + access(account) fun setTenantCuts(tenant: String, types: [Type], category: String, cuts: FindMarketCutStruct.Cuts) { + let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) + let con = self.borrowContract(contractName) + con.setTenantCuts(tenant: tenant, types: types, cuts: cuts) + let cutInfo = cuts.getEventSafeCuts() + for t in types { + emit Cut(tenant: tenant, type: t.identifier, category: category, contractName: contractName, cutInfo: cutInfo, action: "add", remark: nil) + } + } - access(account) fun removeTenantCuts(tenant: String, types: [Type], category: String) { - let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) - let con = self.borrowContract(contractName) - let cuts = con.removeTenantCuts(tenant: tenant, types: types) - for i, t in types { - let cutInfo = cuts[i].getEventSafeCuts() - emit Cut(tenant: tenant, type: t.identifier, category: category, contractName: contractName, cutInfo: cutInfo, action: "remove", remark: nil) - } - } + access(account) fun removeTenantCuts(tenant: String, types: [Type], category: String) { + let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) + let con = self.borrowContract(contractName) + let cuts = con.removeTenantCuts(tenant: tenant, types: types) + for i, t in types { + let cutInfo = cuts[i].getEventSafeCuts() + emit Cut(tenant: tenant, type: t.identifier, category: category, contractName: contractName, cutInfo: cutInfo, action: "remove", remark: nil) + } + } - access(account) fun setTenantRulesCache(tenant: String, ruleId: String, category: String, result: FindMarketCutStruct.Cuts) { - let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) - let con = self.borrowContract(contractName) - con.setTenantRulesCache(tenant: tenant, ruleId: ruleId, result: result) - } + access(account) fun setTenantRulesCache(tenant: String, ruleId: String, category: String, result: FindMarketCutStruct.Cuts) { + let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) + let con = self.borrowContract(contractName) + con.setTenantRulesCache(tenant: tenant, ruleId: ruleId, result: result) + } - pub fun getTenantRules(tenant: String, ruleId: String, category: String) : FindMarketCutStruct.Cuts? { - let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) - let con = self.borrowContract(contractName) - let res = con.getTenantRulesCache(tenant: tenant, ruleId: ruleId) - return res - } + access(all) fun getTenantRules(tenant: String, ruleId: String, category: String) : FindMarketCutStruct.Cuts? { + let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) + let con = self.borrowContract(contractName) + let res = con.getTenantRulesCache(tenant: tenant, ruleId: ruleId) + return res + } - access(account) fun resetTenantRulesCache(tenant: String, category: String) { - let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) - let con = self.borrowContract(contractName) - con.resetTenantRulesCache(tenant) - } + access(account) fun resetTenantRulesCache(tenant: String, category: String) { + let contractName = self.categoryToContractName[category] ?? panic("Category is not set to link with contract. Category ".concat(category)) + let con = self.borrowContract(contractName) + con.resetTenantRulesCache(tenant) + } - access(account) fun setCategory(category: String, contractName: String) { - self.categoryToContractName[category] = contractName - } + access(account) fun setCategory(category: String, contractName: String) { + self.categoryToContractName[category] = contractName + } - access(account) fun removeCategory(category: String) { - self.categoryToContractName.remove(key: category) ?? panic("Category is not set to link with contract. Category ".concat(category)) - } - - init(){ - self.categoryToContractName = {} - } + access(account) fun removeCategory(category: String) { + self.categoryToContractName.remove(key: category) ?? panic("Category is not set to link with contract. Category ".concat(category)) + } + init(){ + self.categoryToContractName = {} + } } diff --git a/contracts/FindMarketCutInterface.cdc b/contracts/FindMarketCutInterface.cdc index e2371af0..6740e9d5 100644 --- a/contracts/FindMarketCutInterface.cdc +++ b/contracts/FindMarketCutInterface.cdc @@ -1,17 +1,16 @@ -import FindMarketCutStruct from "../contracts/FindMarketCutStruct.cdc" +import "FindMarketCutStruct" -pub contract interface FindMarketCutInterface { +access(all) contract interface FindMarketCutInterface { - pub let contractName: String - pub let category: String + access(all) let contractName: String + access(all) let category: String - pub event Cut(tenant: String, type: String, cutInfo: [FindMarketCutStruct.EventSafeCut], action: String, remark: String?) - - access(account) fun setTenantCuts(tenant: String, types: [Type], cuts: FindMarketCutStruct.Cuts) - access(account) fun removeTenantCuts(tenant: String, types: [Type]) : [FindMarketCutStruct.Cuts] - access(account) fun setTenantRulesCache(tenant: String, ruleId: String, result: FindMarketCutStruct.Cuts) - pub fun getTenantRulesCache(tenant: String, ruleId: String) : FindMarketCutStruct.Cuts? - pub fun getCut(tenant: String, listingType: Type, nftType: Type, ftType: Type) : FindMarketCutStruct.Cuts? - access(account) fun resetTenantRulesCache(_ tenant: String) + access(all) event Cut(tenant: String, type: String, cutInfo: [FindMarketCutStruct.EventSafeCut], action: String, remark: String?) + access(account) fun setTenantCuts(tenant: String, types: [Type], cuts: FindMarketCutStruct.Cuts) + access(account) fun removeTenantCuts(tenant: String, types: [Type]) : [FindMarketCutStruct.Cuts] + access(account) fun setTenantRulesCache(tenant: String, ruleId: String, result: FindMarketCutStruct.Cuts) + access(all) fun getTenantRulesCache(tenant: String, ruleId: String) : FindMarketCutStruct.Cuts? + access(all) fun getCut(tenant: String, listingType: Type, nftType: Type, ftType: Type) : FindMarketCutStruct.Cuts? + access(account) fun resetTenantRulesCache(_ tenant: String) } diff --git a/contracts/FindMarketCutStruct.cdc b/contracts/FindMarketCutStruct.cdc index 543e9f96..d18addee 100644 --- a/contracts/FindMarketCutStruct.cdc +++ b/contracts/FindMarketCutStruct.cdc @@ -1,167 +1,166 @@ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" - -pub contract FindMarketCutStruct { - - pub struct Cuts { - pub let cuts : [{Cut}] - access(contract) let extra: {String : AnyStruct} - - init(cuts: [{Cut}]) { - self.cuts = cuts - self.extra = {} - } - - pub fun getEventSafeCuts() : [EventSafeCut] { - let cuts : [EventSafeCut] = [] - for c in self.cuts { - cuts.append(c.getEventSafeCut()) - } - return cuts - } - } - - pub struct EventSafeCut { - pub let name: String - pub let description: String - pub let cut: UFix64 - pub let receiver: Address - pub let extra: {String : String} - - init(name: String, description: String, cut: UFix64, receiver: Address, extra: {String : String}) { - self.name = name - self.description = description - self.cut = cut - self.receiver = receiver - self.extra = extra - } - } - - pub struct interface Cut { - pub fun getName() : String - pub fun getReceiverCap() : Capability<&{FungibleToken.Receiver}> - pub fun getCut() : UFix64 - pub fun getAddress() : Address - pub fun getDescription() : String - pub fun getPayableLogic() : ((UFix64) : UFix64?) - pub fun getExtra() : {String : String} - - pub fun getRoyalty() : MetadataViews.Royalty { - let cap = self.getReceiverCap() - return MetadataViews.Royalty(receiver: cap, cut: self.getCut(), description: self.getName()) - } - - pub fun getAmountPayable(_ salePrice: UFix64) : UFix64? { - if let cut = self.getPayableLogic()(salePrice) { - return cut - } - return nil - } - - pub fun getEventSafeCut() : EventSafeCut { - return EventSafeCut( - name: self.getName(), - description: self.getDescription(), - cut: self.getCut(), - receiver: self.getAddress(), - extra: self.getExtra() - ) - } - } - - pub struct GeneralCut : Cut { - // This is the description of the royalty struct - pub let name : String - pub let cap: Capability<&{FungibleToken.Receiver}> - pub let cut: UFix64 - // This is the description to the cut that can be visible to give detail on detail page - pub let description: String - access(self) let extra : {String : AnyStruct} - - init(name : String, cap: Capability<&{FungibleToken.Receiver}>, cut: UFix64, description: String) { - self.name = name - self.cap = cap - self.cut = cut - self.description = description - self.extra = {} - } - - pub fun getReceiverCap() : Capability<&{FungibleToken.Receiver}> { - return self.cap - } - pub fun getName() : String { - return self.name - } - pub fun getCut() : UFix64 { - return self.cut - } - pub fun getAddress() : Address { - return self.cap.address - } - pub fun getDescription() : String { - return self.description - } - pub fun getExtra() : {String : String} { - return {} - } - - pub fun getPayableLogic() : ((UFix64) : UFix64?) { - return fun(_ salePrice : UFix64) : UFix64? { - return salePrice * self.cut - } - } - } - - pub struct ThresholdCut : Cut { - // This is the description of the royalty struct - pub let name : String - pub let address: Address - pub let cut: UFix64 - // This is the description to the cut that can be visible to give detail on detail page - pub let description: String - pub let publicPath: String - pub let minimumPayment: UFix64 - access(self) let extra : {String : AnyStruct} - - init(name : String , address: Address , cut: UFix64 , description: String , publicPath: String, minimumPayment: UFix64) { - self.name = name - self.address = address - self.cut = cut - self.description = description - self.publicPath = publicPath - self.minimumPayment = minimumPayment - self.extra = {} - } - - pub fun getReceiverCap() : Capability<&{FungibleToken.Receiver}> { - let pp = PublicPath(identifier: self.publicPath)! - return getAccount(self.address).getCapability<&{FungibleToken.Receiver}>(pp) - } - pub fun getName() : String { - return self.name - } - pub fun getCut() : UFix64 { - return self.cut - } - pub fun getAddress() : Address { - return self.address - } - pub fun getDescription() : String { - return self.description - } - pub fun getExtra() : {String : String} { - return {} - } - - pub fun getPayableLogic() : ((UFix64) : UFix64?) { - return fun(_ salePrice : UFix64) : UFix64? { - let rPayable = salePrice * self.cut - if rPayable < self.minimumPayment { - return self.minimumPayment - } - return rPayable - } - } - } - +import "FungibleToken" +import "MetadataViews" + +access(all) contract FindMarketCutStruct { + + access(all) struct Cuts { + access(all) let cuts : [{Cut}] + access(contract) let extra: {String : AnyStruct} + + init(cuts: [{Cut}]) { + self.cuts = cuts + self.extra = {} + } + + access(all) fun getEventSafeCuts() : [EventSafeCut] { + let cuts : [EventSafeCut] = [] + for c in self.cuts { + cuts.append(c.getEventSafeCut()) + } + return cuts + } + } + + access(all) struct EventSafeCut { + access(all) let name: String + access(all) let description: String + access(all) let cut: UFix64 + access(all) let receiver: Address + access(all) let extra: {String : String} + + init(name: String, description: String, cut: UFix64, receiver: Address, extra: {String : String}) { + self.name = name + self.description = description + self.cut = cut + self.receiver = receiver + self.extra = extra + } + } + + access(all) struct interface Cut { + access(all) fun getName() : String + access(all) fun getReceiverCap() : Capability<&{FungibleToken.Receiver}> + access(all) fun getCut() : UFix64 + access(all) fun getAddress() : Address + access(all) fun getDescription() : String + access(all) fun getPayableLogic() : (fun(UFix64) : UFix64?) + access(all) fun getExtra() : {String : String} + + access(all) fun getRoyalty() : MetadataViews.Royalty { + let cap = self.getReceiverCap() + return MetadataViews.Royalty(receiver: cap, cut: self.getCut(), description: self.getName()) + } + + access(all) fun getAmountPayable(_ salePrice: UFix64) : UFix64? { + if let cut = self.getPayableLogic()(salePrice) { + return cut + } + return nil + } + + access(all) fun getEventSafeCut() : EventSafeCut { + return EventSafeCut( + name: self.getName(), + description: self.getDescription(), + cut: self.getCut(), + receiver: self.getAddress(), + extra: self.getExtra() + ) + } + } + + access(all) struct GeneralCut : Cut { + // This is the description of the royalty struct + access(all) let name : String + access(all) let cap: Capability<&{FungibleToken.Receiver}> + access(all) let cut: UFix64 + // This is the description to the cut that can be visible to give detail on detail page + access(all) let description: String + access(self) let extra : {String : AnyStruct} + + init(name : String, cap: Capability<&{FungibleToken.Receiver}>, cut: UFix64, description: String) { + self.name = name + self.cap = cap + self.cut = cut + self.description = description + self.extra = {} + } + + access(all) fun getReceiverCap() : Capability<&{FungibleToken.Receiver}> { + return self.cap + } + access(all) fun getName() : String { + return self.name + } + access(all) fun getCut() : UFix64 { + return self.cut + } + access(all) fun getAddress() : Address { + return self.cap.address + } + access(all) fun getDescription() : String { + return self.description + } + access(all) fun getExtra() : {String : String} { + return {} + } + + access(all) fun getPayableLogic() : (fun(UFix64) : UFix64?) { + return fun(_ salePrice : UFix64) : UFix64? { + return salePrice * self.cut + } + } + } + + access(all) struct ThresholdCut : Cut { + // This is the description of the royalty struct + access(all) let name : String + access(all) let address: Address + access(all) let cut: UFix64 + // This is the description to the cut that can be visible to give detail on detail page + access(all) let description: String + access(all) let publicPath: String + access(all) let minimumPayment: UFix64 + access(self) let extra : {String : AnyStruct} + + init(name : String , address: Address , cut: UFix64 , description: String , publicPath: String, minimumPayment: UFix64) { + self.name = name + self.address = address + self.cut = cut + self.description = description + self.publicPath = publicPath + self.minimumPayment = minimumPayment + self.extra = {} + } + + access(all) fun getReceiverCap() : Capability<&{FungibleToken.Receiver}> { + let pp = PublicPath(identifier: self.publicPath)! + return getAccount(self.address).capabilities.get<&{FungibleToken.Receiver}>(pp)! + } + access(all) fun getName() : String { + return self.name + } + access(all) fun getCut() : UFix64 { + return self.cut + } + access(all) fun getAddress() : Address { + return self.address + } + access(all) fun getDescription() : String { + return self.description + } + access(all) fun getExtra() : {String : String} { + return {} + } + + access(all) fun getPayableLogic() : (fun(UFix64) : UFix64?) { + return fun(_ salePrice : UFix64) : UFix64? { + let rPayable = salePrice * self.cut + if rPayable < self.minimumPayment { + return self.minimumPayment + } + return rPayable + } + } + } } diff --git a/contracts/FindMarketDirectOfferEscrow.cdc b/contracts/FindMarketDirectOfferEscrow.cdc index 32891680..2b39728a 100644 --- a/contracts/FindMarketDirectOfferEscrow.cdc +++ b/contracts/FindMarketDirectOfferEscrow.cdc @@ -1,699 +1,700 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import Clock from "./Clock.cdc" -import Debug from "./Debug.cdc" -import FIND from "./FIND.cdc" -import FindMarket from "./FindMarket.cdc" -import Profile from "./Profile.cdc" - -pub contract FindMarketDirectOfferEscrow { - - pub event DirectOffer(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, nft: FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar: String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) - - - pub resource SaleItem : FindMarket.SaleItem { - - access(contract) var pointer: AnyStruct{FindViews.Pointer} - - access(contract) var offerCallback: Capability<&MarketBidCollection{MarketBidCollectionPublic}> - access(contract) var validUntil: UFix64? - access(contract) var saleItemExtraField: {String : AnyStruct} - access(contract) let totalRoyalties: UFix64 - - init(pointer: AnyStruct{FindViews.Pointer}, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - self.pointer=pointer - self.offerCallback=callback - self.validUntil=validUntil - self.saleItemExtraField=saleItemExtraField - self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() - } - - pub fun getId() : UInt64{ - return self.pointer.getUUID() - } - - pub fun acceptEscrowedBid() : @FungibleToken.Vault { - if !self.offerCallback.check() { - panic("Bidder unlinked bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) - } - let pointer= self.pointer as! FindViews.AuthNFTPointer - let publicPath = pointer.getNFTCollectionData().publicPath - let vault <- self.offerCallback.borrow()!.accept(<- pointer.withdraw(), path:publicPath) - return <- vault - } - - pub fun getRoyalty() : MetadataViews.Royalties { - return self.pointer.getRoyalty() - } - - pub fun getBalance() : UFix64 { - if !self.offerCallback.check() { - panic("Bidder unlinked bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) - } - return self.offerCallback.borrow()!.getBalance(self.getId()) - } - - pub fun getSeller() : Address { - return self.pointer.owner() - } - - pub fun getSellerName() : String? { - let address = self.pointer.owner() - return FIND.reverseLookup(address) - } - - - pub fun getBuyer() : Address? { - return self.offerCallback.address - } - - pub fun getBuyerName() : String? { - if let name = FIND.reverseLookup(self.offerCallback.address) { - return name - } - return nil - } - - pub fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ - return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) - } - - pub fun getSaleType() : String { - return "active_ongoing" - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun getListingTypeIdentifier() : String { - return Type<@SaleItem>().identifier - } - - pub fun setPointer(_ pointer: FindViews.AuthNFTPointer) { - self.pointer=pointer - } - - pub fun getItemID() : UInt64 { - return self.pointer.id - } - - pub fun getItemType() : Type { - return self.pointer.getItemType() - } - - pub fun getAuction(): FindMarket.AuctionItem? { - return nil - } - - pub fun getFtType() : Type { - if !self.offerCallback.check() { - panic("Bidder unlinked bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) - } - return self.offerCallback.borrow()!.getVaultType(self.getId()) - } - - pub fun setValidUntil(_ time: UFix64?) { - self.validUntil=time - } - - pub fun getValidUntil() : UFix64? { - return self.validUntil - } - - pub fun setCallback(_ callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>) { - self.offerCallback=callback - } - - pub fun checkPointer() : Bool { - return self.pointer.valid() - } - - pub fun checkSoulBound() : Bool { - return self.pointer.checkSoulBound() - } - - pub fun getSaleItemExtraField() : {String : AnyStruct} { - return self.saleItemExtraField - } - - access(contract) fun setSaleItemExtraField(_ field: {String : AnyStruct}) { - self.saleItemExtraField = field - } - - pub fun getTotalRoyalties() : UFix64 { - return self.totalRoyalties - } - - pub fun validateRoyalties() : Bool { - return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() - } - - pub fun getDisplay() : MetadataViews.Display { - return self.pointer.getDisplay() - } +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "Clock" +import "Debug" +import "FIND" +import "FindMarket" +import "Profile" + +access(all) contract FindMarketDirectOfferEscrow { + + access(all) event DirectOffer(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, nft: FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar: String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) + + access(all) entitlement Seller + + access(all) resource SaleItem : FindMarket.SaleItem { + + access(contract) var pointer: {FindViews.Pointer} + + access(contract) var offerCallback: Capability<&MarketBidCollection> + access(contract) var validUntil: UFix64? + access(contract) var saleItemExtraField: {String : AnyStruct} + access(contract) let totalRoyalties: UFix64 + + init(pointer: {FindViews.Pointer}, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + self.pointer=pointer + self.offerCallback=callback + self.validUntil=validUntil + self.saleItemExtraField=saleItemExtraField + self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getId() : UInt64{ + return self.pointer.getUUID() + } + + access(contract) fun acceptEscrowedBid() : @{FungibleToken.Vault} { + if !self.offerCallback.check() { + panic("Bidder unlinked bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) + } + let pointer= self.pointer as! FindViews.AuthNFTPointer + let publicPath = pointer.getNFTCollectionData().publicPath + let vault <- self.offerCallback.borrow()!.accept(<- pointer.withdraw(), path:publicPath) + return <- vault + } + + access(all) fun getRoyalty() : MetadataViews.Royalties { + return self.pointer.getRoyalty() + } + + access(all) fun getBalance() : UFix64 { + if !self.offerCallback.check() { + panic("Bidder unlinked bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) + } + return self.offerCallback.borrow()!.getBalance(self.getId()) + } + + access(all) fun getSeller() : Address { + return self.pointer.owner() + } + + access(all) fun getSellerName() : String? { + let address = self.pointer.owner() + return FIND.reverseLookup(address) + } + + + access(all) fun getBuyer() : Address? { + return self.offerCallback.address + } + + access(all) fun getBuyerName() : String? { + if let name = FIND.reverseLookup(self.offerCallback.address) { + return name + } + return nil + } + + access(all) fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ + return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) + } + + access(all) fun getSaleType() : String { + return "active_ongoing" + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun getListingTypeIdentifier() : String { + return Type<@SaleItem>().identifier + } + + access(contract) fun setPointer(_ pointer: FindViews.AuthNFTPointer) { + self.pointer=pointer + } + + access(all) fun getItemID() : UInt64 { + return self.pointer.id + } + + access(all) fun getItemType() : Type { + return self.pointer.getItemType() + } + + access(all) fun getAuction(): FindMarket.AuctionItem? { + return nil + } + + access(all) fun getFtType() : Type { + if !self.offerCallback.check() { + panic("Bidder unlinked bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) + } + return self.offerCallback.borrow()!.getVaultType(self.getId()) + } + + access(contract) fun setValidUntil(_ time: UFix64?) { + self.validUntil=time + } + + access(all) fun getValidUntil() : UFix64? { + return self.validUntil + } + + access(contract) fun setCallback(_ callback: Capability<&MarketBidCollection>) { + self.offerCallback=callback + } + + access(all) fun checkPointer() : Bool { + return self.pointer.valid() + } + + access(all) fun checkSoulBound() : Bool { + return self.pointer.checkSoulBound() + } + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} { + return self.saleItemExtraField + } + + access(contract) fun setSaleItemExtraField(_ field: {String : AnyStruct}) { + self.saleItemExtraField = field + } + + access(all) fun getTotalRoyalties() : UFix64 { + return self.totalRoyalties + } + + access(all) fun validateRoyalties() : Bool { + return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getDisplay() : MetadataViews.Display { + return self.pointer.getDisplay() + } + + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData { + return self.pointer.getNFTCollectionData() + } + } + + access(all) resource interface SaleItemCollectionPublic { + //fetch all the tokens in the collection + access(all) fun getIds(): [UInt64] + access(all) fun containsId(_ id: UInt64): Bool + access(contract)fun cancelBid(_ id: UInt64) + access(contract) fun registerIncreasedBid(_ id: UInt64) - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData { - return self.pointer.getNFTCollectionData() - } - } + //place a bid on a token + access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) + } + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { + //is this the best approach now or just put the NFT inside the saleItem? + access(contract) var items: @{UInt64: SaleItem} - pub resource interface SaleItemCollectionPublic { - //fetch all the tokens in the collection - pub fun getIds(): [UInt64] - pub fun containsId(_ id: UInt64): Bool - access(contract)fun cancelBid(_ id: UInt64) + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> - access(contract) fun registerIncreasedBid(_ id: UInt64) + init (_ tenantCapability: Capability<&FindMarket.Tenant>) { + self.items <- {} + self.tenantCapability=tenantCapability + } - //place a bid on a token - access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } - } + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } - pub resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { - //is this the best approach now or just put the NFT inside the saleItem? - access(contract) var items: @{UInt64: SaleItem} + //this is called when a buyer cancel a direct offer + access(contract) fun cancelBid(_ id: UInt64) { + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + let saleItem=self.borrow(id) - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> + let tenant=self.getTenant() + let ftType= saleItem.getFtType() - init (_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.items <- {} - self.tenantCapability=tenantCapability - } + let status="cancel" + let owner=self.owner!.address + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } + var nftInfo:FindMarket.NFTInfo?=nil + if saleItem.checkPointer() { + nftInfo=saleItem.toNFTInfo(false) + } - pub fun getListingType() : Type { - return Type<@SaleItem>() - } + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - //this is called when a buyer cancel a direct offer - access(contract) fun cancelBid(_ id: UInt64) { - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - let saleItem=self.borrow(id) + destroy <- self.items.remove(key: id) + } - let tenant=self.getTenant() - let ftType= saleItem.getFtType() + //The only thing we do here is basically register an event + access(contract) fun registerIncreasedBid(_ id: UInt64) { - let status="cancel" - let owner=self.owner!.address - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + let saleItem=self.borrow(id) - var nftInfo:FindMarket.NFTInfo?=nil - if saleItem.checkPointer() { - nftInfo=saleItem.toNFTInfo(false) - } + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "add bid in direct offer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - destroy <- self.items.remove(key: id) - } + if !actionResult.allowed { + panic(actionResult.message) + } - //The only thing we do here is basically register an event - access(contract) fun registerIncreasedBid(_ id: UInt64) { + let status="active_offered" + let owner=self.owner!.address + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - let saleItem=self.borrow(id) + let nftInfo=saleItem.toNFTInfo(true) - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "add bid in direct offer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) + } - if !actionResult.allowed { - panic(actionResult.message) - } + //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller + access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - let status="active_offered" - let owner=self.owner!.address - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + let id = item.getUUID() - let nftInfo=saleItem.toNFTInfo(true) + //If there are no bids from anybody else before we need to make the item + if !self.items.containsKey(id) { - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) + let saleItem <- create SaleItem(pointer: item, callback: callback, validUntil: validUntil, saleItemExtraField: saleItemExtraField) - } + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller - access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "bid in direct offer"), seller: self.owner!.address, buyer: callback.address) - let id = item.getUUID() + if !actionResult.allowed { + panic(actionResult.message) + } - //If there are no bids from anybody else before we need to make the item - if !self.items.containsKey(id) { + self.items[id] <-! saleItem + let saleItemRef=self.borrow(id) - let saleItem <- create SaleItem(pointer: item, callback: callback, validUntil: validUntil, saleItemExtraField: saleItemExtraField) + let status="active_offered" + let owner=self.owner!.address + let balance=saleItemRef.getBalance() + let buyer=callback.address + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() + let nftInfo=saleItemRef.toNFTInfo(true) - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "bid in direct offer"), seller: self.owner!.address, buyer: callback.address) + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItemRef.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItemRef.validUntil, previousBuyer:nil, previousBuyerName:nil) - if !actionResult.allowed { - panic(actionResult.message) - } + return + } - self.items[id] <-! saleItem - let saleItemRef=self.borrow(id) + let saleItem=self.borrow(id) - let status="active_offered" - let owner=self.owner!.address - let balance=saleItemRef.getBalance() - let buyer=callback.address - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + if self.borrow(id).getBuyer()! == callback.address { + panic("You already have the latest bid on this item, use the incraseBid transaction") + } - let nftInfo=saleItemRef.toNFTInfo(true) + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItemRef.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItemRef.validUntil, previousBuyer:nil, previousBuyerName:nil) + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "bid in direct offer"), seller: self.owner!.address, buyer: callback.address) - return - } + if !actionResult.allowed { + panic(actionResult.message) + } - let saleItem=self.borrow(id) + let balance=callback.borrow()?.getBalance(id) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) - if self.borrow(id).getBuyer()! == callback.address { - panic("You already have the latest bid on this item, use the incraseBid transaction") - } + let currentBalance=saleItem.getBalance() + Debug.log("currentBalance=".concat(currentBalance.toString()).concat(" new bid is at=").concat(balance.toString())) + if currentBalance >= balance { + panic("There is already a higher bid on this item") + } + //somebody else has the highest item so we cancel it + let previousBuyer=saleItem.offerCallback.address + let previousCB = saleItem.offerCallback.borrow() ?? panic("Previous bidder unlinked the bid collection capability. bidder address : ".concat(previousBuyer.toString())) + previousCB.cancelBidFromSaleItem(id) + saleItem.setValidUntil(validUntil) + saleItem.setCallback(callback) - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() + let status="active_offered" + let owner=self.owner!.address + let buyer=callback.address + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "bid in direct offer"), seller: self.owner!.address, buyer: callback.address) + let nftInfo=saleItem.toNFTInfo(true) - if !actionResult.allowed { - panic(actionResult.message) - } + let previousBuyerName = FIND.reverseLookup(previousBuyer) - let balance=callback.borrow()?.getBalance(id) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - let currentBalance=saleItem.getBalance() - Debug.log("currentBalance=".concat(currentBalance.toString()).concat(" new bid is at=").concat(balance.toString())) - if currentBalance >= balance { - panic("There is already a higher bid on this item") - } - //somebody else has the highest item so we cancel it - let previousBuyer=saleItem.offerCallback.address - let previousCB = saleItem.offerCallback.borrow() ?? panic("Previous bidder unlinked the bid collection capability. bidder address : ".concat(previousBuyer.toString())) - previousCB.cancelBidFromSaleItem(id) - saleItem.setValidUntil(validUntil) - saleItem.setCallback(callback) - let status="active_offered" - let owner=self.owner!.address - let buyer=callback.address - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + } - let nftInfo=saleItem.toNFTInfo(true) + //cancel will reject a direct offer + access(Seller) fun cancel(_ id: UInt64) { - let previousBuyerName = FIND.reverseLookup(previousBuyer) + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) + let saleItem=self.borrow(id) + let tenant=self.getTenant() + let ftType= saleItem.getFtType() - } - //cancel will reject a direct offer - pub fun cancel(_ id: UInt64) { + var status="rejected" + let owner=self.owner!.address + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } + var nftInfo:FindMarket.NFTInfo?=nil + if saleItem.checkPointer() { + nftInfo=saleItem.toNFTInfo(false) + } - let saleItem=self.borrow(id) + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - let tenant=self.getTenant() - let ftType= saleItem.getFtType() + saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(id) + destroy <- self.items.remove(key: id) + } + access(Seller) fun acceptDirectOffer(_ pointer: FindViews.AuthNFTPointer) { - var status="rejected" - let owner=self.owner!.address - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + let id = pointer.getUUID() + if !self.items.containsKey(id) { + panic("Invalid id=".concat(pointer.getUUID().toString())) + } + let saleItem = self.borrow(id) + + if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { + panic("This direct offer is already expired") + } + + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - var nftInfo:FindMarket.NFTInfo?=nil - if saleItem.checkPointer() { - nftInfo=saleItem.toNFTInfo(false) - } + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "fulfill directOffer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - - saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(id) - destroy <- self.items.remove(key: id) - } - - pub fun acceptDirectOffer(_ pointer: FindViews.AuthNFTPointer) { - - let id = pointer.getUUID() - if !self.items.containsKey(id) { - panic("Invalid id=".concat(pointer.getUUID().toString())) - } - let saleItem = self.borrow(id) - - if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { - panic("This direct offer is already expired") - } - - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() - - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "fulfill directOffer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - - if !actionResult.allowed { - panic(actionResult.message) - } - - let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType) - - //Set the auth pointer in the saleItem so that it now can be fulfilled - saleItem.setPointer(pointer) - - let royalty=saleItem.getRoyalty() - let nftInfo=saleItem.toNFTInfo(true) - - let status="sold" - let owner=saleItem.getSeller() - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let sellerName=FIND.reverseLookup(owner) - let profile = Profile.find(buyer) - - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: sellerName , amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - - let vault <- saleItem.acceptEscrowedBid() - - let resolved : {Address : String} = {} - resolved[buyer] = buyerName ?? "" - resolved[owner] = sellerName ?? "" - resolved[FindMarketDirectOfferEscrow.account.address] = "find" - // Have to make sure the tenant always have the valid find name - resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name - - FindMarket.pay(tenant: tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:royalty, nftInfo:nftInfo, cuts:cuts, resolver: fun(address:Address): String? { return FIND.reverseLookup(address) }, resolvedAddress: resolved) - destroy <- self.items.remove(key: id) - } - - pub fun getIds(): [UInt64] { - return self.items.keys - } - - pub fun getRoyaltyChangedIds(): [UInt64] { - let ids : [UInt64] = [] - for id in self.getIds() { - let item = self.borrow(id) - if !item.validateRoyalties() { - ids.append(id) - } - } - return ids - } - - pub fun containsId(_ id: UInt64): Bool { - return self.items.containsKey(id) - } - - pub fun borrow(_ id: UInt64): &SaleItem { - return (&self.items[id] as &SaleItem?)! - } - - pub fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { - if !self.items.containsKey(id) { - panic("This id does not exist : ".concat(id.toString())) - } - return (&self.items[id] as &SaleItem{FindMarket.SaleItem}?)! - } - - destroy() { - destroy self.items - } - } - - pub resource Bid : FindMarket.Bid { - access(contract) let from: Capability<&SaleItemCollection{SaleItemCollectionPublic}> - access(contract) let nftCap: Capability<&{NonFungibleToken.Receiver}> - access(contract) let itemUUID: UInt64 - - //this should reflect on what the above uuid is for - access(contract) let vault: @FungibleToken.Vault - access(contract) let vaultType: Type - access(contract) var bidAt: UFix64 - access(contract) let bidExtraField: {String : AnyStruct} - - init(from: Capability<&SaleItemCollection{SaleItemCollectionPublic}>, itemUUID: UInt64, vault: @FungibleToken.Vault, nftCap: Capability<&{NonFungibleToken.Receiver}>, bidExtraField: {String : AnyStruct}) { - self.vaultType=vault.getType() - self.vault <- vault - self.itemUUID=itemUUID - self.from=from - self.bidAt=Clock.time() - self.nftCap=nftCap - self.bidExtraField=bidExtraField - } - - access(contract) fun setBidAt(_ time: UFix64) { - self.bidAt=time - } - - pub fun getBalance() : UFix64 { - return self.vault.balance - } - - pub fun getSellerAddress() : Address { - return self.from.address - } - - pub fun getBidExtraField() : {String : AnyStruct} { - return self.bidExtraField - } - - destroy() { - destroy self.vault - } - } - - pub resource interface MarketBidCollectionPublic { - pub fun getBalance(_ id: UInt64) : UFix64 - pub fun getVaultType(_ id: UInt64) : Type - pub fun containsId(_ id: UInt64): Bool - access(contract) fun accept(_ nft: @NonFungibleToken.NFT, path:PublicPath) : @FungibleToken.Vault - access(contract) fun cancelBidFromSaleItem(_ id: UInt64) - } - - //A collection stored for bidders/buyers - pub resource MarketBidCollection: MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic { - - access(contract) var bids : @{UInt64: Bid} - access(contract) let receiver: Capability<&{FungibleToken.Receiver}> - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - //not sure we can store this here anymore. think it needs to be in every bid - init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.bids <- {} - self.receiver=receiver - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } - - access(contract) fun accept(_ nft: @NonFungibleToken.NFT, path:PublicPath) : @FungibleToken.Vault { - let id= nft.id - let bid <- self.bids.remove(key: nft.uuid) ?? panic("missing bid") - let vaultRef = &bid.vault as &FungibleToken.Vault - - let nftCap = bid.nftCap - if !nftCap.check() { - let cpCap =getAccount(nftCap.address).getCapability<&{NonFungibleToken.CollectionPublic}>(path) - if !cpCap.check() { - panic("Bidder unlinked the nft receiver capability. bidder address : ".concat(bid.nftCap.address.toString())) - } else { - bid.nftCap.borrow()!.deposit(token: <- nft) - } - } else { - bid.nftCap.borrow()!.deposit(token: <- nft) - } - - let vault <- vaultRef.withdraw(amount: vaultRef.balance) - destroy bid - return <- vault - } - - pub fun getVaultType(_ id:UInt64) : Type { - return self.borrowBid(id).vaultType - } - - pub fun getIds() : [UInt64] { - return self.bids.keys - } - - pub fun containsId(_ id: UInt64) : Bool { - return self.bids.containsKey(id) - } - - pub fun getBidType() : Type { - return Type<@Bid>() - } - - pub fun bid(item: FindViews.ViewReadPointer, vault: @FungibleToken.Vault, nftCap: Capability<&{NonFungibleToken.Receiver}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}, bidExtraField: {String : AnyStruct}) { - - // ensure it is not a 0 dollar listing - if vault.balance <= 0.0 { - panic("Offer price should be greater than 0") - } - - // ensure validUntil is valid - if validUntil != nil && validUntil! < Clock.time() { - panic("Valid until is before current time") - } - - // check soul bound - if item.checkSoulBound() { - panic("This item is soul bounded and cannot be traded") - } - - if self.owner!.address == item.owner() { - panic("You cannot bid on your own resource") - } - - let uuid=item.getUUID() - - if self.bids[uuid] != nil { - panic("You already have an bid for this item, use increaseBid on that bid") - } - let tenant=self.getTenant() - - // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) - if tenant.name == "onefootball" { - // ensure it is not a 0 dollar listing - if vault.balance <= 0.65 { - panic("Offer price should be greater than 0.65") - } - } - - let from=getAccount(item.owner()).getCapability<&SaleItemCollection{SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - - let bid <- create Bid(from: from, itemUUID:item.getUUID(), vault: <- vault, nftCap: nftCap, bidExtraField: bidExtraField) - let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for id=".concat(uuid.toString())) - let callbackCapability =self.owner!.getCapability<&MarketBidCollection{MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - let oldToken <- self.bids[uuid] <- bid - saleItemCollection.registerBid(item: item, callback: callbackCapability, validUntil:validUntil, saleItemExtraField: saleItemExtraField) - destroy oldToken - } - - pub fun increaseBid(id: UInt64, vault: @FungibleToken.Vault) { - let bid =self.borrowBid(id) - bid.setBidAt(Clock.time()) - bid.vault.deposit(from: <- vault) - if !bid.from.check() { - panic("Seller unlinked SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) - } - bid.from.borrow()!.registerIncreasedBid(id) - } - - /// The users cancel a bid himself - pub fun cancelBid(_ id: UInt64) { - let bid= self.borrowBid(id) - bid.from.borrow()!.cancelBid(id) - self.cancelBidFromSaleItem(id) - } - - access(contract) fun cancelBidFromSaleItem(_ id: UInt64) { - if !self.receiver.check() { - panic("This user does not have receiver vault set up. User: ".concat(self.receiver.address.toString())) - } - Debug.log("cancel bid") - let bid <- self.bids.remove(key: id) ?? panic("missing bid") - let vaultRef = &bid.vault as &FungibleToken.Vault - self.receiver.borrow()!.deposit(from: <- vaultRef.withdraw(amount: vaultRef.balance)) - destroy bid - } - - pub fun borrowBid(_ id: UInt64): &Bid { - if !self.bids.containsKey(id){ - panic("This id does not exist : ".concat(id.toString())) - } - return (&self.bids[id] as &Bid?)! - } - - pub fun borrowBidItem(_ id: UInt64): &{FindMarket.Bid} { - if !self.bids.containsKey(id){ - panic("This id does not exist : ".concat(id.toString())) - } - return (&self.bids[id] as &Bid{FindMarket.Bid}?)! - } - - pub fun getBalance(_ id: UInt64) : UFix64 { - let bid= self.borrowBid(id) - return bid.vault.balance - } - - destroy() { - destroy self.bids - } - } - //Create an empty lease collection that store your leases to a name - pub fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>): @SaleItemCollection { - return <- create SaleItemCollection(tenantCapability) - } - - pub fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) : @MarketBidCollection { - return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) - } - - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? { - if FindMarket.getTenantCapability(marketplace) == nil { - panic("Invalid tenant") - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&SaleItemCollection{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - } - return nil - } - - pub fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>? { - if FindMarket.getTenantCapability(marketplace) == nil { - panic("Invalid tenant") - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&MarketBidCollection{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - } - return nil - } - - init() { - FindMarket.addSaleItemType(Type<@SaleItem>()) - FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) - FindMarket.addMarketBidType(Type<@Bid>()) - FindMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) - } + if !actionResult.allowed { + panic(actionResult.message) + } + + let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketDirectOfferEscrow.SaleItem>(), nftType: nftType, ftType: ftType) + + //Set the auth pointer in the saleItem so that it now can be fulfilled + saleItem.setPointer(pointer) + + let royalty=saleItem.getRoyalty() + let nftInfo=saleItem.toNFTInfo(true) + + let status="sold" + let owner=saleItem.getSeller() + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let sellerName=FIND.reverseLookup(owner) + let profile = Profile.find(buyer) + + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: sellerName , amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) + + let vault <- saleItem.acceptEscrowedBid() + + let resolved : {Address : String} = {} + resolved[buyer] = buyerName ?? "" + resolved[owner] = sellerName ?? "" + resolved[FindMarketDirectOfferEscrow.account.address] = "find" + // Have to make sure the tenant always have the valid find name + resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name + + FindMarket.pay(tenant: tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:royalty, nftInfo:nftInfo, cuts:cuts, resolver: fun(address:Address): String? { return FIND.reverseLookup(address) }, resolvedAddress: resolved) + destroy <- self.items.remove(key: id) + } + + access(all) fun getIds(): [UInt64] { + return self.items.keys + } + + access(all) fun getRoyaltyChangedIds(): [UInt64] { + let ids : [UInt64] = [] + for id in self.getIds() { + let item = self.borrow(id) + if !item.validateRoyalties() { + ids.append(id) + } + } + return ids + } + + access(all) fun containsId(_ id: UInt64): Bool { + return self.items.containsKey(id) + } + + access(all) fun borrow(_ id: UInt64): &SaleItem { + return (&self.items[id])! + } + + access(all) fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { + if !self.items.containsKey(id) { + panic("This id does not exist : ".concat(id.toString())) + } + return (&self.items[id])! + } + } + + access(all) resource Bid : FindMarket.Bid { + access(contract) let from: Capability<&SaleItemCollection> + access(contract) let nftCap: Capability<&{NonFungibleToken.Receiver}> + access(contract) let itemUUID: UInt64 + + //this should reflect on what the above uuid is for + access(contract) let vault: @{FungibleToken.Vault} + access(contract) let vaultType: Type + access(contract) var bidAt: UFix64 + access(contract) let bidExtraField: {String : AnyStruct} + + init(from: Capability<&SaleItemCollection>, itemUUID: UInt64, vault: @{FungibleToken.Vault}, nftCap: Capability<&{NonFungibleToken.Receiver}>, bidExtraField: {String : AnyStruct}) { + self.vaultType=vault.getType() + self.vault <- vault + self.itemUUID=itemUUID + self.from=from + self.bidAt=Clock.time() + self.nftCap=nftCap + self.bidExtraField=bidExtraField + } + + access(contract) fun setBidAt(_ time: UFix64) { + self.bidAt=time + } + + access(all) fun getBalance() : UFix64 { + return self.vault.balance + } + + access(all) fun getSellerAddress() : Address { + return self.from.address + } + + access(all) fun getBidExtraField() : {String : AnyStruct} { + return self.bidExtraField + } + } + + access(all) resource interface MarketBidCollectionPublic { + access(all) fun getBalance(_ id: UInt64) : UFix64 + access(all) fun getVaultType(_ id: UInt64) : Type + access(all) fun containsId(_ id: UInt64): Bool + access(contract) fun accept(_ nft: @{NonFungibleToken.NFT}, path:PublicPath) : @{FungibleToken.Vault} + access(contract) fun cancelBidFromSaleItem(_ id: UInt64) + } + + access(all) entitlement Buyer + + //A collection stored for bidders/buyers + access(all) resource MarketBidCollection: MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic { + + access(contract) var bids : @{UInt64: Bid} + access(contract) let receiver: Capability<&{FungibleToken.Receiver}> + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + //not sure we can store this here anymore. think it needs to be in every bid + init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) { + self.bids <- {} + self.receiver=receiver + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } + + access(contract) fun accept(_ nft: @{NonFungibleToken.NFT}, path:PublicPath) : @{FungibleToken.Vault} { + let id= nft.id + let bid <- self.bids.remove(key: nft.uuid) ?? panic("missing bid") + let vaultRef = &bid.vault as auth(FungibleToken.Withdraw) &{FungibleToken.Vault} + + let nftCap = bid.nftCap + if !nftCap.check() { + let cpCap =getAccount(nftCap.address).capabilities.get<&{NonFungibleToken.Collection}>(path)! + if !cpCap.check() { + panic("Bidder unlinked the nft receiver capability. bidder address : ".concat(bid.nftCap.address.toString())) + } else { + bid.nftCap.borrow()!.deposit(token: <- nft) + } + } else { + bid.nftCap.borrow()!.deposit(token: <- nft) + } + + let vault <- vaultRef.withdraw(amount: vaultRef.balance) + destroy bid + return <- vault + } + + access(all) fun getVaultType(_ id:UInt64) : Type { + return self.borrowBid(id).vaultType + } + + access(all) fun getIds() : [UInt64] { + return self.bids.keys + } + + access(all) fun containsId(_ id: UInt64) : Bool { + return self.bids.containsKey(id) + } + + access(all) fun getBidType() : Type { + return Type<@Bid>() + } + + access(Buyer) fun bid(item: FindViews.ViewReadPointer, vault: @{FungibleToken.Vault}, nftCap: Capability<&{NonFungibleToken.Receiver}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}, bidExtraField: {String : AnyStruct}) { + + // ensure it is not a 0 dollar listing + if vault.balance <= 0.0 { + panic("Offer price should be greater than 0") + } + + // ensure validUntil is valid + if validUntil != nil && validUntil! < Clock.time() { + panic("Valid until is before current time") + } + + // check soul bound + if item.checkSoulBound() { + panic("This item is soul bounded and cannot be traded") + } + + if self.owner!.address == item.owner() { + panic("You cannot bid on your own resource") + } + + let uuid=item.getUUID() + + if self.bids[uuid] != nil { + panic("You already have an bid for this item, use increaseBid on that bid") + } + let tenant=self.getTenant() + + // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) + if tenant.name == "onefootball" { + // ensure it is not a 0 dollar listing + if vault.balance <= 0.65 { + panic("Offer price should be greater than 0.65") + } + } + let from=getAccount(item.owner()).capabilities.get<&SaleItemCollection>(tenant.getPublicPath(Type<@SaleItemCollection>()))! + + let bid <- create Bid(from: from, itemUUID:item.getUUID(), vault: <- vault, nftCap: nftCap, bidExtraField: bidExtraField) + let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for id=".concat(uuid.toString())) + let callbackCapability =self.owner!.capabilities.get<&MarketBidCollection>(tenant.getPublicPath(Type<@MarketBidCollection>()))! + let oldToken <- self.bids[uuid] <- bid + saleItemCollection.registerBid(item: item, callback: callbackCapability, validUntil:validUntil, saleItemExtraField: saleItemExtraField) + destroy oldToken + } + + access(Buyer) fun increaseBid(id: UInt64, vault: @{FungibleToken.Vault}) { + let bid =self.borrowBid(id) + bid.setBidAt(Clock.time()) + bid.vault.deposit(from: <- vault) + if !bid.from.check() { + panic("Seller unlinked SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) + } + bid.from.borrow()!.registerIncreasedBid(id) + } + + /// The users cancel a bid himself + access(Buyer) fun cancelBid(_ id: UInt64) { + let bid= self.borrowBid(id) + bid.from.borrow()!.cancelBid(id) + self.cancelBidFromSaleItem(id) + } + + access(contract) fun cancelBidFromSaleItem(_ id: UInt64) { + if !self.receiver.check() { + panic("This user does not have receiver vault set up. User: ".concat(self.receiver.address.toString())) + } + Debug.log("cancel bid") + let bid <- self.bids.remove(key: id) ?? panic("missing bid") + let vaultRef = &bid.vault as auth(FungibleToken.Withdraw) &{FungibleToken.Vault} + self.receiver.borrow()!.deposit(from: <- vaultRef.withdraw(amount: vaultRef.balance)) + destroy bid + } + + access(all) fun borrowBid(_ id: UInt64): &Bid { + if !self.bids.containsKey(id){ + panic("This id does not exist : ".concat(id.toString())) + } + return (&self.bids[id])! + } + + access(all) fun borrowBidItem(_ id: UInt64): &{FindMarket.Bid} { + if !self.bids.containsKey(id){ + panic("This id does not exist : ".concat(id.toString())) + } + return (&self.bids[id])! + } + + access(all) fun getBalance(_ id: UInt64) : UFix64 { + let bid= self.borrowBid(id) + return bid.vault.balance + } + } + //Create an empty lease collection that store your leases to a name + access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>): @SaleItemCollection { + return <- create SaleItemCollection(tenantCapability) + } + + access(all) fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) : @MarketBidCollection { + return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) + } + + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&SaleItemCollection>(tenant.getPublicPath(Type<@SaleItemCollection>())) + } + return nil + } + + access(all) fun getSaleItemExtraField(marketplace:Address, user:Address, id:UInt64) : {String : AnyStruct}? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + if let saleItemCollection = getAccount(user).capabilities.get<&{FindMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>()))!.borrow() { + if let saleItem = saleItemCollection.borrowSaleItem(id) { + return saleItem.getSaleItemExtraField() + } + } + } + return nil + } + + access(all) fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + return getAccount(user).capabilities.get<&MarketBidCollection>(tenant.getPublicPath(Type<@MarketBidCollection>())) + } + return nil + } + + init() { + FindMarket.addSaleItemType(Type<@SaleItem>()) + FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) + FindMarket.addMarketBidType(Type<@Bid>()) + FindMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) + } } diff --git a/contracts/FindMarketDirectOfferSoft.cdc b/contracts/FindMarketDirectOfferSoft.cdc index d25865d2..5648c83d 100644 --- a/contracts/FindMarketDirectOfferSoft.cdc +++ b/contracts/FindMarketDirectOfferSoft.cdc @@ -1,784 +1,787 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import FlowToken from "./standard/FlowToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import Clock from "./Clock.cdc" -import Debug from "./Debug.cdc" -import FIND from "./FIND.cdc" -import FindMarket from "./FindMarket.cdc" -import Profile from "./Profile.cdc" - -pub contract FindMarketDirectOfferSoft { - - pub event DirectOffer(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, nft: FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) - - pub resource SaleItem : FindMarket.SaleItem{ - - access(contract) var pointer: AnyStruct{FindViews.Pointer} - access(contract) var offerCallback: Capability<&MarketBidCollection{MarketBidCollectionPublic}> - - access(contract) var directOfferAccepted:Bool - access(contract) var validUntil: UFix64? - access(contract) var saleItemExtraField: {String : AnyStruct} - access(contract) let totalRoyalties: UFix64 - - init(pointer: AnyStruct{FindViews.Pointer}, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - self.pointer=pointer - self.offerCallback=callback - self.directOfferAccepted=false - self.validUntil=validUntil - self.saleItemExtraField=saleItemExtraField - self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() - } - - - pub fun getId() : UInt64{ - return self.pointer.getUUID() - } - - pub fun acceptDirectOffer() { - self.directOfferAccepted=true - } - - //Here we do not get a vault back, it is sent in to the method itself - pub fun acceptNonEscrowedBid() { - if !self.offerCallback.check() { - panic("Bidder unlinked the bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) - } - let pointer= self.pointer as! FindViews.AuthNFTPointer - self.offerCallback.borrow()!.acceptNonEscrowed(<- pointer.withdraw()) - } - - pub fun getRoyalty() : MetadataViews.Royalties { - return self.pointer.getRoyalty() - } - - pub fun getFtType() : Type { - if !self.offerCallback.check() { - panic("Bidder unlinked the bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) - } - return self.offerCallback.borrow()!.getVaultType(self.getId()) - } - - pub fun getItemID() : UInt64 { - return self.pointer.id - } - - pub fun getItemType() : Type { - return self.pointer.getItemType() - } - - pub fun getAuction(): FindMarket.AuctionItem? { - return nil - } - - pub fun getSaleType() : String { - if self.directOfferAccepted { - return "active_finished" - } - return "active_ongoing" - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun getListingTypeIdentifier() : String { - return Type<@SaleItem>().identifier - } - - pub fun getBalance() : UFix64 { - if !self.offerCallback.check() { - panic("Bidder unlinked the bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) - } - return self.offerCallback.borrow()!.getBalance(self.getId()) - } - - pub fun getSeller() : Address { - return self.pointer.owner() - } - - pub fun getSellerName() : String? { - let address = self.pointer.owner() - return FIND.reverseLookup(address) - } - - pub fun getBuyer() : Address? { - return self.offerCallback.address - } - - pub fun getBuyerName() : String? { - if let name = FIND.reverseLookup(self.offerCallback.address) { - return name - } - return nil - } - - pub fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ - return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) - } - - pub fun setValidUntil(_ time: UFix64?) { - self.validUntil=time - } - - pub fun getValidUntil() : UFix64? { - return self.validUntil - } - - pub fun setPointer(_ pointer: FindViews.AuthNFTPointer) { - self.pointer=pointer - } - - pub fun setCallback(_ callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>) { - self.offerCallback=callback - } - - pub fun checkPointer() : Bool { - return self.pointer.valid() - } - - pub fun checkSoulBound() : Bool { - return self.pointer.checkSoulBound() - } - - pub fun getSaleItemExtraField() : {String : AnyStruct} { - return self.saleItemExtraField - } - - access(contract) fun setSaleItemExtraField(_ field: {String : AnyStruct}) { - self.saleItemExtraField = field - } - - pub fun getTotalRoyalties() : UFix64 { - return self.totalRoyalties - } - - pub fun validateRoyalties() : Bool { - return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() - } - - pub fun getDisplay() : MetadataViews.Display { - return self.pointer.getDisplay() - } - - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData { - return self.pointer.getNFTCollectionData() - } - } - - pub resource interface SaleItemCollectionPublic { - //fetch all the tokens in the collection - pub fun getIds(): [UInt64] - pub fun containsId(_ id: UInt64): Bool - access(contract) fun cancelBid(_ id: UInt64) - access(contract) fun registerIncreasedBid(_ id: UInt64) +import "FungibleToken" +import "FlowToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "Clock" +import "Debug" +import "FIND" +import "FindMarket" +import "Profile" + +access(all) contract FindMarketDirectOfferSoft { + + access(all) event DirectOffer(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, nft: FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar:String?, endsAt: UFix64?, previousBuyer:Address?, previousBuyerName:String?) + + access(all) entitlement Seller + + access(all) resource SaleItem : FindMarket.SaleItem{ + + access(contract) var pointer: {FindViews.Pointer} + access(contract) var offerCallback: Capability<&MarketBidCollection> + + access(contract) var directOfferAccepted:Bool + access(contract) var validUntil: UFix64? + access(contract) var saleItemExtraField: {String : AnyStruct} + access(contract) let totalRoyalties: UFix64 + + init(pointer: {FindViews.Pointer}, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + self.pointer=pointer + self.offerCallback=callback + self.directOfferAccepted=false + self.validUntil=validUntil + self.saleItemExtraField=saleItemExtraField + self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() + } + + + access(all) fun getId() : UInt64{ + return self.pointer.getUUID() + } + + access(contract) fun acceptDirectOffer() { + self.directOfferAccepted=true + } + + //Here we do not get a vault back, it is sent in to the method itself + access(contract) fun acceptNonEscrowedBid() { + if !self.offerCallback.check() { + panic("Bidder unlinked the bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) + } + let pointer= self.pointer as! FindViews.AuthNFTPointer + self.offerCallback.borrow()!.acceptNonEscrowed(<- pointer.withdraw()) + } + + access(all) fun getRoyalty() : MetadataViews.Royalties { + return self.pointer.getRoyalty() + } + + access(all) fun getFtType() : Type { + if !self.offerCallback.check() { + panic("Bidder unlinked the bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) + } + return self.offerCallback.borrow()!.getVaultType(self.getId()) + } + + access(all) fun getItemID() : UInt64 { + return self.pointer.id + } + + access(all) fun getItemType() : Type { + return self.pointer.getItemType() + } + + access(all) fun getAuction(): FindMarket.AuctionItem? { + return nil + } + + access(all) fun getSaleType() : String { + if self.directOfferAccepted { + return "active_finished" + } + return "active_ongoing" + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun getListingTypeIdentifier() : String { + return Type<@SaleItem>().identifier + } + + access(all) fun getBalance() : UFix64 { + if !self.offerCallback.check() { + panic("Bidder unlinked the bid collection capability. Bidder Address : ".concat(self.offerCallback.address.toString())) + } + return self.offerCallback.borrow()!.getBalance(self.getId()) + } + + access(all) fun getSeller() : Address { + return self.pointer.owner() + } + + access(all) fun getSellerName() : String? { + let address = self.pointer.owner() + return FIND.reverseLookup(address) + } + + access(all) fun getBuyer() : Address? { + return self.offerCallback.address + } + + access(all) fun getBuyerName() : String? { + if let name = FIND.reverseLookup(self.offerCallback.address) { + return name + } + return nil + } + + access(all) fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ + return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) + } + + access(contract) fun setValidUntil(_ time: UFix64?) { + self.validUntil=time + } + + access(all) fun getValidUntil() : UFix64? { + return self.validUntil + } + + access(contract) fun setPointer(_ pointer: FindViews.AuthNFTPointer) { + self.pointer=pointer + } + + access(contract) fun setCallback(_ callback: Capability<&MarketBidCollection>) { + self.offerCallback=callback + } + + access(all) fun checkPointer() : Bool { + return self.pointer.valid() + } + + access(all) fun checkSoulBound() : Bool { + return self.pointer.checkSoulBound() + } + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} { + return self.saleItemExtraField + } + + access(contract) fun setSaleItemExtraField(_ field: {String : AnyStruct}) { + self.saleItemExtraField = field + } + + access(all) fun getTotalRoyalties() : UFix64 { + return self.totalRoyalties + } + + access(all) fun validateRoyalties() : Bool { + return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getDisplay() : MetadataViews.Display { + return self.pointer.getDisplay() + } + + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData { + return self.pointer.getNFTCollectionData() + } + } + + access(all) resource interface SaleItemCollectionPublic { + //fetch all the tokens in the collection + access(all) fun getIds(): [UInt64] + access(all) fun containsId(_ id: UInt64): Bool + access(contract) fun cancelBid(_ id: UInt64) + access(contract) fun registerIncreasedBid(_ id: UInt64) - //place a bid on a token - access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) + //place a bid on a token + access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) - access(contract) fun isAcceptedDirectOffer(_ id:UInt64) : Bool + access(contract) fun isAcceptedDirectOffer(_ id:UInt64) : Bool - access(contract) fun fulfillDirectOfferNonEscrowed(id:UInt64, vault: @FungibleToken.Vault) + access(contract) fun fulfillDirectOfferNonEscrowed(id:UInt64, vault: @{FungibleToken.Vault}) - } + } - pub resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { - //is this the best approach now or just put the NFT inside the saleItem? - access(contract) var items: @{UInt64: SaleItem} + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { + //is this the best approach now or just put the NFT inside the saleItem? + access(contract) var items: @{UInt64: SaleItem} - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> - init (_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.items <- {} - self.tenantCapability=tenantCapability - } + init (_ tenantCapability: Capability<&FindMarket.Tenant>) { + self.items <- {} + self.tenantCapability=tenantCapability + } - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } - pub fun isAcceptedDirectOffer(_ id:UInt64) : Bool{ + access(contract) fun isAcceptedDirectOffer(_ id:UInt64) : Bool{ - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - let saleItem = self.borrow(id) + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + let saleItem = self.borrow(id) - return saleItem.directOfferAccepted - } + return saleItem.directOfferAccepted + } - pub fun getListingType() : Type { - return Type<@SaleItem>() - } + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } - //this is called when a buyer cancel a direct offer - access(contract) fun cancelBid(_ id: UInt64) { - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - let saleItem=self.borrow(id) + //this is called when a buyer cancel a direct offer + access(contract) fun cancelBid(_ id: UInt64) { + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + let saleItem=self.borrow(id) - let tenant=self.getTenant() - let ftType= saleItem.getFtType() + let tenant=self.getTenant() + let ftType= saleItem.getFtType() - let status="cancel" - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + let status="cancel" + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - var nftInfo:FindMarket.NFTInfo?=nil - if saleItem.checkPointer() { - nftInfo=saleItem.toNFTInfo(false) - } + var nftInfo:FindMarket.NFTInfo?=nil + if saleItem.checkPointer() { + nftInfo=saleItem.toNFTInfo(false) + } - emit DirectOffer(tenant:tenant.name, id: saleItem.getId(), saleID: saleItem.uuid, seller:self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) + emit DirectOffer(tenant:tenant.name, id: saleItem.getId(), saleID: saleItem.uuid, seller:self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - destroy <- self.items.remove(key: id) - } + destroy <- self.items.remove(key: id) + } - //The only thing we do here is basically register an event - access(contract) fun registerIncreasedBid(_ id: UInt64) { + //The only thing we do here is basically register an event + access(contract) fun registerIncreasedBid(_ id: UInt64) { - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - let saleItem=self.borrow(id) + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + let saleItem=self.borrow(id) - let tenant=self.getTenant() - let nftType=saleItem.getItemType() - let ftType= saleItem.getFtType() + let tenant=self.getTenant() + let nftType=saleItem.getItemType() + let ftType= saleItem.getFtType() - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "increase bid in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "increase bid in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - if !actionResult.allowed { - panic(actionResult.message) - } + if !actionResult.allowed { + panic(actionResult.message) + } - let status="active_offered" - let owner=self.owner!.address - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + let status="active_offered" + let owner=self.owner!.address + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - let nftInfo=saleItem.toNFTInfo(true) + let nftInfo=saleItem.toNFTInfo(true) - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - } + } - //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller - access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection{MarketBidCollectionPublic}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + //This is a function that buyer will call (via his bid collection) to register the bicCallback with the seller + access(contract) fun registerBid(item: FindViews.ViewReadPointer, callback: Capability<&MarketBidCollection>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - let id = item.getUUID() + let id = item.getUUID() - //If there are no bids from anybody else before we need to make the item - if !self.items.containsKey(id) { - let saleItem <- create SaleItem(pointer: item, callback: callback, validUntil: validUntil, saleItemExtraField: saleItemExtraField) + //If there are no bids from anybody else before we need to make the item + if !self.items.containsKey(id) { + let saleItem <- create SaleItem(pointer: item, callback: callback, validUntil: validUntil, saleItemExtraField: saleItemExtraField) - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name: "bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address) + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: saleItem.getItemType(), ftType: saleItem.getFtType(), action: FindMarket.MarketAction(listing:true, name: "bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address) - if !actionResult.allowed { - panic(actionResult.message) - } - self.items[id] <-! saleItem - let saleItemRef=self.borrow(id) - let status="active_offered" - let owner=self.owner!.address - let balance=saleItemRef.getBalance() - let buyer=callback.address - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + if !actionResult.allowed { + panic(actionResult.message) + } + self.items[id] <-! saleItem + let saleItemRef=self.borrow(id) + let status="active_offered" + let owner=self.owner!.address + let balance=saleItemRef.getBalance() + let buyer=callback.address + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - let nftInfo=saleItemRef.toNFTInfo(true) + let nftInfo=saleItemRef.toNFTInfo(true) - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItemRef.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItemRef.validUntil, previousBuyer:nil, previousBuyerName:nil) + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItemRef.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItemRef.validUntil, previousBuyer:nil, previousBuyerName:nil) - return - } + return + } - let saleItem=self.borrow(id) - if self.borrow(id).getBuyer()! == callback.address { - panic("You already have the latest bid on this item, use the incraseBid transaction") - } + let saleItem=self.borrow(id) + if self.borrow(id).getBuyer()! == callback.address { + panic("You already have the latest bid on this item, use the incraseBid transaction") + } - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address) + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "bid in direct offer soft"), seller: self.owner!.address, buyer: callback.address) - if !actionResult.allowed { - panic(actionResult.message) - } + if !actionResult.allowed { + panic(actionResult.message) + } - let balance=callback.borrow()?.getBalance(id) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) + let balance=callback.borrow()?.getBalance(id) ?? panic("Bidder unlinked the bid collection capability. bidder address : ".concat(callback.address.toString())) - let currentBalance=saleItem.getBalance() - Debug.log("currentBalance=".concat(currentBalance.toString()).concat(" new bid is at=").concat(balance.toString())) - if currentBalance >= balance { - panic("There is already a higher bid on this item. Current bid : ".concat(currentBalance.toString()).concat(" . New bid is at : ").concat(balance.toString())) - } - let previousBuyer=saleItem.offerCallback.address - //somebody else has the highest item so we cancel it - saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(id) - saleItem.setValidUntil(validUntil) - saleItem.setSaleItemExtraField(saleItemExtraField) - saleItem.setCallback(callback) + let currentBalance=saleItem.getBalance() + Debug.log("currentBalance=".concat(currentBalance.toString()).concat(" new bid is at=").concat(balance.toString())) + if currentBalance >= balance { + panic("There is already a higher bid on this item. Current bid : ".concat(currentBalance.toString()).concat(" . New bid is at : ").concat(balance.toString())) + } + let previousBuyer=saleItem.offerCallback.address + //somebody else has the highest item so we cancel it + saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(id) + saleItem.setValidUntil(validUntil) + saleItem.setSaleItemExtraField(saleItemExtraField) + saleItem.setCallback(callback) - let status="active_offered" - let owner=self.owner!.address - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + let status="active_offered" + let owner=self.owner!.address + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - let nftInfo=saleItem.toNFTInfo(true) + let nftInfo=saleItem.toNFTInfo(true) - let previousBuyerName = FIND.reverseLookup(previousBuyer) + let previousBuyerName = FIND.reverseLookup(previousBuyer) - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:previousBuyer, previousBuyerName:previousBuyerName) - } + } + //cancel will reject a direct offer + access(Seller) fun cancel(_ id: UInt64) { - //cancel will reject a direct offer - pub fun cancel(_ id: UInt64) { + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } + let saleItem=self.borrow(id) - let saleItem=self.borrow(id) + let tenant=self.getTenant() + let ftType= saleItem.getFtType() - let tenant=self.getTenant() - let ftType= saleItem.getFtType() + var status = "cancel_rejected" + let owner=self.owner!.address + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - var status = "cancel_rejected" - let owner=self.owner!.address - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + var nftInfo:FindMarket.NFTInfo?=nil + if saleItem.checkPointer() { + nftInfo=saleItem.toNFTInfo(false) + } - var nftInfo:FindMarket.NFTInfo?=nil - if saleItem.checkPointer() { - nftInfo=saleItem.toNFTInfo(false) - } + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) + if !saleItem.offerCallback.check() { + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(saleItem.offerCallback.address.toString())) + } + saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(id) + destroy <- self.items.remove(key: id) + } - if !saleItem.offerCallback.check() { - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(saleItem.offerCallback.address.toString())) - } - saleItem.offerCallback.borrow()!.cancelBidFromSaleItem(id) - destroy <- self.items.remove(key: id) - } + access(Seller) fun acceptOffer(_ pointer: FindViews.AuthNFTPointer) { - pub fun acceptOffer(_ pointer: FindViews.AuthNFTPointer) { + let id = pointer.getUUID() - let id = pointer.getUUID() + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } + let saleItem = self.borrow(id) - let saleItem = self.borrow(id) + if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { + panic("This direct offer is already expired") + } - if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { - panic("This direct offer is already expired") - } + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "accept offer in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "accept offer in direct offer soft"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) + if !actionResult.allowed { + panic(actionResult.message) + } - if !actionResult.allowed { - panic(actionResult.message) - } + //Set the auth pointer in the saleItem so that it now can be fulfilled + saleItem.setPointer(pointer) + saleItem.acceptDirectOffer() - //Set the auth pointer in the saleItem so that it now can be fulfilled - saleItem.setPointer(pointer) - saleItem.acceptDirectOffer() + let status="active_accepted" + let owner=self.owner!.address + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let profile = Profile.find(buyer) - let status="active_accepted" - let owner=self.owner!.address - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let profile = Profile.find(buyer) + let nftInfo=saleItem.toNFTInfo(true) - let nftInfo=saleItem.toNFTInfo(true) + emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - emit DirectOffer(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) + } - } + /// this is called from a bid when a seller accepts + access(contract) fun fulfillDirectOfferNonEscrowed(id:UInt64, vault: @{FungibleToken.Vault}) { - /// this is called from a bid when a seller accepts - access(contract) fun fulfillDirectOfferNonEscrowed(id:UInt64, vault: @FungibleToken.Vault) { + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } + let saleItem = self.borrow(id) + if !saleItem.directOfferAccepted { + panic("cannot fulfill a direct offer that is not accepted yet") + } - let saleItem = self.borrow(id) - if !saleItem.directOfferAccepted { - panic("cannot fulfill a direct offer that is not accepted yet") - } + if vault.getType() != saleItem.getFtType() { + panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.getFtType().identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier))) + } - if vault.getType() != saleItem.getFtType() { - panic("The FT vault sent in to fulfill does not match the required type. Required Type : ".concat(saleItem.getFtType().identifier).concat(" . Sent-in vault type : ".concat(vault.getType().identifier))) - } + let tenant=self.getTenant() + let nftType= saleItem.getItemType() + let ftType= saleItem.getFtType() - let tenant=self.getTenant() - let nftType= saleItem.getItemType() - let ftType= saleItem.getFtType() + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "fulfill directOffer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "fulfill directOffer"), seller: self.owner!.address, buyer: saleItem.offerCallback.address) + if !actionResult.allowed { + panic(actionResult.message) + } + + let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType) - if !actionResult.allowed { - panic(actionResult.message) - } - let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketDirectOfferSoft.SaleItem>(), nftType: nftType, ftType: ftType) - - - let status="sold" - let owner=self.owner!.address - let balance=saleItem.getBalance() - let buyer=saleItem.getBuyer()! - let buyerName=FIND.reverseLookup(buyer) - let sellerName=FIND.reverseLookup(owner) - let profile = Profile.find(buyer) - - let nftInfo=saleItem.toNFTInfo(true) - - emit DirectOffer(tenant:tenant.name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: sellerName, amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) - - let royalty=saleItem.getRoyalty() - saleItem.acceptNonEscrowedBid() - - let resolved : {Address : String} = {} - resolved[buyer] = buyerName ?? "" - resolved[owner] = sellerName ?? "" - resolved[FindMarketDirectOfferSoft.account.address] = "find" - // Have to make sure the tenant always have the valid find name - resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name - - FindMarket.pay(tenant: tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:royalty, nftInfo: nftInfo, cuts:cuts, resolver: fun(address:Address): String? { return FIND.reverseLookup(address) }, resolvedAddress: resolved) - - destroy <- self.items.remove(key: id) - } - - pub fun getIds(): [UInt64] { - return self.items.keys - } - - pub fun getRoyaltyChangedIds(): [UInt64] { - let ids : [UInt64] = [] - for id in self.getIds() { - let item = self.borrow(id) - if !item.validateRoyalties() { - ids.append(id) - } - } - return ids - } - - pub fun containsId(_ id: UInt64): Bool { - return self.items.containsKey(id) - } - - pub fun borrow(_ id: UInt64): &SaleItem { - if !self.items.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.items[id] as &SaleItem?)! - } - - pub fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { - if !self.items.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.items[id] as &SaleItem{FindMarket.SaleItem}?)! - } - - destroy() { - destroy self.items - } - } - - /* - ========================================================================== - Bids are a collection/resource for storing the bids bidder made on leases - ========================================================================== - */ - - pub resource Bid : FindMarket.Bid { - access(contract) let from: Capability<&SaleItemCollection{SaleItemCollectionPublic}> - access(contract) let nftCap: Capability<&{NonFungibleToken.Receiver}> - access(contract) let itemUUID: UInt64 - - //this should reflect on what the above uuid is for - access(contract) let vaultType: Type - access(contract) var bidAt: UFix64 - access(contract) var balance: UFix64 //This is what you bid for non escrowed bids - access(contract) let bidExtraField: {String : AnyStruct} - - init(from: Capability<&SaleItemCollection{SaleItemCollectionPublic}>, itemUUID: UInt64, nftCap: Capability<&{NonFungibleToken.Receiver}>, vaultType:Type, nonEscrowedBalance:UFix64, bidExtraField: {String : AnyStruct}){ - self.vaultType= vaultType - self.balance=nonEscrowedBalance - self.itemUUID=itemUUID - self.from=from - self.bidAt=Clock.time() - self.nftCap=nftCap - self.bidExtraField=bidExtraField - } - - access(contract) fun setBidAt(_ time: UFix64) { - self.bidAt=time - } - - access(contract) fun increaseBid(_ amount:UFix64) { - self.balance=self.balance+amount - } - - pub fun getBalance() : UFix64 { - return self.balance - } - - pub fun getSellerAddress() : Address { - return self.from.address - } - - pub fun getBidExtraField() : {String : AnyStruct} { - return self.bidExtraField - } - } - - pub resource interface MarketBidCollectionPublic { - pub fun getBalance(_ id: UInt64) : UFix64 - pub fun getVaultType(_ id: UInt64) : Type - pub fun containsId(_ id: UInt64): Bool - access(contract) fun acceptNonEscrowed(_ nft: @NonFungibleToken.NFT) - access(contract) fun cancelBidFromSaleItem(_ id: UInt64) - } - - //A collection stored for bidders/buyers - pub resource MarketBidCollection: MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic { - - access(contract) var bids : @{UInt64: Bid} - access(contract) let receiver: Capability<&{FungibleToken.Receiver}> - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - //not sure we can store this here anymore. think it needs to be in every bid - init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.bids <- {} - self.receiver=receiver - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } - - //called from lease when auction is ended - access(contract) fun acceptNonEscrowed(_ nft: @NonFungibleToken.NFT) { - let id= nft.id - let bid <- self.bids.remove(key: nft.uuid) ?? panic("missing bid") - if !bid.nftCap.check() { - panic("Bidder unlinked the nft receiver capability. bidder address : ".concat(bid.nftCap.address.toString())) - } - bid.nftCap.borrow()!.deposit(token: <- nft) - destroy bid - } - - pub fun getVaultType(_ id:UInt64) : Type { - return self.borrowBid(id).vaultType - } - - pub fun getIds() : [UInt64] { - return self.bids.keys - } - - pub fun containsId(_ id: UInt64) : Bool { - return self.bids.containsKey(id) - } - - pub fun getBidType() : Type { - return Type<@Bid>() - } - - - pub fun bid(item: FindViews.ViewReadPointer, amount:UFix64, vaultType:Type, nftCap: Capability<&{NonFungibleToken.Receiver}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}, bidExtraField: {String : AnyStruct}) { - - // ensure it is not a 0 dollar listing - if amount <= 0.0 { - panic("Offer price should be greater than 0") - } - - // ensure validUntil is valid - if validUntil != nil && validUntil! < Clock.time() { - panic("Valid until is before current time") - } - - // check soul bound - if item.checkSoulBound() { - panic("This item is soul bounded and cannot be traded") - } - - if self.owner!.address == item.owner() { - panic("You cannot bid on your own resource") - } - - let uuid=item.getUUID() - - if self.bids[uuid] != nil { - panic("You already have an bid for this item, use increaseBid on that bid") - } - let tenant=self.getTenant() - - // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) - if tenant.name == "onefootball" { - // ensure it is not a 0 dollar listing - if amount <= 0.65 { - panic("Offer price should be greater than 0.65") - } - } - - let from=getAccount(item.owner()).getCapability<&SaleItemCollection{SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - - let bid <- create Bid(from: from, itemUUID:uuid, nftCap: nftCap, vaultType: vaultType, nonEscrowedBalance:amount, bidExtraField: bidExtraField) - let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for id=".concat(uuid.toString())) - let callbackCapability =self.owner!.getCapability<&MarketBidCollection{MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - - let oldToken <- self.bids[uuid] <- bid - saleItemCollection.registerBid(item: item, callback: callbackCapability, validUntil: validUntil, saleItemExtraField: saleItemExtraField) - destroy oldToken - } - - pub fun fulfillDirectOffer(id:UInt64, vault: @FungibleToken.Vault) { - - if self.bids[id] == nil { - panic( "You need to have a bid here already".concat(id.toString())) - } - - let bid =self.borrowBid(id) - let saleItem=bid.from.borrow()! - - if !saleItem.isAcceptedDirectOffer(id) { - panic("offer is not accepted yet") - } - - saleItem.fulfillDirectOfferNonEscrowed(id:id, vault: <- vault) - } - - pub fun increaseBid(id: UInt64, increaseBy: UFix64) { - let bid =self.borrowBid(id) - bid.setBidAt(Clock.time()) - bid.increaseBid(increaseBy) - if !bid.from.check() { - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) - } - bid.from.borrow()!.registerIncreasedBid(id) - } - - /// The users cancel a bid himself - pub fun cancelBid(_ id: UInt64) { - let bid= self.borrowBid(id) - if !bid.from.check() { - panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) - } - bid.from.borrow()!.cancelBid(id) - self.cancelBidFromSaleItem(id) - } - - //called from saleItem when things are cancelled - //if the bid is canceled from seller then we move the vault tokens back into your vault - access(contract) fun cancelBidFromSaleItem(_ id: UInt64) { - let bid <- self.bids.remove(key: id) ?? panic("missing bid") - destroy bid - } - - pub fun borrowBid(_ id: UInt64): &Bid { - if !self.bids.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.bids[id] as &Bid?)! - } - - pub fun borrowBidItem(_ id: UInt64): &{FindMarket.Bid} { - if !self.bids.containsKey(id) { - panic("This id does not exist.".concat(id.toString())) - } - return (&self.bids[id] as &Bid{FindMarket.Bid}?)! - } - - pub fun getBalance(_ id: UInt64) : UFix64 { - let bid= self.borrowBid(id) - return bid.balance - } - - destroy() { - destroy self.bids - } - } - - //Create an empty lease collection that store your leases to a name - pub fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>): @SaleItemCollection { - return <- create SaleItemCollection(tenantCapability) - } - - pub fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) : @MarketBidCollection { - return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) - } - - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? { - if FindMarket.getTenantCapability(marketplace) == nil { - panic("Invalid tenant") - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&SaleItemCollection{SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - } - return nil - } - - pub fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>? { - if FindMarket.getTenantCapability(marketplace) == nil { - panic("Invalid tenant") - } - if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { - return getAccount(user).getCapability<&MarketBidCollection{MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic}>(tenant.getPublicPath(Type<@MarketBidCollection>())) - } - return nil - } - - init() { - FindMarket.addSaleItemType(Type<@SaleItem>()) - FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) - FindMarket.addMarketBidType(Type<@Bid>()) - FindMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) - } + let status="sold" + let owner=self.owner!.address + let balance=saleItem.getBalance() + let buyer=saleItem.getBuyer()! + let buyerName=FIND.reverseLookup(buyer) + let sellerName=FIND.reverseLookup(owner) + let profile = Profile.find(buyer) + + let nftInfo=saleItem.toNFTInfo(true) + + emit DirectOffer(tenant:tenant.name, id: saleItem.getId(), saleID: saleItem.uuid, seller:owner, sellerName: sellerName, amount: balance, status:status, vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: profile.getAvatar(), endsAt: saleItem.validUntil, previousBuyer:nil, previousBuyerName:nil) + + let royalty=saleItem.getRoyalty() + saleItem.acceptNonEscrowedBid() + + let resolved : {Address : String} = {} + resolved[buyer] = buyerName ?? "" + resolved[owner] = sellerName ?? "" + resolved[FindMarketDirectOfferSoft.account.address] = "find" + // Have to make sure the tenant always have the valid find name + resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name + + FindMarket.pay(tenant: tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:royalty, nftInfo: nftInfo, cuts:cuts, resolver: fun(address:Address): String? { return FIND.reverseLookup(address) }, resolvedAddress: resolved) + + destroy <- self.items.remove(key: id) + } + + access(all) fun getIds(): [UInt64] { + return self.items.keys + } + + access(all) fun getRoyaltyChangedIds(): [UInt64] { + let ids : [UInt64] = [] + for id in self.getIds() { + let item = self.borrow(id) + if !item.validateRoyalties() { + ids.append(id) + } + } + return ids + } + + access(all) fun containsId(_ id: UInt64): Bool { + return self.items.containsKey(id) + } + + access(all) fun borrow(_ id: UInt64): &SaleItem { + if !self.items.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.items[id])! + } + + access(all) fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { + if !self.items.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.items[id])! + } + } + + /* + ========================================================================== + Bids are a collection/resource for storing the bids bidder made on leases + ========================================================================== + */ + + access(all) resource Bid : FindMarket.Bid { + access(contract) let from: Capability<&SaleItemCollection> + access(contract) let nftCap: Capability<&{NonFungibleToken.Receiver}> + access(contract) let itemUUID: UInt64 + + //this should reflect on what the above uuid is for + access(contract) let vaultType: Type + access(contract) var bidAt: UFix64 + access(contract) var balance: UFix64 //This is what you bid for non escrowed bids + access(contract) let bidExtraField: {String : AnyStruct} + + init(from: Capability<&SaleItemCollection>, itemUUID: UInt64, nftCap: Capability<&{NonFungibleToken.Receiver}>, vaultType:Type, nonEscrowedBalance:UFix64, bidExtraField: {String : AnyStruct}){ + self.vaultType= vaultType + self.balance=nonEscrowedBalance + self.itemUUID=itemUUID + self.from=from + self.bidAt=Clock.time() + self.nftCap=nftCap + self.bidExtraField=bidExtraField + } + + access(contract) fun setBidAt(_ time: UFix64) { + self.bidAt=time + } + + access(contract) fun increaseBid(_ amount:UFix64) { + self.balance=self.balance+amount + } + + access(all) fun getBalance() : UFix64 { + return self.balance + } + + access(all) fun getSellerAddress() : Address { + return self.from.address + } + + access(all) fun getBidExtraField() : {String : AnyStruct} { + return self.bidExtraField + } + } + + access(all) resource interface MarketBidCollectionPublic { + access(all) fun getBalance(_ id: UInt64) : UFix64 + access(all) fun getVaultType(_ id: UInt64) : Type + access(all) fun containsId(_ id: UInt64): Bool + access(contract) fun acceptNonEscrowed(_ nft: @{NonFungibleToken.NFT}) + access(contract) fun cancelBidFromSaleItem(_ id: UInt64) + } + + access(all) entitlement Buyer + + //A collection stored for bidders/buyers + access(all) resource MarketBidCollection: MarketBidCollectionPublic, FindMarket.MarketBidCollectionPublic { + + access(contract) var bids : @{UInt64: Bid} + access(contract) let receiver: Capability<&{FungibleToken.Receiver}> + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + //not sure we can store this here anymore. think it needs to be in every bid + init(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) { + self.bids <- {} + self.receiver=receiver + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } + + //called from lease when auction is ended + access(contract) fun acceptNonEscrowed(_ nft: @{NonFungibleToken.NFT}) { + let id= nft.id + let bid <- self.bids.remove(key: nft.uuid) ?? panic("missing bid") + if !bid.nftCap.check() { + panic("Bidder unlinked the nft receiver capability. bidder address : ".concat(bid.nftCap.address.toString())) + } + bid.nftCap.borrow()!.deposit(token: <- nft) + destroy bid + } + + access(all) fun getVaultType(_ id:UInt64) : Type { + return self.borrowBid(id).vaultType + } + + access(all) fun getIds() : [UInt64] { + return self.bids.keys + } + + access(all) fun containsId(_ id: UInt64) : Bool { + return self.bids.containsKey(id) + } + + access(all) fun getBidType() : Type { + return Type<@Bid>() + } + + access(Buyer) fun bid(item: FindViews.ViewReadPointer, amount: UFix64, vaultType:Type, nftCap: Capability<&{NonFungibleToken.Receiver}>, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}, bidExtraField: {String : AnyStruct}) { + + // ensure it is not a 0 dollar listing + if amount <= 0.0 { + panic("Offer price should be greater than 0") + } + + // ensure validUntil is valid + if validUntil != nil && validUntil! < Clock.time() { + panic("Valid until is before current time") + } + + // check soul bound + if item.checkSoulBound() { + panic("This item is soul bounded and cannot be traded") + } + + if self.owner!.address == item.owner() { + panic("You cannot bid on your own resource") + } + + let uuid=item.getUUID() + + if self.bids[uuid] != nil { + panic("You already have an bid for this item, use increaseBid on that bid") + } + let tenant=self.getTenant() + + // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) + if tenant.name == "onefootball" { + // ensure it is not a 0 dollar listing + if amount <= 0.65 { + panic("Offer price should be greater than 0.65") + } + } + + let from=getAccount(item.owner()).capabilities.get<&SaleItemCollection>(tenant.getPublicPath(Type<@SaleItemCollection>())) + + let bid <- create Bid(from: from, itemUUID:uuid, nftCap: nftCap, vaultType: vaultType, nonEscrowedBalance:amount, bidExtraField: bidExtraField) + let saleItemCollection= from.borrow() ?? panic("Could not borrow sale item for id=".concat(uuid.toString())) + let callbackCapability =self.owner!.capabilities.get<&MarketBidCollection>(tenant.getPublicPath(Type<@MarketBidCollection>())) + + let oldToken <- self.bids[uuid] <- bid + saleItemCollection.registerBid(item: item, callback: callbackCapability, validUntil: validUntil, saleItemExtraField: saleItemExtraField) + destroy oldToken + } + + access(Buyer) fun fulfillDirectOffer(id:UInt64, vault: @{FungibleToken.Vault}) { + + if self.bids[id] == nil { + panic( "You need to have a bid here already".concat(id.toString())) + } + + let bid =self.borrowBid(id) + let saleItem=bid.from.borrow()! + + if !saleItem.isAcceptedDirectOffer(id) { + panic("offer is not accepted yet") + } + + saleItem.fulfillDirectOfferNonEscrowed(id:id, vault: <- vault) + } + + access(Buyer) fun increaseBid(id: UInt64, increaseBy: UFix64) { + let bid =self.borrowBid(id) + bid.setBidAt(Clock.time()) + bid.increaseBid(increaseBy) + if !bid.from.check() { + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) + } + bid.from.borrow()!.registerIncreasedBid(id) + } + + /// The users cancel a bid himself + access(Buyer) fun cancelBid(_ id: UInt64) { + let bid= self.borrowBid(id) + if !bid.from.check() { + panic("Seller unlinked the SaleItem collection capability. seller address : ".concat(bid.from.address.toString())) + } + bid.from.borrow()!.cancelBid(id) + self.cancelBidFromSaleItem(id) + } + + //called from saleItem when things are cancelled + //if the bid is canceled from seller then we move the vault tokens back into your vault + access(contract) fun cancelBidFromSaleItem(_ id: UInt64) { + let bid <- self.bids.remove(key: id) ?? panic("missing bid") + destroy bid + } + + access(all) fun borrowBid(_ id: UInt64): &Bid { + if !self.bids.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.bids[id])! + } + + access(all) fun borrowBidItem(_ id: UInt64): &{FindMarket.Bid} { + if !self.bids.containsKey(id) { + panic("This id does not exist.".concat(id.toString())) + } + return (&self.bids[id])! + } + + access(all) fun getBalance(_ id: UInt64) : UFix64 { + let bid= self.borrowBid(id) + return bid.balance + } + + } + + //Create an empty lease collection that store your leases to a name + access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>) : @SaleItemCollection { + return <- create SaleItemCollection(tenantCapability) + } + + access(all) fun createEmptyMarketBidCollection(receiver: Capability<&{FungibleToken.Receiver}>, tenantCapability: Capability<&FindMarket.Tenant>) : @MarketBidCollection { + return <- create MarketBidCollection(receiver: receiver, tenantCapability:tenantCapability) + } + + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&SaleItemCollection>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + let cap = getAccount(user).capabilities.get<&SaleItemCollection>(tenant.getPublicPath(Type<@SaleItemCollection>())) + if !cap.check() { + return nil + } + return cap + } + return nil + } + + access(all) fun getBidCapability( marketplace:Address, user:Address) : Capability<&MarketBidCollection>? { + if FindMarket.getTenantCapability(marketplace) == nil { + panic("Invalid tenant") + } + if let tenant=FindMarket.getTenantCapability(marketplace)!.borrow() { + let cap = getAccount(user).capabilities.get<&MarketBidCollection>(tenant.getPublicPath(Type<@MarketBidCollection>())) + if !cap.check() { + return nil + } + return cap + } + return nil + } + + init() { + FindMarket.addSaleItemType(Type<@SaleItem>()) + FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) + FindMarket.addMarketBidType(Type<@Bid>()) + FindMarket.addMarketBidCollectionType(Type<@MarketBidCollection>()) + } } diff --git a/contracts/FindMarketInfrastructureCut.cdc b/contracts/FindMarketInfrastructureCut.cdc index 33091c19..9ff75482 100644 --- a/contracts/FindMarketInfrastructureCut.cdc +++ b/contracts/FindMarketInfrastructureCut.cdc @@ -1,97 +1,97 @@ -import FindMarketCutInterface from "../contracts/FindMarketCutInterface.cdc" -import FindMarketCutStruct from "../contracts/FindMarketCutStruct.cdc" -import FindMarketCut from "../contracts/FindMarketCut.cdc" - -pub contract FindMarketInfrastructureCut : FindMarketCutInterface { - - pub let contractName: String - pub let category: String - - // tenant to {ruleId to cut} - access(contract) let cuts : {String : {String : FindMarketCutStruct.Cuts}} - access(contract) let cutsCache : {String : {String : FindMarketCutStruct.Cuts}} - - pub event Cut(tenant: String, type: String, cutInfo: [FindMarketCutStruct.EventSafeCut], action: String, remark: String?) - - pub fun getCut(tenant: String, listingType: Type, nftType: Type, ftType: Type) : FindMarketCutStruct.Cuts? { - - let ruleId = FindMarketCut.getRuleId(listingType: listingType, nftType: nftType, ftType: ftType) - if let cache = self.getTenantRulesCache(tenant: tenant, ruleId: ruleId) { - return cache - } - - let types = [listingType.identifier, nftType.identifier, ftType.identifier] - var cuts : [{FindMarketCutStruct.Cut}] = [] - var returningCut : FindMarketCutStruct.Cuts? = nil - for t in types { - let cutMapping = self.cuts[tenant] ?? {} - if let c = cutMapping[t] { - cuts.appendAll(c.cuts) - } - } - if cuts.length > 0 { - returningCut = FindMarketCutStruct.Cuts(cuts) - - // set cache if not already - // we do not need to check if cache exist here, because if it is, it will be returned earlier - self.setTenantRulesCache(tenant: tenant, ruleId: ruleId, result: returningCut!) - } - - return returningCut - } - - access(account) fun setTenantCuts(tenant: String, types: [Type], cuts: FindMarketCutStruct.Cuts) { - let old = self.cuts[tenant] ?? {} - for t in types { - old[t.identifier] = cuts - emit Cut(tenant: tenant, type: t.identifier, cutInfo: cuts.getEventSafeCuts(), action: "add", remark: nil) - } - self.cuts[tenant] = old - } - - access(account) fun removeTenantCuts(tenant: String, types: [Type]) : [FindMarketCutStruct.Cuts] { - var panicMsg = "tenant infrastructure cut is not registered. Tenant : ".concat(tenant) - let old = self.cuts[tenant] ?? panic(panicMsg) - let cutsReturn : [FindMarketCutStruct.Cuts] = [] - for t in types { - let detailedPanicMsg = panicMsg.concat(" Type : ".concat(t.identifier)) - let cuts = old.remove(key: t.identifier) ?? panic(detailedPanicMsg) - cutsReturn.append(cuts) - emit Cut(tenant: tenant, type: t.identifier, cutInfo: cuts.getEventSafeCuts(), action: "remove", remark: nil) - } - self.cuts[tenant] = old - return cutsReturn - } - - access(account) fun setTenantRulesCache(tenant: String, ruleId: String, result: FindMarketCutStruct.Cuts) { - - let old = self.cutsCache[tenant] ?? {} - if old[ruleId] != nil { - panic("There is already a cache for this find rule. RuleId : ".concat(ruleId)) - } - old[ruleId] = result - self.cutsCache[tenant] = old - } - - pub fun getTenantRulesCache(tenant: String, ruleId: String) : FindMarketCutStruct.Cuts? { - if self.cutsCache[tenant] == nil { - return nil - } - return self.cutsCache[tenant]![ruleId] - } - - access(account) fun resetTenantRulesCache(_ tenant: String) { - self.cutsCache.remove(key: tenant) - } - - - init() { - self.cuts = {} - self.cutsCache = {} - - self.contractName = "FindMarketInfrastructureCut" - self.category = "infrastructure" - FindMarketCut.setCategory(category: self.category, contractName: self.contractName) - } +import "FindMarketCutInterface" +import "FindMarketCutStruct" +import "FindMarketCut" + +access(all) contract FindMarketInfrastructureCut : FindMarketCutInterface { + + access(all) let contractName: String + access(all) let category: String + + // tenant to {ruleId to cut} + access(contract) let cuts : {String : {String : FindMarketCutStruct.Cuts}} + access(contract) let cutsCache : {String : {String : FindMarketCutStruct.Cuts}} + + access(all) event Cut(tenant: String, type: String, cutInfo: [FindMarketCutStruct.EventSafeCut], action: String, remark: String?) + + access(all) fun getCut(tenant: String, listingType: Type, nftType: Type, ftType: Type) : FindMarketCutStruct.Cuts? { + + let ruleId = FindMarketCut.getRuleId(listingType: listingType, nftType: nftType, ftType: ftType) + if let cache = self.getTenantRulesCache(tenant: tenant, ruleId: ruleId) { + return cache + } + + let types = [listingType.identifier, nftType.identifier, ftType.identifier] + var cuts : [{FindMarketCutStruct.Cut}] = [] + var returningCut : FindMarketCutStruct.Cuts? = nil + for t in types { + let cutMapping = self.cuts[tenant] ?? {} + if let c = cutMapping[t] { + cuts.appendAll(c.cuts) + } + } + if cuts.length > 0 { + returningCut = FindMarketCutStruct.Cuts(cuts:cuts) + + // set cache if not already + // we do not need to check if cache exist here, because if it is, it will be returned earlier + self.setTenantRulesCache(tenant: tenant, ruleId: ruleId, result: returningCut!) + } + + return returningCut + } + + access(account) fun setTenantCuts(tenant: String, types: [Type], cuts: FindMarketCutStruct.Cuts) { + let old = self.cuts[tenant] ?? {} + for t in types { + old[t.identifier] = cuts + emit Cut(tenant: tenant, type: t.identifier, cutInfo: cuts.getEventSafeCuts(), action: "add", remark: nil) + } + self.cuts[tenant] = old + } + + access(account) fun removeTenantCuts(tenant: String, types: [Type]) : [FindMarketCutStruct.Cuts] { + var panicMsg = "tenant infrastructure cut is not registered. Tenant : ".concat(tenant) + let old = self.cuts[tenant] ?? panic(panicMsg) + let cutsReturn : [FindMarketCutStruct.Cuts] = [] + for t in types { + let detailedPanicMsg = panicMsg.concat(" Type : ".concat(t.identifier)) + let cuts = old.remove(key: t.identifier) ?? panic(detailedPanicMsg) + cutsReturn.append(cuts) + emit Cut(tenant: tenant, type: t.identifier, cutInfo: cuts.getEventSafeCuts(), action: "remove", remark: nil) + } + self.cuts[tenant] = old + return cutsReturn + } + + access(account) fun setTenantRulesCache(tenant: String, ruleId: String, result: FindMarketCutStruct.Cuts) { + + let old = self.cutsCache[tenant] ?? {} + if old[ruleId] != nil { + panic("There is already a cache for this find rule. RuleId : ".concat(ruleId)) + } + old[ruleId] = result + self.cutsCache[tenant] = old + } + + access(all) fun getTenantRulesCache(tenant: String, ruleId: String) : FindMarketCutStruct.Cuts? { + if self.cutsCache[tenant] == nil { + return nil + } + return self.cutsCache[tenant]![ruleId] + } + + access(account) fun resetTenantRulesCache(_ tenant: String) { + self.cutsCache.remove(key: tenant) + } + + + init() { + self.cuts = {} + self.cutsCache = {} + + self.contractName = "FindMarketInfrastructureCut" + self.category = "infrastructure" + FindMarketCut.setCategory(category: self.category, contractName: self.contractName) + } } diff --git a/contracts/FindMarketSale.cdc b/contracts/FindMarketSale.cdc index 615a9a30..d8e820f5 100644 --- a/contracts/FindMarketSale.cdc +++ b/contracts/FindMarketSale.cdc @@ -1,388 +1,386 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import Clock from "./Clock.cdc" -import FIND from "./FIND.cdc" -import Profile from "./Profile.cdc" -import FindMarket from "./FindMarket.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "Clock" +import "FIND" +import "Profile" +import "FindMarket" /* A Find Market for direct sales */ -pub contract FindMarketSale { - - pub event Sale(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, nft: FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar: String?, endsAt:UFix64?) - - //A sale item for a direct sale - pub resource SaleItem : FindMarket.SaleItem{ - - //this is set when bought so that pay will work - access(self) var buyer: Address? - - access(contract) let vaultType: Type //The type of vault to use for this sale Item - access(contract) var pointer: FindViews.AuthNFTPointer - - //this field is set if this is a saleItem - access(contract) var salePrice: UFix64 - access(contract) var validUntil: UFix64? - access(contract) let saleItemExtraField: {String : AnyStruct} - - access(contract) let totalRoyalties: UFix64 - init(pointer: FindViews.AuthNFTPointer, vaultType: Type, price:UFix64, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { - self.vaultType=vaultType - self.pointer=pointer - self.salePrice=price - self.buyer=nil - self.validUntil=validUntil - self.saleItemExtraField=saleItemExtraField - var royalties : UFix64 = 0.0 - self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() - } - - pub fun getSaleType() : String { - return "active_listed" - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun getListingTypeIdentifier(): String { - return Type<@SaleItem>().identifier - } - - pub fun setBuyer(_ address:Address) { - self.buyer=address - } - - pub fun getBuyer(): Address? { - return self.buyer - } - - pub fun getBuyerName() : String? { - if let address = self.buyer { - return FIND.reverseLookup(address) - } - return nil - } - - pub fun getId() : UInt64{ - return self.pointer.getUUID() - } - - pub fun getItemID() : UInt64 { - return self.pointer.id - } - - pub fun getItemType() : Type { - return self.pointer.getItemType() - } - - pub fun getRoyalty() : MetadataViews.Royalties { - return self.pointer.getRoyalty() - } - - pub fun getSeller() : Address { - return self.pointer.owner() - } - - pub fun getSellerName() : String? { - return FIND.reverseLookup(self.pointer.owner()) - } - - pub fun getBalance() : UFix64 { - return self.salePrice - } - - pub fun getAuction(): FindMarket.AuctionItem? { - return nil - } - - pub fun getFtType() : Type { - return self.vaultType - } - - pub fun setValidUntil(_ time: UFix64?) { - self.validUntil=time - } - - pub fun getValidUntil() : UFix64? { - return self.validUntil - } - - pub fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ - return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) - } - - pub fun checkPointer() : Bool { - return self.pointer.valid() - } - - pub fun checkSoulBound() : Bool { - return self.pointer.checkSoulBound() - } - - pub fun getSaleItemExtraField() : {String : AnyStruct} { - return self.saleItemExtraField - } - - pub fun getTotalRoyalties() : UFix64 { - return self.totalRoyalties - } - - pub fun validateRoyalties() : Bool { - return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() - } - - pub fun getDisplay() : MetadataViews.Display { - return self.pointer.getDisplay() - } - - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData { - return self.pointer.getNFTCollectionData() - } - } - - pub resource interface SaleItemCollectionPublic { - //fetch all the tokens in the collection - pub fun getIds(): [UInt64] - pub fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} //TODO: look if this is safe - pub fun containsId(_ id: UInt64): Bool - pub fun buy(id: UInt64, vault: @FungibleToken.Vault, nftCap: Capability<&{NonFungibleToken.Receiver}>) - } - - pub resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { - //is this the best approach now or just put the NFT inside the saleItem? - access(contract) var items: @{UInt64: SaleItem} - - access(contract) let tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}> - - init (_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>) { - self.items <- {} - self.tenantCapability=tenantCapability - } - - access(self) fun getTenant() : &FindMarket.Tenant{FindMarket.TenantPublic} { - if !self.tenantCapability.check() { - panic("Tenant client is not linked anymore") - } - return self.tenantCapability.borrow()! - } - - pub fun getListingType() : Type { - return Type<@SaleItem>() - } - - pub fun buy(id: UInt64, vault: @FungibleToken.Vault, nftCap: Capability<&{NonFungibleToken.Receiver}>) { - if !self.items.containsKey(id) { - panic("Invalid id=".concat(id.toString())) - } - - if self.owner!.address == nftCap.address { - panic("You cannot buy your own listing") - } - - - let saleItem=self.borrow(id) - - - - - if saleItem.salePrice != vault.balance { - panic("Incorrect balance sent in vault. Expected ".concat(saleItem.salePrice.toString()).concat(" got ").concat(vault.balance.toString())) - } - - if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { - panic("This sale item listing is already expired") - } - - if saleItem.vaultType != vault.getType() { - panic("This item can be bought using ".concat(saleItem.vaultType.identifier).concat(" you have sent in ").concat(vault.getType().identifier)) - } - let tenant=self.getTenant() - let ftType=saleItem.vaultType - let nftType=saleItem.getItemType() - - //TOOD: method on saleItems that returns a cacheKey listingType-nftType-ftType - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketSale.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "buy item for sale"), seller: self.owner!.address, buyer: nftCap.address) - - if !actionResult.allowed { - panic(actionResult.message) - } - - let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketSale.SaleItem>(), nftType: nftType, ftType: ftType) - - let nftInfo= saleItem.toNFTInfo(true) - saleItem.setBuyer(nftCap.address) - let buyer=nftCap.address - let buyerName=FIND.reverseLookup(buyer) - let sellerName=FIND.reverseLookup(self.owner!.address) - - emit Sale(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: saleItem.getBalance(), status:"sold", vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: Profile.find(nftCap.address).getAvatar() ,endsAt:saleItem.validUntil) - - - let resolved : {Address : String} = {} - - resolved[buyer] = buyerName ?? "" - resolved[self.owner!.address] = sellerName ?? "" - resolved[FindMarketSale.account.address] = "find" - // Have to make sure the tenant always have the valid find name - resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name - - FindMarket.pay(tenant:tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:saleItem.getRoyalty(), nftInfo:nftInfo, cuts:cuts, resolver: fun(address:Address): String? { return FIND.reverseLookup(address) }, resolvedAddress: resolved) - - - if !nftCap.check() { - let cpCap =getAccount(nftCap.address).getCapability<&{NonFungibleToken.CollectionPublic}>(saleItem.getNFTCollectionData().publicPath) - if !cpCap.check() { - panic("The nft receiver capability passed in is invalid.") - } else { - cpCap.borrow()!.deposit(token: <- saleItem.pointer.withdraw()) - } - } else { - nftCap.borrow()!.deposit(token: <- saleItem.pointer.withdraw()) - } - - destroy <- self.items.remove(key: id) - } - - pub fun listForSale(pointer: FindViews.AuthNFTPointer, vaultType: Type, directSellPrice:UFix64, validUntil: UFix64?, extraField: {String:AnyStruct}) { - - - // ensure it is not a 0 dollar listing - if directSellPrice <= 0.0 { - panic("Listing price should be greater than 0") - } - - if validUntil != nil && validUntil! < Clock.time() { - panic("Valid until is before current time") - } - - // check soul bound - if pointer.checkSoulBound() { - panic("This item is soul bounded and cannot be traded") - } - - // What happends if we relist - let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, price: directSellPrice, validUntil: validUntil, saleItemExtraField:extraField) - - let tenant=self.getTenant() - - // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) - if tenant.name == "onefootball" { - // ensure it is not a 0 dollar listing - if directSellPrice <= 0.65 { - panic("Listing price should be greater than 0.65") - } - } - - let nftType=saleItem.getItemType() - let ftType=saleItem.getFtType() - - let actionResult=tenant.allowedAction(listingType: Type<@FindMarketSale.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "list item for sale"), seller: self.owner!.address, buyer: nil) - - if !actionResult.allowed { - panic(actionResult.message) - // let message = "vault : ".concat(vaultType.identifier).concat(" . NFT Type : ".concat(saleItem.getItemType().identifier)) - // panic(message) - } - - let owner=self.owner!.address - emit Sale(tenant: tenant.name, id: pointer.getUUID(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "active_listed", vaultType: vaultType.identifier, nft:saleItem.toNFTInfo(true), buyer: nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) - let old <- self.items[pointer.getUUID()] <- saleItem - destroy old - - } - - pub fun delist(_ id: UInt64) { - if !self.items.containsKey(id) { - panic("Unknown item with id=".concat(id.toString())) - } - - let saleItem <- self.items.remove(key: id)! - - let tenant=self.getTenant() - - var status = "cancel" - var nftInfo:FindMarket.NFTInfo?=nil - if saleItem.checkPointer() { - nftInfo=saleItem.toNFTInfo(false) - } - - let owner=self.owner!.address - emit Sale(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName:FIND.reverseLookup(owner), amount: saleItem.salePrice, status: status, vaultType: saleItem.vaultType.identifier,nft: nftInfo, buyer:nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) - destroy saleItem - } - - pub fun relist(_ id: UInt64) { - let saleItem = self.borrow(id) - - let pointer = saleItem.pointer - let vaultType= saleItem.vaultType - let directSellPrice=saleItem.salePrice - var validUntil= saleItem.validUntil - if validUntil != nil && saleItem.validUntil! <= Clock.time() { - validUntil = nil - } - let extraField= saleItem.saleItemExtraField - - self.delist(id) - self.listForSale(pointer: pointer, vaultType: vaultType, directSellPrice:directSellPrice, validUntil: validUntil, extraField: extraField) - } - - pub fun getIds(): [UInt64] { - return self.items.keys - } - - pub fun getRoyaltyChangedIds(): [UInt64] { - let ids : [UInt64] = [] - for id in self.getIds() { - let item = self.borrow(id) - if !item.validateRoyalties() { - ids.append(id) - } - } - return ids - } - - pub fun containsId(_ id: UInt64): Bool { - return self.items.containsKey(id) - } - - pub fun borrow(_ id: UInt64): &SaleItem { - return (&self.items[id] as &SaleItem?)! - } - - pub fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem} { - if !self.items.containsKey(id) { - panic("This id does not exist : ".concat(id.toString())) - } - return (&self.items[id] as &SaleItem{FindMarket.SaleItem}?)! - } - - destroy() { - destroy self.items - } - } - - //Create an empty lease collection that store your leases to a name - pub fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant{FindMarket.TenantPublic}>): @SaleItemCollection { - return <- create SaleItemCollection(tenantCapability) - } - - pub fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? { - if let tenantCap=FindMarket.getTenantCapability(marketplace) { - let tenant=tenantCap.borrow() ?? panic("Invalid tenant") - return getAccount(user).getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) - } - return nil - } - - - init() { - FindMarket.addSaleItemType(Type<@SaleItem>()) - FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) - } +access(all) contract FindMarketSale { + + // A seller can list, delist and relist leases for sale + access(all) entitlement Seller + + access(all) event Sale(tenant: String, id: UInt64, saleID: UInt64, seller: Address, sellerName: String?, amount: UFix64, status: String, vaultType:String, nft: FindMarket.NFTInfo?, buyer:Address?, buyerName:String?, buyerAvatar: String?, endsAt:UFix64?) + + //A sale item for a direct sale + access(all) resource SaleItem : FindMarket.SaleItem{ + + //this is set when bought so that pay will work + access(self) var buyer: Address? + + access(contract) let vaultType: Type //The type of vault to use for this sale Item + access(contract) var pointer: FindViews.AuthNFTPointer + + //this field is set if this is a saleItem + access(contract) var salePrice: UFix64 + access(contract) var validUntil: UFix64? + access(contract) let saleItemExtraField: {String : AnyStruct} + + access(contract) let totalRoyalties: UFix64 + init(pointer: FindViews.AuthNFTPointer, vaultType: Type, price:UFix64, validUntil: UFix64?, saleItemExtraField: {String : AnyStruct}) { + self.vaultType=vaultType + self.pointer=pointer + self.salePrice=price + self.buyer=nil + self.validUntil=validUntil + self.saleItemExtraField=saleItemExtraField + var royalties : UFix64 = 0.0 + self.totalRoyalties=self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getPointer() : FindViews.AuthNFTPointer { + return self.pointer + } + + access(all) fun getSaleType() : String { + return "active_listed" + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun getListingTypeIdentifier(): String { + return Type<@SaleItem>().identifier + } + + access(account) fun setBuyer(_ address:Address) { + self.buyer=address + } + + access(all) fun getBuyer(): Address? { + return self.buyer + } + + access(all) fun getBuyerName() : String? { + if let address = self.buyer { + return FIND.reverseLookup(address) + } + return nil + } + + access(all) fun getId() : UInt64{ + return self.pointer.getUUID() + } + + access(all) fun getItemID() : UInt64 { + return self.pointer.id + } + + access(all) fun getItemType() : Type { + return self.pointer.getItemType() + } + + access(all) fun getRoyalty() : MetadataViews.Royalties { + return self.pointer.getRoyalty() + } + + access(all) fun getSeller() : Address { + return self.pointer.owner() + } + + access(all) fun getSellerName() : String? { + return FIND.reverseLookup(self.pointer.owner()) + } + + access(all) fun getBalance() : UFix64 { + return self.salePrice + } + + access(all) fun getAuction(): FindMarket.AuctionItem? { + return nil + } + + access(all) fun getFtType() : Type { + return self.vaultType + } + + access(contract) fun setValidUntil(_ time: UFix64?) { + self.validUntil=time + } + + access(all) fun getValidUntil() : UFix64? { + return self.validUntil + } + + access(all) fun toNFTInfo(_ detail: Bool) : FindMarket.NFTInfo{ + return FindMarket.NFTInfo(self.pointer.getViewResolver(), id: self.pointer.id, detail:detail) + } + + access(all) fun checkPointer() : Bool { + return self.pointer.valid() + } + + access(all) fun checkSoulBound() : Bool { + return self.pointer.checkSoulBound() + } + + access(all) fun getSaleItemExtraField() : {String : AnyStruct} { + return self.saleItemExtraField + } + + access(all) fun getTotalRoyalties() : UFix64 { + return self.totalRoyalties + } + + access(all) fun validateRoyalties() : Bool { + return self.totalRoyalties == self.pointer.getTotalRoyaltiesCut() + } + + access(all) fun getDisplay() : MetadataViews.Display { + return self.pointer.getDisplay() + } + + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData { + return self.pointer.getNFTCollectionData() + } + } + + access(all) resource interface SaleItemCollectionPublic { + //fetch all the tokens in the collection + access(all) fun getIds(): [UInt64] + access(all) fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem}? + access(all) fun containsId(_ id: UInt64): Bool + access(all) fun buy(id: UInt64, vault: @{FungibleToken.Vault}, nftCap: Capability<&{NonFungibleToken.Receiver}>) + } + + access(all) resource SaleItemCollection: SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic { + //is this the best approach now or just put the NFT inside the saleItem? + access(contract) var items: @{UInt64: SaleItem} + + //Not sure if this should be the interface or the impl + access(contract) let tenantCapability: Capability<&FindMarket.Tenant> + + init (_ tenantCapability: Capability<&FindMarket.Tenant>) { + self.items <- {} + self.tenantCapability=tenantCapability + } + + access(self) fun getTenant() : &FindMarket.Tenant { + if !self.tenantCapability.check() { + panic("Tenant client is not linked anymore") + } + return self.tenantCapability.borrow()! + } + + access(all) fun getListingType() : Type { + return Type<@SaleItem>() + } + + access(all) fun buy(id: UInt64, vault: @{FungibleToken.Vault}, nftCap: Capability<&{NonFungibleToken.Receiver}>) { + if !self.items.containsKey(id) { + panic("Invalid id=".concat(id.toString())) + } + + if self.owner!.address == nftCap.address { + panic("You cannot buy your own listing") + } + + let saleItem=self.borrow(id) + + if saleItem.salePrice != vault.balance { + panic("Incorrect balance sent in vault. Expected ".concat(saleItem.salePrice.toString()).concat(" got ").concat(vault.balance.toString())) + } + + if saleItem.validUntil != nil && saleItem.validUntil! < Clock.time() { + panic("This sale item listing is already expired") + } + + if saleItem.vaultType != vault.getType() { + panic("This item can be bought using ".concat(saleItem.vaultType.identifier).concat(" you have sent in ").concat(vault.getType().identifier)) + } + let tenant=self.getTenant() + let ftType=saleItem.vaultType + let nftType=saleItem.getItemType() + + //TOOD: method on saleItems that returns a cacheKey listingType-nftType-ftType + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketSale.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:false, name: "buy item for sale"), seller: self.owner!.address, buyer: nftCap.address) + + if !actionResult.allowed { + panic(actionResult.message) + } + + let cuts= tenant.getCuts(name: actionResult.name, listingType: Type<@FindMarketSale.SaleItem>(), nftType: nftType, ftType: ftType) + + let nftInfo= saleItem.toNFTInfo(true) + saleItem.setBuyer(nftCap.address) + let buyer=nftCap.address + let buyerName=FIND.reverseLookup(buyer) + let sellerName=FIND.reverseLookup(self.owner!.address) + + emit Sale(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:self.owner!.address, sellerName: FIND.reverseLookup(self.owner!.address), amount: saleItem.getBalance(), status:"sold", vaultType: ftType.identifier, nft:nftInfo, buyer: buyer, buyerName: buyerName, buyerAvatar: Profile.find(nftCap.address).getAvatar() ,endsAt:saleItem.validUntil) + let resolved : {Address : String} = {} + + resolved[buyer] = buyerName ?? "" + resolved[self.owner!.address] = sellerName ?? "" + resolved[FindMarketSale.account.address] = "find" + // Have to make sure the tenant always have the valid find name + resolved[FindMarket.tenantNameAddress[tenant.name]!] = tenant.name + + FindMarket.pay(tenant:tenant.name, id:id, saleItem: saleItem, vault: <- vault, royalty:saleItem.getRoyalty(), nftInfo:nftInfo, cuts:cuts, resolver: fun(address:Address): String? { return FIND.reverseLookup(address) }, resolvedAddress: resolved) + + + if !nftCap.check() { + let cp =getAccount(nftCap.address).capabilities.borrow<&{NonFungibleToken.Collection}>(saleItem.getNFTCollectionData().publicPath) + if cp == nil { + panic("The nft receiver capability passed in is invalid.") + } else { + cp!.deposit(token: <- saleItem.pointer.withdraw()) + } + } else { + nftCap.borrow()!.deposit(token: <- saleItem.pointer.withdraw()) + } + + destroy <- self.items.remove(key: id) + } + + access(Seller) fun listForSale(pointer: FindViews.AuthNFTPointer, vaultType: Type, directSellPrice:UFix64, validUntil: UFix64?, extraField: {String:AnyStruct}) { + + + // ensure it is not a 0 dollar listing + if directSellPrice <= 0.0 { + panic("Listing price should be greater than 0") + } + + if validUntil != nil && validUntil! < Clock.time() { + panic("Valid until is before current time") + } + + // check soul bound + if pointer.checkSoulBound() { + panic("This item is soul bounded and cannot be traded") + } + + // What happends if we relist + let saleItem <- create SaleItem(pointer: pointer, vaultType:vaultType, price: directSellPrice, validUntil: validUntil, saleItemExtraField:extraField) + + let tenant=self.getTenant() + + // Check if it is onefootball. If so, listing has to be at least $0.65 (DUC) + if tenant.name == "onefootball" { + // ensure it is not a 0 dollar listing + if directSellPrice <= 0.65 { + panic("Listing price should be greater than 0.65") + } + } + + let nftType=saleItem.getItemType() + let ftType=saleItem.getFtType() + + let actionResult=tenant.allowedAction(listingType: Type<@FindMarketSale.SaleItem>(), nftType: nftType, ftType: ftType, action: FindMarket.MarketAction(listing:true, name: "list item for sale"), seller: self.owner!.address, buyer: nil) + + if !actionResult.allowed { + panic(actionResult.message) + // let message = "vault : ".concat(vaultType.identifier).concat(" . NFT Type : ".concat(saleItem.getItemType().identifier)) + // panic(message) + } + + let owner=self.owner!.address + emit Sale(tenant: tenant.name, id: pointer.getUUID(), saleID: saleItem.uuid, seller:owner, sellerName: FIND.reverseLookup(owner), amount: saleItem.salePrice, status: "active_listed", vaultType: vaultType.identifier, nft:saleItem.toNFTInfo(true), buyer: nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) + let old <- self.items[pointer.getUUID()] <- saleItem + destroy old + + } + + access(Seller) fun delist(_ id: UInt64) { + if !self.items.containsKey(id) { + panic("Unknown item with id=".concat(id.toString())) + } + + let saleItem <- self.items.remove(key: id)! + + let tenant=self.getTenant() + + var status = "cancel" + var nftInfo:FindMarket.NFTInfo?=nil + if saleItem.checkPointer() { + nftInfo=saleItem.toNFTInfo(false) + } + + let owner=self.owner!.address + emit Sale(tenant:tenant.name, id: id, saleID: saleItem.uuid, seller:owner, sellerName:FIND.reverseLookup(owner), amount: saleItem.salePrice, status: status, vaultType: saleItem.vaultType.identifier,nft: nftInfo, buyer:nil, buyerName:nil, buyerAvatar:nil, endsAt:saleItem.validUntil) + destroy saleItem + } + + access(Seller) fun relist(_ id: UInt64) { + let saleItem = self.borrow(id) + + let pointer = saleItem.getPointer() + let vaultType= saleItem.vaultType + let directSellPrice=saleItem.salePrice + var validUntil= saleItem.validUntil + if validUntil != nil && saleItem.validUntil! <= Clock.time() { + validUntil = nil + } + let extraField= saleItem.getSaleItemExtraField() + + self.delist(id) + self.listForSale(pointer: pointer, vaultType: vaultType, directSellPrice:directSellPrice, validUntil: validUntil, extraField: extraField) + } + + access(all) fun getIds(): [UInt64] { + return self.items.keys + } + + access(all) fun getRoyaltyChangedIds(): [UInt64] { + let ids : [UInt64] = [] + for id in self.getIds() { + let item = self.borrow(id) + if !item.validateRoyalties() { + ids.append(id) + } + } + return ids + } + + access(all) fun containsId(_ id: UInt64): Bool { + return self.items.containsKey(id) + } + + access(all) fun borrow(_ id: UInt64): &SaleItem { + return (&self.items[id])! + } + + access(all) fun borrowSaleItem(_ id: UInt64) : &{FindMarket.SaleItem}? { + if !self.items.containsKey(id) { + panic("This id does not exist : ".concat(id.toString())) + } + return &self.items[id] + } + } + + //Create an empty lease collection that store your leases to a name + access(all) fun createEmptySaleItemCollection(_ tenantCapability: Capability<&FindMarket.Tenant>) : @SaleItemCollection { + return <- create SaleItemCollection(tenantCapability) + } + + access(all) fun getSaleItemCapability(marketplace:Address, user:Address) : Capability<&{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>? { + if let tenantCap=FindMarket.getTenantCapability(marketplace) { + let tenant=tenantCap.borrow() ?? panic("Invalid tenant") + return getAccount(user).capabilities.get<&{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(tenant.getPublicPath(Type<@SaleItemCollection>())) + } + return nil + } + + + init() { + FindMarket.addSaleItemType(Type<@SaleItem>()) + FindMarket.addSaleItemCollectionType(Type<@SaleItemCollection>()) + } } diff --git a/contracts/FindMetadataFactory.cdc b/contracts/FindMetadataFactory.cdc deleted file mode 100644 index 58abdaa9..00000000 --- a/contracts/FindMetadataFactory.cdc +++ /dev/null @@ -1,133 +0,0 @@ -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import NFTRegistry from "../contracts/NFTRegistry.cdc" -import FindViews from "../contracts/FindViews.cdc" - -pub contract FindMetadataFactory { - - pub struct MetadataCollectionItem { - pub let id:UInt64 - pub let uuid: UInt64 - pub let name: String - pub let image: String - pub let collection: String - // pub let source: String //which alchemy shard or our own Factory - - pub let rarity:String - pub let subCollection: String? // <- This will be Alias unless they want something else - - pub let url: String - pub let contentTypes:[String] - pub let medias: [MetadataViews.Media] - pub let tag: {String : String} - pub let scalar: {String : UFix64} - - init(id:UInt64, type: Type, uuid: UInt64, name:String, image:String, url:String, contentTypes: [String], rarity: String, medias: [MetadataViews.Media], collection: String, subCollection: String?, tag: {String : String}, scalar: {String : UFix64}) { - self.id=id - self.uuid = uuid - self.name=name - self.url=url - self.image=image - self.contentTypes=contentTypes - self.rarity=rarity - self.medias=medias - self.collection=collection - self.tag=tag - self.scalar=scalar - self.subCollection=subCollection - } - } - - pub fun getNFTs(ownerAddress: Address, ids: {String:[UInt64]}): [MetadataCollectionItem] { - let account= getAccount(ownerAddress) - let items : [MetadataCollectionItem] = [] - - - for nftInfo in NFTRegistry.getNFTInfoAll().values { - let resolverCollectionCap= account.getCapability<&{MetadataViews.ResolverCollection}>(nftInfo.publicPath) - if resolverCollectionCap.check() { - continue; - } - let collection = resolverCollectionCap.borrow()! - for id in collection.getIDs() { - let nft = collection.borrowViewResolver(id: id) - - if let display= MetadataViews.getDisplay(nft) { - var externalUrl=nftInfo.externalFixedUrl - - if let externalUrlViw=MetadataViews.getExternalURL(nft) { - externalUrl=externalUrlViw.url - } - - var rarity="" - if let r = FindViews.getRarity(nft) { - rarity=r.rarityName - } - - var tag : {String : String}={} - if let t= FindViews.getTags(nft) { - tag=t.getTag() - } - - var scalar : {String : UFix64}={} - if let s= FindViews.getScalar(nft) { - scalar=s.getScalar() - } - - var medias : [MetadataViews.Media] = [] - if let m= MetadataViews.getMedias(nft) { - medias=m.items - } - - let cotentTypes : [String] = [] - for media in medias { - cotentTypes.append(media.mediaType) - } - - var subCollection : String? = nil - if let sc= MetadataViews.getNFTCollectionDisplay(nft) { - subCollection=sc.name - } - - let item = MetadataCollectionItem( - id: id, - type: nft.getType() , - uuid: nft.uuid , - name: display.name, - image: display.thumbnail.uri(), - url: externalUrl, - contentTypes: cotentTypes, - rarity: rarity, - medias: medias, - collection: nftInfo.alias, - subCollection: subCollection, - tag: tag, - scalar: scalar - ) - items.append(item) - } - } - } - return items - } - - pub fun getNFTIDs(ownerAddress: Address): {String: [UInt64]} { - let account= getAccount(ownerAddress) - let registryData = NFTRegistry.getNFTInfoAll() - - let collections : {String:[UInt64]} ={} - for item in registryData.values { - let optCap = account.getCapability<&{MetadataViews.ResolverCollection}>(item.publicPath) - if !optCap.check() { - continue - } - let col=optCap!.borrow()! - - let ids=col.getIDs() - let alias=item.alias - if ids.length != 0 { - collections[alias]=ids - } - } - return collections - } -} diff --git a/contracts/FindPack.cdc b/contracts/FindPack.cdc index d4feb574..b6dc0bf4 100644 --- a/contracts/FindPack.cdc +++ b/contracts/FindPack.cdc @@ -1,55 +1,54 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" import Crypto -import Clock from "../contracts/Clock.cdc" -import Debug from "./Debug.cdc" -import FLOAT from "../contracts/standard/FLOAT.cdc" -import FindForge from "../contracts/FindForge.cdc" -import FindVerifier from "../contracts/FindVerifier.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" - -pub contract FindPack: NonFungibleToken { +import "Clock" +import "Debug" +import "FindForge" +import "FindVerifier" +import "FINDNFTCatalog" +import "ViewResolver" + +access(all) contract FindPack: NonFungibleToken{ // Events - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id: UInt64, typeId:UInt64) + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Minted(id: UInt64, typeId:UInt64) - pub event Requeued(packId: UInt64, address:Address) + access(all) event Requeued(packId: UInt64, address:Address) - pub event Opened(packTypeName: String, packTypeId:UInt64, packId: UInt64, address:Address, packFields: {String : String}, packNFTTypes: [String]) - pub event Fulfilled(packTypeName: String, packTypeId:UInt64, packId:UInt64, address:Address, packFields: {String : String}, packNFTTypes: [String]) - pub event PackReveal(packTypeName: String, packTypeId:UInt64, packId:UInt64, address:Address, rewardId:UInt64, rewardType:String, rewardFields:{String:String}, packFields: {String : String}, packNFTTypes: [String]) + access(all) event Opened(packTypeName: String, packTypeId:UInt64, packId: UInt64, address:Address, packFields: {String : String}, packNFTTypes: [String]) + access(all) event Fulfilled(packTypeName: String, packTypeId:UInt64, packId:UInt64, address:Address, packFields: {String : String}, packNFTTypes: [String]) + access(all) event PackReveal(packTypeName: String, packTypeId:UInt64, packId:UInt64, address:Address, rewardId:UInt64, rewardType:String, rewardFields:{String:String}, packFields: {String : String}, packNFTTypes: [String]) - pub event Purchased(packTypeName: String, packTypeId: UInt64, packId: UInt64, address: Address, amount:UFix64, packFields: {String : String}, packNFTTypes: [String]) - pub event MetadataRegistered(packTypeName: String, packTypeId: UInt64) - pub event FulfilledError(packTypeName: String, packTypeId: UInt64, packId:UInt64, address:Address?, reason:String) + access(all) event Purchased(packTypeName: String, packTypeId: UInt64, packId: UInt64, address: Address, amount:UFix64, packFields: {String : String}, packNFTTypes: [String]) + access(all) event MetadataRegistered(packTypeName: String, packTypeId: UInt64) + access(all) event FulfilledError(packTypeName: String, packTypeId: UInt64, packId:UInt64, address:Address?, reason:String) - pub let PackMetadataStoragePath: StoragePath + access(all) let PackMetadataStoragePath: StoragePath - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - pub let CollectionPrivatePath: PrivatePath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath - pub let OpenedCollectionPublicPath: PublicPath - pub let OpenedCollectionStoragePath: StoragePath + access(all) let OpenedCollectionPublicPath: PublicPath + access(all) let OpenedCollectionStoragePath: StoragePath + access(all) let DLQCollectionPublicPath: PublicPath + access(all) let DLQCollectionStoragePath: StoragePath - pub let DLQCollectionPublicPath: PublicPath - pub let DLQCollectionStoragePath: StoragePath - - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 // Mapping of packTypeName (which is the find name) : {typeId : Metadata} access(contract) let packMetadata: {String : {UInt64: Metadata}} // this is a struct specific for airdropping packs - pub struct AirdropInfo { - pub let packTypeName: String - pub let packTypeId: UInt64 - pub let users: [String] - pub let message: String + access(all) struct AirdropInfo { + access(all) let packTypeName: String + access(all) let packTypeId: UInt64 + access(all) let users: [String] + + access(all) let message: String init(packTypeName: String , packTypeId: UInt64 , users: [String], message: String){ self.packTypeName = packTypeName @@ -60,26 +59,26 @@ pub contract FindPack: NonFungibleToken { } // this is a struct specific for registering pack metadata - pub struct PackRegisterInfo { - pub let forge: String - pub let name: String - pub let description: String - pub let typeId: UInt64 - pub let externalURL: String - pub let squareImageHash: String - pub let bannerHash: String - pub let socials: {String : String} - pub let paymentAddress: Address - pub let paymentType: String - pub let openTime: UFix64 - pub let packFields: {String : String} - pub let primaryRoyalty: [Royalty] - pub let secondaryRoyalty: [Royalty] - pub let requiresReservation: Bool - pub let nftTypes: [String] - pub let storageRequirement: UInt64 - pub let saleInfo: [PackRegisterSaleInfo] - pub let extra: {String: AnyStruct} + access(all) struct PackRegisterInfo { + access(all) let forge: String + access(all) let name: String + access(all) let description: String + access(all) let typeId: UInt64 + access(all) let externalURL: String + access(all) let squareImageHash: String + access(all) let bannerHash: String + access(all) let socials: {String : String} + access(all) let paymentAddress: Address + access(all) let paymentType: String + access(all) let openTime: UFix64 + access(all) let packFields: {String : String} + access(all) let primaryRoyalty: [Royalty] + access(all) let secondaryRoyalty: [Royalty] + access(all) let requiresReservation: Bool + access(all) let nftTypes: [String] + access(all) let storageRequirement: UInt64 + access(all) let saleInfo: [PackRegisterSaleInfo] + access(all) let extra: {String: AnyStruct} init( forge: String, @@ -122,7 +121,7 @@ pub contract FindPack: NonFungibleToken { self.extra={} } - pub fun generateSaleInfo() : [SaleInfo] { + access(all) fun generateSaleInfo() : [SaleInfo] { let saleInfo : [SaleInfo] = [] for s in self.saleInfo { saleInfo.append(s.generateSaleInfo()) @@ -131,10 +130,10 @@ pub contract FindPack: NonFungibleToken { } } - pub struct Royalty { - pub let recipient: Address - pub let cut: UFix64 - pub let description: String + access(all) struct Royalty { + access(all) let recipient: Address + access(all) let cut: UFix64 + access(all) let description: String access(contract) let extra: {String: AnyStruct} init( @@ -149,12 +148,13 @@ pub contract FindPack: NonFungibleToken { } } - pub struct PackRegisterSaleInfo { - pub let name : String - pub let startTime : UFix64 - pub let price : UFix64 - pub let verifiers : [{FindVerifier.Verifier}] - pub let verifyAll : Bool + access(all) struct PackRegisterSaleInfo { + access(all) let name : String + access(all) let startTime : UFix64 + access(all) let price : UFix64 + //TODO:potential breaking change? + access(all) let verifiers : [{FindVerifier.Verifier}] + access(all) let verifyAll : Bool access(contract) let extra: {String: AnyStruct} init( @@ -173,7 +173,7 @@ pub contract FindPack: NonFungibleToken { self.extra=extra } - pub fun generateSaleInfo() : SaleInfo { + access(all) fun generateSaleInfo() : SaleInfo { var endTime : UFix64? = nil if let et = self.extra["endTime"] { endTime = et as? UFix64 @@ -198,15 +198,15 @@ pub contract FindPack: NonFungibleToken { // Verifier container for packs // Each struct is one sale type. If they - pub struct SaleInfo { - pub let name : String - pub let startTime : UFix64 - pub let endTime : UFix64? - pub let price : UFix64 - pub let purchaseLimit : UInt64? - pub let purchaseRecord : {Address : UInt64} - pub let verifiers : [{FindVerifier.Verifier}] - pub let verifyAll : Bool + access(all) struct SaleInfo { + access(all) let name : String + access(all) let startTime : UFix64 + access(all) let endTime : UFix64? + access(all) let price : UFix64 + access(all) let purchaseLimit : UInt64? + access(all) let purchaseRecord : {Address : UInt64} + access(all) let verifiers : [{FindVerifier.Verifier}] + access(all) let verifyAll : Bool init(name : String, startTime : UFix64 , endTime : UFix64? , price : UFix64, purchaseLimit : UInt64?, verifiers: [{FindVerifier.Verifier}], verifyAll : Bool ) { self.name = name @@ -219,7 +219,7 @@ pub contract FindPack: NonFungibleToken { self.verifyAll = verifyAll } - pub fun inTime(_ time: UFix64) : Bool { + access(all) fun inTime(_ time: UFix64) : Bool { let started = time >= self.startTime if self.endTime == nil { return started @@ -228,7 +228,7 @@ pub contract FindPack: NonFungibleToken { return started && time <= self.endTime! } - pub fun buy(_ addr: Address) { + access(all) fun buy(_ addr: Address) { // If verified false, then panic @@ -243,11 +243,11 @@ pub contract FindPack: NonFungibleToken { self.purchaseRecord[addr] = purchased } - pub fun checkBought(_ addr: Address) : UInt64 { + access(all) fun checkBought(_ addr: Address) : UInt64 { return self.purchaseRecord[addr] ?? 0 } - pub fun checkBuyable(addr: Address, time: UFix64) : Bool { + access(all) fun checkBuyable(addr: Address, time: UFix64) : Bool { // If not in time, return false if !self.inTime(time) { return false @@ -298,11 +298,11 @@ pub contract FindPack: NonFungibleToken { } // Input for minting packs from forge - pub struct MintPackData { - pub let packTypeName: String - pub let typeId: UInt64 - pub let hash: String - pub let verifierRef: &FindForge.Verifier + access(all) struct MintPackData { + access(all) let packTypeName: String + access(all) let typeId: UInt64 + access(all) let hash: String + access(all) let verifierRef: &FindForge.Verifier init(packTypeName: String, typeId: UInt64, hash: String, verifierRef: &FindForge.Verifier) { self.packTypeName = packTypeName @@ -312,43 +312,42 @@ pub contract FindPack: NonFungibleToken { } } - pub struct PackRevealData { - - pub let data: {String:String} + access(all) struct PackRevealData { + access(all) let data: {String:String} init(_ data: {String:String}) { self.data=data } } - pub struct Metadata { - pub let name: String - pub let description: String + access(all) struct Metadata { + access(all) let name: String + access(all) let description: String - pub let thumbnailHash: String? - pub let thumbnailUrl:String? + access(all) let thumbnailHash: String? + access(all) let thumbnailUrl:String? - pub let wallet: Capability<&{FungibleToken.Receiver}> - pub let walletType: Type + access(all) let wallet: Capability<&{FungibleToken.Receiver}> + access(all) let walletType: Type - pub let openTime: UFix64 - pub let saleInfos: [SaleInfo] + access(all) let openTime: UFix64 + access(all) let saleInfos: [SaleInfo] - pub let storageRequirement: UInt64 - pub let collectionDisplay: MetadataViews.NFTCollectionDisplay + access(all) let storageRequirement: UInt64 + access(all) let collectionDisplay: MetadataViews.NFTCollectionDisplay - pub let packFields: {String : String} - pub let extraData : {String : AnyStruct} + access(all) let packFields: {String : String} + access(all) let extraData : {String : AnyStruct} - pub let itemTypes: [Type] - access(contract) let providerCaps: {Type : Capability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}>} + access(all) let itemTypes: [Type] + access(contract) let providerCaps: {Type : Capability} access(contract) let primarySaleRoyalties : MetadataViews.Royalties access(contract) let royalties : MetadataViews.Royalties - pub let requiresReservation: Bool + access(all) let requiresReservation: Bool - init(name: String, description: String, thumbnailUrl: String?,thumbnailHash: String?, wallet: Capability<&{FungibleToken.Receiver}>, openTime:UFix64, walletType:Type, itemTypes: [Type], providerCaps: {Type : Capability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}>} , requiresReservation:Bool, storageRequirement: UInt64, saleInfos: [SaleInfo], primarySaleRoyalties : MetadataViews.Royalties, royalties : MetadataViews.Royalties, collectionDisplay: MetadataViews.NFTCollectionDisplay, packFields: {String : String} , extraData : {String : AnyStruct}) { + init(name: String, description: String, thumbnailUrl: String?,thumbnailHash: String?, wallet: Capability<&{FungibleToken.Receiver}>, openTime:UFix64, walletType:Type, itemTypes: [Type], providerCaps: {Type : Capability} , requiresReservation:Bool, storageRequirement: UInt64, saleInfos: [SaleInfo], primarySaleRoyalties : MetadataViews.Royalties, royalties : MetadataViews.Royalties, collectionDisplay: MetadataViews.NFTCollectionDisplay, packFields: {String : String} , extraData : {String : AnyStruct}) { self.name = name self.description = description self.thumbnailUrl = thumbnailUrl @@ -373,14 +372,14 @@ pub contract FindPack: NonFungibleToken { self.extraData=extraData } - pub fun getThumbnail() : AnyStruct{MetadataViews.File} { + access(all) fun getThumbnail() : {MetadataViews.File} { if let hash = self.thumbnailHash { return MetadataViews.IPFSFile(cid: hash, path: nil) } return MetadataViews.HTTPFile(url:self.thumbnailUrl!) } - pub fun getItemTypesAsStringArray() : [String] { + access(all) fun getItemTypesAsStringArray() : [String] { let types : [String] = [] for t in self.itemTypes { types.append(t.identifier) @@ -388,36 +387,34 @@ pub contract FindPack: NonFungibleToken { return types } - pub fun canBeOpened() : Bool { + access(all) fun canBeOpened() : Bool { return self.openTime <= Clock.time() } access(contract) fun borrowSaleInfo(_ i: Int) : &SaleInfo { - return &self.saleInfos[i] as &FindPack.SaleInfo + return &self.saleInfos[i] } } access(account) fun registerMetadata(packTypeName: String, typeId: UInt64, metadata: Metadata) { emit MetadataRegistered(packTypeName: packTypeName, packTypeId: typeId) - let mapping = self.packMetadata[packTypeName] ?? {} //<- if this is empty then setup the storage slot for this pack type + let mappingMetadata = self.packMetadata[packTypeName] ?? {} //<- if this is empty then setup the storage slot for this pack type // first time we create this type ID, if its not there then we create it. - if mapping[typeId] == nil { + if mappingMetadata[typeId] == nil { let pathIdentifier = self.getPacksCollectionPath(packTypeName: packTypeName, packTypeId: typeId) let storagePath = StoragePath(identifier: pathIdentifier) ?? panic("Cannot create path from identifier : ".concat(pathIdentifier)) let publicPath = PublicPath(identifier: pathIdentifier) ?? panic("Cannot create path from identifier : ".concat(pathIdentifier)) - FindPack.account.save<@NonFungibleToken.Collection>( <- FindPack.createEmptyCollection(), to: storagePath) - FindPack.account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, FindPack.CollectionPublic, MetadataViews.ResolverCollection}>( - publicPath, - target: storagePath - ) + FindPack.account.storage.save<@{NonFungibleToken.Collection}>( <- FindPack.createEmptyCollection(nftType: Type<@FindPack.NFT>()), to: storagePath) + let cap = FindPack.account.capabilities.storage.issue<&FindPack.Collection>(storagePath) + FindPack.account.capabilities.publish(cap, at: publicPath) } - mapping[typeId] = metadata - self.packMetadata[packTypeName] = mapping + mappingMetadata[typeId] = metadata + self.packMetadata[packTypeName] = mappingMetadata } - pub fun getMetadataById(packTypeName: String, typeId: UInt64): Metadata? { + access(all) fun getMetadataById(packTypeName: String, typeId: UInt64): Metadata? { if self.packMetadata[packTypeName] != nil { return self.packMetadata[packTypeName]![typeId] @@ -426,7 +423,7 @@ pub contract FindPack: NonFungibleToken { return nil } - pub fun getMetadataByName(packTypeName: String): {UInt64 : Metadata} { + access(all) fun getMetadataByName(packTypeName: String): {UInt64 : Metadata} { if self.packMetadata[packTypeName] != nil { return self.packMetadata[packTypeName]! @@ -435,10 +432,10 @@ pub contract FindPack: NonFungibleToken { return {} } - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { // The token's ID - pub let id: UInt64 - pub let packTypeName: String + access(all) let id: UInt64 + access(all) let packTypeName: String // The token's typeId access(self) var typeId: UInt64 @@ -461,14 +458,18 @@ pub contract FindPack: NonFungibleToken { self.packTypeName=packTypeName } - pub fun getOpenedBy() : {Type : Capability<&{NonFungibleToken.Receiver}>} { + access(all) view fun getID() : UInt64 { + return self.id + } + + access(all) fun getOpenedBy() : {Type : Capability<&{NonFungibleToken.Receiver}>} { if self.openedBy== nil { panic("Pack is not opened") } - return self.openedBy! + return self.openedBy } - pub fun getHash() : String{ + access(all) fun getHash() : String{ return self.hash } @@ -480,7 +481,7 @@ pub contract FindPack: NonFungibleToken { if self.openedBy.length == 0 { panic("Pack is not opened") } - let cap = self.openedBy! + let cap = self.openedBy self.openedBy={} return cap.values[0].address @@ -493,15 +494,15 @@ pub contract FindPack: NonFungibleToken { self.openedBy=cap } - pub fun getTypeID() :UInt64 { + access(all) fun getTypeID() :UInt64 { return self.typeId } - pub fun getMetadata(): Metadata { + access(all) fun getMetadata(): Metadata { return FindPack.getMetadataById(packTypeName: self.packTypeName, typeId: self.typeId)! } - pub fun getViews(): [Type] { + access(all) view fun getViews(): [Type] { return [ Type(), Type(), @@ -513,7 +514,7 @@ pub contract FindPack: NonFungibleToken { ] } - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) fun resolveView(_ view: Type): AnyStruct? { let metadata = self.getMetadata() switch view { case Type(): @@ -537,75 +538,92 @@ pub contract FindPack: NonFungibleToken { return MetadataViews.Royalties(self.royalties) case Type(): - return MetadataViews.NFTCollectionData( - storagePath: FindPack.CollectionStoragePath, - publicPath: FindPack.CollectionPublicPath, - providerPath: FindPack.CollectionPrivatePath, - publicCollection: Type<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: fun () : @NonFungibleToken.Collection { - return <- FindPack.createEmptyCollection() - } - ) - + return FindPack.resolveContractView(resourceType: nil, viewType: Type()) case Type(): return self.getMetadata().collectionDisplay - - /* to be determined - //let externalURL = MetadataViews.ExternalURL("https://find.xyz/mp/findPack") - let externalURL = MetadataViews.ExternalURL("https://find.xyz/") - let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_images/1467546091780550658/R1uc6dcq_400x400.jpg"), mediaType: "image") - let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1448245049666510848/1652452073/1500x500"), mediaType: "image") - return MetadataViews.NFTCollectionDisplay(name: "find Pack", - description: "Find pack", - externalURL: externalURL, - squareImage: squareImage, - bannerImage: bannerImage, - socials: { - "discord": MetadataViews.ExternalURL("https://discord.gg/ejdVgzWmYN"), - "twitter" : MetadataViews.ExternalURL("https://twitter.com/findonflow") - }) - */ } return nil } + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create Collection() + } + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] } - pub resource interface CollectionPublic { - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun contains(_ id: UInt64): Bool - pub fun getPacksLeft() : Int // returns the no of a type - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowFindPack(id: UInt64): &FindPack.NFT? - pub fun buyWithSignature(packId: UInt64, signature:String, vault: @FungibleToken.Vault, collectionCapability: Capability<&Collection{NonFungibleToken.Receiver}>) - pub fun buy(packTypeName: String, typeId: UInt64, vault: @FungibleToken.Vault, collectionCapability: Capability<&Collection{NonFungibleToken.Receiver}>) + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return MetadataViews.NFTCollectionDisplay( + name: "Find Pack", + description: "A generic find pack that can contain lots of stuff", + externalURL: MetadataViews.ExternalURL("http://find.xyz"), + squareImage: MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_images/1467546091780550658/R1uc6dcq_400x400.jpg") , mediaType: "image"), + bannerImage: MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1448245049666510848/1652452073/1500x500") , mediaType: "image"), + socials: { + "Twitter" : MetadataViews.ExternalURL("https://twitter.com/findonflow") , + "Discord" : MetadataViews.ExternalURL("https://discord.gg/95P274mayM") + } + ) + + + case Type(): + let collectionData = MetadataViews.NFTCollectionData( + storagePath: FindPack.CollectionStoragePath, + publicPath: FindPack.CollectionPublicPath, + publicCollection: Type<&FindPack.Collection>(), + publicLinkedType: Type<&FindPack.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-FindPack.createEmptyCollection(nftType: Type<@FindPack.NFT>()) + }) + ) + return collectionData + } + return nil + } + + access(all) resource interface CollectionPublic { + access(all) fun deposit(token: @{NonFungibleToken.NFT}) + access(all) view fun getIDs(): [UInt64] + access(all) fun contains(_ id: UInt64): Bool + access(all) fun getPacksLeft() : Int // returns the no of a type + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? + access(all) fun borrowFindPack(id: UInt64): &FindPack.NFT? + access(all) fun buyWithSignature(packId: UInt64, signature:String, vault: @{FungibleToken.Vault}, collectionCapability: Capability<&Collection>) + access(all) fun buy(packTypeName: String, typeId: UInt64, vault: @{FungibleToken.Vault}, collectionCapability: Capability<&Collection>) } + access(all) entitlement Owner + // Collection // A collection of FindPack NFTs owned by an account // - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, CollectionPublic, MetadataViews.ResolverCollection { + access(all) resource Collection: NonFungibleToken.Collection, CollectionPublic, ViewResolver.ResolverCollection { // dictionary of NFT conforming tokens // NFT is a resource type with an `UInt64` ID field // - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} //this has to be called on the DLQ collection - pub fun requeue(packId:UInt64) { + access(Owner) fun requeue(packId:UInt64) { let token <- self.withdraw(withdrawID: packId) as! @NFT let address=token.resetOpenedBy() - let cap=getAccount(address).getCapability<&Collection{NonFungibleToken.Receiver}>(FindPack.CollectionPublicPath) + let cap=getAccount(address).capabilities.get<&Collection>(FindPack.CollectionPublicPath) let receiver = cap.borrow()! receiver.deposit(token: <- token) emit Requeued(packId:packId, address: cap.address) } - pub fun open(packId: UInt64, receiverCap: {Type : Capability<&{NonFungibleToken.Receiver}>}) { + access(Owner) fun open(packId: UInt64, receiverCap: {Type : Capability<&{NonFungibleToken.Receiver}>}) { for cap in receiverCap.values { if !cap.check() { panic("Receiver cap is not valid") @@ -621,7 +639,7 @@ pub contract FindPack: NonFungibleToken { token.setOpenedBy(receiverCap) // establish the receiver for Redeeming FindPack - let receiver = FindPack.account.getCapability<&{NonFungibleToken.Receiver}>(FindPack.OpenedCollectionPublicPath).borrow()! + let receiver = FindPack.account.capabilities.get<&{NonFungibleToken.Receiver}>(FindPack.OpenedCollectionPublicPath).borrow()! let typeId=token.getTypeID() let packTypeName=token.packTypeName @@ -635,7 +653,7 @@ pub contract FindPack: NonFungibleToken { emit Opened(packTypeName: packTypeName, packTypeId:typeId, packId: packId, address:self.owner!.address, packFields:packFields, packNFTTypes:packNFTTypes) } - pub fun buyWithSignature(packId: UInt64, signature:String, vault: @FungibleToken.Vault, collectionCapability: Capability<&Collection{NonFungibleToken.Receiver}>) { + access(all) fun buyWithSignature(packId: UInt64, signature:String, vault: @{FungibleToken.Vault}, collectionCapability: Capability<&Collection>) { pre { self.owner!.address == FindPack.account.address : "You can only buy pack directly from the FindPack account" } @@ -698,7 +716,7 @@ pub contract FindPack: NonFungibleToken { // Verifies that the signature is valid and that it was generated from the // owner of the collection - if(!keyList.verify(signatureSet: signatureSet, signedData: nft.hash.utf8)){ + if(!keyList.verify(signatureSet: signatureSet, signedData: nft.hash.utf8, domainSeparationTag: "FLOW-V0.0-user")){ panic("Unable to validate the signature for the pack!") } @@ -713,7 +731,7 @@ pub contract FindPack: NonFungibleToken { } } - let wallet = getAccount(FindPack.account.address).getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let wallet = getAccount(FindPack.account.address).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) if wallet.check() { let r = MetadataViews.Royalty(receiver: wallet, cut: 0.15, description: ".find") r.receiver.borrow()!.deposit(from: <- vault.withdraw(amount: saleInfo!.price * r.cut)) @@ -728,7 +746,7 @@ pub contract FindPack: NonFungibleToken { emit Purchased(packTypeName: packTypeName, packTypeId: packTypeId, packId: packId, address: collectionCapability.address, amount:saleInfo!.price, packFields:packFields, packNFTTypes:packNFTTypes) } - pub fun buy(packTypeName: String, typeId: UInt64, vault: @FungibleToken.Vault, collectionCapability: Capability<&Collection{NonFungibleToken.Receiver}>) { + access(all) fun buy(packTypeName: String, typeId: UInt64, vault: @{FungibleToken.Vault}, collectionCapability: Capability<&Collection>) { pre { self.owner!.address == FindPack.account.address : "You can only buy pack directly from the FindPack account" } @@ -755,8 +773,8 @@ pub contract FindPack: NonFungibleToken { for i, info in metadata.saleInfos { // for later implement : if it requires all sale info checks if info.checkBuyable(addr: collectionCapability.address, time:timestamp) { - if lowestPrice == nil || lowestPrice! > info!.price { - lowestPrice = info!.price + if lowestPrice == nil || lowestPrice! > info.price { + lowestPrice = info.price saleInfo = info saleInfoIndex = i } @@ -787,7 +805,7 @@ pub contract FindPack: NonFungibleToken { //TODO: REMOVE THIS if !royaltiesPaid { - let wallet = getAccount(FindPack.account.address).getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let wallet = getAccount(FindPack.account.address).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) if wallet.check() { let r = MetadataViews.Royalty(receiver: wallet, cut: 0.10, description: ".find") r.receiver.borrow()!.deposit(from: <- vault.withdraw(amount: saleInfo!.price * r.cut)) @@ -809,7 +827,7 @@ pub contract FindPack: NonFungibleToken { // withdraw // Removes an NFT from the collection and moves it to the caller // - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Could not withdraw nft") let nft <- token as! @NFT @@ -819,11 +837,32 @@ pub contract FindPack: NonFungibleToken { return <-nft } + access(all) view fun getIDsWithTypes(): {Type: [UInt64]} { + return {} + } + + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + return {} + } + + + access(all) view fun isSupportedNFTType(type: Type) : Bool { + return type == Type<@FindPack.NFT>() + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create Collection() + } + + access(all) view fun getLength() : Int { + return self.ownedNFTs.length + } + // deposit // Takes a NFT and adds it to the collections dictionary // and adds the ID to the id array // - pub fun deposit(token: @NonFungibleToken.NFT) { + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { let token <- token as! @FindPack.NFT let id: UInt64 = token.id @@ -840,25 +879,24 @@ pub contract FindPack: NonFungibleToken { // getIDs // Returns an array of the IDs that are in the collection // - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } - pub fun contains(_ id: UInt64) : Bool { + access(all) fun contains(_ id: UInt64) : Bool { return self.ownedNFTs.containsKey(id) } //return the number of packs left of a type - pub fun getPacksLeft() : Int { + access(all) fun getPacksLeft() : Int { return self.ownedNFTs.length } // borrowNFT // Gets a reference to an NFT in the collection // so that the caller can read its metadata and call its methods - // - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] } // borrowFindPack @@ -866,25 +904,30 @@ pub contract FindPack: NonFungibleToken { // exposing all of its fields. // This is safe as there are no functions that can be called on the FindPack. // - pub fun borrowFindPack(id: UInt64): &FindPack.NFT? { + access(all) fun borrowFindPack(id: UInt64): &FindPack.NFT? { if self.ownedNFTs[id] != nil { - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)! return ref as! &FindPack.NFT } else { return nil } } - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let exampleNFT = nft as! &NFT - return exampleNFT + + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? { + if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? { + return nft as &{ViewResolver.Resolver} + } + return nil + } + + + access(all) view fun getDefaultStoragePath() : StoragePath { + return FindPack.CollectionStoragePath } - // destructor - // - destroy() { - destroy self.ownedNFTs + access(all) view fun getDefaultPublicPath() : PublicPath { + return FindPack.CollectionPublicPath } // initializer @@ -894,11 +937,7 @@ pub contract FindPack: NonFungibleToken { } } - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } - - access(account) fun mintNFT(packTypeName: String, typeId: UInt64, hash: String, royalties: [MetadataViews.Royalty]) : @NonFungibleToken.NFT { + access(account) fun mintNFT(packTypeName: String, typeId: UInt64, hash: String, royalties: [MetadataViews.Royalty]) : @{NonFungibleToken.NFT} { let nft <- create FindPack.NFT(packTypeName: packTypeName, typeId: typeId, hash:hash, royalties:royalties) emit Minted(id: nft.id, typeId:typeId) @@ -909,7 +948,7 @@ pub contract FindPack: NonFungibleToken { access(account) fun fulfill(packId: UInt64, types:[Type], rewardIds: [UInt64], salt:String) { - let openedPacksCollection = FindPack.account.borrow<&FindPack.Collection>(from: FindPack.OpenedCollectionStoragePath)! + let openedPacksCollection = FindPack.account.storage.borrow(from: FindPack.OpenedCollectionStoragePath)! let pack <- openedPacksCollection.withdraw(withdrawID: packId) as! @FindPack.NFT let packTypeName = pack.packTypeName let packTypeId = pack.getTypeID() @@ -924,10 +963,10 @@ pub contract FindPack: NonFungibleToken { let rewards=pack.getMetadata().providerCaps let receiverAccount=getAccount(receivingAddress) - var freeStorage=UInt64(0) + var freeStorage=0 as UInt64 // prevent underflow - if receiverAccount.storageCapacity >= receiverAccount.storageUsed { - freeStorage = receiverAccount.storageCapacity - receiverAccount.storageUsed + if receiverAccount.storage.capacity >= receiverAccount.storage.used { + freeStorage = receiverAccount.storage.capacity- receiverAccount.storage.used } Debug.log("Free capacity from account ".concat(freeStorage.toString())) if pack.getMetadata().storageRequirement > freeStorage { @@ -948,6 +987,7 @@ pub contract FindPack: NonFungibleToken { } if !rewards[type]!.check() { + Debug.log("type that is not present in rewards cap ".concat(type.identifier)) emit FulfilledError(packTypeName: packTypeName, packTypeId: packTypeId, packId:packId, address:receiver[type]!.address, reason: "Cannot borrow provider capability to withdraw nfts") self.transferToDLQ(<- pack) return @@ -975,7 +1015,7 @@ pub contract FindPack: NonFungibleToken { let source=rewards[type]!.borrow()! let viewType= Type() - let nft=source.borrowViewResolver(id: id) + let nft=source.borrowViewResolver(id: id)! var fields : {String: String}= {} if nft.getViews().contains(viewType) { @@ -1006,13 +1046,13 @@ pub contract FindPack: NonFungibleToken { ) target.deposit(token: <-token) } - emit Fulfilled(packTypeName: packTypeName, packTypeId: packTypeId, packId:packId, address:receivingAddress!, packFields:packFields, packNFTTypes:packNFTTypes) + emit Fulfilled(packTypeName: packTypeName, packTypeId: packTypeId, packId:packId, address:receivingAddress, packFields:packFields, packNFTTypes:packNFTTypes) destroy pack } access(account) fun transferToDLQ(_ pack: @NFT) { - let dlq = FindPack.account.borrow<&FindPack.Collection>(from: FindPack.DLQCollectionStoragePath)! + let dlq = FindPack.account.storage.borrow<&FindPack.Collection>(from: FindPack.DLQCollectionStoragePath)! dlq.deposit(token: <- pack) } @@ -1020,26 +1060,26 @@ pub contract FindPack: NonFungibleToken { return "FindPack_".concat(packTypeName).concat("_").concat(packTypeId.toString()) } - pub fun getPacksCollection(packTypeName: String, packTypeId: UInt64) : &FindPack.Collection{CollectionPublic} { + access(all) fun getPacksCollection(packTypeName: String, packTypeId: UInt64) : &FindPack.Collection { let pathIdentifier = self.getPacksCollectionPath(packTypeName: packTypeName, packTypeId: packTypeId) let path = PublicPath(identifier: pathIdentifier) ?? panic("Cannot create path from identifier : ".concat(pathIdentifier)) - return FindPack.account.getCapability<&FindPack.Collection{FindPack.CollectionPublic}>(path).borrow() ?? panic("Could not borow FindPack collection for path : ".concat(pathIdentifier)) + return FindPack.account.capabilities.get<&FindPack.Collection>(path).borrow() ?? panic("Could not borow FindPack collection for path : ".concat(pathIdentifier)) } // given a path, lookin to the NFT Collection and return a new empty collection - pub fun createEmptyCollectionFromPackData(packData: FindPack.Metadata, type: Type) : @NonFungibleToken.Collection { + access(all) fun createEmptyCollectionFromPackData(packData: FindPack.Metadata, type: Type) : @{NonFungibleToken.Collection} { let cap = packData.providerCaps[type] ?? panic("Type passed in does not exist in this pack ".concat(type.identifier)) if !cap.check() { panic("Provider capability of pack is not valid Name and ID".concat(type.identifier)) } let ref = cap.borrow()! - let resolver = ref.borrowViewResolver(id : ref.getIDs()[0]) // if the ID length is 0, there must be some problem + let resolver = ref.borrowViewResolver(id: ref.getIDs()[0])! // if the ID length is 0, there must be some problem let collectionData = MetadataViews.getNFTCollectionData(resolver) ?? panic("Collection Data for this NFT Type is missing. Type : ".concat(resolver.getType().identifier)) return <- collectionData.createEmptyCollection() } - pub fun canBuy(packTypeName: String, packTypeId:UInt64, user:Address) : Bool { + access(all) fun canBuy(packTypeName: String, packTypeId:UInt64, user:Address) : Bool { let packs=FindPack.getPacksCollection(packTypeName: packTypeName, packTypeId:packTypeId) @@ -1066,7 +1106,7 @@ pub contract FindPack: NonFungibleToken { return false } - pub fun getCurrentPrice(packTypeName: String, packTypeId:UInt64, user:Address) : UFix64? { + access(all) fun getCurrentPrice(packTypeName: String, packTypeId:UInt64, user:Address) : UFix64? { let packs=FindPack.getPacksCollection(packTypeName: packTypeName, packTypeId:packTypeId) @@ -1087,8 +1127,8 @@ pub contract FindPack: NonFungibleToken { var lowestPrice : UFix64? = nil for info in metadata.saleInfos { if info.checkBuyable(addr: user, time:timestamp) { - if lowestPrice == nil || lowestPrice! > info!.price { - lowestPrice = info!.price + if lowestPrice == nil || lowestPrice! > info.price { + lowestPrice = info.price } } } @@ -1098,16 +1138,16 @@ pub contract FindPack: NonFungibleToken { access(contract) fun borrowSaleInfo(packTypeName: String, packTypeId: UInt64, index: Int) : &FindPack.SaleInfo { let mappingRef = (&FindPack.packMetadata[packTypeName] as &{UInt64: FindPack.Metadata}?)! - let ref = (&mappingRef[packTypeId] as &FindPack.Metadata?)! + let ref = mappingRef[packTypeId]! return ref.borrowSaleInfo(index) } - pub fun getOwnerCollection() : Capability<&FindPack.Collection{MetadataViews.ResolverCollection}> { - return FindPack.account.getCapability<&FindPack.Collection{MetadataViews.ResolverCollection}>(FindPack.CollectionPublicPath) + access(all) fun getOwnerCollection() : Capability<&FindPack.Collection> { + return FindPack.account.capabilities.get<&FindPack.Collection>(FindPack.CollectionPublicPath) } - pub resource Forge: FindForge.Forge { - pub fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @NonFungibleToken.NFT { + access(all) resource Forge: FindForge.Forge { + access(FindForge.ForgeOwner) fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @{NonFungibleToken.NFT} { let royalties : [MetadataViews.Royalty] = [] // there should be no find cut for the pack. @@ -1118,7 +1158,7 @@ pub contract FindPack: NonFungibleToken { return <- FindPack.mintNFT(packTypeName: platform.name, typeId: input.typeId , hash: input.hash, royalties: royalties) } - pub fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { + access(FindForge.ForgeOwner) fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { let type = data.getType() switch type { @@ -1139,12 +1179,15 @@ pub contract FindPack: NonFungibleToken { return <- create Forge() } + access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} { + + return <- create Collection() + } // initializer // init() { self.CollectionStoragePath = /storage/FindPackCollection self.CollectionPublicPath = /public/FindPackCollection - self.CollectionPrivatePath = /private/FindPackCollection self.OpenedCollectionStoragePath = /storage/FindPackOpenedCollection self.OpenedCollectionPublicPath = /public/FindPackOpenedCollection @@ -1161,14 +1204,15 @@ pub contract FindPack: NonFungibleToken { // this contract will hold a Collection that FindPack can be deposited to and Admins can Consume them to transfer nfts to the depositing account let openedCollection <- create Collection() - self.account.save(<- openedCollection, to: self.OpenedCollectionStoragePath) - self.account.link<&FindPack.Collection{NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, FindPack.CollectionPublic, MetadataViews.ResolverCollection}>(FindPack.OpenedCollectionPublicPath, target: FindPack.OpenedCollectionStoragePath) - + self.account.storage.save(<- openedCollection, to: self.OpenedCollectionStoragePath) + let cap = self.account.capabilities.storage.issue<&Collection>(self.OpenedCollectionStoragePath) + self.account.capabilities.publish(cap, at: self.OpenedCollectionPublicPath) //a DLQ storage slot so that the opener can put items that cannot be opened/transferred here. let dlqCollection <- create Collection() - self.account.save(<- dlqCollection, to: self.DLQCollectionStoragePath) - self.account.link<&FindPack.Collection{NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, FindPack.CollectionPublic, MetadataViews.ResolverCollection}>(FindPack.DLQCollectionPublicPath, target: FindPack.DLQCollectionStoragePath) + self.account.storage.save(<- dlqCollection, to: self.DLQCollectionStoragePath) + let dlqCap = self.account.capabilities.storage.issue<&Collection>(self.DLQCollectionStoragePath) + self.account.capabilities.publish(dlqCap, at: self.DLQCollectionPublicPath) FindForge.addForgeType(<- create Forge()) @@ -1176,7 +1220,6 @@ pub contract FindPack: NonFungibleToken { FindForge.addPublicForgeType(forgeType: Type<@Forge>()) emit ContractInitialized() - } } diff --git a/contracts/FindRelatedAccounts.cdc b/contracts/FindRelatedAccounts.cdc index d573a1bc..229ff098 100644 --- a/contracts/FindRelatedAccounts.cdc +++ b/contracts/FindRelatedAccounts.cdc @@ -1,258 +1,264 @@ -pub contract FindRelatedAccounts { - - pub let storagePath: StoragePath - pub let publicPath: PublicPath - - pub event RelatedAccount(user: Address, walletId: String, walletName: String, address: String, network: String, action: String) - - pub struct AccountInformation{ - pub let name:String - pub let address:Address? - pub let network:String //do not use enum because of contract upgrade - pub let stringAddress: String //other networks besides flow may be not support Address, duplication of flow address in string - pub let extra: {String : AnyStruct} - - init(name:String, address:Address?, network:String, otherAddress:String?){ - pre{ - address == nil && otherAddress != nil || address != nil && otherAddress == nil : "Please put either flow address or other address for account" - } - self.name=name - self.address=address - self.network=network - self.stringAddress=otherAddress ?? address!.toString() - self.extra={} - } - } - - pub resource interface Public{ - pub fun getFlowAccounts() : {String: [Address]} - pub fun getRelatedAccounts(_ network: String) : {String : [String]} - pub fun getAllRelatedAccounts() : {String : {String : [String]}} - pub fun getAllRelatedAccountInfo() : {String : AccountInformation} - // verify ensure this wallet address exist under the network - pub fun verify(network: String, address: String) : Bool - // linked ensure this wallet is linked in both wallet with the same name (but not socially linked only) - // only supports flow for now - pub fun linked(name: String, network: String, address: Address) : Bool - pub fun getAccount(name: String, network: String, address: String) : AccountInformation? - } - - /// This is just an empty resource we create in storage, you can safely send a reference to it to obtain msg.sender - pub resource Accounts: Public { - - // { ETH : ETH_Blocto } - access(self) let networks: {String : [String]} - // { ETH_Blocto : [Address] } - access(self) let wallets : {String : [String]} - // { ETH_Blocto_Address : AccountInformation } - access(self) let accounts : {String : AccountInformation} - - init() { - self.networks={} - self.wallets={} - self.accounts={} - } - - pub fun linked(name: String, network: String, address: Address) : Bool { - let cap = FindRelatedAccounts.getCapability(address) - if cap.check() { - if let acct = cap.borrow()!.getAccount(name: name, network: network, address: self.owner!.address.toString()) { - return true - } - } - return false - } - - pub fun verify(network: String, address: String) : Bool { - if let wallets = self.networks[network] { - for wallet in wallets { - let ws = self.wallets[wallet]! - for candiidate in ws { - if candiidate.toLower() == address.toLower() { - return true - } - } - } - } - return false - } - - pub fun getFlowAccounts() : {String: [Address]} { - let network = "Flow" - let tempItems : {String: [Address]} ={} - if let wallets = self.networks[network] { - for wallet in wallets { - let ws = self.wallets[wallet]! - for addr in ws { - let id = wallet.concat("_").concat(addr) - let info = self.accounts[id]! - - let tempArray = tempItems[wallet] ?? [] - tempArray.append(info.address!) - tempItems[wallet] = tempArray - } - } - } - return tempItems - } - - pub fun getRelatedAccounts(_ network: String) : {String : [String]} { - return self.internal_getRelatedAccounts(network)[network] ?? {} - } - - pub fun getAllRelatedAccounts() : {String : {String : [String]}} { - return self.internal_getRelatedAccounts(nil) - } - - pub fun getAllRelatedAccountInfo() : {String : AccountInformation} { - return self.accounts - } - - pub fun getAccount(name: String, network: String, address: String) : AccountInformation? { - let id = FindRelatedAccounts.getIdentifier(name: name, network: network, address: address) - return self.accounts[id] - } - - access(contract) fun internal_getRelatedAccounts(_ network: String?) : {String : {String : [String]}} { - - var isNil = network == nil - - fun wanted(_ n: String) : Bool { - if network! == n { - return true - } - return false - } - - var tempRes : {String : {String : [String]}} = {} - for n in self.networks.keys { - if !isNil && !wanted(n) { - continue - } - let tempItems : {String: [String]} = tempRes[n] ?? {} - if let wallets = self.networks[n] { - for wallet in wallets { - let ws = self.wallets[wallet]! - let tempArray = tempItems[wallet] ?? [] - tempArray.appendAll(ws) - tempItems[wallet] = tempArray - } - } - tempRes[n] = tempItems - } - return tempRes - } - - pub fun addFlowAccount(name: String, address:Address) { - let network = "Flow" - let id = FindRelatedAccounts.getIdentifier(name: name, network: network, address: address.toString()) - if self.accounts[id] != nil { - return - } - self.internal_add(id: id, acct: AccountInformation(name: name, address:address, network: network, otherAddress:nil)) - emit RelatedAccount(user: self.owner!.address, walletId: id, walletName: name, address: address.toString(), network: network, action: "add") - } - - pub fun addRelatedAccount(name: String, network: String, address: String) { - let id = FindRelatedAccounts.getIdentifier(name: name, network: network, address: address) - if self.accounts[id] != nil { - return - } - self.internal_add(id: id, acct: AccountInformation(name: name, address:nil, network: network, otherAddress:address)) - emit RelatedAccount(user: self.owner!.address, walletId: id, walletName: name, address: address, network: network, action: "add") - } - - pub fun updateFlowAccount(name: String, oldAddress: Address, address:Address) { - self.removeRelatedAccount(name: name, network: "Flow", address: oldAddress.toString()) - self.addFlowAccount(name: name, address: address) - } - - pub fun updateRelatedAccount(name: String, network: String, oldAddress: String, address: String) { - self.removeRelatedAccount(name: name, network: network, address: oldAddress) - self.addRelatedAccount(name: name, network: network, address: address) - } - - pub fun removeRelatedAccount(name: String, network: String, address: String) { - let id = FindRelatedAccounts.getIdentifier(name: name, network: network, address: address) - if self.accounts[id] == nil { - panic(network.concat(" address is not added as related account : ").concat(address)) - } - self.internal_remove(id: id) - emit RelatedAccount(user: self.owner!.address, walletId: id, walletName: name, address: address, network: network, action: "remove") - } - - access(contract) fun internal_add(id: String, acct: AccountInformation) { - let walletName = acct.network.concat("_").concat(acct.name) - let tempNetworks = self.networks[acct.network] ?? [] - if !tempNetworks.contains(walletName) { - tempNetworks.append(walletName) - self.networks[acct.network] = tempNetworks - } - - let tempWallets = self.wallets[walletName] ?? [] - tempWallets.append(acct.stringAddress) - self.wallets[walletName] = tempWallets - - self.accounts[id] = acct - } - - access(contract) fun internal_remove(id: String) { - let acct = self.accounts.remove(key: id)! - - let walletName = acct.network.concat("_").concat(acct.name) - let tempWallets = self.wallets[walletName]! - tempWallets.remove(at: tempWallets.firstIndex(of: acct.stringAddress)!) - if tempWallets.length > 0 { - self.wallets[walletName] = tempWallets - return - } - self.wallets.remove(key: walletName) - - let tempNetwork = self.networks[acct.network]! - tempNetwork.remove(at: tempNetwork.firstIndex(of: walletName)!) - if tempNetwork.length > 0 { - self.networks[acct.network] = tempNetwork - return - } - self.networks.remove(key: acct.network) - } - } - - pub fun createEmptyAccounts() : @Accounts{ - return <- create Accounts() - } - - pub fun getIdentifier(name: String, network: String, address: String) : String { - return network.concat("_").concat(name).concat("_").concat(address) - } - - pub fun getCapability(_ addr: Address) : Capability<&Accounts{Public}> { - return getAccount(addr).getCapability<&Accounts{Public}>(self.publicPath) - - } - - pub fun findRelatedFlowAccounts(address:Address) : {String: [Address]} { - let cap = self.getCapability(address) - if !cap.check(){ - return {} - } - - return cap.borrow()!.getFlowAccounts() - } - - pub fun findRelatedAccounts(address:Address) : {String: {String: [String]}} { - let cap = self.getCapability(address) - if !cap.check(){ - return {} - } - - return cap.borrow()!.getAllRelatedAccounts() - } - - init() { - - self.storagePath = /storage/findRelatedAccounts - self.publicPath = /public/findRelatedAccounts - } +access(all) contract FindRelatedAccounts { + // Entitlements + access(all) entitlement Owner + + // Paths + access(all) let storagePath: StoragePath + access(all) let publicPath: PublicPath + + // Events + access(all) event RelatedAccount(user: Address, walletId: String, walletName: String, address: String, network: String, action: String) + + access(all) struct AccountInformation{ + access(all) let name:String + access(all) let address:Address? + access(all) let network:String //do not use enum because of contract upgrade + access(all) let stringAddress: String //other networks besides flow may be not support Address, duplication of flow address in string + access(all) let extra: {String : AnyStruct} + + init(name:String, address:Address?, network:String, otherAddress:String?){ + pre{ + address == nil && otherAddress != nil || address != nil && otherAddress == nil : "Please put either flow address or other address for account" + } + self.name=name + self.address=address + self.network=network + self.stringAddress=otherAddress ?? address!.toString() + self.extra={} + } + } + + access(all) resource interface Public{ + access(all) fun getFlowAccounts() : {String: [Address]} + access(all) fun getRelatedAccounts(_ network: String) : {String : [String]} + access(all) fun getAllRelatedAccounts() : {String : {String : [String]}} + access(all) fun getAllRelatedAccountInfo() : {String : AccountInformation} + // verify enfun sure this wallet address exist under the network + access(all) fun verify(network: String, address: String) : Bool + // linked enfun sure this wallet is linked in both wallet with the same name (but not socially linked only) + // only suppfun orts flow for now + access(all) fun linked(name: String, network: String, address: Address) : Bool + access(all) fun getAccount(name: String, network: String, address: String) : AccountInformation? + } + + /// This is just an empty resource we create in storage, you can safely send a reference to it to obtain msg.sender + access(all) resource Accounts: Public { + + // { ETH : ETH_Blocto } + access(self) let networks: {String : [String]} + // { ETH_Blocto : [Address] } + access(self) let wallets : {String : [String]} + // { ETH_Blocto_Address : AccountInformation } + access(self) let accounts : {String : AccountInformation} + + init() { + self.networks={} + self.wallets={} + self.accounts={} + } + + access(all) fun linked(name: String, network: String, address: Address) : Bool { + if let cap = FindRelatedAccounts.getCapability(address) { + if let acct = cap.borrow()!.getAccount(name: name, network: network, address: self.owner!.address.toString()) { + return true + } + } + return false + } + + access(all) fun verify(network: String, address: String) : Bool { + if let wallets = self.networks[network] { + for wallet in wallets { + let ws = self.wallets[wallet]! + for candiidate in ws { + if candiidate.toLower() == address.toLower() { + return true + } + } + } + } + return false + } + + access(all) fun getFlowAccounts() : {String: [Address]} { + let network = "Flow" + let tempItems : {String: [Address]} ={} + if let wallets = self.networks[network] { + for wallet in wallets { + let ws = self.wallets[wallet]! + for addr in ws { + let id = wallet.concat("_").concat(addr) + let info = self.accounts[id]! + + let tempArray = tempItems[wallet] ?? [] + tempArray.append(info.address!) + tempItems[wallet] = tempArray + } + } + } + return tempItems + } + + access(all) fun getRelatedAccounts(_ network: String) : {String : [String]} { + return self.internal_getRelatedAccounts(network)[network] ?? {} + } + + access(all) fun getAllRelatedAccounts() : {String : {String : [String]}} { + return self.internal_getRelatedAccounts(nil) + } + + access(all) fun getAllRelatedAccountInfo() : {String : AccountInformation} { + return self.accounts + } + + access(all) fun getAccount(name: String, network: String, address: String) : AccountInformation? { + let id = FindRelatedAccounts.getIdentifier(name: name, network: network, address: address) + return self.accounts[id] + } + + access(contract) fun internal_getRelatedAccounts(_ network: String?) : {String : {String : [String]}} { + + var isNil = network == nil + + fun wanted(_ n: String) : Bool { + if network! == n { + return true + } + return false + } + + var tempRes : {String : {String : [String]}} = {} + for n in self.networks.keys { + if !isNil && !wanted(n) { + continue + } + let tempItems : {String: [String]} = tempRes[n] ?? {} + if let wallets = self.networks[n] { + for wallet in wallets { + let ws = self.wallets[wallet]! + let tempArray = tempItems[wallet] ?? [] + tempArray.appendAll(ws) + tempItems[wallet] = tempArray + } + } + tempRes[n] = tempItems + } + return tempRes + } + + access(Owner) fun addFlowAccount(name: String, address:Address) { + let network = "Flow" + let id = FindRelatedAccounts.getIdentifier(name: name, network: network, address: address.toString()) + if self.accounts[id] != nil { + return + } + self.internal_add(id: id, acct: AccountInformation(name: name, address:address, network: network, otherAddress:nil)) + emit RelatedAccount(user: self.owner!.address, walletId: id, walletName: name, address: address.toString(), network: network, action: "add") + } + + access(Owner) fun addRelatedAccount(name: String, network: String, address: String) { + let id = FindRelatedAccounts.getIdentifier(name: name, network: network, address: address) + if self.accounts[id] != nil { + return + } + self.internal_add(id: id, acct: AccountInformation(name: name, address:nil, network: network, otherAddress:address)) + emit RelatedAccount(user: self.owner!.address, walletId: id, walletName: name, address: address, network: network, action: "add") + } + + access(Owner) fun updateFlowAccount(name: String, oldAddress: Address, address:Address) { + self.removeRelatedAccount(name: name, network: "Flow", address: oldAddress.toString()) + self.addFlowAccount(name: name, address: address) + } + + access(Owner) fun updateRelatedAccount(name: String, network: String, oldAddress: String, address: String) { + self.removeRelatedAccount(name: name, network: network, address: oldAddress) + self.addRelatedAccount(name: name, network: network, address: address) + } + + access(Owner) fun removeRelatedAccount(name: String, network: String, address: String) { + let id = FindRelatedAccounts.getIdentifier(name: name, network: network, address: address) + if self.accounts[id] == nil { + panic(network.concat(" address is not added as related account : ").concat(address)) + } + self.internal_remove(id: id) + emit RelatedAccount(user: self.owner!.address, walletId: id, walletName: name, address: address, network: network, action: "remove") + } + + access(contract) fun internal_add(id: String, acct: AccountInformation) { + let walletName = acct.network.concat("_").concat(acct.name) + let tempNetworks = self.networks[acct.network] ?? [] + if !tempNetworks.contains(walletName) { + tempNetworks.append(walletName) + self.networks[acct.network] = tempNetworks + } + + let tempWallets = self.wallets[walletName] ?? [] + tempWallets.append(acct.stringAddress) + self.wallets[walletName] = tempWallets + + self.accounts[id] = acct + } + + access(contract) fun internal_remove(id: String) { + let acct = self.accounts.remove(key: id)! + + let walletName = acct.network.concat("_").concat(acct.name) + let tempWallets = self.wallets[walletName]! + tempWallets.remove(at: tempWallets.firstIndex(of: acct.stringAddress)!) + if tempWallets.length > 0 { + self.wallets[walletName] = tempWallets + return + } + self.wallets.remove(key: walletName) + + let tempNetwork = self.networks[acct.network]! + tempNetwork.remove(at: tempNetwork.firstIndex(of: walletName)!) + if tempNetwork.length > 0 { + self.networks[acct.network] = tempNetwork + return + } + self.networks.remove(key: acct.network) + } + } + + access(all) fun createEmptyAccounts() : @Accounts{ + return <- create Accounts() + } + + access(all) fun getIdentifier(name: String, network: String, address: String) : String { + return network.concat("_").concat(name).concat("_").concat(address) + } + + access(all) fun getCapability(_ addr: Address) : Capability<&{Public}>? { + let cap = getAccount(addr).capabilities.get<&{Public}>(self.publicPath) + if !cap.check() { + return nil + } + return cap + + } + + access(all) fun findRelatedFlowAccounts(address:Address) : {String: [Address]} { + let cap = self.getCapability(address) + if cap == nil { + return {} + } + + return cap!.borrow()!.getFlowAccounts() + } + + access(all) fun findRelatedAccounts(address:Address) : {String: {String: [String]}} { + let cap = self.getCapability(address) + if cap == nil { + return {} + } + + return cap!.borrow()!.getAllRelatedAccounts() + } + + init() { + self.storagePath = /storage/findRelatedAccounts + self.publicPath = /public/findRelatedAccounts + } } diff --git a/contracts/FindRewardToken.cdc b/contracts/FindRewardToken.cdc deleted file mode 100644 index be3f87f3..00000000 --- a/contracts/FindRewardToken.cdc +++ /dev/null @@ -1,51 +0,0 @@ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" - -pub contract FindRewardToken { - - // Map tenantToken to custom task rewards - access(contract) let defaultTaskRewards: {String : UFix64} - access(contract) let tenantTokenCapabilities: {Address : Capability<&{FungibleToken.Provider}>} - - access(account) fun addTenantRewardToken(tenant: Address, cap: Capability<&{FungibleToken.Provider}>) { - if self.tenantTokenCapabilities[tenant] != nil { - panic("This tenant token has already registered.") - } - self.tenantTokenCapabilities[tenant] = cap - } - - access(account) fun removeTenantRewardToken(tenant: Address) { - if self.tenantTokenCapabilities[tenant] == nil { - panic("This tenant token has not yet registered.") - } - self.tenantTokenCapabilities.remove(key: tenant) - } - - access(account) fun getRewardVault(_ tenant: Address) : Capability<&{FungibleToken.Provider}>? { - return FindRewardToken.tenantTokenCapabilities[tenant] - } - - access(account) fun getRewardVaults() : [Capability<&{FungibleToken.Provider}>] { - return FindRewardToken.tenantTokenCapabilities.values - } - - pub fun getDefaultTaskRewards() : {String : UFix64} { - return self.defaultTaskRewards - } - - pub fun getTasks() : [String] { - return self.defaultTaskRewards.keys - } - - - init(){ - self.defaultTaskRewards = { - "findName_register" : 10.0, - "findName_fulfill_buyer" : 5.0, - "findName_fulfill_seller" : 10.0, - "findMarket_fulfill_buyer" : 5.0, - "findMarket_fulfill_seller" : 10.0 - } - self.tenantTokenCapabilities = {} - } - -} \ No newline at end of file diff --git a/contracts/FindRulesCache.cdc b/contracts/FindRulesCache.cdc index 5e07fbdd..05efbcdc 100644 --- a/contracts/FindRulesCache.cdc +++ b/contracts/FindRulesCache.cdc @@ -1,117 +1,116 @@ -import MetadataViews from "../contracts/standard/MetadataViews.cdc" - -pub contract FindRulesCache { - - access(contract) let tenantFindRules : {String : {String : ActionResult}} - access(contract) let tenantTenantRules : {String : {String : ActionResult}} - access(contract) let tenantCuts : {String : {String : TenantCuts}} - - pub struct ActionResult { - pub let allowed:Bool - pub let message:String - pub let name:String - - init(allowed:Bool, message:String, name:String) { - self.allowed=allowed - self.message=message - self.name =name - } - } - - pub struct TenantCuts { - pub let findCut:MetadataViews.Royalty? - pub let tenantCut:MetadataViews.Royalty? - - init(findCut:MetadataViews.Royalty?, tenantCut:MetadataViews.Royalty?) { - self.findCut=findCut - self.tenantCut=tenantCut - } - } - - // Tenant Find Rules - access(account) fun setTenantFindRulesCache(tenant: String, ruleId: String, result: ActionResult) { - if self.tenantFindRules[tenant] == nil { - self.tenantFindRules[tenant] = {} - self.tenantFindRules[tenant]!.insert(key: ruleId, result) - return - } - - if self.tenantFindRules[tenant]![ruleId] == nil { - self.tenantFindRules[tenant]!.insert(key: ruleId, result) - return - } - - panic("There is already a cache for this find rule. RuleId : ".concat(ruleId)) - } - - pub fun getTenantFindRules(tenant: String, ruleId: String) : ActionResult? { - if self.tenantFindRules[tenant] == nil { - return nil - } - return self.tenantFindRules[tenant]![ruleId] - } - - access(account) fun resetTenantFindRulesCache(_ tenant: String) { - self.tenantFindRules.remove(key: tenant) - } - - // Tenant Tenant Rules - access(account) fun setTenantTenantRulesCache(tenant: String, ruleId: String, result: ActionResult) { - if self.tenantTenantRules[tenant] == nil { - self.tenantTenantRules[tenant] = {} - self.tenantTenantRules[tenant]!.insert(key: ruleId, result) - return - } - - if self.tenantTenantRules[tenant]![ruleId] == nil { - self.tenantTenantRules[tenant]!.insert(key: ruleId, result) - return - } - - panic("There is already a cache for this tenant rule. RuleId : ".concat(ruleId)) - } - - pub fun getTenantTenantRules(tenant: String, ruleId: String) : ActionResult? { - if self.tenantTenantRules[tenant] == nil { - return nil - } - return self.tenantTenantRules[tenant]![ruleId] - } - - access(account) fun resetTenantTenantRulesCache(_ tenant: String) { - self.tenantTenantRules.remove(key: tenant) - } - - access(account) fun setTenantCutCache(tenant: String, ruleId: String, cut: TenantCuts) { - if self.tenantCuts[tenant] == nil { - self.tenantCuts[tenant] = {} - self.tenantCuts[tenant]!.insert(key: ruleId, cut) - return - } - - if self.tenantCuts[tenant]![ruleId] == nil { - self.tenantCuts[tenant]!.insert(key: ruleId, cut) - return - } - - panic("There is already a cache for this tenant cut information. RuleId : ".concat(ruleId)) - } - - pub fun getTenantCut(tenant: String, ruleId: String) : TenantCuts? { - if self.tenantCuts[tenant] == nil { - return nil - } - return self.tenantCuts[tenant]![ruleId] - } - - access(account) fun resetTenantCutCache(_ tenant: String) { - self.tenantCuts.remove(key: tenant) - } - - init() { - self.tenantFindRules = {} - self.tenantTenantRules = {} - self.tenantCuts = {} - } - +import "MetadataViews" + +access(all) contract FindRulesCache { + + access(contract) let tenantFindRules : {String : {String : ActionResult}} + access(contract) let tenantTenantRules : {String : {String : ActionResult}} + access(contract) let tenantCuts : {String : {String : TenantCuts}} + + access(all) struct ActionResult { + access(all) let allowed:Bool + access(all) let message:String + access(all) let name:String + + init(allowed:Bool, message:String, name:String) { + self.allowed=allowed + self.message=message + self.name =name + } + } + + access(all) struct TenantCuts { + access(all) let findCut:MetadataViews.Royalty? + access(all) let tenantCut:MetadataViews.Royalty? + + init(findCut:MetadataViews.Royalty?, tenantCut:MetadataViews.Royalty?) { + self.findCut=findCut + self.tenantCut=tenantCut + } + } + + // Tenant Find Rules + access(account) fun setTenantFindRulesCache(tenant: String, ruleId: String, result: ActionResult) { + if self.tenantFindRules[tenant] == nil { + self.tenantFindRules[tenant] = {} + self.tenantFindRules[tenant]!.insert(key: ruleId, result) + return + } + + if self.tenantFindRules[tenant]![ruleId] == nil { + self.tenantFindRules[tenant]!.insert(key: ruleId, result) + return + } + + panic("There is already a cache for this find rule. RuleId : ".concat(ruleId)) + } + + access(all) fun getTenantFindRules(tenant: String, ruleId: String) : ActionResult? { + if self.tenantFindRules[tenant] == nil { + return nil + } + return self.tenantFindRules[tenant]![ruleId] + } + + access(account) fun resetTenantFindRulesCache(_ tenant: String) { + self.tenantFindRules.remove(key: tenant) + } + + // Tenant Tenant Rules + access(account) fun setTenantTenantRulesCache(tenant: String, ruleId: String, result: ActionResult) { + if self.tenantTenantRules[tenant] == nil { + self.tenantTenantRules[tenant] = {} + self.tenantTenantRules[tenant]!.insert(key: ruleId, result) + return + } + + if self.tenantTenantRules[tenant]![ruleId] == nil { + self.tenantTenantRules[tenant]!.insert(key: ruleId, result) + return + } + + panic("There is already a cache for this tenant rule. RuleId : ".concat(ruleId)) + } + + access(all) fun getTenantTenantRules(tenant: String, ruleId: String) : ActionResult? { + if self.tenantTenantRules[tenant] == nil { + return nil + } + return self.tenantTenantRules[tenant]![ruleId] + } + + access(account) fun resetTenantTenantRulesCache(_ tenant: String) { + self.tenantTenantRules.remove(key: tenant) + } + + access(account) fun setTenantCutCache(tenant: String, ruleId: String, cut: TenantCuts) { + if self.tenantCuts[tenant] == nil { + self.tenantCuts[tenant] = {} + self.tenantCuts[tenant]!.insert(key: ruleId, cut) + return + } + + if self.tenantCuts[tenant]![ruleId] == nil { + self.tenantCuts[tenant]!.insert(key: ruleId, cut) + return + } + + panic("There is already a cache for this tenant cut information. RuleId : ".concat(ruleId)) + } + + access(all) fun getTenantCut(tenant: String, ruleId: String) : TenantCuts? { + if self.tenantCuts[tenant] == nil { + return nil + } + return self.tenantCuts[tenant]![ruleId] + } + + access(account) fun resetTenantCutCache(_ tenant: String) { + self.tenantCuts.remove(key: tenant) + } + + init() { + self.tenantFindRules = {} + self.tenantTenantRules = {} + self.tenantCuts = {} + } } diff --git a/contracts/FindThoughts.cdc b/contracts/FindThoughts.cdc index b5608448..165b5bcc 100644 --- a/contracts/FindThoughts.cdc +++ b/contracts/FindThoughts.cdc @@ -1,332 +1,341 @@ -import FindViews from "./FindViews.cdc" -import FindMarket from "./FindMarket.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FINDNFTCatalog from "./FINDNFTCatalog.cdc" -import FIND from "./FIND.cdc" -import Clock from "./Clock.cdc" - -pub contract FindThoughts { - - pub event Published(id: UInt64, creator: Address, creatorName: String?, header: String, message: String, medias: [String], nfts:[FindMarket.NFTInfo], tags: [String], quoteOwner: Address?, quoteId: UInt64?) - pub event Edited(id: UInt64, creator: Address, creatorName: String?, header: String, message: String, medias: [String], hide: Bool, tags: [String]) - pub event Deleted(id: UInt64, creator: Address, creatorName: String?, header: String, message: String, medias: [String], tags: [String]) - pub event Reacted(id: UInt64, by: Address, byName: String?, creator: Address, creatorName: String?, header: String, reaction: String?, totalCount: {String : Int}) - - pub let CollectionStoragePath : StoragePath - pub let CollectionPublicPath : PublicPath - pub let CollectionPrivatePath : PrivatePath - - pub struct ThoughtPointer { - pub let cap: Capability<&FindThoughts.Collection{FindThoughts.CollectionPublic}> - pub let id: UInt64 - - init(creator: Address, id: UInt64) { - let cap = getAccount(creator).getCapability<&FindThoughts.Collection{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath) - if !cap.check() { - panic("creator's find thought capability is not valid. Creator : ".concat(creator.toString())) - } - self.cap = cap - self.id = id - } - - pub fun borrowThoughtPublic() : &{ThoughtPublic}? { - if self.cap.check() { - let ref = self.cap.borrow()! - if ref.contains(self.id) { - return ref.borrowThoughtPublic(self.id) - } - } - return nil - } - - pub fun valid() : Bool { - if self.borrowThoughtPublic() != nil { - return true - } - return false - } - - pub fun owner() : Address { - return self.cap.address - } - } - - pub resource interface ThoughtPublic { - pub let id: UInt64 - pub let creator: Address - pub var header: String - pub var body: String - pub let created: UFix64 - pub var lastUpdated: UFix64? - pub let medias: [MetadataViews.Media] - pub let nft: [FindViews.ViewReadPointer] - pub var tags: [String] - pub var reacted: {Address : String} - pub var reactions: {String : Int} - - access(contract) fun internal_react(user: Address, reaction: String?) - pub fun getQuotedThought() : ThoughtPointer? - pub fun getHide() : Bool - } - - pub resource Thought : ThoughtPublic , MetadataViews.Resolver { - pub let id: UInt64 - pub let creator: Address - pub var header: String - pub var body: String - pub let created: UFix64 - pub var lastUpdated: UFix64? - pub var tags: [String] - // user : Reactions - pub var reacted: {Address : String} - // Reactions : Counts - pub var reactions: {String : Int} - - // only one image is enabled at the moment - pub let medias: [MetadataViews.Media] - - // These are here only for future extension - pub let nft: [FindViews.ViewReadPointer] - access(self) let stringTags: {String : String} - access(self) let scalars: {String : UFix64} - access(self) let extras: {String : AnyStruct} - - init(creator: Address , header: String , body: String , created: UFix64, tags: [String], medias: [MetadataViews.Media], nft: [FindViews.ViewReadPointer], quote: ThoughtPointer?, stringTags: {String : String}, scalars : {String : UFix64}, extras: {String : AnyStruct} ) { - self.id = self.uuid - self.creator = creator - self.header = header - self.body = body - self.created = created - self.lastUpdated = nil - self.tags = tags - self.medias = medias - - self.nft = nft - self.stringTags = stringTags - self.scalars = scalars - extras["quote"] = quote - extras["hidden"] = false - self.extras = extras - - self.reacted = {} - self.reactions = {} - } - - destroy(){ - let address = self.owner?.address - let medias : [String] = [] - for m in self.medias { - medias.append(m.file.uri()) - } - - var name : String? = nil - if address != nil { - name = FIND.reverseLookup(address!) - } - emit Deleted(id: self.id, creator: self.creator, creatorName: FIND.reverseLookup(self.creator), header: self.header, message: self.body, medias: medias, tags: self.tags) - } - - pub fun getQuotedThought() : ThoughtPointer? { - if let r = self.extras["quote"] { - return r as! ThoughtPointer - } - return nil - } - - pub fun getHide() : Bool { - if let r = self.extras["hidden"] { - return r as! Bool - } - return false - } - - pub fun hide(_ hide: Bool) { - self.extras["hidden"] = hide - let medias : [String] = [] - for m in self.medias { - medias.append(m.file.uri()) - } - emit Edited(id: self.id, creator: self.creator, creatorName: FIND.reverseLookup(self.creator), header: self.header, message: self.body, medias: medias, hide: hide, tags: self.tags) - } - - pub fun edit(header: String , body: String, tags: [String]) { - self.header = header - self.body = body - self.tags = tags - let address = self.owner!.address - let medias : [String] = [] - for m in self.medias { - medias.append(m.file.uri()) - } - self.lastUpdated = Clock.time() - emit Edited(id: self.id, creator: address, creatorName: FIND.reverseLookup(address), header: self.header, message: self.body, medias: medias, hide: self.getHide(), tags: self.tags) - } - - // To withdraw reaction, pass in nil - access(contract) fun internal_react(user: Address, reaction: String?) { - let owner = self.owner!.address - if let previousReaction = self.reacted[user] { - // reaction here cannot be nil, therefore we can ! - self.reactions[previousReaction] = self.reactions[previousReaction]! - 1 - if self.reactions[previousReaction]! == 0 { - self.reactions.remove(key: previousReaction) - } - } - - self.reacted[user] = reaction - - if reaction != nil { - var reacted = self.reactions[reaction!] ?? 0 - reacted = reacted + 1 - self.reactions[reaction!] = reacted - } - - emit Reacted(id: self.id, by: user, byName: FIND.reverseLookup(user), creator: owner, creatorName: FIND.reverseLookup(owner), header: self.header, reaction: reaction, totalCount: self.reactions) - } - - pub fun getViews(): [Type] { - return [ - Type() - ] - } - - pub fun resolveView(_ type: Type) : AnyStruct? { - switch type { - - case Type(): - - let content = self.body.concat(" -- FIND Thought by ").concat(FIND.reverseLookup(self.owner!.address) ?? self.owner!.address.toString()) - - return MetadataViews.Display( - name: self.header, - description: content, - thumbnail: self.medias[0].file - ) - - } - return nil - } - } - - pub resource interface CollectionPublic { - pub fun contains(_ id: UInt64) : Bool - pub fun getIDs() : [UInt64] - pub fun borrowThoughtPublic(_ id: UInt64) : &FindThoughts.Thought{FindThoughts.ThoughtPublic} - } - - pub resource Collection : CollectionPublic, MetadataViews.ResolverCollection { - access(self) let ownedThoughts : @{UInt64 : FindThoughts.Thought} - - access(self) let sequence : [UInt64] - - init() { - self.ownedThoughts <- {} - self.sequence = [] - } - - destroy() { - destroy self.ownedThoughts - } - - pub fun contains(_ id: UInt64) : Bool { - return self.ownedThoughts.containsKey(id) - } - - pub fun getIDs() : [UInt64] { - return self.ownedThoughts.keys - } - - pub fun borrow(_ id: UInt64) : &FindThoughts.Thought { - pre{ - self.ownedThoughts.containsKey(id) : "Cannot borrow Thought with ID : ".concat(id.toString()) - } - return (&self.ownedThoughts[id] as &FindThoughts.Thought?)! - } - - pub fun borrowThoughtPublic(_ id: UInt64) : &FindThoughts.Thought{FindThoughts.ThoughtPublic} { - pre{ - self.ownedThoughts.containsKey(id) : "Cannot borrow Thought with ID : ".concat(id.toString()) - } - return (&self.ownedThoughts[id] as &FindThoughts.Thought?)! - } - - pub fun borrowViewResolver(id: UInt64): &{MetadataViews.Resolver} { - pre{ - self.ownedThoughts.containsKey(id) : "Cannot borrow Thought with ID : ".concat(id.toString()) - } - return (&self.ownedThoughts[id] as &FindThoughts.Thought?)! - } - - // TODO : Restructure this to take structs , and declare the structs in Trxn. And identify IPFS and url - // So take pointer, thought pointer and media - pub fun publish(header: String , body: String , tags: [String], media: MetadataViews.Media?, nftPointer: FindViews.ViewReadPointer?, quote: FindThoughts.ThoughtPointer?) { - let medias : [MetadataViews.Media] = [] - let m : [String] = [] - if media != nil { - medias.append(media!) - m.append(media!.file.uri()) - } - let address = self.owner!.address - - let nfts : [FindMarket.NFTInfo] = [] - let extra : {String : AnyStruct} = {} - if nftPointer != nil { - let rv = nftPointer!.getViewResolver() - nfts.append(FindMarket.NFTInfo(rv, id: nftPointer!.id, detail: true)) - } - - let thought <- create Thought(creator: address, header: header , body: body , created: Clock.time(), tags: tags, medias: medias, nft: [], quote: quote, stringTags: {}, scalars : {}, extras: extra) - - self.sequence.append(thought.uuid) - - let creatorName = FIND.reverseLookup(address) - - emit Published(id: thought.id ,creator: address, creatorName: creatorName , header: header, message: body, medias: m, nfts: nfts, tags: tags, quoteOwner: quote?.owner(), quoteId: quote?.id) - - self.ownedThoughts[thought.uuid] <-! thought - } - - pub fun delete(_ id: UInt64) { - pre{ - self.ownedThoughts.containsKey(id) : "Does not contains Thought with ID : ".concat(id.toString()) - } - - let thought <- self.ownedThoughts.remove(key: id)! - self.sequence.remove(at: self.sequence.firstIndex(of: id)!) - - let address = self.owner!.address - destroy thought - } - - pub fun react(user: Address, id: UInt64, reaction: String?) { - let cap = FindThoughts.getFindThoughtsCapability(user) - let ref = cap.borrow() ?? panic("Cannot borrow reference to Find Thoughts Collection from user : ".concat(user.toString())) - - let thought = ref.borrowThoughtPublic(id) - thought.internal_react(user: self.owner!.address, reaction: reaction) - } - - pub fun hide(id: UInt64, hide: Bool) { - let thought = self.borrow(id) - thought.hide(hide) - } - - } - - pub fun createEmptyCollection() : @FindThoughts.Collection { - return <- create Collection() - } - - pub fun getFindThoughtsCapability(_ user: Address) : Capability<&FindThoughts.Collection{FindThoughts.CollectionPublic}> { - return getAccount(user).getCapability<&FindThoughts.Collection{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath) - } - - init(){ - self.CollectionStoragePath = /storage/FindThoughts - self.CollectionPublicPath = /public/FindThoughts - self.CollectionPrivatePath = /private/FindThoughts - } - +import "FindViews" +import "FindMarket" +import "MetadataViews" +import "ViewResolver" +import "FINDNFTCatalog" +import "FIND" +import "Clock" + +access(all) contract FindThoughts { + // Entitlements + access(all) entitlement Owner + + // Events + access(all) event Published(id: UInt64, creator: Address, creatorName: String?, header: String, message: String, medias: [String], nfts:[FindMarket.NFTInfo], tags: [String], quoteOwner: Address?, quoteId: UInt64?) + access(all) event Edited(id: UInt64, creator: Address, creatorName: String?, header: String, message: String, medias: [String], hide: Bool, tags: [String]) + access(all) event Deleted(id: UInt64, creator: Address, creatorName: String?, header: String, message: String, medias: [String], tags: [String]) + access(all) event Reacted(id: UInt64, by: Address, byName: String?, creator: Address, creatorName: String?, header: String, reaction: String?, totalCount: {String : Int}) + + // Paths + access(all) let CollectionStoragePath : StoragePath + access(all) let CollectionPublicPath : PublicPath + + access(all) struct ThoughtPointer { + access(all) let cap: Capability<&FindThoughts.Collection> + access(all) let id: UInt64 + + init(creator: Address, id: UInt64) { + let cap = getAccount(creator).capabilities.get<&FindThoughts.Collection>(FindThoughts.CollectionPublicPath) + if cap !=nil && !cap!.check() { + panic("creator's find thought capability is not valid. Creator : ".concat(creator.toString())) + } + self.cap = cap! + self.id = id + } + + access(all) fun borrowThoughtPublic() : &{ThoughtPublic}? { + if self.cap.check() { + let ref = self.cap.borrow()! + if ref.contains(self.id) { + return ref.borrowThoughtPublic(self.id) + } + } + return nil + } + + access(all) fun valid() : Bool { + if self.borrowThoughtPublic() != nil { + return true + } + return false + } + + access(all) fun owner() : Address { + return self.cap.address + } + } + + access(all) resource interface ThoughtPublic { + access(all) let id: UInt64 + access(all) let creator: Address + access(all) var header: String + access(all) var body: String + access(all) let created: UFix64 + access(all) var lastUpdated: UFix64? + access(all) let medias: [MetadataViews.Media] + access(all) let nft: [FindViews.ViewReadPointer] + access(all) var tags: [String] + access(all) var reacted: {Address : String} + access(all) var reactions: {String : Int} + + access(contract) fun internal_react(user: Address, reaction: String?) + access(all) fun getQuotedThought() : ThoughtPointer? + access(all) fun getHide() : Bool + access(all) fun getTags() : [String] { + return self.tags + } + access(all) fun getReactions() : {String:Int}{ + return self.reactions + } + + access(all) fun getNFTS() : [FindViews.ViewReadPointer] { + return self.nft + } + } + + access(all) resource interface ThoughtPrivate { + access(Owner) fun hide(_ hide: Bool) + access(Owner) fun edit(header: String , body: String, tags: [String]) + } + + access(all) resource Thought : ThoughtPublic, ThoughtPrivate, ViewResolver.Resolver { + access(all) let id: UInt64 + access(all) let creator: Address + access(all) var header: String + access(all) var body: String + access(all) let created: UFix64 + access(all) var lastUpdated: UFix64? + access(all) var tags: [String] + // user : Reactions + access(all) var reacted: {Address : String} + // Reactions : Counts + access(all) var reactions: {String : Int} + + // only one image is enabled at the moment + access(all) let medias: [MetadataViews.Media] + + // These are here only for future extension + access(all) let nft: [FindViews.ViewReadPointer] + access(self) let stringTags: {String : String} + access(self) let scalars: {String : UFix64} + access(self) let extras: {String : AnyStruct} + + init(creator: Address , header: String , body: String , created: UFix64, tags: [String], medias: [MetadataViews.Media], nft: [FindViews.ViewReadPointer], quote: ThoughtPointer?, stringTags: {String : String}, scalars : {String : UFix64}, extras: {String : AnyStruct} ) { + self.id = self.uuid + self.creator = creator + self.header = header + self.body = body + self.created = created + self.lastUpdated = nil + self.tags = tags + self.medias = medias + + self.nft = nft + self.stringTags = stringTags + self.scalars = scalars + extras["quote"] = quote + extras["hidden"] = false + self.extras = extras + + self.reacted = {} + self.reactions = {} + } + + access(all) fun getQuotedThought() : ThoughtPointer? { + if let r = self.extras["quote"] { + return r as! ThoughtPointer + } + return nil + } + + access(all) fun getHide() : Bool { + if let r = self.extras["hidden"] { + return r as! Bool + } + return false + } + + access(Owner) fun hide(_ hide: Bool) { + self.extras["hidden"] = hide + let medias : [String] = [] + for m in self.medias { + medias.append(m.file.uri()) + } + emit Edited(id: self.id, creator: self.creator, creatorName: FIND.reverseLookup(self.creator), header: self.header, message: self.body, medias: medias, hide: hide, tags: self.tags) + } + + access(Owner) fun edit(header: String , body: String, tags: [String]) { + self.header = header + self.body = body + self.tags = tags + let address = self.owner!.address + let medias : [String] = [] + for m in self.medias { + medias.append(m.file.uri()) + } + self.lastUpdated = Clock.time() + emit Edited(id: self.id, creator: address, creatorName: FIND.reverseLookup(address), header: self.header, message: self.body, medias: medias, hide: self.getHide(), tags: self.tags) + } + + // To withdraw reaction, pass in nil + access(contract) fun internal_react(user: Address, reaction: String?) { + let owner = self.owner!.address + if let previousReaction = self.reacted[user] { + // reaction here cannot be nil, therefore we can ! + self.reactions[previousReaction] = self.reactions[previousReaction]! - 1 + if self.reactions[previousReaction]! == 0 { + self.reactions.remove(key: previousReaction) + } + } + + self.reacted[user] = reaction + + if reaction != nil { + var reacted = self.reactions[reaction!] ?? 0 + reacted = reacted + 1 + self.reactions[reaction!] = reacted + } + + emit Reacted(id: self.id, by: user, byName: FIND.reverseLookup(user), creator: owner, creatorName: FIND.reverseLookup(owner), header: self.header, reaction: reaction, totalCount: self.reactions) + } + + access(all) view fun getViews(): [Type] { + return [ + Type() + ] + } + + access(all) view fun resolveView(_ type: Type) : AnyStruct? { + switch type { + + case Type(): + + let content = self.body.concat(" -- FIND Thought by ").concat(self.owner!.address.toString()) + + return MetadataViews.Display( + name: self.header, + description: content, + thumbnail: self.medias[0].file + ) + + } + return nil + } + } + + access(all) resource interface CollectionPublic { + access(all) fun contains(_ id: UInt64) : Bool + access(all) view fun borrowThoughtPublic(_ id: UInt64) : &{FindThoughts.ThoughtPublic} + } + + access(all) resource Collection : CollectionPublic, ViewResolver.ResolverCollection { + access(self) let ownedThoughts : @{UInt64 : FindThoughts.Thought} + access(self) let sequence : [UInt64] + + init() { + self.ownedThoughts <- {} + self.sequence = [] + } + + access(all) fun contains(_ id: UInt64) : Bool { + return self.ownedThoughts.containsKey(id) + } + + access(all) view fun getIDs() : [UInt64] { + return self.ownedThoughts.keys + } + + access(Owner) fun borrow(_ id: UInt64) : auth(Owner) &{FindThoughts.ThoughtPrivate} { + pre{ + self.ownedThoughts.containsKey(id) : "Cannot borrow Thought with ID : ".concat(id.toString()) + } + return (&self.ownedThoughts[id])! + } + + access(all) view fun borrowThoughtPublic(_ id: UInt64) : &{FindThoughts.ThoughtPublic} { + pre{ + self.ownedThoughts.containsKey(id) : "Cannot borrow Thought with ID : ".concat(id.toString()) + } + return (&self.ownedThoughts[id] as &FindThoughts.Thought?)! + } + + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} { + pre{ + self.ownedThoughts.containsKey(id) : "Cannot borrow Thought with ID : ".concat(id.toString()) + } + return (&self.ownedThoughts[id] as &FindThoughts.Thought?)! + } + + access(Owner) fun publish(header: String , body: String , tags: [String], media: MetadataViews.Media?, nftPointer: FindViews.ViewReadPointer?, quote: FindThoughts.ThoughtPointer?) { + let medias : [MetadataViews.Media] = [] + let m : [String] = [] + if media != nil { + medias.append(media!) + m.append(media!.file.uri()) + } + let address = self.owner!.address + + let nfts : [FindMarket.NFTInfo] = [] + let extra : {String : AnyStruct} = {} + let nftPointers : [FindViews.ViewReadPointer] = [] + if nftPointer != nil { + let rv = nftPointer!.getViewResolver() + nfts.append(FindMarket.NFTInfo(rv, id: nftPointer!.id, detail: true)) + nftPointers.append(nftPointer!) + } + + + let thought <- create Thought(creator: address, header: header , body: body , created: Clock.time(), tags: tags, medias: medias, nft: nftPointers, quote: quote, stringTags: {}, scalars : {}, extras: extra) + + self.sequence.append(thought.uuid) + + let creatorName = FIND.reverseLookup(address) + + emit Published(id: thought.id ,creator: address, creatorName: creatorName , header: header, message: body, medias: m, nfts: nfts, tags: tags, quoteOwner: quote?.owner(), quoteId: quote?.id) + + + self.ownedThoughts[thought.uuid] <-! thought + } + + access(Owner) fun delete(_ id: UInt64) { + pre{ + self.ownedThoughts.containsKey(id) : "Does not contains Thought with ID : ".concat(id.toString()) + } + + let thought <- self.ownedThoughts.remove(key: id)! + self.sequence.remove(at: self.sequence.firstIndex(of: id)!) + + let address = self.owner!.address + + let medias : [String] = [] + for m in thought.medias { + medias.append(m.file.uri()) + } + + var name : String? = nil + if address != nil { + name = FIND.reverseLookup(address) + } + emit Deleted(id: thought.id, creator: thought.creator, creatorName: FIND.reverseLookup(thought.creator), header: thought.header, message: thought.body, medias: medias, tags: thought.tags) + + destroy thought + } + + access(Owner) fun react(user: Address, id: UInt64, reaction: String?) { + let cap = FindThoughts.getFindThoughtsCapability(user) + let ref = cap.borrow() ?? panic("Cannot borrow reference to Find Thoughts Collection from user : ".concat(user.toString())) + + let thought = ref.borrowThoughtPublic(id) + thought.internal_react(user: self.owner!.address, reaction: reaction) + } + + access(Owner) fun hide(id: UInt64, hide: Bool) { + let thought = self.borrow(id) + thought.hide(hide) + } + + } + + access(all) fun createEmptyCollection() : @FindThoughts.Collection { + return <- create Collection() + } + + access(all) fun getFindThoughtsCapability(_ user: Address) : Capability<&{FindThoughts.CollectionPublic}> { + return getAccount(user).capabilities.get<&{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath)! + } + + init(){ + self.CollectionStoragePath = /storage/FindThoughts + self.CollectionPublicPath = /public/FindThoughts + } } - - \ No newline at end of file diff --git a/contracts/FindToken.cdc b/contracts/FindToken.cdc deleted file mode 100644 index 76d04899..00000000 --- a/contracts/FindToken.cdc +++ /dev/null @@ -1,154 +0,0 @@ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FindViews from "../contracts/FindViews.cdc" -import Clock from "../contracts/Clock.cdc" - -pub contract FindToken : FungibleToken { - - pub event TokensInitialized(initialSupply: UFix64) - pub event TokensWithdrawn(amount: UFix64, from: Address?) - pub event TokensDeposited(amount: UFix64, to: Address?) - - pub event TokensMinted(amount: UFix64) - pub event TokensBurned(amount: UFix64) - pub event TokenRewardMultiplier(multiplier: UFix64) - - pub let tokenAlias: String - pub var totalSupply: UFix64 - pub let initialSupply: UFix64 - - - pub let vaultStoragePath: StoragePath - pub let receiverPublicPath: PublicPath - pub let balancePublicPath: PublicPath - pub let providerPath: PrivatePath - pub let minterPath: StoragePath - pub let findRewardPath: PrivatePath - - pub resource Vault : FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance, FindViews.VaultViews { - - pub var balance: UFix64 - - init(balance: UFix64) { - self.balance=balance - } - - destroy(){ - FindToken.totalSupply = FindToken.totalSupply - self.balance - emit TokensBurned(amount: self.balance) - } - - pub fun withdraw(amount: UFix64) : @FungibleToken.Vault { - self.balance = self.balance - amount - emit TokensWithdrawn(amount: amount, from: self.owner?.address) - return <-create Vault(balance: amount) - } - - pub fun deposit(from: @FungibleToken.Vault) { - let vault <- from as! @Vault - self.balance = self.balance + vault.balance - emit TokensDeposited(amount: vault.balance, to: self.owner?.address) - vault.balance = 0.0 - destroy vault - } - - pub fun getViews() : [Type] { - return [ - Type() , - Type<&FindToken.Vault{FungibleToken.Receiver}>() , - Type<&FindToken.Vault{FungibleToken.Balance}>() , - Type<&FindToken.Vault{FindViews.VaultViews}>() - ] - } - - pub fun resolveView(_ view: Type) : AnyStruct? { - switch view { - case Type() : - return FindViews.FTVaultData( - tokenAlias: FindToken.tokenAlias, - storagePath: FindToken.vaultStoragePath, - receiverPath: FindToken.receiverPublicPath, - balancePath: FindToken.balancePublicPath, - providerPath: FindToken.providerPath, - vaultType: FindToken.getVaultType(), - receiverType: Type<&FindToken.Vault{FungibleToken.Receiver, FindViews.VaultViews}>(), - balanceType: Type<&FindToken.Vault{FungibleToken.Balance, FindViews.VaultViews}>(), - providerType: Type<&FindToken.Vault{FungibleToken.Provider, FindViews.VaultViews}>(), - createEmptyVault: FindToken.createEmptyVaultFN() - ) - - case Type<&FindToken.Vault{FungibleToken.Receiver}>() : - return (&self as &{FungibleToken.Receiver}?)! - - case Type<&FindToken.Vault{FungibleToken.Balance}>() : - return (&self as &{FungibleToken.Balance}?)! - - default : - return nil - } - } - - } - - pub fun createEmptyVault() : @FungibleToken.Vault { - return <- create FindToken.Vault(balance: 0.0) - } - - pub fun createEmptyVaultFN() : (() : @FungibleToken.Vault) { - return fun () : @FungibleToken.Vault { - return <- FindToken.createEmptyVault() - } - } - - pub resource Minter { - pub fun mintTokens(_ amount: UFix64) : @FungibleToken.Vault { - if amount == 0.0 { - panic("Amount minted must be greater than zero") - } - FindToken.totalSupply = FindToken.totalSupply + amount - emit TokensMinted(amount: amount) - return <-create Vault(balance: amount) - } - } - - pub fun getBalanceCapability(address: Address) : Capability<&{FungibleToken.Balance}> { - return getAccount(address).getCapability<&{FungibleToken.Balance}>(FindToken.balancePublicPath) - } - - pub fun getReceiverCapability(address: Address) : Capability<&{FungibleToken.Receiver}> { - return getAccount(address).getCapability<&{FungibleToken.Receiver}>(FindToken.receiverPublicPath) - } - - pub fun getVaultType() : Type { - return Type<@Vault>() - } - - init(){ - self.tokenAlias = "FIND" - self.totalSupply = 0.0 - self.initialSupply = 100000000.0 - - self.vaultStoragePath = /storage/findTokenVault - self.receiverPublicPath = /public/findTokenReceiver - self.balancePublicPath = /public/findTokenBalance - self.providerPath = /private/findTokenProvider - self.minterPath = /storage/findTokenMinter - - let minter <- create Minter() - let vault <- create Vault(balance: 0.0) - - vault.deposit(from: <- minter.mintTokens(self.initialSupply)) - - self.account.save(<- vault, to: self.vaultStoragePath) - self.account.link<&Vault{FungibleToken.Receiver, FindViews.VaultViews}>(self.receiverPublicPath, target: self.vaultStoragePath) - self.account.link<&Vault{FungibleToken.Balance, FindViews.VaultViews}>(self.balancePublicPath, target: self.vaultStoragePath) - self.account.link<&Vault{FungibleToken.Provider, FindViews.VaultViews}>(self.providerPath, target: self.vaultStoragePath) - - self.account.save(<- minter, to: self.minterPath) - - emit TokensInitialized(initialSupply: self.initialSupply) - - // Extra Field (to be deleted) - self.findRewardPath = /private/findTokenReward - } - -} \ No newline at end of file diff --git a/contracts/FindUserStatus.cdc b/contracts/FindUserStatus.cdc index df561de1..98709f97 100644 --- a/contracts/FindUserStatus.cdc +++ b/contracts/FindUserStatus.cdc @@ -1,420 +1,420 @@ -import FIND from "../contracts/FIND.cdc" -import NFTStorefront from "../contracts/standard/NFTStorefront.cdc" -import NFTStorefrontV2 from "../contracts/standard/NFTStorefrontV2.cdc" -import Flowty from "../contracts/community/Flowty.cdc" -import FlowtyRentals from "../contracts/community/FlowtyRentals.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FlovatarMarketplace from "../contracts/community/FlovatarMarketplace.cdc" -import Flovatar from "../contracts/community/Flovatar.cdc" -import FlovatarComponent from "../contracts/community/FlovatarComponent.cdc" - -pub contract FindUserStatus { - - pub struct StoreFrontCut { - pub let amount:UFix64 - pub let address: Address - pub let findName:String? - pub let tags: {String : String} - pub let scalars: {String : UFix64} - pub let extra: {String : AnyStruct} - - init(amount:UFix64, address:Address){ - self.amount=amount - self.address=address - self.findName= FIND.reverseLookup(address) - self.tags={} - self.scalars={} - self.extra={} - } - } - - - pub struct StorefrontListing { - pub var listingId: UInt64 - // if purchased is true -> don't show it - //pub var purchased: Bool - pub let nftIdentifier: String - pub let nftId: UInt64 - pub let ftTypeIdentifier: String - pub let amount: UFix64 - pub let cuts: [StoreFrontCut] - pub var customID: String? - pub let commissionAmount: UFix64? - pub let listingValidUntil: UInt64? - pub let tags: {String : String} - pub let scalars: {String : UFix64} - pub let extra: {String : AnyStruct} - - init(storefrontID: UInt64, nftType: String, nftID: UInt64, salePaymentVaultType: String, salePrice: UFix64, saleCuts: [StoreFrontCut], customID: String?, commissionAmount: UFix64?, expiry: UInt64?) { - self.listingId = storefrontID - self.nftIdentifier = nftType - self.nftId = nftID - self.ftTypeIdentifier = salePaymentVaultType - self.amount = salePrice - self.cuts = saleCuts - self.customID = customID - self.commissionAmount = commissionAmount - self.listingValidUntil = expiry - self.tags={} - self.scalars={} - self.extra={} - } - } - - pub struct FlowtyListing { - pub var listingId: UInt64 - pub var funded: Bool - pub let nftIdentifier: String - pub let nftId: UInt64 - pub let amount: UFix64 - pub let interestRate: UFix64 - pub var term: UFix64 - pub let paymentVaultType: String - - pub let paymentCuts: [StoreFrontCut] - pub var listedTime: UFix64 - pub var royaltyRate: UFix64 - pub var listingValidUntil: UFix64 - pub var repaymentAmount: UFix64 - - pub let tags: {String : String} - pub let scalars: {String : UFix64} - pub let extra: {String : AnyStruct} - - init(flowtyStorefrontID: UInt64, funded: Bool, nftType: String, nftID: UInt64, amount: UFix64, interestRate: UFix64, term: UFix64, paymentVaultType: String,paymentCuts: [StoreFrontCut], listedTime: UFix64, royaltyRate: UFix64, expiresAfter: UFix64, repaymentAmount: UFix64) { - self.listingId = flowtyStorefrontID - self.funded = funded - self.nftIdentifier = nftType - self.nftId = nftID - self.amount = amount - self.interestRate = interestRate - self.term = term - self.paymentVaultType = paymentVaultType - self.paymentCuts = paymentCuts - self.listedTime = listedTime - self.royaltyRate = royaltyRate - self.listingValidUntil = expiresAfter + listedTime - self.repaymentAmount = repaymentAmount - self.tags={} - self.scalars={} - self.extra={} - } - } - - pub struct FlowtyRental { - pub var listingId: UInt64 - pub var rented: Bool - pub let nftIdentifier: String - pub let nftId: UInt64 - pub let amount: UFix64 - pub let deposit: UFix64 - pub var term: UFix64 - pub let paymentVaultType: String - pub let reenableOnReturn: Bool - - pub let paymentCuts: [StoreFrontCut] - pub var listedTime: UFix64 - pub var royaltyRate: UFix64 - pub var listingValidUntil: UFix64 - pub var repaymentAmount: UFix64 - pub var renter: Address? - pub var renterName: String? - - pub let tags: {String : String} - pub let scalars: {String : UFix64} - pub let extra: {String : AnyStruct} - - init(flowtyStorefrontID: UInt64, rented: Bool, nftType: String, nftID: UInt64, amount: UFix64, deposit: UFix64, term: UFix64, paymentVaultType: String, reenableOnReturn:Bool, paymentCuts: [StoreFrontCut], listedTime: UFix64, royaltyRate: UFix64, expiresAfter: UFix64, repaymentAmount: UFix64, renter: Address?) { - self.listingId = flowtyStorefrontID - self.rented = rented - self.nftIdentifier = nftType - self.nftId = nftID - self.deposit = deposit - self.amount = amount - self.term = term - self.paymentVaultType = paymentVaultType - self.reenableOnReturn = reenableOnReturn - self.paymentCuts = paymentCuts - self.listedTime = listedTime - self.royaltyRate = royaltyRate - self.listingValidUntil = expiresAfter + listedTime - self.repaymentAmount = repaymentAmount - self.renter = renter - self.renterName = nil - if renter != nil { - self.renterName = FIND.reverseLookup(renter!) - } - self.tags={} - self.scalars={} - self.extra={} - } - } - - pub struct FlovatarListing { - pub var listingId: UInt64 - pub let nftIdentifier: String - pub let nftId: UInt64 - pub let ftTypeIdentifier: String - pub let amount: UFix64 - pub let cuts: [StoreFrontCut] - pub let accessoryId: UInt64? - pub let hatId: UInt64? - pub let eyeglassesId: UInt64? - pub let backgroundId: UInt64? - pub let mint: UInt64 - pub let series: UInt32 - pub let creatorAddress: Address - pub let components: {String: UInt64} - pub let rareCount: UInt8 - pub let epicCount: UInt8 - pub let legendaryCount: UInt8 - pub let tags: {String : String} - pub let scalars: {String : UFix64} - pub let extra: {String : AnyStruct} - - init(storefrontID: UInt64, nftType: String, nftID: UInt64, salePaymentVaultType: String, salePrice: UFix64, saleCuts: [StoreFrontCut], flovatarMetadata: FlovatarMarketplace.FlovatarSaleData) { - self.listingId = storefrontID - self.nftIdentifier = nftType - self.nftId = nftID - self.ftTypeIdentifier = salePaymentVaultType - self.amount = salePrice - self.cuts = saleCuts - let f = flovatarMetadata - self.accessoryId = f.accessoryId - self.hatId = f.hatId - self.eyeglassesId = f.eyeglassesId - self.backgroundId = f.backgroundId - let d = f.metadata - self.mint = d.mint - self.series = d.series - self.creatorAddress = d.creatorAddress - self.components = d.getComponents() - self.rareCount = d.rareCount - self.epicCount = d.epicCount - self.legendaryCount = d.legendaryCount - self.tags={} - self.scalars={} - self.extra={} - } - } - - pub struct FlovatarComponentListing { - pub var listingId: UInt64 - pub let nftIdentifier: String - pub let nftId: UInt64 - pub let ftTypeIdentifier: String - pub let amount: UFix64 - pub let cuts: [StoreFrontCut] - pub let mint: UInt64 - pub let templateId: UInt64 - pub let name: String - pub let description: String - pub let category: String - pub let rarity: String - pub let color: String - pub let tags: {String : String} - pub let scalars: {String : UFix64} - pub let extra: {String : AnyStruct} - - init(storefrontID: UInt64, nftType: String, nftID: UInt64, salePaymentVaultType: String, salePrice: UFix64, saleCuts: [StoreFrontCut], flovatarComponentMetadata: FlovatarMarketplace.FlovatarComponentSaleData) { - self.listingId = storefrontID - self.nftIdentifier = nftType - self.nftId = nftID - self.ftTypeIdentifier = salePaymentVaultType - self.amount = salePrice - self.cuts = saleCuts - let f = flovatarComponentMetadata.metadata - self.mint = f.mint - self.templateId = f.templateId - self.name = f.name - self.description = f.description - self.category = f.category - self.rarity = f.rarity - self.color = f.color - self.tags={} - self.scalars={} - self.extra={} - } - } - - pub fun getStorefrontListing(user: Address, id: UInt64, type: Type) : StorefrontListing? { - - var listingsV1 : StorefrontListing? = nil - let account = getAccount(user) - let storefrontCap = account.getCapability<&NFTStorefront.Storefront{NFTStorefront.StorefrontPublic}>(NFTStorefront.StorefrontPublicPath) - - if storefrontCap.check() { - let storefrontRef=storefrontCap.borrow()! - for listingId in storefrontRef.getListingIDs() { - let listing = storefrontRef.borrowListing(listingResourceID: listingId)! - let d = listing.getDetails() - if d.nftID!=id || d.nftType != type { - continue - } - if d.purchased { - continue - } - let saleCuts : [StoreFrontCut] = [] - for cut in d.saleCuts { - saleCuts.append( - StoreFrontCut( - amount: cut.amount, - address: cut.receiver.address - ) - ) - } - listingsV1 = StorefrontListing(storefrontID: d.storefrontID, nftType: d.nftType.identifier, nftID: d.nftID, salePaymentVaultType: d.salePaymentVaultType.identifier, salePrice: d.salePrice, saleCuts: saleCuts, customID: nil, commissionAmount: nil, expiry: nil) - return listingsV1 - - } - } - return nil - } - - - pub fun getStorefrontV2Listing(user: Address, id: UInt64, type: Type) : StorefrontListing? { - var listingsV2 : StorefrontListing? = nil - let account = getAccount(user) - let storefrontV2Cap = account.getCapability<&NFTStorefrontV2.Storefront{NFTStorefrontV2.StorefrontPublic}>(NFTStorefrontV2.StorefrontPublicPath) - - if storefrontV2Cap.check() { - let storefrontRef=storefrontV2Cap.borrow()! - for listingId in storefrontRef.getListingIDs() { - let listing = storefrontRef.borrowListing(listingResourceID: listingId)! - let d = listing.getDetails() - if d.nftID!=id || d.nftType != type { - continue - } - if d.purchased { - continue - } - let saleCuts : [StoreFrontCut] = [] - for cut in d.saleCuts { - saleCuts.append( - StoreFrontCut( - amount: cut.amount, - address: cut.receiver.address - ) - ) - } - listingsV2 = StorefrontListing(storefrontID: d.storefrontID, nftType: d.nftType.identifier, nftID: d.nftID, salePaymentVaultType: d.salePaymentVaultType.identifier, salePrice: d.salePrice, saleCuts: saleCuts, customID: d.customID, commissionAmount: d.commissionAmount, expiry: d.expiry) - return listingsV2 - } - } - return nil - } - - pub fun getFlowtyListing(user: Address, id: UInt64, type: Type) : FlowtyListing? { - var flowty : FlowtyListing? = nil - let account = getAccount(user) - let flowtyCap = account.getCapability<&Flowty.FlowtyStorefront{Flowty.FlowtyStorefrontPublic}>(Flowty.FlowtyStorefrontPublicPath) - - if flowtyCap.check() { - let storefrontRef=flowtyCap.borrow()! - for listingId in storefrontRef.getListingIDs() { - let listing = storefrontRef.borrowListing(listingResourceID: listingId)! - let d = listing.getDetails() - if d.nftID!=id || d.nftType != type { - continue - } - if d.funded { - continue - } - let saleCuts : [StoreFrontCut] = [] - for cut in d.getPaymentCuts() { - saleCuts.append( - StoreFrontCut( - amount: cut.amount, - address: cut.receiver.address - ) - ) - } - flowty = FlowtyListing(flowtyStorefrontID: d.flowtyStorefrontID, funded: d.funded, nftType: d.nftType.identifier, nftID: d.nftID, amount: d.amount, interestRate: d.interestRate, term: d.term, paymentVaultType: d.paymentVaultType.identifier ,paymentCuts: saleCuts, listedTime: d.listedTime, royaltyRate: d.royaltyRate, expiresAfter: d.expiresAfter, repaymentAmount: d.getTotalPayment()) - return flowty - } - } - return nil - } - - pub fun getFlowtyRentals(user: Address, id: UInt64, type: Type) : FlowtyRental? { - - var flowtyRental : FlowtyRental? = nil - let account = getAccount(user) - let flowtyRentalCap = account.getCapability<&FlowtyRentals.FlowtyRentalsStorefront{FlowtyRentals.FlowtyRentalsStorefrontPublic}>(FlowtyRentals.FlowtyRentalsStorefrontPublicPath) - - if flowtyRentalCap.check() { - let storefrontRef=flowtyRentalCap.borrow()! - for listingId in storefrontRef.getListingIDs() { - let listing = storefrontRef.borrowListing(listingResourceID: listingId)! - let d = listing.getDetails() - if d.nftID!=id || d.nftType != type { - continue - } - if d.rented { - continue - } - let saleCuts : [StoreFrontCut] = [] - let cut = d.getPaymentCut() - saleCuts.append( - StoreFrontCut( - amount: cut.amount, - address: cut.receiver.address - ) - ) - - flowtyRental = FlowtyRental(flowtyStorefrontID: d.flowtyStorefrontID, rented: d.rented, nftType: d.nftType.identifier, nftID: d.nftID, amount: d.amount, deposit: d.deposit, term: d.term, paymentVaultType: d.paymentVaultType.identifier, reenableOnReturn: d.reenableOnReturn, paymentCuts: saleCuts, listedTime: d.listedTime, royaltyRate: d.royaltyRate, expiresAfter: d.expiresAfter, repaymentAmount: d.getTotalPayment(), renter: d.renter) - return flowtyRental - } - } - return nil - } - - pub fun getFlovatarListing(user: Address, id: UInt64, type: Type) : FlovatarListing? { - let nftType = Type<@Flovatar.NFT>() - if type != nftType { - return nil - } - let flovatar = FlovatarMarketplace.getFlovatarSale(address: user, id: id) - if flovatar == nil { - return nil - } - let f = flovatar! - let saleCuts : [StoreFrontCut] = [] - let creatorCut = Flovatar.getRoyaltyCut() - let marketCut = Flovatar.getMarketplaceCut() - saleCuts.appendAll([ - StoreFrontCut( - amount: creatorCut, - address: f.metadata.creatorAddress - ), - StoreFrontCut( - amount: marketCut, - address: FlovatarMarketplace.marketplaceWallet.address - ) - ]) - return FlovatarListing(storefrontID: f.id, nftType: nftType.identifier, nftID: f.id, salePaymentVaultType: Type<@FlowToken.Vault>().identifier, salePrice: f.price, saleCuts: saleCuts, flovatarMetadata: f) - } - - pub fun getFlovatarComponentListing(user: Address, id: UInt64, type: Type) : FlovatarComponentListing? { - let nftType = Type<@FlovatarComponent.NFT>() - if type != nftType { - return nil - } - let flovatar = FlovatarMarketplace.getFlovatarComponentSale(address: user, id: id) - if flovatar == nil { - return nil - } - let f = flovatar! - let saleCuts : [StoreFrontCut] = [] - let creatorCut = Flovatar.getRoyaltyCut() - let marketCut = Flovatar.getMarketplaceCut() - saleCuts.appendAll([ - StoreFrontCut( - amount: marketCut, - address: FlovatarMarketplace.marketplaceWallet.address - ) - ]) - return FlovatarComponentListing(storefrontID: f.id, nftType: nftType.identifier, nftID: f.id, salePaymentVaultType: Type<@FlowToken.Vault>().identifier, salePrice: f.price, saleCuts: saleCuts, flovatarComponentMetadata: f) - } +import "FIND" +import "NFTStorefront" +import "NFTStorefrontV2" +import "Flowty" +import "FlowtyRentals" +import "FlowToken" +import "FlovatarMarketplace" +import "Flovatar" +import "FlovatarComponent" + +access(all) contract FindUserStatus { + + access(all) struct StoreFrontCut { + access(all) let amount:UFix64 + access(all) let address: Address + access(all) let findName:String? + access(all) let tags: {String : String} + access(all) let scalars: {String : UFix64} + access(all) let extra: {String : AnyStruct} + + init(amount:UFix64, address:Address){ + self.amount=amount + self.address=address + self.findName= FIND.reverseLookup(address) + self.tags={} + self.scalars={} + self.extra={} + } + } + + + access(all) struct StorefrontListing { + access(all) var listingId: UInt64 + // if purchased is true -> don't show it + //access(all) var purchased: Bool + access(all) let nftIdentifier: String + access(all) let nftId: UInt64 + access(all) let ftTypeIdentifier: String + access(all) let amount: UFix64 + access(all) let cuts: [StoreFrontCut] + access(all) var customID: String? + access(all) let commissionAmount: UFix64? + access(all) let listingValidUntil: UInt64? + access(all) let tags: {String : String} + access(all) let scalars: {String : UFix64} + access(all) let extra: {String : AnyStruct} + + init(storefrontID: UInt64, nftType: String, nftID: UInt64, salePaymentVaultType: String, salePrice: UFix64, saleCuts: [StoreFrontCut], customID: String?, commissionAmount: UFix64?, expiry: UInt64?) { + self.listingId = storefrontID + self.nftIdentifier = nftType + self.nftId = nftID + self.ftTypeIdentifier = salePaymentVaultType + self.amount = salePrice + self.cuts = saleCuts + self.customID = customID + self.commissionAmount = commissionAmount + self.listingValidUntil = expiry + self.tags={} + self.scalars={} + self.extra={} + } + } + + access(all) struct FlowtyListing { + access(all) var listingId: UInt64 + access(all) var funded: Bool + access(all) let nftIdentifier: String + access(all) let nftId: UInt64 + access(all) let amount: UFix64 + access(all) let interestRate: UFix64 + access(all) var term: UFix64 + access(all) let paymentVaultType: String + + access(all) let paymentCuts: [StoreFrontCut] + access(all) var listedTime: UFix64 + access(all) var royaltyRate: UFix64 + access(all) var listingValidUntil: UFix64 + access(all) var repaymentAmount: UFix64 + + access(all) let tags: {String : String} + access(all) let scalars: {String : UFix64} + access(all) let extra: {String : AnyStruct} + + init(flowtyStorefrontID: UInt64, funded: Bool, nftType: String, nftID: UInt64, amount: UFix64, interestRate: UFix64, term: UFix64, paymentVaultType: String,paymentCuts: [StoreFrontCut], listedTime: UFix64, royaltyRate: UFix64, expiresAfter: UFix64, repaymentAmount: UFix64) { + self.listingId = flowtyStorefrontID + self.funded = funded + self.nftIdentifier = nftType + self.nftId = nftID + self.amount = amount + self.interestRate = interestRate + self.term = term + self.paymentVaultType = paymentVaultType + self.paymentCuts = paymentCuts + self.listedTime = listedTime + self.royaltyRate = royaltyRate + self.listingValidUntil = expiresAfter + listedTime + self.repaymentAmount = repaymentAmount + self.tags={} + self.scalars={} + self.extra={} + } + } + + access(all) struct FlowtyRental { + access(all) var listingId: UInt64 + access(all) var rented: Bool + access(all) let nftIdentifier: String + access(all) let nftId: UInt64 + access(all) let amount: UFix64 + access(all) let deposit: UFix64 + access(all) var term: UFix64 + access(all) let paymentVaultType: String + access(all) let reenableOnReturn: Bool + + access(all) let paymentCuts: [StoreFrontCut] + access(all) var listedTime: UFix64 + access(all) var royaltyRate: UFix64 + access(all) var listingValidUntil: UFix64 + access(all) var repaymentAmount: UFix64 + access(all) var renter: Address? + access(all) var renterName: String? + + access(all) let tags: {String : String} + access(all) let scalars: {String : UFix64} + access(all) let extra: {String : AnyStruct} + + init(flowtyStorefrontID: UInt64, rented: Bool, nftType: String, nftID: UInt64, amount: UFix64, deposit: UFix64, term: UFix64, paymentVaultType: String, reenableOnReturn:Bool, paymentCuts: [StoreFrontCut], listedTime: UFix64, royaltyRate: UFix64, expiresAfter: UFix64, repaymentAmount: UFix64, renter: Address?) { + self.listingId = flowtyStorefrontID + self.rented = rented + self.nftIdentifier = nftType + self.nftId = nftID + self.deposit = deposit + self.amount = amount + self.term = term + self.paymentVaultType = paymentVaultType + self.reenableOnReturn = reenableOnReturn + self.paymentCuts = paymentCuts + self.listedTime = listedTime + self.royaltyRate = royaltyRate + self.listingValidUntil = expiresAfter + listedTime + self.repaymentAmount = repaymentAmount + self.renter = renter + self.renterName = nil + if renter != nil { + self.renterName = FIND.reverseLookup(renter!) + } + self.tags={} + self.scalars={} + self.extra={} + } + } + + access(all) struct FlovatarListing { + access(all) var listingId: UInt64 + access(all) let nftIdentifier: String + access(all) let nftId: UInt64 + access(all) let ftTypeIdentifier: String + access(all) let amount: UFix64 + access(all) let cuts: [StoreFrontCut] + access(all) let accessoryId: UInt64? + access(all) let hatId: UInt64? + access(all) let eyeglassesId: UInt64? + access(all) let backgroundId: UInt64? + access(all) let mint: UInt64 + access(all) let series: UInt32 + access(all) let creatorAddress: Address + access(all) let components: {String: UInt64} + access(all) let rareCount: UInt8 + access(all) let epicCount: UInt8 + access(all) let legendaryCount: UInt8 + access(all) let tags: {String : String} + access(all) let scalars: {String : UFix64} + access(all) let extra: {String : AnyStruct} + + init(storefrontID: UInt64, nftType: String, nftID: UInt64, salePaymentVaultType: String, salePrice: UFix64, saleCuts: [StoreFrontCut], flovatarMetadata: FlovatarMarketplace.FlovatarSaleData) { + self.listingId = storefrontID + self.nftIdentifier = nftType + self.nftId = nftID + self.ftTypeIdentifier = salePaymentVaultType + self.amount = salePrice + self.cuts = saleCuts + let f = flovatarMetadata + self.accessoryId = f.accessoryId + self.hatId = f.hatId + self.eyeglassesId = f.eyeglassesId + self.backgroundId = f.backgroundId + let d = f.metadata + self.mint = d.mint + self.series = d.series + self.creatorAddress = d.creatorAddress + self.components = d.getComponents() + self.rareCount = d.rareCount + self.epicCount = d.epicCount + self.legendaryCount = d.legendaryCount + self.tags={} + self.scalars={} + self.extra={} + } + } + + access(all) struct FlovatarComponentListing { + access(all) var listingId: UInt64 + access(all) let nftIdentifier: String + access(all) let nftId: UInt64 + access(all) let ftTypeIdentifier: String + access(all) let amount: UFix64 + access(all) let cuts: [StoreFrontCut] + access(all) let mint: UInt64 + access(all) let templateId: UInt64 + access(all) let name: String + access(all) let description: String + access(all) let category: String + access(all) let rarity: String + access(all) let color: String + access(all) let tags: {String : String} + access(all) let scalars: {String : UFix64} + access(all) let extra: {String : AnyStruct} + + init(storefrontID: UInt64, nftType: String, nftID: UInt64, salePaymentVaultType: String, salePrice: UFix64, saleCuts: [StoreFrontCut], flovatarComponentMetadata: FlovatarMarketplace.FlovatarComponentSaleData) { + self.listingId = storefrontID + self.nftIdentifier = nftType + self.nftId = nftID + self.ftTypeIdentifier = salePaymentVaultType + self.amount = salePrice + self.cuts = saleCuts + let f = flovatarComponentMetadata.metadata + self.mint = f.mint + self.templateId = f.templateId + self.name = f.name + self.description = f.description + self.category = f.category + self.rarity = f.rarity + self.color = f.color + self.tags={} + self.scalars={} + self.extra={} + } + } + + access(all) fun getStorefrontListing(user: Address, id: UInt64, type: Type) : StorefrontListing? { + + var listingsV1 : StorefrontListing? = nil + let account = getAccount(user) + let storefrontCap = account.capabilities.get<&{NFTStorefront.StorefrontPublic}>(NFTStorefront.StorefrontPublicPath)! + + if storefrontCap.check() { + let storefrontRef=storefrontCap.borrow()! + for listingId in storefrontRef.getListingIDs() { + let listing = storefrontRef.borrowListing(listingResourceID: listingId)! + let d = listing.getDetails() + if d.nftID!=id || d.nftType != type { + continue + } + if d.purchased { + continue + } + let saleCuts : [StoreFrontCut] = [] + for cut in d.saleCuts { + saleCuts.append( + StoreFrontCut( + amount: cut.amount, + address: cut.receiver.address + ) + ) + } + listingsV1 = StorefrontListing(storefrontID: d.storefrontID, nftType: d.nftType.identifier, nftID: d.nftID, salePaymentVaultType: d.salePaymentVaultType.identifier, salePrice: d.salePrice, saleCuts: saleCuts, customID: nil, commissionAmount: nil, expiry: nil) + return listingsV1 + + } + } + return nil + } + + + access(all) fun getStorefrontV2Listing(user: Address, id: UInt64, type: Type) : StorefrontListing? { + var listingsV2 : StorefrontListing? = nil + let account = getAccount(user) + let storefrontV2Cap = account.capabiltiies.get<&{NFTStorefrontV2.StorefrontPublic}>(NFTStorefrontV2.StorefrontPublicPath)! + + if storefrontV2Cap.check() { + let storefrontRef=storefrontV2Cap.borrow()! + for listingId in storefrontRef.getListingIDs() { + let listing = storefrontRef.borrowListing(listingResourceID: listingId)! + let d = listing.getDetails() + if d.nftID!=id || d.nftType != type { + continue + } + if d.purchased { + continue + } + let saleCuts : [StoreFrontCut] = [] + for cut in d.saleCuts { + saleCuts.append( + StoreFrontCut( + amount: cut.amount, + address: cut.receiver.address + ) + ) + } + listingsV2 = StorefrontListing(storefrontID: d.storefrontID, nftType: d.nftType.identifier, nftID: d.nftID, salePaymentVaultType: d.salePaymentVaultType.identifier, salePrice: d.salePrice, saleCuts: saleCuts, customID: d.customID, commissionAmount: d.commissionAmount, expiry: d.expiry) + return listingsV2 + } + } + return nil + } + + access(all) fun getFlowtyListing(user: Address, id: UInt64, type: Type) : FlowtyListing? { + var flowty : FlowtyListing? = nil + let account = getAccount(user) + let flowtyCap = account.capabilities.get<&Flowty.FlowtyStorefront>(Flowty.FlowtyStorefrontPublicPath)! + + if flowtyCap.check() { + let storefrontRef=flowtyCap.borrow()! + for listingId in storefrontRef.getListingIDs() { + let listing = storefrontRef.borrowListing(listingResourceID: listingId)! + let d = listing.getDetails() + if d.nftID!=id || d.nftType != type { + continue + } + if d.funded { + continue + } + let saleCuts : [StoreFrontCut] = [] + for cut in d.getPaymentCuts() { + saleCuts.append( + StoreFrontCut( + amount: cut.amount, + address: cut.receiver.address + ) + ) + } + flowty = FlowtyListing(flowtyStorefrontID: d.flowtyStorefrontID, funded: d.funded, nftType: d.nftType.identifier, nftID: d.nftID, amount: d.amount, interestRate: d.interestRate, term: d.term, paymentVaultType: d.paymentVaultType.identifier ,paymentCuts: saleCuts, listedTime: d.listedTime, royaltyRate: d.royaltyRate, expiresAfter: d.expiresAfter, repaymentAmount: d.getTotalPayment()) + return flowty + } + } + return nil + } + + access(all) getFlowtyRentals(user: Address, id: UInt64, type: Type) : FlowtyRental? { + + var flowtyRental : FlowtyRental? = nil + let account = getAccount(user) + let flowtyRentalCap = account.capabilities.get<&FlowtyRentals.FlowtyRentalsStorefront>(FlowtyRentals.FlowtyRentalsStorefrontPublicPath)! + + if flowtyRentalCap.check() { + let storefrontRef=flowtyRentalCap.borrow()! + for listingId in storefrontRef.getListingIDs() { + let listing = storefrontRef.borrowListing(listingResourceID: listingId)! + let d = listing.getDetails() + if d.nftID!=id || d.nftType != type { + continue + } + if d.rented { + continue + } + let saleCuts : [StoreFrontCut] = [] + let cut = d.getPaymentCut() + saleCuts.append( + StoreFrontCut( + amount: cut.amount, + address: cut.receiver.address + ) + ) + + flowtyRental = FlowtyRental(flowtyStorefrontID: d.flowtyStorefrontID, rented: d.rented, nftType: d.nftType.identifier, nftID: d.nftID, amount: d.amount, deposit: d.deposit, term: d.term, paymentVaultType: d.paymentVaultType.identifier, reenableOnReturn: d.reenableOnReturn, paymentCuts: saleCuts, listedTime: d.listedTime, royaltyRate: d.royaltyRate, expiresAfter: d.expiresAfter, repaymentAmount: d.getTotalPayment(), renter: d.renter) + return flowtyRental + } + } + return nil + } + + access(all) getFlovatarListing(user: Address, id: UInt64, type: Type) : FlovatarListing? { + let nftType = Type<@Flovatar.NFT>() + if type != nftType { + return nil + } + let flovatar = FlovatarMarketplace.getFlovatarSale(address: user, id: id) + if flovatar == nil { + return nil + } + let f = flovatar! + let saleCuts : [StoreFrontCut] = [] + let creatorCut = Flovatar.getRoyaltyCut() + let marketCut = Flovatar.getMarketplaceCut() + saleCuts.appendAll([ + StoreFrontCut( + amount: creatorCut, + address: f.metadata.creatorAddress + ), + StoreFrontCut( + amount: marketCut, + address: FlovatarMarketplace.marketplaceWallet.address + ) + ]) + return FlovatarListing(storefrontID: f.id, nftType: nftType.identifier, nftID: f.id, salePaymentVaultType: Type<@FlowToken.Vault>().identifier, salePrice: f.price, saleCuts: saleCuts, flovatarMetadata: f) + } + + access(all) getFlovatarComponentListing(user: Address, id: UInt64, type: Type) : FlovatarComponentListing? { + let nftType = Type<@FlovatarComponent.NFT>() + if type != nftType { + return nil + } + let flovatar = FlovatarMarketplace.getFlovatarComponentSale(address: user, id: id) + if flovatar == nil { + return nil + } + let f = flovatar! + let saleCuts : [StoreFrontCut] = [] + let creatorCut = Flovatar.getRoyaltyCut() + let marketCut = Flovatar.getMarketplaceCut() + saleCuts.appendAll([ + StoreFrontCut( + amount: marketCut, + address: FlovatarMarketplace.marketplaceWallet.address + ) + ]) + return FlovatarComponentListing(storefrontID: f.id, nftType: nftType.identifier, nftID: f.id, salePaymentVaultType: Type<@FlowToken.Vault>().identifier, salePrice: f.price, saleCuts: saleCuts, flovatarComponentMetadata: f) + } } - \ No newline at end of file + diff --git a/contracts/FindUtils.cdc b/contracts/FindUtils.cdc index 1dc32f19..26361d95 100644 --- a/contracts/FindUtils.cdc +++ b/contracts/FindUtils.cdc @@ -1,7 +1,6 @@ -pub contract FindUtils { - - pub fun deDupTypeArray(_ arr:[Type]) : [Type] { +access(all) contract FindUtils { + access(all) fun deDupTypeArray(_ arr:[Type]) : [Type] { let removeElement = fun (_ arr: [Type], _ element: Type): [Type] { var i = arr.firstIndex(of: element) let firstIndex = i @@ -22,10 +21,9 @@ pub contract FindUtils { c = c + 1 } return arr - } - pub fun joinString(_ arr:[String], sep: String) : String { + access(all) fun joinString(_ arr:[String], sep: String) : String { var message="" for i, key in arr { if i > 0 { @@ -36,7 +34,7 @@ pub contract FindUtils { return message } - pub fun joinMapToString( _ map:{String:String}) : String { + access(all) fun joinMapToString( _ map:{String:String}) : String { var message="" for i, key in map.keys { if i > 0 { @@ -47,14 +45,14 @@ pub contract FindUtils { return message } - pub fun containsChar(_ string: String, char: Character) : Bool { + access(all) fun containsChar(_ string: String, char: Character) : Bool { if var index = string.utf8.firstIndex(of: char.toString().utf8[0]) { return true } return false } - pub fun contains(_ string: String, element: String) : Bool { + access(all) fun contains(_ string: String, element: String) : Bool { if element.length == 0 { return true } @@ -70,7 +68,7 @@ pub contract FindUtils { return false } - pub fun trimSuffix(_ name: String, suffix: String) : String { + access(all) fun trimSuffix(_ name: String, suffix: String) : String { if !self.hasSuffix(name, suffix:suffix) { return name } @@ -78,21 +76,21 @@ pub contract FindUtils { return name.slice(from: 0, upTo: pos) } - pub fun hasSuffix(_ string: String, suffix: String) : Bool { + access(all) fun hasSuffix(_ string: String, suffix: String) : Bool { if suffix.length > string.length { return false } return string.slice(from: string.length - suffix.length, upTo: string.length) == suffix } - pub fun hasPrefix(_ string: String, prefix: String) : Bool { + access(all) fun hasPrefix(_ string: String, prefix: String) : Bool { if prefix.length > string.length { return false } return string.slice(from: 0, upTo: prefix.length) == prefix } - pub fun splitString(_ string: String, sep: Character) : [String] { + access(all) fun splitString(_ string: String, sep: Character) : [String] { if var index = string.utf8.firstIndex(of: sep.toString().utf8[0]) { let first = string.slice(from: 0, upTo: index) let second = string.slice(from: index + 1, upTo: string.length) @@ -103,7 +101,7 @@ pub contract FindUtils { return [string] } - pub fun toUpper(_ string: String) : String { + access(all) fun toUpper(_ string: String) : String { let map = FindUtils.getLowerCaseToUpperCase() var res = "" var i = 0 @@ -115,7 +113,7 @@ pub contract FindUtils { return res } - pub fun firstUpperLetter(_ string: String) : String { + access(all) fun firstUpperLetter(_ string: String) : String { if string.length < 1 { return string } @@ -127,7 +125,7 @@ pub contract FindUtils { return string } - pub fun to_snake_case(_ string: String) : String { + access(all) fun to_snake_case(_ string: String) : String { var res = "" var i = 0 let map = FindUtils.getUpperCaseToLowerCase() @@ -154,7 +152,7 @@ pub contract FindUtils { return res } - pub fun toCamelCase(_ string: String) : String { + access(all) fun toCamelCase(_ string: String) : String { var res = "" var i = 0 let map = FindUtils.getLowerCaseToUpperCase() @@ -180,7 +178,7 @@ pub contract FindUtils { return res } - pub fun getLowerCaseToUpperCase() : {String : String} { + access(all) fun getLowerCaseToUpperCase() : {String : String} { return { "a" : "A", "b" : "B", @@ -211,7 +209,7 @@ pub contract FindUtils { } } - pub fun getUpperCaseToLowerCase() : {String : String} { + access(all) fun getUpperCaseToLowerCase() : {String : String} { return { "A" : "a", "B" : "b", @@ -241,6 +239,5 @@ pub contract FindUtils { "Z" : "z" } } - } diff --git a/contracts/FindVerifier.cdc b/contracts/FindVerifier.cdc index 7d79b4c7..ecc6fcac 100644 --- a/contracts/FindVerifier.cdc +++ b/contracts/FindVerifier.cdc @@ -1,303 +1,296 @@ -import FLOAT from "../contracts/standard/FLOAT.cdc" -import FIND from "../contracts/FIND.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" - -pub contract FindVerifier { - - pub struct interface Verifier { - pub let description : String - pub fun verify(_ param: {String : AnyStruct}) : Bool - } - - pub struct HasOneFLOAT : Verifier { - pub let floatEventIds : [UInt64] - pub let description: String - - init(_ floatEventIds: [UInt64]) { - pre{ - floatEventIds.length > 0 : "list cannot be empty" - } - self.floatEventIds = floatEventIds - var desc = "User with one of these FLOATs are verified : " - for floatEventId in floatEventIds { - desc = desc.concat(floatEventId.toString()).concat(", ") - } - desc = desc.slice(from:0 ,upTo:desc.length-2) - self.description = desc - } - - pub fun verify(_ param: {String : AnyStruct}) : Bool { - - if self.floatEventIds.length == 0 { - return true - } - - let user : Address = param["address"]! as! Address - let float = getAccount(user).getCapability(FLOAT.FLOATCollectionPublicPath).borrow<&FLOAT.Collection{FLOAT.CollectionPublic}>() - - if float == nil { - return false - } - - let floatsCollection=float! - - for eventId in self.floatEventIds { - let ids = floatsCollection.ownedIdsFromEvent(eventId: eventId) - if ids.length > 0 { - return true - } - } - return false - } - - } - - pub struct HasAllFLOAT : Verifier { - pub let floatEventIds : [UInt64] - pub let description: String - - init(_ floatEventIds : [UInt64]) { - pre{ - floatEventIds.length > 0 : "list cannot be empty" - } - self.floatEventIds = floatEventIds - var desc = "User with all of these FLOATs are verified : " - for floatEventId in floatEventIds { - desc = desc.concat(floatEventId.toString()).concat(", ") - } - desc = desc.slice(from:0 ,upTo:desc.length-2) - self.description = desc - } - - pub fun verify(_ param: {String : AnyStruct}) : Bool { - - if self.floatEventIds.length == 0 { - return true - } - - let user : Address = param["address"]! as! Address - let float = getAccount(user).getCapability(FLOAT.FLOATCollectionPublicPath).borrow<&FLOAT.Collection{FLOAT.CollectionPublic}>() - - if float == nil { - return false - } - - let floatsCollection=float! - - let checked : [UInt64] = [] - for eventId in self.floatEventIds { - let ids = floatsCollection.ownedIdsFromEvent(eventId: eventId) - if ids.length > 0 { - checked.append(ids[0]) - } - } - - if checked.length == self.floatEventIds.length { - return true - } - return false - } - } - - pub struct IsInWhiteList : Verifier { - pub let addressList : [Address] - pub let description: String - - init(_ addressList: [Address]) { - pre{ - addressList.length > 0 : "list cannot be empty" - } - self.addressList = addressList - var desc = "Only these wallet addresses are verified : " - for addr in addressList { - desc = desc.concat(addr.toString()).concat(", ") - } - desc = desc.slice(from:0 ,upTo:desc.length-2) - self.description = desc - } - - pub fun verify(_ param: {String : AnyStruct}) : Bool { - let user : Address = param["address"]! as! Address - return self.addressList.contains(user) - } - } - - // Has Find Name - pub struct HasFINDName : Verifier { - pub let findNames: [String] - pub let description: String - - init(_ findNames: [String]) { - pre{ - findNames.length > 0 : "list cannot be empty" - } - self.findNames = findNames - var desc = "Users with one of these find names are verified : " - for name in findNames { - desc = desc.concat(name.concat(", ")) - } - desc = desc.slice(from:0 ,upTo:desc.length-2) - self.description = desc - } - - pub fun verify(_ param: {String : AnyStruct}) : Bool { - - if self.findNames.length == 0 { - return true - } - - let user : Address = param["address"]! as! Address - - let cap = getAccount(user).getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !cap.check() { - return false - } - let ref = cap.borrow()! - let names = ref.getLeases() - - var longerArray = self.findNames - var shorterArray = names - - if shorterArray.length > longerArray.length { - longerArray = names - shorterArray = self.findNames - } - - for name in shorterArray { - if longerArray.contains(name) { - return true - } - } - - return false - } - } - - // Has a no. of NFTs in given path - pub struct HasNFTsInPath : Verifier { - pub let path: PublicPath - pub let threshold: Int - pub let description: String - - init(path: PublicPath , threshold: Int ) { - pre { - threshold > 0 : "threshold should be greater than zero" - } - self.path = path - self.threshold = threshold - var desc = "Users with at least ".concat(threshold.toString()).concat(" nos. of NFT in path ".concat(path.toString()).concat(" are verified")) - self.description = desc - } - - pub fun verify(_ param: {String : AnyStruct}) : Bool { - if self.threshold == 0 { - return true - } - - let user : Address = param["address"]! as! Address - - let cap = getAccount(user).getCapability<&{NonFungibleToken.CollectionPublic}>(self.path) - if !cap.check() { - let mvCap = getAccount(user).getCapability<&{MetadataViews.ResolverCollection}>(self.path) - if !mvCap.check() { - return false - } - return mvCap.borrow()!.getIDs().length >= self.threshold - } - return cap.borrow()!.getIDs().length >= self.threshold - } - } - - // Has given NFTs in given path with rarity (can cache this with uuid) - pub struct HasNFTWithRarities : Verifier { - pub let path: PublicPath - pub let rarities: [MetadataViews.Rarity] - access(self) let rarityIdentifiers: [String] - pub let description: String - - // leave this here for caching in case useful, but people might be able to change rarity - access(self) let cache : {UInt64 : Bool} - - init(path: PublicPath , rarities: [MetadataViews.Rarity]) { - pre{ - rarities.length > 0 : "list cannot be empty" - } - self.path = path - self.rarities = rarities - let rarityIdentifiers : [String] = [] - var rarityDesc = "" - for r in rarities { - var rI = r.description ?? "" - if r.description != nil { - rarityDesc = rarityDesc.concat("description : ".concat(r.description!).concat(", ")) - } - - if r.score != nil { - rI = rI.concat(r.score!.toString()) - rarityDesc = rarityDesc.concat("score : ".concat(r.score!.toString()).concat(", ")) - } else { - rI = rI.concat(" ") - } - - if r.max != nil { - rI = rI.concat(r.max!.toString()) - rarityDesc = rarityDesc.concat("max score : ".concat(r.max!.toString()).concat(", ")) - } else { - rI = rI.concat(" ") - } - - if rI == " " { - panic("Rarity cannot be all nil") - } - - rarityDesc = rarityDesc.slice(from:0 ,upTo:rarityDesc.length-2).concat("; ") - rarityIdentifiers.append(rI) - } - self.rarityIdentifiers = rarityIdentifiers - self.cache = {} - var desc = "Users with at least 1 NFT in path ".concat(path.toString()).concat(" with one of these rarities are verified : ").concat(rarityDesc) - self.description = desc - } - - access(self) fun rarityToIdentifier(_ r: MetadataViews.Rarity) : String { - var rI = r.description ?? "" - if r.score != nil { - rI = rI.concat(r.score!.toString()) - } - if r.max != nil { - rI = rI.concat(r.max!.toString()) - } - return rI - } - - pub fun verify(_ param: {String : AnyStruct}) : Bool { - if self.rarities.length == 0 { - return true - } - - let user : Address = param["address"]! as! Address - - let mvCap = getAccount(user).getCapability<&{MetadataViews.ResolverCollection}>(self.path) - if !mvCap.check() { - return false - } - let ref = mvCap.borrow()! - - for id in ref.getIDs() { - let resolver = ref.borrowViewResolver(id: id) - if let r = MetadataViews.getRarity(resolver) { - if self.rarityIdentifiers.contains(self.rarityToIdentifier(r)) { - return true - } - } - } - return false - } - - } - - - - -} \ No newline at end of file +import "FLOAT" +import "FIND" +import "NonFungibleToken" +import "MetadataViews" +import "ViewResolver" + +access(all) contract FindVerifier { + + access(all) struct interface Verifier { + access(all) let description : String + access(all) fun verify(_ param: {String : AnyStruct}) : Bool + } + + access(all) struct HasOneFLOAT : Verifier { + access(all) let floatEventIds : [UInt64] + access(all) let description: String + + init(_ floatEventIds: [UInt64]) { + pre{ + floatEventIds.length > 0 : "list cannot be empty" + } + self.floatEventIds = floatEventIds + var desc = "User with one of these FLOATs are verified : " + for floatEventId in floatEventIds { + desc = desc.concat(floatEventId.toString()).concat(", ") + } + desc = desc.slice(from:0 ,upTo:desc.length-2) + self.description = desc + } + + access(all) fun verify(_ param: {String : AnyStruct}) : Bool { + + if self.floatEventIds.length == 0 { + return true + } + + let user : Address = param["address"]! as! Address + let float = getAccount(user).capabilities.borrow<&FLOAT.Collection>(FLOAT.FLOATCollectionPublicPath) + + if float == nil { + return false + } + + let floatsCollection=float! + + for eventId in self.floatEventIds { + let ids = floatsCollection.ownedIdsFromEvent(eventId: eventId) + if ids.length > 0 { + return true + } + } + return false + } + + } + + access(all) struct HasAllFLOAT : Verifier { + access(all) let floatEventIds : [UInt64] + access(all) let description: String + + init(_ floatEventIds : [UInt64]) { + pre{ + floatEventIds.length > 0 : "list cannot be empty" + } + self.floatEventIds = floatEventIds + var desc = "User with all of these FLOATs are verified : " + for floatEventId in floatEventIds { + desc = desc.concat(floatEventId.toString()).concat(", ") + } + desc = desc.slice(from:0 ,upTo:desc.length-2) + self.description = desc + } + + access(all) fun verify(_ param: {String : AnyStruct}) : Bool { + + if self.floatEventIds.length == 0 { + return true + } + + let user : Address = param["address"]! as! Address + let float = getAccount(user).capabilities.borrow<&FLOAT.Collection>(FLOAT.FLOATCollectionPublicPath) + + if float == nil { + return false + } + + let floatsCollection=float! + + let checked : [UInt64] = [] + for eventId in self.floatEventIds { + let ids = floatsCollection.ownedIdsFromEvent(eventId: eventId) + if ids.length > 0 { + checked.append(ids[0]) + } + } + + if checked.length == self.floatEventIds.length { + return true + } + return false + } + } + + access(all) struct IsInWhiteList : Verifier { + access(all) let addressList : [Address] + access(all) let description: String + + init(_ addressList: [Address]) { + pre{ + addressList.length > 0 : "list cannot be empty" + } + self.addressList = addressList + var desc = "Only these wallet addresses are verified : " + for addr in addressList { + desc = desc.concat(addr.toString()).concat(", ") + } + desc = desc.slice(from:0 ,upTo:desc.length-2) + self.description = desc + } + + access(all) fun verify(_ param: {String : AnyStruct}) : Bool { + let user : Address = param["address"]! as! Address + return self.addressList.contains(user) + } + } + + // Has Find Name + access(all) struct HasFINDName : Verifier { + access(all) let findNames: [String] + access(all) let description: String + + init(_ findNames: [String]) { + pre{ + findNames.length > 0 : "list cannot be empty" + } + self.findNames = findNames + var desc = "Users with one of these find names are verified : " + for name in findNames { + desc = desc.concat(name.concat(", ")) + } + desc = desc.slice(from:0 ,upTo:desc.length-2) + self.description = desc + } + + access(all) fun verify(_ param: {String : AnyStruct}) : Bool { + + if self.findNames.length == 0 { + return true + } + + let user : Address = param["address"]! as! Address + + let cap = getAccount(user).capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) + if !cap.check() { + return false + } + let ref = cap.borrow()! + let names = ref.getLeases() + + var longerArray = self.findNames + var shorterArray = names + + if shorterArray.length > longerArray.length { + longerArray = names + shorterArray = self.findNames + } + + for name in shorterArray { + if longerArray.contains(name) { + return true + } + } + + return false + } + } + + // Has a no. of NFTs in given path + access(all) struct HasNFTsInPath : Verifier { + access(all) let path: PublicPath + access(all) let threshold: Int + access(all) let description: String + + init(path: PublicPath , threshold: Int ) { + pre { + threshold > 0 : "threshold should be greater than zero" + } + self.path = path + self.threshold = threshold + var desc = "Users with at least ".concat(threshold.toString()).concat(" nos. of NFT in path ".concat(path.toString()).concat(" are verified")) + self.description = desc + } + + access(all) fun verify(_ param: {String : AnyStruct}) : Bool { + if self.threshold == 0 { + return true + } + + let user : Address = param["address"]! as! Address + + let ref = getAccount(user).capabilities.borrow<&{NonFungibleToken.Collection}>(self.path) + + if ref == nil{ + return false + } + return ref!.getIDs().length >= self.threshold + } + } + + // Has given NFTs in given path with rarity (can cache this with uuid) + access(all) struct HasNFTWithRarities : Verifier { + access(all) let path: PublicPath + access(all) let rarities: [MetadataViews.Rarity] + access(self) let rarityIdentifiers: [String] + access(all) let description: String + + // leave this here for caching in case useful, but people might be able to change rarity + access(self) let cache : {UInt64 : Bool} + + init(path: PublicPath , rarities: [MetadataViews.Rarity]) { + pre{ + rarities.length > 0 : "list cannot be empty" + } + self.path = path + self.rarities = rarities + let rarityIdentifiers : [String] = [] + var rarityDesc = "" + for r in rarities { + var rI = r.description ?? "" + if r.description != nil { + rarityDesc = rarityDesc.concat("description : ".concat(r.description!).concat(", ")) + } + + if r.score != nil { + rI = rI.concat(r.score!.toString()) + rarityDesc = rarityDesc.concat("score : ".concat(r.score!.toString()).concat(", ")) + } else { + rI = rI.concat(" ") + } + + if r.max != nil { + rI = rI.concat(r.max!.toString()) + rarityDesc = rarityDesc.concat("max score : ".concat(r.max!.toString()).concat(", ")) + } else { + rI = rI.concat(" ") + } + + if rI == " " { + panic("Rarity cannot be all nil") + } + + rarityDesc = rarityDesc.slice(from:0 ,upTo:rarityDesc.length-2).concat("; ") + rarityIdentifiers.append(rI) + } + self.rarityIdentifiers = rarityIdentifiers + self.cache = {} + var desc = "Users with at least 1 NFT in path ".concat(path.toString()).concat(" with one of these rarities are verified : ").concat(rarityDesc) + self.description = desc + } + + access(self) fun rarityToIdentifier(_ r: MetadataViews.Rarity) : String { + var rI = r.description ?? "" + if r.score != nil { + rI = rI.concat(r.score!.toString()) + } + if r.max != nil { + rI = rI.concat(r.max!.toString()) + } + return rI + } + + access(all) fun verify(_ param: {String : AnyStruct}) : Bool { + if self.rarities.length == 0 { + return true + } + + let user : Address = param["address"]! as! Address + + let mvCap = getAccount(user).capabilities.borrow<&{ViewResolver.ResolverCollection}>(self.path) + if mvCap ==nil{ + return false + } + let ref = mvCap! + + for id in ref.getIDs() { + let resolver = ref.borrowViewResolver(id: id)! + if let r = MetadataViews.getRarity(resolver) { + if self.rarityIdentifiers.contains(self.rarityToIdentifier(r)) { + return true + } + } + } + return false + } + } +} diff --git a/contracts/FindViews.cdc b/contracts/FindViews.cdc index b991f14f..28f1e44b 100644 --- a/contracts/FindViews.cdc +++ b/contracts/FindViews.cdc @@ -1,67 +1,64 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" - -pub contract FindViews { - - pub struct OnChainFile : MetadataViews.File{ - pub let content: String - pub let mediaType: String - pub let protocol: String - - init(content:String, mediaType: String) { - self.content=content - self.protocol="onChain" - self.mediaType=mediaType - } - - pub fun uri(): String { - return "data:".concat(self.mediaType).concat(",").concat(self.content) - } - } - - pub struct SharedMedia : MetadataViews.File { - pub let mediaType: String - pub let pointer: ViewReadPointer - pub let protocol: String - - init(pointer: ViewReadPointer, mediaType: String) { - self.pointer=pointer - self.mediaType=mediaType - self.protocol="shared" - - if pointer.resolveView(Type()) == nil { - panic("Cannot create shared media if the pointer does not contain StringMedia") - } - } - - pub fun uri(): String { - let media = self.pointer.resolveView(Type()) - if media == nil { - return "" - } - return (media as! OnChainFile).uri() - } - } - - pub resource interface VaultViews { - pub var balance: UFix64 - - pub fun getViews() : [Type] - pub fun resolveView(_ view: Type): AnyStruct? +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "ViewResolver" + +access(all) contract FindViews { + + access(all) struct OnChainFile : MetadataViews.File{ + access(all) let content: String + access(all) let mediaType: String + access(all) let protocol: String + + init(content:String, mediaType: String) { + self.content=content + self.protocol="onChain" + self.mediaType=mediaType + } + + access(all) view fun uri(): String { + return "data:".concat(self.mediaType).concat(",").concat(self.content) + } } - pub struct FTVaultData { - pub let tokenAlias: String - pub let storagePath: StoragePath - pub let receiverPath: PublicPath - pub let balancePath: PublicPath - pub let providerPath: PrivatePath - pub let vaultType: Type - pub let receiverType: Type - pub let balanceType: Type - pub let providerType: Type - pub let createEmptyVault: ((): @FungibleToken.Vault) + access(all) struct SharedMedia : MetadataViews.File { + access(all) let mediaType: String + access(all) let pointer: ViewReadPointer + access(all) let protocol: String + + init(pointer: ViewReadPointer, mediaType: String) { + self.pointer=pointer + self.mediaType=mediaType + self.protocol="shared" + + if pointer.resolveView(Type()) == nil { + panic("Cannot create shared media if the pointer does not contain StringMedia") + } + } + + // todo: this is not working so we have a workaround in the contract + access(all) view fun uri(): String { + return "data:".concat(self.mediaType).concat(",").concat(self.protocol) + } + } + + access(all) resource interface VaultViews { + access(all) var balance: UFix64 + access(all) view fun getViews() : [Type] + access(all) fun resolveView(_ view: Type): AnyStruct? + } + + access(all) struct FTVaultData { + access(all) let tokenAlias: String + access(all) let storagePath: StoragePath + access(all) let receiverPath: PublicPath + access(all) let balancePath: PublicPath + access(all) let providerPath: PrivatePath + access(all) let vaultType: Type + access(all) let receiverType: Type + access(all) let balanceType: Type + access(all) let providerType: Type + access(all) let createEmptyVault: (fun(): @{FungibleToken.Vault}) init( tokenAlias: String, @@ -73,11 +70,11 @@ pub contract FindViews { receiverType: Type, balanceType: Type, providerType: Type, - createEmptyVault: ((): @FungibleToken.Vault) + createEmptyVault: (fun(): @{FungibleToken.Vault}) ) { pre { receiverType.isSubtype(of: Type<&{FungibleToken.Receiver}>()): "Receiver type must include FungibleToken.Receiver interfaces." - balanceType.isSubtype(of: Type<&{FungibleToken.Balance}>()): "Balance type must include FungibleToken.Balance interfaces." + balanceType.isSubtype(of: Type<&{FungibleToken.Vault}>()): "Balance type must include FungibleToken.Vault interfaces." providerType.isSubtype(of: Type<&{FungibleToken.Provider}>()): "Provider type must include FungibleToken.Provider interface." } self.tokenAlias=tokenAlias @@ -93,300 +90,314 @@ pub contract FindViews { } } - // This is an example taken from Versus - pub struct CreativeWork { - pub let artist: String - pub let name: String - pub let description: String - pub let type: String - - init(artist: String, name: String, description: String, type: String) { - self.artist=artist - self.name=name - self.description=description - self.type=type - } - } - - - /// A basic pointer that can resolve data and get owner/id/uuid and gype - pub struct interface Pointer { - pub let id: UInt64 - pub fun resolveView(_ type: Type) : AnyStruct? - pub fun getUUID() :UInt64 - pub fun getViews() : [Type] - pub fun owner() : Address - pub fun valid() : Bool - pub fun getItemType() : Type - pub fun getViewResolver() : &AnyResource{MetadataViews.Resolver} - - //There are just convenience functions for shared views in the standard - pub fun getRoyalty() : MetadataViews.Royalties - pub fun getTotalRoyaltiesCut() : UFix64 - - //Requred views - pub fun getDisplay() : MetadataViews.Display - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData - - pub fun checkSoulBound() : Bool - - } - - //An interface to say that this pointer can withdraw - pub struct interface AuthPointer { - pub fun withdraw() : @AnyResource - } - - pub struct ViewReadPointer : Pointer { - access(self) let cap: Capability<&{MetadataViews.ResolverCollection}> - pub let id: UInt64 - pub let uuid: UInt64 - pub let itemType: Type - - init(cap: Capability<&{MetadataViews.ResolverCollection}>, id: UInt64) { - self.cap=cap - self.id=id - - if !self.cap.check() { - panic("The capability is not valid.") - } - let viewResolver=self.cap.borrow()!.borrowViewResolver(id: self.id) - let display = MetadataViews.getDisplay(viewResolver) ?? panic("MetadataViews Display View is not implemented on this NFT.") - let nftCollectionData = MetadataViews.getNFTCollectionData(viewResolver) ?? panic("MetadataViews NFTCollectionData View is not implemented on this NFT.") - self.uuid=viewResolver.uuid - self.itemType=viewResolver.getType() - } - - pub fun resolveView(_ type: Type) : AnyStruct? { - return self.getViewResolver().resolveView(type) - } - - pub fun getUUID() :UInt64{ - return self.uuid - } - - pub fun getViews() : [Type]{ - return self.getViewResolver().getViews() - } - - pub fun owner() : Address { - return self.cap.address - } - - pub fun getTotalRoyaltiesCut() :UFix64 { - var total=0.0 - for royalty in self.getRoyalty().getRoyalties() { - total = total + royalty.cut - } - return total - } - - pub fun getRoyalty() : MetadataViews.Royalties { - if let v = MetadataViews.getRoyalties(self.getViewResolver()) { - return v - } - return MetadataViews.Royalties([]) - } - - pub fun valid() : Bool { - if !self.cap.check() || !self.cap.borrow()!.getIDs().contains(self.id) { - return false - } - return true - } - - pub fun getItemType() : Type { - return self.itemType - } - - pub fun getViewResolver() : &AnyResource{MetadataViews.Resolver} { - return self.cap.borrow()?.borrowViewResolver(id: self.id) ?? panic("The capability of view pointer is not linked.") - } - - pub fun getDisplay() : MetadataViews.Display { - if let v = MetadataViews.getDisplay(self.getViewResolver()) { - return v - } - panic("MetadataViews Display View is not implemented on this NFT.") - } - - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData { - if let v = MetadataViews.getNFTCollectionData(self.getViewResolver()) { - return v - } - panic("MetadataViews NFTCollectionData View is not implemented on this NFT.") - } - - pub fun checkSoulBound() : Bool { - return FindViews.checkSoulBound(self.getViewResolver()) - } - } - - - pub fun getNounce(_ viewResolver: &{MetadataViews.Resolver}) : UInt64 { - if let nounce = viewResolver.resolveView(Type()) { - if let v = nounce as? FindViews.Nounce { - return v.nounce - } - } - return 0 - } - - - pub struct AuthNFTPointer : Pointer, AuthPointer{ - access(self) let cap: Capability<&{MetadataViews.ResolverCollection, NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}> - pub let id: UInt64 - pub let nounce: UInt64 - pub let uuid: UInt64 - pub let itemType: Type - - init(cap: Capability<&{MetadataViews.ResolverCollection, NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, id: UInt64) { - self.cap=cap - self.id=id - - if !self.cap.check() { - panic("The capability is not valid.") - } - - let viewResolver=self.cap.borrow()!.borrowViewResolver(id: self.id) - let display = MetadataViews.getDisplay(viewResolver) ?? panic("MetadataViews Display View is not implemented on this NFT.") - let nftCollectionData = MetadataViews.getNFTCollectionData(viewResolver) ?? panic("MetadataViews NFTCollectionData View is not implemented on this NFT.") - self.nounce=FindViews.getNounce(viewResolver) - self.uuid=viewResolver.uuid - self.itemType=viewResolver.getType() - } - - pub fun getViewResolver() : &AnyResource{MetadataViews.Resolver} { - return self.cap.borrow()?.borrowViewResolver(id: self.id) ?? panic("The capability of view pointer is not linked.") - } - - pub fun resolveView(_ type: Type) : AnyStruct? { - return self.getViewResolver().resolveView(type) - } - - pub fun getUUID() :UInt64{ - return self.uuid - } - - pub fun getViews() : [Type]{ - return self.getViewResolver().getViews() - } - - pub fun valid() : Bool { - if !self.cap.check() || !self.cap.borrow()!.getIDs().contains(self.id) { - return false - } - - let viewResolver=self.getViewResolver() - - if let nounce = viewResolver.resolveView(Type()) { - if let v = nounce as? FindViews.Nounce { - return v.nounce==self.nounce - } - } - return true - } - - pub fun getTotalRoyaltiesCut() :UFix64 { - var total=0.0 - for royalty in self.getRoyalty().getRoyalties() { - total = total + royalty.cut - } - return total - } - - pub fun getRoyalty() : MetadataViews.Royalties { - if let v = MetadataViews.getRoyalties(self.getViewResolver()) { - return v - } - return MetadataViews.Royalties([]) - } - - pub fun getDisplay() : MetadataViews.Display { - if let v = MetadataViews.getDisplay(self.getViewResolver()) { - return v - } - panic("MetadataViews Display View is not implemented on this NFT.") - } - - pub fun getNFTCollectionData() : MetadataViews.NFTCollectionData { - if let v = MetadataViews.getNFTCollectionData(self.getViewResolver()) { - return v - } - panic("MetadataViews NFTCollectionData View is not implemented on this NFT.") - } - - pub fun withdraw() :@NonFungibleToken.NFT { - if !self.cap.check() { - panic("The pointer capability is invalid.") - } - return <- self.cap.borrow()!.withdraw(withdrawID: self.id) - } - - pub fun deposit(_ nft: @NonFungibleToken.NFT){ + // This is an example taken from Versus + access(all) struct CreativeWork { + access(all) let artist: String + access(all) let name: String + access(all) let description: String + access(all) let type: String + + init(artist: String, name: String, description: String, type: String) { + self.artist=artist + self.name=name + self.description=description + self.type=type + } + } + + /// A basic pointer that can resolve data and get owner/id/uuid and gype + access(all) struct interface Pointer { + access(all) let id: UInt64 + access(all) fun resolveView(_ type: Type) : AnyStruct? + access(all) fun getUUID() :UInt64 + access(all) fun getViews() : [Type] + access(all) fun owner() : Address + access(all) fun valid() : Bool + access(all) fun getItemType() : Type + access(all) fun getViewResolver() : &{ViewResolver.Resolver} + + //There are just convenience functions for shared views in the standard + access(all) fun getRoyalty() : MetadataViews.Royalties + access(all) fun getTotalRoyaltiesCut() : UFix64 + + //Requred views + access(all) fun getDisplay() : MetadataViews.Display + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData + + access(all) fun checkSoulBound() : Bool + + } + + //An interface to say that this pointer can withdraw + access(all) struct interface AuthPointer { + access(all) fun withdraw() : @AnyResource + } + + access(all) struct ViewReadPointer : Pointer { + access(self) let cap: Capability<&{ViewResolver.ResolverCollection}> + access(all) let id: UInt64 + access(all) let uuid: UInt64 + access(all) let itemType: Type + + init(cap: Capability<&{ViewResolver.ResolverCollection}>, id: UInt64) { + self.cap=cap + self.id=id + + if !self.cap.check() { + panic("The capability is not valid.") + } + let viewResolver=self.cap.borrow()!.borrowViewResolver(id: self.id)! + let display = MetadataViews.getDisplay(viewResolver) ?? panic("MetadataViews Display View is not implemented on this NFT.") + let nftCollectionData = MetadataViews.getNFTCollectionData(viewResolver) ?? panic("MetadataViews NFTCollectionData View is not implemented on this NFT.") + self.uuid=viewResolver.uuid + self.itemType=viewResolver.getType() + } + + access(all) fun resolveView(_ type: Type) : AnyStruct? { + return self.getViewResolver().resolveView(type) + } + + access(all) fun getUUID() :UInt64{ + return self.uuid + } + + access(all) fun getViews() : [Type]{ + return self.getViewResolver().getViews() + } + + access(all) fun owner() : Address { + return self.cap.address + } + + access(all) fun getTotalRoyaltiesCut() :UFix64 { + var total=0.0 + for royalty in self.getRoyalty().getRoyalties() { + total = total + royalty.cut + } + return total + } + + access(all) fun getRoyalty() : MetadataViews.Royalties { + if let v = MetadataViews.getRoyalties(self.getViewResolver()) { + return v + } + return MetadataViews.Royalties([]) + } + + access(all) fun valid() : Bool { + if !self.cap.check() || self.cap.borrow()!.borrowViewResolver(id: self.id) == nil { + return false + } + return true + } + + access(all) fun getItemType() : Type { + return self.itemType + } + + access(all) fun getViewResolver() : &{ViewResolver.Resolver} { + let nft=self.cap.borrow()!.borrowViewResolver(id: self.id) ?? panic("The capability of view pointer is not linked.") + return nft + + } + + access(all) fun getDisplay() : MetadataViews.Display { + if let v = MetadataViews.getDisplay(self.getViewResolver()) { + return v + } + panic("MetadataViews Display View is not implemented on this NFT.") + } + + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData { + if let v = MetadataViews.getNFTCollectionData(self.getViewResolver()) { + return v + } + panic("MetadataViews NFTCollectionData View is not implemented on this NFT.") + } + + access(all) fun checkSoulBound() : Bool { + return FindViews.checkSoulBound(self.getViewResolver()) + } + } + + + access(all) fun getNounce(_ viewResolver: &{ViewResolver.Resolver}) : UInt64 { + if let nounce = viewResolver.resolveView(Type()) { + if let v = nounce as? FindViews.Nounce { + return v.nounce + } + } + return 0 + } + + access(all) struct AuthNFTPointer : Pointer, AuthPointer{ + access(self) let cap: Capability + access(all) let id: UInt64 + access(all) let nounce: UInt64 + access(all) let uuid: UInt64 + access(all) let itemType: Type + + init(cap: Capability, id: UInt64) { + self.cap=cap + self.id=id + + if !self.cap.check() { + panic("The capability is not valid.") + } + + let collection = self.cap.borrow() ?? panic("could not find collection") + let viewResolver=collection.borrowNFT(self.id) ?? panic("could not borrow nft") + let display = MetadataViews.getDisplay(viewResolver) ?? panic("MetadataViews Display View is not implemented on this NFT.") + let nftCollectionData = MetadataViews.getNFTCollectionData(viewResolver) ?? panic("MetadataViews NFTCollectionData View is not implemented on this NFT.") + self.nounce=FindViews.getNounce(viewResolver) + self.uuid=viewResolver.uuid + self.itemType=viewResolver.getType() + } + + access(all) fun getViewResolver() : &{ViewResolver.Resolver} { + let cap = self.cap.borrow()! + let viewResolver = cap.borrowNFT(self.id) ?? panic("The capability of view pointer is not linked.") + return viewResolver + } + + access(all) fun resolveView(_ type: Type) : AnyStruct? { + return self.getViewResolver().resolveView(type) + } + + access(all) fun getUUID() :UInt64{ + return self.uuid + } + + access(all) fun getViews() : [Type]{ + return self.getViewResolver().getViews() + } + + access(all) fun valid() : Bool { + if !self.cap.check() { + return false + } + + let collection = self.cap.borrow()! + + let collectionType=collection.getType() + if collectionType.isRecovered { + return false + } + + let nft= collection.borrowNFT(self.id) + + if nft ==nil { + return false + } + + if let nounce = nft!.resolveView(Type()) { + if let v = nounce as? FindViews.Nounce { + return v.nounce==self.nounce + } + } + return true + } + + access(all) fun getTotalRoyaltiesCut() :UFix64 { + var total=0.0 + for royalty in self.getRoyalty().getRoyalties() { + total = total + royalty.cut + } + return total + } + + access(all) fun getRoyalty() : MetadataViews.Royalties { + if let v = MetadataViews.getRoyalties(self.getViewResolver()) { + return v + } + return MetadataViews.Royalties([]) + } + + access(all) fun getDisplay() : MetadataViews.Display { + if let v = MetadataViews.getDisplay(self.getViewResolver()) { + return v + } + panic("MetadataViews Display View is not implemented on this NFT.") + } + + access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData { + if let v = MetadataViews.getNFTCollectionData(self.getViewResolver()) { + return v + } + panic("MetadataViews NFTCollectionData View is not implemented on this NFT.") + } + + access(all) fun withdraw() :@{NonFungibleToken.NFT} { + if !self.cap.check() { + panic("The pointer capability is invalid.") + } + return <- self.cap.borrow()!.withdraw(withdrawID: self.id) + } + + access(all) fun deposit(_ nft: @{NonFungibleToken.NFT}){ if !self.cap.check(){ panic("The pointer capablity is invalid.") } - self.cap.borrow()!.deposit(token: <- nft) - } - - pub fun owner() : Address { - return self.cap.address - } - - pub fun getItemType() : Type { - return self.itemType - } - - pub fun checkSoulBound() : Bool { - return FindViews.checkSoulBound(self.getViewResolver()) - } - } - - pub fun createViewReadPointer(address:Address, path:PublicPath, id:UInt64) : ViewReadPointer { - let cap= getAccount(address).getCapability<&{MetadataViews.ResolverCollection}>(path) - let pointer= FindViews.ViewReadPointer(cap: cap, id: id) - return pointer - } - - pub struct Nounce { - pub let nounce: UInt64 - - init(_ nounce: UInt64) { - self.nounce=nounce - } - } - - pub struct SoulBound { - - pub let message: String - - init(_ message:String) { - self.message=message - - } - } - - pub fun checkSoulBound(_ viewResolver: &{MetadataViews.Resolver}) : Bool { - if let soulBound = viewResolver.resolveView(Type()) { - if let v = soulBound as? FindViews.SoulBound { - return true - } - } - return false - } - - pub fun getDapperAddress(): Address { - switch FindViews.account.address.toString() { - case "0x097bafa4e0b48eef": - //mainnet - return 0xead892083b3e2c6c - case "0x35717efbbce11c74": - //testnet - return 0x82ec283f88a62e65 - default: - //emulator - return 0x01cf0e2f2f715450 - } - } + self.cap.borrow()!.deposit(token: <- nft) + } + + access(all) fun owner() : Address { + return self.cap.address + } + + access(all) fun getItemType() : Type { + return self.itemType + } + + access(all) fun checkSoulBound() : Bool { + return FindViews.checkSoulBound(self.getViewResolver()) + } + } + + access(all) fun createViewReadPointer(address:Address, path:PublicPath, id:UInt64) : ViewReadPointer { + let cap= getAccount(address).capabilities.get<&{ViewResolver.ResolverCollection}>(path) + let pointer= FindViews.ViewReadPointer(cap: cap, id: id) + return pointer + } + + access(all) struct Nounce { + access(all) let nounce: UInt64 + + init(_ nounce: UInt64) { + self.nounce=nounce + } + } + + access(all) struct SoulBound { + + access(all) let message: String + + init(_ message:String) { + self.message=message + + } + } + + access(all) fun checkSoulBound(_ viewResolver: &{ViewResolver.Resolver}) : Bool { + if let soulBound = viewResolver.resolveView(Type()) { + if let v = soulBound as? FindViews.SoulBound { + return true + } + } + return false + } + + access(all) fun getDapperAddress(): Address { + switch FindViews.account.address.toString() { + case "0x097bafa4e0b48eef": + //mainnet + return 0xead892083b3e2c6c + case "0x35717efbbce11c74": + //testnet + return 0x82ec283f88a62e65 + default: + //emulator + return 0x01cf0e2f2f715450 + } + } } diff --git a/contracts/Flomies.cdc b/contracts/Flomies.cdc index d5b78e0c..fbfd0fc9 100644 --- a/contracts/Flomies.cdc +++ b/contracts/Flomies.cdc @@ -1,384 +1,426 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindForge from "./FindForge.cdc" -import FindPack from "./FindPack.cdc" - - -pub contract Flomies: NonFungibleToken { - - pub var totalSupply: UInt64 - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id:UInt64, serial: UInt64, traits: [UInt64]) - pub event RegisteredTraits(traitId:UInt64, trait:{String : String}) - - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - pub let CollectionPrivatePath: PrivatePath - - access(account) var royalties : [MetadataViews.Royalty] - access(self) let traits : {UInt64: MetadataViews.Trait} - - /* - Iconic - Legendary - Rare - Common - */ - - pub struct Metadata { - pub let nftId: UInt64 - pub let name: String - pub let serial:UInt64 - pub let thumbnail: String - pub let image: String - pub let traits: [UInt64] - - init(nftId: UInt64,name:String,thumbnail: String, image:String, serial:UInt64, traits: [UInt64]) { - self.nftId=nftId - self.name=name - self.thumbnail=thumbnail - self.image=image - self.serial=serial - self.traits=traits - } - } - - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - - pub let id:UInt64 - pub let serial:UInt64 - pub var nounce:UInt64 - pub let rootHash:String - pub let traits: [UInt64] - - init( - serial:UInt64, - rootHash:String, - traits: [UInt64] - ) { - self.nounce=0 - self.serial=serial - self.id=self.uuid - self.rootHash=rootHash - self.traits=traits - } - - pub fun getViews(): [Type] { - return [ - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type() - ] - } - - pub fun resolveView(_ view: Type): AnyStruct? { - - let imageFile=MetadataViews.IPFSFile( url: self.rootHash, path: self.serial.toString().concat(".png")) - var fullMediaType="image/png" - let traits = self.traits - - let fullMedia=MetadataViews.Media(file:imageFile, mediaType: fullMediaType) - - let name ="Flomies #".concat(self.serial.toString()) - let description= "Flomies is a collection of 3333 homies living on the flow blockchain. Flomies are about art, mental health and innovating in this ecosystem. Our adventure is unique, as is our community." - - switch view { - case Type(): - return MetadataViews.Display( - name: name, - description: description, - thumbnail: imageFile - ) - - case Type(): - if self.owner == nil { - return MetadataViews.ExternalURL("https://find.xyz/") - } - return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/flomies/").concat(self.id.toString())) - - case Type(): - return MetadataViews.Royalties(Flomies.royalties) - - case Type(): - return MetadataViews.Medias([fullMedia]) - - case Type(): - return Metadata( - nftId : self.id , - name : name , - thumbnail : imageFile.uri(), - image : imageFile.uri(), - serial:self.serial, - traits:self.traits - ) - case Type(): - let externalURL = MetadataViews.ExternalURL("https://flomiesnft.com") - let squareImage = MetadataViews.Media(file: MetadataViews.IPFSFile(cid: "QmYtowktCz6GbP6MqMd6SXqJEYazCpGTcFm4HrWX89nUvo", path: nil), mediaType: "image/png") - let bannerImage = MetadataViews.Media(file: MetadataViews.IPFSFile(cid: "QmPeZUjsfrFvkB1bvKBpAsxfoQ6jSoezqwWz9grkmNYdz1", path: nil), mediaType: "image/png") - return MetadataViews.NFTCollectionDisplay(name: "flomies", - description: "Flomies is a collection of 3333 homies living on the flow blockchain. Flomies are about art, mental health and innovating in this ecosystem. Our adventure is unique, as is our community.", - externalURL: externalURL, - squareImage: squareImage, - bannerImage: bannerImage, - socials: { - "discord": MetadataViews.ExternalURL("https://discord.gg/tVavHtPD"), - "twitter" : MetadataViews.ExternalURL("https://twitter.com/flomiesnft"), - "instagram" : MetadataViews.ExternalURL("https://www.instagram.com/flomies_nft/") - }) - - case Type(): - return MetadataViews.NFTCollectionData(storagePath: Flomies.CollectionStoragePath, - publicPath: Flomies.CollectionPublicPath, - providerPath: Flomies.CollectionPrivatePath, - publicCollection: Type<&Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: fun(): @NonFungibleToken.Collection {return <- Flomies.createEmptyCollection()}) - - case Type(): - return MetadataViews.Traits(self.getAllTraitsMetadataAsArray()) - - - case Type(): - let data : {String : String} = { - "nftImage" : imageFile.uri() , - "nftName" : "Flomies ".concat(self.serial.toString()), - "packType" : "Flomies" - } - return FindPack.PackRevealData(data) - - case Type() : - return MetadataViews.Editions([ - MetadataViews.Edition(name: "set", number: self.serial, max: 3333) - ]) - - case Type() : - return MetadataViews.Serial(self.serial) - } - - return nil - } - - pub fun increaseNounce() { - self.nounce=self.nounce+1 - } - - pub fun getAllTraitsMetadataAsArray() : [MetadataViews.Trait] { - let traits = self.traits - - var traitMetadata : [MetadataViews.Trait] = [] - for trait in traits { - traitMetadata.append(Flomies.traits[trait]!) - } - return traitMetadata - } - - pub fun getAllTraitsMetadata() : {String : MetadataViews.Trait} { - let traitMetadata : {String : MetadataViews.Trait} = {} - for trait in self.getAllTraitsMetadataAsArray() { - let traitName = trait.name - traitMetadata[traitName] = trait - } - return traitMetadata - } - } - - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} - - init () { - self.ownedNFTs <- {} - } - - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") - - emit Withdraw(id: token.id, from: self.owner?.address) - - return <-token - } - - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { - let token <- token as! @NFT - - let id: UInt64 = token.id - //TODO: add nounce and emit better event the first time it is moved. - - token.increaseNounce() - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) - - - destroy oldToken - } - - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { - return self.ownedNFTs.keys - } - - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! - } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let flomies = nft as! &NFT - return flomies as &AnyResource{MetadataViews.Resolver} - } - - destroy() { - destroy self.ownedNFTs - } - } - - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } - - // mintNFT mints a new NFT with a new ID - // and deposit it in the recipients collection using their collection reference - //The distinction between sending in a reference and sending in a capability is that when you send in a reference it cannot be stored. So it can only be used in this method - //while a capability can be stored and used later. So in this case using a reference is the right choice, but it needs to be owned so that you can have a good event - access(account) fun mintNFT( - serial:UInt64, - rootHash:String, - traits: [UInt64] - ) : @NonFungibleToken.NFT { - - Flomies.totalSupply = Flomies.totalSupply + 1 - // create a new NFT - var newNFT <- create NFT( - serial:serial, - rootHash:rootHash, - traits: traits) - - emit Minted(id: newNFT.uuid, serial: newNFT.serial, traits: traits) - - //Always emit events on state changes! always contain human readable and machine readable information - //TODO: discuss that fields we want in this event. Or do we prefer to use the richer deposit event, since this is really done in the backend - //emit Minted(id:newNFT.id, address:recipient.owner!.address) - // deposit it in the recipient's account using their reference - return <-newNFT - - } - - access(account) fun addTrait(_ traits: {UInt64 : MetadataViews.Trait}) { - for key in traits.keys { - let trait = traits[key]! - self.traits[key]=trait - let traits : {String : String} = {} - traits["name"] = trait.name - traits["value"] = trait.value as! String - traits["rarity_description"] = trait.rarity?.description - traits["rarity_score"] = trait.rarity?.score?.toString() - traits["rarity_max"] = trait.rarity?.max?.toString() - - emit RegisteredTraits(traitId: key, trait:traits) - } - } - - pub fun getTraits() : {UInt64:MetadataViews.Trait}{ - return self.traits - } - - pub fun getTrait(_ id:UInt64) : MetadataViews.Trait? { - return self.traits[id] - } - - access(account) fun addRoyaltycut(_ cutInfo: [MetadataViews.Royalty]) { - var cutInfos = self.royalties - cutInfos.appendAll(cutInfo) - // for validation only - let royalties = MetadataViews.Royalties(cutInfos) - self.royalties.appendAll(cutInfo) - } - - pub resource Forge: FindForge.Forge { - pub fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @NonFungibleToken.NFT { - let info = data as? {String : AnyStruct} ?? panic("The data passed in is not in form of {String : AnyStruct}") - - let serial = info["serial"]! as? UInt64 ?? panic("Serial is missing") - let rootHash = info["rootHash"]! as? String ?? panic("RootHash is missing") - let traits = info["traits"]! as? [UInt64] ?? panic("traits are missing") - - return <- Flomies.mintNFT( - serial:serial, - rootHash:rootHash, - traits:traits - ) - } - - pub fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { - let type = data.getType() - - switch type { - case Type<{UInt64 : MetadataViews.Trait}>() : - // for duplicated indexes, the new one will replace the old one - let typedData = data as! {UInt64 : MetadataViews.Trait} - Flomies.addTrait(typedData) - return - - case Type<[MetadataViews.Royalty]>() : - let typedData = data as! [MetadataViews.Royalty] - Flomies.royalties = typedData - return - - } - } - } - - access(account) fun createForge() : @{FindForge.Forge} { - return <- create Forge() - } - - init() { - self.traits={} - // Initialize the total supply - self.totalSupply = 0 - - self.royalties = [] - - // Set the named paths - self.CollectionStoragePath = /storage/flomiesNFT - self.CollectionPublicPath = /public/flomiesNFT - self.CollectionPrivatePath = /private/flomiesNFT - - self.account.save<@NonFungibleToken.Collection>(<- Flomies.createEmptyCollection(), to: Flomies.CollectionStoragePath) - self.account.link<&Flomies.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Flomies.CollectionPublicPath, - target: Flomies.CollectionStoragePath - ) - self.account.link<&Flomies.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Flomies.CollectionPrivatePath, - target: Flomies.CollectionStoragePath - ) - - FindForge.addForgeType(<- create Forge()) - - emit ContractInitialized() - } -} - \ No newline at end of file +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindForge" +import "FindPack" +import "ViewResolver" + + +access(all) contract Flomies: NonFungibleToken{ + + access(all) var totalSupply: UInt64 + + access(all) event ContractInitialized() + access(all) event Minted(id:UInt64, serial: UInt64, traits: [UInt64]) + access(all) event RegisteredTraits(traitId:UInt64, trait:{String : String}) + + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + + access(account) var royalties : [MetadataViews.Royalty] + access(self) let traits : {UInt64: MetadataViews.Trait} + + /* + Iconic + Legendary + Rare + Common + */ + + access(all) struct Metadata { + access(all) let nftId: UInt64 + access(all) let name: String + access(all) let serial:UInt64 + access(all) let thumbnail: String + access(all) let image: String + access(all) let traits: [UInt64] + + init(nftId: UInt64,name:String,thumbnail: String, image:String, serial:UInt64, traits: [UInt64]) { + self.nftId=nftId + self.name=name + self.thumbnail=thumbnail + self.image=image + self.serial=serial + self.traits=traits + } + } + + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { + + access(all) let id:UInt64 + access(all) let serial:UInt64 + access(all) var nounce:UInt64 + access(all) let rootHash:String + access(all) let traits: [UInt64] + + init( + serial:UInt64, + rootHash:String, + traits: [UInt64] + ) { + self.nounce=0 + self.serial=serial + self.id=self.uuid + self.rootHash=rootHash + self.traits=traits + } + + access(all) view fun getViews(): [Type] { + return [ + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) view fun getID(): UInt64 { + return self.id + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + + let imageFile=MetadataViews.IPFSFile( cid: self.rootHash, path: self.serial.toString().concat(".png")) + var fullMediaType="image/png" + let traits = self.traits + + let fullMedia=MetadataViews.Media(file:imageFile, mediaType: fullMediaType) + + let name ="Flomies #".concat(self.serial.toString()) + let description= "Flomies is a collection of 3333 homies living on the flow blockchain. Flomies are about art, mental health and innovating in this ecosystem. Our adventure is unique, as is our community." + + switch view { + case Type(): + return MetadataViews.Display( + name: name, + description: description, + thumbnail: imageFile + ) + + case Type(): + if self.owner == nil { + return MetadataViews.ExternalURL("https://find.xyz/") + } + return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/flomies/").concat(self.id.toString())) + + case Type(): + return MetadataViews.Royalties(Flomies.royalties) + + case Type(): + return MetadataViews.Medias([fullMedia]) + + case Type(): + return Metadata( + nftId : self.id , + name : name , + thumbnail : imageFile.uri(), + image : imageFile.uri(), + serial:self.serial, + traits:self.traits + ) + case Type(): + return Flomies.resolveContractView(resourceType: Type<@Flomies.NFT>(), viewType: Type()) as! MetadataViews.NFTCollectionDisplay + + case Type(): + return Flomies.resolveContractView(resourceType: Type<@Flomies.NFT>(), viewType: Type()) as! MetadataViews.NFTCollectionData + + case Type(): + return MetadataViews.Traits(self.getAllTraitsMetadataAsArray()) + + + case Type(): + let data : {String : String} = { + "nftImage" : imageFile.uri() , + "nftName" : "Flomies ".concat(self.serial.toString()), + "packType" : "Flomies" + } + return FindPack.PackRevealData(data) + + case Type() : + return MetadataViews.Editions([ + MetadataViews.Edition(name: "set", number: self.serial, max: 3333) + ]) + + case Type() : + return MetadataViews.Serial(self.serial) + } + + return nil + } + + access(contract) fun increaseNounce() { + self.nounce=self.nounce+1 + } + + access(all) fun getAllTraitsMetadataAsArray() : [MetadataViews.Trait] { + let traits = self.traits + + var traitMetadata : [MetadataViews.Trait] = [] + for trait in traits { + traitMetadata.append(Flomies.traits[trait]!) + } + return traitMetadata + } + + access(all) fun getAllTraitsMetadata() : {String : MetadataViews.Trait} { + let traitMetadata : {String : MetadataViews.Trait} = {} + for trait in self.getAllTraitsMetadataAsArray() { + let traitName = trait.name + traitMetadata[traitName] = trait + } + return traitMetadata + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-Flomies.createEmptyCollection(nftType:Type<@Flomies.NFT>()) + } + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionRef = self.account.storage.borrow<&Flomies.Collection>( + from: Flomies.CollectionStoragePath + ) ?? panic("Could not borrow a reference to the stored collection") + let collectionData = MetadataViews.NFTCollectionData( + storagePath: Flomies.CollectionStoragePath, + publicPath: Flomies.CollectionPublicPath, + publicCollection: Type<&Flomies.Collection>(), + publicLinkedType: Type<&Flomies.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-Flomies.createEmptyCollection(nftType:Type<@Flomies.NFT>()) + }) + ) + return collectionData + case Type(): + let externalURL = MetadataViews.ExternalURL("https://flomiesnft.com") + let squareImage = MetadataViews.Media(file: MetadataViews.IPFSFile(cid: "QmYtowktCz6GbP6MqMd6SXqJEYazCpGTcFm4HrWX89nUvo", path: nil), mediaType: "image/png") + let bannerImage = MetadataViews.Media(file: MetadataViews.IPFSFile(cid: "QmPeZUjsfrFvkB1bvKBpAsxfoQ6jSoezqwWz9grkmNYdz1", path: nil), mediaType: "image/png") + return MetadataViews.NFTCollectionDisplay(name: "flomies", + description: "Flomies is a collection of 3333 homies living on the flow blockchain. Flomies are about art, mental health and innovating in this ecosystem. Our adventure is unique, as is our community.", + externalURL: externalURL, + squareImage: squareImage, + bannerImage: bannerImage, + socials: { + "discord": MetadataViews.ExternalURL("https://discord.gg/tVavHtPD"), + "twitter" : MetadataViews.ExternalURL("https://twitter.com/flomiesnft"), + "instagram" : MetadataViews.ExternalURL("https://www.instagram.com/flomies_nft/") + }) + } + return nil + } + + access(all) resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, ViewResolver.ResolverCollection { + // dictionary of NFT conforming tokens + // NFT is a resource type with an `UInt64` ID field + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + + init () { + self.ownedNFTs <- {} + } + + // withdraw removes an NFT from the collection and moves it to the caller + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") + + return <-token + } + + // deposit takes a NFT and adds it to the collections dictionary + // and adds the ID to the id array + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { + let token <- token as! @NFT + + let id: UInt64 = token.id + //TODO: add nounce and emit better event the first time it is moved. + + token.increaseNounce() + // add the new token to the dictionary which removes the old one + let oldToken <- self.ownedNFTs[id] <- token + + + destroy oldToken + } + + // getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { + return self.ownedNFTs.keys + } + + access(all) view fun getLength(): Int { + return self.ownedNFTs.keys.length + } + + // borrowNFT gets a reference to an NFT in the collection + // so that the caller can read its metadata and call its methods + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] + } + + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} { + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) + let flomies = nft as! &NFT + return flomies + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create Flomies.Collection() + } + + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[Type<@Flomies.NFT>()] = true + return supportedTypes + } + + + + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + access(all) view fun isSupportedNFTType(type: Type): Bool { + if type == Type<@Flomies.NFT>() { + return true + } else { + return false + } + } + } + + + access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} { + return <- create Collection() + } + + // mintNFT mints a new NFT with a new ID + // and deposit it in the recipients collection using their collection reference + //The distinction between sending in a reference and sending in a capability is that when you send in a reference it cannot be stored. So it can only be used in this method + //while a capability can be stored and used later. So in this case using a reference is the right choice, but it needs to be owned so that you can have a good event + access(account) fun mintNFT( + serial:UInt64, + rootHash:String, + traits: [UInt64] + ) : @{NonFungibleToken.NFT} { + + Flomies.totalSupply = Flomies.totalSupply + 1 + // create a new NFT + var newNFT <- create NFT( + serial:serial, + rootHash:rootHash, + traits: traits) + + emit Minted(id: newNFT.uuid, serial: newNFT.serial, traits: traits) + + //Always emit events on state changes! always contain human readable and machine readable information + //TODO: discuss that fields we want in this event. Or do we prefer to use the richer deposit event, since this is really done in the backend + //emit Minted(id:newNFT.id, address:recipient.owner!.address) + // deposit it in the recipient's account using their reference + return <-newNFT + + } + + access(account) fun addTrait(_ traits: {UInt64 : MetadataViews.Trait}) { + for key in traits.keys { + let trait = traits[key]! + self.traits[key]=trait + let traits : {String : String} = {} + traits["name"] = trait.name + traits["value"] = trait.value as! String + traits["rarity_description"] = trait.rarity?.description + traits["rarity_score"] = trait.rarity?.score?.toString() + traits["rarity_max"] = trait.rarity?.max?.toString() + + emit RegisteredTraits(traitId: key, trait:traits) + } + } + + access(all) fun getTraits() : {UInt64:MetadataViews.Trait}{ + return self.traits + } + + access(all) fun getTrait(_ id:UInt64) : MetadataViews.Trait? { + return self.traits[id] + } + + access(account) fun addRoyaltycut(_ cutInfo: [MetadataViews.Royalty]) { + var cutInfos = self.royalties + cutInfos.appendAll(cutInfo) + // for validation only + let royalties = MetadataViews.Royalties(cutInfos) + self.royalties.appendAll(cutInfo) + } + + access(all) resource Forge: FindForge.Forge { + access(FindForge.ForgeOwner) fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @{NonFungibleToken.NFT} { + let info = data as? {String : AnyStruct} ?? panic("The data passed in is not in form of {String : AnyStruct}") + + let serial = info["serial"]! as? UInt64 ?? panic("Serial is missing") + let rootHash = info["rootHash"]! as? String ?? panic("RootHash is missing") + let traits = info["traits"]! as? [UInt64] ?? panic("traits are missing") + + return <- Flomies.mintNFT( + serial:serial, + rootHash:rootHash, + traits:traits + ) + } + + access(FindForge.ForgeOwner) fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { + let type = data.getType() + + switch type { + case Type<{UInt64 : MetadataViews.Trait}>() : + // for duplicated indexes, the new one will replace the old one + let typedData = data as! {UInt64 : MetadataViews.Trait} + Flomies.addTrait(typedData) + return + + case Type<[MetadataViews.Royalty]>() : + let typedData = data as! [MetadataViews.Royalty] + Flomies.royalties = typedData + return + + } + } + } + + access(account) fun createForge() : @{FindForge.Forge} { + return <- create Forge() + } + + init() { + self.traits={} + // Initialize the total supply + self.totalSupply = 0 + + self.royalties = [] + + // Set the named paths + self.CollectionStoragePath = /storage/flomiesNFT + self.CollectionPublicPath = /public/flomiesNFT + + let collection <- create Collection() + self.account.storage.save(<-collection, to: self.CollectionStoragePath) + let collectionCap = self.account.capabilities.storage.issue<&{NonFungibleToken.Collection}>(self.CollectionStoragePath) + self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath) + + FindForge.addForgeType(<- create Forge()) + + emit ContractInitialized() + } + } + diff --git a/contracts/GeneratedExperiences.cdc b/contracts/GeneratedExperiences.cdc index fc8ca513..47bd4c32 100644 --- a/contracts/GeneratedExperiences.cdc +++ b/contracts/GeneratedExperiences.cdc @@ -1,39 +1,39 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindForge from "./FindForge.cdc" -import FindPack from "./FindPack.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "ViewResolver" +import "FindForge" +import "FindPack" -pub contract GeneratedExperiences: NonFungibleToken { +access(all) contract GeneratedExperiences: NonFungibleToken { - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id:UInt64, season: UInt64, name: String, thumbnail: String, fullsize: String, artist: String, rarity: String, edition: UInt64, maxEdition: UInt64) - pub event SeasonAdded(season:UInt64, squareImage: String, bannerImage: String) + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Minted(id:UInt64, season: UInt64, name: String, thumbnail: String, fullsize: String, artist: String, rarity: String, edition: UInt64, maxEdition: UInt64) + access(all) event SeasonAdded(season:UInt64, squareImage: String, bannerImage: String) - pub let CollectionStoragePath: StoragePath - pub let CollectionPrivatePath: PrivatePath - pub let CollectionPublicPath: PublicPath - pub let MinterStoragePath: StoragePath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPrivatePath: PrivatePath + access(all) let CollectionPublicPath: PublicPath + access(all) let MinterStoragePath: StoragePath - pub let CollectionName : String + access(all) let CollectionName : String - // {Season : CollectionInfo} - pub let collectionInfo: {UInt64 : CollectionInfo} + access(all) let collectionInfo: {UInt64 : CollectionInfo} - pub struct CollectionInfo { - pub let season: UInt64 - pub var royalties: [MetadataViews.Royalty] + access(all) struct CollectionInfo { + access(all) let season: UInt64 + access(all) var royalties: [MetadataViews.Royalty] // This is only used internally for fetching royalties in - pub let royaltiesInput: [FindPack.Royalty] - pub let squareImage: MetadataViews.Media - pub let bannerImage: MetadataViews.Media - pub let description: String - pub let socials: {String : String} - pub let extra: {String: AnyStruct} + access(all) let royaltiesInput: [FindPack.Royalty] + access(all) let squareImage: MetadataViews.Media + access(all) let bannerImage: MetadataViews.Media + access(all) let description: String + access(all) let socials: {String : String} + access(all) let extra: {String: AnyStruct} init( season: UInt64, @@ -60,16 +60,16 @@ pub contract GeneratedExperiences: NonFungibleToken { } } - pub struct Info { - pub let season: UInt64 - pub let name: String - pub let description: String - pub let thumbnail: {MetadataViews.File} - pub let fullsize: {MetadataViews.File} - pub let edition: UInt64 - pub let maxEdition: UInt64 - pub let artist: String - pub let rarity: String + access(all) struct Info { + access(all) let season: UInt64 + access(all) let name: String + access(all) let description: String + access(all) let thumbnail: {MetadataViews.File} + access(all) let fullsize: {MetadataViews.File} + access(all) let edition: UInt64 + access(all) let maxEdition: UInt64 + access(all) let artist: String + access(all) let rarity: String access(self) let extra: {String: AnyStruct} init(season: UInt64, name: String, description: String, thumbnail: {MetadataViews.File}, edition:UInt64, maxEdition:UInt64, fullsize: {MetadataViews.File}, artist: String, rarity: String) { @@ -86,9 +86,10 @@ pub contract GeneratedExperiences: NonFungibleToken { } } - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - pub let id: UInt64 - pub let info: Info + + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { + access(all) let id: UInt64 + access(all) let info: Info init( info: Info @@ -97,7 +98,13 @@ pub contract GeneratedExperiences: NonFungibleToken { self.info=info } - pub fun getViews(): [Type] { + + + access(all) view fun getID(): UInt64 { + return self.id + } + + access(all) view fun getViews(): [Type] { return [ Type(), Type(), @@ -112,7 +119,7 @@ pub contract GeneratedExperiences: NonFungibleToken { ] } - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) fun resolveView(_ view: Type): AnyStruct? { let collection = GeneratedExperiences.collectionInfo[self.info.season]! @@ -150,36 +157,10 @@ pub contract GeneratedExperiences: NonFungibleToken { return MetadataViews.ExternalURL("https://find.xyz/") case Type(): - return MetadataViews.NFTCollectionData( - storagePath: GeneratedExperiences.CollectionStoragePath, - publicPath: GeneratedExperiences.CollectionPublicPath, - providerPath: GeneratedExperiences.CollectionPrivatePath, - publicCollection: Type<&GeneratedExperiences.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&GeneratedExperiences.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&GeneratedExperiences.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { - return <-GeneratedExperiences.createEmptyCollection() - }) - ) - case Type(): + return GeneratedExperiences.resolveContractView(resourceType: nil, viewType: Type()) - var square = collection.squareImage - - var banner = collection.bannerImage - - let social : {String : MetadataViews.ExternalURL} = {} - for s in collection.socials.keys { - social[s] = MetadataViews.ExternalURL(collection.socials[s]!) - } - - return MetadataViews.NFTCollectionDisplay( - name: GeneratedExperiences.CollectionName, - description: collection.description, - externalURL: MetadataViews.ExternalURL("https://find.xyz/mp/".concat(GeneratedExperiences.CollectionName)), - squareImage: square, - bannerImage: banner, - socials: social - ) + case Type(): + return GeneratedExperiences.getCollectionDisplay(self.info.season) case Type() : @@ -204,70 +185,160 @@ pub contract GeneratedExperiences: NonFungibleToken { } return nil } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-GeneratedExperiences.createEmptyCollection(nftType:Type<@GeneratedExperiences.NFT>()) + } + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] } - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionRef = self.account.storage.borrow<&GeneratedExperiences.Collection>( + from: GeneratedExperiences.CollectionStoragePath + ) ?? panic("Could not borrow a reference to the stored collection") + let collectionData = MetadataViews.NFTCollectionData( + storagePath: GeneratedExperiences.CollectionStoragePath, + publicPath: GeneratedExperiences.CollectionPublicPath, + publicCollection: Type<&GeneratedExperiences.Collection>(), + publicLinkedType: Type<&GeneratedExperiences.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-GeneratedExperiences.createEmptyCollection(nftType:Type<@GeneratedExperiences.NFT>()) + }) + ) + return collectionData + } + return nil + } + + access(all) resource Collection: NonFungibleToken.Collection, ViewResolver.ResolverCollection { + /// dictionary of NFT conforming tokens + /// NFT is a resource type with an `UInt64` ID field + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + + /// Return the default storage path for the collection + access(all) view fun getDefaultStoragePath(): StoragePath? { + return GeneratedExperiences.CollectionStoragePath + } + + /// Return the default public path for the collection + access(all) view fun getDefaultPublicPath(): PublicPath? { + return GeneratedExperiences.CollectionPublicPath + } init () { self.ownedNFTs <- {} } - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[Type<@GeneratedExperiences.NFT>()] = true + return supportedTypes + } + + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + access(all) view fun isSupportedNFTType(type: Type): Bool { + if type == Type<@GeneratedExperiences.NFT>() { + return true + } else { + return false + } + } - emit Withdraw(id: token.id, from: self.owner?.address) + /// withdraw removes an NFT from the collection and moves it to the caller + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) + ?? panic("Could not withdraw an NFT with the provided ID from the collection") return <-token } - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { + /// deposit takes a NFT and adds it to the collections dictionary + /// and adds the ID to the id array + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { let token <- token as! @GeneratedExperiences.NFT - let id: UInt64 = token.id - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) + let oldToken <- self.ownedNFTs[token.id] <- token destroy oldToken } - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + /// getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! + /// Gets the amount of NFTs stored in the collection + access(all) view fun getLength(): Int { + return self.ownedNFTs.keys.length } - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let ge = nft as! &GeneratedExperiences.NFT - return ge as &AnyResource{MetadataViews.Resolver} + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] } - destroy() { - destroy self.ownedNFTs + /// Borrow the view resolver for the specified NFT ID + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? { + if let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) as! &GeneratedExperiences.NFT? { + return nft as &{ViewResolver.Resolver} + } + return nil + } + + /// public function that anyone can call to create a new empty collection + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + + return <- create GeneratedExperiences.Collection() } } + // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { + access(all) fun createEmptyCollection(nftType:Type): @GeneratedExperiences.Collection { return <- create Collection() } - pub resource Forge: FindForge.Forge { - pub fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @NonFungibleToken.NFT { + + access(all) view fun getViews(): [Type] { + return [ Type(), Type() ] + } + + + access(all) view fun getCollectionDisplay(_ season: UInt64): MetadataViews.NFTCollectionDisplay? { + let collection = GeneratedExperiences.collectionInfo[season]! + + var square = collection.squareImage + + var banner = collection.bannerImage + + let social : {String : MetadataViews.ExternalURL} = {} + for s in collection.socials.keys { + social[s] = MetadataViews.ExternalURL(collection.socials[s]!) + } + + return MetadataViews.NFTCollectionDisplay( + name: GeneratedExperiences.CollectionName, + description: collection.description, + externalURL: MetadataViews.ExternalURL("https://find.xyz/mp/".concat(GeneratedExperiences.CollectionName)), + squareImage: square, + bannerImage: banner, + socials: social + ) + + } + + access(all) resource Forge: FindForge.Forge { + access(FindForge.ForgeOwner) fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @{NonFungibleToken.NFT} { let info = data as? Info ?? panic("The data passed in is not in form as needed. Needed: ".concat(Type().identifier)) // create a new NFT @@ -280,20 +351,20 @@ pub contract GeneratedExperiences: NonFungibleToken { return <- newNFT } - pub fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { + access(FindForge.ForgeOwner) fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { let collectionInfo = data as? CollectionInfo ?? panic("The data passed in is not in form as needed. Needed: ".concat(Type().identifier)) // We cannot send in royalties directly, therefore we have to send in FindPack Royalties and generate it during minting let arr : [MetadataViews.Royalty] = [] for r in collectionInfo.royaltiesInput { // Try to get Token Switchboard - var receiverCap = getAccount(r.recipient).getCapability<&{FungibleToken.Receiver}>(/public/GenericFTReceiver) - // If it fails, try to get Find Profile - if !receiverCap.check(){ - receiverCap = getAccount(r.recipient).getCapability<&{FungibleToken.Receiver}>(/public/findProfileReceiver) + var receiverCap = getAccount(r.recipient).capabilities.get<&{FungibleToken.Receiver}>(/public/GenericFTReceiver) + + if receiverCap == nil || !receiverCap!.check() { + receiverCap = getAccount(r.recipient).capabilities.get<&{FungibleToken.Receiver}>(/public/findProfileReceiver) } - arr.append(MetadataViews.Royalty(recipient: receiverCap, cut: r.cut, description: r.description)) + arr.append(MetadataViews.Royalty(receiver: receiverCap!, cut: r.cut, description: r.description)) } collectionInfo.setRoyalty(r: arr) @@ -302,7 +373,7 @@ pub contract GeneratedExperiences: NonFungibleToken { } } - pub fun getForgeType() : Type { + access(all) fun getForgeType() : Type { return Type<@Forge>() } @@ -321,13 +392,10 @@ pub contract GeneratedExperiences: NonFungibleToken { // Create a Collection resource and save it to storage let collection <- create Collection() - self.account.save(<-collection, to: self.CollectionStoragePath) + self.account.storage.save(<-collection, to: self.CollectionStoragePath) + let cap = self.account.capabilities.storage.issue<&GeneratedExperiences.Collection>(GeneratedExperiences.CollectionStoragePath) + self.account.capabilities.publish(cap, at: GeneratedExperiences.CollectionPublicPath) - // create a public capability for the collection - self.account.link<&GeneratedExperiences.Collection{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>( - self.CollectionPublicPath, - target: self.CollectionStoragePath - ) FindForge.addForgeType(<- create Forge()) emit ContractInitialized() } diff --git a/contracts/Giefts.cdc b/contracts/Giefts.cdc index bc33ae5a..5e0e1897 100644 --- a/contracts/Giefts.cdc +++ b/contracts/Giefts.cdc @@ -1,5 +1,6 @@ import "NonFungibleToken" import "MetadataViews" +import "ViewResolver" // ___ __ // __ /'___\/\ \__ @@ -14,108 +15,165 @@ import "MetadataViews" // Giefts - wrap NFT gifts in a box and send them to your friends. // The gifts can be claimed by passing the correct password. // -pub contract Giefts { - - /**////////////////////////////////////////////////////////////// - // PATHS // - /////////////////////////////////////////////////////////////**/ +access(all) +contract Giefts{ - pub let GieftsStoragePath: StoragePath - pub let GieftsPublicPath: PublicPath - pub let GieftsPrivatePath: PrivatePath + access(all) entitlement Owner + /**/ + ///////////////////////////////////////////////////////////// - /**////////////////////////////////////////////////////////////// - // EVENTS // + // PATHS // /////////////////////////////////////////////////////////////**/ + access(all) + let GieftsStoragePath: StoragePath - pub event Packed(gieft: UInt64, nfts: [UInt64]) - pub event Added(gieft: UInt64, nft: UInt64, type: String, name: String, thumbnail: String) - pub event Removed(gieft: UInt64, nft: UInt64, type: String, name: String, thumbnail: String) - pub event Claimed(gieft: UInt64, nft: UInt64, type: String, name: String, thumbnail: String, gifter: Address?, giftee: Address?) + access(all) + let GieftsPublicPath: PublicPath - /**////////////////////////////////////////////////////////////// - // INTERFACES // + // EVENTS // /////////////////////////////////////////////////////////////**/ + access(all) + event Packed(gieft: UInt64, nfts: [UInt64]) - /// Gieft + access(all) + event Added(gieft: UInt64, nft: UInt64, type: String, name: String, thumbnail: String) + + access(all) + event Removed(gieft: UInt64, nft: UInt64, type: String, name: String, thumbnail: String) - pub resource interface GieftPublic { - pub let password: [UInt8] - pub fun borrowClaimableNFT(): &NonFungibleToken.NFT? - pub fun claimNft(password: String, collection: &AnyResource{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}) - pub fun getNftIDs(): [UInt64] + access(all) + event Claimed( + gieft: UInt64, + nft: UInt64, + type: String, + name: String, + thumbnail: String, + gifter: Address?, + giftee: Address? + ) /**/ + ///////////////////////////////////////////////////////////// + + + // INTERFACES // + /////////////////////////////////////////////////////////////**/ + /// Gieft + access(all) + resource interface GieftPublic{ + access(all) + let password: [UInt8] + + access(all) + fun borrowClaimableNFT(): &{NonFungibleToken.NFT}? + + access(all) + fun claimNft( + password: String, + collection: &{NonFungibleToken.CollectionPublic, ViewResolver.ResolverCollection} + ) + + access(all) + fun getNftIDs(): [UInt64] } /// GieftCollection + access(all) + resource interface GieftCollectionPublic{ + access(all) + fun borrowGieft(_ gieft: UInt64): &Giefts.Gieft? - pub resource interface GieftCollectionPublic { - pub fun borrowGieft(_ gieft: UInt64): &Gieft{GieftPublic}? - pub fun getGieftIDs(): [UInt64] + access(all) + fun getGieftIDs(): [UInt64] } - pub resource interface GieftCollectionPrivate { - pub fun packGieft(name: String, password: [UInt8], nfts: @{UInt64: NonFungibleToken.NFT}) - pub fun addNftToGieft(gieft: UInt64, nft: @NonFungibleToken.NFT) - pub fun unpackGieft(gieft: UInt64): @{UInt64: NonFungibleToken.NFT} - } + access(all) + resource interface GieftCollectionPrivate{ + access(Owner) + fun packGieft( + name: String, + password: [ + UInt8 + ], + nfts: @{ + UInt64:{ NonFungibleToken.NFT} + } + ): Void + + access(Owner) + fun addNftToGieft(gieft: UInt64, nft: @{NonFungibleToken.NFT}) + + access(Owner) + fun unpackGieft(gieft: UInt64): @{UInt64:{ NonFungibleToken.NFT}} + } /**/ + ///////////////////////////////////////////////////////////// - /**////////////////////////////////////////////////////////////// - // RESOURCES // - /////////////////////////////////////////////////////////////**/ + // RESOURCES // + /////////////////////////////////////////////////////////////**/ /// Gieft /// A collection of NFTs that can be claimed by passing the correct password - - pub resource Gieft: GieftPublic { + access(all) + resource Gieft: GieftPublic{ /// The name of the gieft - pub let name: String + access(all) + let name: String + /// A collection of NFTs /// nfts are stored as a map of uuids to NFTs - access(contract) var nfts: @{UInt64: NonFungibleToken.NFT} + access(contract) + var nfts: @{UInt64:{ NonFungibleToken.NFT}} /// The hashed password to claim an nft - pub let password: [UInt8] + access(all) + let password: [UInt8] /// add an NFT to the gieft - access(contract) fun addNft(nft: @NonFungibleToken.NFT) { - pre { - !self.nfts.keys.contains(nft.uuid) : "NFT uuid already added" + access(contract) + fun addNft(nft: @{NonFungibleToken.NFT}){ + pre{ + !self.nfts.keys.contains(nft.uuid): + "NFT uuid already added" } let display: MetadataViews.Display = nft.resolveView(Type())! as! MetadataViews.Display emit Added(gieft: self.uuid, nft: nft.uuid, type: nft.getType().identifier, name: display.name, thumbnail: display.thumbnail.uri()) - let oldNft <- self.nfts[nft.uuid] <-nft + let oldNft <- self.nfts[nft.uuid] <- nft destroy oldNft } /// borrwClaimableNFT /// get a reference to the first NFT that can be claimed /// @returns the first NFT that can be claimed - pub fun borrowClaimableNFT(): &NonFungibleToken.NFT? { - if self.nfts.length > 0 { - return &self.nfts[self.nfts.keys[0]] as &NonFungibleToken.NFT? - } else { + access(all) + fun borrowClaimableNFT(): &{NonFungibleToken.NFT}?{ + if self.nfts.length > 0{ + return &self.nfts[self.nfts.keys[0]] + } else{ return nil } } /// claim an NFT from the gieft /// @params password: the password to claim the NFT - pub fun claimNft(password: String, collection: &AnyResource{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}) { - pre { - self.password == HashAlgorithm.KECCAK_256.hash(password.utf8) : "Incorrect password" - self.nfts.length > 0 : "No NFTs to claim" + access(all) + fun claimNft(password: String, collection: &{NonFungibleToken.CollectionPublic, ViewResolver.ResolverCollection}){ + pre{ + self.password == HashAlgorithm.KECCAK_256.hash(password.utf8): + "Incorrect password" + self.nfts.length > 0: + "No NFTs to claim" } let nft <- self.nfts.remove(key: self.nfts.keys[0])! let display: MetadataViews.Display = nft.resolveView(Type())! as! MetadataViews.Display emit Claimed(gieft: self.uuid, nft: nft.uuid, type: nft.getType().identifier, name: display.name, thumbnail: display.thumbnail.uri(), gifter: self.owner?.address, giftee: collection.owner?.address) - collection.deposit(token: <- nft) + collection.deposit(token: <-nft) } /// unpack, a function to unpack an NFT from the gieft, this function is only callable by the owner /// @params nft: the uuid of the NFT to claim - access(contract) fun unpack(nft: UInt64): @NonFungibleToken.NFT { - pre { - self.nfts.keys.contains(nft) : "NFT does not exist" + access(contract) + fun unpack(nft: UInt64): @{NonFungibleToken.NFT}{ + pre{ + self.nfts.keys.contains(nft): + "NFT does not exist" } let nft <- self.nfts.remove(key: nft)! let display: MetadataViews.Display = nft.resolveView(Type())! as! MetadataViews.Display @@ -124,37 +182,33 @@ pub contract Giefts { } /// get all NFT ids - pub fun getNftIDs(): [UInt64] { + access(all) + fun getNftIDs(): [UInt64]{ return self.nfts.keys } - init (name: String, password: [UInt8], nfts: @{UInt64: NonFungibleToken.NFT}) { + init(name: String, password: [UInt8], nfts: @{UInt64:{ NonFungibleToken.NFT}}){ self.name = name self.nfts <- nfts self.password = password emit Packed(gieft: self.uuid, nfts: self.nfts.keys) } - - destroy () { - pre { - self.nfts.length == 0 : "All NFTs must be claimed before destroying the gieft" - } - destroy self.nfts - } } /// GieftCollection /// A collection of giefts - - pub resource GieftCollection: GieftCollectionPublic, GieftCollectionPrivate { + access(all) + resource GieftCollection: GieftCollectionPublic, GieftCollectionPrivate{ /// a collection of giefts - pub var giefts: @{UInt64: Gieft} + access(all) + var giefts: @{UInt64: Gieft} /// create a new gieft /// @params password: the hashed password to claim an NFT from the Gieft /// @params nfts: the NFTs to add to the gieft - pub fun packGieft(name: String, password: [UInt8], nfts: @{UInt64: NonFungibleToken.NFT}) { - let gieft <- create Gieft(name: name, password: password, nfts: <- nfts) + access(Owner) + fun packGieft(name: String, password: [UInt8], nfts: @{UInt64:{ NonFungibleToken.NFT}}){ + let gieft <- create Gieft(name: name, password: password, nfts: <-nfts) let oldGieft <- self.giefts[gieft.uuid] <- gieft destroy oldGieft } @@ -162,24 +216,27 @@ pub contract Giefts { /// add an NFT to a gieft /// @params gieft: the uuid of the gieft to add the NFT to /// @params nft: the NFT to add to the gieft - pub fun addNftToGieft(gieft: UInt64, nft: @NonFungibleToken.NFT) { - pre { - self.giefts.keys.contains(gieft) : "Gieft does not exist" + access(Owner) + fun addNftToGieft(gieft: UInt64, nft: @{NonFungibleToken.NFT}){ + pre{ + self.giefts.keys.contains(gieft): + "Gieft does not exist" } - self.borrowGieft(gieft)!.addNft(nft: <-nft) + (self.borrowGieft(gieft)!).addNft(nft: <-nft) } /// unpack a gieft /// @params gieft: the uuid of the gieft to unpack - pub fun unpackGieft(gieft: UInt64): @{UInt64: NonFungibleToken.NFT} { - pre { - self.giefts.keys.contains(gieft) : "Gieft does not exist" + access(Owner) + fun unpackGieft(gieft: UInt64): @{UInt64:{ NonFungibleToken.NFT}}{ + pre{ + self.giefts.keys.contains(gieft): + "Gieft does not exist" } - var nfts: @{UInt64: NonFungibleToken.NFT} <- {} - + var nfts: @{UInt64:{ NonFungibleToken.NFT}} <-{} let gieft = self.borrowGieft(gieft)! let nftIDs = gieft.getNftIDs() - for nftID in nftIDs { + for nftID in nftIDs{ let nft <- gieft.unpack(nft: nftID) let oldNft <- nfts[nftID] <- nft destroy oldNft @@ -189,37 +246,35 @@ pub contract Giefts { /// borrow a gieft reference /// @params gieft: the uuid of the gieft to borrow - pub fun borrowGieft(_ gieft: UInt64): &Gieft? { - return &self.giefts[gieft] as &Gieft? + access(all) + fun borrowGieft(_ gieft: UInt64): &Gieft?{ + return &self.giefts[gieft] } /// get all gieft ids - pub fun getGieftIDs(): [UInt64] { + access(all) + fun getGieftIDs(): [UInt64]{ return self.giefts.keys } - init () { - self.giefts <- {} + init(){ + self.giefts <-{} } + } /**/ + ///////////////////////////////////////////////////////////// - destroy () { - destroy self.giefts - } - } - /**////////////////////////////////////////////////////////////// - // FUNCTIONS // + // FUNCTIONS // /////////////////////////////////////////////////////////////**/ - /// create a new gieft collection resource - pub fun createGieftCollection (): @GieftCollection { + access(all) + fun createGieftCollection(): @GieftCollection{ return <-create GieftCollection() } - init () { + init(){ /// paths self.GieftsStoragePath = /storage/Giefts self.GieftsPublicPath = /public/Giefts - self.GieftsPrivatePath = /private/Giefts } -} \ No newline at end of file +} diff --git a/contracts/NFGv3.cdc b/contracts/NFGv3.cdc index 66271381..ddb345f4 100644 --- a/contracts/NFGv3.cdc +++ b/contracts/NFGv3.cdc @@ -1,33 +1,33 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindForge from "./FindForge.cdc" - -pub contract NFGv3: NonFungibleToken { - - pub var totalSupply: UInt64 - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - - pub let CollectionStoragePath: StoragePath - pub let CollectionPrivatePath: PrivatePath - pub let CollectionPublicPath: PublicPath - pub let MinterStoragePath: StoragePath - - pub struct Info { - pub let name: String - pub let description: String - pub let thumbnailHash: String - pub let externalURL: String - pub let edition: UInt64 - pub let maxEdition: UInt64 - pub let levels: {String: UFix64} - pub let scalars: {String: UFix64} - pub let traits: {String: String} - pub let birthday: UFix64 - pub let medias: {String: String} +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "FindForge" +import "ViewResolver" + +access(all) contract NFGv3: NonFungibleToken { + + access(all) var totalSupply: UInt64 + + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + access(all) let MinterStoragePath: StoragePath + + access(all) struct Info { + access(all) let name: String + access(all) let description: String + access(all) let thumbnailHash: String + access(all) let externalURL: String + access(all) let edition: UInt64 + access(all) let maxEdition: UInt64 + access(all) let levels: {String: UFix64} + access(all) let scalars: {String: UFix64} + access(all) let traits: {String: String} + access(all) let birthday: UFix64 + access(all) let medias: {String: String} init(name: String, description: String, thumbnailHash: String, edition:UInt64, maxEdition:UInt64, externalURL:String, traits: {String: String}, levels: {String: UFix64}, scalars: {String:UFix64}, birthday: UFix64, medias: {String: String}) { self.name=name @@ -44,10 +44,10 @@ pub contract NFGv3: NonFungibleToken { } } - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - pub let id: UInt64 + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { + access(all) let id: UInt64 - pub let info: Info + access(all) let info: Info access(self) let royalties: MetadataViews.Royalties init( @@ -59,7 +59,11 @@ pub contract NFGv3: NonFungibleToken { self.royalties = royalties } - pub fun getViews(): [Type] { + access(all) view fun getID(): UInt64 { + return self.id + } + + access(all) view fun getViews(): [Type] { return [ Type(), Type(), @@ -72,7 +76,7 @@ pub contract NFGv3: NonFungibleToken { ] } - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) fun resolveView(_ view: Type): AnyStruct? { switch view { case Type(): let traits = MetadataViews.Traits([MetadataViews.Trait(name: "Birthday", value: self.info.birthday, displayType: "date", rarity: nil)]) @@ -102,12 +106,9 @@ pub contract NFGv3: NonFungibleToken { ) case Type(): return self.royalties - case Type(): return MetadataViews.ExternalURL(self.info.externalURL) - case Type() : - let mediaList : [MetadataViews.Media]=[] for hash in self.info.medias.keys { let mediaType=self.info.medias[hash]! @@ -119,63 +120,83 @@ pub contract NFGv3: NonFungibleToken { mediaList.append(m) } return MetadataViews.Medias(mediaList) - case Type(): - return MetadataViews.NFTCollectionData( - storagePath: NFGv3.CollectionStoragePath, - publicPath: NFGv3.CollectionPublicPath, - providerPath: NFGv3.CollectionPrivatePath, - publicCollection: Type<&NFGv3.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&NFGv3.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&NFGv3.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { - return <-NFGv3.createEmptyCollection() - }) - ) + return NFGv3.resolveContractView(resourceType: Type<@NFGv3.NFT>(), viewType: Type()) case Type(): + return NFGv3.resolveContractView(resourceType: Type<@NFGv3.NFT>(), viewType: Type()) + } + return nil + } - let square = MetadataViews.Media( - file: MetadataViews.IPFSFile( - cid: "QmeG1rPaLWmn4uUSjQ2Wbs7QnjxdQDyeadCGWyGwvHTB7c", - path: nil - ), - mediaType: "image/png" - ) + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-NFGv3.createEmptyCollection(nftType:Type<@NFGv3.NFT>()) + } + } - let banner = MetadataViews.Media( - file: MetadataViews.IPFSFile( - cid: "QmWmDRnSrv8HK5QsiHwUNR4akK95WC8veydq6dnnFbMja1", - path: nil - ), - mediaType: "image/png" - ) + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] + } - return MetadataViews.NFTCollectionDisplay( - name: "NonFunGerbils", - description: "The NonFunGerbils are a collaboration between the NonFunGerbils Podcast, their audience and sometimes fabolous artists. Harnessing the power of MEMEs with creative writing and collaboration they create the most dankest, cutest gerbils in the NFT space.", - externalURL: MetadataViews.ExternalURL("https://nonfungerbils.com"), - squareImage: square, - bannerImage: banner, - socials: { - "twitter": MetadataViews.ExternalURL("https://twitter.com/NonFunGerbils") - } - ) - } - return nil + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionRef = self.account.storage.borrow<&NFGv3.Collection>( + from: NFGv3.CollectionStoragePath + ) ?? panic("Could not borrow a reference to the stored collection") + let collectionData = MetadataViews.NFTCollectionData( + storagePath: NFGv3.CollectionStoragePath, + publicPath: NFGv3.CollectionPublicPath, + publicCollection: Type<&NFGv3.Collection>(), + publicLinkedType: Type<&NFGv3.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-NFGv3.createEmptyCollection(nftType:Type<@NFGv3.NFT>()) + }) + ) + return collectionData + case Type(): + let square = MetadataViews.Media( + file: MetadataViews.IPFSFile( + cid: "QmeG1rPaLWmn4uUSjQ2Wbs7QnjxdQDyeadCGWyGwvHTB7c", + path: nil + ), + mediaType: "image/png" + ) + let banner = MetadataViews.Media( + file: MetadataViews.IPFSFile( + cid: "QmWmDRnSrv8HK5QsiHwUNR4akK95WC8veydq6dnnFbMja1", + path: nil + ), + mediaType: "image/png" + ) + return MetadataViews.NFTCollectionDisplay( + name: "NonFunGerbils", + description: "The NonFunGerbils are a collaboration between the NonFunGerbils Podcast, their audience and sometimes fabolous artists. Harnessing the power of MEMEs with creative writing and collaboration they create the most dankest, cutest gerbils in the NFT space.", + externalURL: MetadataViews.ExternalURL("https://nonfungerbils.com"), + squareImage: square, + bannerImage: banner, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/NonFunGerbils") + } + ) } + return nil } - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { + access(all) resource Collection: NonFungibleToken.Collection, ViewResolver.ResolverCollection { // dictionary of NFT conforming tokens // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} init () { self.ownedNFTs <- {} + let identifier = "NFGv3NFTCollection" } // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) @@ -185,7 +206,7 @@ pub contract NFGv3: NonFungibleToken { // deposit takes a NFT and adds it to the collections dictionary // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { let token <- token as! @NFGv3.NFT let id: UInt64 = token.id @@ -199,34 +220,55 @@ pub contract NFGv3: NonFungibleToken { } // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } // borrowNFT gets a reference to an NFT in the collection // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] } - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} { + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) let nfgNFT = nft as! &NFGv3.NFT - return nfgNFT as &AnyResource{MetadataViews.Resolver} + return nfgNFT } - destroy() { - destroy self.ownedNFTs + access(all) view fun getLength(): Int { + return self.ownedNFTs.keys.length + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create NFGv3.Collection() + } + + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[Type<@NFGv3.NFT>()] = true + return supportedTypes + } + + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + access(all) view fun isSupportedNFTType(type: Type): Bool { + if type == Type<@NFGv3.NFT>() { + return true + } else { + return false + } } } // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { + access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} { return <- create Collection() } - pub resource Forge: FindForge.Forge { - pub fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @NonFungibleToken.NFT { + access(all) resource Forge: FindForge.Forge { + access(FindForge.ForgeOwner) fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @{NonFungibleToken.NFT} { let info = data as? Info ?? panic("The data passed in is not in form of NFGv3Info.") let royalties : [MetadataViews.Royalty] = [] royalties.append(MetadataViews.Royalty(receiver:platform.platform, cut: platform.platformPercentCut, description: "find forge")) @@ -240,18 +282,17 @@ pub contract NFGv3: NonFungibleToken { royalties: MetadataViews.Royalties(royalties) ) - NFGv3.totalSupply = NFGv3.totalSupply + UInt64(1) + NFGv3.totalSupply = NFGv3.totalSupply + 1 return <- newNFT } - pub fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { + access(FindForge.ForgeOwner) fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { // not used here - panic("Not supported for NFGv3 Contract") } } - pub fun getForgeType() : Type { + access(all) fun getForgeType() : Type { return Type<@Forge>() } @@ -261,19 +302,15 @@ pub contract NFGv3: NonFungibleToken { // Set the named paths self.CollectionStoragePath = /storage/nfgNFTCollection - self.CollectionPrivatePath = /private/nfgNFTCollection self.CollectionPublicPath = /public/nfgNFTCollection self.MinterStoragePath = /storage/nfgNFTMinter // Create a Collection resource and save it to storage let collection <- create Collection() - self.account.save(<-collection, to: self.CollectionStoragePath) + self.account.storage.save(<-collection, to: self.CollectionStoragePath) + let collectionCap = self.account.capabilities.storage.issue<&{NonFungibleToken.Collection}>(self.CollectionStoragePath) + self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath) - // create a public capability for the collection - self.account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>( - self.CollectionPublicPath, - target: self.CollectionStoragePath - ) FindForge.addForgeType(<- create Forge()) emit ContractInitialized() } diff --git a/contracts/NFTRegistry.cdc b/contracts/NFTRegistry.cdc deleted file mode 100644 index 6d129c5c..00000000 --- a/contracts/NFTRegistry.cdc +++ /dev/null @@ -1,134 +0,0 @@ -//This contract is temporary until dapper finishes their initiative -pub contract NFTRegistry { - - /* Event */ - pub event ContractInitialized() - pub event NFTInfoRegistered(alias: String, typeIdentifier: String) - pub event NFTInfoRemoved(alias: String, typeIdentifier: String) - - /* Variables */ - // Mapping of {Type Identifier : NFT Info Struct} - access(contract) var nonFungibleTokenList : {String : NFTInfo} - - // Mapping of {Alias : Type Identifier} - access(contract) var aliasMap : {String : String} - - //TODO: name of init transactions - //TODO: name of check storage slot script - /* Struct */ - pub struct NFTInfo { - pub let alias : String - // Pass in @NFT type - pub let type : Type - pub let typeIdentifier : String - pub let icon : String? - pub let providerPath : PrivatePath - pub let providerPathIdentifier : String - // Must implement {MetadataViews.ResolverCollection} - pub let publicPath : PublicPath - pub let publicPathIdentifier : String - pub let storagePath : StoragePath - pub let storagePathIdentifier : String - // Pass in arrays of allowed Token Vault, nil => support all types of FTs - pub let allowedFTTypes : [Type]? - // Pass in the Contract Address - pub let address : Address - pub let externalFixedUrl : String - - init(alias: String, type: Type, typeIdentifier: String, icon: String?, providerPath: PrivatePath, publicPath: PublicPath, storagePath: StoragePath, allowedFTTypes: [Type]?, address: Address, externalFixedUrl: String) { - self.alias = alias - self.type = type - self.typeIdentifier = typeIdentifier - self.icon = icon - self.providerPath = providerPath - self.providerPathIdentifier = providerPath.toString().slice(from: "/private/".length, upTo: providerPath.toString().length) - self.publicPath = publicPath - self.publicPathIdentifier = publicPath.toString().slice(from: "/public/".length, upTo: publicPath.toString().length) - self.storagePath = storagePath - self.storagePathIdentifier = storagePath.toString().slice(from: "/storage/".length, upTo: storagePath.toString().length) - self.allowedFTTypes = allowedFTTypes - self.address = address - self.externalFixedUrl = externalFixedUrl - } - } - - /* getters */ - pub fun getNFTInfoByTypeIdentifier(_ typeIdentifier: String) : NFTInfo? { - return NFTRegistry.nonFungibleTokenList[typeIdentifier] - } - - pub fun getNFTInfoByAlias(_ alias: String) : NFTInfo? { - if let identifier = NFTRegistry.aliasMap[alias] { - return NFTRegistry.nonFungibleTokenList[identifier] - } - return nil - } - - pub fun getNFTInfo(_ input: String) : NFTInfo? { - if let info = self.getNFTInfoByAlias(input) { - return info - } - if let info = self.getNFTInfoByTypeIdentifier(input) { - return info - } - return nil - } - - pub fun getTypeIdentifier(_ alias: String) : String? { - return NFTRegistry.aliasMap[alias] - } - - pub fun getNFTInfoAll() : {String : NFTInfo} { - return NFTRegistry.nonFungibleTokenList - } - - pub fun getSupportedNFTAlias() : [String] { - return NFTRegistry.aliasMap.keys - } - - pub fun getSupportedNFTTypeIdentifier() : [String] { - return NFTRegistry.aliasMap.values - } - - /* setters */ - access(account) fun setNFTInfo(alias: String, type: Type, icon: String?, providerPath: PrivatePath, publicPath: PublicPath, storagePath: StoragePath, allowedFTTypes: [Type]?, address: Address, externalFixedUrl: String ) { - if NFTRegistry.nonFungibleTokenList.containsKey(type.identifier) { - panic("This NonFungibleToken Register already exist") - } - let typeIdentifier : String = type.identifier - NFTRegistry.nonFungibleTokenList[typeIdentifier] = NFTInfo(alias: alias, - type: type, - typeIdentifier: typeIdentifier, - icon: icon, - providerPath: providerPath, - publicPath: publicPath, - storagePath: storagePath, - allowedFTTypes: allowedFTTypes, - address: address, - externalFixedUrl: externalFixedUrl) - - NFTRegistry.aliasMap[alias] = typeIdentifier - emit NFTInfoRegistered(alias: alias, typeIdentifier: typeIdentifier) - } - - access(account) fun removeNFTInfoByTypeIdentifier(_ typeIdentifier: String) : NFTInfo { - let info = NFTRegistry.nonFungibleTokenList.remove(key: typeIdentifier) ?? panic("Cannot find this NonFungibleToken Registry. Type : ".concat(typeIdentifier)) - NFTRegistry.aliasMap.remove(key: info.alias) - emit NFTInfoRemoved(alias:info!.alias, typeIdentifier: info!.typeIdentifier) - return info - } - - access(account) fun removeNFTInfoByAlias(_ alias: String) : NFTInfo { - let typeIdentifier = self.getTypeIdentifier(alias) ?? panic("Cannot find type identifier from this alias. Alias : ".concat(alias)) - return self.removeNFTInfoByTypeIdentifier(typeIdentifier) - } - - init() { - self.nonFungibleTokenList = {} - self.aliasMap = {} - } - - -} - - diff --git a/contracts/NameVoucher.cdc b/contracts/NameVoucher.cdc index f1b24d2e..3f830245 100644 --- a/contracts/NameVoucher.cdc +++ b/contracts/NameVoucher.cdc @@ -1,292 +1,372 @@ -import FungibleToken from "./standard/FungibleToken.cdc" -import FlowToken from "./standard/FlowToken.cdc" -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FungibleTokenSwitchboard from "./standard/FungibleTokenSwitchboard.cdc" -import Profile from "./Profile.cdc" -import FIND from "./FIND.cdc" -import FindViews from "./FindViews.cdc" -// import FindAirdropper from "./FindAirdropper.cdc" - -pub contract NameVoucher: NonFungibleToken { - - pub var totalSupply: UInt64 - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id:UInt64, address:Address, minCharLength: UInt64) - - pub event Destroyed(id: UInt64, address: Address?, minCharLength: UInt64) - pub event Redeemed(id: UInt64, address: Address?, minCharLength: UInt64, findName: String, action: String) - - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - pub let CollectionPrivatePath: PrivatePath - - pub var royalties : [MetadataViews.Royalty] - pub var thumbnail : {MetadataViews.File} - - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - - pub let id:UInt64 - pub var nounce:UInt64 - // 3 characters voucher should be able to claim name with at LEAST 3 char and so on - pub let minCharLength:UInt64 - - init( - minCharLength: UInt64 - ) { - self.nounce=0 - self.minCharLength=minCharLength - self.id=self.uuid - } - - destroy() { - emit Destroyed(id: self.id, address: self.owner?.address, minCharLength: self.minCharLength) - } - - pub fun getViews(): [Type] { - return [ - Type(), - Type(), - Type(), - Type(), - Type(), - Type() - ] - } - - pub fun resolveView(_ view: Type): AnyStruct? { - - var imageFile=NameVoucher.thumbnail - - switch self.minCharLength { - case 3 : - imageFile = MetadataViews.IPFSFile(cid: "QmYMtXfFcgpJgm3Mhy68r6cuHTCMMcucVUpYTVeSRTWLTh", path: nil) - - case 4 : - imageFile = MetadataViews.IPFSFile(cid: "QmWpQRvGudYrkZw6rKKTrkghkYKs4wt3KQGzxcXJ8JmuSc", path: nil) - } - - let name= self.minCharLength.toString().concat("-characters .find name voucher") - let description ="This voucher entitles the holder to claim or extend any available or owned .find name with ".concat(self.minCharLength.toString()).concat(" characters or more. It is valid for one-time use only and will be voided after the successful registration or extension of a .find name.\n\nIf you received this voucher via airdrop, check your inbox to claim it. Once claimed, it will be added to your collection. To use the voucher, follow these steps:\nLog in to your account.\nNavigate to the Collection page and locate the voucher you wish to use.\nClick the “Use Voucher” button and follow the on-screen instructions to register a new .find name or extend an existing one.\nUpon successful completion, the voucher will be invalidated, and the chosen .find name will be registered or extended under your account.") - - switch view { - case Type(): - return MetadataViews.Display( - name: name, - description: description, - thumbnail: imageFile - ) - - case Type(): - return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/nameVoucher/").concat(self.id.toString())) - - case Type(): - return MetadataViews.Royalties(NameVoucher.royalties) - - case Type(): - let externalURL = MetadataViews.ExternalURL("https://find.xyz/") - let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_images/1467546091780550658/R1uc6dcq_400x400.jpg"), mediaType: "image") - let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1448245049666510848/1674733461/1500x500"), mediaType: "image") - let desc = "Name Vouchers can be used to claim or extend any available .find name of 3-characters or more, depending on voucher rarity. Vouchers can be used only once and will be destroyed after use. Enjoy!" - return MetadataViews.NFTCollectionDisplay( - name: "NameVoucher", - description: desc, - externalURL: externalURL, - squareImage: squareImage, - bannerImage: bannerImage, - socials: { - "discord": MetadataViews.ExternalURL("https://discord.gg/findonflow"), - "twitter" : MetadataViews.ExternalURL("https://twitter.com/findonflow") - } - ) - - case Type(): - return MetadataViews.NFTCollectionData(storagePath: NameVoucher.CollectionStoragePath, - publicPath: NameVoucher.CollectionPublicPath, - providerPath: NameVoucher.CollectionPrivatePath, - publicCollection: Type<&Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: fun(): @NonFungibleToken.Collection {return <- NameVoucher.createEmptyCollection()}) - - case Type(): - return MetadataViews.Traits([ - MetadataViews.Trait( - name: "Minimum number of characters", - value: self.minCharLength, - displayType: "number", - rarity: nil - ) - ]) - } - return nil - } - - access(contract) fun increaseNounce() { - self.nounce=self.nounce+1 - } - - } - - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} - - init () { - self.ownedNFTs <- {} - } - - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") - - emit Withdraw(id: token.id, from: self.owner?.address) - - return <-token - } - - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { - let token <- token as! @NFT - - let id: UInt64 = token.id - //TODO: add nounce and emit better event the first time it is moved. - - token.increaseNounce() - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) - - - destroy oldToken - } - - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { - return self.ownedNFTs.keys - } - - pub fun contains(_ id: UInt64) : Bool { - return self.ownedNFTs.containsKey(id) - } - - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! - } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let vr = nft as! &NFT - return vr as &AnyResource{MetadataViews.Resolver} - } - - pub fun redeem(id: UInt64, name: String) { - let nft <- self.ownedNFTs.remove(key: id) ?? panic("Cannot find voucher with ID ".concat(id.toString())) - let typedNFT <- nft as! @NameVoucher.NFT - let nameLength = UInt64(name.length) - let minLength = typedNFT.minCharLength - - // Assert that the name voucher is valid for claiming name with this length - assert(nameLength >= minLength, message: "You are trying to register a ".concat(nameLength.toString()).concat(" character name, but the voucher can only support names with minimun character of ").concat(minLength.toString())) - destroy typedNFT - - // get All the paths here for registration - let network = NameVoucher.account.borrow<&FIND.Network>(from: FIND.NetworkStoragePath) ?? panic("Cannot borrow find network for registration") - let status = FIND.status(name) - - // If the lease is free, we register it - if status.status == FIND.LeaseStatus.FREE { - let profile = self.owner!.getCapability<&{Profile.Public}>(Profile.publicPath) - let lease = self.owner!.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - network.internal_register(name: name, profile: profile, leases: lease) - emit Redeemed(id: id, address: self.owner?.address, minCharLength: minLength, findName: name, action: "register") - return - } - - // If the lease is already taken / locked, we check if that's under the name of the voucher owner, then extend it - if status.owner != nil && status.owner! == self.owner!.address { - network.internal_renew(name: name) - emit Redeemed(id: id, address: self.owner?.address, minCharLength: minLength, findName: name, action: "renew") - return - } - - panic("Name is already taken by others ".concat(status.owner!.toString())) - } - - destroy() { - destroy self.ownedNFTs - } - } - - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } - - // Internal mint NFT is used inside the contract as a helper function - // It DOES NOT emit events so the admin function calling this should emit that - access(account) fun mintNFT( - recipient: &{NonFungibleToken.Receiver}, - minCharLength: UInt64 - ) : UInt64 { - pre { - recipient.owner != nil : "Recipients NFT collection is not owned" - } - - NameVoucher.totalSupply = NameVoucher.totalSupply + 1 - // create a new NFT - var newNFT <- create NFT( - minCharLength: minCharLength - ) - - let id = newNFT.id - recipient.deposit(token: <-newNFT) - emit Minted(id: id, address: recipient.owner!.address, minCharLength: minCharLength) - return id - } - - access(account) fun setRoyaltycut(_ cutInfo: [MetadataViews.Royalty]) { - NameVoucher.royalties = cutInfo - } - - init() { - // Initialize the total supply - self.totalSupply = 0 - - // Set Royalty cuts in a transaction - self.royalties = [ - MetadataViews.Royalty( - receiver: NameVoucher.account.getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath), - cut: 0.025, - description: "network" - ) - ] - // 5 - letter Thumbnail - self.thumbnail = MetadataViews.IPFSFile(cid: "QmWj3bwRfksGXvFQYoWtjdycD68cp4xRGMJonnDibsN6Rz", path: nil) - - // Set the named paths - self.CollectionStoragePath = /storage/nameVoucher - self.CollectionPublicPath = /public/nameVoucher - self.CollectionPrivatePath = /private/nameVoucher - - self.account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - self.account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - self.account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - - emit ContractInitialized() - } +import "FungibleToken" +import "FlowToken" +import "NonFungibleToken" +import "MetadataViews" +import "ViewResolver" +import "FungibleTokenSwitchboard" +import "Profile" +import "FIND" +import "FindViews" +import "FindAirdropper" + +access(all) contract NameVoucher :NonFungibleToken{ + + access(all) var totalSupply: UInt64 + + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Minted(id:UInt64, address:Address, minCharLength: UInt64) + + access(all) event Destroyed(id: UInt64, address: Address?, minCharLength: UInt64) + access(all) event Redeemed(id: UInt64, address: Address?, minCharLength: UInt64, findName: String, action: String) + + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + + access(all) var royalties : [MetadataViews.Royalty] + access(all) var thumbnail : {MetadataViews.File} + + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { + access(all) let id:UInt64 + access(all) var nounce:UInt64 + // 3 characters voucher should be able to claim name with at LEAST 3 char and so on + access(all) let minCharLength:UInt64 + + init( + minCharLength: UInt64 + ) { + self.nounce=0 + self.minCharLength=minCharLength + self.id=self.uuid + } + + access(all) view fun getViews(): [Type] { + return [ + Type(), + Type(), + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) view fun getID() : UInt64 { + return self.id + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + + var imageFile=NameVoucher.thumbnail + + switch self.minCharLength { + case 3 : + imageFile = MetadataViews.IPFSFile(cid: "QmYMtXfFcgpJgm3Mhy68r6cuHTCMMcucVUpYTVeSRTWLTh", path: nil) + + case 4 : + imageFile = MetadataViews.IPFSFile(cid: "QmWpQRvGudYrkZw6rKKTrkghkYKs4wt3KQGzxcXJ8JmuSc", path: nil) + } + + let name= self.minCharLength.toString().concat("-characters .find name voucher") + let description ="This voucher entitles the holder to claim or extend any available or owned .find name with ".concat(self.minCharLength.toString()).concat(" characters or more. It is valid for one-time use only and will be voided after the successful registration or extension of a .find name.\n\nIf you received this voucher via airdrop, check your inbox to claim it. Once claimed, it will be added to your collection. To use the voucher, follow these steps:\nLog in to your account.\nNavigate to the Collection page and locate the voucher you wish to use.\nClick the “Use Voucher” button and follow the on-screen instructions to register a new .find name or extend an existing one.\nUpon successful completion, the voucher will be invalidated, and the chosen .find name will be registered or extended under your account.") + + switch view { + case Type(): + return MetadataViews.Display( + name: name, + description: description, + thumbnail: imageFile + ) + + case Type(): + return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/nameVoucher/").concat(self.id.toString())) + + case Type(): + return MetadataViews.Royalties(NameVoucher.royalties) + + case Type(): + let externalURL = MetadataViews.ExternalURL("https://find.xyz/") + let squareImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_images/1467546091780550658/R1uc6dcq_400x400.jpg"), mediaType: "image") + let bannerImage = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://pbs.twimg.com/profile_banners/1448245049666510848/1674733461/1500x500"), mediaType: "image") + let desc = "Name Vouchers can be used to claim or extend any available .find name of 3-characters or more, depending on voucher rarity. Vouchers can be used only once and will be destroyed after use. Enjoy!" + return MetadataViews.NFTCollectionDisplay( + name: "NameVoucher", + description: desc, + externalURL: externalURL, + squareImage: squareImage, + bannerImage: bannerImage, + socials: { + "discord": MetadataViews.ExternalURL("https://discord.gg/findonflow"), + "twitter" : MetadataViews.ExternalURL("https://twitter.com/findonflow") + } + ) + + case Type(): + return NameVoucher.resolveContractView(resourceType: Type<@NameVoucher.NFT>(), viewType: Type()) + case Type(): + return MetadataViews.Traits([ + MetadataViews.Trait( + name: "Minimum number of characters", + value: self.minCharLength, + displayType: "number", + rarity: nil + ) + ]) + } + return nil + } + + access(contract) fun increaseNounce() { + self.nounce=self.nounce+1 + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-NameVoucher.createEmptyCollection(nftType:Type<@NameVoucher.NFT>()) + } + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionRef = self.account.storage.borrow<&NameVoucher.Collection>( + from: NameVoucher.CollectionStoragePath + ) ?? panic("Could not borrow a reference to the stored collection") + let collectionData = MetadataViews.NFTCollectionData( + storagePath: NameVoucher.CollectionStoragePath, + publicPath: NameVoucher.CollectionPublicPath, + publicCollection: Type<&NameVoucher.Collection>(), + publicLinkedType: Type<&NameVoucher.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-NameVoucher.createEmptyCollection(nftType:Type<@NameVoucher.NFT>()) + }) + ) + return collectionData + } + return nil + } + + access(all) entitlement Owner + + access(all) resource Collection: NonFungibleToken.Collection, ViewResolver.ResolverCollection { + // dictionary of NFT conforming tokens + // NFT is a resource type with an `UInt64` ID field + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + + init () { + self.ownedNFTs <- {} + } + + // withdraw removes an NFT from the collection and moves it to the caller + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") + + emit Withdraw(id: token.id, from: self.owner?.address) + + return <-token + } + + // deposit takes a NFT and adds it to the collections dictionary + // and adds the ID to the id array + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { + let token <- token as! @NFT + + let id: UInt64 = token.id + + token.increaseNounce() + // add the new token to the dictionary which removes the old one + let oldToken <- self.ownedNFTs[id] <- token + + emit Deposit(id: id, to: self.owner?.address) + + + destroy oldToken + } + // getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { + return self.ownedNFTs.keys + } + + access(all) fun contains(_ id: UInt64) : Bool { + return self.ownedNFTs.containsKey(id) + } + + // borrowNFT gets a reference to an NFT in the collection + // so that the caller can read its metadata and call its methods + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] + } + + + /// Borrow the view resolver for the specified NFT ID + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? { + if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? { + return nft as &{ViewResolver.Resolver} + } + return nil + } + + access(Owner) fun redeem(id: UInt64, name: String) { + let nft <- self.ownedNFTs.remove(key: id) ?? panic("Cannot find voucher with ID ".concat(id.toString())) + let typedNFT <- nft as! @NameVoucher.NFT + let nameLength = UInt64(name.length) + let minLength = typedNFT.minCharLength + + // Assert that the name voucher is valid for claiming name with this length + assert(nameLength >= minLength, message: "You are trying to register a ".concat(nameLength.toString()).concat(" character name, but the voucher can only support names with minimun character of ").concat(minLength.toString())) + destroy typedNFT + + // get All the paths here for registration + let network = NameVoucher.account.storage.borrow<&FIND.Network>(from: FIND.NetworkStoragePath) ?? panic("Cannot borrow find network for registration") + let status = FIND.status(name) + + // If the lease is free, we register it + if status.status == FIND.LeaseStatus.FREE { + let profile = self.owner!.capabilities.get<&{Profile.Public}>(Profile.publicPath)! + let lease = self.owner!.capabilities.get<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)! + network.internal_register(name: name, profile: profile, leases: lease) + emit Redeemed(id: id, address: self.owner?.address, minCharLength: minLength, findName: name, action: "register") + return + } + + // If the lease is already taken / locked, we check if that's under the name of the voucher owner, then extend it + if status.owner != nil && status.owner! == self.owner!.address { + network.internal_renew(name: name) + emit Redeemed(id: id, address: self.owner?.address, minCharLength: minLength, findName: name, action: "renew") + return + } + + panic("Name is already taken by others ".concat(status.owner!.toString())) + } + + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + return supportedTypes + } + + /// Returns whether or not the given type is accepted by the collection + access(all) view fun isSupportedNFTType(type: Type): Bool { + return type == Type<@NameVoucher.NFT>() + } + + /// Gets the amount of NFTs stored in the collection + access(all) view fun getLength(): Int { + return self.ownedNFTs.length + } + + /// getIDsWithTypes returns a list of IDs that are in the collection, keyed by type + /// Should only be used by collections that can store multiple NFT types + access(all) view fun getIDsWithTypes(): {Type: [UInt64]} { + let ids: {Type: [UInt64]} = {} + return ids + } + + // public function that anyone can call to create a new empty collection + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- NameVoucher.createEmptyCollection(nftType:Type<@NameVoucher.NFT>()) + } + + access(all) view fun getDefaultStoragePath() : StoragePath { + return NameVoucher.CollectionStoragePath + } + + access(all) view fun getDefaultPublicPath() : PublicPath { + return NameVoucher.CollectionPublicPath + } + + } + + // Internal mint NFT is used inside the contract as a helper function + // It DOES NOT emit events so the admin function calling this should emit that + access(account) fun mintNFT( + recipient: &{NonFungibleToken.Receiver}, + minCharLength: UInt64 + ) : UInt64 { + pre { + recipient.owner != nil : "Recipients NFT collection is not owned" + } + + NameVoucher.totalSupply = NameVoucher.totalSupply + 1 + // create a new NFT + var newNFT <- create NFT( + minCharLength: minCharLength + ) + + let id = newNFT.id + recipient.deposit(token: <-newNFT) + emit Minted(id: id, address: recipient.owner!.address, minCharLength: minCharLength) + return id + } + + access(account) fun setRoyaltycut(_ cutInfo: [MetadataViews.Royalty]) { + NameVoucher.royalties = cutInfo + } + + // public function that anyone can call to create a new empty collection + access(all) fun createEmptyCollection(nftType:Type): @{NonFungibleToken.Collection} { + return <- create Collection() + } + + init() { + // Initialize the total supply + self.totalSupply = 0 + + // Check if the account already has a Switchboard resource + if self.account.storage.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath) == nil { + // Create a new Switchboard resource and put it into storage + self.account.storage.save( + <- FungibleTokenSwitchboard.createSwitchboard(), + to: FungibleTokenSwitchboard.StoragePath + ) + + // Clear existing Capabilities at canonical paths + self.account.capabilities.unpublish(FungibleTokenSwitchboard.ReceiverPublicPath) + self.account.capabilities.unpublish(FungibleTokenSwitchboard.PublicPath) + + // Create a public capability to the Switchboard exposing the deposit + // function through the {FungibleToken.Receiver} interface + let receiverCap = self.account.capabilities.storage.issue<&{FungibleToken.Receiver}>( + FungibleTokenSwitchboard.StoragePath + ) + self.account.capabilities.publish(receiverCap, at: FungibleTokenSwitchboard.ReceiverPublicPath) + + // Create a public capability to the Switchboard exposing both the + // {FungibleTokenSwitchboard.SwitchboardPublic} and the + // {FungibleToken.Receiver} interfaces + let switchboardPublicCap = self.account.capabilities.storage.issue<&{FungibleTokenSwitchboard.SwitchboardPublic, FungibleToken.Receiver}>( + FungibleTokenSwitchboard.StoragePath + ) + self.account.capabilities.publish(switchboardPublicCap, at: FungibleTokenSwitchboard.PublicPath) + } + + // Set Royalty cuts in a transaction + + self.royalties = [ + MetadataViews.Royalty( + receiver: NameVoucher.account.capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath)! , + cut: 0.025, + description: "network" + ) + ] + + // 5 - letter Thumbnail + self.thumbnail = MetadataViews.IPFSFile(cid: "QmWj3bwRfksGXvFQYoWtjdycD68cp4xRGMJonnDibsN6Rz", path: nil) + + // Set the named paths + self.CollectionStoragePath = /storage/nameVoucher + self.CollectionPublicPath = /public/nameVoucher + + self.account.storage.save<@{NonFungibleToken.Collection}>(<- NameVoucher.createEmptyCollection(nftType:Type<@NameVoucher.NFT>()) , to: NameVoucher.CollectionStoragePath) + let collectionCap = self.account.capabilities.storage.issue<&NameVoucher.Collection>(NameVoucher.CollectionStoragePath) + self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath) + + emit ContractInitialized() + } } diff --git a/contracts/PartyFavorz.cdc b/contracts/PartyFavorz.cdc index ff7a6edd..d85eb586 100644 --- a/contracts/PartyFavorz.cdc +++ b/contracts/PartyFavorz.cdc @@ -1,350 +1,397 @@ -import NonFungibleToken from "./standard/NonFungibleToken.cdc" -import FungibleToken from "./standard/FungibleToken.cdc" -import MetadataViews from "./standard/MetadataViews.cdc" -import FindForge from "./FindForge.cdc" -import FindPack from "./FindPack.cdc" -import PartyFavorzExtraData from "./PartyFavorzExtraData.cdc" - -pub contract PartyFavorz: NonFungibleToken { - - pub var totalSupply: UInt64 - - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Minted(id:UInt64, serial: UInt64, season: UInt64, name: String ) - - pub let CollectionStoragePath: StoragePath - pub let CollectionPrivatePath: PrivatePath - pub let CollectionPublicPath: PublicPath - pub let MinterStoragePath: StoragePath - - pub let royalties: [MetadataViews.Royalty] - - pub struct Info { - pub let name: String - pub let description: String - pub let thumbnailHash: String - pub let edition: UInt64 - pub let maxEdition: UInt64 - pub let fullsizeHash: String - pub let artist: String - - init(name: String, description: String, thumbnailHash: String, edition:UInt64, maxEdition:UInt64, fullsizeHash: String, artist: String) { - self.name=name - self.description=description - self.thumbnailHash=thumbnailHash - self.edition=edition - self.maxEdition=maxEdition - self.fullsizeHash=fullsizeHash - self.artist=artist - } - } - - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - pub let id: UInt64 - - pub let info: Info - - init( - info: Info, - season: UInt64, - royalties: [MetadataViews.Royalty], - squareImage: String, - bannerImage: String - ) { - self.id = self.uuid - self.info=info - - PartyFavorzExtraData.setData(id: self.id, field: "season", value: season) - PartyFavorzExtraData.setData(id: self.id, field: "royalties", value: royalties) - PartyFavorzExtraData.setData(id: self.id, field: "nftCollectionDisplay", value: {"squareImage" : squareImage, "bannerImage" : bannerImage}) - } - - pub fun getViews(): [Type] { - return [ - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type() - ] - } - - pub fun resolveView(_ view: Type): AnyStruct? { - - - let imageFile = MetadataViews.IPFSFile( cid: self.info.thumbnailHash, path: nil) - - switch view { - - case Type(): - let data : {String : String} = { - "nftImage" : imageFile.uri() , - "nftName" : self.info.name, - "packType" : "PartyFavorz" - } - return FindPack.PackRevealData(data) - - case Type(): - return MetadataViews.Display( - name: self.info.name, - description: self.info.description, - thumbnail: MetadataViews.IPFSFile( - cid: self.info.thumbnailHash, path: nil - ) - ) - case Type(): - let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season") - var season = 1 as UInt64 - if seasonData != nil { - season = seasonData! as! UInt64 - } - let editionInfo = MetadataViews.Edition(name: "season ".concat(season.toString()), number: self.info.edition, max: self.info.maxEdition) - let editionList: [MetadataViews.Edition] = [editionInfo] - return MetadataViews.Editions( - editionList - ) - case Type(): - let royaltiesData = PartyFavorzExtraData.getData(id: self.id, field: "royalties") - if royaltiesData != nil { - let r = royaltiesData! as! [MetadataViews.Royalty] - return MetadataViews.Royalties(r) - } - return MetadataViews.Royalties(PartyFavorz.royalties) - - case Type(): - if self.owner != nil { - return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/partyfavorz/").concat(self.id.toString())) - } - return MetadataViews.ExternalURL("https://find.xyz/") - - case Type(): - return MetadataViews.NFTCollectionData( - storagePath: PartyFavorz.CollectionStoragePath, - publicPath: PartyFavorz.CollectionPublicPath, - providerPath: PartyFavorz.CollectionPrivatePath, - publicCollection: Type<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { - return <-PartyFavorz.createEmptyCollection() - }) - ) - case Type(): - - var square = MetadataViews.Media( - file: MetadataViews.IPFSFile( - cid: "QmNkJGEzNYzXsKFqCMweFZBZ9cMQsfMUzV2ZDh2Nn8a1Xc", - path: nil - ), - mediaType: "image/png" - ) - - var banner = MetadataViews.Media( - file: MetadataViews.IPFSFile( - cid: "QmVuMpDyJXHMCK9LnFboemWfPYabcwPNEmXgQMWbtxtGWD", - path: nil - ), - mediaType: "image/png" - ) - - let nftCollectionDisplayData = PartyFavorzExtraData.getData(id: self.id, field: "nftCollectionDisplay") - if nftCollectionDisplayData != nil { - let nftCollectionDisplay = nftCollectionDisplayData! as! {String : String} - - square = MetadataViews.Media( - file: MetadataViews.IPFSFile( - cid: nftCollectionDisplay["squareImage"]!, - path: nil - ), - mediaType: "image/png" - ) - - banner = MetadataViews.Media( - file: MetadataViews.IPFSFile( - cid: nftCollectionDisplay["bannerImage"]!, - path: nil - ), - mediaType: "image/png" - ) - - } - - return MetadataViews.NFTCollectionDisplay( - name: "PartyFavorz", - description: "By owning a Party Favorz NFT, you are granted access to the VIP sections of our virtual parties which include, but are not limited to major giveaways, 1 on 1s with artists/project leaders, and some IRL utility that involves partying, down the line. By owning Party Favorz, you are supporting the idea of community coming together for a few goals that include having fun, being positive, learning, and most importantly SUPPORTING ARTISTS.", - externalURL: MetadataViews.ExternalURL("https://find.xyz/partyfavorz"), - squareImage: square, - bannerImage: banner, - socials: { - "twitter": MetadataViews.ExternalURL("https://twitter.com/FlowPartyFavorz"), - "discord" : MetadataViews.ExternalURL("https://discord.gg/bM76F34EnN") - } - ) - - case Type() : - let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season") - var season = 1 as UInt64 - if seasonData != nil { - season = seasonData! as! UInt64 - } - return MetadataViews.Traits([ - MetadataViews.Trait(name: "Artist", value: self.info.artist, displayType: "String", rarity: nil) , - MetadataViews.Trait(name: "Season", value: season, displayType: "Numeric", rarity: nil) - ]) - - case Type() : - let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season") - var season = 1 as UInt64 - if seasonData != nil { - season = seasonData! as! UInt64 - } - - var thumbnailMediaType = "image/png" - var fullImageMediaType = "image/png" - - switch season { - case 2 as UInt64 : - fullImageMediaType = "image/gif" - - } - - return MetadataViews.Medias([ - MetadataViews.Media(file: MetadataViews.IPFSFile(cid: self.info.thumbnailHash, path: nil), mediaType: thumbnailMediaType), - MetadataViews.Media(file: MetadataViews.IPFSFile(cid: self.info.fullsizeHash, path: nil), mediaType: fullImageMediaType) - ]) - } - return nil - } - } - - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} - - init () { - self.ownedNFTs <- {} - } - - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") - - emit Withdraw(id: token.id, from: self.owner?.address) - - return <-token - } - - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { - let token <- token as! @PartyFavorz.NFT - - let id: UInt64 = token.id - - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) - - destroy oldToken - } - - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { - return self.ownedNFTs.keys - } - - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! - } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let PartyFavorz = nft as! &PartyFavorz.NFT - return PartyFavorz as &AnyResource{MetadataViews.Resolver} - } - - destroy() { - destroy self.ownedNFTs - } - } - - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { - return <- create Collection() - } - - pub resource Forge: FindForge.Forge { - pub fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @NonFungibleToken.NFT { - let info = data as? {String : AnyStruct} ?? panic("The data passed in is not in form as needed.") - - assert(info.length == 5, message: "Please make sure to pass in `Info, season, royalties, squareImage, bannerImage`") - - // create a new NFT - var newNFT <- create NFT( - info: info["info"]! as! Info, - season: info["season"]! as! UInt64, - royalties: info["royalties"]! as! [MetadataViews.Royalty], - squareImage: info["squareImage"]! as! String, - bannerImage: info["bannerImage"]! as! String - ) +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "FindForge" +import "FindPack" +import "PartyFavorzExtraData" +import "ViewResolver" + +access(all) contract PartyFavorz: NonFungibleToken { + + access(all) var totalSupply: UInt64 + + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Minted(id:UInt64, serial: UInt64, season: UInt64, name: String ) + + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + access(all) let MinterStoragePath: StoragePath + + access(all) let royalties: [MetadataViews.Royalty] + + access(all) struct Info { + access(all) let name: String + access(all) let description: String + access(all) let thumbnailHash: String + access(all) let edition: UInt64 + access(all) let maxEdition: UInt64 + access(all) let fullsizeHash: String + access(all) let artist: String + + init(name: String, description: String, thumbnailHash: String, edition:UInt64, maxEdition:UInt64, fullsizeHash: String, artist: String) { + self.name=name + self.description=description + self.thumbnailHash=thumbnailHash + self.edition=edition + self.maxEdition=maxEdition + self.fullsizeHash=fullsizeHash + self.artist=artist + } + } + + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { + access(all) let id: UInt64 + access(all) let info: Info + + init( + info: Info, + season: UInt64, + royalties: [MetadataViews.Royalty], + squareImage: String, + bannerImage: String + ) { + self.id = self.uuid + self.info=info + + PartyFavorzExtraData.setData(id: self.id, field: "season", value: season) + PartyFavorzExtraData.setData(id: self.id, field: "royalties", value: royalties) + PartyFavorzExtraData.setData(id: self.id, field: "nftCollectionDisplay", value: {"squareImage" : squareImage, "bannerImage" : bannerImage}) + } + + access(all) view fun getID(): UInt64 { + return self.id + } + + access(all) view fun getViews(): [Type] { + return [ + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + let imageFile = MetadataViews.IPFSFile( cid: self.info.thumbnailHash, path: nil) + + switch view { + + case Type(): + let data : {String : String} = { + "nftImage" : imageFile.uri() , + "nftName" : self.info.name, + "packType" : "PartyFavorz" + } + return FindPack.PackRevealData(data) + + case Type(): + return MetadataViews.Display( + name: self.info.name, + description: self.info.description, + thumbnail: MetadataViews.IPFSFile( + cid: self.info.thumbnailHash, path: nil + ) + ) + case Type(): + let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season") + var season = 1 as UInt64 + if seasonData != nil { + season = seasonData! as! UInt64 + } + let editionInfo = MetadataViews.Edition(name: "season ".concat(season.toString()), number: self.info.edition, max: self.info.maxEdition) + let editionList: [MetadataViews.Edition] = [editionInfo] + return MetadataViews.Editions( + editionList + ) + case Type(): + let royaltiesData = PartyFavorzExtraData.getData(id: self.id, field: "royalties") + if royaltiesData != nil { + let r = royaltiesData! as! [MetadataViews.Royalty] + return MetadataViews.Royalties(r) + } + return MetadataViews.Royalties(PartyFavorz.royalties) + + case Type(): + if self.owner != nil { + return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/partyfavorz/").concat(self.id.toString())) + } + return MetadataViews.ExternalURL("https://find.xyz/") + + case Type(): + return PartyFavorz.resolveContractView(resourceType: Type<@PartyFavorz.NFT>(), viewType: Type()) + case Type(): + var square = MetadataViews.Media( + file: MetadataViews.IPFSFile( + cid: "QmNkJGEzNYzXsKFqCMweFZBZ9cMQsfMUzV2ZDh2Nn8a1Xc", + path: nil + ), + mediaType: "image/png" + ) + + var banner = MetadataViews.Media( + file: MetadataViews.IPFSFile( + cid: "QmVuMpDyJXHMCK9LnFboemWfPYabcwPNEmXgQMWbtxtGWD", + path: nil + ), + mediaType: "image/png" + ) + + let nftCollectionDisplayData = PartyFavorzExtraData.getData(id: self.id, field: "nftCollectionDisplay") + if nftCollectionDisplayData != nil { + let nftCollectionDisplay = nftCollectionDisplayData! as! {String : String} + + square = MetadataViews.Media( + file: MetadataViews.IPFSFile( + cid: nftCollectionDisplay["squareImage"]!, + path: nil + ), + mediaType: "image/png" + ) + + banner = MetadataViews.Media( + file: MetadataViews.IPFSFile( + cid: nftCollectionDisplay["bannerImage"]!, + path: nil + ), + mediaType: "image/png" + ) + } + + return MetadataViews.NFTCollectionDisplay( + name: "PartyFavorz", + description: "By owning a Party Favorz NFT, you are granted access to the VIP sections of our virtual parties which include, but are not limited to major giveaways, 1 on 1s with artists/project leaders, and some IRL utility that involves partying, down the line. By owning Party Favorz, you are supporting the idea of community coming together for a few goals that include having fun, being positive, learning, and most importantly SUPPORTING ARTISTS.", + externalURL: MetadataViews.ExternalURL("https://find.xyz/partyfavorz"), + squareImage: square, + bannerImage: banner, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/FlowPartyFavorz"), + "discord" : MetadataViews.ExternalURL("https://discord.gg/bM76F34EnN") + } + ) + case Type() : + let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season") + var season = 1 as UInt64 + if seasonData != nil { + season = seasonData! as! UInt64 + } + return MetadataViews.Traits([ + MetadataViews.Trait(name: "Artist", value: self.info.artist, displayType: "String", rarity: nil) , + MetadataViews.Trait(name: "Season", value: season, displayType: "Numeric", rarity: nil) + ]) + + case Type() : + let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season") + var season = 1 as UInt64 + if seasonData != nil { + season = seasonData! as! UInt64 + } + + var thumbnailMediaType = "image/png" + var fullImageMediaType = "image/png" + + switch season { + case 2: + fullImageMediaType = "image/gif" + + } + + return MetadataViews.Medias([ + MetadataViews.Media(file: MetadataViews.IPFSFile(cid: self.info.thumbnailHash, path: nil), mediaType: thumbnailMediaType), + MetadataViews.Media(file: MetadataViews.IPFSFile(cid: self.info.fullsizeHash, path: nil), mediaType: fullImageMediaType) + ]) + } + return nil + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-PartyFavorz.createEmptyCollection(nftType:Type<@PartyFavorz.NFT>()) + } + } + + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionRef = self.account.storage.borrow<&PartyFavorz.Collection>( + from: PartyFavorz.CollectionStoragePath + ) ?? panic("Could not borrow a reference to the stored collection") + let collectionData = MetadataViews.NFTCollectionData( + storagePath: PartyFavorz.CollectionStoragePath, + publicPath: PartyFavorz.CollectionPublicPath, + publicCollection: Type<&PartyFavorz.Collection>(), + publicLinkedType: Type<&PartyFavorz.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-PartyFavorz.createEmptyCollection(nftType:Type<@PartyFavorz.NFT>()) + }) + ) + return collectionData + } + return nil + } - PartyFavorz.totalSupply = PartyFavorz.totalSupply + UInt64(1) - emit Minted(id:newNFT.id, serial: PartyFavorz.totalSupply, season: info["season"]! as! UInt64 , name: newNFT.info.name ) - return <- newNFT - } + access(all) resource Collection: NonFungibleToken.Collection, ViewResolver.ResolverCollection { + // dictionary of NFT conforming tokens + // NFT is a resource type with an `UInt64` ID field + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + init () { + self.ownedNFTs <- {} + } + + // withdraw removes an NFT from the collection and moves it to the caller + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") - pub fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { - // not used here + emit Withdraw(id: token.id, from: self.owner?.address) - panic("Not supported for PartyFavorz Contract") + return <-token } - } - - pub fun getForgeType() : Type { - return Type<@Forge>() - } - - init() { - // Initialize the total supply - self.totalSupply = 0 - - // Set the named paths - self.CollectionStoragePath = /storage/PartyFavorzCollection - self.CollectionPrivatePath = /private/PartyFavorzCollection - self.CollectionPublicPath = /public/PartyFavorzCollection - self.MinterStoragePath = /storage/PartyFavorzMinter - - let partyFavorz = getAccount(0xded455fa967d350e).getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) - let artist = getAccount(0x34f2bf4a80bb0f69).getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) - - self.royalties = [ - MetadataViews.Royalty(receiver: partyFavorz, cut: 0.03, description: "Party Favorz"), - MetadataViews.Royalty(receiver: artist, cut: 0.02, description: "Artist") - ] - - // Create a Collection resource and save it to storage - let collection <- create Collection() - self.account.save(<-collection, to: self.CollectionStoragePath) - - // create a public capability for the collection - self.account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>( - self.CollectionPublicPath, - target: self.CollectionStoragePath - ) - FindForge.addForgeType(<- create Forge()) - emit ContractInitialized() - } + + // deposit takes a NFT and adds it to the collections dictionary + // and adds the ID to the id array + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { + let token <- token as! @PartyFavorz.NFT + + let id: UInt64 = token.id + + // add the new token to the dictionary which removes the old one + let oldToken <- self.ownedNFTs[id] <- token + + emit Deposit(id: id, to: self.owner?.address) + + destroy oldToken + } + + // getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { + return self.ownedNFTs.keys + } + + // borrowNFT gets a reference to an NFT in the collection + // so that the caller can read its metadata and call its methods + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return (&self.ownedNFTs[id]) + } + + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} { + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) + let PartyFavorz = nft as! &PartyFavorz.NFT + return PartyFavorz + } + + access(all) view fun getLength(): Int { + return self.ownedNFTs.keys.length + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create PartyFavorz.Collection() + } + + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[Type<@PartyFavorz.NFT>()] = true + return supportedTypes + } + + /// Return the default storage path for the collection + access(all) view fun getDefaultStoragePath(): StoragePath? { + return PartyFavorz.CollectionStoragePath + + } + + /// Return the default public path for the collection + access(all) view fun getDefaultPublicPath(): PublicPath? { + return PartyFavorz.CollectionPublicPath + } + + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + access(all) view fun isSupportedNFTType(type: Type): Bool { + if type == Type<@PartyFavorz.NFT>() { + return true + } else { + return false + } + } + } + + // public function that anyone can call to create a new empty collection + access(all) fun createEmptyCollection(nftType:Type): @{NonFungibleToken.Collection} { + return <- create Collection() + } + + access(all) resource Forge: FindForge.Forge { + access(FindForge.ForgeOwner) fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @{NonFungibleToken.NFT} { + let info = data as? {String : AnyStruct} ?? panic("The data passed in is not in form as needed.") + + assert(info.length == 5, message: "Please make sure to pass in `Info, season, royalties, squareImage, bannerImage`") + + // create a new NFT + var newNFT <- create NFT( + info: info["info"]! as! Info, + season: info["season"]! as! UInt64, + royalties: info["royalties"]! as! [MetadataViews.Royalty], + squareImage: info["squareImage"]! as! String, + bannerImage: info["bannerImage"]! as! String + ) + + PartyFavorz.totalSupply = PartyFavorz.totalSupply + 1 + emit Minted(id:newNFT.id, serial: PartyFavorz.totalSupply, season: info["season"]! as! UInt64 , name: newNFT.info.name ) + return <- newNFT + } + + + access(FindForge.ForgeOwner) fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { + // not used here + panic("Not supported for PartyFavorz Contract") + } + } + + access(all) fun getForgeType() : Type { + return Type<@Forge>() + } + + init() { + // Initialize the total supply + self.totalSupply = 0 + + // Set the named paths + self.CollectionStoragePath = /storage/PartyFavorzCollection + self.CollectionPublicPath = /public/PartyFavorzCollection + self.MinterStoragePath = /storage/PartyFavorzMinter + + // TODO: Fix this to run on tests + let partyFavorz = self.account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let artist = self.account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + + self.royalties = [ + MetadataViews.Royalty(receiver: partyFavorz, cut: 0.03, description: "Party Favorz"), + MetadataViews.Royalty(receiver: artist, cut: 0.02, description: "Artist") + ] + + // Create a Collection resource and save it to storage + let collection <- create Collection() + self.account.storage.save(<-collection, to: self.CollectionStoragePath) + let collectionCap = self.account.capabilities.storage.issue<&{NonFungibleToken.Collection}>(self.CollectionStoragePath) + self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath) + + FindForge.addForgeType(<- create Forge()) + emit ContractInitialized() + } } - + diff --git a/contracts/PartyFavorzExtraData.cdc b/contracts/PartyFavorzExtraData.cdc index 74a1c46b..7d214575 100644 --- a/contracts/PartyFavorzExtraData.cdc +++ b/contracts/PartyFavorzExtraData.cdc @@ -1,6 +1,5 @@ - -pub contract PartyFavorzExtraData { - pub let extraData : {UInt64 : {String : AnyStruct}} +access(all) contract PartyFavorzExtraData { + access(all) let extraData : {UInt64 : {String : AnyStruct}} access(account) fun setData(id: UInt64, field: String, value: AnyStruct) { let previousData = self.extraData[id] ?? {} @@ -17,7 +16,7 @@ pub contract PartyFavorzExtraData { self.extraData[id]!.remove(key: field)! } - pub fun getData(id: UInt64, field: String) : AnyStruct? { + access(all) fun getData(id: UInt64, field: String) : AnyStruct? { let partyfavorz = self.extraData[id] if partyfavorz == nil { return nil @@ -28,4 +27,4 @@ pub contract PartyFavorzExtraData { init(){ self.extraData = {} } -} \ No newline at end of file +} diff --git a/contracts/Profile.cdc b/contracts/Profile.cdc index 8982be3a..bc205bc7 100644 --- a/contracts/Profile.cdc +++ b/contracts/Profile.cdc @@ -2,685 +2,717 @@ * Inspiration: https://flow-view-source.com/testnet/account/0xba1132bc08f82fe2/contract/Ghost */ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import ProfileCache from "../contracts/ProfileCache.cdc" -import FindUtils from "../contracts/FindUtils.cdc" - -pub contract Profile { - pub let publicPath: PublicPath - pub let publicReceiverPath: PublicPath - pub let storagePath: StoragePath - - //and event emitted when somebody follows another user - pub event Follow(follower:Address, following: Address, tags: [String]) - - //an event emitted when somebody unfollows somebody - pub event Unfollow(follower:Address, unfollowing: Address) - - //and event emitted when a user verifies something - pub event Verification(account:Address, message:String) - - pub event Created(account:Address, userName:String, findName:String, createdAt:String) - pub event Updated(account:Address, userName:String, findName:String, thumbnail:String) - - /* - Represents a Fungible token wallet with a name and a supported type. - */ - pub struct Wallet { - pub let name: String - pub let receiver: Capability<&{FungibleToken.Receiver}> - pub let balance: Capability<&{FungibleToken.Balance}> - pub let accept: Type - pub let tags: [String] - - init( - name: String, - receiver: Capability<&{FungibleToken.Receiver}>, - balance: Capability<&{FungibleToken.Balance}>, - accept: Type, - tags: [String] - ) { - self.name=name - self.receiver=receiver - self.balance=balance - self.accept=accept - self.tags=tags - } - } - - /* - - Represent a collection of a Resource that you want to expose - Since NFT standard is not so great at just add Type and you have to use instanceOf to check for now - */ - pub struct ResourceCollection { - pub let collection: Capability - pub let tags: [String] - pub let type: Type - pub let name: String - - init(name: String, collection:Capability, type: Type, tags: [String]) { - self.name=name - self.collection=collection - self.tags=tags - self.type=type - } - } - - - pub struct CollectionProfile{ - pub let tags: [String] - pub let type: String - pub let name: String - - init(_ collection: ResourceCollection){ - self.name=collection.name - self.type=collection.type.identifier - self.tags=collection.tags - } - } - - /* - A link that you could add to your profile - */ - pub struct Link { - pub let url: String - pub let title: String - pub let type: String - - init(title: String, type: String, url: String) { - self.url=url - self.title=title - self.type=type - } - } - - /* - Information about a connection between one profile and another. - */ - pub struct FriendStatus { - pub let follower: Address - pub let following:Address - pub let tags: [String] - - init(follower: Address, following:Address, tags: [String]) { - self.follower=follower - self.following=following - self.tags= tags - } - } - - pub struct WalletProfile { - pub let name: String - pub let balance: UFix64 - pub let accept: String - pub let tags: [String] - - init(_ wallet: Wallet) { - self.name=wallet.name - self.balance=wallet.balance.borrow()?.balance ?? 0.0 - self.accept=wallet.accept.identifier - self.tags=wallet.tags - } - } - - //This is the new return struct from the profile - pub struct UserReport { - pub let findName: String - pub let createdAt: String - pub let address: Address - pub let name: String - pub let gender: String - pub let description: String - pub let tags: [String] - pub let avatar: String - pub let links: {String:Link} - pub let wallets: [WalletProfile] - pub let following: [FriendStatus] - pub let followers: [FriendStatus] - pub let allowStoringFollowers: Bool - - init( - findName:String, - address: Address, - name: String, - gender: String, - description: String, - tags: [String], - avatar: String, - links: {String:Link}, - wallets: [WalletProfile], - following: [FriendStatus], - followers: [FriendStatus], - allowStoringFollowers:Bool, - createdAt: String - ) { - self.findName=findName - self.address=address - self.name=name - self.gender=gender - self.description=description - self.tags=tags - self.avatar=avatar - self.links=links - self.wallets=wallets - self.following=following - self.followers=followers - self.allowStoringFollowers=allowStoringFollowers - self.createdAt=createdAt - } - } - - - - //This format is deperated - pub struct UserProfile { - pub let findName: String - pub let createdAt: String - pub let address: Address - pub let name: String - pub let gender: String - pub let description: String - pub let tags: [String] - pub let avatar: String - pub let links: [Link] - pub let wallets: [WalletProfile] - pub let collections: [CollectionProfile] - pub let following: [FriendStatus] - pub let followers: [FriendStatus] - pub let allowStoringFollowers: Bool - - init( - findName:String, - address: Address, - name: String, - gender: String, - description: String, - tags: [String], - avatar: String, - links: [Link], - wallets: [WalletProfile], - collections: [CollectionProfile], - following: [FriendStatus], - followers: [FriendStatus], - allowStoringFollowers:Bool, - createdAt: String - ) { - self.findName=findName - self.address=address - self.name=name - self.gender=gender - self.description=description - self.tags=tags - self.avatar=avatar - self.links=links - self.collections=collections - self.wallets=wallets - self.following=following - self.followers=followers - self.allowStoringFollowers=allowStoringFollowers - self.createdAt=createdAt - } - } - - pub resource interface Public{ - pub fun getAddress() : Address - pub fun getName(): String - pub fun getFindName(): String - pub fun getCreatedAt(): String - pub fun getGender(): String - pub fun getDescription(): String - pub fun getTags(): [String] - pub fun getAvatar(): String - pub fun getCollections(): [ResourceCollection] - pub fun follows(_ address: Address) : Bool - pub fun getFollowers(): [FriendStatus] - pub fun getFollowing(): [FriendStatus] - pub fun getWallets() : [Wallet] - pub fun hasWallet(_ name: String) : Bool - pub fun getLinks() : [Link] - pub fun deposit(from: @FungibleToken.Vault) - pub fun supportedFungigleTokenTypes() : [Type] - pub fun asProfile() : UserProfile - pub fun asReport() : UserReport - pub fun isBanned(_ val: Address): Bool - pub fun isPrivateModeEnabled() : Bool - - access(contract) fun internal_addFollower(_ val: FriendStatus) - access(contract) fun internal_removeFollower(_ address: Address) - access(account) fun setFindName(_ val: String) - } - - pub resource interface Owner { - pub fun setName(_ val: String) { - pre { - val.length <= 64: "Name must be 64 or less characters" - } - } - - pub fun setGender(_ val:String){ - pre { - val.length <= 64: "Gender must be 64 or less characters" - } - } - - pub fun setAvatar(_ val: String){ - pre { - val.length <= 1024: "Avatar must be 1024 characters or less" - } - } - - pub fun setTags(_ val: [String]) { - pre { - Profile.verifyTags(tags: val, tagLength:64, tagSize:32) : "cannot have more then 32 tags of length 64" - } - } - - //validate length of description to be 255 or something? - pub fun setDescription(_ val: String) { - pre { - val.length <= 1024: "Description must be 1024 characters or less" - } - } - - pub fun follow(_ address: Address, tags:[String]) { - pre { - Profile.verifyTags(tags: tags, tagLength:64, tagSize:32) : "cannot have more then 32 tags of length 64" - } - } - pub fun unfollow(_ address: Address) - - pub fun removeCollection(_ val: String) - pub fun addCollection(_ val: ResourceCollection) - - pub fun addWallet(_ val : Wallet) - pub fun removeWallet(_ val: String) - pub fun setWallets(_ val: [Wallet]) - pub fun hasWallet(_ name: String) : Bool - pub fun addLink(_ val: Link) - pub fun addLinkWithName(name:String, link:Link) - - pub fun removeLink(_ val: String) - - //Verify that this user has signed something. - pub fun verify(_ val:String) - - //A user must be able to remove a follower since this data in your account is added there by another user - pub fun removeFollower(_ val: Address) - - //manage bans - pub fun addBan(_ val: Address) - pub fun removeBan(_ val: Address) - pub fun getBans(): [Address] - - //Set if user is allowed to store followers or now - pub fun setAllowStoringFollowers(_ val: Bool) - - //set if this user prefers sensitive information about his account to be kept private, no guarantee here but should be honored - pub fun setPrivateMode(_ val: Bool) - } - - - pub resource User: Public, Owner, FungibleToken.Receiver { - access(self) var name: String - access(self) var findName: String - access(self) var createdAt: String - access(self) var gender: String - access(self) var description: String - access(self) var avatar: String - access(self) var tags: [String] - access(self) var followers: {Address: FriendStatus} - access(self) var bans: {Address: Bool} - access(self) var following: {Address: FriendStatus} - access(self) var collections: {String: ResourceCollection} - access(self) var wallets: [Wallet] - access(self) var links: {String: Link} - access(self) var allowStoringFollowers: Bool - - //this is just a bag of properties if we need more fields here, so that we can do it with contract upgrade - access(self) var additionalProperties: {String : String} - - init(name:String, createdAt: String) { - let randomNumber = (1 as UInt64) + (unsafeRandom() % 25) - self.createdAt=createdAt - self.name = name - self.findName="" - self.gender="" - self.description="" - self.tags=[] - self.avatar = "https://find.xyz/assets/img/avatars/avatar".concat(randomNumber.toString()).concat(".png") - self.followers = {} - self.following = {} - self.collections={} - self.wallets=[] - self.links={} - self.allowStoringFollowers=true - self.bans={} - self.additionalProperties={} - - } - - /// We do not have a seperate field for this so we use the additionalProperties 'bag' to store this in - pub fun setPrivateMode(_ val: Bool) { - var private="true" - if !val{ - private="false" - } - self.additionalProperties["privateMode"] = private - } - - pub fun emitUpdatedEvent() { - emit Updated(account:self.owner!.address, userName:self.name, findName:self.findName, thumbnail:self.avatar) - } - - pub fun emitCreatedEvent() { - emit Created(account:self.owner!.address, userName:self.name, findName:self.findName, createdAt:self.createdAt) - } - - pub fun isPrivateModeEnabled() : Bool { - let boolString= self.additionalProperties["privateMode"] - if boolString== nil || boolString=="false" { - return false - } - return true - } - - pub fun addBan(_ val: Address) { self.bans[val]= true} - pub fun removeBan(_ val:Address) { self.bans.remove(key: val) } - pub fun getBans() : [Address] { return self.bans.keys } - pub fun isBanned(_ val:Address) : Bool { return self.bans.containsKey(val)} - - pub fun setAllowStoringFollowers(_ val: Bool) { - self.allowStoringFollowers=val - } - - pub fun verify(_ val:String) { - emit Verification(account: self.owner!.address, message:val) - } - - - pub fun asReport() : UserReport { - let wallets: [WalletProfile]=[] - for w in self.wallets { - wallets.append(WalletProfile(w)) - } - - return UserReport( - findName: self.getFindName(), - address: self.owner!.address, - name: self.getName(), - gender: self.getGender(), - description: self.getDescription(), - tags: self.getTags(), - avatar: self.getAvatar(), - links: self.getLinksMap(), - wallets: wallets, - following: self.getFollowing(), - followers: self.getFollowers(), - allowStoringFollowers: self.allowStoringFollowers, - createdAt:self.getCreatedAt() - ) - } - - pub fun getAddress() : Address { - return self.owner!.address - } - - pub fun asProfile() : UserProfile { - let wallets: [WalletProfile]=[] - for w in self.wallets { - wallets.append(WalletProfile(w)) - } - - let collections:[CollectionProfile]=[] - for c in self.getCollections() { - collections.append(CollectionProfile(c)) - } - - return UserProfile( - findName: self.getFindName(), - address: self.owner!.address, - name: self.getName(), - gender: self.getGender(), - description: self.getDescription(), - tags: self.getTags(), - avatar: self.getAvatar(), - links: self.getLinks(), - wallets: wallets, - collections: collections, - following: self.getFollowing(), - followers: self.getFollowers(), - allowStoringFollowers: self.allowStoringFollowers, - createdAt:self.getCreatedAt() - ) - } - - pub fun getLinksMap() : {String: Link} { - return self.links - } - - pub fun getLinks() : [Link] { - return self.links.values - } - - pub fun addLinkWithName(name:String, link:Link) { - self.links[name]=link - } - - pub fun addLink(_ val: Link) { - self.links[val.title]=val - } - - pub fun removeLink(_ val: String) { - self.links.remove(key: val) - } - - pub fun supportedFungigleTokenTypes() : [Type] { - let types: [Type] =[] - for w in self.wallets { - if !types.contains(w.accept) { - types.append(w.accept) - } - } - return types - } - - pub fun deposit(from: @FungibleToken.Vault) { - - let walletIndexCache = ProfileCache.getWalletIndex(address: self.owner!.address, walletType: from.getType()) - - if walletIndexCache != nil { - let ref = self.wallets[walletIndexCache!].receiver.borrow() ?? panic("This vault is not set up. ".concat(from.getType().identifier).concat(self.owner!.address.toString()).concat(" . ").concat(from.balance.toString())) - ref.deposit(from: <- from) - return - } - - for i , w in self.wallets { - if from.isInstance(w.accept) { - ProfileCache.setWalletIndexCache(address: self.owner!.address, walletType: from.getType(), index: i) - let ref = w.receiver.borrow() ?? panic("This vault is not set up. ".concat(from.getType().identifier).concat(self.owner!.address.toString()).concat(" . ").concat(from.balance.toString())) - ref.deposit(from: <- from) - return - } - } - let identifier=from.getType().identifier - - // Try borrow that in a standard way. Only work for flow, usdc and fusd - // Check the vault type - var ref : &{FungibleToken.Receiver}? = nil - if FindUtils.contains(identifier, element: "FlowToken.Vault") { - ref = self.owner!.getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver).borrow() - } else if FindUtils.contains(identifier, element: "FiatToken.Vault") { - ref = self.owner!.getCapability<&{FungibleToken.Receiver}>(/public/USDCVaultReceiver).borrow() - } else if FindUtils.contains(identifier, element: "FUSD.Vault") { - ref = self.owner!.getCapability<&{FungibleToken.Receiver}>(/public/fusdReceiver).borrow() - } else if FindUtils.contains(identifier, element: "FlowUtilityToken.Vault") { - ref = self.owner!.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver).borrow() - } else if FindUtils.contains(identifier, element: "DapperUtilityCoin.Vault") { - ref = self.owner!.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver).borrow() - } - - if ref != nil { - ref!.deposit(from: <- from) - return - } - - //I need to destroy here for this to compile, but WHY? - // oh we dont neet this anymore - // destroy from - panic("could not find a supported wallet for:".concat(identifier).concat(" for address ").concat(self.owner!.address.toString())) - } - - - pub fun hasWallet(_ name: String) : Bool { - for wallet in self.wallets { - if wallet.name == name || wallet.accept.identifier == name { - return wallet.receiver.check() - } - } - return false - } - - pub fun getWallets() : [Wallet] { return self.wallets} - pub fun addWallet(_ val: Wallet) { self.wallets.append(val) } - pub fun removeWallet(_ val: String) { - let numWallets=self.wallets.length - var i=0 - while(i < numWallets) { - if self.wallets[i].name== val { - self.wallets.remove(at: i) - ProfileCache.resetWalletIndexCache(address: self.owner!.address) - return - } - i=i+1 - } - } - - pub fun setWallets(_ val: [Wallet]) { - self.wallets=val - ProfileCache.resetWalletIndexCache(address: self.owner!.address) - } - - pub fun removeFollower(_ val: Address) { - self.followers.remove(key:val) - } - - pub fun follows(_ address: Address) : Bool { - return self.following.containsKey(address) - } - - pub fun getName(): String { return self.name } - pub fun getFindName(): String { return self.findName } - pub fun getCreatedAt(): String { return self.createdAt } - pub fun getGender() : String { return self.gender } - pub fun getDescription(): String{ return self.description} - pub fun getTags(): [String] { return self.tags} - pub fun getAvatar(): String { return self.avatar } - pub fun getFollowers(): [FriendStatus] { return self.followers.values } - pub fun getFollowing(): [FriendStatus] { return self.following.values } - - pub fun setName(_ val: String) { self.name = val } - pub fun setFindName(_ val: String) { - emit Updated(account:self.owner!.address, userName:self.name, findName:val, thumbnail:self.avatar) - ProfileCache.resetLeaseCache(address: self.owner!.address, leaseName: self.findName) - self.findName = val - } - pub fun setGender(_ val: String) { self.gender = val } - pub fun setAvatar(_ val: String) { self.avatar = val } - pub fun setDescription(_ val: String) { self.description=val} - pub fun setTags(_ val: [String]) { self.tags=val} - - pub fun removeCollection(_ val: String) { self.collections.remove(key: val)} - pub fun addCollection(_ val: ResourceCollection) { self.collections[val.name]=val} - pub fun getCollections(): [ResourceCollection] { return self.collections.values} - - - pub fun follow(_ address: Address, tags:[String]) { - let friendProfile=Profile.find(address) - let owner=self.owner!.address - let status=FriendStatus(follower:owner, following:address, tags:tags) - - self.following[address] = status - friendProfile.internal_addFollower(status) - emit Follow(follower:owner, following: address, tags:tags) - } - - pub fun unfollow(_ address: Address) { - self.following.remove(key: address) - Profile.find(address).internal_removeFollower(self.owner!.address) - emit Unfollow(follower: self.owner!.address, unfollowing:address) - } - - access(contract) fun internal_addFollower(_ val: FriendStatus) { - if self.allowStoringFollowers && !self.bans.containsKey(val.follower) { - self.followers[val.follower] = val - } - } - - access(contract) fun internal_removeFollower(_ address: Address) { - if self.followers.containsKey(address) { - self.followers.remove(key: address) - } - } - - } - - pub fun findReceiverCapability(address: Address, path: PublicPath, type: Type) : Capability<&{FungibleToken.Receiver}>? { - let profileCap = self.findWalletCapability(address) - if profileCap.check() { - if let profile = getAccount(address).getCapability<&Profile.User{Profile.Public}>(Profile.publicPath).borrow() { - if profile.hasWallet(type.identifier) { - return profileCap - } - } - } - let cap = getAccount(address).getCapability<&{FungibleToken.Receiver}>(path) - if cap.check() { - return cap - } - return nil - } - - pub fun findWalletCapability(_ address: Address) : Capability<&{FungibleToken.Receiver}> { - return getAccount(address) - .getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - } - - pub fun find(_ address: Address) : &{Profile.Public} { - return getAccount(address) - .getCapability<&{Profile.Public}>(Profile.publicPath) - .borrow()! - } - - - pub fun createUser(name: String, createdAt:String) : @Profile.User { - - if name.length > 64 { - panic("Name must be 64 or less characters") - } - if createdAt.length > 32 { - panic("createdAt must be 32 or less characters") - } - - return <- create Profile.User(name: name,createdAt: createdAt) - } - - pub fun verifyTags(tags : [String], tagLength: Int, tagSize: Int): Bool { - if tags.length > tagSize { - return false - } - - for t in tags { - if t.length > tagLength { - return false - } - } - return true - } - - init() { - self.publicPath = /public/findProfile - self.publicReceiverPath = /public/findProfileReceiver - self.storagePath = /storage/findProfile - } +import "FungibleToken" +import "ProfileCache" +import "FindUtils" + +access(all) contract Profile { + + // entitlements + access(all) entitlement Admin + + // paths + access(all) let publicPath: PublicPath + access(all) let publicReceiverPath: PublicPath + access(all) let storagePath: StoragePath + + // an event emitted when somebody follows another user + access(all) event Follow(follower:Address, following: Address, tags: [String]) + + // an event emitted when somebody unfollows somebody + access(all) event Unfollow(follower:Address, unfollowing: Address) + + // an event emitted when a user verifies something + access(all) event Verification(account:Address, message:String) + + // an event emitted when a user creates a profile + access(all) event Created(account:Address, userName:String, findName:String, createdAt:String) + + // an event emitted when a user updates their profile + access(all) event Updated(account:Address, userName:String, findName:String, thumbnail:String) + + /* + Represents a Fungible token wallet with a name and a supported type. + */ + access(all) struct Wallet { + access(all) let name: String + access(all) let receiver: Capability<&{FungibleToken.Receiver}> + access(all) let balance: Capability<&{FungibleToken.Balance}> + access(all) let accept: Type + access(all) let tags: [String] + + init( + name: String, + receiver: Capability<&{FungibleToken.Receiver}>, + balance: Capability<&{FungibleToken.Vault}>, + accept: Type, + tags: [String] + ) { + self.name=name + self.receiver=receiver + self.balance=balance + self.accept=accept + self.tags=tags + } + } + + /* + + Represent a collection of a Resource that you want to expose + Since NFT standard is not so great at just add Type and you have to use instanceOf to check for now + */ + access(all) struct ResourceCollection { + access(all) let collection: Capability + access(all) let tags: [String] + access(all) let type: Type + access(all) let name: String + + init(name: String, collection:Capability, type: Type, tags: [String]) { + self.name=name + self.collection=collection + self.tags=tags + self.type=type + } + } + + + access(all) struct CollectionProfile{ + access(all) let tags: [String] + access(all) let type: String + access(all) let name: String + + init(_ collection: ResourceCollection){ + self.name=collection.name + self.type=collection.type.identifier + self.tags=collection.tags + } + } + + /* + A link that you could add to your profile + */ + access(all) struct Link { + access(all) let url: String + access(all) let title: String + access(all) let type: String + + init(title: String, type: String, url: String) { + self.url=url + self.title=title + self.type=type + } + } + + /* + Information about a connection between one profile and another. + */ + access(all) struct FriendStatus { + access(all) let follower: Address + access(all) let following:Address + access(all) let tags: [String] + + init(follower: Address, following:Address, tags: [String]) { + self.follower=follower + self.following=following + self.tags= tags + } + } + + access(all) struct WalletProfile { + access(all) let name: String + access(all) let balance: UFix64 + access(all) let accept: String + access(all) let tags: [String] + + init(_ wallet: Wallet) { + self.name=wallet.name + self.balance=wallet.balance.borrow()?.balance ?? 0.0 + self.accept=wallet.accept.identifier + self.tags=wallet.tags + } + } + + //This is the new return struct from the profile + access(all) struct UserReport { + access(all) let findName: String + access(all) let createdAt: String + access(all) let address: Address + access(all) let name: String + access(all) let gender: String + access(all) let description: String + access(all) let tags: [String] + access(all) let avatar: String + access(all) let links: {String:Link} + access(all) let wallets: [WalletProfile] + access(all) let following: [FriendStatus] + access(all) let followers: [FriendStatus] + access(all) let allowStoringFollowers: Bool + + init( + findName:String, + address: Address, + name: String, + gender: String, + description: String, + tags: [String], + avatar: String, + links: {String:Link}, + wallets: [WalletProfile], + following: [FriendStatus], + followers: [FriendStatus], + allowStoringFollowers:Bool, + createdAt: String + ) { + self.findName=findName + self.address=address + self.name=name + self.gender=gender + self.description=description + self.tags=tags + self.avatar=avatar + self.links=links + self.wallets=wallets + self.following=following + self.followers=followers + self.allowStoringFollowers=allowStoringFollowers + self.createdAt=createdAt + } + } + + //This format is deperated + access(all) struct UserProfile { + access(all) let findName: String + access(all) let createdAt: String + access(all) let address: Address + access(all) let name: String + access(all) let gender: String + access(all) let description: String + access(all) let tags: [String] + access(all) let avatar: String + access(all) let links: [Link] + access(all) let wallets: [WalletProfile] + access(all) let collections: [CollectionProfile] + access(all) let following: [FriendStatus] + access(all) let followers: [FriendStatus] + access(all) let allowStoringFollowers: Bool + + init( + findName:String, + address: Address, + name: String, + gender: String, + description: String, + tags: [String], + avatar: String, + links: [Link], + wallets: [WalletProfile], + collections: [CollectionProfile], + following: [FriendStatus], + followers: [FriendStatus], + allowStoringFollowers:Bool, + createdAt: String + ) { + self.findName=findName + self.address=address + self.name=name + self.gender=gender + self.description=description + self.tags=tags + self.avatar=avatar + self.links=links + self.collections=collections + self.wallets=wallets + self.following=following + self.followers=followers + self.allowStoringFollowers=allowStoringFollowers + self.createdAt=createdAt + } + } + + access(all) resource interface Public{ + access(all) fun getAddress() : Address + access(all) fun getName(): String + access(all) fun getFindName(): String + access(all) fun getCreatedAt(): String + access(all) fun getGender(): String + access(all) fun getDescription(): String + access(all) fun getTags(): [String] + access(all) fun getAvatar(): String + access(all) fun getCollections(): [ResourceCollection] + access(all) fun follows(_ address: Address) : Bool + access(all) fun getFollowers(): [FriendStatus] + access(all) fun getFollowing(): [FriendStatus] + access(all) fun getWallets() : [Wallet] + access(all) fun hasWallet(_ name: String) : Bool + access(all) fun getLinks() : [Link] + access(all) fun deposit(from: @{FungibleToken.Vault}) + access(all) fun supportedFungigleTokenTypes() : [Type] + access(all) fun asProfile() : UserProfile + access(all) fun asReport() : UserReport + access(all) fun isBanned(_ val: Address): Bool + access(all) fun isPrivateModeEnabled() : Bool + access(contract) fun internal_addFollower(_ val: FriendStatus) + access(contract) fun internal_removeFollower(_ address: Address) + access(account) fun setFindName(_ val: String) + } + + access(all) resource interface Owner { + access(Admin) fun setName(_ val: String) { + pre { + val.length <= 64: "Name must be 64 or less characters" + } + } + + access(Admin) fun setGender(_ val:String){ + pre { + val.length <= 64: "Gender must be 64 or less characters" + } + } + + access(Admin) fun setAvatar(_ val: String){ + pre { + val.length <= 1024: "Avatar must be 1024 characters or less" + } + } + + access(Admin) fun setTags(_ val: [String]) { + pre { + Profile.verifyTags(tags: val, tagLength:64, tagSize:32) : "cannot have more then 32 tags of length 64" + } + } + + //validate length of description to be 255 or something? + access(Admin) fun setDescription(_ val: String) { + pre { + val.length <= 1024: "Description must be 1024 characters or less" + } + } + + access(Admin) fun follow(_ address: Address, tags:[String]) { + pre { + Profile.verifyTags(tags: tags, tagLength:64, tagSize:32) : "cannot have more then 32 tags of length 64" + } + } + access(Admin) fun unfollow(_ address: Address) + + access(Admin) fun removeCollection(_ val: String) + access(Admin) fun addCollection(_ val: ResourceCollection) + + access(Admin) fun addWallet(_ val : Wallet) + access(Admin) fun removeWallet(_ val: String) + access(Admin) fun setWallets(_ val: [Wallet]) + access(all) fun hasWallet(_ name: String) : Bool + access(Admin) fun addLink(_ val: Link) + access(Admin) fun addLinkWithName(name:String, link:Link) + + access(Admin) fun removeLink(_ val: String) + + //Verify that this user has signed something. + access(Admin) fun verify(_ val:String) + + //A user must be able to remove a follower since this data in your account is added there by another user + access(Admin) fun removeFollower(_ val: Address) + + //manage bans + access(Admin) fun addBan(_ val: Address) + access(Admin) fun removeBan(_ val: Address) + access(Admin) fun getBans(): [Address] + + //Set if user is allowed to store followers or now + access(Admin) fun setAllowStoringFollowers(_ val: Bool) + + //set if this user prefers sensitive information about his account to be kept private, no guarantee here but should be honored + access(Admin) fun setPrivateMode(_ val: Bool) + } + + access(all) resource User: Owner, Public, FungibleToken.Receiver { + access(self) var name: String + access(self) var findName: String + access(self) var createdAt: String + access(self) var gender: String + access(self) var description: String + access(self) var avatar: String + access(self) var tags: [String] + access(self) var followers: {Address: FriendStatus} + access(self) var bans: {Address: Bool} + access(self) var following: {Address: FriendStatus} + access(self) var collections: {String: ResourceCollection} + access(self) var wallets: [Wallet] + access(self) var links: {String: Link} + access(self) var allowStoringFollowers: Bool + + //this is just a bag of properties if we need more fields here, so that we can do it with contract upgrade + access(self) var additionalProperties: {String : String} + + init(name:String, createdAt: String) { + let randomNumber = (1 as UInt64) + revertibleRandom(modulo: 25 as UInt64) + self.createdAt=createdAt + self.name = name + self.findName="" + self.gender="" + self.description="" + self.tags=[] + self.avatar = "https://find.xyz/assets/img/avatars/avatar".concat(randomNumber.toString()).concat(".png") + self.followers = {} + self.following = {} + self.collections={} + self.wallets=[] + self.links={} + self.allowStoringFollowers=true + self.bans={} + self.additionalProperties={} + + } + + /// We do not have a seperate field for this so we use the additionalProperties 'bag' to store this in + access(Admin) fun setPrivateMode(_ val: Bool) { + var private="true" + if !val{ + private="false" + } + self.additionalProperties["privateMode"] = private + } + + access(Admin) fun emitUpdatedEvent() { + emit Updated(account:self.owner!.address, userName:self.name, findName:self.findName, thumbnail:self.avatar) + } + + access(Admin) fun emitCreatedEvent() { + emit Created(account:self.owner!.address, userName:self.name, findName:self.findName, createdAt:self.createdAt) + } + + access(all) fun isPrivateModeEnabled() : Bool { + let boolString= self.additionalProperties["privateMode"] + if boolString== nil || boolString=="false" { + return false + } + return true + } + + access(Admin) fun addBan(_ val: Address) { + self.bans[val]= true + } + + access(Admin) fun removeBan(_ val:Address) { + self.bans.remove(key: val) + } + + access(Admin) fun getBans() : [Address] { + return self.bans.keys + } + + access(all) fun isBanned(_ val:Address) : Bool { + return self.bans.containsKey(val) + } + + access(Admin) fun setAllowStoringFollowers(_ val: Bool) { + self.allowStoringFollowers=val + } + + access(Admin) fun verify(_ val:String) { + emit Verification(account: self.owner!.address, message:val) + } + + access(all) fun asReport() : UserReport { + let wallets: [WalletProfile]=[] + for w in self.wallets { + wallets.append(WalletProfile(w)) + } + + return UserReport( + findName: self.getFindName(), + address: self.owner!.address, + name: self.getName(), + gender: self.getGender(), + description: self.getDescription(), + tags: self.getTags(), + avatar: self.getAvatar(), + links: self.getLinksMap(), + wallets: wallets, + following: self.getFollowing(), + followers: self.getFollowers(), + allowStoringFollowers: self.allowStoringFollowers, + createdAt:self.getCreatedAt() + ) + } + + access(all) fun getAddress() : Address { + return self.owner!.address + } + + access(all) fun asProfile() : UserProfile { + let wallets: [WalletProfile]=[] + for w in self.wallets { + wallets.append(WalletProfile(w)) + } + + let collections:[CollectionProfile]=[] + for c in self.getCollections() { + collections.append(CollectionProfile(c)) + } + + return UserProfile( + findName: self.getFindName(), + address: self.owner!.address, + name: self.getName(), + gender: self.getGender(), + description: self.getDescription(), + tags: self.getTags(), + avatar: self.getAvatar(), + links: self.getLinks(), + wallets: wallets, + collections: collections, + following: self.getFollowing(), + followers: self.getFollowers(), + allowStoringFollowers: self.allowStoringFollowers, + createdAt:self.getCreatedAt() + ) + } + + access(all) fun getLinksMap() : {String: Link} { + return self.links + } + + access(all) fun getLinks() : [Link] { + return self.links.values + } + + access(Admin) fun addLinkWithName(name:String, link:Link) { + self.links[name]=link + } + + access(Admin) fun addLink(_ val: Link) { + self.links[val.title]=val + } + + access(Admin) fun removeLink(_ val: String) { + self.links.remove(key: val) + } + + access(all) fun supportedFungigleTokenTypes() : [Type] { + let types: [Type] =[] + for w in self.wallets { + if !types.contains(w.accept) { + types.append(w.accept) + } + } + return types + } + + access(all) fun deposit(from: @{FungibleToken.Vault}) { + + let walletIndexCache = ProfileCache.getWalletIndex(address: self.owner!.address, walletType: from.getType()) + + if walletIndexCache != nil { + let ref = self.wallets[walletIndexCache!].receiver.borrow() ?? panic("This vault is not set up. ".concat(from.getType().identifier).concat(self.owner!.address.toString()).concat(" . ").concat(from.balance.toString())) + ref.deposit(from: <- from) + return + } + + for i , w in self.wallets { + if from.isInstance(w.accept) { + ProfileCache.setWalletIndexCache(address: self.owner!.address, walletType: from.getType(), index: i) + let ref = w.receiver.borrow() ?? panic("This vault is not set up. ".concat(from.getType().identifier).concat(self.owner!.address.toString()).concat(" . ").concat(from.balance.toString())) + ref.deposit(from: <- from) + return + } + } + let identifier=from.getType().identifier + + // Try borrow that in a standard way. Only work for flow, usdc and fusd + // Check the vault type + var ref : &{FungibleToken.Receiver}? = nil + if FindUtils.contains(identifier, element: "FlowToken.Vault") { + ref = self.owner!.capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + } else if FindUtils.contains(identifier, element: "FlowUtilityToken.Vault") { + ref = self.owner!.capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) + } else if FindUtils.contains(identifier, element: "DapperUtilityCoin.Vault") { + ref = self.owner!.capabilities.borrow<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) + } + + if ref != nil { + ref!.deposit(from: <- from) + return + } + + //I need to destroy here for this to compile, but WHY? + // oh we dont neet this anymore + // destroy from + panic("could not find a supported wallet for:".concat(identifier).concat(" for address ").concat(self.owner!.address.toString())) + } + + access(all) fun hasWallet(_ name: String) : Bool { + for wallet in self.wallets { + if wallet.name == name || wallet.accept.identifier == name { + return wallet.receiver.check() + } + } + return false + } + + access(all) fun getWallets() : [Wallet] { return self.wallets} + + access(Admin) fun addWallet(_ val: Wallet) { + self.wallets.append(val) + } + + access(Admin) fun removeWallet(_ val: String) { + let numWallets=self.wallets.length + var i=0 + while(i < numWallets) { + if self.wallets[i].name== val { + self.wallets.remove(at: i) + ProfileCache.resetWalletIndexCache(address: self.owner!.address) + return + } + i=i+1 + } + } + + access(Admin) fun setWallets(_ val: [Wallet]) { + self.wallets=val + ProfileCache.resetWalletIndexCache(address: self.owner!.address) + } + + access(Admin) fun removeFollower(_ val: Address) { + self.followers.remove(key:val) + } + + access(all) fun follows(_ address: Address) : Bool { + return self.following.containsKey(address) + } + + access(all) fun getName(): String { return self.name } + access(all) fun getFindName(): String { return self.findName } + access(all) fun getCreatedAt(): String { return self.createdAt } + access(all) fun getGender() : String { return self.gender } + access(all) fun getDescription(): String{ return self.description} + access(all) fun getTags(): [String] { return self.tags} + access(all) fun getAvatar(): String { return self.avatar } + access(all) fun getFollowers(): [FriendStatus] { return self.followers.values } + access(all) fun getFollowing(): [FriendStatus] { return self.following.values } + + access(Admin) fun setName(_ val: String) { self.name = val } + access(account) fun setFindName(_ val: String) { + emit Updated(account:self.owner!.address, userName:self.name, findName:val, thumbnail:self.avatar) + ProfileCache.resetLeaseCache(address: self.owner!.address, leaseName: self.findName) + self.findName = val + } + access(Admin) fun setMainName(_ val: String) { + emit Updated(account:self.owner!.address, userName:self.name, findName:val, thumbnail:self.avatar) + ProfileCache.resetLeaseCache(address: self.owner!.address, leaseName: self.findName) + self.findName = val + } + access(Admin) fun setGender(_ val: String) { self.gender = val } + access(Admin) fun setAvatar(_ val: String) { self.avatar = val } + access(Admin) fun setDescription(_ val: String) { self.description=val} + access(Admin) fun setTags(_ val: [String]) { self.tags=val} + + access(Admin) fun removeCollection(_ val: String) { self.collections.remove(key: val)} + access(Admin) fun addCollection(_ val: ResourceCollection) { self.collections[val.name]=val} + access(all) fun getCollections(): [ResourceCollection] { return self.collections.values} + + + access(Admin) fun follow(_ address: Address, tags:[String]) { + let friendProfile=Profile.find(address) + let owner=self.owner!.address + let status=FriendStatus(follower:owner, following:address, tags:tags) + + self.following[address] = status + friendProfile.internal_addFollower(status) + emit Follow(follower:owner, following: address, tags:tags) + } + + access(Admin) fun unfollow(_ address: Address) { + self.following.remove(key: address) + Profile.find(address).internal_removeFollower(self.owner!.address) + emit Unfollow(follower: self.owner!.address, unfollowing:address) + } + + access(contract) fun internal_addFollower(_ val: FriendStatus) { + if self.allowStoringFollowers && !self.bans.containsKey(val.follower) { + self.followers[val.follower] = val + } + } + + access(contract) fun internal_removeFollower(_ address: Address) { + if self.followers.containsKey(address) { + self.followers.remove(key: address) + } + } + + /// A getter function that returns the token types supported by this resource, + /// which can be deposited using the 'deposit' function. + /// + /// @return Dictionary of FT types that can be deposited. + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + let supportedVaults: {Type: Bool} = {} + for w in self.wallets { + if w.receiver.check() { + supportedVaults[w.accept] = true + } + } + return supportedVaults + } + + /// Returns whether or not the given type is accepted by the Receiver + access(all) view fun isSupportedVaultType(type: Type): Bool { + let supportedVaults = self.getSupportedVaultTypes() + if let supported = supportedVaults[type] { + return supported + } else { return false } + } + } + + access(all) fun findReceiverCapability(address: Address, path: PublicPath, type: Type) : Capability<&{FungibleToken.Receiver}>? { + let profileCap = self.findWalletCapability(address) + if profileCap.check() { + if let profile = getAccount(address).capabilities.borrow<&Profile.User>(Profile.publicPath) { + if profile.hasWallet(type.identifier) { + return profileCap + } + } + } + let cap = getAccount(address).capabilities.get<&{FungibleToken.Receiver}>(path) + return cap + } + + access(all) fun findWalletCapability(_ address: Address) : Capability<&{FungibleToken.Receiver}> { + return getAccount(address) + .capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath)! + } + + access(all) fun find(_ address: Address) : &{Profile.Public} { + return getAccount(address) + .capabilities.borrow<&{Profile.Public}>(Profile.publicPath)! + } + + access(all) fun createUser(name: String, createdAt:String) : @Profile.User { + if name.length > 64 { + panic("Name must be 64 or less characters") + } + if createdAt.length > 32 { + panic("createdAt must be 32 or less characters") + } + return <- create Profile.User(name: name,createdAt: createdAt) + } + + access(all) view fun verifyTags(tags : [String], tagLength: Int, tagSize: Int): Bool { + if tags.length > tagSize { + return false + } + + for t in tags { + if t.length > tagLength { + return false + } + } + return true + } + + init() { + self.publicPath = /public/findProfile + self.publicReceiverPath = /public/findProfileReceiver + self.storagePath = /storage/findProfile + } } diff --git a/contracts/ProfileCache.cdc b/contracts/ProfileCache.cdc index 4bf271dc..76ecf476 100644 --- a/contracts/ProfileCache.cdc +++ b/contracts/ProfileCache.cdc @@ -1,6 +1,6 @@ -import Clock from "../contracts/Clock.cdc" +import "Clock" -pub contract ProfileCache { +access(all) contract ProfileCache { // If there is no findName, the string is set to "". access(contract) let addressLeaseName : {Address : LeaseCache} @@ -9,10 +9,10 @@ pub contract ProfileCache { access(contract) let profileWalletIndex : {Address : {Type : Int}} // Find Leases - pub struct LeaseCache { - pub let address : Address? - pub let leaseName : String - pub let validUntil : UFix64 + access(all) struct LeaseCache { + access(all) let address : Address? + access(all) let leaseName : String + access(all) let validUntil : UFix64 init(leaseName: String, validUntil: UFix64, address: Address?) { self.leaseName=leaseName @@ -34,7 +34,7 @@ pub contract ProfileCache { // We cannot panic here, because imagine someone has expired lease. } - pub fun getAddressLeaseName(_ address: Address) : String? { + access(all) fun getAddressLeaseName(_ address: Address) : String? { if self.addressLeaseName[address] == nil { return nil } @@ -52,7 +52,7 @@ pub contract ProfileCache { panic("There is already a cache for this name. Name : ".concat(leaseName)) } - pub fun getNameAddress(_ name: String) : LeaseCache? { + access(all) fun getNameAddress(_ name: String) : LeaseCache? { if self.nameAddress[name]!.validUntil >= Clock.time() { return self.nameAddress[name] } @@ -64,8 +64,6 @@ pub contract ProfileCache { self.nameAddress.remove(key: leaseName) } - - access(account) fun setWalletIndexCache(address: Address, walletType: Type, index: Int) { if self.profileWalletIndex[address] == nil { self.profileWalletIndex[address] = {} @@ -78,7 +76,7 @@ pub contract ProfileCache { panic("There is already a cache for this wallet. User : ".concat(address.toString()).concat(". Wallet : ").concat(walletType.identifier)) } - pub fun getWalletIndex(address: Address, walletType: Type) : Int? { + access(all) fun getWalletIndex(address: Address, walletType: Type) : Int? { if self.profileWalletIndex[address] == nil { return nil } @@ -92,8 +90,6 @@ pub contract ProfileCache { init() { self.addressLeaseName = {} self.nameAddress = {} - self.profileWalletIndex = {} } - } diff --git a/contracts/RelatedAccounts.cdc b/contracts/RelatedAccounts.cdc deleted file mode 100644 index 24930661..00000000 --- a/contracts/RelatedAccounts.cdc +++ /dev/null @@ -1,134 +0,0 @@ -pub contract RelatedAccounts { - - // The entire contract is deprecated - - pub let storagePath: StoragePath - pub let publicPath: PublicPath - - // Deprecated - pub event RelatedFlowAccountAdded() - pub event RelatedFlowAccountRemoved() - - pub event RelatedAccountAdded(name: String, address: Address, related: String, network: String) - pub event RelatedAccountRemoved(name: String, address: Address, related: String, network: String) - - pub struct AccountInformation{ - // unique alias for each wallet - pub let name:String - pub let address:Address? - pub let network:String //do not use enum because of contract upgrade - pub let otherAddress: String? //other networks besides flow may be not support Address - - init(name:String, address:Address?, network:String, otherAddress:String?){ - self.name=name - self.address=address - self.network=network - self.otherAddress=otherAddress - } - } - - pub resource interface Public{ - pub fun getFlowAccounts() : {String: Address} - pub fun getRelatedAccounts(_ network: String) : {String : String} - pub fun getAllRelatedAccounts() : {String : {String : String}} - pub fun verify(network: String, address: String) : Bool - } - - /// This is just an empty resource we create in storage, you can safely send a reference to it to obtain msg.sender - pub resource Accounts: Public { - - access(self) let accounts: { String: AccountInformation} - - pub fun verify(network: String, address: String) : Bool { - for account in self.accounts.keys { - let item = self.accounts[account]! - let addr = item.address?.toString() ?? item.otherAddress! - if item.network == network && addr == address { - return true - } - } - return false - } - - pub fun getFlowAccounts() : {String: Address} { - let items : {String: Address} ={} - for account in self.accounts.keys { - let item = self.accounts[account]! - if item.network == "Flow" { - items[item.name]=item.address! - } - } - return items - } - - pub fun getRelatedAccounts(_ network: String) : {String : String} { - let items : {String: String} ={} - for account in self.accounts.keys { - let item = self.accounts[account]! - if item.network == network { - let address = item.address?.toString() ?? item.otherAddress! - items[item.name]=address - } - } - return items - } - - pub fun getAllRelatedAccounts() : {String : {String : String}} { - let items : {String: {String : String}} ={} - for account in self.accounts.keys { - let item = self.accounts[account]! - if item.address != nil { - let i = items[item.network] ?? {} - i[item.name] = item.address!.toString() - items[item.name] = i - continue - } - let i = items[item.network] ?? {} - i[item.name] = item.otherAddress! - items[item.name] = i - } - return items - } - - pub fun setFlowAccount(name: String, address:Address) { - self.accounts[name] = AccountInformation(name: name, address:address, network: "Flow", otherAddress:nil) - emit RelatedAccountAdded(name:name, address: self.owner!.address, related:address.toString(), network: "Flow") - } - - pub fun setRelatedAccount(name: String, address: String, network: String) { - self.accounts[name] = AccountInformation(name: name, address:nil, network: network, otherAddress:address) - emit RelatedAccountAdded(name:name, address: self.owner!.address, related:address, network: network) - } - - pub fun deleteAccount(name: String) { - let item =self.accounts.remove(key: name)! - emit RelatedAccountRemoved(name:name,address: self.owner!.address, related: item.address?.toString() ?? item.otherAddress!, network: "Flow") - } - - init() { - self.accounts={} - } - } - - pub fun createEmptyAccounts() : @Accounts{ - return <- create Accounts() - } - - pub fun findRelatedFlowAccounts(address:Address) : { String: Address} { - let cap = getAccount(address).getCapability<&Accounts{Public}>(self.publicPath) - if !cap.check(){ - return {} - } - - return cap.borrow()!.getFlowAccounts() - } - - init() { - - self.storagePath = /storage/findAccounts - self.publicPath = /public/findAccounts - } - -} - - diff --git a/contracts/Sender.cdc b/contracts/Sender.cdc index 519a46ac..7367ff77 100644 --- a/contracts/Sender.cdc +++ b/contracts/Sender.cdc @@ -1,17 +1,16 @@ -pub contract Sender { +access(all) contract Sender { - pub let storagePath: StoragePath - - /// This is just an empty resource we create in storage, you can safely send a reference to it to obtain msg.sender - pub resource Token { } + access(all) let storagePath: StoragePath - pub fun create() : @Sender.Token { - return <- create Token() - } + /// This is just an empty resource we create in storage, you can safely send a reference to it to obtain msg.sender + access(all) resource Token { } - init() { - self.storagePath = /storage/findSender - } + access(all) fun createToken() : @Sender.Token { + return <- create Token() + } + init() { + self.storagePath = /storage/findSender + } } diff --git a/contracts/community/BandOracle.cdc b/contracts/community/BandOracle.cdc new file mode 100644 index 00000000..5fb5ff72 --- /dev/null +++ b/contracts/community/BandOracle.cdc @@ -0,0 +1,477 @@ +import "FungibleToken" +import "FlowToken" + +/// The Flow blockchain contract for the Band Protocol Oracle. +/// https://docs.bandchain.org/ +/// +access(all) contract BandOracle { + + /// Paths + + // OracleAdmin resource path. + access(all) let OracleAdminStoragePath: StoragePath + + // Relay resource path. + access(all) let RelayStoragePath: StoragePath + + // FeeCollector resource path. + access(all) let FeeCollectorStoragePath: StoragePath + + + /// Fields + + // String as base private path for data updater capabilities. + access(contract) let dataUpdaterBasePath: String + + // Mapping from symbol to data struct. + access(contract) let symbolsRefData: {String: RefData} + + // Aux constant for holding the 10^18 value. + access(all) let e18: UInt256 + + // Aux constant for holding the 10^9 value. + access(all) let e9: UInt256 + + // Vault for storing service fees. + access(contract) let payments: @{FungibleToken.Vault} + + // Service fee per request. + access(contract) var fee: UFix64 + + // Mapping of Relayer address to their issued capability ID + access(contract) let relayersCapabilityID: {Address: UInt64} + + + /// Events + + // Emitted when a relayer updates a set of symbols. + access(all) event BandOracleSymbolsUpdated(symbols: [String], relayerID: UInt64, requestID: UInt64) + + // Emitted when a symbol is removed from the oracle. + access(all) event BandOracleSymbolRemoved(symbol: String) + + // Emitted when fees are collected. + access(all) event FeesCollected(amount: UFix64, to: Address?, collectorUUID: UInt64, collectorAddress: Address) + + // Emitted when fees are updated. + access(all) event FeeUpdated(old: UFix64, new: UFix64) + + + /// Structs + + /// Structure for storing any symbol USD-rate. + /// + access(all) struct RefData { + /// USD-rate, multiplied by 1e9. + access(all) var rate: UInt64 + /// UNIX epoch when data is last resolved. + access(all) var timestamp: UInt64 + /// BandChain request identifier for this data. + access(all) var requestID: UInt64 + + init(rate: UInt64, timestamp: UInt64, requestID: UInt64) { + self.rate = rate + self.timestamp = timestamp + self.requestID = requestID + } + } + + /// Structure for consuming data as quote / base symbols. + /// + access(all) struct ReferenceData { + /// Base / quote symbols rate multiplied by 10^18. + access(all) var integerE18Rate: UInt256 + /// Base / quote symbols rate as a fixed point number. + access(all) var fixedPointRate: UFix64 + /// UNIX epoch when base data is last resolved. + access(all) var baseTimestamp: UInt64 + /// UNIX epoch when quote data is last resolved. + access(all) var quoteTimestamp: UInt64 + + init(rate: UInt256, baseTimestamp: UInt64, quoteTimestamp: UInt64) { + self.integerE18Rate = rate + self.fixedPointRate = BandOracle.e18ToFixedPoint(rate: rate) + self.baseTimestamp = baseTimestamp + self.quoteTimestamp = quoteTimestamp + } + } + + + /// Resources + + /// Admin only operations. + /// + access(all) resource interface OracleAdmin { + access(all) fun setRelayerCapabilityID (relayer: Address, capabilityID: UInt64) + access(all) fun removeRelayerCapabilityID (relayer: Address) + access(all) fun getUpdaterCapabilityIDFromAddress (relayer: Address): UInt64? + access(all) fun removeSymbol (symbol: String) + access(all) fun createNewFeeCollector (): @BandOracle.FeeCollector + } + + /// Relayer operations. + /// + access(all) resource interface DataUpdater { + access(all) fun updateData (symbolsRates: {String: UInt64}, resolveTime: UInt64, + requestID: UInt64, relayerID: UInt64) + access(all) fun forceUpdateData (symbolsRates: {String: UInt64}, resolveTime: UInt64, + requestID: UInt64, relayerID: UInt64) + } + + /// The `BandOracleAdmin` will be created on the contract deployment, and will allow + /// the own admin to manage the oracle and the relayers to update prices on it. + /// + access(all) resource BandOracleAdmin: OracleAdmin, DataUpdater { + + /// Stores in contract the data updater capability ID along with the address + /// of the relayer who got the capability + /// + /// @param relayer: The entitled relayer account address + /// @param capabilityID: The ID of the data updater capability + /// + access(all) fun setRelayerCapabilityID (relayer: Address, capabilityID: UInt64) { + BandOracle.relayersCapabilityID[relayer] = capabilityID + } + + /// Deletes a relayer's CapabilityID from `BandOracle.relayersCapabilityID` mapping for traceability purposes + /// NOTE: Does not revoke the underlying Capability - this must be done in a separate call from the issuing account + /// + /// @param relayer: The entitled relayer account address + /// + access(all) fun removeRelayerCapabilityID (relayer: Address) { + BandOracle.relayersCapabilityID.remove(key: relayer) + } + + /// Method to retrieve the data updater capability ID from the relayer + /// + /// @param relayer: The entitled relayer account address + /// + access(all) fun getUpdaterCapabilityIDFromAddress (relayer: Address): UInt64? { + return BandOracle.relayersCapabilityID[relayer] + } + + /// Removes a symbol and its quotes from the contract storage. + /// + /// @param symbol: The string representing the symbol to be removed from the contract. + /// + access(all) fun removeSymbol (symbol: String) { + BandOracle.removeSymbol(symbol: symbol) + } + + /// Relayers can call this method to update rates. + /// + /// @param symbolsRates: Set of symbols and corresponding usd rates to update. + /// @param resolveTime: The registered time for the rates. + /// @param requestID: The Band Protocol request ID. + /// @param relayerID: The ID of the relayer carrying the update. + /// + access(all) fun updateData (symbolsRates: {String: UInt64}, resolveTime: UInt64, + requestID: UInt64, relayerID: UInt64) { + BandOracle.updateRefData(symbolsRates: symbolsRates, resolveTime: resolveTime, + requestID: requestID, relayerID: relayerID) + } + + /// Relayers can call this method to force update rates. + /// + /// @param symbolsRates: Set of symbols and corresponding usd rates to update. + /// @param resolveTime: The registered time for the rates. + /// @param requestID: The Band Protocol request ID. + /// @param relayerID: The ID of the relayer carrying the update. + /// + access(all) fun forceUpdateData (symbolsRates: {String: UInt64}, resolveTime: UInt64, + requestID: UInt64, relayerID: UInt64) { + BandOracle.forceUpdateRefData(symbolsRates: symbolsRates, resolveTime: resolveTime, + requestID: requestID, relayerID: relayerID) + } + + /// Creates a fee collector, meant to be called once after contract deployment + /// for storing the resource on the maintainer's account. + /// + /// @return The `FeeCollector` resource + /// + access(all) fun createNewFeeCollector (): @FeeCollector { + return <- create FeeCollector() + } + + } + + /// The resource that will allow an account to make quote updates + /// + access(all) resource Relay { + + // Capability linked to the OracleAdmin allowing relayers to relay rate updates + access(self) let updaterCapability: Capability<&{DataUpdater}> + + /// Relay updated rates to the Oracle Admin + /// + /// @param symbolsRates: Set of symbols and corresponding usd rates to update. + /// @param resolveTime: The registered time for the rates. + /// @param requestID: The Band Protocol request ID. + /// + access(all) fun relayRates (symbolsRates: {String: UInt64}, resolveTime: UInt64, requestID: UInt64) { + let updaterRef = self.updaterCapability.borrow() + ?? panic ("Can't borrow reference to data updater while processing request ".concat(requestID.toString())) + updaterRef.updateData(symbolsRates: symbolsRates, resolveTime: resolveTime, requestID: requestID, relayerID: self.uuid) + } + + /// Relay updated rates to the Oracle Admin forcing the update of the symbols even if the `resolveTime` is older than the last update. + /// + /// @param symbolsRates: Set of symbols and corresponding usd rates to update. + /// @param resolveTime: The registered time for the rates. + /// @param requestID: The Band Protocol request ID. + /// + access(all) fun forceRelayRates (symbolsRates: {String: UInt64}, resolveTime: UInt64, requestID: UInt64) { + let updaterRef = self.updaterCapability.borrow() + ?? panic ("Can't borrow reference to data updater while processing request ".concat(requestID.toString())) + updaterRef.forceUpdateData(symbolsRates: symbolsRates, resolveTime: resolveTime, requestID: requestID, relayerID: self.uuid) + } + + init(updaterCapability: Capability<&{DataUpdater}>) { + self.updaterCapability = updaterCapability + let updaterRef = self.updaterCapability.borrow() + ?? panic ("Can't borrow linked updater") + } + } + + /// The resource that allows the maintainer account to charge a fee for the use of the oracle. + /// + access(all) resource FeeCollector { + + /// Sets the fee in Flow tokens for the oracle use. + /// + /// @param fee: The amount of Flow tokens. + /// + access(all) fun setFee (fee: UFix64) { + BandOracle.setFee(fee: fee) + emit FeeUpdated(old: BandOracle.fee, new: fee) + } + + /// Extracts the fees from the contract's vault. + /// + /// @return A vault containing the funds obtained for the oracle use. + /// + access(all) fun collectFees (receiver: &{FungibleToken.Receiver}) { + let fees <- BandOracle.collectFees() + emit FeesCollected(amount: fees.balance, to: receiver.owner?.address, collectorUUID: self.uuid, collectorAddress: self.owner!.address) + receiver.deposit(from: <-fees) + } + + } + + + /// Functions + + /// Aux access(contract) functions + + /// Auxiliary private function for the `OracleAdmin` to update the rates. + /// + /// @param symbolsRates: Set of symbols and corresponding usd rates to update. + /// @param resolveTime: The registered time for the rates. + /// @param requestID: The Band Protocol request ID. + /// @param relayerID: The ID of the relayer carrying the update. + /// + access(contract) fun updateRefData (symbolsRates: {String: UInt64}, resolveTime: UInt64, requestID: UInt64, relayerID: UInt64) { + let updatedSymbols: [String] = [] + // For each symbol rate relayed + for symbol in symbolsRates.keys { + // If the symbol hasn't stored rates yet, or the stored records are older + // than the new relayed rates + if (BandOracle.symbolsRefData[symbol] == nil ) || + (BandOracle.symbolsRefData[symbol]!.timestamp < resolveTime) { + // Store the relayed rate + BandOracle.symbolsRefData[symbol] = + RefData(rate: symbolsRates[symbol]!, timestamp: resolveTime, requestID: requestID) + updatedSymbols.append(symbol) + } + } + emit BandOracleSymbolsUpdated(symbols: updatedSymbols, relayerID: relayerID, requestID: requestID) + } + + /// Auxiliary private function for the `OracleAdmin` to force update the rates. + /// + /// @param symbolsRates: Set of symbols and corresponding usd rates to update. + /// @param resolveTime: The registered time for the rates. + /// @param requestID: The Band Protocol request ID. + /// @param relayerID: The ID of the relayer carrying the update. + /// + access(contract) fun forceUpdateRefData (symbolsRates: {String: UInt64}, resolveTime: UInt64, requestID: UInt64, relayerID: UInt64) { + // For each symbol rate relayed, store it no matter what was the previous + // records for it + for symbol in symbolsRates.keys { + BandOracle.symbolsRefData[symbol] = + RefData(rate: symbolsRates[symbol]!, timestamp: resolveTime, requestID: requestID) + } + emit BandOracleSymbolsUpdated(symbols: symbolsRates.keys, relayerID: relayerID, requestID: requestID) + } + + /// Auxiliary private function for removing a stored symbol + /// + /// @param symbol: The string representing the symbol to delete + /// + access(contract) fun removeSymbol (symbol: String) { + BandOracle.symbolsRefData.remove(key: symbol) + emit BandOracleSymbolRemoved(symbol: symbol) + } + + /// Auxiliary private function for checking and retrieving data for a given symbol. + /// + /// @param symbol: String representing a symbol. + /// @return Optional `RefData` struct if there is any quote stored for the requested symbol. + /// + access(contract) fun _getRefData (symbol: String): RefData? { + // If the requested symbol is USD just return 10^9 + if (symbol == "USD") { + return RefData(rate: UInt64(BandOracle.e9), timestamp: UInt64(getCurrentBlock().timestamp), requestID: 0) + } else { + return self.symbolsRefData[symbol] ?? nil + } + } + + /// Private function that calculates the reference data between two base and quote symbols. + /// + /// @param baseRefData: Base ref data. + /// @param quoteRefData: Quote ref data. + /// @return Calculated `ReferenceData` structure. + /// + access(contract) fun calculateReferenceData (baseRefData: RefData, quoteRefData: RefData): ReferenceData { + let rate = UInt256((UInt256(baseRefData.rate) * BandOracle.e18) / UInt256(quoteRefData.rate)) + return ReferenceData (rate: rate, + baseTimestamp: baseRefData.timestamp, + quoteTimestamp: quoteRefData.timestamp) + } + + /// Private method for the `FeeCollector` to be able to set the fee for using the oracle + /// + /// @param fee: The amount of flow tokens to set as fee. + /// + access(contract) fun setFee (fee: UFix64) { + BandOracle.fee = fee + } + + /// Private method for the `FeeCollector` to be able to collect the fees from the contract vault. + /// + /// @return A flow token vault with the collected fees so far. + /// + access(contract) fun collectFees (): @{FungibleToken.Vault} { + let collectedFees <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()) + collectedFees.deposit(from: <- BandOracle.payments.withdraw(amount: BandOracle.payments.balance)) + return <- collectedFees + } + + + /// Public access functions. + + /// Public method for creating a relay and become a relayer. + /// + /// @param updaterCapability: The capability pointing to the OracleAdmin resource needed to create the relay. + /// @return The new relay resource. + /// + access(all) fun createRelay (updaterCapability: Capability<&{DataUpdater}>): @Relay { + return <- create Relay(updaterCapability: updaterCapability) + } + + /// Auxiliary method to ensure that the formation of the capability name that + /// identifies data updater capability for relayers is done in a uniform way + /// by both admin and relayers. + /// + /// @param relayer: Address of the account who will be granted with a relayer. + /// @return The capability name. + /// + access(all) view fun getUpdaterCapabilityNameFromAddress (relayer: Address): String { + // Create the string that will form the private path concatenating the base + // path and the relayer identifying address. + let capabilityName = + BandOracle.dataUpdaterBasePath.concat(relayer.toString()) + return capabilityName + } + + /// This function returns the current fee for using the oracle in Flow tokens. + /// + /// @return The fee to be charged for every request made to the oracle. + /// + access(all) view fun getFee (): UFix64 { + return BandOracle.fee + } + + /// The entry point for consumers to query the oracle in exchange of a fee. + /// + /// @param baseSymbol: String representing base symbol. + /// @param quoteSymbol: String representing quote symbol. + /// @param payment: Flow token vault containing the service fee. + /// @return The `ReferenceData` containing the requested data. + /// + access(all) fun getReferenceData (baseSymbol: String, quoteSymbol: String, payment: @{FungibleToken.Vault}): ReferenceData { + + + + pre { + payment.balance >= BandOracle.fee : "Insufficient balance" + } + //THIS IS MOCKED + //500000000000000000 + if baseSymbol=="FLOW" { + BandOracle.payments.deposit(from: <- payment) + return ReferenceData(rate:500000000000000000, baseTimestamp:0, quoteTimestamp:0) + } + + + if (BandOracle._getRefData(symbol: baseSymbol) != nil && BandOracle._getRefData(symbol: quoteSymbol) != nil){ + let baseRefData = BandOracle._getRefData(symbol: baseSymbol)! + let quoteRefData = BandOracle._getRefData(symbol: quoteSymbol)! + BandOracle.payments.deposit(from: <- payment) + return BandOracle.calculateReferenceData (baseRefData: baseRefData, quoteRefData: quoteRefData) + } else { + panic("Cannot get a quote for the requested symbol pair.") + } + } + + /// Turn scientific notation numbers as `UInt256` multiplied by e8 into `UFix64` + /// fixed point numbers. Exceptionally large integer rates may lose some precision + /// when converted to a decimal number. + /// + /// @param rate: The symbol rate as an integer. + /// @return The symbol rate as a decimal. + /// + access(all) view fun e18ToFixedPoint (rate: UInt256): UFix64 { + return ( + UFix64( + rate / BandOracle.e18 + ) + + + ( + UFix64( + (rate + / + BandOracle.e9) + % + BandOracle.e9 + ) + / + UFix64(BandOracle.e9) + ) + ) + } + + init() { + self.OracleAdminStoragePath = /storage/BandOracleAdmin + self.RelayStoragePath = /storage/BandOracleRelay + self.FeeCollectorStoragePath = /storage/BandOracleFeeCollector + self.dataUpdaterBasePath = "BandOracleDataUpdater_" + self.account.storage.save(<- create BandOracleAdmin(), to: self.OracleAdminStoragePath) + self.symbolsRefData = {} + self.relayersCapabilityID = {} + self.payments <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()) + self.fee = 0.0 + self.e18 = 1_000_000_000_000_000_000 + self.e9 = 1_000_000_000 + // Create a relayer on the admin account so the relay methods are never accessed directly. + // The admin could decide to build a transaction borrowing the whole BandOracleAdmin + // resource and call updateData methods bypassing relayData methods but we are explicitly + // discouraging that by giving the admin a regular relay resource on contract deployment. + let oracleAdminRef = self.account.storage.borrow<&{OracleAdmin}>(from: BandOracle.OracleAdminStoragePath) + ?? panic("Can't borrow a reference to the Oracle Admin") + let updaterCapability = self.account.capabilities.storage.issue<&{BandOracle.DataUpdater}>(BandOracle.OracleAdminStoragePath) + let relayer <- BandOracle.createRelay(updaterCapability: updaterCapability) + self.account.storage.save(<- relayer, to: BandOracle.RelayStoragePath) + } +} diff --git a/contracts/community/CoatCheck.cdc b/contracts/community/CoatCheck.cdc index 2b8ab600..cb193820 100644 --- a/contracts/community/CoatCheck.cdc +++ b/contracts/community/CoatCheck.cdc @@ -1,5 +1,5 @@ -import FungibleToken from "../standard/FungibleToken.cdc" -import NonFungibleToken from "../standard/NonFungibleToken.cdc" +import "FungibleToken" +import "NonFungibleToken" // CoatCheck @@ -8,31 +8,31 @@ import NonFungibleToken from "../standard/NonFungibleToken.cdc" // this contract is essentially an escrow that no one holds the keys to. It will support holding any Fungible and NonFungible Tokens // with a specified address that is allowed to claim them. In this way, dapps which need to ensure that accounts are able to "Receive" assets // have a way of putting them into a holding resource that the intended receiver can redeem. -pub contract CoatCheck { +access(all) contract CoatCheck { // | ---------------- Events ----------------- | - pub event Initialized() + access(all) event Initialized() - pub event TicketCreated(ticketResourceID: UInt64, redeemer: Address, fungibleTokenTypes: [Type], nonFungibleTokenTypes: [Type]) + access(all) event TicketCreated(ticketResourceID: UInt64, redeemer: Address, fungibleTokenTypes: [Type], nonFungibleTokenTypes: [Type]) - pub event TicketRedeemed(ticketResourceID: UInt64, redeemer: Address) + access(all) event TicketRedeemed(ticketResourceID: UInt64, redeemer: Address) - pub event ValetDestroyed(resourceID: UInt64) + access(all) event ValetDestroyed(resourceID: UInt64) access(account) let valet: @CoatCheck.Valet // A CoatCheck has been initialized. This resource can now be watched for deposited items that accounts can redeem - pub event CoatCheckInitialized(resourceID: UInt64) + access(all) event CoatCheckInitialized(resourceID: UInt64) - pub resource interface TicketPublic { - pub fun redeem(fungibleTokenReceiver: &{FungibleToken.Receiver}?, nonFungibleTokenReceiver: &{NonFungibleToken.CollectionPublic}?) - pub fun getDetails(): CoatCheck.TicketDetails + access(all) resource interface TicketPublic { + access(all) fun redeem(fungibleTokenReceiver: &{FungibleToken.Receiver}?, nonFungibleTokenReceiver: &{NonFungibleToken.Collection}?) + access(all) fun getDetails(): CoatCheck.TicketDetails } - pub struct TicketDetails { - pub let nftTypes: [Type] - pub let vaultTypes: [Type] - pub let redeemer: Address + access(all) struct TicketDetails { + access(all) let nftTypes: [Type] + access(all) let vaultTypes: [Type] + access(all) let redeemer: Address init( redeemer: Address, @@ -48,20 +48,20 @@ pub contract CoatCheck { // Tickets are used to fungible tokens, non-fungible tokens, or both. // A ticket can be created by the CoatCheck valet, and can be redeemed only by // capabilities owned by the designated redeemer of a ticket - pub resource Ticket: TicketPublic { + access(all) resource Ticket: TicketPublic { // a ticket can have Fungible Tokens AND NonFungibleTokens - access(self) var fungibleTokenVaults: @[FungibleToken.Vault]? - access(self) var nonFungibleTokens: @[NonFungibleToken.NFT]? - - pub let details: TicketDetails + access(self) var fungibleTokenVaults: @[{FungibleToken.Vault}]? + access(self) var nonFungibleTokens: @[{NonFungibleToken.NFT}]? + + access(all) let details: TicketDetails // The following variables are maintained by the CoatCheck contract access(self) var redeemed: Bool // a ticket can only be redeemed once. It also cannot be destroyed unless redeemed is set to true access(self) var storageFee: UFix64 // the storage fee taken to hold this ticket in storage. It is returned when the ticket is redeemed. init( - fungibleTokenVaults: @[FungibleToken.Vault]?, - nonFungibleTokens: @[NonFungibleToken.NFT]?, + fungibleTokenVaults: @[{FungibleToken.Vault}]?, + nonFungibleTokens: @[{NonFungibleToken.NFT}]?, redeemer: Address ) { assert( @@ -72,8 +72,8 @@ pub contract CoatCheck { let ftTypes: [Type] = [] let nftTypes: [Type] = [] - let ticketVaults: @[FungibleToken.Vault] <- [] - let ticketTokens: @[NonFungibleToken.NFT] <- [] + let ticketVaults: @[{FungibleToken.Vault}] <- [] + let ticketTokens: @[{NonFungibleToken.NFT}] <- [] if fungibleTokenVaults != nil { while fungibleTokenVaults?.length! > 0 { @@ -106,7 +106,7 @@ pub contract CoatCheck { } self.details = TicketDetails(redeemer: redeemer, nftTypes: nftTypes, vaultTypes: ftTypes) - + self.redeemed = false self.storageFee = 0.0 @@ -118,7 +118,7 @@ pub contract CoatCheck { // redeem the ticket using an optional receiver for fungible tokens and non-fungible tokens. The supplied receivers must be // owned by the redeemer of this ticket. - pub fun redeem(fungibleTokenReceiver: &{FungibleToken.Receiver}?, nonFungibleTokenReceiver: &{NonFungibleToken.CollectionPublic}?) { + access(all) fun redeem(fungibleTokenReceiver: &{FungibleToken.Receiver}?, nonFungibleTokenReceiver: &{NonFungibleToken.Collection}?) { pre { fungibleTokenReceiver == nil || (fungibleTokenReceiver!.owner!.address == self.details.redeemer) : "incorrect owner" nonFungibleTokenReceiver == nil || (nonFungibleTokenReceiver!.owner!.address == self.details.redeemer) : "incorrect owner" @@ -155,35 +155,26 @@ pub contract CoatCheck { destroy tokens } - pub fun getDetails(): CoatCheck.TicketDetails { + access(all) fun getDetails(): CoatCheck.TicketDetails { return self.details } - - destroy () { - pre { - self.redeemed : "not redeemed" - } - - destroy self.fungibleTokenVaults - destroy self.nonFungibleTokens - } } // ValetPublic contains our main entry-point methods that // anyone can use to make/redeem tickets. - pub resource interface ValetPublic { + access(all) resource interface ValetPublic { // redeem a ticket, supplying an optional receiver to use for depositing // any fts or nfts in the ticket - pub fun redeemTicket( + access(all) fun redeemTicket( ticketID: UInt64, fungibleTokenReceiver: &{FungibleToken.Receiver}?, - nonFungibleTokenReceiver: &{NonFungibleToken.CollectionPublic}?, + nonFungibleTokenReceiver: &{NonFungibleToken.Collection}?, ) - pub fun borrowTicket(ticketID: UInt64): &Ticket{TicketPublic}? - + access(all) fun borrowTicket(ticketID: UInt64): &Ticket? + } - pub resource Valet: ValetPublic { + access(all) resource Valet: ValetPublic { access(self) var tickets: @{UInt64: Ticket} // we store the fees taken when a ticket is made so that the exact amount is withdrawn @@ -201,8 +192,8 @@ pub contract CoatCheck { // Any extra tokens sent for the storage fee are sent back when the ticket is made access(account) fun createTicket( redeemer: Address, - vaults: @[FungibleToken.Vault]?, - tokens: @[NonFungibleToken.NFT]?, + vaults: @[{FungibleToken.Vault}]?, + tokens: @[{NonFungibleToken.NFT}]?, ) { let ticket <- create Ticket( fungibleTokenVaults: <-vaults, @@ -215,9 +206,9 @@ pub contract CoatCheck { destroy oldTicket } - pub fun borrowTicket(ticketID: UInt64): &Ticket{TicketPublic}? { - if self.tickets[ticketID] != nil { - return &self.tickets[ticketID] as! &Ticket{TicketPublic}? + access(all) fun borrowTicket(ticketID: UInt64): &Ticket? { + if self.tickets[ticketID] != nil { + return &self.tickets[ticketID] } else { return nil } @@ -226,10 +217,10 @@ pub contract CoatCheck { // redeem the ticket using supplied receivers. // if a ticket has fungible tokens, the fungibleTokenReceiver is required. // if a ticket has nfts, the nonFungibleTokenReceiver is required. - pub fun redeemTicket( + access(all) fun redeemTicket( ticketID: UInt64, fungibleTokenReceiver: &{FungibleToken.Receiver}?, - nonFungibleTokenReceiver: &{NonFungibleToken.CollectionPublic}? + nonFungibleTokenReceiver: &{NonFungibleToken.Collection}? ) { pre { self.tickets[ticketID] != nil : "ticket does not exist" @@ -239,23 +230,18 @@ pub contract CoatCheck { ticket?.redeem(fungibleTokenReceiver: fungibleTokenReceiver, nonFungibleTokenReceiver: nonFungibleTokenReceiver) destroy ticket } - - destroy () { - emit ValetDestroyed(resourceID: self.uuid) - destroy self.tickets - } } - pub fun getValetPublic(): &CoatCheck.Valet{CoatCheck.ValetPublic} { - return &self.valet as &CoatCheck.Valet{CoatCheck.ValetPublic} + access(all) fun getValetPublic(): &CoatCheck.Valet { + return &self.valet } access(account) fun getValet(): &CoatCheck.Valet { - return &self.valet as &CoatCheck.Valet + return &self.valet } init() { self.valet <- create Valet() } } - \ No newline at end of file + diff --git a/contracts/community/Flovatar.cdc b/contracts/community/Flovatar.cdc index b14822f8..f077b692 100644 --- a/contracts/community/Flovatar.cdc +++ b/contracts/community/Flovatar.cdc @@ -1,10 +1,10 @@ -import FungibleToken from "../standard/FungibleToken.cdc" -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import FlowToken from "../standard/FlowToken.cdc" -import FlovatarComponentTemplate from "./FlovatarComponentTemplate.cdc" -import FlovatarComponent from "./FlovatarComponent.cdc" -import FlovatarPack from "./FlovatarPack.cdc" -import MetadataViews from "../standard/MetadataViews.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "FlowToken" +import "FlovatarComponentTemplate" +import "FlovatarComponent" +import "FlovatarPack" +import "MetadataViews" /* @@ -21,11 +21,11 @@ This contract contains also the Admin resource that can be used to manage and ge */ -pub contract Flovatar: NonFungibleToken { +access(all) contract Flovatar: NonFungibleToken { - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - pub let AdminStoragePath: StoragePath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + access(all) let AdminStoragePath: StoragePath // These will be used in the Marketplace to pay out // royalties to the creator and to the marketplace @@ -34,36 +34,36 @@ pub contract Flovatar: NonFungibleToken { // Here we keep track of all the Flovatar unique combinations and names // that people will generate to make sure that there are no duplicates - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 access(contract) let mintedCombinations: {String: Bool} access(contract) let mintedNames: {String: Bool} - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Created(id: UInt64, metadata: Metadata) - pub event Updated(id: UInt64) - pub event NameSet(id: UInt64, name: String) + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Created(id: UInt64, metadata: Metadata) + access(all) event Updated(id: UInt64) + access(all) event NameSet(id: UInt64, name: String) - pub struct Royalties{ - pub let royalty: [Royalty] + access(all) struct Royalties{ + access(all) let royalty: [Royalty] init(royalty: [Royalty]) { self.royalty=royalty } } - pub enum RoyaltyType: UInt8{ - pub case fixed - pub case percentage + access(all) enum RoyaltyType: UInt8{ + access(all) case fixed + access(all) case percentage } - pub struct Royalty{ - pub let wallet:Capability<&{FungibleToken.Receiver}> - pub let cut: UFix64 + access(all) struct Royalty{ + access(all) let wallet:Capability<&{FungibleToken.Receiver}> + access(all) let cut: UFix64 //can be percentage - pub let type: RoyaltyType + access(all) let type: RoyaltyType init(wallet:Capability<&{FungibleToken.Receiver}>, cut: UFix64, type: RoyaltyType ){ self.wallet=wallet @@ -74,16 +74,16 @@ pub contract Flovatar: NonFungibleToken { // This Metadata struct contains all the most important informations about the Flovatar - pub struct Metadata { - pub let mint: UInt64 - pub let series: UInt32 - pub let svg: String - pub let combination: String - pub let creatorAddress: Address + access(all) struct Metadata { + access(all) let mint: UInt64 + access(all) let series: UInt32 + access(all) let svg: String + access(all) let combination: String + access(all) let creatorAddress: Address access(self) let components: {String: UInt64} - pub let rareCount: UInt8 - pub let epicCount: UInt8 - pub let legendaryCount: UInt8 + access(all) let rareCount: UInt8 + access(all) let epicCount: UInt8 + access(all) let legendaryCount: UInt8 init( @@ -107,7 +107,7 @@ pub contract Flovatar: NonFungibleToken { self.epicCount = epicCount self.legendaryCount = legendaryCount } - pub fun getComponents(): {String: UInt64} { + access(all) getComponents(): {String: UInt64} { return self.components } } @@ -115,46 +115,46 @@ pub contract Flovatar: NonFungibleToken { // The public interface can show metadata and the content for the Flovatar. // In addition to it, it provides methods to access the additional optional // components (accessory, hat, eyeglasses, background) for everyone. - pub resource interface Public { - pub let id: UInt64 + access(all) resource interface Public { + access(all) let id: UInt64 access(contract) let metadata: Metadata access(contract) let royalties: Royalties // these three are added because I think they will be in the standard. At least Dieter thinks it will be needed access(contract) var name: String - pub let description: String - pub let schema: String? - - pub fun getName(): String - pub fun getAccessory(): UInt64? - pub fun getHat(): UInt64? - pub fun getEyeglasses(): UInt64? - pub fun getBackground(): UInt64? - - pub fun getSvg(): String - pub fun getMetadata(): Metadata - pub fun getRoyalties(): Royalties - pub fun getBio(): {String: String} - pub fun getRarityScore(): UFix64 + access(all) let description: String + access(all) let schema: String? + + access(all) getName(): String + access(all) getAccessory(): UInt64? + access(all) getHat(): UInt64? + access(all) getEyeglasses(): UInt64? + access(all) getBackground(): UInt64? + + access(all) getSvg(): String + access(all) getMetadata(): Metadata + access(all) getRoyalties(): Royalties + access(all) getBio(): {String: String} + access(all) getRarityScore(): UFix64 } //The private interface can update the Accessory, Hat, Eyeglasses and Background //for the Flovatar and is accessible only to the owner of the NFT - pub resource interface Private { - pub fun setName(name: String): String - pub fun setAccessory(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? - pub fun setHat(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? - pub fun setEyeglasses(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? - pub fun setBackground(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? - pub fun removeAccessory(): @FlovatarComponent.NFT? - pub fun removeHat(): @FlovatarComponent.NFT? - pub fun removeEyeglasses(): @FlovatarComponent.NFT? - pub fun removeBackground(): @FlovatarComponent.NFT? + access(all) resource interface Private { + access(all) setName(name: String): String + access(all) setAccessory(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? + access(all) setHat(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? + access(all) setEyeglasses(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? + access(all) setBackground(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? + access(all) removeAccessory(): @FlovatarComponent.NFT? + access(all) removeHat(): @FlovatarComponent.NFT? + access(all) removeEyeglasses(): @FlovatarComponent.NFT? + access(all) removeBackground(): @FlovatarComponent.NFT? } //The NFT resource that implements both Private and Public interfaces - pub resource NFT: NonFungibleToken.INFT, Public, Private, MetadataViews.Resolver { - pub let id: UInt64 + access(all) resource NFT: NonFungibleToken.INFT, Public, Private, ViewResolver.Resolver { + access(all) let id: UInt64 access(contract) let metadata: Metadata access(contract) let royalties: Royalties access(contract) var accessory: @FlovatarComponent.NFT? @@ -163,8 +163,8 @@ pub contract Flovatar: NonFungibleToken { access(contract) var background: @FlovatarComponent.NFT? access(contract) var name: String - pub let description: String - pub let schema: String? + access(all) let description: String + access(all) let schema: String? access(self) let bio: {String: String} init(metadata: Metadata, @@ -192,29 +192,29 @@ pub contract Flovatar: NonFungibleToken { destroy self.background } - pub fun getID(): UInt64 { + access(all) getID(): UInt64 { return self.id } - pub fun getMetadata(): Metadata { + access(all) getMetadata(): Metadata { return self.metadata } - pub fun getRoyalties(): Royalties { + access(all) getRoyalties(): Royalties { return self.royalties } - pub fun getBio(): {String: String} { + access(all) getBio(): {String: String} { return self.bio } - pub fun getName(): String { + access(all) getName(): String { return self.name } // This will allow to change the Name of the Flovatar only once. // It checks for the current name is empty, otherwise it will throw an error. - pub fun setName(name: String): String { + access(all) setName(name: String): String { pre { // TODO: Make sure that the text of the name is sanitized //and that bad words are not accepted? @@ -239,13 +239,13 @@ pub contract Flovatar: NonFungibleToken { return self.name } - pub fun getAccessory(): UInt64? { + access(all) getAccessory(): UInt64? { return self.accessory?.templateId } // This will allow to change the Accessory of the Flovatar any time. // It checks for the right category and series before executing. - pub fun setAccessory(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? { + access(all) setAccessory(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? { pre { component.getCategory() == "accessory" : "The component needs to be an accessory" component.getSeries() == self.metadata.series : "The accessory belongs to a different series" @@ -258,19 +258,19 @@ pub contract Flovatar: NonFungibleToken { } // This will allow to remove the Accessory of the Flovatar any time. - pub fun removeAccessory(): @FlovatarComponent.NFT? { + access(all) removeAccessory(): @FlovatarComponent.NFT? { emit Updated(id: self.id) let compNFT <- self.accessory <- nil return <-compNFT } - pub fun getHat(): UInt64? { + access(all) getHat(): UInt64? { return self.hat?.templateId } // This will allow to change the Hat of the Flovatar any time. // It checks for the right category and series before executing. - pub fun setHat(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? { + access(all) setHat(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? { pre { component.getCategory() == "hat" : "The component needs to be a hat" component.getSeries() == self.metadata.series : "The hat belongs to a different series" @@ -283,19 +283,19 @@ pub contract Flovatar: NonFungibleToken { } // This will allow to remove the Hat of the Flovatar any time. - pub fun removeHat(): @FlovatarComponent.NFT? { + access(all) removeHat(): @FlovatarComponent.NFT? { emit Updated(id: self.id) let compNFT <- self.hat <- nil return <-compNFT } - pub fun getEyeglasses(): UInt64? { + access(all) getEyeglasses(): UInt64? { return self.eyeglasses?.templateId } // This will allow to change the Eyeglasses of the Flovatar any time. // It checks for the right category and series before executing. - pub fun setEyeglasses(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? { + access(all) setEyeglasses(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? { pre { component.getCategory() == "eyeglasses" : "The component needs to be a pair of eyeglasses" component.getSeries() == self.metadata.series : "The eyeglasses belongs to a different series" @@ -308,19 +308,19 @@ pub contract Flovatar: NonFungibleToken { } // This will allow to remove the Eyeglasses of the Flovatar any time. - pub fun removeEyeglasses(): @FlovatarComponent.NFT? { + access(all) removeEyeglasses(): @FlovatarComponent.NFT? { emit Updated(id: self.id) let compNFT <- self.eyeglasses <- nil return <-compNFT } - pub fun getBackground(): UInt64? { + access(all) getBackground(): UInt64? { return self.background?.templateId } // This will allow to change the Background of the Flovatar any time. // It checks for the right category and series before executing. - pub fun setBackground(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? { + access(all) setBackground(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT? { pre { component.getCategory() == "background" : "The component needs to be a background" component.getSeries() == self.metadata.series : "The accessory belongs to a different series" @@ -333,7 +333,7 @@ pub contract Flovatar: NonFungibleToken { } // This will allow to remove the Background of the Flovatar any time. - pub fun removeBackground(): @FlovatarComponent.NFT? { + access(all) removeBackground(): @FlovatarComponent.NFT? { emit Updated(id: self.id) let compNFT <- self.background <- nil return <-compNFT @@ -343,7 +343,7 @@ pub contract Flovatar: NonFungibleToken { // optional components (Accessory, Hat, Eyeglasses and Background) from their // original Template resources, while all the other unmutable components are // taken from the Metadata directly. - pub fun getSvg(): String { + access(all) getSvg(): String { var svg: String = "" if let background = self.getBackground() { @@ -378,7 +378,7 @@ pub contract Flovatar: NonFungibleToken { } - pub fun getRarityScore(): UFix64{ + access(all) getRarityScore(): UFix64{ var rareCount: UInt8 = self.metadata.rareCount var epicCount: UInt8 = self.metadata.epicCount var legendaryCount: UInt8 = self.metadata.legendaryCount @@ -404,7 +404,7 @@ pub contract Flovatar: NonFungibleToken { return scoreFix } - pub fun getViews() : [Type] { + access(all) getViews() : [Type] { var views : [Type]=[] views.append(Type()) views.append(Type()) @@ -416,7 +416,7 @@ pub contract Flovatar: NonFungibleToken { views.append(Type()) return views } - pub fun resolveView(_ type: Type): AnyStruct? { + access(all) resolveView(_ type: Type): AnyStruct? { if type == Type() { return MetadataViews.ExternalURL("https://flovatar.com/flovatars/".concat(self.id.toString())) @@ -531,9 +531,9 @@ pub contract Flovatar: NonFungibleToken { storagePath: Flovatar.CollectionStoragePath, publicPath: Flovatar.CollectionPublicPath, providerPath: /private/FlovatarCollection, - publicCollection: Type<&Flovatar.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Flovatar.CollectionPublic}>(), - publicLinkedType: Type<&Flovatar.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Flovatar.CollectionPublic}>(), - providerLinkedType: Type<&Flovatar.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Flovatar.CollectionPublic}>(), + publicCollection: Type<&Flovatar.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Flovatar.CollectionPublic}>(), + publicLinkedType: Type<&Flovatar.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Flovatar.CollectionPublic}>(), + providerLinkedType: Type<&Flovatar.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Flovatar.CollectionPublic}>(), createEmptyCollectionFunction: fun(): @NonFungibleToken.Collection {return <- Flovatar.createEmptyCollection()} ) } @@ -543,11 +543,11 @@ pub contract Flovatar: NonFungibleToken { // Standard NFT collectionPublic interface that can also borrowFlovatar as the correct type - pub resource interface CollectionPublic { - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowFlovatar(id: UInt64): &Flovatar.NFT{Flovatar.Public, MetadataViews.Resolver}? { + access(all) resource interface CollectionPublic { + access(all) deposit(token: @NonFungibleToken.NFT) + access(all) view fun getIDs(): [UInt64] + access(all) borrowNFT(id: UInt64): &NonFungibleToken.NFT + access(all) borrowFlovatar(id: UInt64): &Flovatar.NFT{Flovatar.Public, ViewResolver.Resolver}? { // If the result isn't nil, the id of the returned reference // should be the same as the argument to the function post { @@ -558,17 +558,17 @@ pub contract Flovatar: NonFungibleToken { } // Main Collection to manage all the Flovatar NFT - pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { + access(all) resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, ViewResolver.ResolverCollection { // dictionary of NFT conforming tokens // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} init () { self.ownedNFTs <- {} } // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + access(all) withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) @@ -578,7 +578,7 @@ pub contract Flovatar: NonFungibleToken { // deposit takes a NFT and adds it to the collections dictionary // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { + access(all) deposit(token: @NonFungibleToken.NFT) { let token <- token as! @Flovatar.NFT let id: UInt64 = token.id @@ -592,23 +592,23 @@ pub contract Flovatar: NonFungibleToken { } // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } // borrowNFT gets a reference to an NFT in the collection // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { + access(all) borrowNFT(id: UInt64): &NonFungibleToken.NFT { return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! } // borrowFlovatar returns a borrowed reference to a Flovatar // so that the caller can read data and call methods from it. - pub fun borrowFlovatar(id: UInt64): &Flovatar.NFT{Flovatar.Public, MetadataViews.Resolver}? { + access(all) borrowFlovatar(id: UInt64): &Flovatar.NFT{Flovatar.Public, ViewResolver.Resolver}? { if self.ownedNFTs[id] != nil { - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) let flovatarNFT = ref as! &Flovatar.NFT - return flovatarNFT as &Flovatar.NFT{Flovatar.Public, MetadataViews.Resolver} + return flovatarNFT as &Flovatar.NFT{Flovatar.Public, ViewResolver.Resolver} } else { return nil } @@ -616,9 +616,9 @@ pub contract Flovatar: NonFungibleToken { // borrowFlovatarPrivate returns a borrowed reference to a Flovatar using the Private interface // so that the caller can read data and call methods from it, like setting the optional components. - pub fun borrowFlovatarPrivate(id: UInt64): &{Flovatar.Private}? { + access(all) borrowFlovatarPrivate(id: UInt64): &{Flovatar.Private}? { if self.ownedNFTs[id] != nil { - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) return ref as! &Flovatar.NFT } else { return nil @@ -629,32 +629,32 @@ pub contract Flovatar: NonFungibleToken { destroy self.ownedNFTs } - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { + access(all) borrowViewResolver(id: UInt64): &AnyResource{ViewResolver.Resolver} { pre { self.ownedNFTs[id] != nil : "NFT does not exist" } - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) let flovatarNFT = nft as! &Flovatar.NFT - return flovatarNFT as &AnyResource{MetadataViews.Resolver} + return flovatarNFT as &AnyResource{ViewResolver.Resolver} } } // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { + access(all) createEmptyCollection(): @NonFungibleToken.Collection { return <- create Collection() } // This struct is used to send a data representation of the Flovatars // when retrieved using the contract helper methods outside the collection. - pub struct FlovatarData { - pub let id: UInt64 - pub let name: String - pub let metadata: Flovatar.Metadata - pub let accessoryId: UInt64? - pub let hatId: UInt64? - pub let eyeglassesId: UInt64? - pub let backgroundId: UInt64? - pub let bio: {String: String} + access(all) struct FlovatarData { + access(all) let id: UInt64 + access(all) let name: String + access(all) let metadata: Flovatar.Metadata + access(all) let accessoryId: UInt64? + access(all) let hatId: UInt64? + access(all) let eyeglassesId: UInt64? + access(all) let backgroundId: UInt64? + access(all) let bio: {String: String} init( id: UInt64, name: String, @@ -678,7 +678,7 @@ pub contract Flovatar: NonFungibleToken { // This function will look for a specific Flovatar on a user account and return a FlovatarData if found - pub fun getFlovatar(address: Address, flovatarId: UInt64) : FlovatarData? { + access(all) getFlovatar(address: Address, flovatarId: UInt64) : FlovatarData? { let account = getAccount(address) @@ -699,7 +699,7 @@ pub contract Flovatar: NonFungibleToken { return nil } // This function will look for a specific Flovatar on a user account and return the Score - pub fun getFlovatarRarityScore(address: Address, flovatarId: UInt64) : UFix64? { + access(all) getFlovatarRarityScore(address: Address, flovatarId: UInt64) : UFix64? { let account = getAccount(address) @@ -712,7 +712,7 @@ pub contract Flovatar: NonFungibleToken { } // This function will return all Flovatars on a user account and return an array of FlovatarData - pub fun getFlovatars(address: Address) : [FlovatarData] { + access(all) getFlovatars(address: Address) : [FlovatarData] { var flovatarData: [FlovatarData] = [] let account = getAccount(address) @@ -749,11 +749,11 @@ pub contract Flovatar: NonFungibleToken { // This returns all the previously minted combinations, so that duplicates won't be allowed - pub fun getMintedCombinations() : [String] { + access(all) getMintedCombinations() : [String] { return Flovatar.mintedCombinations.keys } // This returns all the previously minted names, so that duplicates won't be allowed - pub fun getMintedNames() : [String] { + access(all) getMintedNames() : [String] { return Flovatar.mintedNames.keys } @@ -769,7 +769,7 @@ pub contract Flovatar: NonFungibleToken { // This helper function will generate a string from a list of components, // to be used as a sort of barcode to keep the inventory of the minted // Flovatars and to avoid duplicates - pub fun getCombinationString( + access(all) getCombinationString( body: UInt64, hair: UInt64, facialHair: UInt64?, @@ -784,7 +784,7 @@ pub contract Flovatar: NonFungibleToken { // This function will get a list of component IDs and will check if the // generated string is unique or if someone already used it before. - pub fun checkCombinationAvailable( + access(all) checkCombinationAvailable( body: UInt64, hair: UInt64, facialHair: UInt64?, @@ -807,7 +807,7 @@ pub contract Flovatar: NonFungibleToken { // This will check if a specific Name has already been taken // and assigned to some Flovatar - pub fun checkNameAvailable(name: String) : Bool { + access(all) checkNameAvailable(name: String) : Bool { return name.length > 2 && name.length < 20 && ! Flovatar.mintedNames.containsKey(name) } @@ -819,7 +819,7 @@ pub contract Flovatar: NonFungibleToken { // The Spark NFT will entitle to use any common basic component (body, hair, etc.) // In order to use special rare components a boost of the same rarity will be needed // for each component used - pub fun createFlovatar( + access(all) createFlovatar( spark: @FlovatarComponent.NFT, body: UInt64, hair: UInt64, @@ -1110,10 +1110,10 @@ pub contract Flovatar: NonFungibleToken { // These functions will return the current Royalty cuts for // both the Creator and the Marketplace. - pub fun getRoyaltyCut(): UFix64{ + access(all) getRoyaltyCut(): UFix64{ return self.royaltyCut } - pub fun getMarketplaceCut(): UFix64{ + access(all) getMarketplaceCut(): UFix64{ return self.marketplaceCut } // Only Admins will be able to call the set functions to @@ -1130,13 +1130,13 @@ pub contract Flovatar: NonFungibleToken { // This is the main Admin resource that will allow the owner // to generate new Templates, Components and Packs - pub resource Admin { + access(all) resource Admin { //This will create a new FlovatarComponentTemplate that // contains all the SVG and basic informations to represent // a specific part of the Flovatar (body, hair, eyes, mouth, etc.) // More info in the FlovatarComponentTemplate.cdc file - pub fun createComponentTemplate( + access(all) createComponentTemplate( name: String, category: String, color: String, @@ -1159,11 +1159,11 @@ pub contract Flovatar: NonFungibleToken { } // This will mint a new Component based from a selected Template - pub fun createComponent(templateId: UInt64) : @FlovatarComponent.NFT { + access(all) createComponent(templateId: UInt64) : @FlovatarComponent.NFT { return <- FlovatarComponent.createComponent(templateId: templateId) } // This will mint Components in batch and return a Collection instead of the single NFT - pub fun batchCreateComponents(templateId: UInt64, quantity: UInt64) : @FlovatarComponent.Collection { + access(all) batchCreateComponents(templateId: UInt64, quantity: UInt64) : @FlovatarComponent.Collection { return <- FlovatarComponent.batchCreateComponents(templateId: templateId, quantity: quantity) } @@ -1171,7 +1171,7 @@ pub contract Flovatar: NonFungibleToken { // A random string is passed to manage permissions for the // purchase of it (more info on FlovatarPack.cdc). // Finally the sale price is set as well. - pub fun createPack( + access(all) createPack( components: @[FlovatarComponent.NFT], randomString: String, price: UFix64, @@ -1192,17 +1192,17 @@ pub contract Flovatar: NonFungibleToken { // With this function you can generate a new Admin resource // and pass it to another user if needed - pub fun createNewAdmin(): @Admin { + access(all) createNewAdmin(): @Admin { return <-create Admin() } // Helper functions to update the Royalty cut - pub fun setRoyaltyCut(value: UFix64) { + access(all) setRoyaltyCut(value: UFix64) { Flovatar.setRoyaltyCut(value: value) } // Helper functions to update the Marketplace cut - pub fun setMarketplaceCut(value: UFix64) { + access(all) setMarketplaceCut(value: UFix64) { Flovatar.setMarketplaceCut(value: value) } } @@ -1225,11 +1225,11 @@ pub contract Flovatar: NonFungibleToken { self.royaltyCut = 0.01 self.marketplaceCut = 0.05 - self.account.save<@NonFungibleToken.Collection>(<- Flovatar.createEmptyCollection(), to: Flovatar.CollectionStoragePath) + self.account.storage.save<@NonFungibleToken.Collection>(<- Flovatar.createEmptyCollection(), to: Flovatar.CollectionStoragePath) self.account.link<&{Flovatar.CollectionPublic}>(Flovatar.CollectionPublicPath, target: Flovatar.CollectionStoragePath) // Put the Admin resource in storage - self.account.save<@Admin>(<- create Admin(), to: self.AdminStoragePath) + self.account.storage.save<@Admin>(<- create Admin(), to: self.AdminStoragePath) emit ContractInitialized() } diff --git a/contracts/community/FlovatarComponent.cdc b/contracts/community/FlovatarComponent.cdc index f68d6379..8ab6f632 100644 --- a/contracts/community/FlovatarComponent.cdc +++ b/contracts/community/FlovatarComponent.cdc @@ -1,8 +1,8 @@ -import FungibleToken from "../standard/FungibleToken.cdc" -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import FlowToken from "../standard/FlowToken.cdc" -import FlovatarComponentTemplate from "./FlovatarComponentTemplate.cdc" -import MetadataViews from "../standard/MetadataViews.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "FlowToken" +import "FlovatarComponentTemplate" +import "MetadataViews" /* @@ -12,50 +12,50 @@ import MetadataViews from "../standard/MetadataViews.cdc" */ -pub contract FlovatarComponent: NonFungibleToken { +access(all) contract FlovatarComponent: NonFungibleToken { - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath // Counter for all the Components ever minted - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 // Standard events that will be emitted - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Created(id: UInt64, templateId: UInt64, mint: UInt64) - pub event Destroyed(id: UInt64, templateId: UInt64) + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Created(id: UInt64, templateId: UInt64, mint: UInt64) + access(all) event Destroyed(id: UInt64, templateId: UInt64) // The public interface provides all the basic informations about // the Component and also the Template ID associated with it. - pub resource interface Public { - pub let id: UInt64 - pub let templateId: UInt64 - pub let mint: UInt64 - pub fun getTemplate(): FlovatarComponentTemplate.ComponentTemplateData - pub fun getSvg(): String - pub fun getCategory(): String - pub fun getSeries(): UInt32 - pub fun getRarity(): String - pub fun isBooster(rarity: String): Bool - pub fun checkCategorySeries(category: String, series: UInt32): Bool + access(all) resource interface Public { + access(all) let id: UInt64 + access(all) let templateId: UInt64 + access(all) let mint: UInt64 + access(all) getTemplate(): FlovatarComponentTemplate.ComponentTemplateData + access(all) getSvg(): String + access(all) getCategory(): String + access(all) getSeries(): UInt32 + access(all) getRarity(): String + access(all) isBooster(rarity: String): Bool + access(all) checkCategorySeries(category: String, series: UInt32): Bool //these three are added because I think they will be in the standard. At least Dieter thinks it will be needed - pub let name: String - pub let description: String - pub let schema: String? + access(all) let name: String + access(all) let description: String + access(all) let schema: String? } // The NFT resource that implements the Public interface as well - pub resource NFT: NonFungibleToken.INFT, Public, MetadataViews.Resolver { - pub let id: UInt64 - pub let templateId: UInt64 - pub let mint: UInt64 - pub let name: String - pub let description: String - pub let schema: String? + access(all) resource NFT: NonFungibleToken.INFT, Public, ViewResolver.Resolver { + access(all) let id: UInt64 + access(all) let templateId: UInt64 + access(all) let mint: UInt64 + access(all) let name: String + access(all) let description: String + access(all) let schema: String? // Initiates the NFT from a Template ID. init(templateId: UInt64) { @@ -76,43 +76,43 @@ pub contract FlovatarComponent: NonFungibleToken { FlovatarComponentTemplate.setLastComponentMintedAt(id: templateId, value: getCurrentBlock().timestamp) } - pub fun getID(): UInt64 { + access(all) getID(): UInt64 { return self.id } // Returns the Template associated to the current Component - pub fun getTemplate(): FlovatarComponentTemplate.ComponentTemplateData { + access(all) getTemplate(): FlovatarComponentTemplate.ComponentTemplateData { return FlovatarComponentTemplate.getComponentTemplate(id: self.templateId)! } // Gets the SVG from the parent Template - pub fun getSvg(): String { + access(all) getSvg(): String { return self.getTemplate().svg! } // Gets the category from the parent Template - pub fun getCategory(): String { + access(all) getCategory(): String { return self.getTemplate().category } // Gets the series number from the parent Template - pub fun getSeries(): UInt32 { + access(all) getSeries(): UInt32 { return self.getTemplate().series } // Gets the rarity from the parent Template - pub fun getRarity(): String { + access(all) getRarity(): String { return self.getTemplate().rarity } // Check the boost and rarity from the parent Template - pub fun isBooster(rarity: String): Bool { + access(all) isBooster(rarity: String): Bool { let template = self.getTemplate() return template.category == "boost" && template.rarity == rarity } //Check the category and series from the parent Template - pub fun checkCategorySeries(category: String, series: UInt32): Bool { + access(all) checkCategorySeries(category: String, series: UInt32): Bool { let template = self.getTemplate() return template.category == category && template.series == series } @@ -124,7 +124,7 @@ pub contract FlovatarComponent: NonFungibleToken { emit Destroyed(id: self.id, templateId: self.templateId) } - pub fun getViews() : [Type] { + access(all) getViews() : [Type] { var views : [Type]=[] views.append(Type()) views.append(Type()) @@ -137,7 +137,7 @@ pub contract FlovatarComponent: NonFungibleToken { return views } - pub fun resolveView(_ type: Type): AnyStruct? { + access(all) resolveView(_ type: Type): AnyStruct? { if type == Type() { let address = self.owner?.address @@ -224,9 +224,9 @@ pub contract FlovatarComponent: NonFungibleToken { storagePath: FlovatarComponent.CollectionStoragePath, publicPath: FlovatarComponent.CollectionPublicPath, providerPath: /private/FlovatarComponentCollection, - publicCollection: Type<&FlovatarComponent.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, FlovatarComponent.CollectionPublic}>(), - publicLinkedType: Type<&FlovatarComponent.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, FlovatarComponent.CollectionPublic}>(), - providerLinkedType: Type<&FlovatarComponent.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, FlovatarComponent.CollectionPublic}>(), + publicCollection: Type<&FlovatarComponent.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, FlovatarComponent.CollectionPublic}>(), + publicLinkedType: Type<&FlovatarComponent.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, FlovatarComponent.CollectionPublic}>(), + providerLinkedType: Type<&FlovatarComponent.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, FlovatarComponent.CollectionPublic}>(), createEmptyCollectionFunction: fun(): @NonFungibleToken.Collection {return <- FlovatarComponent.createEmptyCollection()} ) } @@ -235,12 +235,12 @@ pub contract FlovatarComponent: NonFungibleToken { } // Standard NFT collectionPublic interface that can also borrowComponent as the correct type - pub resource interface CollectionPublic { + access(all) resource interface CollectionPublic { - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowComponent(id: UInt64): &FlovatarComponent.NFT? { + access(all) deposit(token: @NonFungibleToken.NFT) + access(all) view fun getIDs(): [UInt64] + access(all) borrowNFT(id: UInt64): &NonFungibleToken.NFT + access(all) borrowComponent(id: UInt64): &FlovatarComponent.NFT? { // If the result isn't nil, the id of the returned reference // should be the same as the argument to the function post { @@ -251,17 +251,17 @@ pub contract FlovatarComponent: NonFungibleToken { } // Main Collection to manage all the Components NFT - pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { + access(all) resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, ViewResolver.ResolverCollection { // dictionary of NFT conforming tokens // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} init () { self.ownedNFTs <- {} } // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + access(all) withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) @@ -271,7 +271,7 @@ pub contract FlovatarComponent: NonFungibleToken { // deposit takes a NFT and adds it to the collections dictionary // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { + access(all) deposit(token: @NonFungibleToken.NFT) { let token <- token as! @FlovatarComponent.NFT let id: UInt64 = token.id @@ -285,21 +285,21 @@ pub contract FlovatarComponent: NonFungibleToken { } // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } // borrowNFT gets a reference to an NFT in the collection // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { + access(all) borrowNFT(id: UInt64): &NonFungibleToken.NFT { return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! } // borrowComponent returns a borrowed reference to a FlovatarComponent // so that the caller can read data and call methods from it. - pub fun borrowComponent(id: UInt64): &FlovatarComponent.NFT? { + access(all) borrowComponent(id: UInt64): &FlovatarComponent.NFT? { if self.ownedNFTs[id] != nil { - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) return ref as! &FlovatarComponent.NFT } else { return nil @@ -310,32 +310,32 @@ pub contract FlovatarComponent: NonFungibleToken { destroy self.ownedNFTs } - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { + access(all) borrowViewResolver(id: UInt64): &AnyResource{ViewResolver.Resolver} { pre { self.ownedNFTs[id] != nil : "NFT does not exist" } - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) let componentNFT = nft as! &FlovatarComponent.NFT - return componentNFT as &AnyResource{MetadataViews.Resolver} + return componentNFT as &AnyResource{ViewResolver.Resolver} } } // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { + access(all) createEmptyCollection(): @NonFungibleToken.Collection { return <- create Collection() } // This struct is used to send a data representation of the Components // when retrieved using the contract helper methods outside the collection. - pub struct ComponentData { - pub let id: UInt64 - pub let templateId: UInt64 - pub let mint: UInt64 - pub let name: String - pub let description: String - pub let category: String - pub let rarity: String - pub let color: String + access(all) struct ComponentData { + access(all) let id: UInt64 + access(all) let templateId: UInt64 + access(all) let mint: UInt64 + access(all) let name: String + access(all) let description: String + access(all) let category: String + access(all) let rarity: String + access(all) let color: String init(id: UInt64, templateId: UInt64, mint: UInt64) { self.id = id @@ -351,7 +351,7 @@ pub contract FlovatarComponent: NonFungibleToken { } // Get the SVG of a specific Component from an account and the ID - pub fun getSvgForComponent(address: Address, componentId: UInt64) : String? { + access(all) getSvgForComponent(address: Address, componentId: UInt64) : String? { let account = getAccount(address) if let componentCollection = account.getCapability(self.CollectionPublicPath).borrow<&{FlovatarComponent.CollectionPublic}>() { return componentCollection.borrowComponent(id: componentId)!.getSvg() @@ -360,7 +360,7 @@ pub contract FlovatarComponent: NonFungibleToken { } // Get a specific Component from an account and the ID as ComponentData - pub fun getComponent(address: Address, componentId: UInt64) : ComponentData? { + access(all) getComponent(address: Address, componentId: UInt64) : ComponentData? { let account = getAccount(address) if let componentCollection = account.getCapability(self.CollectionPublicPath).borrow<&{FlovatarComponent.CollectionPublic}>() { if let component = componentCollection.borrowComponent(id: componentId) { @@ -375,7 +375,7 @@ pub contract FlovatarComponent: NonFungibleToken { } // Get an array of all the components in a specific account as ComponentData - pub fun getComponents(address: Address) : [ComponentData] { + access(all) getComponents(address: Address) : [ComponentData] { var componentData: [ComponentData] = [] let account = getAccount(address) @@ -433,7 +433,7 @@ pub contract FlovatarComponent: NonFungibleToken { // Initialize the total supply self.totalSupply = UInt64(0) - self.account.save<@NonFungibleToken.Collection>(<- FlovatarComponent.createEmptyCollection(), to: FlovatarComponent.CollectionStoragePath) + self.account.storage.save<@NonFungibleToken.Collection>(<- FlovatarComponent.createEmptyCollection(), to: FlovatarComponent.CollectionStoragePath) self.account.link<&{FlovatarComponent.CollectionPublic}>(FlovatarComponent.CollectionPublicPath, target: FlovatarComponent.CollectionStoragePath) emit ContractInitialized() diff --git a/contracts/community/FlovatarComponentTemplate.cdc b/contracts/community/FlovatarComponentTemplate.cdc index 0907ba3f..a9eccc3f 100644 --- a/contracts/community/FlovatarComponentTemplate.cdc +++ b/contracts/community/FlovatarComponentTemplate.cdc @@ -16,48 +16,48 @@ */ -pub contract FlovatarComponentTemplate { +access(all) contract FlovatarComponentTemplate { - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath // Counter for all the Templates ever minted - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 //These counters will keep track of how many Components were minted for each Template access(contract) let totalMintedComponents: { UInt64: UInt64 } access(contract) let lastComponentMintedAt: { UInt64: UFix64 } // Event to notify about the Template creation - pub event ContractInitialized() - pub event Created(id: UInt64, name: String, category: String, color: String, maxMintableComponents: UInt64) + access(all) event ContractInitialized() + access(all) event Created(id: UInt64, name: String, category: String, color: String, maxMintableComponents: UInt64) // The public interface providing the SVG and all the other // metadata like name, category, color, series, description and // the maximum mintable Components - pub resource interface Public { - pub let id: UInt64 - pub let name: String - pub let category: String - pub let color: String - pub let description: String - pub let svg: String - pub let series: UInt32 - pub let maxMintableComponents: UInt64 - pub let rarity: String + access(all) resource interface Public { + access(all) let id: UInt64 + access(all) let name: String + access(all) let category: String + access(all) let color: String + access(all) let description: String + access(all) let svg: String + access(all) let series: UInt32 + access(all) let maxMintableComponents: UInt64 + access(all) let rarity: String } // The Component resource implementing the public interface as well - pub resource ComponentTemplate: Public { - pub let id: UInt64 - pub let name: String - pub let category: String - pub let color: String - pub let description: String - pub let svg: String - pub let series: UInt32 - pub let maxMintableComponents: UInt64 - pub let rarity: String + access(all) resource ComponentTemplate: Public { + access(all) let id: UInt64 + access(all) let name: String + access(all) let category: String + access(all) let color: String + access(all) let description: String + access(all) let svg: String + access(all) let series: UInt32 + access(all) let maxMintableComponents: UInt64 + access(all) let rarity: String // Initialize a Template with all the necessary data init( @@ -85,15 +85,15 @@ pub contract FlovatarComponentTemplate { } // Standard CollectionPublic interface that can also borrow Component Templates - pub resource interface CollectionPublic { - pub fun getIDs(): [UInt64] - pub fun borrowComponentTemplate(id: UInt64): &{FlovatarComponentTemplate.Public}? + access(all) resource interface CollectionPublic { + access(all) view fun getIDs(): [UInt64] + access(all) borrowComponentTemplate(id: UInt64): &{FlovatarComponentTemplate.Public}? } // The main Collection that manages the Templates and that implements also the Public interface - pub resource Collection: CollectionPublic { + access(all) resource Collection: CollectionPublic { // Dictionary of Component Templates - pub var ownedComponentTemplates: @{UInt64: FlovatarComponentTemplate.ComponentTemplate} + access(all) var ownedComponentTemplates: @{UInt64: FlovatarComponentTemplate.ComponentTemplate} init () { self.ownedComponentTemplates <- {} @@ -103,7 +103,7 @@ pub contract FlovatarComponentTemplate { // deposit takes a Component Template and adds it to the collections dictionary // and adds the ID to the id array - pub fun deposit(componentTemplate: @FlovatarComponentTemplate.ComponentTemplate) { + access(all) deposit(componentTemplate: @FlovatarComponentTemplate.ComponentTemplate) { let id: UInt64 = componentTemplate.id @@ -114,13 +114,13 @@ pub contract FlovatarComponentTemplate { } // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedComponentTemplates.keys } // borrowComponentTemplate returns a borrowed reference to a Component Template // so that the caller can read data and call methods from it. - pub fun borrowComponentTemplate(id: UInt64): &{FlovatarComponentTemplate.Public}? { + access(all) borrowComponentTemplate(id: UInt64): &{FlovatarComponentTemplate.Public}? { if self.ownedComponentTemplates[id] != nil { let ref = (&self.ownedComponentTemplates[id] as auth &FlovatarComponentTemplate.ComponentTemplate?)! return ref as! &FlovatarComponentTemplate.ComponentTemplate @@ -142,18 +142,18 @@ pub contract FlovatarComponentTemplate { // This struct is used to send a data representation of the Templates // when retrieved using the contract helper methods outside the collection. - pub struct ComponentTemplateData { - pub let id: UInt64 - pub let name: String - pub let category: String - pub let color: String - pub let description: String - pub let svg: String? - pub let series: UInt32 - pub let maxMintableComponents: UInt64 - pub let totalMintedComponents: UInt64 - pub let lastComponentMintedAt: UFix64 - pub let rarity: String + access(all) struct ComponentTemplateData { + access(all) let id: UInt64 + access(all) let name: String + access(all) let category: String + access(all) let color: String + access(all) let description: String + access(all) let svg: String? + access(all) let series: UInt32 + access(all) let maxMintableComponents: UInt64 + access(all) let totalMintedComponents: UInt64 + access(all) let lastComponentMintedAt: UFix64 + access(all) let rarity: String init( id: UInt64, @@ -182,7 +182,7 @@ pub contract FlovatarComponentTemplate { // Get all the Component Templates from the account. // We hide the SVG field because it might be too big to execute in a script - pub fun getComponentTemplates() : [ComponentTemplateData] { + access(all) getComponentTemplates() : [ComponentTemplateData] { var componentTemplateData: [ComponentTemplateData] = [] if let componentTemplateCollection = self.account.getCapability(self.CollectionPublicPath).borrow<&{FlovatarComponentTemplate.CollectionPublic}>() { @@ -205,7 +205,7 @@ pub contract FlovatarComponentTemplate { } // Gets a specific Template from its ID - pub fun getComponentTemplate(id: UInt64) : ComponentTemplateData? { + access(all) getComponentTemplate(id: UInt64) : ComponentTemplateData? { if let componentTemplateCollection = self.account.getCapability(self.CollectionPublicPath).borrow<&{FlovatarComponentTemplate.CollectionPublic}>() { if let componentTemplate = componentTemplateCollection.borrowComponentTemplate(id: id) { return ComponentTemplateData( @@ -225,11 +225,11 @@ pub contract FlovatarComponentTemplate { } // Returns the amount of minted Components for a specific Template - pub fun getTotalMintedComponents(id: UInt64) : UInt64? { + access(all) getTotalMintedComponents(id: UInt64) : UInt64? { return FlovatarComponentTemplate.totalMintedComponents[id] } // Returns the timestamp of the last time a Component for a specific Template was minted - pub fun getLastComponentMintedAt(id: UInt64) : UFix64? { + access(all) getLastComponentMintedAt(id: UInt64) : UFix64? { return FlovatarComponentTemplate.lastComponentMintedAt[id] } @@ -286,7 +286,7 @@ pub contract FlovatarComponentTemplate { self.totalMintedComponents = {} self.lastComponentMintedAt = {} - self.account.save<@FlovatarComponentTemplate.Collection>(<- FlovatarComponentTemplate.createEmptyCollection(), to: FlovatarComponentTemplate.CollectionStoragePath) + self.account.storage.save<@FlovatarComponentTemplate.Collection>(<- FlovatarComponentTemplate.createEmptyCollection(), to: FlovatarComponentTemplate.CollectionStoragePath) self.account.link<&{FlovatarComponentTemplate.CollectionPublic}>(FlovatarComponentTemplate.CollectionPublicPath, target: FlovatarComponentTemplate.CollectionStoragePath) emit ContractInitialized() diff --git a/contracts/community/FlovatarMarketplace.cdc b/contracts/community/FlovatarMarketplace.cdc index 35bdf619..c3f32537 100644 --- a/contracts/community/FlovatarMarketplace.cdc +++ b/contracts/community/FlovatarMarketplace.cdc @@ -1,8 +1,8 @@ -import FungibleToken from "../standard/FungibleToken.cdc" -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import FlowToken from "../standard/FlowToken.cdc" -import Flovatar from "./Flovatar.cdc" -import FlovatarComponent from "./FlovatarComponent.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "FlowToken" +import "Flovatar" +import "FlovatarComponent" /* A standard marketplace contract with Royalties management and hardcoded against Flovatar and Components. @@ -12,49 +12,49 @@ import FlovatarComponent from "./FlovatarComponent.cdc" */ -pub contract FlovatarMarketplace { +access(all) contract FlovatarMarketplace { - pub let CollectionPublicPath: PublicPath - pub let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + access(all) let CollectionStoragePath: StoragePath // The Vault of the Marketplace where it will receive the cuts on each sale - pub let marketplaceWallet: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + access(all) let marketplaceWallet: Capability<&FlowToken.Vault{FungibleToken.Receiver}> // Event that is emitted when a new NFT is put up for sale - pub event FlovatarForSale(id: UInt64, price: UFix64, address: Address) - pub event FlovatarComponentForSale(id: UInt64, price: UFix64, address: Address) + access(all) event FlovatarForSale(id: UInt64, price: UFix64, address: Address) + access(all) event FlovatarComponentForSale(id: UInt64, price: UFix64, address: Address) // Event that is emitted when the price of an NFT changes - pub event FlovatarPriceChanged(id: UInt64, newPrice: UFix64, address: Address) - pub event FlovatarComponentPriceChanged(id: UInt64, newPrice: UFix64, address: Address) + access(all) event FlovatarPriceChanged(id: UInt64, newPrice: UFix64, address: Address) + access(all) event FlovatarComponentPriceChanged(id: UInt64, newPrice: UFix64, address: Address) // Event that is emitted when a token is purchased - pub event FlovatarPurchased(id: UInt64, price: UFix64, from: Address, to: Address) - pub event FlovatarComponentPurchased(id: UInt64, price: UFix64, from: Address, to: Address) + access(all) event FlovatarPurchased(id: UInt64, price: UFix64, from: Address, to: Address) + access(all) event FlovatarComponentPurchased(id: UInt64, price: UFix64, from: Address, to: Address) // Event that is emitted when a royalty has been paid - pub event RoyaltyPaid(id: UInt64, amount: UFix64, to: Address, name: String) + access(all) event RoyaltyPaid(id: UInt64, amount: UFix64, to: Address, name: String) // Event that is emitted when a seller withdraws their NFT from the sale - pub event FlovatarSaleWithdrawn(tokenId: UInt64, address: Address) - pub event FlovatarComponentSaleWithdrawn(tokenId: UInt64, address: Address) + access(all) event FlovatarSaleWithdrawn(tokenId: UInt64, address: Address) + access(all) event FlovatarComponentSaleWithdrawn(tokenId: UInt64, address: Address) - // Interface that users will publish for their Sale collection + // Interface that users will access(all)lish for their Sale collection // that only exposes the methods that are supposed to be public - pub resource interface SalePublic { - pub fun purchaseFlovatar(tokenId: UInt64, recipientCap: Capability<&{Flovatar.CollectionPublic}>, buyTokens: @FungibleToken.Vault) - pub fun purchaseFlovatarComponent(tokenId: UInt64, recipientCap: Capability<&{FlovatarComponent.CollectionPublic}>, buyTokens: @FungibleToken.Vault) - pub fun getFlovatarPrice(tokenId: UInt64): UFix64? - pub fun getFlovatarComponentPrice(tokenId: UInt64): UFix64? - pub fun getFlovatarIDs(): [UInt64] - pub fun getFlovatarComponentIDs(): [UInt64] - pub fun getFlovatar(tokenId: UInt64): &{Flovatar.Public}? - pub fun getFlovatarComponent(tokenId: UInt64): &{FlovatarComponent.Public}? + access(all) resource interface SalePublic { + access(all) purchaseFlovatar(tokenId: UInt64, recipientCap: Capability<&{Flovatar.CollectionPublic}>, buyTokens: @FungibleToken.Vault) + access(all) purchaseFlovatarComponent(tokenId: UInt64, recipientCap: Capability<&{FlovatarComponent.CollectionPublic}>, buyTokens: @FungibleToken.Vault) + access(all) getFlovatarPrice(tokenId: UInt64): UFix64? + access(all) getFlovatarComponentPrice(tokenId: UInt64): UFix64? + access(all) getFlovatarIDs(): [UInt64] + access(all) getFlovatarComponentIDs(): [UInt64] + access(all) getFlovatar(tokenId: UInt64): &{Flovatar.Public}? + access(all) getFlovatarComponent(tokenId: UInt64): &{FlovatarComponent.Public}? } // NFT Collection object that allows a user to put their NFT up for sale // where others can send fungible tokens to purchase it - pub resource SaleCollection: SalePublic { + access(all) resource SaleCollection: SalePublic { // Dictionary of the NFTs that the user is putting up for sale access(contract) let flovatarForSale: @{UInt64: Flovatar.NFT} @@ -78,7 +78,7 @@ pub contract FlovatarMarketplace { } // Gives the owner the opportunity to remove a Flovatar sale from the collection - pub fun withdrawFlovatar(tokenId: UInt64): @Flovatar.NFT { + access(all) withdrawFlovatar(tokenId: UInt64): @Flovatar.NFT { // remove the price self.flovatarPrices.remove(key: tokenId) // remove and return the token @@ -91,7 +91,7 @@ pub contract FlovatarMarketplace { } // Gives the owner the opportunity to remove a Component sale from the collection - pub fun withdrawFlovatarComponent(tokenId: UInt64): @FlovatarComponent.NFT { + access(all) withdrawFlovatarComponent(tokenId: UInt64): @FlovatarComponent.NFT { // remove the price self.flovatarComponentPrices.remove(key: tokenId) // remove and return the token @@ -104,7 +104,7 @@ pub contract FlovatarMarketplace { } // Lists a Flovatar NFT for sale in this collection - pub fun listFlovatarForSale(token: @Flovatar.NFT, price: UFix64) { + access(all) listFlovatarForSale(token: @Flovatar.NFT, price: UFix64) { let id = token.id // store the price in the price array @@ -120,7 +120,7 @@ pub contract FlovatarMarketplace { } // Lists a Component NFT for sale in this collection - pub fun listFlovatarComponentForSale(token: @FlovatarComponent.NFT, price: UFix64) { + access(all) listFlovatarComponentForSale(token: @FlovatarComponent.NFT, price: UFix64) { let id = token.id // store the price in the price array @@ -136,7 +136,7 @@ pub contract FlovatarMarketplace { } // Changes the price of a Flovatar that is currently for sale - pub fun changeFlovatarPrice(tokenId: UInt64, newPrice: UFix64) { + access(all) changeFlovatarPrice(tokenId: UInt64, newPrice: UFix64) { self.flovatarPrices[tokenId] = newPrice let vaultRef = self.ownerVault.borrow() @@ -144,7 +144,7 @@ pub contract FlovatarMarketplace { emit FlovatarPriceChanged(id: tokenId, newPrice: newPrice, address: vaultRef.owner!.address) } // Changes the price of a Component that is currently for sale - pub fun changeFlovatarComponentPrice(tokenId: UInt64, newPrice: UFix64) { + access(all) changeFlovatarComponentPrice(tokenId: UInt64, newPrice: UFix64) { self.flovatarComponentPrices[tokenId] = newPrice let vaultRef = self.ownerVault.borrow() @@ -153,7 +153,7 @@ pub contract FlovatarMarketplace { } // Lets a user send tokens to purchase a Flovatar that is for sale - pub fun purchaseFlovatar(tokenId: UInt64, recipientCap: Capability<&{Flovatar.CollectionPublic}>, buyTokens: @FungibleToken.Vault) { + access(all) purchaseFlovatar(tokenId: UInt64, recipientCap: Capability<&{Flovatar.CollectionPublic}>, buyTokens: @FungibleToken.Vault) { pre { self.flovatarForSale[tokenId] != nil && self.flovatarPrices[tokenId] != nil: "No token matching this ID for sale!" @@ -194,7 +194,7 @@ pub contract FlovatarMarketplace { } // Lets a user send tokens to purchase a Component that is for sale - pub fun purchaseFlovatarComponent(tokenId: UInt64, recipientCap: Capability<&{FlovatarComponent.CollectionPublic}>, buyTokens: @FungibleToken.Vault) { + access(all) purchaseFlovatarComponent(tokenId: UInt64, recipientCap: Capability<&{FlovatarComponent.CollectionPublic}>, buyTokens: @FungibleToken.Vault) { pre { self.flovatarComponentForSale[tokenId] != nil && self.flovatarComponentPrices[tokenId] != nil: "No token matching this ID for sale!" @@ -229,26 +229,26 @@ pub contract FlovatarMarketplace { } // Returns the price of a specific Flovatar in the sale - pub fun getFlovatarPrice(tokenId: UInt64): UFix64? { + access(all) getFlovatarPrice(tokenId: UInt64): UFix64? { return self.flovatarPrices[tokenId] } // Returns the price of a specific Component in the sale - pub fun getFlovatarComponentPrice(tokenId: UInt64): UFix64? { + access(all) getFlovatarComponentPrice(tokenId: UInt64): UFix64? { return self.flovatarComponentPrices[tokenId] } // Returns an array of Flovatar IDs that are for sale - pub fun getFlovatarIDs(): [UInt64] { + access(all) getFlovatarIDs(): [UInt64] { return self.flovatarForSale.keys } // Returns an array of Component IDs that are for sale - pub fun getFlovatarComponentIDs(): [UInt64] { + access(all) getFlovatarComponentIDs(): [UInt64] { return self.flovatarComponentForSale.keys } // Returns a borrowed reference to a Flovatar Sale // so that the caller can read data and call methods from it. - pub fun getFlovatar(tokenId: UInt64): &{Flovatar.Public}? { + access(all) getFlovatar(tokenId: UInt64): &{Flovatar.Public}? { if self.flovatarForSale[tokenId] != nil { let ref = (&self.flovatarForSale[tokenId] as auth &NonFungibleToken.NFT?)! return ref as! &Flovatar.NFT @@ -258,7 +258,7 @@ pub contract FlovatarMarketplace { } // Returns a borrowed reference to a Component Sale // so that the caller can read data and call methods from it. - pub fun getFlovatarComponent(tokenId: UInt64): &{FlovatarComponent.Public}? { + access(all) getFlovatarComponent(tokenId: UInt64): &{FlovatarComponent.Public}? { if self.flovatarComponentForSale[tokenId] != nil { let ref = (&self.flovatarComponentForSale[tokenId] as auth &NonFungibleToken.NFT?)! return ref as! &FlovatarComponent.NFT @@ -276,14 +276,14 @@ pub contract FlovatarMarketplace { // This struct is used to send a data representation of the Flovatar Sales // when retrieved using the contract helper methods outside the collection. - pub struct FlovatarSaleData { - pub let id: UInt64 - pub let price: UFix64 - pub let metadata: Flovatar.Metadata - pub let accessoryId: UInt64? - pub let hatId: UInt64? - pub let eyeglassesId: UInt64? - pub let backgroundId: UInt64? + access(all) struct FlovatarSaleData { + access(all) let id: UInt64 + access(all) let price: UFix64 + access(all) let metadata: Flovatar.Metadata + access(all) let accessoryId: UInt64? + access(all) let hatId: UInt64? + access(all) let eyeglassesId: UInt64? + access(all) let backgroundId: UInt64? init( id: UInt64, @@ -307,10 +307,10 @@ pub contract FlovatarMarketplace { // This struct is used to send a data representation of the Component Sales // when retrieved using the contract helper methods outside the collection. - pub struct FlovatarComponentSaleData { - pub let id: UInt64 - pub let price: UFix64 - pub let metadata: FlovatarComponent.ComponentData + access(all) struct FlovatarComponentSaleData { + access(all) let id: UInt64 + access(all) let price: UFix64 + access(all) let metadata: FlovatarComponent.ComponentData init( id: UInt64, @@ -324,7 +324,7 @@ pub contract FlovatarMarketplace { } // Get all the Flovatar Sale offers for a specific account - pub fun getFlovatarSales(address: Address) : [FlovatarSaleData] { + access(all) getFlovatarSales(address: Address) : [FlovatarSaleData] { var saleData: [FlovatarSaleData] = [] let account = getAccount(address) @@ -347,7 +347,7 @@ pub contract FlovatarMarketplace { } // Get all the Component Sale offers for a specific account - pub fun getFlovatarComponentSales(address: Address) : [FlovatarComponentSaleData] { + access(all) getFlovatarComponentSales(address: Address) : [FlovatarComponentSaleData] { var saleData: [FlovatarComponentSaleData] = [] let account = getAccount(address) @@ -370,7 +370,7 @@ pub contract FlovatarMarketplace { } // Get a specific Flovatar Sale offers for an account - pub fun getFlovatarSale(address: Address, id: UInt64) : FlovatarSaleData? { + access(all) getFlovatarSale(address: Address, id: UInt64) : FlovatarSaleData? { let account = getAccount(address) if let saleCollection = account.getCapability(self.CollectionPublicPath).borrow<&{FlovatarMarketplace.SalePublic}>() { @@ -391,7 +391,7 @@ pub contract FlovatarMarketplace { } // Get a specific Component Sale offers for an account - pub fun getFlovatarComponentSale(address: Address, id: UInt64) : FlovatarComponentSaleData? { + access(all) getFlovatarComponentSale(address: Address, id: UInt64) : FlovatarComponentSaleData? { let account = getAccount(address) @@ -415,11 +415,11 @@ pub contract FlovatarMarketplace { // Returns a new collection resource to the caller - pub fun createSaleCollection(ownerVault: Capability<&{FungibleToken.Receiver}>): @SaleCollection { + access(all) createSaleCollection(ownerVault: Capability<&{FungibleToken.Receiver}>): @SaleCollection { return <- create SaleCollection(vault: ownerVault) } - pub init() { + access(all) init() { self.CollectionPublicPath= /public/FlovatarMarketplace self.CollectionStoragePath= /storage/FlovatarMarketplace diff --git a/contracts/community/FlovatarPack.cdc b/contracts/community/FlovatarPack.cdc index 30d7ebf7..8c68fb7d 100644 --- a/contracts/community/FlovatarPack.cdc +++ b/contracts/community/FlovatarPack.cdc @@ -1,10 +1,10 @@ -import FungibleToken from "../standard/FungibleToken.cdc" -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import FlowToken from "../standard/FlowToken.cdc" -import FlovatarComponentTemplate from "./FlovatarComponentTemplate.cdc" -import FlovatarComponent from "./FlovatarComponent.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "FlowToken" +import "FlovatarComponentTemplate" +import "FlovatarComponent" import Crypto -import FlowUtilityToken from "../standard/FlowUtilityToken.cdc" +import "FlowUtilityToken" /* @@ -21,39 +21,39 @@ import FlowUtilityToken from "../standard/FlowUtilityToken.cdc" */ -pub contract FlovatarPack { +access(all) contract FlovatarPack { - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath // Counter for all the Packs ever minted - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 // Standard events that will be emitted - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Created(id: UInt64, prefix: String) - pub event Opened(id: UInt64) - pub event Purchased(id: UInt64) + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Created(id: UInt64, prefix: String) + access(all) event Opened(id: UInt64) + access(all) event Purchased(id: UInt64) // The public interface contains only the ID and the price of the Pack - pub resource interface Public { - pub let id: UInt64 - pub let price: UFix64 - pub let sparkCount: UInt32 - pub let series: UInt32 - pub let name: String + access(all) resource interface Public { + access(all) let id: UInt64 + access(all) let price: UFix64 + access(all) let sparkCount: UInt32 + access(all) let series: UInt32 + access(all) let name: String } // The Pack resource that implements the Public interface and that contains // different Components in a Dictionary - pub resource Pack: Public { - pub let id: UInt64 - pub let price: UFix64 - pub let sparkCount: UInt32 - pub let series: UInt32 - pub let name: String + access(all) resource Pack: Public { + access(all) let id: UInt64 + access(all) let price: UFix64 + access(all) let sparkCount: UInt32 + access(all) let series: UInt32 + access(all) let name: String access(account) let components: @[FlovatarComponent.NFT] access(account) var randomString: String @@ -125,23 +125,23 @@ pub contract FlovatarPack { self.randomString = randomString } - pub fun removeComponent(at: Int): @FlovatarComponent.NFT { + access(all) removeComponent(at: Int): @FlovatarComponent.NFT { return <- self.components.remove(at: at) } } //Pack CollectionPublic interface that allows users to purchase a Pack - pub resource interface CollectionPublic { - pub fun getIDs(): [UInt64] - pub fun deposit(token: @FlovatarPack.Pack) - pub fun purchase(tokenId: UInt64, recipientCap: Capability<&{FlovatarPack.CollectionPublic}>, buyTokens: @FungibleToken.Vault, signature: String) - pub fun purchaseDapper(tokenId: UInt64, recipientCap: Capability<&{FlovatarPack.CollectionPublic}>, buyTokens: @FungibleToken.Vault, signature: String, expectedPrice: UFix64) + access(all) resource interface CollectionPublic { + access(all) view fun getIDs(): [UInt64] + access(all) deposit(token: @FlovatarPack.Pack) + access(all) purchase(tokenId: UInt64, recipientCap: Capability<&{FlovatarPack.CollectionPublic}>, buyTokens: @FungibleToken.Vault, signature: String) + access(all) purchaseDapper(tokenId: UInt64, recipientCap: Capability<&{FlovatarPack.CollectionPublic}>, buyTokens: @FungibleToken.Vault, signature: String, expectedPrice: UFix64) } // Main Collection that implements the Public interface and that // will handle the purchase transactions - pub resource Collection: CollectionPublic { + access(all) resource Collection: CollectionPublic { // Dictionary of all the Packs owned access(account) let ownedPacks: @{UInt64: FlovatarPack.Pack} // Capability to send the FLOW tokens to the owner's account @@ -154,13 +154,13 @@ pub contract FlovatarPack { } // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedPacks.keys } // deposit takes a Pack and adds it to the collections dictionary // and adds the ID to the id array - pub fun deposit(token: @FlovatarPack.Pack) { + access(all) deposit(token: @FlovatarPack.Pack) { let id: UInt64 = token.id // add the new token to the dictionary which removes the old one @@ -172,7 +172,7 @@ pub contract FlovatarPack { } // withdraw removes a Pack from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @FlovatarPack.Pack { + access(all) withdraw(withdrawID: UInt64): @FlovatarPack.Pack { let token <- self.ownedPacks.remove(key: withdrawID) ?? panic("Missing Pack") emit Withdraw(id: token.id, from: self.owner?.address) @@ -183,7 +183,7 @@ pub contract FlovatarPack { // This function allows any Pack owner to open the pack and receive its content // into the owner's Component Collection. // The pack is destroyed after the Components are delivered. - pub fun openPack(id: UInt64) { + access(all) openPack(id: UInt64) { // Gets the Component Collection Public capability to be able to // send there the Components contained in the Pack @@ -233,7 +233,7 @@ pub contract FlovatarPack { // This will guarantee that the contract owner will be able to decide which user can buy a pack, by // providing them the correct signature. // - pub fun purchase(tokenId: UInt64, recipientCap: Capability<&{FlovatarPack.CollectionPublic}>, buyTokens: @FungibleToken.Vault, signature: String) { + access(all) purchase(tokenId: UInt64, recipientCap: Capability<&{FlovatarPack.CollectionPublic}>, buyTokens: @FungibleToken.Vault, signature: String) { // Checks that the pack is still available and that the FLOW tokens are sufficient pre { @@ -267,7 +267,7 @@ pub contract FlovatarPack { // Verifies that the signature is valid and that it was generated from the // owner of the collection - if(!keyList.verify(signatureSet: signatureSet, signedData: self.getRandomString(id: tokenId).utf8)){ + if(!keyList.verify(signatureSet: signatureSet, signedData: self.getRandomString(id: tokenId).utf8, domainSeparationTag: "FLOW-V0.0-user")){ panic("Unable to validate the signature for the pack!") } @@ -296,7 +296,7 @@ pub contract FlovatarPack { } // - pub fun purchaseDapper(tokenId: UInt64, recipientCap: Capability<&{FlovatarPack.CollectionPublic}>, buyTokens: @FungibleToken.Vault, signature: String, expectedPrice: UFix64) { + access(all) purchaseDapper(tokenId: UInt64, recipientCap: Capability<&{FlovatarPack.CollectionPublic}>, buyTokens: @FungibleToken.Vault, signature: String, expectedPrice: UFix64) { // Checks that the pack is still available and that the FLOW tokens are sufficient pre { @@ -331,7 +331,7 @@ pub contract FlovatarPack { // Verifies that the signature is valid and that it was generated from the // owner of the collection - if(!keyList.verify(signatureSet: signatureSet, signedData: self.getRandomString(id: tokenId).utf8)){ + if(!keyList.verify(signatureSet: signatureSet, signedData: self.getRandomString(id: tokenId).utf8, domainSeparationTag: "FLOW-V0.0-user")){ panic("Unable to validate the signature for the pack!") } @@ -368,12 +368,12 @@ pub contract FlovatarPack { // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(ownerVault: Capability<&{FungibleToken.Receiver}>): @FlovatarPack.Collection { + access(all) createEmptyCollection(ownerVault: Capability<&{FungibleToken.Receiver}>): @FlovatarPack.Collection { return <- create Collection(ownerVault: ownerVault) } // Get all the packs from a specific account - pub fun getPacks(address: Address) : [UInt64]? { + access(all) getPacks(address: Address) : [UInt64]? { let account = getAccount(address) @@ -423,7 +423,7 @@ pub contract FlovatarPack { // Initialize the total supply self.totalSupply = 0 - self.account.save<@FlovatarPack.Collection>(<- FlovatarPack.createEmptyCollection(ownerVault: wallet), to: FlovatarPack.CollectionStoragePath) + self.account.storage.save<@FlovatarPack.Collection>(<- FlovatarPack.createEmptyCollection(ownerVault: wallet), to: FlovatarPack.CollectionStoragePath) self.account.link<&{FlovatarPack.CollectionPublic}>(FlovatarPack.CollectionPublicPath, target: FlovatarPack.CollectionStoragePath) emit ContractInitialized() diff --git a/contracts/community/Flowty.cdc b/contracts/community/Flowty.cdc index 9adb67bd..7e0f5ea7 100644 --- a/contracts/community/Flowty.cdc +++ b/contracts/community/Flowty.cdc @@ -1,9 +1,9 @@ -import FungibleToken from "../standard/FungibleToken.cdc" -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import FUSD from "../standard/FUSD.cdc" +import "FungibleToken" +import "NonFungibleToken" +import "FUSD" -import FlowtyUtils from "./FlowtyUtils.cdc" -import CoatCheck from "./CoatCheck.cdc" +import "FlowtyUtils" +import "CoatCheck" // Flowty // @@ -25,12 +25,12 @@ import CoatCheck from "./CoatCheck.cdc" // Lenders can watch for Listing events and check the NFT type and // ID to see if they wish to fund the listed loan. // -pub contract Flowty { +access(all) contract Flowty { // FlowtyInitialized // This contract has been deployed. // Event consumers can now expect events from this contract. // - pub event FlowtyInitialized() + access(all) event FlowtyInitialized() // FlowtyStorefrontInitialized // A FlowtyStorefront resource has been created. @@ -44,7 +44,7 @@ pub contract Flowty { // If the seller moves the FlowtyStorefront while the listing is valid, // that is on them. // - pub event FlowtyStorefrontInitialized(flowtyStorefrontResourceID: UInt64) + access(all) event FlowtyStorefrontInitialized(flowtyStorefrontResourceID: UInt64) // FlowtyMarketplaceInitialized // A FlowtyMarketplace resource has been created. @@ -58,21 +58,21 @@ pub contract Flowty { // If the seller moves the FlowtyStorefront while the listing is valid, // that is on them. // - pub event FlowtyMarketplaceInitialized(flowtyMarketplaceResourceID: UInt64) + access(all) event FlowtyMarketplaceInitialized(flowtyMarketplaceResourceID: UInt64) // FlowtyStorefrontDestroyed // A FlowtyStorefront has been destroyed. // Event consumers can now stop processing events from this FlowtyStorefront. // Note that we do not specify an address. // - pub event FlowtyStorefrontDestroyed(flowtyStorefrontResourceID: UInt64) + access(all) event FlowtyStorefrontDestroyed(flowtyStorefrontResourceID: UInt64) // FlowtyMarketplaceDestroyed // A FlowtyMarketplace has been destroyed. // Event consumers can now stop processing events from this FlowtyMarketplace. // Note that we do not specify an address. // - pub event FlowtyMarketplaceDestroyed(flowtyStorefrontResourceID: UInt64) + access(all) event FlowtyMarketplaceDestroyed(flowtyStorefrontResourceID: UInt64) // ListingAvailable // A listing has been created and added to a FlowtyStorefront resource. @@ -80,7 +80,7 @@ pub contract Flowty { // the state of the accounts they refer to may be changed outside of the // FlowtyMarketplace workflow, so be careful to check when using them. // - pub event ListingAvailable( + access(all) event ListingAvailable( flowtyStorefrontAddress: Address, flowtyStorefrontID: UInt64, listingResourceID: UInt64, @@ -98,7 +98,7 @@ pub contract Flowty { // ListingCompleted // The listing has been resolved. It has either been funded, or removed and destroyed. // - pub event ListingCompleted( + access(all) event ListingCompleted( listingResourceID: UInt64, flowtyStorefrontID: UInt64, funded: Bool, @@ -113,7 +113,7 @@ pub contract Flowty { // the state of the accounts they refer to may be changed outside of the // FlowtyMarketplace workflow, so be careful to check when using them. // - pub event FundingAvailable( + access(all) event FundingAvailable( fundingResourceID: UInt64, listingResourceID: UInt64, borrower: Address, @@ -127,7 +127,7 @@ pub contract Flowty { // FundingRepaid // A funding has been repaid. // - pub event FundingRepaid( + access(all) event FundingRepaid( fundingResourceID: UInt64, listingResourceID: UInt64, borrower: Address, @@ -140,7 +140,7 @@ pub contract Flowty { // FundingSettled // A funding has been settled. // - pub event FundingSettled( + access(all) event FundingSettled( fundingResourceID: UInt64, listingResourceID: UInt64, borrower: Address, @@ -150,17 +150,17 @@ pub contract Flowty { repaymentAmount: UFix64 ) - pub event CollectionSupportChanged( + access(all) event CollectionSupportChanged( collectionIdentifier: String, state: Bool ) - pub event RoyaltyAdded( + access(all) event RoyaltyAdded( collectionIdentifier: String, rate: UFix64 ) - pub event RoyaltyEscrow( + access(all) event RoyaltyEscrow( fundingResourceID: UInt64, listingResourceID: UInt64, lender: Address, @@ -169,48 +169,48 @@ pub contract Flowty { // FlowtyStorefrontStoragePath // The location in storage that a FlowtyStorefront resource should be located. - pub let FlowtyStorefrontStoragePath: StoragePath + access(all) let FlowtyStorefrontStoragePath: StoragePath // FlowtyMarketplaceStoragePath // The location in storage that a FlowtyMarketplace resource should be located. - pub let FlowtyMarketplaceStoragePath: StoragePath + access(all) let FlowtyMarketplaceStoragePath: StoragePath // FlowtyStorefrontPublicPath // The public location for a FlowtyStorefront link. - pub let FlowtyStorefrontPublicPath: PublicPath + access(all) let FlowtyStorefrontPublicPath: PublicPath // FlowtyMarketplacePublicPath // The public location for a FlowtyMarketplace link. - pub let FlowtyMarketplacePublicPath: PublicPath + access(all) let FlowtyMarketplacePublicPath: PublicPath // FlowtyAdminStoragePath // The location in storage that an FlowtyAdmin resource should be located. - pub let FlowtyAdminStoragePath: StoragePath + access(all) let FlowtyAdminStoragePath: StoragePath // FusdVaultStoragePath // The location in storage that an FUSD Vault resource should be located. - pub let FusdVaultStoragePath: StoragePath + access(all) let FusdVaultStoragePath: StoragePath // FusdReceiverPublicPath // The public location for a FUSD Receiver link. - pub let FusdReceiverPublicPath: PublicPath + access(all) let FusdReceiverPublicPath: PublicPath // FusdBalancePublicPath // The public location for a FUSD Balance link. - pub let FusdBalancePublicPath: PublicPath + access(all) let FusdBalancePublicPath: PublicPath // ListingFee // The fixed fee in FUSD for a listing. - pub var ListingFee: UFix64 + access(all) var ListingFee: UFix64 // FundingFee // The percentage fee on funding, a number between 0 and 1. - pub var FundingFee: UFix64 + access(all) var FundingFee: UFix64 // SuspendedFundingPeriod // The suspended funding period in seconds(started on listing). // So that the borrower has some time to delist it. - pub var SuspendedFundingPeriod: UFix64 + access(all) var SuspendedFundingPeriod: UFix64 // A dictionary for the Collection to royalty configuration. access(account) var Royalties: {String:Royalty} @@ -223,17 +223,17 @@ pub contract Flowty { // A struct representing a recipient that must be sent a certain amount // of the payment when a tx is executed. // - pub struct PaymentCut { + access(all) struct PaymentCut { // The receiver for the payment. // Note that we do not store an address to find the Vault that this represents, // as the link or resource that we fetch in this way may be manipulated, // so to find the address that a cut goes to you must get this struct and then // call receiver.borrow().owner.address on it. // This can be done efficiently in a script. - pub let receiver: Capability<&{FungibleToken.Receiver}> + access(all) let receiver: Capability<&{FungibleToken.Receiver}> // The amount of the payment FungibleToken that will be paid to the receiver. - pub let amount: UFix64 + access(all) let amount: UFix64 // initializer // @@ -243,12 +243,12 @@ pub contract Flowty { } } - pub struct Royalty { + access(all) struct Royalty { // The percentage points that should go to the collection owner // In the event of a loan default - pub let Rate: UFix64 - pub let Address: Address - pub let ReceiverPaths: {String: PublicPath} + access(all) let Rate: UFix64 + access(all) let Address: Address + access(all) let ReceiverPaths: {String: PublicPath} init(rate: UFix64, address: Address) { self.Rate = rate @@ -264,40 +264,40 @@ pub contract Flowty { // ListingDetails // A struct containing a Listing's data. // - pub struct ListingDetails { + access(all) struct ListingDetails { // The FlowtyStorefront that the Listing is stored in. // Note that this resource cannot be moved to a different FlowtyStorefront - pub var flowtyStorefrontID: UInt64 + access(all) var flowtyStorefrontID: UInt64 // Whether this listing has been funded or not. - pub var funded: Bool + access(all) var funded: Bool // The Type of the NonFungibleToken.NFT that is being listed. - pub let nftType: Type + access(all) let nftType: Type // The ID of the NFT within that type. - pub let nftID: UInt64 + access(all) let nftID: UInt64 // The amount of the requested loan. - pub let amount: UFix64 + access(all) let amount: UFix64 // The interest rate in %, a number between 0 and 1. - pub let interestRate: UFix64 + access(all) let interestRate: UFix64 //The term in seconds for this listing. - pub var term: UFix64 + access(all) var term: UFix64 // The Type of the FungibleToken that fundings must be made in. - pub let paymentVaultType: Type + access(all) let paymentVaultType: Type // This specifies the division of payment between recipients. access(self) let paymentCuts: [PaymentCut] //The time the funding start at - pub var listedTime: UFix64 + access(all) var listedTime: UFix64 // The royalty rate needed as a deposit for this loan to be funded - pub var royaltyRate: UFix64 + access(all) var royaltyRate: UFix64 // The number of seconds this listing is valid for - pub var expiresAfter: UFix64 + access(all) var expiresAfter: UFix64 // getPaymentCuts // Returns payment cuts - pub fun getPaymentCuts(): [PaymentCut] { + access(all) getPaymentCuts(): [PaymentCut] { return self.paymentCuts } - pub fun getTotalPayment(): UFix64 { + access(all) getTotalPayment(): UFix64 { return self.amount * (1.0 + (self.interestRate * Flowty.FundingFee) + self.royaltyRate) } @@ -353,36 +353,36 @@ pub contract Flowty { // ListingPublic // An interface providing a useful public interface to a Listing. // - pub resource interface ListingPublic { + access(all) resource interface ListingPublic { // borrowNFT // This will assert in the same way as the NFT standard borrowNFT() // if the NFT is absent, for example if it has been sold via another listing. // - pub fun borrowNFT(): &NonFungibleToken.NFT + access(all) borrowNFT(): &NonFungibleToken.NFT // fund // Fund the listing. // This pays the beneficiaries and returns the token to the buyer. // - pub fun fund(payment: @FungibleToken.Vault, + access(all) fund(payment: @FungibleToken.Vault, lenderFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, - lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>) + lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>) // getDetails // - pub fun getDetails(): ListingDetails + access(all) getDetails(): ListingDetails // suspensionTimeRemaining // - pub fun suspensionTimeRemaining() : Fix64 + access(all) suspensionTimeRemaining() : Fix64 // remainingTimeToFund // - pub fun remainingTimeToFund(): Fix64 + access(all) remainingTimeToFund(): Fix64 // isFundingEnabled // - pub fun isFundingEnabled(): Bool + access(all) isFundingEnabled(): Bool } @@ -390,7 +390,7 @@ pub contract Flowty { // A resource that allows an NFT to be fund for an amount of a given FungibleToken, // and for the proceeds of that payment to be split between several recipients. // - pub resource Listing: ListingPublic { + access(all) resource Listing: ListingPublic { // The simple (non-Capability, non-complex) details of the listing access(self) let details: ListingDetails @@ -398,10 +398,10 @@ pub contract Flowty { // This capability allows the resource to withdraw *any* NFT, so you should be careful when giving // such a capability to a resource and always check its code to make sure it will use it in the // way that it claims. - access(contract) let nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}> + access(contract) let nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}> // A capability allowing this resource to access the owner's NFT public collection - access(contract) let nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.CollectionPublic}> + access(contract) let nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.Collection}> // A capability allowing this resource to withdraw `FungibleToken`s from borrower account. @@ -413,7 +413,7 @@ pub contract Flowty { // This will assert in the same way as the NFT standard borrowNFT() // if the NFT is absent, for example if it has been sold via another listing. // - pub fun borrowNFT(): &NonFungibleToken.NFT { + access(all) borrowNFT(): &NonFungibleToken.NFT { let ref = self.nftProviderCapability.borrow()!.borrowNFT(id: self.getDetails().nftID) assert(ref.getType() == self.getDetails().nftType, message: "token has wrong type") assert(ref.id == self.getDetails().nftID, message: "token has wrong ID") @@ -425,7 +425,7 @@ pub contract Flowty { // This avoids having more public variables and getter methods for them, and plays // nicely with scripts (which cannot return resources). // - pub fun getDetails(): ListingDetails { + access(all) getDetails(): ListingDetails { return self.details } @@ -433,9 +433,9 @@ pub contract Flowty { // Fund the listing. // This pays the beneficiaries and move the NFT to the funding resource stored in the marketplace account. // - pub fun fund(payment: @FungibleToken.Vault, + access(all) fund(payment: @FungibleToken.Vault, lenderFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, - lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>) { + lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>) { pre { self.isFundingEnabled(): "Funding is not enabled or this listing has expired" self.details.funded == false: "listing has already been funded" @@ -528,7 +528,7 @@ pub contract Flowty { // suspensionTimeRemaining // The remaining time. This can be negative if is expired - pub fun suspensionTimeRemaining() : Fix64 { + access(all) suspensionTimeRemaining() : Fix64 { let listedTime = self.details.listedTime let currentTime = getCurrentBlock().timestamp @@ -539,7 +539,7 @@ pub contract Flowty { // remainingTimeToFund // The time in seconds left until this listing is no longer valid - pub fun remainingTimeToFund(): Fix64 { + access(all) remainingTimeToFund(): Fix64 { let listedTime = self.details.listedTime let currentTime = getCurrentBlock().timestamp let remaining = Fix64(listedTime + self.details.expiresAfter) - Fix64(currentTime) @@ -547,7 +547,7 @@ pub contract Flowty { } // isFundingEnabled - pub fun isFundingEnabled(): Bool { + access(all) isFundingEnabled(): Bool { let timeRemaining = self.suspensionTimeRemaining() let listingTimeRemaining = self.remainingTimeToFund() return timeRemaining < Fix64(0.0) && listingTimeRemaining > Fix64(0.0) @@ -556,8 +556,8 @@ pub contract Flowty { // initializer // init ( - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, - nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, + nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.Collection}>, fusdProviderCapability: Capability<&{FungibleToken.Provider}>?, nftType: Type, nftID: UInt64, @@ -618,29 +618,29 @@ pub contract Flowty { // FundingDetails // A struct containing a Fundings's data. // - pub struct FundingDetails { + access(all) struct FundingDetails { // The FlowtyStorefront that the Funding is stored in. // Note that this resource cannot be moved to a different FlowtyStorefront - pub var flowtyStorefrontID: UInt64 - pub var listingResourceID: UInt64 + access(all) var flowtyStorefrontID: UInt64 + access(all) var listingResourceID: UInt64 // Whether this funding has been repaid or not. - pub var repaid: Bool + access(all) var repaid: Bool // Whether this funding has been settled or not. - pub var settled: Bool + access(all) var settled: Bool // The Type of the FungibleToken that fundings must be repaid. - pub let paymentVaultType: Type + access(all) let paymentVaultType: Type // The amount that must be repaid in the specified FungibleToken. - pub let repaymentAmount: UFix64 + access(all) let repaymentAmount: UFix64 // the time the funding start at - pub var startTime: UFix64 + access(all) var startTime: UFix64 // The length in seconds for this funding - pub var term: UFix64 + access(all) var term: UFix64 // setToRepaid // Irreversibly set this funding as repaid. @@ -679,45 +679,45 @@ pub contract Flowty { // FundingPublic // An interface providing a useful public interface to a Funding. // - pub resource interface FundingPublic { + access(all) resource interface FundingPublic { // repay // - pub fun repay(payment: @FungibleToken.Vault) + access(all) repay(payment: @FungibleToken.Vault) // getDetails // - pub fun getDetails(): FundingDetails + access(all) getDetails(): FundingDetails // get the listing details for this loan // - pub fun getListingDetails(): Flowty.ListingDetails + access(all) getListingDetails(): Flowty.ListingDetails // timeRemaining // - pub fun timeRemaining() : Fix64 + access(all) timeRemaining() : Fix64 // isFundingExpired // - pub fun isFundingExpired(): Bool + access(all) isFundingExpired(): Bool // get the amount stored in a vault for royalty payouts // - pub fun getRoyaltyAmount(): UFix64? + access(all) getRoyaltyAmount(): UFix64? } // Funding // - pub resource Funding: FundingPublic { + access(all) resource Funding: FundingPublic { // The simple (non-Capability, non-complex) details of the listing access(self) let details: FundingDetails access(self) let listingDetails: ListingDetails // A capability allowing this resource to access the owner's NFT public collection - access(contract) let ownerNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}> + access(contract) let ownerNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}> // A capability allowing this resource to access the lender's NFT public collection - access(contract) let lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}> + access(contract) let lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}> // The receiver for the repayment. access(contract) let lenderFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}> @@ -736,15 +736,15 @@ pub contract Flowty { // This avoids having more public variables and getter methods for them, and plays // nicely with scripts (which cannot return resources). // - pub fun getDetails(): FundingDetails { + access(all) getDetails(): FundingDetails { return self.details } - pub fun getListingDetails(): ListingDetails { + access(all) getListingDetails(): ListingDetails { return self.listingDetails } - pub fun getRoyaltyAmount(): UFix64? { + access(all) getRoyaltyAmount(): UFix64? { return self.royaltyVault?.balance } @@ -752,7 +752,7 @@ pub contract Flowty { // Repay the funding. // This pays the lender and returns the NFT to the owner. // - pub fun repay(payment: @FungibleToken.Vault) { + access(all) repay(payment: @FungibleToken.Vault) { pre { !self.isFundingExpired(): "the loan has expired" self.details.repaid == false: "funding has already been repaid" @@ -794,7 +794,7 @@ pub contract Flowty { // Repay the funding with borrower permit. // This pays the lender and returns the NFT to the owner using FUSD allowance from borrower account. // - pub fun repayWithPermit() { + access(all) repayWithPermit() { pre { self.details.repaid == false: "funding has already been repaid" self.details.settled == false: "funding has already been settled" @@ -838,7 +838,7 @@ pub contract Flowty { // Settle the different statuses responsible for the repayment and claiming processes. // NFT is moved to the lender, because the borrower hasn't repaid the loan. // - pub fun settleFunding() { + access(all) settleFunding() { pre { self.isFundingExpired(): "the loan hasn't expired" self.details.repaid == false: "funding has already been repaid" @@ -878,7 +878,7 @@ pub contract Flowty { // timeRemaining // The remaining time. This can be negative if is expired - pub fun timeRemaining() : Fix64 { + access(all) timeRemaining() : Fix64 { let fundingTerm = self.details.term let startTime = self.details.startTime @@ -890,7 +890,7 @@ pub contract Flowty { } // isFundingExpired - pub fun isFundingExpired(): Bool { + access(all) isFundingExpired(): Bool { let timeRemaining= self.timeRemaining() return timeRemaining < Fix64(0.0) } @@ -900,8 +900,8 @@ pub contract Flowty { init ( flowtyStorefrontID: UInt64, listingResourceID: UInt64, - ownerNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, - lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + ownerNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, + lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, NFT: @NonFungibleToken.NFT, paymentVaultType: Type, repaymentAmount: UFix64, @@ -949,15 +949,15 @@ pub contract Flowty { // An interface for adding and removing Fundings within a FlowtyMarketplace, // intended for use by the FlowtyStorefront's own // - pub resource interface FlowtyMarketplaceManager { + access(all) resource interface FlowtyMarketplaceManager { // createFunding // Allows the FlowtyMarketplace owner to create and insert Fundings. // access(contract) fun createFunding( flowtyStorefrontID: UInt64, listingResourceID: UInt64, - ownerNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, - lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + ownerNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, + lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, NFT: @NonFungibleToken.NFT, paymentVaultType: Type, lenderFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, @@ -970,37 +970,37 @@ pub contract Flowty { // removeFunding // Allows the FlowtyMarketplace owner to remove any funding. // - pub fun removeFunding(fundingResourceID: UInt64) + access(all) removeFunding(fundingResourceID: UInt64) - pub fun borrowPrivateFunding(fundingResourceID: UInt64): &Funding? + access(all) borrowPrivateFunding(fundingResourceID: UInt64): &Funding? } // FlowtyMarketplacePublic // An interface to allow listing and borrowing Listings, and funding loans via Listings // in a FlowtyStorefront. // - pub resource interface FlowtyMarketplacePublic { - pub fun getFundingIDs(): [UInt64] - pub fun borrowFunding(fundingResourceID: UInt64): &Funding{FundingPublic}? - pub fun getAllowedCollections(): [String] + access(all) resource interface FlowtyMarketplacePublic { + access(all) getFundingIDs(): [UInt64] + access(all) borrowFunding(fundingResourceID: UInt64): &Funding{FundingPublic}? + access(all) getAllowedCollections(): [String] } // FlowtyStorefront // A resource that allows its owner to manage a list of Listings, and anyone to interact with them // in order to query their details and fund the loans that they represent. // - pub resource FlowtyMarketplace : FlowtyMarketplaceManager, FlowtyMarketplacePublic { + access(all) resource FlowtyMarketplace : FlowtyMarketplaceManager, FlowtyMarketplacePublic { // The dictionary of Fundings uuids to Funding resources. access(self) var fundings: @{UInt64: Funding} // insert - // Create and publish a funding for an NFT. + // Create and access(all)lish a funding for an NFT. // access(contract) fun createFunding( flowtyStorefrontID: UInt64, listingResourceID: UInt64, - ownerNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, - lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + ownerNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, + lenderNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, NFT: @NonFungibleToken.NFT, paymentVaultType: Type, lenderFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, @@ -1062,7 +1062,7 @@ pub contract Flowty { // removeFunding // Remove a Funding. // - pub fun removeFunding(fundingResourceID: UInt64) { + access(all) removeFunding(fundingResourceID: UInt64) { let funding <- self.fundings.remove(key: fundingResourceID) ?? panic("missing Funding") @@ -1075,14 +1075,14 @@ pub contract Flowty { // getFundingIDs // Returns an array of the Funding resource IDs that are in the collection // - pub fun getFundingIDs(): [UInt64] { + access(all) getFundingIDs(): [UInt64] { return self.fundings.keys } // borrowFunding // Returns a read-only view of the Funding for the given fundingID if it is contained by this collection. // - pub fun borrowFunding(fundingResourceID: UInt64): &Funding{FundingPublic}? { + access(all) borrowFunding(fundingResourceID: UInt64): &Funding{FundingPublic}? { if self.fundings[fundingResourceID] != nil { return &self.fundings[fundingResourceID] as! &Funding{FundingPublic}? } else { @@ -1093,7 +1093,7 @@ pub contract Flowty { // borrowPrivateFunding // Returns a private view of the Funding for the given fundingID if it is contained by this collection. // - pub fun borrowPrivateFunding(fundingResourceID: UInt64): &Funding? { + access(all) borrowPrivateFunding(fundingResourceID: UInt64): &Funding? { if self.fundings[fundingResourceID] != nil { return &self.fundings[fundingResourceID] as! &Funding? } else { @@ -1101,7 +1101,7 @@ pub contract Flowty { } } - pub fun getAllowedCollections(): [String] { + access(all) getAllowedCollections(): [String] { return Flowty.SupportedCollections.keys } @@ -1127,14 +1127,14 @@ pub contract Flowty { // FlowtyStorefrontManager // An interface for adding and removing Listings within a FlowtyStorefront, // intended for use by the FlowtyStorefront's own - pub resource interface FlowtyStorefrontManager { + access(all) resource interface FlowtyStorefrontManager { // createListing // Allows the FlowtyStorefront owner to create and insert Listings. // - pub fun createListing( + access(all) createListing( payment: @FungibleToken.Vault, - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, - nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, + nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.Collection}>, fusdProviderCapability: Capability<&{FungibleToken.Provider}>?, nftType: Type, nftID: UInt64, @@ -1148,35 +1148,35 @@ pub contract Flowty { // removeListing // Allows the FlowtyStorefront owner to remove any sale listing, accepted or not. // - pub fun removeListing(listingResourceID: UInt64) + access(all) removeListing(listingResourceID: UInt64) } // FlowtyStorefrontPublic // An interface to allow listing and borrowing Listings, and funding loans via Listings // in a FlowtyStorefront. // - pub resource interface FlowtyStorefrontPublic { - pub fun getListingIDs(): [UInt64] - pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? - pub fun cleanup(listingResourceID: UInt64) - pub fun getRoyalties(): {String:Flowty.Royalty} + access(all) resource interface FlowtyStorefrontPublic { + access(all) getListingIDs(): [UInt64] + access(all) borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? + access(all) cleanup(listingResourceID: UInt64) + access(all) getRoyalties(): {String:Flowty.Royalty} } // FlowtyStorefront // A resource that allows its owner to manage a list of Listings, and anyone to interact with them // in order to query their details and fund the loans that they represent. // - pub resource FlowtyStorefront : FlowtyStorefrontManager, FlowtyStorefrontPublic { + access(all) resource FlowtyStorefront : FlowtyStorefrontManager, FlowtyStorefrontPublic { // The dictionary of Listing uuids to Listing resources. access(self) var listings: @{UInt64: Listing} // insert - // Create and publish a Listing for an NFT. + // Create and access(all)lish a Listing for an NFT. // - pub fun createListing( + access(all) createListing( payment: @FungibleToken.Vault, - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, - nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, + nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.Collection}>, fusdProviderCapability: Capability<&{FungibleToken.Provider}>?, nftType: Type, nftID: UInt64, @@ -1228,7 +1228,7 @@ pub contract Flowty { // Listing fee // let listingFee <- payment.withdraw(amount: Flowty.ListingFee) - // let flowtyFusdReceiver = Flowty.account.borrow<&FUSD.Vault{FungibleToken.Receiver}>(from: Flowty.FusdVaultStoragePath) + // let flowtyFusdReceiver = Flowty.account.storage.borrow<&FUSD.Vault{FungibleToken.Receiver}>(from: Flowty.FusdVaultStoragePath) // ?? panic("Missing or mis-typed FUSD Reveiver") // flowtyFusdReceiver.deposit(from: <-listingFee) destroy payment @@ -1256,7 +1256,7 @@ pub contract Flowty { // removeListing // Remove a Listing that has not yet been funded from the collection and destroy it. // - pub fun removeListing(listingResourceID: UInt64) { + access(all) removeListing(listingResourceID: UInt64) { let listing <- self.listings.remove(key: listingResourceID) ?? panic("missing Listing") @@ -1267,14 +1267,14 @@ pub contract Flowty { // getListingIDs // Returns an array of the Listing resource IDs that are in the collection // - pub fun getListingIDs(): [UInt64] { + access(all) getListingIDs(): [UInt64] { return self.listings.keys } // borrowListing // Returns a read-only view of the Listing for the given listingID if it is contained by this collection. // - pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? { + access(all) borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? { if self.listings[listingResourceID] != nil { return &self.listings[listingResourceID] as! &Listing{ListingPublic}? } else { @@ -1287,7 +1287,7 @@ pub contract Flowty { // Anyone can call, but at present it only benefits the account owner to do so. // Kind purchasers can however call it if they like. // - pub fun cleanup(listingResourceID: UInt64) { + access(all) cleanup(listingResourceID: UInt64) { pre { self.listings[listingResourceID] != nil: "could not find listing with given id" } @@ -1297,7 +1297,7 @@ pub contract Flowty { destroy listing } - pub fun getRoyalties(): {String:Flowty.Royalty} { + access(all) getRoyalties(): {String:Flowty.Royalty} { return Flowty.Royalties } @@ -1323,27 +1323,27 @@ pub contract Flowty { // createStorefront // Make creating a FlowtyStorefront publicly accessible. // - pub fun createStorefront(): @FlowtyStorefront { + access(all) createStorefront(): @FlowtyStorefront { return <-create FlowtyStorefront() } access(account) fun borrowMarketplace(): &Flowty.FlowtyMarketplace { - return self.account.borrow<&Flowty.FlowtyMarketplace>(from: Flowty.FlowtyMarketplaceStoragePath)! + return self.account.storage.borrow<&Flowty.FlowtyMarketplace>(from: Flowty.FlowtyMarketplaceStoragePath)! } - pub fun getRoyalty(nftTypeIdentifier: String): Royalty { + access(all) getRoyalty(nftTypeIdentifier: String): Royalty { return Flowty.Royalties[nftTypeIdentifier]! } - pub fun getTokenPaths(): {String:PublicPath} { + access(all) getTokenPaths(): {String:PublicPath} { return self.TokenPaths } // FlowtyAdmin // Allows the adminitrator to set the amount of fees, set the suspended funding period // - pub resource FlowtyAdmin { - pub fun setFees(listingFixedFee: UFix64, fundingPercentageFee: UFix64) { + access(all) resource FlowtyAdmin { + access(all) setFees(listingFixedFee: UFix64, fundingPercentageFee: UFix64) { pre { // The UFix64 type covers a negative numbers fundingPercentageFee <= 1.0: "Funding fee should be a percentage" @@ -1353,16 +1353,16 @@ pub contract Flowty { Flowty.FundingFee = fundingPercentageFee } - pub fun setSuspendedFundingPeriod(period: UFix64) { + access(all) setSuspendedFundingPeriod(period: UFix64) { Flowty.SuspendedFundingPeriod = period } - pub fun setSupportedCollection(collection: String, state: Bool) { + access(all) setSupportedCollection(collection: String, state: Bool) { Flowty.SupportedCollections[collection] = state emit CollectionSupportChanged(collectionIdentifier: collection, state: state) } - pub fun setCollectionRoyalty(collection: String, royalty: Royalty) { + access(all) setCollectionRoyalty(collection: String, royalty: Royalty) { pre { royalty.Rate <= 1.0: "Royalty rate must be a percentage" } @@ -1371,7 +1371,7 @@ pub contract Flowty { emit RoyaltyAdded(collectionIdentifier: collection, rate: royalty.Rate) } - pub fun registerFungibleTokenPath(vaultType: Type, path: PublicPath) { + access(all) registerFungibleTokenPath(vaultType: Type, path: PublicPath) { Flowty.TokenPaths[vaultType.identifier] = path } } @@ -1395,13 +1395,13 @@ pub contract Flowty { let marketplace <- create FlowtyMarketplace() - self.account.save(<-marketplace, to: self.FlowtyMarketplaceStoragePath) + self.account.storage.save(<-marketplace, to: self.FlowtyMarketplaceStoragePath) // create a public capability for the .Marketplace self.account.link<&Flowty.FlowtyMarketplace{Flowty.FlowtyMarketplacePublic}>(Flowty.FlowtyMarketplacePublicPath, target: Flowty.FlowtyMarketplaceStoragePath) // FlowtyAdmin let flowtyAdmin <- create FlowtyAdmin() - self.account.save(<-flowtyAdmin, to: self.FlowtyAdminStoragePath) + self.account.storage.save(<-flowtyAdmin, to: self.FlowtyAdminStoragePath) emit FlowtyInitialized() } diff --git a/contracts/community/FlowtyRentals.cdc b/contracts/community/FlowtyRentals.cdc index 84a36e7b..b5c11879 100644 --- a/contracts/community/FlowtyRentals.cdc +++ b/contracts/community/FlowtyRentals.cdc @@ -1,8 +1,8 @@ import FungibleToken from "../standard/FungibleToken.cdc" -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import FlowtyUtils from "./FlowtyUtils.cdc" -import Flowty from "./Flowty.cdc" -import CoatCheck from "./CoatCheck.cdc" +import "NonFungibleToken" +import "FlowtyUtils" +import "Flowty" +import "CoatCheck" // FlowtyRentals // @@ -22,11 +22,11 @@ import CoatCheck from "./CoatCheck.cdc" // // Lenders can watch for Listing events and check the NFT type and // ID to see if they wish to rent the listing on a storefront. -pub contract FlowtyRentals { +access(all) contract FlowtyRentals { // FlowtyRentalsInitialized // This contract has been deployed - pub event FlowtyRentalsInitialized() + access(all) event FlowtyRentalsInitialized() // FlowtyRentalsStorefrontInitialized // A FlowtyRentalsStorefront resource has been created. @@ -40,14 +40,14 @@ pub contract FlowtyRentals { // If the seller moves the FlowtyRentalsStorefront while the listing is valid, // that is on them. // - pub event FlowtyRentalsStorefrontInitialized(flowtyRentalsStorefrontResourceID: UInt64) + access(all) event FlowtyRentalsStorefrontInitialized(flowtyRentalsStorefrontResourceID: UInt64) // FlowtyRentalsStorefrontfrontDestroyed // A FlowtyRentalsStorefront has been destroyed. // Event consumers can now stop processing events from this FlowtyRentalsStorefront. // Note that we do not specify an address. // - pub event FlowtyRentalsStorefrontDestroyed(flowtyRentalsStorefrontResourceID: UInt64) + access(all) event FlowtyRentalsStorefrontDestroyed(flowtyRentalsStorefrontResourceID: UInt64) // FlowtyRentalsMarketplaceInitialized // A FlowtyRentalsMarketplace resource has been created. @@ -59,14 +59,14 @@ pub contract FlowtyRentals { // by default, access the one stored in this contract address's account. Any listing that is // funded will get routed to and stored there. // - pub event FlowtyRentalsMarketplaceInitialized(flowtyRentalsMarketplaceResourceID: UInt64) + access(all) event FlowtyRentalsMarketplaceInitialized(flowtyRentalsMarketplaceResourceID: UInt64) // FlowtyRentalsMarketplaceDestroyed // A FlowtyRentalsMarketplace has been destroyed. // Event consumers can now stop processing events from this FlowtyRentalsMarketplace. // Note that we do not specify an address. // - pub event FlowtyRentalsMarketplaceDestroyed(flowtyRentalsMarketplaceResourceID: UInt64) + access(all) event FlowtyRentalsMarketplaceDestroyed(flowtyRentalsMarketplaceResourceID: UInt64) // ListingAvailable // A listing has been created and added to a FlowtyRentalsStorefront resource. @@ -74,7 +74,7 @@ pub contract FlowtyRentals { // the state of the accounts they refer to may be changed outside of the // FlowtyRentalsStorefront workflow, so be careful to check before using them. // - pub event ListingAvailable( + access(all) event ListingAvailable( flowtyStorefrontAddress: Address, flowtyStorefrontID: UInt64, listingResourceID: UInt64, @@ -95,7 +95,7 @@ pub contract FlowtyRentals { // of the accounts they refer to may be changed outside of the // FlowtyRentalsMarketplace workflow, so be careful to check when using them. // - pub event ListingRented( + access(all) event ListingRented( flowtyStorefrontAddress: Address, flowtyStorefrontID: UInt64, renterAddress: Address, @@ -111,7 +111,7 @@ pub contract FlowtyRentals { // RentalReturned // A rental has been returned, releasing the deposit back to its renter // - pub event RentalReturned( + access(all) event RentalReturned( flowtyStorefrontAddress: Address, flowtyStorefrontID: UInt64, renterAddress: Address, @@ -125,7 +125,7 @@ pub contract FlowtyRentals { // Listing has been destroyed and has been removed from // the owning account's FlowtyRentalsStorefront // - pub event ListingDestroyed( + access(all) event ListingDestroyed( flowtyStorefrontAddress: Address, flowtyStorefrontID: UInt64, listingResourceID: UInt64, @@ -138,7 +138,7 @@ pub contract FlowtyRentals { // to the original owner of the rented asset and to the assets' // royalty beneficiaries // - pub event RentalSettled( + access(all) event RentalSettled( rentalResourceID: UInt64, listingResourceID: UInt64, renter: Address, @@ -148,95 +148,95 @@ pub contract FlowtyRentals { deposit: UFix64 ) - pub let FlowtyRentalsStorefrontStoragePath: StoragePath - pub let FlowtyRentalsMarketplaceStoragePath: StoragePath - pub let FlowtyRentalsStorefrontPublicPath: PublicPath - pub let FlowtyRentalsMarketplacePublicPath: PublicPath - pub let FlowtyRentalsAdminStoragePath: StoragePath + access(all) let FlowtyRentalsStorefrontStoragePath: StoragePath + access(all) let FlowtyRentalsMarketplaceStoragePath: StoragePath + access(all) let FlowtyRentalsStorefrontPublicPath: PublicPath + access(all) let FlowtyRentalsMarketplacePublicPath: PublicPath + access(all) let FlowtyRentalsAdminStoragePath: StoragePath // SuspendedFundingPeriod // A period of time in seconds before which // a listing cannot be rented. - pub var SuspendedFundingPeriod: UFix64 + access(all) var SuspendedFundingPeriod: UFix64 // Fee // Fee taken as a percentage of the initial rental fee. // For instance, if a rental has a fee of 10, Flowty will take a fee // of 10 * Fee where Fee is less than 1. - pub var Fee: UFix64 + access(all) var Fee: UFix64 // ListingDetails // Non-resource data about a listing. // - pub struct ListingDetails { + access(all) struct ListingDetails { // The ID of the storefront that this listing was made on. // Note that this listing cannot be transferred to another address - pub var flowtyStorefrontID: UInt64 + access(all) var flowtyStorefrontID: UInt64 // Signal indicating whether the listing has been rented or not. // It can only be rented once. - pub var rented: Bool + access(all) var rented: Bool // The type of the nft being rented. When attempting to rent an nft, // a listing will check that the type of the nft being rented // matches nftType // - pub let nftType: Type + access(all) let nftType: Type // The ID of the nft being rented. When attempting to rent an nft, // a listing will check that the ID of the nft being rented // matched nftID - pub let nftID: UInt64 + access(all) let nftID: UInt64 // The flat fee amount collected. This amount is split when a listing is // rented to the owner of the listing, flowty, and royalty owners // - pub let amount: UFix64 + access(all) let amount: UFix64 // The deposit fee collected. This amount is returned to a renter // if they return the nft they rented. However, if they do not, // the deposit will be transferred to the original owner of the nft // and to the royalty recipient of the nft collection // - pub let deposit: UFix64 + access(all) let deposit: UFix64 // The number of seconds that a rental is valid for when it is rented // After the term has elapsed, a rental can be settled. - pub var term: UFix64 + access(all) var term: UFix64 // The type of FungibleToken to be accepted as payment. - pub let paymentVaultType: Type + access(all) let paymentVaultType: Type // A flag to reenable the listing once it has been returned // This allows a user to keep a listing open in perpetuity // should they desire to leave it open. - pub var reenableOnReturn: Bool + access(all) var reenableOnReturn: Bool // Contains information about how to pay owner of this listing access(self) let paymentCut: Flowty.PaymentCut // The time that this listing was created - pub let listedTime: UFix64 + access(all) let listedTime: UFix64 // The royalty percentage taken at the time of listing. - pub var royaltyRate: UFix64 + access(all) var royaltyRate: UFix64 // The duration that this listing is valid for. If this amount of time // has passed, the listing can no-longer be rented. - pub var expiresAfter: UFix64 + access(all) var expiresAfter: UFix64 // An optional parameter that can be used to prevent all addresses // except for the specified one to rent this listing. // This is how we achieve private listings. - pub var renter: Address? + access(all) var renter: Address? - pub fun getPaymentCut(): Flowty.PaymentCut { + access(all) getPaymentCut(): Flowty.PaymentCut { return self.paymentCut } // getTotalPayment // get the total amount needed to rent this listing. - pub fun getTotalPayment(): UFix64 { + access(all) getTotalPayment(): UFix64 { return self.amount + self.deposit } @@ -278,47 +278,47 @@ pub contract FlowtyRentals { // ListingPublic // An inerface providing a useful public interface to a listing // - pub resource interface ListingPublic { + access(all) resource interface ListingPublic { // borrowNFT // This will assert in the same way as the NFT standard borrowNFT() // if the NFT is absent, for example if it has been sold via another listing. // - pub fun borrowNFT(): &NonFungibleToken.NFT + access(all) borrowNFT(): &NonFungibleToken.NFT // rent // Rent the listing. Distributing fees to all parties and taking a deposit to be held // until the nft is either returned or the rental defaults. A rental can be automatically returned // if renterNFTProvider is provided, giving us a way obtain the the rented nft automatically // to be returned. - pub fun rent( + access(all) rent( payment: @FungibleToken.Vault, renterFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, - renterNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, - renterNFTProvider: Capability<&AnyResource{NonFungibleToken.CollectionPublic, NonFungibleToken.Provider}>? + renterNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, + renterNFTProvider: Capability<&AnyResource{NonFungibleToken.Collection, NonFungibleToken.Provider}>? ) - pub fun getDetails(): ListingDetails + access(all) getDetails(): ListingDetails // suspensionTimeRemaining // returns the amount of time left until a listing can be filled. // - pub fun suspensionTimeRemaining(): Fix64 + access(all) suspensionTimeRemaining(): Fix64 // remainingTimeToRent // returns the amount of time left until this listing is no longer valid // - pub fun remainingTimeToRent(): Fix64 + access(all) remainingTimeToRent(): Fix64 // isRentingEnabled // checks if a listing can be rented or not. // - pub fun isRentingEnabled(): Bool + access(all) isRentingEnabled(): Bool } // Listing // A resource that allows an NFT to be temporarily owned by another account in exchange // for a Fee and a Deposit. - pub resource Listing: ListingPublic { + access(all) resource Listing: ListingPublic { // The simple (non-Capability, non-complex) details of the listing access(self) let details: ListingDetails @@ -326,10 +326,10 @@ pub contract FlowtyRentals { // This capability allows the resource to withdraw *any* NFT, so you should be careful when giving // such a capability to a resource and always check its code to make sure it will use it in the // way that it claims. - access(contract) let nftProviderCapability: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}> + access(contract) let nftProviderCapability: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.Collection}> // A capability allowing this resource to access the owner's NFT public collection - access(contract) let nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.CollectionPublic}> + access(contract) let nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.Collection}> // reference to the owner's fungibleTokenReceiver to pay them in the event of a settlement. access(contract) let ownerFungibleTokenReceiver: Capability<&AnyResource{FungibleToken.Receiver}> @@ -338,7 +338,7 @@ pub contract FlowtyRentals { // This will assert in the same way as the NFT standard borrowNFT() // if the NFT is absent, for example if it has been sold via another listing. // - pub fun borrowNFT(): &NonFungibleToken.NFT { + access(all) borrowNFT(): &NonFungibleToken.NFT { pre { self.nftProviderCapability.check(): "provider capability failed check" } @@ -354,7 +354,7 @@ pub contract FlowtyRentals { // This avoids having more public variables and getter methods for them, and plays // nicely with scripts (which cannot return resources). // - pub fun getDetails(): ListingDetails { + access(all) getDetails(): ListingDetails { return self.details } @@ -363,11 +363,11 @@ pub contract FlowtyRentals { // until the nft is either returned or the rental defaults. A rental can be automatically returned // if renterNFTProvider is provided, giving us a way obtain the the rented nft automatically // to be returned. - pub fun rent( + access(all) rent( payment: @FungibleToken.Vault, renterFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, - renterNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, - renterNFTProvider: Capability<&AnyResource{NonFungibleToken.CollectionPublic, NonFungibleToken.Provider}>? + renterNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, + renterNFTProvider: Capability<&AnyResource{NonFungibleToken.Collection, NonFungibleToken.Provider}>? ) { pre { self.isRentingEnabled(): "Renting is not enabled or this listing has expired" @@ -468,7 +468,7 @@ pub contract FlowtyRentals { // suspensionTimeRemaining // returns the amount of time left until a listing can be filled. // - pub fun suspensionTimeRemaining() : Fix64 { + access(all) suspensionTimeRemaining() : Fix64 { let listedTime = self.details.listedTime let currentTime = getCurrentBlock().timestamp @@ -480,7 +480,7 @@ pub contract FlowtyRentals { // remainingTimeToRent // returns the amount of time left until this listing is no longer valid // - pub fun remainingTimeToRent(): Fix64 { + access(all) remainingTimeToRent(): Fix64 { let listedTime = self.details.listedTime let currentTime = getCurrentBlock().timestamp let remaining = Fix64(listedTime + self.details.expiresAfter) - Fix64(currentTime) @@ -490,15 +490,15 @@ pub contract FlowtyRentals { // isRentingEnabled // checks if a listing can be rented or not. // - pub fun isRentingEnabled(): Bool { + access(all) isRentingEnabled(): Bool { let timeRemaining = self.suspensionTimeRemaining() let listingTimeRemaining = self.remainingTimeToRent() return timeRemaining < Fix64(0.0) && listingTimeRemaining > Fix64(0.0) } init ( - nftProviderCapability: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, - nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + nftProviderCapability: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.Collection}>, + nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.Collection}>, ownerFungibleTokenReceiver: Capability<&AnyResource{FungibleToken.Receiver}>, nftType: Type, nftID: UInt64, @@ -553,32 +553,32 @@ pub contract FlowtyRentals { // Rental Details // A struct containing a Rental's non-resource data. - pub struct RentalDetails { + access(all) struct RentalDetails { // |-- gathered by an initialized Rental resource --| // The storefront which owns this rental. - pub var flowtyStorefrontID: UInt64 + access(all) var flowtyStorefrontID: UInt64 // The listing being funded - pub var listingResourceID: UInt64 + access(all) var listingResourceID: UInt64 // They type used for payment to obtain the rental. // Tokens taken as a deposit are also made of this type - pub var paymentVaultType: Type + access(all) var paymentVaultType: Type // The number of seconds that this rental is good for. // If the rental is not returned before this time, the deposit can be revoked - pub var term: UFix64 + access(all) var term: UFix64 // The id of the nft that was rented. This is the same as listingDetails.nftID - pub var nftID: UInt64 + access(all) var nftID: UInt64 // The type of the nft that was rented. This is the same as listingDetails.nftType - pub var nftType: Type + access(all) var nftType: Type // |-- The below variables are maintained by our smart contract --| - pub var returned: Bool - pub var settled: Bool + access(all) var returned: Bool + access(all) var settled: Bool // The time this Rental was created - pub var startTime: UFix64 + access(all) var startTime: UFix64 access(contract) fun setToReturned() { self.returned = true @@ -612,28 +612,28 @@ pub contract FlowtyRentals { // RentalPublic // An interface providing a useful public interface to a Rental. // - pub resource interface RentalPublic { + access(all) resource interface RentalPublic { // The entry point method to return a rental. // The same NFT as the one that was rented must be returned. - pub fun returnNFT(nft: @NonFungibleToken.NFT) + access(all) returnNFT(nft: @NonFungibleToken.NFT) // Return the details of this Rental - pub fun getDetails(): RentalDetails + access(all) getDetails(): RentalDetails // Return the listingDetails that were used to create this rental - pub fun getListingDetails(): FlowtyRentals.ListingDetails + access(all) getListingDetails(): FlowtyRentals.ListingDetails // How much time is left until this Rental has expired - pub fun timeRemaining() : Fix64 + access(all) timeRemaining() : Fix64 // Whether this rental has expired and can be settled - pub fun isRentalExpired(): Bool + access(all) isRentalExpired(): Bool } // The resource used to represent a Rental. // A Rental contains the deposit held in exchange for an NFT // If that same NFT is returned, the deposit is released back to the renter. - pub resource Rental: RentalPublic { + access(all) resource Rental: RentalPublic { // The non-resource data of a Rental access(self) let details: RentalDetails @@ -644,7 +644,7 @@ pub contract FlowtyRentals { access(contract) var depositedFungibleTokens: @FungibleToken.Vault? // reference to the original owner of the nft which was rented - access(contract) let ownerNFTCollectionPublic: Capability<&AnyResource{NonFungibleToken.CollectionPublic}> + access(contract) let ownerNFTCollectionPublic: Capability<&AnyResource{NonFungibleToken.Collection}> // reference to pay the original owner in the event that the rented NFT is not returned access(contract) let ownerFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}> @@ -652,10 +652,10 @@ pub contract FlowtyRentals { access(contract) let renterFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}> // Capability used to transfer the rented nft to our renter - access(contract) let renterNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}> + access(contract) let renterNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}> // optional capability to automatically return the asset on settlement - access(contract) let renterNFTProvider: Capability<&AnyResource{NonFungibleToken.CollectionPublic, NonFungibleToken.Provider}>? + access(contract) let renterNFTProvider: Capability<&AnyResource{NonFungibleToken.Collection, NonFungibleToken.Provider}>? init ( // Rental details @@ -668,12 +668,12 @@ pub contract FlowtyRentals { listingDetails: ListingDetails, // Rental resource - ownerNFTCollectionPublic: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + ownerNFTCollectionPublic: Capability<&AnyResource{NonFungibleToken.Collection}>, renterFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, ownerFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, depositedFungibleTokens: @FungibleToken.Vault?, - renterNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, - renterNFTProvider: Capability<&AnyResource{NonFungibleToken.CollectionPublic, NonFungibleToken.Provider}>? + renterNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, + renterNFTProvider: Capability<&AnyResource{NonFungibleToken.Collection, NonFungibleToken.Provider}>? ) { self.ownerNFTCollectionPublic = ownerNFTCollectionPublic self.renterFungibleTokenReceiver = renterFungibleTokenReceiver @@ -694,17 +694,17 @@ pub contract FlowtyRentals { ) } - pub fun getDetails(): RentalDetails { + access(all) getDetails(): RentalDetails { return self.details } - pub fun getListingDetails(): ListingDetails { + access(all) getListingDetails(): ListingDetails { return self.listingDetails } // The entry point method to return a rental. // The same NFT as the one that was rented must be returned. - pub fun returnNFT(nft: @NonFungibleToken.NFT) { + access(all) returnNFT(nft: @NonFungibleToken.NFT) { pre { !self.isRentalExpired(): "rental has expired" !self.details.returned: "rental has been returned" @@ -738,7 +738,7 @@ pub contract FlowtyRentals { // If the Renter supplied an optional provider which we can withdraw the NFT with, // Then we will attempt to automatically take the NFT back. If this is possible, the deposit will // be returned to the renter. - pub fun settleRental() { + access(all) settleRental() { pre { self.isRentalExpired(): "rental hasn't expired" self.details.returned == false: "rental has already been returned" @@ -843,7 +843,7 @@ pub contract FlowtyRentals { } // how much time is left to return this rental - pub fun timeRemaining() : Fix64 { + access(all) timeRemaining() : Fix64 { let rentalTerm = self.details.term let startTime = self.details.startTime let currentTime = getCurrentBlock().timestamp @@ -851,7 +851,7 @@ pub contract FlowtyRentals { return remaining } - pub fun isRentalExpired() : Bool { + access(all) isRentalExpired() : Bool { return self.timeRemaining() < Fix64(0.0) } } @@ -859,7 +859,7 @@ pub contract FlowtyRentals { // FlowtyRentalsMarketplaceManager // An interface for adding and removing rental resources within a FlowtyRentalsMarketplace, // - pub resource interface FlowtyRentalsMarketplaceManager { + access(all) resource interface FlowtyRentalsMarketplaceManager { // createFunding // Allows the FlowtyRentalsMarketplace owner to create and insert Fundings. // @@ -871,27 +871,27 @@ pub contract FlowtyRentals { paymentVaultType: Type, term: UFix64, listingDetails: ListingDetails, - ownerNFTCollectionPublic: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + ownerNFTCollectionPublic: Capability<&AnyResource{NonFungibleToken.Collection}>, ownerFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, renterFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, depositedFungibleTokens: @FungibleToken.Vault?, - renterNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, - renterNFTProvider: Capability<&AnyResource{NonFungibleToken.CollectionPublic, NonFungibleToken.Provider}>? + renterNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, + renterNFTProvider: Capability<&AnyResource{NonFungibleToken.Collection, NonFungibleToken.Provider}>? ): UInt64 // removeRental // Allows the FlowtyRentalsMarketplace owner to remove any rental resource. // - pub fun removeRental(rentalResourceID: UInt64) + access(all) removeRental(rentalResourceID: UInt64) - pub fun borrowPrivateRental(rentalResourceID: UInt64): &Rental? + access(all) borrowPrivateRental(rentalResourceID: UInt64): &Rental? } - pub resource interface FlowtyRentalsMarketplacePublic { - pub fun getRentalIDs(): [UInt64] - pub fun borrowRental(rentalResourceID: UInt64): &Rental{RentalPublic}? + access(all) resource interface FlowtyRentalsMarketplacePublic { + access(all) getRentalIDs(): [UInt64] + access(all) borrowRental(rentalResourceID: UInt64): &Rental{RentalPublic}? } - pub resource FlowtyRentalsMarketplace: FlowtyRentalsMarketplaceManager, FlowtyRentalsMarketplacePublic { + access(all) resource FlowtyRentalsMarketplace: FlowtyRentalsMarketplaceManager, FlowtyRentalsMarketplacePublic { access(self) var rentals: @{UInt64: Rental} // create a rental and store it on our contract marketplace @@ -903,12 +903,12 @@ pub contract FlowtyRentals { paymentVaultType: Type, term: UFix64, listingDetails: ListingDetails, - ownerNFTCollectionPublic: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + ownerNFTCollectionPublic: Capability<&AnyResource{NonFungibleToken.Collection}>, ownerFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, renterFungibleTokenReceiver: Capability<&{FungibleToken.Receiver}>, depositedFungibleTokens: @FungibleToken.Vault?, - renterNFTCollection: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, - renterNFTProvider: Capability<&AnyResource{NonFungibleToken.CollectionPublic, NonFungibleToken.Provider}>? + renterNFTCollection: Capability<&AnyResource{NonFungibleToken.Collection}>, + renterNFTProvider: Capability<&AnyResource{NonFungibleToken.Collection, NonFungibleToken.Provider}>? ): UInt64 { let renter = renterFungibleTokenReceiver.address let owner = ownerNFTCollectionPublic.address @@ -941,7 +941,7 @@ pub contract FlowtyRentals { } // removes a rental from our contract - pub fun removeRental(rentalResourceID: UInt64) { + access(all) removeRental(rentalResourceID: UInt64) { let rental <- self.rentals.remove(key: rentalResourceID) ?? panic("missing Rental") @@ -951,11 +951,11 @@ pub contract FlowtyRentals { destroy rental } - pub fun getRentalIDs(): [UInt64] { + access(all) getRentalIDs(): [UInt64] { return self.rentals.keys } - pub fun borrowRental(rentalResourceID: UInt64): &Rental{RentalPublic}? { + access(all) borrowRental(rentalResourceID: UInt64): &Rental{RentalPublic}? { if self.rentals[rentalResourceID] != nil { return &self.rentals[rentalResourceID] as &Rental{RentalPublic}? } else { @@ -963,7 +963,7 @@ pub contract FlowtyRentals { } } - pub fun borrowPrivateRental(rentalResourceID: UInt64): &Rental? { + access(all) borrowPrivateRental(rentalResourceID: UInt64): &Rental? { if self.rentals[rentalResourceID] != nil { return &self.rentals[rentalResourceID] as &Rental? } else { @@ -986,10 +986,10 @@ pub contract FlowtyRentals { } } - pub resource interface FlowtyRentalsStorefrontManager { - pub fun createListing( - nftProviderCapability: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, - nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + access(all) resource interface FlowtyRentalsStorefrontManager { + access(all) createListing( + nftProviderCapability: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.Collection}>, + nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.Collection}>, ownerFungibleTokenReceiver: Capability<&AnyResource{FungibleToken.Receiver}>, nftType: Type, nftID: UInt64, @@ -1002,25 +1002,25 @@ pub contract FlowtyRentals { renter: Address? ): UInt64 - pub fun removeListing(listingResourceID: UInt64) + access(all) removeListing(listingResourceID: UInt64) } - pub resource interface FlowtyRentalsStorefrontPublic { - pub fun getListingIDs(): [UInt64] - pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? - pub fun cleanup(listingResourceID: UInt64) + access(all) resource interface FlowtyRentalsStorefrontPublic { + access(all) getListingIDs(): [UInt64] + access(all) borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? + access(all) cleanup(listingResourceID: UInt64) } // FlowtyRentalsStorefront - The storefront which stores listing and provides functionality to fill them // A listing records the an nftid and type, a fee and deposit, and an optional address. - pub resource FlowtyRentalsStorefront : FlowtyRentalsStorefrontManager, FlowtyRentalsStorefrontPublic { + access(all) resource FlowtyRentalsStorefront : FlowtyRentalsStorefrontManager, FlowtyRentalsStorefrontPublic { access(self) var listings: @{UInt64: Listing} // create a new listing. Takes in a provider to withdraw the listed nft, and details // about the terms of the rental and ways to send out payment - pub fun createListing( - nftProviderCapability: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, - nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.CollectionPublic}>, + access(all) createListing( + nftProviderCapability: Capability<&AnyResource{NonFungibleToken.Provider, NonFungibleToken.Collection}>, + nftPublicCollectionCapability: Capability<&AnyResource{NonFungibleToken.Collection}>, ownerFungibleTokenReceiver: Capability<&AnyResource{FungibleToken.Receiver}>, nftType: Type, nftID: UInt64, @@ -1082,18 +1082,18 @@ pub contract FlowtyRentals { return listingResourceID } - pub fun removeListing(listingResourceID: UInt64) { + access(all) removeListing(listingResourceID: UInt64) { let listing <- self.listings.remove(key: listingResourceID) ?? panic("missing Listing") destroy listing } - pub fun getListingIDs(): [UInt64] { + access(all) getListingIDs(): [UInt64] { return self.listings.keys } - pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? { + access(all) borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? { if self.listings[listingResourceID] != nil { return &self.listings[listingResourceID] as &Listing{ListingPublic}? } else { @@ -1101,7 +1101,7 @@ pub contract FlowtyRentals { } } - pub fun cleanup(listingResourceID: UInt64) { + access(all) cleanup(listingResourceID: UInt64) { pre { self.listings[listingResourceID] != nil: "could not find listing with given id" } @@ -1126,8 +1126,8 @@ pub contract FlowtyRentals { } } - pub resource FlowtyAdmin { - pub fun setFees(fee: UFix64) { + access(all) resource FlowtyAdmin { + access(all) setFees(fee: UFix64) { pre { fee <= 1.0: "rental is a percentage" } @@ -1136,16 +1136,16 @@ pub contract FlowtyRentals { } } - pub fun createStorefront(): @FlowtyRentalsStorefront { + access(all) createStorefront(): @FlowtyRentalsStorefront { return <-create FlowtyRentalsStorefront() } access(account) fun borrowMarketplace(): &FlowtyRentals.FlowtyRentalsMarketplace { - return self.account.borrow<&FlowtyRentals.FlowtyRentalsMarketplace>(from: FlowtyRentals.FlowtyRentalsMarketplaceStoragePath)! + return self.account.storage.borrow<&FlowtyRentals.FlowtyRentalsMarketplace>(from: FlowtyRentals.FlowtyRentalsMarketplaceStoragePath)! } - pub resource FlowtyRentalsAdmin { - pub fun setFees(rentalFee: UFix64) { + access(all) resource FlowtyRentalsAdmin { + access(all) setFees(rentalFee: UFix64) { pre { rentalFee <= 1.0: "Funding fee should be a percentage" } @@ -1153,7 +1153,7 @@ pub contract FlowtyRentals { FlowtyRentals.Fee = rentalFee } - pub fun setSuspendedFundingPeriod(period: UFix64) { + access(all) setSuspendedFundingPeriod(period: UFix64) { FlowtyRentals.SuspendedFundingPeriod = period } } @@ -1170,13 +1170,13 @@ pub contract FlowtyRentals { let marketplace <- create FlowtyRentalsMarketplace() - self.account.save(<-marketplace, to: self.FlowtyRentalsMarketplaceStoragePath) + self.account.storage.save(<-marketplace, to: self.FlowtyRentalsMarketplaceStoragePath) self.account.link<&FlowtyRentals.FlowtyRentalsMarketplace{FlowtyRentals.FlowtyRentalsMarketplacePublic}>(FlowtyRentals.FlowtyRentalsMarketplacePublicPath, target: FlowtyRentals.FlowtyRentalsMarketplaceStoragePath) // FlowtyAdmin let flowtyAdmin <- create FlowtyRentalsAdmin() - self.account.save(<-flowtyAdmin, to: self.FlowtyRentalsAdminStoragePath) + self.account.storage.save(<-flowtyAdmin, to: self.FlowtyRentalsAdminStoragePath) emit FlowtyRentalsInitialized() } -} \ No newline at end of file +} diff --git a/contracts/community/FlowtyUtils.cdc b/contracts/community/FlowtyUtils.cdc index 86cd88d5..b7bb1f0a 100644 --- a/contracts/community/FlowtyUtils.cdc +++ b/contracts/community/FlowtyUtils.cdc @@ -3,15 +3,15 @@ import NonFungibleToken from "../standard/NonFungibleToken.cdc" import FungibleToken from "../standard/FungibleToken.cdc" import CoatCheck from "./CoatCheck.cdc" -pub contract FlowtyUtils { +access(all) contract FlowtyUtils { access(contract) var Attributes: {String: AnyStruct} - pub let FlowtyUtilsStoragePath: StoragePath + access(all) let FlowtyUtilsStoragePath: StoragePath - pub resource FlowtyUtilsAdmin { + access(all) resource FlowtyUtilsAdmin { // addSupportedTokenType // add a supported token type that can be used in Flowty loans - pub fun addSupportedTokenType(type: Type) { + access(all) addSupportedTokenType(type: Type) { var supportedTokens = FlowtyUtils.Attributes["supportedTokens"] if supportedTokens == nil { supportedTokens = [Type<@FUSD.Vault>()] as! [Type] @@ -27,21 +27,21 @@ pub contract FlowtyUtils { } } - pub fun getSupportedTokens(): AnyStruct { + access(all) getSupportedTokens(): AnyStruct { return self.Attributes["supportedTokens"]! } // getAllowedTokens // return an array of types that are able to be used as the payment type // for loans - pub fun getAllowedTokens(): [Type] { + access(all) getAllowedTokens(): [Type] { var supportedTokens = self.Attributes["supportedTokens"] return supportedTokens != nil ? supportedTokens! as! [Type] : [Type<@FUSD.Vault>()] } // isTokenSupported // check if the given type is able to be used as payment - pub fun isTokenSupported(type: Type): Bool { + access(all) isTokenSupported(type: Type): Bool { for t in FlowtyUtils.getAllowedTokens() { if t == type { return true @@ -63,7 +63,7 @@ pub contract FlowtyUtils { } } - access(account) fun trySendNFT(nft: @NonFungibleToken.NFT, receiver: Capability<&{NonFungibleToken.CollectionPublic}>) { + access(account) fun trySendNFT(nft: @NonFungibleToken.NFT, receiver: Capability<&{NonFungibleToken.Collection}>) { let redeemer = receiver.address if !receiver.check() { let valet = CoatCheck.getValet() @@ -82,6 +82,6 @@ pub contract FlowtyUtils { self.FlowtyUtilsStoragePath = /storage/FlowtyUtils let utilsAdmin <- create FlowtyUtilsAdmin() - self.account.save(<-utilsAdmin, to: self.FlowtyUtilsStoragePath) + self.account.storage.save(<-utilsAdmin, to: self.FlowtyUtilsStoragePath) } -} \ No newline at end of file +} diff --git a/contracts/community/PublicPriceOracle.cdc b/contracts/community/PublicPriceOracle.cdc new file mode 100644 index 00000000..93b2ff84 --- /dev/null +++ b/contracts/community/PublicPriceOracle.cdc @@ -0,0 +1,28 @@ +/** + +# This contract provides public oracle data sourced from the multi-node PriceOracle contracts of Increment. + +# Anyone can access price data directly with getLatestPrice() & getLatestBlockHeight(), no whitelist needed. Check example here: https://docs.increment.fi/protocols/decentralized-price-feed-oracle/using-price-feeds + +# Admin controls what PriceOracles are exposed publicly. + +# Author: Increment Labs + +THIS is a local stub for testing +*/ + + +access(all) contract PublicPriceOracle { + + access(all) view fun getLatestPrice(oracleAddr: Address): UFix64 { + return 0.5 + } + + /// Get the block height at the time of the latest update. + /// + access(all) view fun getLatestBlockHeight(oracleAddr: Address): UInt64 { + return getCurrentBlock().height + } + + +} diff --git a/contracts/community/SwapRouter.cdc b/contracts/community/SwapRouter.cdc index fa5f64ea..7637f811 100644 --- a/contracts/community/SwapRouter.cdc +++ b/contracts/community/SwapRouter.cdc @@ -11,14 +11,14 @@ import SwapConfig from 0xddb929038d45d4b3 import SwapError from 0xddb929038d45d4b3 import SwapInterfaces from 0xddb929038d45d4b3 -pub contract SwapRouter { +access(all) contract SwapRouter { /// Perform a chained swap calculation starting with exact amountIn /// /// @Param - amountIn: e.g. 50.0 /// @Param - tokenKeyPath: e.g. [A.f8d6e0586b0a20c7.FUSD, A.f8d6e0586b0a20c7.FlowToken, A.f8d6e0586b0a20c7.USDC] /// @Return - [UFix64]: e.g. [50.0, 10.0, 48.0] /// - pub fun getAmountsOut(amountIn: UFix64, tokenKeyPath: [String]): [UFix64] { + access(all) fun getAmountsOut(amountIn: UFix64, tokenKeyPath: [String]): [UFix64] { pre { tokenKeyPath.length >= 2: SwapError.ErrorEncode(msg: "SwapRouter: Invalid path", err: SwapError.ErrorCode.INVALID_PARAMETERS) } @@ -54,7 +54,7 @@ pub contract SwapRouter { /// Perform a chained swap calculation end with exact amountOut /// - pub fun getAmountsIn(amountOut: UFix64, tokenKeyPath: [String]): [UFix64] { + access(all) fun getAmountsIn(amountOut: UFix64, tokenKeyPath: [String]): [UFix64] { pre { tokenKeyPath.length >= 2: SwapError.ErrorEncode(msg: "SwapRouter: Invalid path", err: SwapError.ErrorCode.INVALID_PARAMETERS) } @@ -99,7 +99,7 @@ pub contract SwapRouter { /// @Param - deadline: The timeout block timestamp for the transaction /// @Return - Vault: outVault /// - pub fun swapExactTokensForTokens( + access(all) fun swapExactTokensForTokens( exactVaultIn: @FungibleToken.Vault, amountOutMin: UFix64, tokenKeyPath: [String], @@ -131,7 +131,7 @@ return <- self.swapWithPath(vaultIn: <-exactVaultIn, tokenKeyPath: tokenKeyPath, /// @Param - deadline: The timeout block timestamp for the transaction /// @Return - [OutVault, RemainingInVault] /// - pub fun swapTokensForExactTokens( + access(all) fun swapTokensForExactTokens( vaultInMax: @FungibleToken.Vault, exactAmountOut: UFix64, tokenKeyPath: [String], @@ -158,7 +158,7 @@ return <-[<-self.swapWithPath(vaultIn: <-vaultInExact, tokenKeyPath: tokenKeyPat /// SwapWithPath /// - pub fun swapWithPath(vaultIn: @FungibleToken.Vault, tokenKeyPath: [String], exactAmounts: [UFix64]?): @FungibleToken.Vault { + access(all) fun swapWithPath(vaultIn: @FungibleToken.Vault, tokenKeyPath: [String], exactAmounts: [UFix64]?): @FungibleToken.Vault { pre { tokenKeyPath.length >= 2: SwapError.ErrorEncode(msg: "Invalid path.", err: SwapError.ErrorCode.INVALID_PARAMETERS) } @@ -194,11 +194,11 @@ return <-[<-self.swapWithPath(vaultIn: <-vaultInExact, tokenKeyPath: tokenKeyPat var index = 4 var curVaultOut <- vaultOut4 while(index < tokenKeyPath.length-1) { - var in <- curVaultOut.withdraw(amount: curVaultOut.balance) + var in2 <- curVaultOut.withdraw(amount: curVaultOut.balance) var exactAmountOut: UFix64? = nil if exactAmounts != nil { exactAmountOut = exactAmounts![index+1] } - var out <- self.swapWithPair(vaultIn: <- in, exactAmountOut: exactAmountOut, token0Key: tokenKeyPath[index], token1Key:tokenKeyPath[index+1]) + var out <- self.swapWithPair(vaultIn: <- in2, exactAmountOut: exactAmountOut, token0Key: tokenKeyPath[index], token1Key:tokenKeyPath[index+1]) curVaultOut <-> out destroy out @@ -210,7 +210,7 @@ return <-[<-self.swapWithPath(vaultIn: <-vaultInExact, tokenKeyPath: tokenKeyPat /// SwapWithPair /// - pub fun swapWithPair( + access(all) fun swapWithPair( vaultIn: @FungibleToken.Vault, exactAmountOut: UFix64?, token0Key: String, @@ -221,3 +221,4 @@ return <-[<-self.swapWithPath(vaultIn: <-vaultInExact, tokenKeyPath: tokenKeyPat return <- pairPublicRef.swap(vaultIn: <- vaultIn, exactAmountOut: exactAmountOut) } } + diff --git a/contracts/community/Templates.cdc b/contracts/community/Templates.cdc index fc7d5017..9341038d 100644 --- a/contracts/community/Templates.cdc +++ b/contracts/community/Templates.cdc @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT -import MetadataViews from "../standard/MetadataViews.cdc" -import FungibleToken from "../standard/FungibleToken.cdc" +import "MetadataViews" +import "FungibleToken" // This contracts stores all the defined interfaces and structs. // Interfaces can span on both Characters and Wearables therefore it is better to have them in a central contract -pub contract Templates { +access(all) contract Templates { access(contract) let counters : {String : UInt64} access(contract) let features : {String : Bool} - pub event CountersReset() + access(all) event CountersReset() access(account) fun createEditionInfoManually(name: String, counter:String, edition:UInt64?) : EditionInfo { let oldMax=Templates.counters[counter] ?? 0 @@ -27,15 +27,15 @@ pub contract Templates { return EditionInfo(counter: counter, name:name, number:max) } - pub struct interface Editionable { + access(all) struct interface Editionable { - pub fun getCounterSuffix() : String + access(all) getCounterSuffix() : String // e.g. set , position - pub fun getClassifier() : String + access(all) getClassifier() : String // e.g. character, wearable - pub fun getContract() : String + access(all) getContract() : String - pub fun getCounter() : String { + access(all) getCounter() : String { return self.getContract().concat("_").concat(self.getClassifier()).concat("_").concat(self.getCounterSuffix()) } @@ -43,19 +43,19 @@ pub contract Templates { return Templates.createEditionInfoManually(name:self.getClassifier(), counter:self.getCounter(), edition:edition) } - pub fun getCurrentCount() : UInt64 { + access(all) getCurrentCount() : UInt64 { return Templates.counters[self.getCounter()] ?? 0 } } - pub struct interface Retirable{ + access(all) struct interface Retirable{ - pub var active:Bool + access(all) var active:Bool - pub fun getCounterSuffix() : String - pub fun getClassifier() : String - pub fun getContract() : String + access(all) getCounterSuffix() : String + access(all) getClassifier() : String + access(all) getContract() : String access(account) fun enable(_ bool : Bool) { pre{ @@ -65,10 +65,10 @@ pub contract Templates { } } - pub struct interface RoyaltyHolder { - pub let royalties: [Templates.Royalty] + access(all) struct interface RoyaltyHolder { + access(all) let royalties: [Templates.Royalty] - pub fun getRoyalties() : [MetadataViews.Royalty] { + access(all) getRoyalties() : [MetadataViews.Royalty] { let royalty : [MetadataViews.Royalty] = [] for r in self.royalties { royalty.append(r.getRoyalty()) @@ -77,10 +77,10 @@ pub contract Templates { } } - pub struct EditionInfo { - pub let counter :String - pub let name : String - pub let number:UInt64 + access(all) struct EditionInfo { + access(all) let counter :String + access(all) let name : String + access(all) let number:UInt64 init(counter: String, name:String, number:UInt64) { self.counter=counter @@ -88,11 +88,11 @@ pub contract Templates { self.number=number } - pub fun getSupply() : UInt64 { + access(all) getSupply() : UInt64 { return Templates.counters[self.counter] ?? 0 } - pub fun getAsMetadataEdition(_ active:Bool) : MetadataViews.Edition { + access(all) getAsMetadataEdition(_ active:Bool) : MetadataViews.Edition { var max : UInt64?=nil if !active { max=Templates.counters[self.counter] @@ -100,18 +100,18 @@ pub contract Templates { return MetadataViews.Edition(name:self.name, number:self.number, max:max) } - pub fun getMaxEdition() : UInt64 { + access(all) getMaxEdition() : UInt64 { return Templates.counters[self.counter]! } } - pub struct Royalty { - pub let name : String - pub let address: Address - pub let cut: UFix64 - pub let description: String - pub let publicPath: String + access(all) struct Royalty { + access(all) let name : String + access(all) let address: Address + access(all) let cut: UFix64 + access(all) let description: String + access(all) let publicPath: String init(name : String , address: Address , cut: UFix64 , description: String , publicPath: String) { self.name = name @@ -121,22 +121,22 @@ pub contract Templates { self.publicPath = publicPath } - pub fun getPublicPath() : PublicPath { + access(all) getPublicPath() : PublicPath { return PublicPath(identifier: self.publicPath)! } - pub fun getRoyalty() : MetadataViews.Royalty { + access(all) getRoyalty() : MetadataViews.Royalty { let cap = getAccount(self.address).getCapability<&{FungibleToken.Receiver}>(self.getPublicPath()) return MetadataViews.Royalty(receiver: cap, cut: self.cut, description: self.name) } } - pub fun featureEnabled(_ action: String) : Bool { + access(all) featureEnabled(_ action: String) : Bool { return self.features[action] ?? false } - pub fun assertFeatureEnabled(_ action: String) { + access(all) assertFeatureEnabled(_ action: String) { if !Templates.featureEnabled(action) { panic("Action cannot be taken, feature is not enabled : ".concat(action)) } diff --git a/contracts/community/TopShot.cdc b/contracts/community/TopShot.cdc index 548540ee..78d155dd 100644 --- a/contracts/community/TopShot.cdc +++ b/contracts/community/TopShot.cdc @@ -1,32 +1,32 @@ -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import MetadataViews from "../standard/MetadataViews.cdc" +import "NonFungibleToken" +import "MetadataViews" -pub contract TopShot: NonFungibleToken { +access(all) contract TopShot: NonFungibleToken { // Emitted when the TopShot contract is created - pub event ContractInitialized() + access(all) event ContractInitialized() // // Emitted when a moment is withdrawn from a Collection - pub event Withdraw(id: UInt64, from: Address?) + access(all) event Withdraw(id: UInt64, from: Address?) // Emitted when a moment is deposited into a Collection - pub event Deposit(id: UInt64, to: Address?) - pub var totalSupply: UInt64 + access(all) event Deposit(id: UInt64, to: Address?) + access(all) var totalSupply: UInt64 // The resource that represents the Moment NFTs // - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { + access(all) resource NFT: NonFungibleToken.INFT, ViewResolver.Resolver { // Global unique moment ID - pub let id: UInt64 + access(all) let id: UInt64 init() { self.id = self.uuid } // All supported metadata views for the Moment including the Core NFT Views - pub fun getViews(): [Type] { + access(all) getViews(): [Type] { return [ Type(), Type(), @@ -38,7 +38,7 @@ pub contract TopShot: NonFungibleToken { - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) resolveView(_ view: Type): AnyStruct? { switch view { case Type(): return MetadataViews.Display( @@ -60,8 +60,8 @@ pub contract TopShot: NonFungibleToken { publicPath: /public/MomentCollection, providerPath: /private/MomentCollection, publicCollection: Type<&TopShot.Collection{TopShot.MomentCollectionPublic}>(), - publicLinkedType: Type<&TopShot.Collection{TopShot.MomentCollectionPublic,NonFungibleToken.Receiver,NonFungibleToken.CollectionPublic,MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&TopShot.Collection{NonFungibleToken.Provider,TopShot.MomentCollectionPublic,NonFungibleToken.Receiver,NonFungibleToken.CollectionPublic,MetadataViews.ResolverCollection}>(), + publicLinkedType: Type<&TopShot.Collection{TopShot.MomentCollectionPublic,NonFungibleToken.Receiver,NonFungibleToken.Collection,ViewResolver.ResolverCollection}>(), + providerLinkedType: Type<&TopShot.Collection{NonFungibleToken.Provider,TopShot.MomentCollectionPublic,NonFungibleToken.Receiver,NonFungibleToken.Collection,ViewResolver.ResolverCollection}>(), createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { return <-TopShot.createEmptyCollection() }) @@ -97,11 +97,11 @@ pub contract TopShot: NonFungibleToken { } } - pub resource interface MomentCollectionPublic { - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowMoment(id: UInt64): &TopShot.NFT? { + access(all) resource interface MomentCollectionPublic { + access(all) deposit(token: @NonFungibleToken.NFT) + access(all) view fun getIDs(): [UInt64] + access(all) borrowNFT(id: UInt64): &NonFungibleToken.NFT + access(all) borrowMoment(id: UInt64): &TopShot.NFT? { // If the result isn't nil, the id of the returned reference // should be the same as the argument to the function post { @@ -114,10 +114,10 @@ pub contract TopShot: NonFungibleToken { // Collection is a resource that every user who owns NFTs // will store in their account to manage their NFTS // - pub resource Collection: MomentCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { + access(all) resource Collection: MomentCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, ViewResolver.ResolverCollection { // Dictionary of Moment conforming tokens // NFT is a resource type with a UInt64 ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) var ownedNFTs: @{UInt64: NonFungibleToken.NFT} init() { self.ownedNFTs <- {} @@ -129,7 +129,7 @@ pub contract TopShot: NonFungibleToken { // that is to be removed from the Collection // // returns: @NonFungibleToken.NFT the token that was withdrawn - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + access(all) withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { // Borrow nft and check if locked let nft = self.borrowNFT(id: withdrawID) @@ -148,7 +148,7 @@ pub contract TopShot: NonFungibleToken { // // Paramters: token: the NFT to be deposited in the collection // - pub fun deposit(token: @NonFungibleToken.NFT) { + access(all) deposit(token: @NonFungibleToken.NFT) { // Cast the deposited token as a TopShot NFT to make sure // it is the correct type @@ -171,7 +171,7 @@ pub contract TopShot: NonFungibleToken { } // getIDs returns an array of the IDs that are in the Collection - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } @@ -186,7 +186,7 @@ pub contract TopShot: NonFungibleToken { // not any topshot specific data. Please use borrowMoment to // read Moment data. // - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { + access(all) borrowNFT(id: UInt64): &NonFungibleToken.NFT { return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! } @@ -200,19 +200,19 @@ pub contract TopShot: NonFungibleToken { // Parameters: id: The ID of the NFT to get the reference for // // Returns: A reference to the NFT - pub fun borrowMoment(id: UInt64): &TopShot.NFT? { + access(all) borrowMoment(id: UInt64): &TopShot.NFT? { if self.ownedNFTs[id] != nil { - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) return ref as! &TopShot.NFT } else { return nil } } - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + access(all) borrowViewResolver(id: UInt64): &AnyResource{ViewResolver.Resolver} { + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) let topShotNFT = nft as! &TopShot.NFT - return topShotNFT as &AnyResource{MetadataViews.Resolver} + return topShotNFT as &AnyResource{ViewResolver.Resolver} } // If a transaction destroys the Collection object, @@ -225,7 +225,7 @@ pub contract TopShot: NonFungibleToken { } } - pub fun createEmptyCollection() : @NonFungibleToken.Collection { + access(all) createEmptyCollection() : @NonFungibleToken.Collection { return <- create Collection() } @@ -234,7 +234,7 @@ pub contract TopShot: NonFungibleToken { self.totalSupply = 0 // Put a new Collection in storage - self.account.save<@Collection>(<- create Collection(), to: /storage/MomentCollection) + self.account.storage.save<@Collection>(<- create Collection(), to: /storage/MomentCollection) // Create a public capability for the Collection self.account.link<&{MomentCollectionPublic}>(/public/MomentCollection, target: /storage/MomentCollection) diff --git a/contracts/community/Wearables.cdc b/contracts/community/Wearables.cdc index 6df30f9d..62dd5e23 100644 --- a/contracts/community/Wearables.cdc +++ b/contracts/community/Wearables.cdc @@ -6,50 +6,50 @@ Welcome to the Wearables contract for Doodles2 A wearable is an equipment that can be equipped to a Doodle2 */ -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import FungibleToken from "../standard/FungibleToken.cdc" -import MetadataViews from "../standard/MetadataViews.cdc" -import Templates from "./Templates.cdc" -import FindUtils from "../FindUtils.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "Templates" +import "FindUtils" -pub contract Wearables: NonFungibleToken { +access(all) contract Wearables: NonFungibleToken { //Holds the total supply of wearables ever minted - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 - pub event ContractInitialized() + access(all) event ContractInitialized() //emitted when a NFT is withdrawn as defined in the NFT standard - pub event Withdraw(id: UInt64, from: Address?) + access(all) event Withdraw(id: UInt64, from: Address?) //emitted when a NFT is deposited as defined in the NFT standard - pub event Deposit(id: UInt64, to: Address?) + access(all) event Deposit(id: UInt64, to: Address?) //emitted when an Wearable is minted either as part of dooplication or later as part of batch minting, note that context and its fields will vary according to when/how it was minted - pub event Minted(id:UInt64, address:Address, name: String, thumbnail:String, set: String, position: String, template: String, tags:[String], templateId:UInt64, context: {String : String}) + access(all) event Minted(id:UInt64, address:Address, name: String, thumbnail:String, set: String, position: String, template: String, tags:[String], templateId:UInt64, context: {String : String}) //standard paths in the nft metadata standard - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - pub let CollectionPrivatePath: PrivatePath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + access(all) let CollectionPrivatePath: PrivatePath // SETS // sets is a registry that is stored in the contract for ease of reuse and also to be able to count the mints of a set an retire it - pub event SetRegistered(id:UInt64, name:String) - pub event SetRetired(id:UInt64) + access(all) event SetRegistered(id:UInt64, name:String) + access(all) event SetRetired(id:UInt64) //a registry of sets to group Wearables - pub let sets: {UInt64 : Set} + access(all) let sets: {UInt64 : Set} //the definition of a set, a data structure that is Retriable and Editionable - pub struct Set : Templates.Retirable, Templates.Editionable, Templates.RoyaltyHolder { - pub let id:UInt64 - pub let name: String - pub var active:Bool - pub let royalties: [Templates.Royalty] - pub let creator : String + access(all) struct Set : Templates.Retirable, Templates.Editionable, Templates.RoyaltyHolder { + access(all) let id:UInt64 + access(all) let name: String + access(all) var active:Bool + access(all) let royalties: [Templates.Royalty] + access(all) let creator : String access(self) let extra: {String : AnyStruct} init(id:UInt64, name:String, creator: String, royalties: [Templates.Royalty]) { @@ -61,20 +61,20 @@ pub contract Wearables: NonFungibleToken { self.extra={} } - pub fun getCreator() : String { + access(all) getCreator() : String { return self.creator } - pub fun getClassifier() : String{ + access(all) getClassifier() : String{ return "set" } - pub fun getCounterSuffix() : String { + access(all) getCounterSuffix() : String { return self.name } - pub fun getContract() : String { + access(all) getContract() : String { return "wearable" } } @@ -98,17 +98,17 @@ pub contract Wearables: NonFungibleToken { // POSITION // a concept that tells where on a Doodle2 a wearable can be equipped. - pub event PositionRegistered(id:UInt64, name:String, classifiers:[String]) - pub event PositionRetired(id:UInt64) + access(all) event PositionRegistered(id:UInt64, name:String, classifiers:[String]) + access(all) event PositionRetired(id:UInt64) - pub let positions: {UInt64 : Position} + access(all) let positions: {UInt64 : Position} //the definition of a position, a data structure that is Retriable and Editionable - pub struct Position : Templates.Retirable, Templates.Editionable{ - pub let id:UInt64 - pub let name: String - pub let classifiers: [String] - pub var active:Bool + access(all) struct Position : Templates.Retirable, Templates.Editionable{ + access(all) let id:UInt64 + access(all) let name: String + access(all) let classifiers: [String] + access(all) var active:Bool access(self) let extra: {String : AnyStruct} init(id:UInt64, name:String) { @@ -119,7 +119,7 @@ pub contract Wearables: NonFungibleToken { self.extra={} } - pub fun getName(_ index: Int) :String { + access(all) getName(_ index: Int) :String { if self.classifiers.length==0 { return self.name } @@ -128,7 +128,7 @@ pub contract Wearables: NonFungibleToken { return self.name.concat("_").concat(classifier) } - pub fun getPositionCount() :Int{ + access(all) getPositionCount() :Int{ let length=self.classifiers.length if length==0 { return 1 @@ -136,15 +136,15 @@ pub contract Wearables: NonFungibleToken { return length } - pub fun getClassifier() :String { + access(all) getClassifier() :String { return "position" } - pub fun getCounterSuffix() : String { + access(all) getCounterSuffix() : String { return self.name } - pub fun getContract() : String { + access(all) getContract() : String { return "wearable" } } @@ -169,24 +169,24 @@ pub contract Wearables: NonFungibleToken { // a template is a preregistered set of values that a Wearable can get when it is minted, it is then copied into the NFT for provenance //these events are there to track changes internally for registers that are needed to make this contract work - pub event TemplateRegistered(id:UInt64, set: UInt64, position: UInt64, name: String, tags:[String]) - pub event TemplateRetired(id:UInt64) + access(all) event TemplateRegistered(id:UInt64, set: UInt64, position: UInt64, name: String, tags:[String]) + access(all) event TemplateRetired(id:UInt64) //a registry of templates that defines how a Wearable can be minted - pub let templates: {UInt64 : Template} + access(all) let templates: {UInt64 : Template} //the definition of a template, a data structure that is Retriable and Editionable - pub struct Template : Templates.Retirable, Templates.Editionable { - pub let id:UInt64 - pub let name: String - pub let set: UInt64 - pub let position: UInt64 - pub let tags: [Tag] - pub let thumbnail: MetadataViews.Media - pub let image: MetadataViews.Media - pub var active: Bool - pub let hidden: Bool - pub let plural: Bool + access(all) struct Template : Templates.Retirable, Templates.Editionable { + access(all) let id:UInt64 + access(all) let name: String + access(all) let set: UInt64 + access(all) let position: UInt64 + access(all) let tags: [Tag] + access(all) let thumbnail: MetadataViews.Media + access(all) let image: MetadataViews.Media + access(all) var active: Bool + access(all) let hidden: Bool + access(all) let plural: Bool access(self) let extra: {String : AnyStruct} init(id:UInt64, set: UInt64, position: UInt64, name: String, tags:[Tag], thumbnail: MetadataViews.Media, image: MetadataViews.Media, hidden: Bool, plural: Bool) { @@ -205,7 +205,7 @@ pub contract Wearables: NonFungibleToken { self.extra={} } - pub fun getTags() : [String] { + access(all) getTags() : [String] { let t : [String] = [] for tag in self.tags { t.append(tag.getCounterSuffix()) @@ -213,48 +213,48 @@ pub contract Wearables: NonFungibleToken { return t } - pub fun getPlural() : Bool { + access(all) getPlural() : Bool { return self.plural } - pub fun getHidden() : Bool { + access(all) getHidden() : Bool { return self.hidden } - pub fun getIdentifier() : String { + access(all) getIdentifier() : String { return self.name } - pub fun getClassifier() :String { + access(all) getClassifier() :String { return "template" } // Trim is not a unique identifier here - pub fun getCounterSuffix() : String { + access(all) getCounterSuffix() : String { return self.name } - pub fun getContract() : String { + access(all) getContract() : String { return "wearable" } - pub fun getPositionName(_ index:Int) : String { + access(all) getPositionName(_ index:Int) : String { return Wearables.positions[self.position]!.getName(index) } - pub fun getPosition() : Wearables.Position { + access(all) getPosition() : Wearables.Position { return Wearables.positions[self.position]! } - pub fun getSetName() : String { + access(all) getSetName() : String { return Wearables.sets[self.set]!.name } - pub fun getSet() : Wearables.Set { + access(all) getSet() : Wearables.Set { return Wearables.sets[self.set]! } - pub fun getRoyalties() : [MetadataViews.Royalty] { + access(all) getRoyalties() : [MetadataViews.Royalty] { return Wearables.sets[self.set]!.getRoyalties() } @@ -272,8 +272,8 @@ pub contract Wearables: NonFungibleToken { } //A tag is a label for a Wearable, they can have many tags associated with them - pub struct Tag : Templates.Editionable { - pub let value : String + access(all) struct Tag : Templates.Editionable { + access(all) let value : String access(self) let extra: {String : AnyStruct} init(value: String) { @@ -281,20 +281,20 @@ pub contract Wearables: NonFungibleToken { self.extra={} } - pub fun getValue() : String { + access(all) getValue() : String { return self.value } - pub fun getCounterSuffix() : String { + access(all) getCounterSuffix() : String { return self.value } // e.g. set , position - pub fun getClassifier() : String { + access(all) getClassifier() : String { return "tag_".concat(self.value) } // e.g. character, wearable - pub fun getContract() : String { + access(all) getContract() : String { return "wearable" } } @@ -322,29 +322,29 @@ pub contract Wearables: NonFungibleToken { // A resource on flow https://developers.flow.com/cadence/language/resources is kind of like a struct just with way stronger semantics and rules around security - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { + access(all) resource NFT: NonFungibleToken.INFT, ViewResolver.Resolver { //the unique id of a NFT, Wearables uses UUID so this id is unique across _all_ resources on flow - pub let id:UInt64 + access(all) let id:UInt64 //The template that this Werable was made as - pub let template: Template + access(all) let template: Template //a list of edition info used to present counters for the various types of data - pub let editions: [Templates.EditionInfo] + access(all) let editions: [Templates.EditionInfo] //stores who has interacted with this wearable, that - pub let interactions: [Pointer] + access(all) let interactions: [Pointer] //internal counter to count how many times a wearable has been deposited. access(account) var nounce:UInt64 //the royalties defined in this werable - pub let royalties: MetadataViews.Royalties + access(all) let royalties: MetadataViews.Royalties - pub let context: { String: String} + access(all) let context: { String: String} //stores extra data in case we need it for later iterations since we cannot add data - pub let extra: {String : AnyStruct} + access(all) let extra: {String : AnyStruct} init( template: Template, @@ -361,11 +361,11 @@ pub contract Wearables: NonFungibleToken { self.editions=editions } - pub fun getContext() : {String:String} { + access(all) getContext() : {String:String} { return self.context } - pub fun getViews(): [Type] { + access(all) getViews(): [Type] { return [ Type(), Type(), @@ -378,22 +378,22 @@ pub contract Wearables: NonFungibleToken { ] } - pub fun getTemplateActive() : Bool { + access(all) getTemplateActive() : Bool { let t = Wearables.templates[self.template.id]! return t.active } - pub fun getPositionActive() : Bool { + access(all) getPositionActive() : Bool { let p = self.template.getPosition() return p.active } - pub fun getSetActive() : Bool { + access(all) getSetActive() : Bool { let s = self.template.getSet() return s.active } - pub fun getActive(_ classifier: String) : Bool { + access(all) getActive(_ classifier: String) : Bool { switch classifier { case "wearable" : @@ -411,7 +411,7 @@ pub contract Wearables: NonFungibleToken { return true } - pub fun getLastInteraction() : Pointer? { + access(all) getLastInteraction() : Pointer? { if self.interactions.length == 0 { return nil } @@ -429,18 +429,18 @@ pub contract Wearables: NonFungibleToken { } //the thumbnail is a png but the image is a SVG, it was decided after deployment that the svg is what we will use for thumbnail and ignore the image - pub fun getThumbnail() : {MetadataViews.File} { + access(all) getThumbnail() : {MetadataViews.File} { let ipfsFile =self.template.image.file as! MetadataViews.IPFSFile let httpFile= MetadataViews.HTTPFile(url:"https://wcnft.mypinata.cloud/ipfs/".concat(ipfsFile.cid)) return httpFile } - pub fun getThumbnailUrl() : String{ + access(all) getThumbnailUrl() : String{ return self.getThumbnail().uri() } - pub fun getName() : String { + access(all) getName() : String { if self.template.tags.length == 0 { return self.template.name } @@ -450,7 +450,7 @@ pub contract Wearables: NonFungibleToken { } - pub fun getDescription() : String { + access(all) getDescription() : String { var plural=self.template.getPlural() var first="This" @@ -464,7 +464,7 @@ pub contract Wearables: NonFungibleToken { } - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) resolveView(_ view: Type): AnyStruct? { let description= self.getDescription() switch view { @@ -496,9 +496,9 @@ pub contract Wearables: NonFungibleToken { return MetadataViews.NFTCollectionData(storagePath: Wearables.CollectionStoragePath, publicPath: Wearables.CollectionPublicPath, providerPath: Wearables.CollectionPrivatePath, - publicCollection: Type<&Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - publicLinkedType: Type<&Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(), + publicCollection: Type<&Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(), + publicLinkedType: Type<&Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(), + providerLinkedType: Type<&Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(), createEmptyCollectionFunction: fun(): @NonFungibleToken.Collection {return <- Wearables.createEmptyCollection()}) case Type() : @@ -523,7 +523,7 @@ pub contract Wearables: NonFungibleToken { self.nounce=self.nounce+1 } - pub fun getAllTraitsMetadata() : [MetadataViews.Trait] { + access(all) getAllTraitsMetadata() : [MetadataViews.Trait] { var rarity : MetadataViews.Rarity? = nil let traits : [MetadataViews.Trait]= [] @@ -596,10 +596,10 @@ pub contract Wearables: NonFungibleToken { } //A metadata for technical information that is not useful as traits - pub struct Metadata { - pub let templateId:UInt64 - pub let setId:UInt64 - pub let positionId:UInt64 + access(all) struct Metadata { + access(all) let templateId:UInt64 + access(all) let setId:UInt64 + access(all) let positionId:UInt64 init(templateId:UInt64, setId:UInt64, positionId:UInt64) { self.templateId=templateId @@ -611,10 +611,10 @@ pub contract Wearables: NonFungibleToken { // POINTER // a struct to store who has interacted with a wearable - pub struct Pointer { - pub let id: UInt64 - pub let characterId: UInt64 - pub let address: Address + access(all) struct Pointer { + access(all) let id: UInt64 + access(all) let characterId: UInt64 + access(all) let address: Address access(self) let extra: {String : AnyStruct} init(id: UInt64 , characterId: UInt64 , address: Address ) { self.id = id @@ -623,7 +623,7 @@ pub contract Wearables: NonFungibleToken { self.extra = {} } - pub fun isNewInteraction(owner: Address, characterId: UInt64) : Bool { + access(all) isNewInteraction(owner: Address, characterId: UInt64) : Bool { return self.address == owner && self.characterId == characterId } } @@ -631,17 +631,17 @@ pub contract Wearables: NonFungibleToken { - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { + access(all) resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, ViewResolver.ResolverCollection { // dictionary of NFT conforming tokens // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} init () { self.ownedNFTs <- {} } // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + access(all) withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) @@ -650,7 +650,7 @@ pub contract Wearables: NonFungibleToken { } // deposit moves an NFT into this collection - pub fun deposit(token: @NonFungibleToken.NFT) { + access(all) deposit(token: @NonFungibleToken.NFT) { let token <- token as! @NFT let id: UInt64 = token.id @@ -665,26 +665,26 @@ pub contract Wearables: NonFungibleToken { } // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } // borrowNFT gets a reference to an NFT in the collection // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { + access(all) borrowNFT(id: UInt64): &NonFungibleToken.NFT { return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! } //a borrow method for the generic view resolver pattern - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + access(all) borrowViewResolver(id: UInt64): &AnyResource{ViewResolver.Resolver} { + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) let wearable = nft as! &NFT return wearable } //This function is here so that other accounts in the doodles ecosystem can borrow it to perform cross-contract interactions. like bumping the equipped counter access(account) fun borrowWearableNFT(id: UInt64) : &Wearables.NFT { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?) let wearable = nft as! &NFT return wearable } @@ -695,7 +695,7 @@ pub contract Wearables: NonFungibleToken { } // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { + access(all) createEmptyCollection(): @NonFungibleToken.Collection { return <- create Collection() } @@ -825,14 +825,14 @@ pub contract Wearables: NonFungibleToken { //Below here are internal resources that is not really relevant to the public //internal struct to use for batch minting that points to a specific wearable - pub struct WearableMintData { - pub let template: UInt64 - pub let setEdition: UInt64 - pub let positionEdition: UInt64 - pub let templateEdition: UInt64 - pub let taggedTemplateEdition: UInt64 - pub let tagEditions: [UInt64] - pub let extra: {String : AnyStruct} + access(all) struct WearableMintData { + access(all) let template: UInt64 + access(all) let setEdition: UInt64 + access(all) let positionEdition: UInt64 + access(all) let templateEdition: UInt64 + access(all) let taggedTemplateEdition: UInt64 + access(all) let tagEditions: [UInt64] + access(all) let extra: {String : AnyStruct} init( template: UInt64, @@ -854,12 +854,12 @@ pub contract Wearables: NonFungibleToken { // This is not in use anymore. Use WearableMintData //cadence does not allow us to remove this - pub struct MintData { - pub let template: UInt64 - pub let setEdition: UInt64 - pub let positionEdition: UInt64 - pub let templateEdition: UInt64 - pub let tagEditions: [UInt64] + access(all) struct MintData { + access(all) let template: UInt64 + access(all) let setEdition: UInt64 + access(all) let positionEdition: UInt64 + access(all) let templateEdition: UInt64 + access(all) let tagEditions: [UInt64] init( ) { @@ -883,12 +883,12 @@ pub contract Wearables: NonFungibleToken { self.CollectionPublicPath = /public/wearables self.CollectionPrivatePath = /private/wearables - self.account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - self.account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + self.account.storage.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) + self.account.link<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPublicPath, target: Wearables.CollectionStoragePath ) - self.account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + self.account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPrivatePath, target: Wearables.CollectionStoragePath ) diff --git a/contracts/community/WearablesDev.cdc b/contracts/community/WearablesDev.cdc index 6c4c6390..6a849814 100644 --- a/contracts/community/WearablesDev.cdc +++ b/contracts/community/WearablesDev.cdc @@ -1,14 +1,14 @@ //This contract is for testing only and should not be deployed elsewhere -import NonFungibleToken from "../standard/NonFungibleToken.cdc" -import MetadataViews from "../standard/MetadataViews.cdc" -import Wearables from "./Wearables.cdc" +import "NonFungibleToken" +import "MetadataViews" +import "Wearables" -pub contract WearablesDev { +access(all) contract WearablesDev { - pub var initiated: Bool + access(all) var initiated: Bool - pub fun mintWearablesForTest(receiver: Address) { + access(all) mintWearablesForTest(receiver: Address) { self.initialize() let account = getAccount(receiver) let wearable= account.getCapability<&Wearables.Collection{NonFungibleToken.Receiver}>(Wearables.CollectionPublicPath).borrow() ?? panic("cannot borrow werable cap") diff --git a/contracts/standard/Burner.cdc b/contracts/standard/Burner.cdc new file mode 100644 index 00000000..fd733ab6 --- /dev/null +++ b/contracts/standard/Burner.cdc @@ -0,0 +1,44 @@ +/// Burner is a contract that can facilitate the destruction of any resource on flow. +/// +/// Contributors +/// - Austin Kline - https://twitter.com/austin_flowty +/// - Deniz Edincik - https://twitter.com/bluesign +/// - Bastian Müller - https://twitter.com/turbolent +access(all) contract Burner { + /// When Crescendo (Cadence 1.0) is released, custom destructors will be removed from cadece. + /// Burnable is an interface meant to replace this lost feature, allowing anyone to add a callback + /// method to ensure they do not destroy something which is not meant to be, + /// or to add logic based on destruction such as tracking the supply of a FT Collection + /// + /// NOTE: The only way to see benefit from this interface + /// is to always use the burn method in this contract. Anyone who owns a resource can always elect **not** + /// to destroy a resource this way + access(all) resource interface Burnable { + access(contract) fun burnCallback() + } + + /// burn is a global method which will destroy any resource it is given. + /// If the provided resource implements the Burnable interface, + /// it will call the burnCallback method and then destroy afterwards. + access(all) fun burn(_ r: @AnyResource) { + if let s <- r as? @{Burnable} { + s.burnCallback() + destroy s + } else if let arr <- r as? @[AnyResource] { + while arr.length > 0 { + let item <- arr.removeFirst() + self.burn(<-item) + } + destroy arr + } else if let dict <- r as? @{HashableStruct: AnyResource} { + let keys = dict.keys + while keys.length > 0 { + let item <- dict.remove(key: keys.removeFirst())! + self.burn(<-item) + } + destroy dict + } else { + destroy r + } + } +} diff --git a/contracts/standard/DapperStorageRent.cdc b/contracts/standard/DapperStorageRent.cdc index 9e566924..281495b4 100644 --- a/contracts/standard/DapperStorageRent.cdc +++ b/contracts/standard/DapperStorageRent.cdc @@ -1,260 +1,260 @@ -import FungibleToken from "./FungibleToken.cdc" -import FlowToken from "./FlowToken.cdc" +import "FungibleToken" +import "FlowToken" /// DapperStorageRent /// Provide a means for accounts storage TopUps. To be used during transaction execution. -pub contract DapperStorageRent { - - pub let DapperStorageRentAdminStoragePath: StoragePath - - /// Threshold of storage required to trigger a refill - access(contract) var StorageRentRefillThreshold: UInt64 - /// List of all refilledAccounts - access(contract) var RefilledAccounts: [Address] - /// Detailed account information of refilled accounts - access(contract) var RefilledAccountInfos: {Address: RefilledAccountInfo} - /// List of all blockedAccounts - access(contract) var BlockedAccounts: [Address] - /// Blocks required between refill attempts - access(contract) var RefillRequiredBlocks: UInt64 - - /// Event emitted when an Admin blocks an address - pub event BlockedAddress(_ address: [Address]) - /// Event emitted when a Refill is successful - pub event Refuelled(_ address: Address) - /// Event emitted when a Refill is not successful - pub event RefilledFailed(address: Address, reason: String) - - /// getStorageRentRefillThreshold - /// Get the current StorageRentRefillThreshold - /// - /// @return UInt64 value of the current StorageRentRefillThreshold value - pub fun getStorageRentRefillThreshold(): UInt64 { - return self.StorageRentRefillThreshold - } - - /// getRefilledAccounts - /// Get the current StorageRentRefillThreshold - /// - /// @return List of refilled Accounts - pub fun getRefilledAccounts(): [Address] { - return self.RefilledAccounts - } - - /// getBlockedAccounts - /// Get the current StorageRentRefillThreshold - /// - /// @return List of blocked accounts - pub fun getBlockedAccounts() : [Address] { - return self.BlockedAccounts - } - - /// getRefilledAccountInfos - /// Get the current StorageRentRefillThreshold - /// - /// @return Address: RefilledAccountInfo mapping - pub fun getRefilledAccountInfos(): {Address: RefilledAccountInfo} { - return self.RefilledAccountInfos - } - - /// getRefillRequiredBlocks - /// Get the current StorageRentRefillThreshold - /// - /// @return UInt64 value of the current RefillRequiredBlocks value - pub fun getRefillRequiredBlocks(): UInt64 { - return self.RefillRequiredBlocks - } - - - pub fun fundedRefill(address: Address, tokens: @FungibleToken.Vault) { - destroy tokens - - /* - let privateForwardingSenderRef = self.account.borrow<&PrivateReceiverForwarder.Sender>(from: PrivateReceiverForwarder.SenderStoragePath)! - privateForwardingSenderRef!.sendPrivateTokens(address,tokens:<-tokens) - */ - } - - - /// tryRefill - /// Attempt to refill an accounts storage capacity if it has dipped below threshold and passes other checks. - /// - /// @param address: Address to attempt a storage refill on - pub fun tryRefill(_ address: Address) { - /* - let REFUEL_AMOUNT = 0.06; - - self.cleanExpiredRefilledAccounts(10) - - // Get the Flow Token reciever of the address - let recipient = getAccount(address) - let receiverRef = recipient.getCapability<&PrivateReceiverForwarder.Forwarder>(PrivateReceiverForwarder.PrivateReceiverPublicPath).borrow() - - // Sliently fail if the receiverRef is nill - if receiverRef == nil || receiverRef!.owner == nil { - emit RefilledFailed(address: address, reason: "Couldn't borrow the Accounts flowTokenVault") - return +access(all) contract DapperStorageRent { + + access(all) let DapperStorageRentAdminStoragePath: StoragePath + + /// Threshold of storage required to trigger a refill + access(contract) var StorageRentRefillThreshold: UInt64 + /// List of all refilledAccounts + access(contract) var RefilledAccounts: [Address] + /// Detailed account information of refilled accounts + access(contract) var RefilledAccountInfos: {Address: RefilledAccountInfo} + /// List of all blockedAccounts + access(contract) var BlockedAccounts: [Address] + /// Blocks required between refill attempts + access(contract) var RefillRequiredBlocks: UInt64 + + /// Event emitted when an Admin blocks an address + access(all) event BlockedAddress(_ address: [Address]) + /// Event emitted when a Refill is successful + access(all) event Refuelled(_ address: Address) + /// Event emitted when a Refill is not successful + access(all) event RefilledFailed(address: Address, reason: String) + + /// getStorageRentRefillThreshold + /// Get the current StorageRentRefillThreshold + /// + /// @return UInt64 value of the current StorageRentRefillThreshold value + access(all) fun getStorageRentRefillThreshold(): UInt64 { + return self.StorageRentRefillThreshold } - // Sliently fail if the account has already be refueled within the block allowance - if self.RefilledAccountInfos[address] != nil && getCurrentBlock().height - self.RefilledAccountInfos[address]!.atBlock < self.RefillRequiredBlocks { - emit RefilledFailed(address: address, reason: "RefillRequiredBlocks") - return + /// getRefilledAccounts + /// Get the current StorageRentRefillThreshold + /// + /// @return List of refilled Accounts + access(all) fun getRefilledAccounts(): [Address] { + return self.RefilledAccounts } - // Get the users storage capacity and usage values - var low: UInt64 = recipient.storageUsed - var high: UInt64 = recipient.storageCapacity - - if high < low { - high <-> low + /// getBlockedAccounts + /// Get the current StorageRentRefillThreshold + /// + /// @return List of blocked accounts + access(all) fun getBlockedAccounts() : [Address] { + return self.BlockedAccounts } - // Sliently fail if the account has been blocked from receiving refills - if DapperStorageRent.getBlockedAccounts().contains(address) { - emit RefilledFailed(address: address, reason: "Address is Blocked") - return + /// getRefilledAccountInfos + /// Get the current StorageRentRefillThreshold + /// + /// @return Address: RefilledAccountInfo mapping + access(all) fun getRefilledAccountInfos(): {Address: RefilledAccountInfo} { + return self.RefilledAccountInfos } - // If the user is below the threshold PrivateReceiverForwarder will send 0.06 Flow tokens for about 6MB of storage - if high - low < self.StorageRentRefillThreshold { - let vaultRef = self.account.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) - if vaultRef == nil { - emit RefilledFailed(address: address, reason: "Couldn't borrow the Accounts FlowToken.Vault") - return - } - - let privateForwardingSenderRef = self.account.borrow<&PrivateReceiverForwarder.Sender>(from: PrivateReceiverForwarder.SenderStoragePath) - if privateForwardingSenderRef == nil { - emit RefilledFailed(address: address, reason: "Couldn't borrow the Accounts PrivateReceiverForwarder") - return - } - - // Check to make sure the payment vault has sufficient funds - if let vaultBalanceRef = self.account.getCapability(/public/flowTokenBalance).borrow<&FlowToken.Vault{FungibleToken.Balance}>() { - if vaultBalanceRef.balance <= REFUEL_AMOUNT { - emit RefilledFailed(address: address, reason: "Insufficient balance to refuel") - return - } - } else { - emit RefilledFailed(address: address, reason: "Couldn't borrow flowToken balance") - return - } - - // 0.06 = 6MB of storage, or ~20k NBA TS moments - privateForwardingSenderRef!.sendPrivateTokens(address,tokens:<-vaultRef!.withdraw(amount: REFUEL_AMOUNT)) - self.addRefilledAccount(address) - emit Refuelled(address) - } else { - emit RefilledFailed(address: address, reason: "Address is not below StorageRentRefillThreshold") - } - */ - } - - /// checkEligibility - /// - /// @param address: Address to check eligibility on - /// @return Boolean valued based on if the provided address is below the storage threshold - pub fun checkEligibility(_ address: Address): Bool { - if self.RefilledAccountInfos[address] != nil && getCurrentBlock().height - self.RefilledAccountInfos[address]!.atBlock < self.RefillRequiredBlocks { - return false - } - let acct = getAccount(address) - var high: UInt64 = acct.storageCapacity - var low: UInt64 = acct.storageUsed - if high < low { - high <-> low + /// getRefillRequiredBlocks + /// Get the current StorageRentRefillThreshold + /// + /// @return UInt64 value of the current RefillRequiredBlocks value + access(all) fun getRefillRequiredBlocks(): UInt64 { + return self.RefillRequiredBlocks } - if high - low >= self.StorageRentRefillThreshold { - return false - } - return true - } + access(all) fun fundedRefill(address: Address, tokens: @{FungibleToken.Vault}) { + destroy tokens - /// addRefilledAccount - /// - /// @param address: Address to add to RefilledAccounts/RefilledAccountInfos - access(contract) fun addRefilledAccount(_ address: Address) { - if self.RefilledAccountInfos[address] != nil { - self.RefilledAccounts.remove(at: self.RefilledAccountInfos[address]!.index) + /* + let privateForwardingSenderRef = self.account.storage.borrow<&PrivateReceiverForwarder.Sender>(from: PrivateReceiverForwarder.SenderStoragePath)! + privateForwardingSenderRef!.sendPrivateTokens(address,tokens:<-tokens) + */ } - self.RefilledAccounts.append(address) - self.RefilledAccountInfos[address] = RefilledAccountInfo(self.RefilledAccounts.length-1, getCurrentBlock().height) - } - - /// cleanExpiredRefilledAccounts - /// public method to clean up expired accounts based on current block height - /// - /// @param batchSize: Int to set the batch size of the cleanup - pub fun cleanExpiredRefilledAccounts(_ batchSize: Int) { - var index = 0 - while index < batchSize && self.RefilledAccounts.length > index { - if self.RefilledAccountInfos[self.RefilledAccounts[index]] != nil && - getCurrentBlock().height - self.RefilledAccountInfos[self.RefilledAccounts[index]]!.atBlock < self.RefillRequiredBlocks { - break - } - - self.RefilledAccountInfos.remove(key: self.RefilledAccounts[index]) - self.RefilledAccounts.remove(at: index) - index = index + 1 + + /// tryRefill + /// Attempt to refill an accounts storage capacity if it has dipped below threshold and passes other checks. + /// + /// @param address: Address to attempt a storage refill on + access(all) fun tryRefill(_ address: Address) { + /* + let REFUEL_AMOUNT = 0.06; + + self.cleanExpiredRefilledAccounts(10) + + // Get the Flow Token reciever of the address + let recipient = getAccount(address) + let receiverRef = recipient.getCapability<&PrivateReceiverForwarder.Forwarder>(PrivateReceiverForwarder.PrivateReceiverPublicPath).borrow() + + // Sliently fail if the receiverRef is nill + if receiverRef == nil || receiverRef!.owner == nil { + emit RefilledFailed(address: address, reason: "Couldn't borrow the Accounts flowTokenVault") + return + } + + // Sliently fail if the account has already be refueled within the block allowance + if self.RefilledAccountInfos[address] != nil && getCurrentBlock().height - self.RefilledAccountInfos[address]!.atBlock < self.RefillRequiredBlocks { + emit RefilledFailed(address: address, reason: "RefillRequiredBlocks") + return + } + + // Get the users storage capacity and usage values + var low: UInt64 = recipient.storageUsed + var high: UInt64 = recipient.storageCapacity + + if high < low { + high <-> low + } + + // Sliently fail if the account has been blocked from receiving refills + if DapperStorageRent.getBlockedAccounts().contains(address) { + emit RefilledFailed(address: address, reason: "Address is Blocked") + return + } + + // If the user is below the threshold PrivateReceiverForwarder will send 0.06 Flow tokens for about 6MB of storage + if high - low < self.StorageRentRefillThreshold { + let vaultRef = self.account.storage.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) + if vaultRef == nil { + emit RefilledFailed(address: address, reason: "Couldn't borrow the Accounts FlowToken.Vault") + return + } + + let privateForwardingSenderRef = self.account.storage.borrow<&PrivateReceiverForwarder.Sender>(from: PrivateReceiverForwarder.SenderStoragePath) + if privateForwardingSenderRef == nil { + emit RefilledFailed(address: address, reason: "Couldn't borrow the Accounts PrivateReceiverForwarder") + return + } + + // Check to make sure the payment vault has sufficient funds + if let vaultBalanceRef = self.account.getCapability(/public/flowTokenBalance).borrow<&FlowToken.Vault{FungibleToken.Balance}>() { + if vaultBalanceRef.balance <= REFUEL_AMOUNT { + emit RefilledFailed(address: address, reason: "Insufficient balance to refuel") + return + } + } else { + emit RefilledFailed(address: address, reason: "Couldn't borrow flowToken balance") + return + } + + // 0.06 = 6MB of storage, or ~20k NBA TS moments + privateForwardingSenderRef!.sendPrivateTokens(address,tokens:<-vaultRef!.withdraw(amount: REFUEL_AMOUNT)) + self.addRefilledAccount(address) + emit Refuelled(address) + } else { + emit RefilledFailed(address: address, reason: "Address is not below StorageRentRefillThreshold") + } + */ } - } - /// RefilledAccountInfo struct - /// Holds the block number it was refilled at - pub struct RefilledAccountInfo { - pub let atBlock: UInt64 - pub let index: Int + /// checkEligibility + /// + /// @param address: Address to check eligibility on + /// @return Boolean valued based on if the provided address is below the storage threshold + access(all) fun checkEligibility(_ address: Address): Bool { + if self.RefilledAccountInfos[address] != nil && getCurrentBlock().height - self.RefilledAccountInfos[address]!.atBlock < self.RefillRequiredBlocks { + return false + } + let acct = getAccount(address) + var high: UInt64 = acct.storage.capacity + var low: UInt64 = acct.storage.used + if high < low { + high <-> low + } + + if high - low >= self.StorageRentRefillThreshold { + return false + } - init(_ index: Int, _ atBlock: UInt64) { - self.index = index - self.atBlock = atBlock + return true } - } - /// Admin resource - /// Used to set different configuration levers such as StorageRentRefillThreshold, RefillRequiredBlocks, and BlockedAccounts - pub resource Admin { - pub fun setStorageRentRefillThreshold(_ threshold: UInt64) { - DapperStorageRent.StorageRentRefillThreshold = threshold + /// addRefilledAccount + /// + /// @param address: Address to add to RefilledAccounts/RefilledAccountInfos + access(contract) fun addRefilledAccount(_ address: Address) { + if self.RefilledAccountInfos[address] != nil { + self.RefilledAccounts.remove(at: self.RefilledAccountInfos[address]!.index) + } + + self.RefilledAccounts.append(address) + self.RefilledAccountInfos[address] = RefilledAccountInfo(self.RefilledAccounts.length-1, getCurrentBlock().height) } - pub fun setRefillRequiredBlocks(_ blocks: UInt64) { - DapperStorageRent.RefillRequiredBlocks = blocks + /// cleanExpiredRefilledAccounts + /// public method to clean up expired accounts based on current block height + /// + /// @param batchSize: Int to set the batch size of the cleanup + access(all) fun cleanExpiredRefilledAccounts(_ batchSize: Int) { + var index = 0 + while index < batchSize && self.RefilledAccounts.length > index { + if self.RefilledAccountInfos[self.RefilledAccounts[index]] != nil && + getCurrentBlock().height - self.RefilledAccountInfos[self.RefilledAccounts[index]]!.atBlock < self.RefillRequiredBlocks { + break + } + + self.RefilledAccountInfos.remove(key: self.RefilledAccounts[index]) + self.RefilledAccounts.remove(at: index) + index = index + 1 + } } - pub fun blockAddress(_ address: Address) { - if !DapperStorageRent.getBlockedAccounts().contains(address) { - DapperStorageRent.BlockedAccounts.append(address) - emit BlockedAddress(DapperStorageRent.getBlockedAccounts()) + /// RefilledAccountInfo struct + /// Holds the block number it was refilled at + access(all) struct RefilledAccountInfo { + access(all) let atBlock: UInt64 + access(all) let index: Int + + init(_ index: Int, _ atBlock: UInt64) { + self.index = index + self.atBlock = atBlock } } - pub fun unblockAddress(_ address: Address) { - if DapperStorageRent.getBlockedAccounts().contains(address) { - let position = DapperStorageRent.BlockedAccounts.firstIndex(of: address) ?? panic("Trying to unblock an address that is not blocked.") - if position != nil { - DapperStorageRent.BlockedAccounts.remove(at: position) + /// Admin resource + /// Used to set different configuration levers such as StorageRentRefillThreshold, RefillRequiredBlocks, and BlockedAccounts + access(all) resource Admin { + access(all) fun setStorageRentRefillThreshold(_ threshold: UInt64) { + DapperStorageRent.StorageRentRefillThreshold = threshold + } + + access(all) fun setRefillRequiredBlocks(_ blocks: UInt64) { + DapperStorageRent.RefillRequiredBlocks = blocks + } + + access(all) fun blockAddress(_ address: Address) { + if !DapperStorageRent.getBlockedAccounts().contains(address) { + DapperStorageRent.BlockedAccounts.append(address) emit BlockedAddress(DapperStorageRent.getBlockedAccounts()) } } + + access(all) fun unblockAddress(_ address: Address) { + if DapperStorageRent.getBlockedAccounts().contains(address) { + let position = DapperStorageRent.BlockedAccounts.firstIndex(of: address) ?? panic("Trying to unblock an address that is not blocked.") + if position != nil { + DapperStorageRent.BlockedAccounts.remove(at: position) + emit BlockedAddress(DapperStorageRent.getBlockedAccounts()) + } + } + } + } + + // DapperStorageRent init + init() { + self.DapperStorageRentAdminStoragePath = /storage/DapperStorageRentAdmin + self.StorageRentRefillThreshold = 5000 + self.RefilledAccounts = [] + self.RefilledAccountInfos = {} + self.RefillRequiredBlocks = 86400 + self.BlockedAccounts = [] + + let admin <- create Admin() + self.account.storage.save(<-admin, to: self.DapperStorageRentAdminStoragePath) } - } - - // DapperStorageRent init - init() { - self.DapperStorageRentAdminStoragePath = /storage/DapperStorageRentAdmin - self.StorageRentRefillThreshold = 5000 - self.RefilledAccounts = [] - self.RefilledAccountInfos = {} - self.RefillRequiredBlocks = 86400 - self.BlockedAccounts = [] - - let admin <- create Admin() - self.account.save(<-admin, to: self.DapperStorageRentAdminStoragePath) - } } diff --git a/contracts/standard/DapperUtilityCoin.cdc b/contracts/standard/DapperUtilityCoin.cdc index b5573e12..f2032756 100644 --- a/contracts/standard/DapperUtilityCoin.cdc +++ b/contracts/standard/DapperUtilityCoin.cdc @@ -1,30 +1,33 @@ -import FungibleToken from "./FungibleToken.cdc" +import "FungibleToken" +import "ViewResolver" +import "MetadataViews" +import "FungibleTokenMetadataViews" -pub contract DapperUtilityCoin: FungibleToken { +access(all) contract DapperUtilityCoin: ViewResolver { // Total supply of DapperUtilityCoins in existence - pub var totalSupply: UFix64 + access(all) var totalSupply: UFix64 // Event that is emitted when the contract is created - pub event TokensInitialized(initialSupply: UFix64) + access(all) event TokensInitialized(initialSupply: UFix64) // Event that is emitted when tokens are withdrawn from a Vault - pub event TokensWithdrawn(amount: UFix64, from: Address?) + access(all) event TokensWithdrawn(amount: UFix64, from: Address?) // Event that is emitted when tokens are deposited to a Vault - pub event TokensDeposited(amount: UFix64, to: Address?) + access(all) event TokensDeposited(amount: UFix64, to: Address?) // Event that is emitted when new tokens are minted - pub event TokensMinted(amount: UFix64) + access(all) event TokensMinted(amount: UFix64) // Event that is emitted when tokens are destroyed - pub event TokensBurned(amount: UFix64) + access(all) event TokensBurned(amount: UFix64) // Event that is emitted when a new minter resource is created - pub event MinterCreated(allowedAmount: UFix64) + access(all) event MinterCreated(allowedAmount: UFix64) // Event that is emitted when a new burner resource is created - pub event BurnerCreated() + access(all) event BurnerCreated() // Vault // @@ -38,51 +41,233 @@ pub contract DapperUtilityCoin: FungibleToken { // out of thin air. A special Minter resource needs to be defined to mint // new tokens. // - pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance { + /// Vault + /// + /// Each user stores an instance of only the Vault in their storage + /// The functions in the Vault and governed by the pre and post conditions + /// in FungibleToken when they are called. + /// The checks happen at runtime whenever a function is called. + /// + /// Resources can only be created in the context of the contract that they + /// are defined in, so there is no way for a malicious user to create Vaults + /// out of thin air. A special Minter resource needs to be defined to mint + /// new tokens. + /// + access(all) resource Vault: FungibleToken.Vault { - // holds the balance of a users tokens - pub var balance: UFix64 + /// The total balance of this vault + access(all) var balance: UFix64 + + access(self) var storagePath: StoragePath + access(self) var publicPath: PublicPath + access(self) var receiverPath: PublicPath + + /// Returns the storage path where the vault should typically be stored + access(all) view fun getDefaultStoragePath(): StoragePath? { + return self.storagePath + } + + /// Returns the public path where this vault should have a public capability + access(all) view fun getDefaultPublicPath(): PublicPath? { + return self.publicPath + } + + /// Returns the public path where this vault's Receiver should have a public capability + access(all) view fun getDefaultReceiverPath(): PublicPath? { + return self.receiverPath + } + + access(all) view fun getViews(): [Type] { + return [ + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveView(Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveView(Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + name: "Example Fungible Token", + symbol: "EFT", + description: "This fungible token is used as an example to help you develop your next FT #onFlow.", + externalURL: MetadataViews.ExternalURL("https://example-ft.onflow.org"), + logos: medias, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + case Type(): + return DapperUtilityCoin.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + case Type(): + return FungibleTokenMetadataViews.TotalSupply( + totalSupply: DapperUtilityCoin.totalSupply + ) + } + return nil + } + + /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[self.getType()] = true + return supportedTypes + } + + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } // initialize the balance at resource creation time init(balance: UFix64) { self.balance = balance + let identifier = "exampleTokenVault" + self.storagePath = StoragePath(identifier: identifier)! + self.publicPath = PublicPath(identifier: identifier)! + self.receiverPath = PublicPath(identifier: "exampleTokenReceiver")! } - // withdraw - // - // Function that takes an integer amount as an argument - // and withdraws that amount from the Vault. - // It creates a new temporary Vault that is used to hold - // the money that is being transferred. It returns the newly - // created Vault to the context that called so it can be deposited - // elsewhere. - // - pub fun withdraw(amount: UFix64): @FungibleToken.Vault { + /// Get the balance of the vault + access(all) view fun getBalance(): UFix64 { + return self.balance + } + + /// withdraw + /// + /// Function that takes an amount as an argument + /// and withdraws that amount from the Vault. + /// + /// It creates a new temporary Vault that is used to hold + /// the tokens that are being transferred. It returns the newly + /// created Vault to the context that called so it can be deposited + /// elsewhere. + /// + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @DapperUtilityCoin.Vault { self.balance = self.balance - amount - emit TokensWithdrawn(amount: amount, from: self.owner?.address) return <-create Vault(balance: amount) } - // deposit - // - // Function that takes a Vault object as an argument and adds - // its balance to the balance of the owners Vault. - // It is allowed to destroy the sent Vault because the Vault - // was a temporary holder of the tokens. The Vault's balance has - // been consumed and therefore can be destroyed. - pub fun deposit(from: @FungibleToken.Vault) { + /// deposit + /// + /// Function that takes a Vault object as an argument and adds + /// its balance to the balance of the owners Vault. + /// + /// It is allowed to destroy the sent Vault because the Vault + /// was a temporary holder of the tokens. The Vault's balance has + /// been consumed and therefore can be destroyed. + /// + access(all) fun deposit(from: @{FungibleToken.Vault}) { let vault <- from as! @DapperUtilityCoin.Vault self.balance = self.balance + vault.balance - emit TokensDeposited(amount: vault.balance, to: self.owner?.address) vault.balance = 0.0 destroy vault } - destroy() { - DapperUtilityCoin.totalSupply = DapperUtilityCoin.totalSupply - self.balance + + access(FungibleToken.Withdraw) fun transfer(amount: UFix64, receiver: Capability<&{FungibleToken.Receiver}>) { + let transferVault <- self.withdraw(amount: amount) + + // Get a reference to the recipient's Receiver + let receiverRef = receiver.borrow() + ?? panic("Could not borrow receiver reference to the recipient's Vault") + + // Deposit the withdrawn tokens in the recipient's receiver + receiverRef.deposit(from: <-transferVault) + } + + + /// createEmptyVault + /// + /// Function that creates a new Vault with a balance of zero + /// and returns it to the calling context. A user must call this function + /// and store the returned Vault in their storage in order to allow their + /// account to be able to receive deposits of this token type. + /// + access(all) fun createEmptyVault(): @DapperUtilityCoin.Vault { + return <-create Vault(balance: 0.0) + } + + access(contract) fun burnCallback() { + // Placeholder for a burn callback + } + + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return true } } + /// Gets a list of the metadata views that this contract supports + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [Type(), + Type(), + Type(), + Type()] + } + + /// Get a Metadata View from DapperUtilityCoin + /// + /// @param view: The Type of the desired view. + /// @return A structure representing the requested view. + /// + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + name: "FLOW Network Token", + symbol: "FLOW", + description: "FLOW is the native token for the Flow blockchain. It is required for securing the network, transaction fees, storage fees, staking, FLIP voting and may be used by applications built on the Flow Blockchain", + externalURL: MetadataViews.ExternalURL("https://flow.com"), + logos: medias, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + case Type(): + let vaultRef = DapperUtilityCoin.account.storage.borrow(from: /storage/DapperUtilityCoinVault) + ?? panic("Could not borrow reference to the contract's Vault!") + return FungibleTokenMetadataViews.FTVaultData( + storagePath: /storage/DapperUtilityCoinVault, + receiverPath: /public/DapperUtilityCoinReceiver, + metadataPath: /public/DapperUtilityCoinBalance, + receiverLinkedType: Type<&DapperUtilityCoin.Vault>(), + metadataLinkedType: Type<&DapperUtilityCoin.Vault>(), + createEmptyVaultFunction: (fun (): @{FungibleToken.Vault} { + return <-vaultRef.createEmptyVault() + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply(totalSupply: DapperUtilityCoin.totalSupply) + } + return nil + } + + // createEmptyVault // // Function that creates a new Vault with a balance of zero @@ -90,16 +275,16 @@ pub contract DapperUtilityCoin: FungibleToken { // and store the returned Vault in their storage in order to allow their // account to be able to receive deposits of this token type. // - pub fun createEmptyVault(): @FungibleToken.Vault { + access(all) fun createEmptyVault(): @{FungibleToken.Vault} { return <-create Vault(balance: 0.0) } - pub resource Administrator { + access(all) resource Administrator { // createNewMinter // // Function that creates and returns a new minter resource // - pub fun createNewMinter(allowedAmount: UFix64): @Minter { + access(all) fun createNewMinter(allowedAmount: UFix64): @Minter { emit MinterCreated(allowedAmount: allowedAmount) return <-create Minter(allowedAmount: allowedAmount) } @@ -108,7 +293,7 @@ pub contract DapperUtilityCoin: FungibleToken { // // Function that creates and returns a new burner resource // - pub fun createNewBurner(): @Burner { + access(all) fun createNewBurner(): @Burner { emit BurnerCreated() return <-create Burner() } @@ -118,17 +303,17 @@ pub contract DapperUtilityCoin: FungibleToken { // // Resource object that token admin accounts can hold to mint new tokens. // - pub resource Minter { + access(all) resource Minter { // the amount of tokens that the minter is allowed to mint - pub var allowedAmount: UFix64 + access(all) var allowedAmount: UFix64 // mintTokens // // Function that mints new tokens, adds them to the total supply, // and returns them to the calling context. // - pub fun mintTokens(amount: UFix64): @DapperUtilityCoin.Vault { + access(all) fun mintTokens(amount: UFix64): @DapperUtilityCoin.Vault { pre { amount > UFix64(0): "Amount minted must be greater than zero" amount <= self.allowedAmount: "Amount minted must be less than the allowed amount" @@ -148,7 +333,7 @@ pub contract DapperUtilityCoin: FungibleToken { // // Resource object that token admin accounts can hold to burn tokens. // - pub resource Burner { + access(all) resource Burner { // burnTokens // @@ -157,7 +342,7 @@ pub contract DapperUtilityCoin: FungibleToken { // Note: the burned tokens are automatically subtracted from the // total supply in the Vault destructor. // - pub fun burnTokens(from: @FungibleToken.Vault) { + access(all) fun burnTokens(from: @{FungibleToken.Vault}) { let vault <- from as! @DapperUtilityCoin.Vault let amount = vault.balance destroy vault @@ -172,26 +357,24 @@ pub contract DapperUtilityCoin: FungibleToken { let admin <- create Administrator() let minter <- admin.createNewMinter(allowedAmount: self.totalSupply) - self.account.save(<-admin, to: /storage/dapperUtilityCoinAdmin) + self.account.storage.save(<-admin, to: /storage/dapperUtilityCoinAdmin) // mint tokens let tokenVault <- minter.mintTokens(amount: self.totalSupply) - self.account.save(<-tokenVault, to: /storage/dapperUtilityCoinVault) + self.account.storage.save(<-tokenVault, to: /storage/dapperUtilityCoinVault) destroy minter // Create a public capability to the stored Vault that only exposes // the `balance` field through the `Balance` interface - self.account.link<&DapperUtilityCoin.Vault{FungibleToken.Balance}>( - /public/dapperUtilityCoinBalance, - target: /storage/dapperUtilityCoinVault - ) + let vaultCap = self.account.capabilities.storage.issue<&Vault>(/storage/dapperUtilityCoinVault) + self.account.capabilities.publish(vaultCap, at: /public/dapperUtilityCoinVault) // Create a public capability to the stored Vault that only exposes // the `deposit` method through the `Receiver` interface - self.account.link<&{FungibleToken.Receiver}>( - /public/dapperUtilityCoinReceiver, - target: /storage/dapperUtilityCoinVault + let recieverCap = self.account.capabilities.storage.issue<&{FungibleToken.Receiver}>( + /storage/dapperUtilityCoinVault ) + self.account.capabilities.publish(recieverCap, at: /public/dapperUtilityCoinReceiver) // Emit an event that shows that the contract was initialized emit TokensInitialized(initialSupply: self.totalSupply) diff --git a/contracts/standard/EmeraldIdentity.cdc b/contracts/standard/EmeraldIdentity.cdc index 6c06920d..bd00af95 100644 --- a/contracts/standard/EmeraldIdentity.cdc +++ b/contracts/standard/EmeraldIdentity.cdc @@ -11,35 +11,35 @@ // multiple addresses to your DiscordID, and you cannot configure // multiple DiscordIDs to your address. 1-1. -pub contract EmeraldIdentity { +access(all) contract EmeraldIdentity { // // Paths // - pub let AdministratorStoragePath: StoragePath - pub let AdministratorPrivatePath: PrivatePath + access(all) let AdministratorStoragePath: StoragePath + access(all) let AdministratorPrivatePath: PrivatePath // // Events // - pub event EmeraldIDCreated(account: Address, discordID: String) - pub event EmeraldIDRemoved(account: Address, discordID: String) - + access(all) event EmeraldIDCreated(account: Address, discordID: String) + access(all) event EmeraldIDRemoved(account: Address, discordID: String) + // // Administrator // - pub resource Administrator { + access(all) resource Administrator { // 1-to-1 access(account) var accountToDiscord: {Address: String} // 1-to-1 access(account) var discordToAccount: {String: Address} - pub fun createEmeraldID(account: Address, discordID: String) { + access(all) fun createEmeraldID(account: Address, discordID: String) { pre { EmeraldIdentity.getAccountFromDiscord(discordID: discordID) == nil: - "The old discordID must remove their EmeraldID first." + "The old discordID must remove their EmeraldID first." EmeraldIdentity.getDiscordFromAccount(account: account) == nil: - "The old account must remove their EmeraldID first." + "The old account must remove their EmeraldID first." } self.accountToDiscord[account] = discordID @@ -48,12 +48,12 @@ pub contract EmeraldIdentity { emit EmeraldIDCreated(account: account, discordID: discordID) } - pub fun removeByAccount(account: Address) { + access(all) fun removeByAccount(account: Address) { let discordID = EmeraldIdentity.getDiscordFromAccount(account: account) ?? panic("This EmeraldID does not exist!") self.remove(account: account, discordID: discordID) } - pub fun removeByDiscord(discordID: String) { + access(all) fun removeByDiscord(discordID: String) { let account = EmeraldIdentity.getAccountFromDiscord(discordID: discordID) ?? panic("This EmeraldID does not exist!") self.remove(account: account, discordID: discordID) } @@ -65,8 +65,8 @@ pub contract EmeraldIdentity { emit EmeraldIDRemoved(account: account, discordID: discordID) } - pub fun createAdministrator(): Capability<&Administrator> { - return EmeraldIdentity.account.getCapability<&Administrator>(EmeraldIdentity.AdministratorPrivatePath) + access(all) fun createAdministrator(): Capability<&Administrator> { + return EmeraldIdentity.account.capabilities.storage.issue<&Administrator>(EmeraldIdentity.AdministratorStoragePath) } init() { @@ -77,13 +77,13 @@ pub contract EmeraldIdentity { /*** USE THE BELOW FUNCTIONS FOR SECURE VERIFICATION OF ID ***/ - pub fun getDiscordFromAccount(account: Address): String? { - let admin = EmeraldIdentity.account.borrow<&Administrator>(from: EmeraldIdentity.AdministratorStoragePath)! + access(all) view fun getDiscordFromAccount(account: Address): String? { + let admin = EmeraldIdentity.account.storage.borrow<&Administrator>(from: EmeraldIdentity.AdministratorStoragePath)! return admin.accountToDiscord[account] } - pub fun getAccountFromDiscord(discordID: String): Address? { - let admin = EmeraldIdentity.account.borrow<&Administrator>(from: EmeraldIdentity.AdministratorStoragePath)! + access(all) view fun getAccountFromDiscord(discordID: String): Address? { + let admin = EmeraldIdentity.account.storage.borrow<&Administrator>(from: EmeraldIdentity.AdministratorStoragePath)! return admin.discordToAccount[discordID] } @@ -91,7 +91,6 @@ pub contract EmeraldIdentity { self.AdministratorStoragePath = /storage/EmeraldIDAdministrator self.AdministratorPrivatePath = /private/EmeraldIDAdministrator - self.account.save(<- create Administrator(), to: EmeraldIdentity.AdministratorStoragePath) - self.account.link<&Administrator>(EmeraldIdentity.AdministratorPrivatePath, target: EmeraldIdentity.AdministratorStoragePath) + self.account.storage.save(<- create Administrator(), to: EmeraldIdentity.AdministratorStoragePath) } -} \ No newline at end of file +} diff --git a/contracts/standard/EmeraldIdentityDapper.cdc b/contracts/standard/EmeraldIdentityDapper.cdc index 1026882c..bffa96d2 100644 --- a/contracts/standard/EmeraldIdentityDapper.cdc +++ b/contracts/standard/EmeraldIdentityDapper.cdc @@ -11,30 +11,30 @@ // multiple addresses to your DiscordID, and you cannot configure // multiple DiscordIDs to your address. 1-1. -pub contract EmeraldIdentityDapper { +access(all) contract EmeraldIdentityDapper { // // Paths // - pub let AdministratorStoragePath: StoragePath - pub let AdministratorPrivatePath: PrivatePath + access(all) let AdministratorStoragePath: StoragePath + access(all) let AdministratorPrivatePath: PrivatePath // // Events // - pub event EmeraldIDCreated(account: Address, discordID: String) - pub event EmeraldIDRemoved(account: Address, discordID: String) + access(all) event EmeraldIDCreated(account: Address, discordID: String) + access(all) event EmeraldIDRemoved(account: Address, discordID: String) // // Administrator // - pub resource Administrator { + access(all) resource Administrator { // 1-to-1 access(account) var accountToDiscord: {Address: String} // 1-to-1 access(account) var discordToAccount: {String: Address} - pub fun createEmeraldID(account: Address, discordID: String) { + access(all) createEmeraldID(account: Address, discordID: String) { pre { EmeraldIdentityDapper.getAccountFromDiscord(discordID: discordID) == nil: "The old discordID must remove their EmeraldID first." @@ -48,12 +48,12 @@ pub contract EmeraldIdentityDapper { emit EmeraldIDCreated(account: account, discordID: discordID) } - pub fun removeByAccount(account: Address) { + access(all) removeByAccount(account: Address) { let discordID = EmeraldIdentityDapper.getDiscordFromAccount(account: account) ?? panic("This EmeraldID does not exist!") self.remove(account: account, discordID: discordID) } - pub fun removeByDiscord(discordID: String) { + access(all) removeByDiscord(discordID: String) { let account = EmeraldIdentityDapper.getAccountFromDiscord(discordID: discordID) ?? panic("This EmeraldID does not exist!") self.remove(account: account, discordID: discordID) } @@ -65,7 +65,7 @@ pub contract EmeraldIdentityDapper { emit EmeraldIDRemoved(account: account, discordID: discordID) } - pub fun createAdministrator(): Capability<&Administrator> { + access(all) createAdministrator(): Capability<&Administrator> { return EmeraldIdentityDapper.account.getCapability<&Administrator>(EmeraldIdentityDapper.AdministratorPrivatePath) } @@ -77,13 +77,13 @@ pub contract EmeraldIdentityDapper { /*** USE THE BELOW FUNCTIONS FOR SECURE VERIFICATION OF ID ***/ - pub fun getDiscordFromAccount(account: Address): String? { - let admin = EmeraldIdentityDapper.account.borrow<&Administrator>(from: EmeraldIdentityDapper.AdministratorStoragePath)! + access(all) getDiscordFromAccount(account: Address): String? { + let admin = EmeraldIdentityDapper.account.storage.borrow<&Administrator>(from: EmeraldIdentityDapper.AdministratorStoragePath)! return admin.accountToDiscord[account] } - pub fun getAccountFromDiscord(discordID: String): Address? { - let admin = EmeraldIdentityDapper.account.borrow<&Administrator>(from: EmeraldIdentityDapper.AdministratorStoragePath)! + access(all) getAccountFromDiscord(discordID: String): Address? { + let admin = EmeraldIdentityDapper.account.storage.borrow<&Administrator>(from: EmeraldIdentityDapper.AdministratorStoragePath)! return admin.discordToAccount[discordID] } @@ -91,7 +91,7 @@ pub contract EmeraldIdentityDapper { self.AdministratorStoragePath = /storage/EmeraldIDDapperAdministrator self.AdministratorPrivatePath = /private/EmeraldIDDapperAdministrator - self.account.save(<- create Administrator(), to: EmeraldIdentityDapper.AdministratorStoragePath) + self.account.storage.save(<- create Administrator(), to: EmeraldIdentityDapper.AdministratorStoragePath) self.account.link<&Administrator>(EmeraldIdentityDapper.AdministratorPrivatePath, target: EmeraldIdentityDapper.AdministratorStoragePath) } -} \ No newline at end of file +} diff --git a/contracts/standard/EmeraldIdentityLilico.cdc b/contracts/standard/EmeraldIdentityLilico.cdc index 961f4a6b..654e499a 100644 --- a/contracts/standard/EmeraldIdentityLilico.cdc +++ b/contracts/standard/EmeraldIdentityLilico.cdc @@ -11,30 +11,30 @@ // multiple addresses to your DiscordID, and you cannot configure // multiple DiscordIDs to your address. 1-1. -pub contract EmeraldIdentityLilico { +access(all) contract EmeraldIdentityLilico { // // Paths // - pub let AdministratorStoragePath: StoragePath - pub let AdministratorPrivatePath: PrivatePath + access(all) let AdministratorStoragePath: StoragePath + access(all) let AdministratorPrivatePath: PrivatePath // // Events // - pub event EmeraldIDCreated(account: Address, discordID: String) - pub event EmeraldIDRemoved(account: Address, discordID: String) + access(all) event EmeraldIDCreated(account: Address, discordID: String) + access(all) event EmeraldIDRemoved(account: Address, discordID: String) // // Administrator // - pub resource Administrator { + access(all) resource Administrator { // 1-to-1 access(account) var accountToDiscord: {Address: String} // 1-to-1 access(account) var discordToAccount: {String: Address} - pub fun createEmeraldID(account: Address, discordID: String) { + access(all) createEmeraldID(account: Address, discordID: String) { pre { EmeraldIdentityLilico.getAccountFromDiscord(discordID: discordID) == nil: "The old discordID must remove their EmeraldID first." @@ -48,12 +48,12 @@ pub contract EmeraldIdentityLilico { emit EmeraldIDCreated(account: account, discordID: discordID) } - pub fun removeByAccount(account: Address) { + access(all) removeByAccount(account: Address) { let discordID = EmeraldIdentityLilico.getDiscordFromAccount(account: account) ?? panic("This EmeraldID does not exist!") self.remove(account: account, discordID: discordID) } - pub fun removeByDiscord(discordID: String) { + access(all) removeByDiscord(discordID: String) { let account = EmeraldIdentityLilico.getAccountFromDiscord(discordID: discordID) ?? panic("This EmeraldID does not exist!") self.remove(account: account, discordID: discordID) } @@ -65,7 +65,7 @@ pub contract EmeraldIdentityLilico { emit EmeraldIDRemoved(account: account, discordID: discordID) } - pub fun createAdministrator(): Capability<&Administrator> { + access(all) createAdministrator(): Capability<&Administrator> { return EmeraldIdentityLilico.account.getCapability<&Administrator>(EmeraldIdentityLilico.AdministratorPrivatePath) } @@ -77,13 +77,13 @@ pub contract EmeraldIdentityLilico { /*** USE THE BELOW FUNCTIONS FOR SECURE VERIFICATION OF ID ***/ - pub fun getDiscordFromAccount(account: Address): String? { - let admin = EmeraldIdentityLilico.account.borrow<&Administrator>(from: EmeraldIdentityLilico.AdministratorStoragePath)! + access(all) getDiscordFromAccount(account: Address): String? { + let admin = EmeraldIdentityLilico.account.storage.borrow<&Administrator>(from: EmeraldIdentityLilico.AdministratorStoragePath)! return admin.accountToDiscord[account] } - pub fun getAccountFromDiscord(discordID: String): Address? { - let admin = EmeraldIdentityLilico.account.borrow<&Administrator>(from: EmeraldIdentityLilico.AdministratorStoragePath)! + access(all) getAccountFromDiscord(discordID: String): Address? { + let admin = EmeraldIdentityLilico.account.storage.borrow<&Administrator>(from: EmeraldIdentityLilico.AdministratorStoragePath)! return admin.discordToAccount[discordID] } @@ -91,7 +91,7 @@ pub contract EmeraldIdentityLilico { self.AdministratorStoragePath = /storage/EmeraldIDLilicoAdministrator self.AdministratorPrivatePath = /private/EmeraldIDLilicoAdministrator - self.account.save(<- create Administrator(), to: EmeraldIdentityLilico.AdministratorStoragePath) + self.account.storage.save(<- create Administrator(), to: EmeraldIdentityLilico.AdministratorStoragePath) self.account.link<&Administrator>(EmeraldIdentityLilico.AdministratorPrivatePath, target: EmeraldIdentityLilico.AdministratorStoragePath) } -} \ No newline at end of file +} diff --git a/contracts/standard/ExampleNFT.cdc b/contracts/standard/ExampleNFT.cdc index 33ae3386..bab5b0de 100644 --- a/contracts/standard/ExampleNFT.cdc +++ b/contracts/standard/ExampleNFT.cdc @@ -9,34 +9,32 @@ * */ -import NonFungibleToken from "./NonFungibleToken.cdc" -import FungibleToken from "./FungibleToken.cdc" -import MetadataViews from "./MetadataViews.cdc" -import FindViews from "../FindViews.cdc" -import FindForge from "../FindForge.cdc" -import DapperUtilityCoin from "./DapperUtilityCoin.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "FindViews" +import "FindForge" +import "DapperUtilityCoin" +import "ViewResolver" -pub contract ExampleNFT: NonFungibleToken { - pub var totalSupply: UInt64 +access(all) contract ExampleNFT: NonFungibleToken { - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) + access(all) var totalSupply: UInt64 - pub let CollectionStoragePath: StoragePath - pub let CollectionPrivatePath: PrivatePath - pub let CollectionPublicPath: PublicPath - pub let MinterStoragePath: StoragePath + access(all) event ContractInitialized() - pub let traits : {UInt64 : MetadataViews.Trait} + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath - pub struct ExampleNFTInfo { - pub let name: String - pub let description: String - pub let soulBound: Bool - pub let traits : [UInt64] - pub let thumbnail: String + access(all) let traits : {UInt64 : MetadataViews.Trait} + + access(all) struct ExampleNFTInfo { + access(all) let name: String + access(all) let description: String + access(all) let soulBound: Bool + access(all) let traits : [UInt64] + access(all) let thumbnail: String init(name: String, description: String, soulBound: Bool, traits : [UInt64], thumbnail: String) { self.name=name @@ -47,18 +45,19 @@ pub contract ExampleNFT: NonFungibleToken { } } - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - pub let id: UInt64 - pub let name: String - pub let description: String - pub let thumbnail: String - pub var soulBound: Bool + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { + access(all) let id: UInt64 + + access(all) let name: String + access(all) let description: String + access(all) let thumbnail: String + access(all) var soulBound: Bool // For testing - pub let traits : [UInt64] + access(all) let traits : [UInt64] access(self) let royalties: MetadataViews.Royalties - pub var changedRoyalties: Bool + access(all) var changedRoyalties: Bool init( id: UInt64, @@ -85,187 +84,210 @@ pub contract ExampleNFT: NonFungibleToken { self.changedRoyalties = false } - pub fun toggleSoulBound(_ status: Bool) { + access(all) view fun getID(): UInt64 { + return self.id + } + + access(all) fun toggleSoulBound(_ status: Bool) { self.soulBound = status } - pub fun changeRoyalties(_ bool: Bool) { + access(all) fun changeRoyalties(_ bool: Bool) { self.changedRoyalties = bool } - pub fun getViews(): [Type] { - let views = [ - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type(), - Type() + access(all) view fun getViews(): [Type] { + var views = [ + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type(), + Type() ] if self.soulBound { - views.append(Type()) + views=views.concat([Type()]) } return views } - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) fun resolveView(_ view: Type): AnyStruct? { switch view { - case Type(): - return MetadataViews.Display( - name: self.name, - description: self.description, - thumbnail: MetadataViews.HTTPFile( - url: self.thumbnail - ) - ) - case Type(): - // There is no max number of NFTs that can be minted from this contract - // so the max edition field value is set to nil - let editionInfo = MetadataViews.Edition(name: "Example NFT Edition", number: self.id, max: nil) - let editionList: [MetadataViews.Edition] = [editionInfo] - return MetadataViews.Editions( - editionList - ) - case Type(): - return MetadataViews.Serial( - self.id - ) - case Type(): - if !self.changedRoyalties { - return self.royalties - } - return MetadataViews.Royalties([MetadataViews.Royalty(receiver:ExampleNFT.account.getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver), cut: 0.99, description: "cheater")]) - case Type(): - return MetadataViews.ExternalURL("https://example-nft.onflow.org/".concat(self.id.toString())) - case Type(): - return MetadataViews.NFTCollectionData( - storagePath: ExampleNFT.CollectionStoragePath, - publicPath: ExampleNFT.CollectionPublicPath, - providerPath: /private/exampleNFTCollection, - publicCollection: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic}>(), - publicLinkedType: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { - return <-ExampleNFT.createEmptyCollection() - }) - ) - case Type(): - let media = MetadataViews.Media( - file: MetadataViews.HTTPFile( - url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg" - ), - mediaType: "image/svg+xml" - ) - return MetadataViews.NFTCollectionDisplay( - name: "The Example Collection", - description: "This collection is used as an example to help you develop your next Flow NFT.", - externalURL: MetadataViews.ExternalURL("https://example-nft.onflow.org"), - squareImage: media, - bannerImage: media, - socials: { - "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") - } - ) - - case Type() : - if !self.soulBound { - return nil - } - return FindViews.SoulBound( - "This NFT is soulbound." + case Type(): + return MetadataViews.Display( + name: self.name, + description: self.description, + thumbnail: MetadataViews.HTTPFile( + url: self.thumbnail ) + ) + case Type(): + // There is no max number of NFTs that can be minted from this contract + // so the max edition field value is set to nil + let editionInfo = MetadataViews.Edition(name: "Example NFT Edition", number: self.id, max: nil) + let editionList: [MetadataViews.Edition] = [editionInfo] + return MetadataViews.Editions( + editionList + ) + case Type(): + return MetadataViews.Serial( + self.id + ) + case Type(): + if !self.changedRoyalties { + return self.royalties + } + return MetadataViews.Royalties([ + MetadataViews.Royalty(receiver:ExampleNFT.account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver), cut: 0.99, description: "cheater") + ]) + case Type(): + return MetadataViews.ExternalURL("https://example-nft.onflow.org/".concat(self.id.toString())) + case Type(): + return ExampleNFT.getCollectionData(nftType: Type<@ExampleNFT.NFT>()) + case Type(): + return ExampleNFT.getCollectionDisplay(nftType: Type<@ExampleNFT.NFT>()) + case Type() : + if !self.soulBound { + return nil + } + return FindViews.SoulBound( + "This NFT is soulbound." + ) - case Type() : - return MetadataViews.Rarity(score: 1.0, max: 2.0, description: "rarity description") + case Type() : + return MetadataViews.Rarity(score: 1.0, max: 2.0, description: "rarity description") } return nil } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-ExampleNFT.createEmptyCollection(nftType:Type<@ExampleNFT.NFT>()) + } } - pub resource interface ExampleNFTCollectionPublic { - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? { - post { - (result == nil) || (result?.id == id): - "Cannot borrow ExampleNFT reference: the ID of the returned reference is incorrect" - } + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [ + Type(), + Type() + ] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + let collectionData = MetadataViews.NFTCollectionData( + storagePath: ExampleNFT.CollectionStoragePath, + publicPath: ExampleNFT.CollectionPublicPath, + publicCollection: Type<&ExampleNFT.Collection>(), + publicLinkedType: Type<&ExampleNFT.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + return <-ExampleNFT.createEmptyCollection(nftType:Type<@ExampleNFT.NFT>()) + }) + ) + return collectionData } + return nil } - pub resource Collection: ExampleNFTCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { - // dictionary of NFT conforming tokens - // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) resource Collection: NonFungibleToken.Collection, ViewResolver.ResolverCollection { + /// dictionary of NFT conforming tokens + /// NFT is a resource type with an `UInt64` ID field + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} + + access(self) var storagePath: StoragePath + access(self) var publicPath: PublicPath + + /// Return the default storage path for the collection + access(all) view fun getDefaultStoragePath(): StoragePath? { + return self.storagePath + } + + /// Return the default public path for the collection + access(all) view fun getDefaultPublicPath(): PublicPath? { + return self.publicPath + } init () { self.ownedNFTs <- {} + let identifier = "exampleNFTCollection" + self.storagePath = StoragePath(identifier: identifier)! + self.publicPath = PublicPath(identifier: identifier)! + } + + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[Type<@ExampleNFT.NFT>()] = true + return supportedTypes } - // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + access(all) view fun isSupportedNFTType(type: Type): Bool { + if type == Type<@ExampleNFT.NFT>() { + return true + } else { + return false + } + } - emit Withdraw(id: token.id, from: self.owner?.address) + /// withdraw removes an NFT from the collection and moves it to the caller + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) + ?? panic("Could not withdraw an NFT with the provided ID from the collection") return <-token } - // deposit takes a NFT and adds it to the collections dictionary - // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { + /// deposit takes a NFT and adds it to the collections dictionary + /// and adds the ID to the id array + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { let token <- token as! @ExampleNFT.NFT - let id: UInt64 = token.id - // add the new token to the dictionary which removes the old one - let oldToken <- self.ownedNFTs[id] <- token - - emit Deposit(id: id, to: self.owner?.address) + let oldToken <- self.ownedNFTs[token.id] <- token destroy oldToken } - // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + /// getIDs returns an array of the IDs that are in the collection + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } - // borrowNFT gets a reference to an NFT in the collection - // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! + /// Gets the amount of NFTs stored in the collection + access(all) view fun getLength(): Int { + return self.ownedNFTs.keys.length } - pub fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? { - if self.ownedNFTs[id] != nil { - // Create an authorized reference to allow downcasting - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - return ref as! &ExampleNFT.NFT - } - - return nil + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] } - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let exampleNFT = nft as! &ExampleNFT.NFT - return exampleNFT as &AnyResource{MetadataViews.Resolver} + /// Borrow the view resolver for the specified NFT ID + // + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? { + return &self.ownedNFTs[id] } - destroy() { - destroy self.ownedNFTs + + /// public function that anyone can call to create a new empty collection + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-ExampleNFT.createEmptyCollection(nftType:Type<@ExampleNFT.NFT>()) } } - // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @NonFungibleToken.Collection { + + + /// public function that anyone can call to create a new empty collection + /// Since multiple collection types can be defined in a contract, + /// The caller needs to specify which one they want to create + access(all) fun createEmptyCollection(nftType:Type): @ExampleNFT.Collection { return <- create Collection() } @@ -273,15 +295,14 @@ pub contract ExampleNFT: NonFungibleToken { /* Find Forge Specific code */ // mintNFT mints a new NFT with a new ID // and deposit it in the recipients collection using their collection reference - pub fun mintNFT( + access(all) fun mintNFT( name: String, description: String, thumbnail: String, soulBound: Bool , traits: [UInt64] , royalties: MetadataViews.Royalties - ) : @NonFungibleToken.NFT - { + ) : @{NonFungibleToken.NFT} { // create a new NFT var newNFT <- create NFT( @@ -294,51 +315,121 @@ pub contract ExampleNFT: NonFungibleToken { royalties: royalties ) - ExampleNFT.totalSupply = ExampleNFT.totalSupply + UInt64(1) + ExampleNFT.totalSupply = ExampleNFT.totalSupply + 1 return <- newNFT } - pub resource Forge: FindForge.Forge { - pub fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @NonFungibleToken.NFT { - let info = data as? ExampleNFTInfo ?? panic("The data passed in is not in form of ExampleNFTInfo.") + + access(all) view fun getViews(): [Type] { + return [ Type(), Type() ] + } + + + /// Function that resolves a metadata view for this contract. + /// + /// @param view: The Type of the desired view. + /// @return A structure representing the requested view. + /// + access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + case Type(): + return ExampleNFT.getCollectionData(nftType: Type<@ExampleNFT.NFT>()) + case Type(): + return ExampleNFT.getCollectionDisplay(nftType: Type<@ExampleNFT.NFT>()) + } + return nil + } + + /// resolve a type to its CollectionData so you know where to store it + /// Returns `nil` if no collection type exists for the specified NFT type + access(all) view fun getCollectionData(nftType: Type): MetadataViews.NFTCollectionData? { + switch nftType { + case Type<@ExampleNFT.NFT>(): + let collectionData = MetadataViews.NFTCollectionData( + storagePath: ExampleNFT.CollectionStoragePath, + publicPath: ExampleNFT.CollectionPublicPath, + publicCollection: Type<&ExampleNFT.Collection>(), + publicLinkedType: Type<&ExampleNFT.Collection>(), + createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} { + + return <-ExampleNFT.createEmptyCollection(nftType:Type<@ExampleNFT.NFT>()) + + }) + ) + return collectionData + default: + return nil + } + } + + /// Returns the CollectionDisplay view for the NFT type that is specified + access(all) view fun getCollectionDisplay(nftType: Type): MetadataViews.NFTCollectionDisplay? { + switch nftType { + case Type<@ExampleNFT.NFT>(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg" + ), + mediaType: "image/svg+xml" + ) + return MetadataViews.NFTCollectionDisplay( + name: "The Example Collection", + description: "This collection is used as an example to help you develop your next Flow NFT.", + externalURL: MetadataViews.ExternalURL("https://example-nft.onflow.org"), + squareImage: media, + bannerImage: media, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + default: + return nil + } + } + + + + access(all)resource Forge: FindForge.Forge { + access(FindForge.ForgeOwner) fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @{NonFungibleToken.NFT} { + let info = data as? ExampleNFTInfo ?? panic("The data passed in is not in form of ExampleNFTInfo.") let royalties : [MetadataViews.Royalty] = [] - if platform.platformPercentCut! != 0.0 { + if platform.platformPercentCut != 0.0 { royalties.append(MetadataViews.Royalty(receiver:platform.platform, cut: platform.platformPercentCut, description: "find forge")) } if platform.minterCut != nil && platform.minterCut! != 0.0 { royalties.append(MetadataViews.Royalty(receiver:platform.getMinterFTReceiver(), cut: platform.minterCut!, description: "creator")) } - return <- ExampleNFT.mintNFT(name: info.name, - description: info.description, - thumbnail: info.thumbnail, - soulBound: info.soulBound, - traits: info.traits, - royalties: MetadataViews.Royalties(royalties)) - } - - pub fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { + return <- ExampleNFT.mintNFT(name: info.name, + description: info.description, + thumbnail: info.thumbnail, + soulBound: info.soulBound, + traits: info.traits, + royalties: MetadataViews.Royalties(royalties)) + } + + access(FindForge.ForgeOwner) fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) { let type = data.getType() switch type { - case Type<{UInt64 : MetadataViews.Trait}>() : - // for duplicated indexes, the new one will replace the old one - let typedData = data as! {UInt64 : MetadataViews.Trait} - for key in typedData.keys { - ExampleNFT.traits[key] = ExampleNFT.traits[key] ?? typedData[key] - } - return + case Type<{UInt64 : MetadataViews.Trait}>() : + // for duplicated indexes, the new one will replace the old one + let typedData = data as! {UInt64 : MetadataViews.Trait} + for key in typedData.keys { + ExampleNFT.traits[key] = ExampleNFT.traits[key] ?? typedData[key] + } + return } } - } + } - access(account) fun createForge() : @{FindForge.Forge} { - return <- create Forge() - } + access(account) fun createForge() : @{FindForge.Forge} { + return <- create Forge() + } - pub fun getForgeType() : Type { - return Type<@Forge>() - } + access(all) fun getForgeType() : Type { + return Type<@Forge>() + } init() { // Initialize the total supply @@ -346,9 +437,7 @@ pub contract ExampleNFT: NonFungibleToken { // Set the named paths self.CollectionStoragePath = /storage/exampleNFTCollection - self.CollectionPrivatePath = /private/exampleNFTCollection self.CollectionPublicPath = /public/exampleNFTCollection - self.MinterStoragePath = /storage/exampleNFTMinter self.traits={ 1 : MetadataViews.Trait(name: "head", value: "hat", displayType: "string", rarity: nil), @@ -358,40 +447,14 @@ pub contract ExampleNFT: NonFungibleToken { // Create a Collection resource and save it to storage let collection <- create Collection() - self.account.save(<-collection, to: self.CollectionStoragePath) + self.account.storage.save(<-collection, to: self.CollectionStoragePath) // create a public capability for the collection - self.account.link<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic, ExampleNFT.ExampleNFTCollectionPublic, MetadataViews.ResolverCollection}>( - self.CollectionPublicPath, - target: self.CollectionStoragePath - ) - - // create a private capability for the collection - self.account.link<&ExampleNFT.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, ExampleNFT.ExampleNFTCollectionPublic, MetadataViews.ResolverCollection}>( - self.CollectionPrivatePath, - target: self.CollectionStoragePath - ) - - FindForge.addForgeType(<- create Forge()) - - //TODO: Add the Forge resource aswell - FindForge.addPublicForgeType(forgeType: Type<@Forge>()) - - emit ContractInitialized() - - // Deposit exampleNFTs for testing - let dapper = getAccount(ExampleNFT.account.address).getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) - let minterCut = MetadataViews.Royalty(receiver:dapper , cut: 0.01, description: "creator") - let royalties : [MetadataViews.Royalty] = [] - royalties.append(minterCut) - let nft <- ExampleNFT.mintNFT(name: "DUCExampleNFT", description: "For testing listing in DUC", thumbnail: "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", soulBound: false,traits : [], royalties: MetadataViews.Royalties(royalties)) - let nft2 <- ExampleNFT.mintNFT(name: "SoulBoundNFT", description: "This is soulBound", thumbnail: "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", soulBound: true,traits : [1,2,3], royalties: MetadataViews.Royalties(royalties)) + let collectionCap = self.account.capabilities.storage.issue<&ExampleNFT.Collection>(self.CollectionStoragePath) + self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath) - let flowR = MetadataViews.Royalties([MetadataViews.Royalty(receiver:ExampleNFT.account.getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver), cut: 0.01, description: "Flow royalty")]) - let nft3 <- ExampleNFT.mintNFT(name: "FlowExampleNFT", description: "For testing listing in Flow", thumbnail: "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", soulBound: false,traits : [1,2,3], royalties: flowR) + FindForge.addForgeType(<- create Forge()) - ExampleNFT.account.borrow<&ExampleNFT.Collection>(from: self.CollectionStoragePath)!.deposit(token : <- nft) - ExampleNFT.account.borrow<&ExampleNFT.Collection>(from: self.CollectionStoragePath)!.deposit(token : <- nft2) - ExampleNFT.account.borrow<&ExampleNFT.Collection>(from: self.CollectionStoragePath)!.deposit(token : <- nft3) + FindForge.addPublicForgeType(forgeType: Type<@Forge>()) } } diff --git a/contracts/standard/FLOAT.cdc b/contracts/standard/FLOAT.cdc index 9e9ce7aa..dee2e3ec 100644 --- a/contracts/standard/FLOAT.cdc +++ b/contracts/standard/FLOAT.cdc @@ -27,39 +27,40 @@ // For more info on GrantedAccountAccess, see GrantedAccountAccess.cdc -import NonFungibleToken from "./NonFungibleToken.cdc" -import MetadataViews from "./MetadataViews.cdc" -import GrantedAccountAccess from "./GrantedAccountAccess.cdc" -import FungibleToken from "./FungibleToken.cdc" -import FlowToken from "./FlowToken.cdc" +import "NonFungibleToken" +import "MetadataViews" +import "ViewResolver" +import "GrantedAccountAccess" +import "FungibleToken" +import "FlowToken" -pub contract FLOAT: NonFungibleToken { +access(all) contract FLOAT { /***********************************************/ /******************** PATHS ********************/ /***********************************************/ - pub let FLOATCollectionStoragePath: StoragePath - pub let FLOATCollectionPublicPath: PublicPath - pub let FLOATEventsStoragePath: StoragePath - pub let FLOATEventsPublicPath: PublicPath - pub let FLOATEventsPrivatePath: PrivatePath + access(all) let FLOATCollectionStoragePath: StoragePath + access(all) let FLOATCollectionPublicPath: PublicPath + access(all) let FLOATEventsStoragePath: StoragePath + access(all) let FLOATEventsPublicPath: PublicPath + access(all) let FLOATEventsPrivatePath: PrivatePath /************************************************/ /******************** EVENTS ********************/ /************************************************/ - pub event ContractInitialized() - pub event FLOATMinted(id: UInt64, eventHost: Address, eventId: UInt64, eventImage: String, recipient: Address, serial: UInt64) - pub event FLOATClaimed(id: UInt64, eventHost: Address, eventId: UInt64, eventImage: String, eventName: String, recipient: Address, serial: UInt64) - pub event FLOATDestroyed(id: UInt64, eventHost: Address, eventId: UInt64, serial: UInt64) - pub event FLOATTransferred(id: UInt64, eventHost: Address, eventId: UInt64, newOwner: Address?, serial: UInt64) - pub event FLOATPurchased(id: UInt64, eventHost: Address, eventId: UInt64, recipient: Address, serial: UInt64) - pub event FLOATEventCreated(eventId: UInt64, description: String, host: Address, image: String, name: String, url: String) - pub event FLOATEventDestroyed(eventId: UInt64, host: Address, name: String) + access(all) event ContractInitialized() + access(all) event FLOATMinted(id: UInt64, eventHost: Address, eventId: UInt64, eventImage: String, recipient: Address, serial: UInt64) + access(all) event FLOATClaimed(id: UInt64, eventHost: Address, eventId: UInt64, eventImage: String, eventName: String, recipient: Address, serial: UInt64) + access(all) event FLOATDestroyed(id: UInt64, eventHost: Address, eventId: UInt64, serial: UInt64) + access(all) event FLOATTransferred(id: UInt64, eventHost: Address, eventId: UInt64, newOwner: Address?, serial: UInt64) + access(all) event FLOATPurchased(id: UInt64, eventHost: Address, eventId: UInt64, recipient: Address, serial: UInt64) + access(all) event FLOATEventCreated(eventId: UInt64, description: String, host: Address, image: String, name: String, url: String) + access(all) event FLOATEventDestroyed(eventId: UInt64, host: Address, name: String) - pub event Deposit(id: UInt64, to: Address?) - pub event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Withdraw(id: UInt64, from: Address?) /***********************************************/ /******************** STATE ********************/ @@ -67,10 +68,10 @@ pub contract FLOAT: NonFungibleToken { // The total amount of FLOATs that have ever been // created (does not go down when a FLOAT is destroyed) - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 // The total amount of FLOATEvents that have ever been // created (does not go down when a FLOATEvent is destroyed) - pub var totalFLOATEvents: UInt64 + access(all) var totalFLOATEvents: UInt64 /***********************************************/ /**************** FUNCTIONALITY ****************/ @@ -78,10 +79,10 @@ pub contract FLOAT: NonFungibleToken { // A helpful wrapper to contain an address, // the id of a FLOAT, and its serial - pub struct TokenIdentifier { - pub let id: UInt64 - pub let address: Address - pub let serial: UInt64 + access(all) struct TokenIdentifier { + access(all) let id: UInt64 + access(all) let address: Address + access(all) let serial: UInt64 init(_id: UInt64, _address: Address, _serial: UInt64) { self.id = _id @@ -90,9 +91,9 @@ pub contract FLOAT: NonFungibleToken { } } - pub struct TokenInfo { - pub let path: PublicPath - pub let price: UFix64 + access(all) struct TokenInfo { + access(all) let path: PublicPath + access(all) let price: UFix64 init(_path: PublicPath, _price: UFix64) { self.path = _path @@ -101,32 +102,37 @@ pub contract FLOAT: NonFungibleToken { } // Represents a FLOAT - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { // The `uuid` of this resource - pub let id: UInt64 + access(all) let id: UInt64 // Some of these are also duplicated on the event, // but it's necessary to put them here as well // in case the FLOATEvent host deletes the event - pub let dateReceived: UFix64 - pub let eventDescription: String - pub let eventHost: Address - pub let eventId: UInt64 - pub let eventImage: String - pub let eventName: String - pub let originalRecipient: Address - pub let serial: UInt64 + access(all) let dateReceived: UFix64 + access(all) let eventDescription: String + access(all) let eventHost: Address + access(all) let eventId: UInt64 + access(all) let eventImage: String + access(all) let eventName: String + access(all) let originalRecipient: Address + access(all) let serial: UInt64 // A capability that points to the FLOATEvents this FLOAT is from. // There is a chance the event host unlinks their event from // the public, in which case it's impossible to know details // about the event. Which is fine, since we store the // crucial data to know about the FLOAT in the FLOAT itself. - pub let eventsCap: Capability<&FLOATEvents{FLOATEventsPublic, MetadataViews.ResolverCollection}> - + access(all) let eventsCap: Capability<&FLOATEvents> + + + access(all) view fun getID() : UInt64 { + return self.id + } + // Helper function to get the metadata of the event // this FLOAT is from. - pub fun getEventMetadata(): &FLOATEvent{FLOATEventPublic}? { + access(all) fun getEventMetadata(): &FLOATEvent? { if let events = self.eventsCap.borrow() { return events.borrowPublicEventRef(eventId: self.eventId) } @@ -134,33 +140,37 @@ pub contract FLOAT: NonFungibleToken { } // This is for the MetdataStandard - pub fun getViews(): [Type] { - return [ - Type(), - Type() + access(all) view fun getViews(): [Type] { + return [ + Type(), + Type() ] } // This is for the MetdataStandard - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) fun resolveView(_ view: Type): AnyStruct? { switch view { - case Type(): - return MetadataViews.Display( - name: self.eventName, - description: self.eventDescription, - file: MetadataViews.IPFSFile(cid: self.eventImage, path: nil) - ) - case Type(): - return TokenIdentifier( - _id: self.id, - _address: self.owner!.address, - _serial: self.serial - ) + case Type(): + return MetadataViews.Display( + name: self.eventName, + description: self.eventDescription, + thumbnail: MetadataViews.IPFSFile(cid: self.eventImage, path: nil) + ) + case Type(): + return TokenIdentifier( + _id: self.id, + _address: self.owner!.address, + _serial: self.serial + ) } return nil } + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <-FLOAT.createEmptyCollection() + } + init(_eventDescription: String, _eventHost: Address, _eventId: UInt64, _eventImage: String, _eventName: String, _originalRecipient: Address, _serial: UInt64) { self.id = self.uuid self.dateReceived = getCurrentBlock().timestamp @@ -174,8 +184,8 @@ pub contract FLOAT: NonFungibleToken { // Stores a capability to the FLOATEvents of its creator self.eventsCap = getAccount(_eventHost) - .getCapability<&FLOATEvents{FLOATEventsPublic, MetadataViews.ResolverCollection}>(FLOAT.FLOATEventsPublicPath) - + .capabilities.get<&FLOATEvents>(FLOAT.FLOATEventsPublicPath)! + emit FLOATMinted( id: self.id, eventHost: _eventHost, @@ -187,40 +197,24 @@ pub contract FLOAT: NonFungibleToken { FLOAT.totalSupply = FLOAT.totalSupply + 1 } - - destroy() { - // If the FLOATEvent owner decided to unlink their public reference - // for some reason (heavily recommend against it), their records - // of who owns the FLOAT is going to be messed up. But that is their - // fault. We shouldn't let that prevent the user from deleting the FLOAT. - if let floatEvent: &FLOATEvent{FLOATEventPublic} = self.getEventMetadata() { - floatEvent.updateFLOATHome(id: self.id, serial: self.serial, owner: nil) - } - emit FLOATDestroyed( - id: self.id, - eventHost: self.eventHost, - eventId: self.eventId, - serial: self.serial - ) - } } // A public interface for people to call into our Collection - pub resource interface CollectionPublic { - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowFLOAT(id: UInt64): &NFT? - pub fun borrowViewResolver(id: UInt64): &{MetadataViews.Resolver} - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun getAllIDs(): [UInt64] - pub fun ownedIdsFromEvent(eventId: UInt64): [UInt64] + access(all) resource interface CollectionPublic { + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? + access(all) fun borrowFLOAT(id: UInt64): &NFT? + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} + access(all) fun deposit(token: @{NonFungibleToken.NFT}) + access(all) view fun getIDs(): [UInt64] + access(all) fun getAllIDs(): [UInt64] + access(all) fun ownedIdsFromEvent(eventId: UInt64): [UInt64] } // A Collection that holds all of the users FLOATs. // Withdrawing is not allowed. You can only transfer. - pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection, CollectionPublic { + access(all) resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, ViewResolver.ResolverCollection, CollectionPublic { // Maps a FLOAT id to the FLOAT itself - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} // Maps an eventId to the ids of FLOATs that // this user owns from that event. It's possible // for it to be out of sync until June 2022 spork, @@ -228,11 +222,11 @@ pub contract FLOAT: NonFungibleToken { access(account) var events: {UInt64: {UInt64: Bool}} // Deposits a FLOAT to the collection - pub fun deposit(token: @NonFungibleToken.NFT) { + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { let nft <- token as! @NFT let id = nft.id let eventId = nft.eventId - + // Update self.events[eventId] to have // this FLOAT's id in it if self.events[eventId] == nil { @@ -244,7 +238,7 @@ pub contract FLOAT: NonFungibleToken { // Try to update the FLOATEvent's current holders. This will // not work if they unlinked their FLOATEvent to the public, // and the data will go out of sync. But that is their fault. - if let floatEvent: &FLOATEvent{FLOATEventPublic} = nft.getEventMetadata() { + if let floatEvent: &FLOATEvent = nft.getEventMetadata() { floatEvent.updateFLOATHome(id: id, serial: nft.serial, owner: self.owner!.address) } @@ -252,7 +246,48 @@ pub contract FLOAT: NonFungibleToken { self.ownedNFTs[id] <-! nft } - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + + + //TODO: this will be removed + /// withdrawWithUUID removes an NFT from the collection, using its UUID, and moves it to the caller + access(NonFungibleToken.Withdraw) fun withdrawWithUUID(_ uuid: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: uuid) ?? panic("Could not withdraw nft") + + let nft <- token as! @NFT + + emit Withdraw(id: nft.id, from: self.owner?.address) + + return <-nft + + } + + /// withdrawWithType removes an NFT from the collection, using its Type and ID and moves it to the caller + /// This would be used by a collection that can store multiple NFT types + access(NonFungibleToken.Withdraw) fun withdrawWithType(type: Type, withdrawID: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Could not withdraw nft") + + let nft <- token as! @NFT + + emit Withdraw(id: nft.id, from: self.owner?.address) + + return <-nft + + } + + /// withdrawWithTypeAndUUID removes an NFT from the collection using its type and uuid and moves it to the caller + /// This would be used by a collection that can store multiple NFT types + access(NonFungibleToken.Withdraw) fun withdrawWithTypeAndUUID(type: Type, uuid: UInt64): @{NonFungibleToken.NFT} { + let token <- self.ownedNFTs.remove(key: uuid) ?? panic("Could not withdraw nft") + + let nft <- token as! @NFT + + emit Withdraw(id: nft.id, from: self.owner?.address) + + return <-nft + } + + + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("You do not own this FLOAT in your collection") let nft <- token as! @NFT let id = nft.id @@ -269,7 +304,7 @@ pub contract FLOAT: NonFungibleToken { // FLOAT to be transferrable. Secondary marketplaces will use this // withdraw function, so if the FLOAT is not transferrable, // you can't sell it there. - if let floatEvent: &FLOATEvent{FLOATEventPublic} = nft.getEventMetadata() { + if let floatEvent: &FLOATEvent = nft.getEventMetadata() { assert( floatEvent.transferrable, message: "This FLOAT is not transferrable." @@ -281,9 +316,49 @@ pub contract FLOAT: NonFungibleToken { return <- nft } + + access(NonFungibleToken.Withdraw) fun transfer(id: UInt64, receiver: Capability<&{NonFungibleToken.Receiver}>): Bool { + let token <- self.ownedNFTs.remove(key: id) ?? panic("missing NFT") + let receiver = receiver as! &{NonFungibleToken.Receiver} + receiver.deposit(token: <-token) + return true + } + + + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + return supportedTypes + } + + /// Returns whether or not the given type is accepted by the collection + access(all) view fun isSupportedNFTType(type: Type): Bool { + return type == Type<@FLOAT.NFT>() + } + + + /// Gets the amount of NFTs stored in the collection + access(all) view fun getLength(): Int { + return self.ownedNFTs.length + } + + /// getIDsWithTypes returns a list of IDs that are in the collection, keyed by type + /// Should only be used by collections that can store multiple NFT types + access(all) view fun getIDsWithTypes(): {Type: [UInt64]} { + let ids: {Type: [UInt64]} = {} + return ids + } + + // public function that anyone can call to create a new empty collection + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- FLOAT.createEmptyCollection() + } + // Only returns the FLOATs for which we can still // access data about their event. - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { + return [] + //TODO not sure how to do this here + /* let ids: [UInt64] = [] for key in self.ownedNFTs.keys { let nftRef = self.borrowFLOAT(id: key)! @@ -292,10 +367,11 @@ pub contract FLOAT: NonFungibleToken { } } return ids + */ } // Returns all the FLOATs ids - pub fun getAllIDs(): [UInt64] { + access(all) fun getAllIDs(): [UInt64] { return self.ownedNFTs.keys } @@ -307,7 +383,7 @@ pub contract FLOAT: NonFungibleToken { // from `ownedNFTs` (not possible after June 2022 spork), // but this makes sure the returned // ids are all actually owned by this account. - pub fun ownedIdsFromEvent(eventId: UInt64): [UInt64] { + access(all) fun ownedIdsFromEvent(eventId: UInt64): [UInt64] { let answer: [UInt64] = [] if let idsInEvent = self.events[eventId]?.keys { for id in idsInEvent { @@ -319,32 +395,38 @@ pub contract FLOAT: NonFungibleToken { return answer } - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] } - pub fun borrowFLOAT(id: UInt64): &NFT? { + access(all) fun borrowFLOAT(id: UInt64): &NFT? { if self.ownedNFTs[id] != nil { - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)! return ref as! &NFT } return nil } - pub fun borrowViewResolver(id: UInt64): &{MetadataViews.Resolver} { - let tokenRef = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} { + let tokenRef = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)! let nftRef = tokenRef as! &NFT - return nftRef as &{MetadataViews.Resolver} + return nftRef } + access(all) view fun getDefaultStoragePath() : StoragePath { + return FLOAT.FLOATCollectionStoragePath + } + + access(all) view fun getDefaultPublicPath() : PublicPath { + return FLOAT.FLOATCollectionPublicPath + } + + + init() { self.ownedNFTs <- {} self.events = {} } - - destroy() { - destroy self.ownedNFTs - } } // An interface that every "verifier" must implement. @@ -352,35 +434,35 @@ pub contract FLOAT: NonFungibleToken { // for example, a "time limit," or a "limited" number of // FLOATs that can be claimed. // All the current verifiers can be seen inside FLOATVerifiers.cdc - pub struct interface IVerifier { + access(all) struct interface IVerifier { // A function every verifier must implement. // Will have `assert`s in it to make sure // the user fits some criteria. - access(account) fun verify(_ params: {String: AnyStruct}) + access(all) fun verify(_ params: {String: AnyStruct}) } // A public interface to read the FLOATEvent - pub resource interface FLOATEventPublic { - pub var claimable: Bool - pub let dateCreated: UFix64 - pub let description: String - pub let eventId: UInt64 - pub let host: Address - pub let image: String - pub let name: String - pub var totalSupply: UInt64 - pub var transferrable: Bool - pub let url: String - pub fun claim(recipient: &Collection, params: {String: AnyStruct}) - pub fun purchase(recipient: &Collection, params: {String: AnyStruct}, payment: @FungibleToken.Vault) - pub fun getClaimed(): {Address: TokenIdentifier} - pub fun getCurrentHolders(): {UInt64: TokenIdentifier} - pub fun getCurrentHolder(serial: UInt64): TokenIdentifier? - pub fun getExtraMetadata(): {String: AnyStruct} - pub fun getVerifiers(): {String: [{IVerifier}]} - pub fun getGroups(): [String] - pub fun getPrices(): {String: TokenInfo}? - pub fun hasClaimed(account: Address): TokenIdentifier? + access(all) resource interface FLOATEventPublic { + access(all) var claimable: Bool + access(all) let dateCreated: UFix64 + access(all) let description: String + access(all) let eventId: UInt64 + access(all) let host: Address + access(all) let image: String + access(all) let name: String + access(all) var totalSupply: UInt64 + access(all) var transferrable: Bool + access(all) let url: String + access(all) fun claim(recipient: &Collection, params: {String: AnyStruct}) + access(all) fun purchase(recipient: &Collection, params: {String: AnyStruct}, payment: @{FungibleToken.Vault}) + access(all) fun getClaimed(): {Address: TokenIdentifier} + access(all) fun getCurrentHolders(): {UInt64: TokenIdentifier} + access(all) fun getCurrentHolder(serial: UInt64): TokenIdentifier? + access(all) fun getExtraMetadata(): {String: AnyStruct} + access(all) fun getVerifiers(): {String: [{IVerifier}]} + access(all) fun getGroups(): [String] + access(all) view fun getPrices(): {String: TokenInfo}? + access(all) fun hasClaimed(account: Address): TokenIdentifier? access(account) fun updateFLOATHome(id: UInt64, serial: UInt64, owner: Address?) } @@ -388,40 +470,40 @@ pub contract FLOAT: NonFungibleToken { // // FLOATEvent // - pub resource FLOATEvent: FLOATEventPublic, MetadataViews.Resolver { + access(all) resource FLOATEvent: FLOATEventPublic, ViewResolver.Resolver { // Whether or not users can claim from our event (can be toggled // at any time) - pub var claimable: Bool + access(all) var claimable: Bool // Maps an address to the FLOAT they claimed access(account) var claimed: {Address: TokenIdentifier} // Maps a serial to the person who theoretically owns // that FLOAT. Must be serial --> TokenIdentifier because // it's possible someone has multiple FLOATs from this event. access(account) var currentHolders: {UInt64: TokenIdentifier} - pub let dateCreated: UFix64 - pub let description: String + access(all) let dateCreated: UFix64 + access(all) let description: String // This is equal to this resource's uuid - pub let eventId: UInt64 + access(all) let eventId: UInt64 access(account) var extraMetadata: {String: AnyStruct} // The groups that this FLOAT Event belongs to (groups // are within the FLOATEvents resource) access(account) var groups: {String: Bool} // Who created this FLOAT Event - pub let host: Address + access(all) let host: Address // The image of the FLOAT Event - pub let image: String + access(all) let image: String // The name of the FLOAT Event - pub let name: String + access(all) let name: String // The total number of FLOATs that have been // minted from this event - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 // Whether or not the FLOATs that users own // from this event can be transferred on the // FLOAT platform itself (transferring allowed // elsewhere) - pub var transferrable: Bool + access(all) var transferrable: Bool // A url of where the event took place - pub let url: String + access(all) let url: String // A list of verifiers this FLOAT Event contains. // Will be used every time someone "claims" a FLOAT // to see if they pass the requirements @@ -430,20 +512,20 @@ pub contract FLOAT: NonFungibleToken { /***************** Setters for the Event Owner *****************/ // Toggles claiming on/off - pub fun toggleClaimable(): Bool { + access(all) fun toggleClaimable(): Bool { self.claimable = !self.claimable return self.claimable } // Toggles transferring on/off - pub fun toggleTransferrable(): Bool { + access(all) fun toggleTransferrable(): Bool { self.transferrable = !self.transferrable return self.transferrable } // Updates the metadata in case you want // to add something. - pub fun updateMetadata(newExtraMetadata: {String: AnyStruct}) { + access(all) fun updateMetadata(newExtraMetadata: {String: AnyStruct}) { for key in newExtraMetadata.keys { if !self.extraMetadata.containsKey(key) { self.extraMetadata[key] = newExtraMetadata[key] @@ -482,29 +564,29 @@ pub contract FLOAT: NonFungibleToken { // Returns info about the FLOAT that this account claimed // (if any) - pub fun hasClaimed(account: Address): TokenIdentifier? { + access(all) fun hasClaimed(account: Address): TokenIdentifier? { return self.claimed[account] } // This is a guarantee that the person owns the FLOAT // with the passed in serial - pub fun getCurrentHolder(serial: UInt64): TokenIdentifier? { + access(all) fun getCurrentHolder(serial: UInt64): TokenIdentifier? { pre { self.currentHolders[serial] != nil: - "This serial has not been created yet." + "This serial has not been created yet." } let data = self.currentHolders[serial]! - let collection = getAccount(data.address).getCapability(FLOAT.FLOATCollectionPublicPath).borrow<&Collection{CollectionPublic}>() + let collection : &Collection? = getAccount(data.address).capabilities.get<&Collection>(FLOAT.FLOATCollectionPublicPath)!.borrow() if collection?.borrowFLOAT(id: data.id) != nil { return data } - + return nil } // Returns an accurate dictionary of all the // claimers - pub fun getClaimed(): {Address: TokenIdentifier} { + access(all) fun getClaimed(): {Address: TokenIdentifier} { return self.claimed } @@ -513,45 +595,45 @@ pub contract FLOAT: NonFungibleToken { // resource from the public. // Use `getCurrentHolder(serial: UInt64)` to truly // verify if someone holds that serial. - pub fun getCurrentHolders(): {UInt64: TokenIdentifier} { + access(all) fun getCurrentHolders(): {UInt64: TokenIdentifier} { return self.currentHolders } - pub fun getExtraMetadata(): {String: AnyStruct} { + access(all) fun getExtraMetadata(): {String: AnyStruct} { return self.extraMetadata } // Gets all the verifiers that will be used // for claiming - pub fun getVerifiers(): {String: [{IVerifier}]} { + access(all) fun getVerifiers(): {String: [{IVerifier}]} { return self.verifiers } - pub fun getGroups(): [String] { + access(all) fun getGroups(): [String] { return self.groups.keys } - pub fun getViews(): [Type] { - return [ - Type() + access(all) view fun getViews(): [Type] { + return [ + Type() ] } - pub fun getPrices(): {String: TokenInfo}? { + access(all) view fun getPrices(): {String: TokenInfo}? { if let prices = self.extraMetadata["prices"] { return prices as! {String: TokenInfo} } return nil } - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) fun resolveView(_ view: Type): AnyStruct? { switch view { - case Type(): - return MetadataViews.Display( - name: self.name, - description: self.description, - file: MetadataViews.IPFSFile(cid: self.image, path: nil) - ) + case Type(): + return MetadataViews.Display( + name: self.name, + description: self.description, + thumbnail: MetadataViews.IPFSFile(cid: self.image, path: nil) + ) } return nil @@ -561,7 +643,7 @@ pub contract FLOAT: NonFungibleToken { // Will not panic if one of the recipients has already claimed. // It will just skip them. - pub fun batchMint(recipients: [&Collection{NonFungibleToken.CollectionPublic}]) { + access(all) fun batchMint(recipients: [&Collection]) { for recipient in recipients { if self.claimed[recipient.owner!.address] == nil { self.mint(recipient: recipient) @@ -578,10 +660,10 @@ pub contract FLOAT: NonFungibleToken { // run the verifiers on the user. It bypasses all of them. // // Return the id of the FLOAT it minted - pub fun mint(recipient: &Collection{NonFungibleToken.CollectionPublic}): UInt64 { + access(all) fun mint(recipient: &Collection): UInt64 { pre { self.claimed[recipient.owner!.address] == nil: - "This person already claimed their FLOAT!" + "This person already claimed their FLOAT!" } let recipientAddr: Address = recipient.owner!.address let serial = self.totalSupply @@ -616,21 +698,25 @@ pub contract FLOAT: NonFungibleToken { } access(account) fun verifyAndMint(recipient: &Collection, params: {String: AnyStruct}): UInt64 { - params["event"] = &self as &FLOATEvent{FLOATEventPublic} + params["event"] = &self as &FLOATEvent params["claimee"] = recipient.owner!.address - + // Runs a loop over all the verifiers that this FLOAT Events // implements. For example, "Limited", "Timelock", "Secret", etc. // All the verifiers are in the FLOATVerifiers.cdc contract + /* TODO:: do not bother fixing this now for identifier in self.verifiers.keys { let typedModules = (&self.verifiers[identifier] as &[{IVerifier}]?)! var i = 0 + while i < typedModules.length { - let verifier = &typedModules[i] as &{IVerifier} + //Dont know how to fix this + let verifier = &typedModules[i] as {FLOAT.IVerifier} verifier.verify(params) i = i + 1 } } + */ // You're good to go. let id = self.mint(recipient: recipient) @@ -654,49 +740,48 @@ pub contract FLOAT: NonFungibleToken { // For example, the FLOAT platform allows event hosts // to specify a secret phrase. That secret phrase will // be passed in the `params`. - pub fun claim(recipient: &Collection, params: {String: AnyStruct}) { + access(all) fun claim(recipient: &Collection, params: {String: AnyStruct}) { pre { - self.getPrices() == nil: - "You need to purchase this FLOAT." - self.claimed[recipient.owner!.address] == nil: - "This person already claimed their FLOAT!" - self.claimable: - "This FLOATEvent is not claimable, and thus not currently active." + self.claimed[recipient.owner!.address] == nil: "This person already claimed their FLOAT!" + self.claimable: "This FLOATEvent is not claimable, and thus not currently active." + } + + if (self.getPrices() != nil) { + panic("This FLOATEvent is not free. Use the purchase function instead.") } - self.verifyAndMint(recipient: recipient, params: params) } - - pub fun purchase(recipient: &Collection, params: {String: AnyStruct}, payment: @FungibleToken.Vault) { + + access(all) fun purchase(recipient: &Collection, params: {String: AnyStruct}, payment: @{FungibleToken.Vault}) { pre { self.getPrices() != nil: - "Don't call this function. The FLOAT is free." - self.getPrices()![payment.getType().identifier] != nil: - "This FLOAT does not support purchasing in the passed in token." - payment.balance == self.getPrices()![payment.getType().identifier]!.price: - "You did not pass in the correct amount of tokens." + "Don't call this function. The FLOAT is free." self.claimed[recipient.owner!.address] == nil: - "This person already claimed their FLOAT!" + "This person already claimed their FLOAT!" self.claimable: - "This FLOATEvent is not claimable, and thus not currently active." + "This FLOATEvent is not claimable, and thus not currently active." + } + if (self.getPrices()![payment.getType().identifier] == nil) { + panic("This FLOAT does not support purchasing in the passed in token.") + } + if (payment.balance != self.getPrices()![payment.getType().identifier]!.price) { + panic("You did not pass in the correct amount of tokens.") } let royalty: UFix64 = 0.05 let emeraldCityTreasury: Address = 0x5643fd47a29770e7 let paymentType: String = payment.getType().identifier let tokenInfo: TokenInfo = self.getPrices()![paymentType]! - let EventHostVault = getAccount(self.host).getCapability(tokenInfo.path) - .borrow<&{FungibleToken.Receiver}>() - ?? panic("Could not borrow the &{FungibleToken.Receiver} from the event host.") + let EventHostVault = getAccount(self.host).capabilities.get<&{FungibleToken.Receiver}>(tokenInfo.path)!.borrow() + ?? panic("Could not borrow the &{FungibleToken.Receiver} from the event host.") assert( EventHostVault.getType().identifier == paymentType, message: "The event host's path is not associated with the intended token." ) - - let EmeraldCityVault = getAccount(emeraldCityTreasury).getCapability(tokenInfo.path) - .borrow<&{FungibleToken.Receiver}>() - ?? panic("Could not borrow the &{FungibleToken.Receiver} from Emerald City's Vault.") + + let EmeraldCityVault = getAccount(emeraldCityTreasury).capabilities.get<&{FungibleToken.Receiver}>(tokenInfo.path)!.borrow() + ?? panic("Could not borrow the &{FungibleToken.Receiver} from Emerald City's Vault.") assert( EmeraldCityVault.getType().identifier == paymentType, @@ -744,18 +829,15 @@ pub contract FLOAT: NonFungibleToken { emit FLOATEventCreated(eventId: self.eventId, description: self.description, host: self.host, image: self.image, name: self.name, url: self.url) } - destroy() { - emit FLOATEventDestroyed(eventId: self.eventId, host: self.host, name: self.name) - } } // A container of FLOAT Events (maybe because they're similar to // one another, or an event host wants to list all their AMAs together, etc). - pub resource Group { - pub let id: UInt64 - pub let name: String - pub let image: String - pub let description: String + access(all) resource Group { + access(all) let id: UInt64 + access(all) let name: String + access(all) let image: String + access(all) let description: String // All the FLOAT Events that belong // to this group. access(account) var events: {UInt64: Bool} @@ -768,7 +850,7 @@ pub contract FLOAT: NonFungibleToken { self.events.remove(key: eventId) } - pub fun getEvents(): [UInt64] { + access(all) fun getEvents(): [UInt64] { return self.events.keys } @@ -780,23 +862,23 @@ pub contract FLOAT: NonFungibleToken { self.events = {} } } - + // // FLOATEvents // - pub resource interface FLOATEventsPublic { + access(all) resource interface FLOATEventsPublic { // Public Getters - pub fun borrowPublicEventRef(eventId: UInt64): &FLOATEvent{FLOATEventPublic}? - pub fun getAllEvents(): {UInt64: String} - pub fun getIDs(): [UInt64] - pub fun getGroup(groupName: String): &Group? - pub fun getGroups(): [String] + access(all) fun borrowPublicEventRef(eventId: UInt64): &FLOATEvent? + access(all) fun getAllEvents(): {UInt64: String} + access(all) view fun getIDs(): [UInt64] + access(all) fun getGroup(groupName: String): &Group? + access(all) fun getGroups(): [String] // Account Getters access(account) fun borrowEventsRef(): &FLOATEvents } // A "Collection" of FLOAT Events - pub resource FLOATEvents: FLOATEventsPublic, MetadataViews.ResolverCollection { + access(all) resource FLOATEvents: FLOATEventsPublic, ViewResolver.ResolverCollection { // All the FLOAT Events this collection stores access(account) var events: @{UInt64: FLOATEvent} // All the Groups this collection stores @@ -804,7 +886,7 @@ pub contract FLOAT: NonFungibleToken { // Creates a new FLOAT Event by passing in some basic parameters // and a list of all the verifiers this event must abide by - pub fun createEvent( + access(all) fun createEvent( claimable: Bool, description: String, image: String, @@ -847,16 +929,16 @@ pub contract FLOAT: NonFungibleToken { // Deletes an event. Also makes sure to remove // the event from all the groups its in. - pub fun deleteEvent(eventId: UInt64) { - let event <- self.events.remove(key: eventId) ?? panic("This event does not exist") - for groupName in event.getGroups() { + access(all) fun deleteEvent(eventId: UInt64) { + let eventRes <- self.events.remove(key: eventId) ?? panic("This event does not exist") + for groupName in eventRes.getGroups() { let groupRef = (&self.groups[groupName] as &Group?)! groupRef.removeEvent(eventId: eventId) } - destroy event + destroy eventRes } - pub fun createGroup(groupName: String, image: String, description: String) { + access(all) fun createGroup(groupName: String, image: String, description: String) { pre { self.groups[groupName] == nil: "A group with this name already exists." } @@ -865,9 +947,9 @@ pub contract FLOAT: NonFungibleToken { // Deletes a group. Also makes sure to remove // the group from all the events that use it. - pub fun deleteGroup(groupName: String) { + access(all) fun deleteGroup(groupName: String) { let eventsInGroup = self.groups[groupName]?.getEvents() - ?? panic("This Group does not exist.") + ?? panic("This Group does not exist.") for eventId in eventsInGroup { let ref = (&self.events[eventId] as &FLOATEvent?)! ref.removeFromGroup(groupName: groupName) @@ -877,7 +959,7 @@ pub contract FLOAT: NonFungibleToken { // Adds an event to a group. Also adds the group // to the event. - pub fun addEventToGroup(groupName: String, eventId: UInt64) { + access(all) fun addEventToGroup(groupName: String, eventId: UInt64) { pre { self.groups[groupName] != nil: "This group does not exist." self.events[eventId] != nil: "This event does not exist." @@ -890,7 +972,7 @@ pub contract FLOAT: NonFungibleToken { } // Simply takes the event away from the group - pub fun removeEventFromGroup(groupName: String, eventId: UInt64) { + access(all) fun removeEventFromGroup(groupName: String, eventId: UInt64) { pre { self.groups[groupName] != nil: "This group does not exist." self.events[eventId] != nil: "This event does not exist." @@ -902,14 +984,14 @@ pub contract FLOAT: NonFungibleToken { eventRef.removeFromGroup(groupName: groupName) } - pub fun getGroup(groupName: String): &Group? { + access(all) fun getGroup(groupName: String): &Group? { if self.groups[groupName] != nil { return &self.groups[groupName] as &Group? } return nil } - - pub fun getGroups(): [String] { + + access(all) fun getGroups(): [String] { return self.groups.keys } @@ -917,17 +999,15 @@ pub contract FLOAT: NonFungibleToken { // If `fromHost` has allowed you to share your account // in the GrantedAccountAccess.cdc contract, you can get a reference // to their FLOATEvents here and do pretty much whatever you want. - pub fun borrowSharedRef(fromHost: Address): &FLOATEvents { - let sharedInfo = getAccount(fromHost).getCapability(GrantedAccountAccess.InfoPublicPath) - .borrow<&GrantedAccountAccess.Info{GrantedAccountAccess.InfoPublic}>() - ?? panic("Cannot borrow the InfoPublic from the host") + access(all) fun borrowSharedRef(fromHost: Address): &FLOATEvents { + let sharedInfo = getAccount(fromHost).capabilities.get<&GrantedAccountAccess.Info>(GrantedAccountAccess.InfoPublicPath)!.borrow() + ?? panic("Cannot borrow the InfoPublic from the host") assert( sharedInfo.isAllowed(account: self.owner!.address), message: "This account owner does not share their account with you." ) - let otherFLOATEvents = getAccount(fromHost).getCapability(FLOAT.FLOATEventsPublicPath) - .borrow<&FLOATEvents{FLOATEventsPublic}>() - ?? panic("Could not borrow the public FLOATEvents.") + let otherFLOATEvents = getAccount(fromHost).capabilities.get<&FLOATEvents>(FLOAT.FLOATEventsPublicPath)!.borrow() + ?? panic("Could not borrow the public FLOATEvents.") return otherFLOATEvents.borrowEventsRef() } @@ -936,7 +1016,7 @@ pub contract FLOAT: NonFungibleToken { return &self as &FLOATEvents } - pub fun borrowEventRef(eventId: UInt64): &FLOATEvent? { + access(all) fun borrowEventRef(eventId: UInt64): &FLOATEvent? { if self.events[eventId] != nil { return &self.events[eventId] as &FLOATEvent? } @@ -947,20 +1027,20 @@ pub contract FLOAT: NonFungibleToken { // Get a public reference to the FLOATEvent // so you can call some helpful getters - pub fun borrowPublicEventRef(eventId: UInt64): &FLOATEvent{FLOATEventPublic}? { + access(all) fun borrowPublicEventRef(eventId: UInt64): &FLOATEvent? { if self.events[eventId] != nil { - return &self.events[eventId] as &FLOATEvent{FLOATEventPublic}? + return &self.events[eventId] as &FLOATEvent? } return nil } - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.events.keys } // Maps the eventId to the name of that // event. Just a kind helper. - pub fun getAllEvents(): {UInt64: String} { + access(all) fun getAllEvents(): {UInt64: String} { let answer: {UInt64: String} = {} for id in self.events.keys { let ref = (&self.events[id] as &FLOATEvent?)! @@ -969,8 +1049,8 @@ pub contract FLOAT: NonFungibleToken { return answer } - pub fun borrowViewResolver(id: UInt64): &{MetadataViews.Resolver} { - return (&self.events[id] as &{MetadataViews.Resolver}?)! + access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} { + return (&self.events[id] as &{ViewResolver.Resolver}?)! } init() { @@ -978,17 +1058,13 @@ pub contract FLOAT: NonFungibleToken { self.groups <- {} } - destroy() { - destroy self.events - destroy self.groups - } } - pub fun createEmptyCollection(): @Collection { + access(all) fun createEmptyCollection(): @Collection { return <- create Collection() } - pub fun createEmptyFLOATEventCollection(): @FLOATEvents { + access(all) fun createEmptyFLOATEventCollection(): @FLOATEvents { return <- create FLOATEvents() } diff --git a/contracts/standard/FLOATVerifiers.cdc b/contracts/standard/FLOATVerifiers.cdc index 6448cd4e..0195e6a3 100644 --- a/contracts/standard/FLOATVerifiers.cdc +++ b/contracts/standard/FLOATVerifiers.cdc @@ -20,24 +20,24 @@ // of the secret code through. For Limited, we need to know the totalSupply of the event, // so we pass it through as well. -import FLOAT from "./FLOAT.cdc" +import "FLOAT" -pub contract FLOATVerifiers { +access(all) contract FLOATVerifiers { // The "verifiers" to be used - + // // Timelock // // Specifies a time range in which the // FLOAT from an event can be claimed - pub struct Timelock: FLOAT.IVerifier { + access(all) struct Timelock: FLOAT.IVerifier { // An automatic switch handled by the contract // to stop people from claiming after a certain time. - pub let dateStart: UFix64 - pub let dateEnding: UFix64 + access(all) let dateStart: UFix64 + access(all) let dateEnding: UFix64 - pub fun verify(_ params: {String: AnyStruct}) { + access(all) fun verify(_ params: {String: AnyStruct}) { assert( getCurrentBlock().timestamp >= self.dateStart, message: "This FLOAT Event has not started yet." @@ -59,11 +59,11 @@ pub contract FLOATVerifiers { // // Specifies a secret code in order // to claim a FLOAT (not very secure, but cool feature) - pub struct Secret: FLOAT.IVerifier { + access(all) struct Secret: FLOAT.IVerifier { // The secret code, set by the owner of this event. access(self) let secretPhrase: String - pub fun verify(_ params: {String: AnyStruct}) { + access(all) fun verify(_ params: {String: AnyStruct}) { let secretPhrase = params["secretPhrase"]! as! String assert( self.secretPhrase == secretPhrase, @@ -83,12 +83,12 @@ pub contract FLOATVerifiers { // who can CLAIM. Not to be confused with how many currently // hold a FLOAT from this event, since users can // delete their FLOATs. - pub struct Limited: FLOAT.IVerifier { - pub var capacity: UInt64 + access(all) struct Limited: FLOAT.IVerifier { + access(all) var capacity: UInt64 - pub fun verify(_ params: {String: AnyStruct}) { - let event = params["event"]! as! &FLOAT.FLOATEvent{FLOAT.FLOATEventPublic} - let currentCapacity = event.totalSupply + access(all) fun verify(_ params: {String: AnyStruct}) { + let e = params["event"]! as! &FLOAT.FLOATEvent + let currentCapacity = e.totalSupply assert( currentCapacity < self.capacity, message: "This FLOAT Event is at capacity." @@ -106,10 +106,10 @@ pub contract FLOATVerifiers { // Allows for Multiple Secret codes // Everytime a secret gets used, it gets removed // from the list. - pub struct MultipleSecret: FLOAT.IVerifier { + access(all) struct MultipleSecret: FLOAT.IVerifier { access(self) let secrets: {String: Bool} - pub fun verify(_ params: {String: AnyStruct}) { + access(all) fun verify(_ params: {String: AnyStruct}) { let secretPhrase = params["secretPhrase"]! as! String assert( self.secrets[secretPhrase] != nil, @@ -125,4 +125,4 @@ pub contract FLOATVerifiers { } } } -} \ No newline at end of file +} diff --git a/contracts/standard/FUSD.cdc b/contracts/standard/FUSD.cdc deleted file mode 100644 index f2691c85..00000000 --- a/contracts/standard/FUSD.cdc +++ /dev/null @@ -1,209 +0,0 @@ -import FungibleToken from "./FungibleToken.cdc" - -pub contract FUSD: FungibleToken { - - // Event that is emitted when the contract is created - pub event TokensInitialized(initialSupply: UFix64) - - // Event that is emitted when tokens are withdrawn from a Vault - pub event TokensWithdrawn(amount: UFix64, from: Address?) - - // Event that is emitted when tokens are deposited to a Vault - pub event TokensDeposited(amount: UFix64, to: Address?) - - // Event that is emitted when new tokens are minted - pub event TokensMinted(amount: UFix64) - - // The storage path for the admin resource - pub let AdminStoragePath: StoragePath - - // The storage Path for minters' MinterProxy - pub let MinterProxyStoragePath: StoragePath - - // The public path for minters' MinterProxy capability - pub let MinterProxyPublicPath: PublicPath - - // Event that is emitted when a new minter resource is created - pub event MinterCreated() - - // Total supply of fusd in existence - pub var totalSupply: UFix64 - - // Vault - // - // Each user stores an instance of only the Vault in their storage - // The functions in the Vault are governed by the pre and post conditions - // in FungibleToken when they are called. - // The checks happen at runtime whenever a function is called. - // - // Resources can only be created in the context of the contract that they - // are defined in, so there is no way for a malicious user to create Vaults - // out of thin air. A special Minter resource needs to be defined to mint - // new tokens. - // - pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance { - - // holds the balance of a users tokens - pub var balance: UFix64 - - // initialize the balance at resource creation time - init(balance: UFix64) { - self.balance = balance - } - - // withdraw - // - // Function that takes an integer amount as an argument - // and withdraws that amount from the Vault. - // It creates a new temporary Vault that is used to hold - // the money that is being transferred. It returns the newly - // created Vault to the context that called so it can be deposited - // elsewhere. - // - pub fun withdraw(amount: UFix64): @FungibleToken.Vault { - self.balance = self.balance - amount - emit TokensWithdrawn(amount: amount, from: self.owner?.address) - return <-create Vault(balance: amount) - } - - // deposit - // - // Function that takes a Vault object as an argument and adds - // its balance to the balance of the owners Vault. - // It is allowed to destroy the sent Vault because the Vault - // was a temporary holder of the tokens. The Vault's balance has - // been consumed and therefore can be destroyed. - pub fun deposit(from: @FungibleToken.Vault) { - let vault <- from as! @FUSD.Vault - self.balance = self.balance + vault.balance - emit TokensDeposited(amount: vault.balance, to: self.owner?.address) - vault.balance = 0.0 - destroy vault - } - - destroy() { - FUSD.totalSupply = FUSD.totalSupply - self.balance - } - } - - // createEmptyVault - // - // Function that creates a new Vault with a balance of zero - // and returns it to the calling context. A user must call this function - // and store the returned Vault in their storage in order to allow their - // account to be able to receive deposits of this token type. - // - pub fun createEmptyVault(): @FUSD.Vault { - return <-create Vault(balance: 0.0) - } - - // Minter - // - // Resource object that can mint new tokens. - // The admin stores this and passes it to the minter account as a capability wrapper resource. - // - pub resource Minter { - - // mintTokens - // - // Function that mints new tokens, adds them to the total supply, - // and returns them to the calling context. - // - pub fun mintTokens(amount: UFix64): @FUSD.Vault { - pre { - amount > 0.0: "Amount minted must be greater than zero" - } - FUSD.totalSupply = FUSD.totalSupply + amount - emit TokensMinted(amount: amount) - return <-create Vault(balance: amount) - } - - } - - pub resource interface MinterProxyPublic { - pub fun setMinterCapability(cap: Capability<&Minter>) - } - - // MinterProxy - // - // Resource object holding a capability that can be used to mint new tokens. - // The resource that this capability represents can be deleted by the admin - // in order to unilaterally revoke minting capability if needed. - - pub resource MinterProxy: MinterProxyPublic { - - // access(self) so nobody else can copy the capability and use it. - access(self) var minterCapability: Capability<&Minter>? - - // Anyone can call this, but only the admin can create Minter capabilities, - // so the type system constrains this to being called by the admin. - pub fun setMinterCapability(cap: Capability<&Minter>) { - self.minterCapability = cap - } - - pub fun mintTokens(amount: UFix64): @FUSD.Vault { - return <- self.minterCapability! - .borrow()! - .mintTokens(amount:amount) - } - - init() { - self.minterCapability = nil - } - - } - - // createMinterProxy - // - // Function that creates a MinterProxy. - // Anyone can call this, but the MinterProxy cannot mint without a Minter capability, - // and only the admin can provide that. - // - pub fun createMinterProxy(): @MinterProxy { - return <- create MinterProxy() - } - - // Administrator - // - // A resource that allows new minters to be created - // - // We will only want one minter for now, but might need to add or replace them in future. - // The Minter/Minter Proxy structure enables this. - // Ideally we would create this structure in a single function, generate the paths from the address - // and cache all of this information to enable easy revocation but String/Path comversion isn't yet supported. - // - pub resource Administrator { - - // createNewMinter - // - // Function that creates a Minter resource. - // This should be stored at a unique path in storage then a capability to it wrapped - // in a MinterProxy to be stored in a minter account's storage. - // This is done by the minter account running: - // transactions/FUSD/minter/setup_minter_account.cdc - // then the admin account running: - // transactions/flowArcaddeToken/admin/deposit_minter_capability.cdc - // - pub fun createNewMinter(): @Minter { - emit MinterCreated() - return <- create Minter() - } - - } - - //Modified from source, to make it easier to work with locally - init() { - let adminAccount =self.account - self.AdminStoragePath = /storage/fusdAdmin - self.MinterProxyPublicPath = /public/fusdMinterProxy - self.MinterProxyStoragePath = /storage/fusdMinterProxy - - self.totalSupply = 0.0 - - let admin <- create Administrator() - adminAccount.save(<-admin, to: self.AdminStoragePath) - - // Emit an event that shows that the contract was initialized - emit TokensInitialized(initialSupply: 0.0) - } -} diff --git a/contracts/standard/FeeEstimator.cdc b/contracts/standard/FeeEstimator.cdc index 82e37da2..9c86a254 100644 --- a/contracts/standard/FeeEstimator.cdc +++ b/contracts/standard/FeeEstimator.cdc @@ -1,62 +1,54 @@ -import FungibleToken from "./FungibleToken.cdc" -import FlowStorageFees from "./FlowStorageFees.cdc" -import FlowToken from "./FlowToken.cdc" +import "FungibleToken" +import "FlowStorageFees" +import "FlowToken" /* - FeeEstimator - - Small contract that allows other contracts to estimate how much storage cost a resource might take up. - This is done by storing a resource in the FeeEstimator, recording the difference in available balance, - then returning the difference and the original item being estimated. - - Consumers of this contract would then need to pop the resource out of the DepositEstimate resource to get it back - */ -pub contract FeeEstimator { - pub resource DepositEstimate { - pub var item: @AnyResource? - pub var storageFee: UFix64 +FeeEstimator + +Small contract that allows other contracts to estimate how much storage cost a resource might take up. +This is done by storing a resource in the FeeEstimator, recording the difference in available balance, +then returning the difference and the original item being estimated. + +Consumers of this contract would then need to pop the resource out of the DepositEstimate resource to get it back +*/ +access(all) contract FeeEstimator { + access(all) resource DepositEstimate { + access(all) var item: @AnyResource? + access(all) var storageFee: UFix64 init(item: @AnyResource, storageFee: UFix64) { self.item <- item self.storageFee = storageFee } - pub fun withdraw(): @AnyResource { - let resource <- self.item <- nil - return <-resource! - } - - destroy() { - pre { - self.item == nil: "cannot destroy with non-null item" - } - - destroy self.item + access(all) fun withdraw(): @AnyResource { + let r <- self.item <- nil + return <-r! } } - pub fun hasStorageCapacity(_ addr: Address, _ storageFee: UFix64): Bool { + access(all) fun hasStorageCapacity(_ addr: Address, _ storageFee: UFix64): Bool { return FlowStorageFees.defaultTokenAvailableBalance(addr) > storageFee } - pub fun estimateDeposit( + access(all) fun estimateDeposit( item: @AnyResource, ): @DepositEstimate { - let storageUsedBefore = FeeEstimator.account.storageUsed - FeeEstimator.account.save(<-item, to: /storage/temp) - let storageUsedAfter = FeeEstimator.account.storageUsed + let storageUsedBefore = FeeEstimator.account.storage.used + FeeEstimator.account.storage.save(<-item, to: /storage/temp) + let storageUsedAfter = FeeEstimator.account.storage.used let storageDiff = storageUsedAfter - storageUsedBefore let storageFee = FeeEstimator.storageUsedToFlowAmount(storageDiff) - let loadedItem <- FeeEstimator.account.load<@AnyResource>(from: /storage/temp)! + let loadedItem <- FeeEstimator.account.storage.load<@AnyResource>(from: /storage/temp)! let estimate <- create DepositEstimate(item: <-loadedItem, storageFee: storageFee) return <- estimate } - pub fun storageUsedToFlowAmount(_ storageUsed: UInt64): UFix64 { + access(all) fun storageUsedToFlowAmount(_ storageUsed: UInt64): UFix64 { let storageMB = FlowStorageFees.convertUInt64StorageBytesToUFix64Megabytes(storageUsed) return FlowStorageFees.storageCapacityToFlow(storageMB) } init() {} -} \ No newline at end of file +} diff --git a/contracts/standard/FiatToken.cdc b/contracts/standard/FiatToken.cdc deleted file mode 100644 index 83a3db3c..00000000 --- a/contracts/standard/FiatToken.cdc +++ /dev/null @@ -1,222 +0,0 @@ -import FungibleToken from "./FungibleToken.cdc" - -//NB NB NB! -// THis is a local mocked version of USDC FiatToken that is basically a clone of FUSD just to make it easier to test with -//the paths are copied from the testnet version - -pub contract FiatToken: FungibleToken { - - // Event that is emitted when the contract is created - pub event TokensInitialized(initialSupply: UFix64) - - // Event that is emitted when tokens are withdrawn from a Vault - pub event TokensWithdrawn(amount: UFix64, from: Address?) - - // Event that is emitted when tokens are deposited to a Vault - pub event TokensDeposited(amount: UFix64, to: Address?) - - // Event that is emitted when new tokens are minted - pub event TokensMinted(amount: UFix64) - - // The storage path for the admin resource - pub let AdminStoragePath: StoragePath - - // The storage Path for minters' MinterProxy - pub let MinterProxyStoragePath: StoragePath - - // The public path for minters' MinterProxy capability - pub let MinterProxyPublicPath: PublicPath - - // Event that is emitted when a new minter resource is created - pub event MinterCreated() - - // Total supply of fusd in existence - pub var totalSupply: UFix64 - - - //paths copied from Fiattoken https://github.com/flow-usdc/flow-usdc/blob/main/contracts/FiatToken.cdc - pub let VaultStoragePath: StoragePath - pub let VaultBalancePubPath: PublicPath - pub let VaultUUIDPubPath: PublicPath - pub let VaultReceiverPubPath: PublicPath - - // Vault - // - // Each user stores an instance of only the Vault in their storage - // The functions in the Vault are governed by the pre and post conditions - // in FungibleToken when they are called. - // The checks happen at runtime whenever a function is called. - // - // Resources can only be created in the context of the contract that they - // are defined in, so there is no way for a malicious user to create Vaults - // out of thin air. A special Minter resource needs to be defined to mint - // new tokens. - // - - pub resource interface ResourceId { - pub fun UUID(): UInt64 - } - - pub resource Vault: ResourceId, FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance { - - // holds the balance of a users tokens - pub var balance: UFix64 - - // initialize the balance at resource creation time - init(balance: UFix64) { - self.balance = balance - } - - pub fun UUID(): UInt64 { - return self.uuid - } - // withdraw - // - // Function that takes an integer amount as an argument - // and withdraws that amount from the Vault. - // It creates a new temporary Vault that is used to hold - // the money that is being transferred. It returns the newly - // created Vault to the context that called so it can be deposited - // elsewhere. - // - pub fun withdraw(amount: UFix64): @FungibleToken.Vault { - self.balance = self.balance - amount - emit TokensWithdrawn(amount: amount, from: self.owner?.address) - return <-create Vault(balance: amount) - } - - // deposit - // - // Function that takes a Vault object as an argument and adds - // its balance to the balance of the owners Vault. - // It is allowed to destroy the sent Vault because the Vault - // was a temporary holder of the tokens. The Vault's balance has - // been consumed and therefore can be destroyed. - pub fun deposit(from: @FungibleToken.Vault) { - let vault <- from as! @FiatToken.Vault - self.balance = self.balance + vault.balance - emit TokensDeposited(amount: vault.balance, to: self.owner?.address) - vault.balance = 0.0 - destroy vault - } - - destroy() { - FiatToken.totalSupply = FiatToken.totalSupply - self.balance - } - } - - // createEmptyVault - // - // Function that creates a new Vault with a balance of zero - // and returns it to the calling context. A user must call this function - // and store the returned Vault in their storage in order to allow their - // account to be able to receive deposits of this token type. - // - pub fun createEmptyVault(): @FiatToken.Vault { - return <-create Vault(balance: 0.0) - } - - // Minter - // - // Resource object that can mint new tokens. - // The admin stores this and passes it to the minter account as a capability wrapper resource. - // - pub resource Minter { - - // mintTokens - // - // Function that mints new tokens, adds them to the total supply, - // and returns them to the calling context. - // - pub fun mintTokens(amount: UFix64): @Vault { - pre { - amount > 0.0: "Amount minted must be greater than zero" - } - FiatToken.totalSupply = FiatToken.totalSupply + amount - emit TokensMinted(amount: amount) - return <-create Vault(balance: amount) - } - - } - - pub resource interface MinterProxyPublic { - pub fun setMinterCapability(cap: Capability<&Minter>) - } - - // MinterProxy - // - // Resource object holding a capability that can be used to mint new tokens. - // The resource that this capability represents can be deleted by the admin - // in order to unilaterally revoke minting capability if needed. - - pub resource MinterProxy: MinterProxyPublic { - - // access(self) so nobody else can copy the capability and use it. - access(self) var minterCapability: Capability<&Minter>? - - // Anyone can call this, but only the admin can create Minter capabilities, - // so the type system constrains this to being called by the admin. - pub fun setMinterCapability(cap: Capability<&Minter>) { - self.minterCapability = cap - } - - pub fun mintTokens(amount: UFix64): @FiatToken.Vault { - return <- self.minterCapability! - .borrow()! - .mintTokens(amount:amount) - } - - init() { - self.minterCapability = nil - } - - } - - // createMinterProxy - // - // Function that creates a MinterProxy. - // Anyone can call this, but the MinterProxy cannot mint without a Minter capability, - // and only the admin can provide that. - // - pub fun createMinterProxy(): @MinterProxy { - return <- create MinterProxy() - } - - // Administrator - // - // A resource that allows new minters to be created - // - // We will only want one minter for now, but might need to add or replace them in future. - // The Minter/Minter Proxy structure enables this. - // Ideally we would create this structure in a single function, generate the paths from the address - // and cache all of this information to enable easy revocation but String/Path comversion isn't yet supported. - // - pub resource Administrator { - pub fun createNewMinter(): @Minter { - emit MinterCreated() - return <- create Minter() - } - - } - - init() { - let adminAccount =self.account - self.AdminStoragePath = /storage/fiatAdmin - self.MinterProxyPublicPath = /public/fiatMinterProxy - self.MinterProxyStoragePath = /storage/fiatMinterProxy - - self.totalSupply = 0.0 - - let admin <- create Administrator() - adminAccount.save(<-admin, to: self.AdminStoragePath) - - // Emit an event that shows that the contract was initialized - emit TokensInitialized(initialSupply: 0.0) - - self.VaultStoragePath= /storage/USDCVault - self.VaultBalancePubPath = /public/USDCVaultBalance - self.VaultUUIDPubPath = /public/USDCVaultUUID - self.VaultReceiverPubPath = /public/USDCVaultReceiver - - } -} diff --git a/contracts/standard/FlowStorageFees.cdc b/contracts/standard/FlowStorageFees.cdc index c3bafb35..6451ca1e 100644 --- a/contracts/standard/FlowStorageFees.cdc +++ b/contracts/standard/FlowStorageFees.cdc @@ -1,56 +1,56 @@ /* - * The FlowStorageFees smart contract - * - * An account's storage capacity determines up to how much storage on chain it can use. - * A storage capacity is calculated by multiplying the amount of reserved flow with `StorageFee.storageMegaBytesPerReservedFLOW` - * The minimum amount of flow tokens reserved for storage capacity is `FlowStorageFees.minimumStorageReservation` this is paid during account creation, by the creator. - * - * At the end of all transactions, any account that had any value changed in their storage - * has their storage capacity checked against their storage used and their main flow token vault against the minimum reservation. - * If any account fails this check the transaction wil fail. - * - * An account moving/deleting its `FlowToken.Vault` resource will result - * in the transaction failing because the account will have no storage capacity. - * - */ - -import FungibleToken from "./FungibleToken.cdc" -import FlowToken from "./FlowToken.cdc" - -pub contract FlowStorageFees { +* The FlowStorageFees smart contract +* +* An account's storage capacity determines up to how much storage on chain it can use. +* A storage capacity is calculated by multiplying the amount of reserved flow with `StorageFee.storageMegaBytesPerReservedFLOW` +* The minimum amount of flow tokens reserved for storage capacity is `FlowStorageFees.minimumStorageReservation` this is paid during account creation, by the creator. +* +* At the end of all transactions, any account that had any value changed in their storage +* has their storage capacity checked against their storage used and their main flow token vault against the minimum reservation. +* If any account fails this check the transaction wil fail. +* +* An account moving/deleting its `FlowToken.Vault` resource will result +* in the transaction failing because the account will have no storage capacity. +* +*/ + +import "FungibleToken" +import "FlowToken" + +access(all) contract FlowStorageFees { // Emitted when the amount of storage capacity an account has per reserved Flow token changes - pub event StorageMegaBytesPerReservedFLOWChanged(_ storageMegaBytesPerReservedFLOW: UFix64) + access(all) event StorageMegaBytesPerReservedFLOWChanged(_ storageMegaBytesPerReservedFLOW: UFix64) // Emitted when the minimum amount of Flow tokens that an account needs to have reserved for storage capacity changes. - pub event MinimumStorageReservationChanged(_ minimumStorageReservation: UFix64) + access(all) event MinimumStorageReservationChanged(_ minimumStorageReservation: UFix64) // Defines how much storage capacity every account has per reserved Flow token. // definition is written per unit of flow instead of the inverse, // so there is no loss of precision calculating storage from flow, // but there is loss of precision when calculating flow per storage. - pub var storageMegaBytesPerReservedFLOW: UFix64 + access(all) var storageMegaBytesPerReservedFLOW: UFix64 // Defines the minimum amount of Flow tokens that every account needs to have reserved for storage capacity. // If an account has less then this amount reserved by the end of any transaction it participated in, the transaction will fail. - pub var minimumStorageReservation: UFix64 + access(all) var minimumStorageReservation: UFix64 // An administrator resource that can change the parameters of the FlowStorageFees smart contract. - pub resource Administrator { + access(all) resource Administrator { // Changes the amount of storage capacity an account has per accounts' reserved storage FLOW. - pub fun setStorageMegaBytesPerReservedFLOW(_ storageMegaBytesPerReservedFLOW: UFix64) { + access(all) fun setStorageMegaBytesPerReservedFLOW(_ storageMegaBytesPerReservedFLOW: UFix64) { if FlowStorageFees.storageMegaBytesPerReservedFLOW == storageMegaBytesPerReservedFLOW { - return + return } FlowStorageFees.storageMegaBytesPerReservedFLOW = storageMegaBytesPerReservedFLOW emit StorageMegaBytesPerReservedFLOWChanged(storageMegaBytesPerReservedFLOW) } // Changes the minimum amount of FLOW an account has to have reserved. - pub fun setMinimumStorageReservation(_ minimumStorageReservation: UFix64) { + access(all) fun setMinimumStorageReservation(_ minimumStorageReservation: UFix64) { if FlowStorageFees.minimumStorageReservation == minimumStorageReservation { - return + return } FlowStorageFees.minimumStorageReservation = minimumStorageReservation emit MinimumStorageReservationChanged(minimumStorageReservation) @@ -60,10 +60,8 @@ pub contract FlowStorageFees { } // Returns megabytes - pub fun calculateAccountCapacity(_ accountAddress: Address): UFix64 { - let balanceRef = getAccount(accountAddress) - .getCapability<&FlowToken.Vault{FungibleToken.Balance}>(/public/flowTokenBalance)! - .borrow() ?? panic("Could not borrow FLOW balance capability") + access(all) fun calculateAccountCapacity(_ accountAddress: Address): UFix64 { + let balanceRef = getAccount(accountAddress).capabilities.borrow<&{FungibleToken.Vault}>(/public/flowTokenBalance) ?? panic("Could not borrow FLOW balance capability") // get address token balance if balanceRef.balance < self.minimumStorageReservation { @@ -77,39 +75,38 @@ pub contract FlowStorageFees { // Amount in Flow tokens // Returns megabytes - pub fun flowToStorageCapacity(_ amount: UFix64): UFix64 { + access(all) fun flowToStorageCapacity(_ amount: UFix64): UFix64 { return amount * FlowStorageFees.storageMegaBytesPerReservedFLOW } // Amount in megabytes // Returns Flow tokens - pub fun storageCapacityToFlow(_ amount: UFix64): UFix64 { + access(all) fun storageCapacityToFlow(_ amount: UFix64): UFix64 { // possible loss of precision // putting the result back into `flowToStorageCapacity` might not yield the same result return amount / FlowStorageFees.storageMegaBytesPerReservedFLOW } // converts storage used from UInt64 Bytes to UFix64 Megabytes. - pub fun convertUInt64StorageBytesToUFix64Megabytes(_ storage: UInt64): UFix64 { + access(all) fun convertUInt64StorageBytesToUFix64Megabytes(_ storage: UInt64): UFix64 { // safe convert UInt64 to UFix64 (without overflow) - let f = UFix64(storage % 100000000 as UInt64) * 0.00000001 as UFix64 + UFix64(storage / 100000000 as UInt64) + let f = UFix64(storage % 100000000) * 0.00000001 + UFix64(storage / 100000000) // decimal point correction. Megabytes to bytes have a conversion of 10^-6 while UFix64 minimum value is 10^-8 - let storageMb = f * 100.0 as UFix64 + let storageMb = f * 100.0 return storageMb } // Gets "available" balance of an account // The available balance is its default token balance minus what is reserved for storage. - pub fun defaultTokenAvailableBalance(_ accountAddress: Address): UFix64 { + access(all) fun defaultTokenAvailableBalance(_ accountAddress: Address): UFix64 { //get balance of account let acct = getAccount(accountAddress) let balanceRef = acct - .getCapability(/public/flowTokenBalance) - .borrow<&FlowToken.Vault{FungibleToken.Balance}>()! + .capabilities.borrow<&{FungibleToken.Vault}>(/public/flowTokenBalance)! let balance = balanceRef.balance // get how much should be reserved for storage - var reserved = self.storageCapacityToFlow(self.convertUInt64StorageBytesToUFix64Megabytes(acct.storageUsed)) + var reserved = self.storageCapacityToFlow(self.convertUInt64StorageBytesToUFix64Megabytes(acct.storage.used)) // at least self.minimumStorageReservation should be reserved if reserved < self.minimumStorageReservation { reserved = self.minimumStorageReservation @@ -119,7 +116,7 @@ pub contract FlowStorageFees { if reserved > balance { return 0.0 } - + return balance - reserved } @@ -127,6 +124,6 @@ pub contract FlowStorageFees { self.storageMegaBytesPerReservedFLOW = 1.0 // 1 Mb per 1 Flow token self.minimumStorageReservation = 0.0 // or 0 kb of minimum storage reservation let admin <- create Administrator() - self.account.save(<-admin, to: /storage/storageFeesAdmin) + self.account.storage.save(<-admin, to: /storage/storageFeesAdmin) } -} \ No newline at end of file +} diff --git a/contracts/standard/FlowToken.cdc b/contracts/standard/FlowToken.cdc index a69a7153..a5b5e248 100644 --- a/contracts/standard/FlowToken.cdc +++ b/contracts/standard/FlowToken.cdc @@ -1,30 +1,28 @@ -import FungibleToken from "./FungibleToken.cdc" +import "FungibleToken" +import "MetadataViews" +import "FungibleTokenMetadataViews" +import "ViewResolver" +import "Burner" -pub contract FlowToken: FungibleToken { +access(all) contract FlowToken: FungibleToken { // Total supply of Flow tokens in existence - pub var totalSupply: UFix64 - - // Event that is emitted when the contract is created - pub event TokensInitialized(initialSupply: UFix64) + access(all) var totalSupply: UFix64 // Event that is emitted when tokens are withdrawn from a Vault - pub event TokensWithdrawn(amount: UFix64, from: Address?) + access(all) event TokensWithdrawn(amount: UFix64, from: Address?) // Event that is emitted when tokens are deposited to a Vault - pub event TokensDeposited(amount: UFix64, to: Address?) + access(all) event TokensDeposited(amount: UFix64, to: Address?) // Event that is emitted when new tokens are minted - pub event TokensMinted(amount: UFix64) - - // Event that is emitted when tokens are destroyed - pub event TokensBurned(amount: UFix64) + access(all) event TokensMinted(amount: UFix64) // Event that is emitted when a new minter resource is created - pub event MinterCreated(allowedAmount: UFix64) + access(all) event MinterCreated(allowedAmount: UFix64) // Event that is emitted when a new burner resource is created - pub event BurnerCreated() + access(all) event BurnerCreated() // Vault // @@ -38,16 +36,38 @@ pub contract FlowToken: FungibleToken { // out of thin air. A special Minter resource needs to be defined to mint // new tokens. // - pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance { + access(all) resource Vault: FungibleToken.Vault { // holds the balance of a users tokens - pub var balance: UFix64 + access(all) var balance: UFix64 // initialize the balance at resource creation time init(balance: UFix64) { self.balance = balance } + /// Called when a fungible token is burned via the `Burner.burn()` method + access(contract) fun burnCallback() { + if self.balance > 0.0 { + FlowToken.totalSupply = FlowToken.totalSupply - self.balance + } + self.balance = 0.0 + } + + /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + return {self.getType(): true} + } + + access(all) view fun isSupportedVaultType(type: Type): Bool { + if (type == self.getType()) { return true } else { return false } + } + + /// Asks if the amount can be withdrawn from this vault + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return amount <= self.balance + } + // withdraw // // Function that takes an integer amount as an argument @@ -57,7 +77,7 @@ pub contract FlowToken: FungibleToken { // created Vault to the context that called so it can be deposited // elsewhere. // - pub fun withdraw(amount: UFix64): @FungibleToken.Vault { + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} { self.balance = self.balance - amount emit TokensWithdrawn(amount: amount, from: self.owner?.address) return <-create Vault(balance: amount) @@ -70,7 +90,7 @@ pub contract FlowToken: FungibleToken { // It is allowed to destroy the sent Vault because the Vault // was a temporary holder of the tokens. The Vault's balance has // been consumed and therefore can be destroyed. - pub fun deposit(from: @FungibleToken.Vault) { + access(all) fun deposit(from: @{FungibleToken.Vault}) { let vault <- from as! @FlowToken.Vault self.balance = self.balance + vault.balance emit TokensDeposited(amount: vault.balance, to: self.owner?.address) @@ -78,8 +98,26 @@ pub contract FlowToken: FungibleToken { destroy vault } - destroy() { - FlowToken.totalSupply = FlowToken.totalSupply - self.balance + /// Get all the Metadata Views implemented by FlowToken + /// + /// @return An array of Types defining the implemented views. This value will be used by + /// developers to know which parameter to pass to the resolveView() method. + /// + access(all) view fun getViews(): [Type]{ + return FlowToken.getContractViews(resourceType: nil) + } + + /// Get a Metadata View from FlowToken + /// + /// @param view: The Type of the desired view. + /// @return A structure representing the requested view. + /// + access(all) fun resolveView(_ view: Type): AnyStruct? { + return FlowToken.resolveContractView(resourceType: nil, viewType: view) + } + + access(all) fun createEmptyVault(): @{FungibleToken.Vault} { + return <-create Vault(balance: 0.0) } } @@ -90,45 +128,93 @@ pub contract FlowToken: FungibleToken { // and store the returned Vault in their storage in order to allow their // account to be able to receive deposits of this token type. // - pub fun createEmptyVault(): @FungibleToken.Vault { + access(all) fun createEmptyVault(vaultType: Type): @FlowToken.Vault { return <-create Vault(balance: 0.0) } - pub resource Administrator { + /// Gets a list of the metadata views that this contract supports + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [Type(), + Type(), + Type(), + Type()] + } + + /// Get a Metadata View from FlowToken + /// + /// @param view: The Type of the desired view. + /// @return A structure representing the requested view. + /// + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: FlowToken.getLogoURI() + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + name: "FLOW Network Token", + symbol: "FLOW", + description: "FLOW is the native token for the Flow blockchain. It is required for securing the network, transaction fees, storage fees, staking, FLIP voting and may be used by applications built on the Flow Blockchain", + externalURL: MetadataViews.ExternalURL("https://flow.com"), + logos: medias, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + case Type(): + let vaultRef = FlowToken.account.storage.borrow(from: /storage/flowTokenVault) + ?? panic("Could not borrow reference to the contract's Vault!") + return FungibleTokenMetadataViews.FTVaultData( + storagePath: /storage/flowTokenVault, + receiverPath: /public/flowTokenReceiver, + metadataPath: /public/flowTokenBalance, + receiverLinkedType: Type<&FlowToken.Vault>(), + metadataLinkedType: Type<&FlowToken.Vault>(), + createEmptyVaultFunction: (fun (): @{FungibleToken.Vault} { + return <-vaultRef.createEmptyVault() + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply(totalSupply: FlowToken.totalSupply) + } + return nil + } + + access(all) resource Administrator { // createNewMinter // // Function that creates and returns a new minter resource // - pub fun createNewMinter(allowedAmount: UFix64): @Minter { + access(all) fun createNewMinter(allowedAmount: UFix64): @Minter { emit MinterCreated(allowedAmount: allowedAmount) return <-create Minter(allowedAmount: allowedAmount) } - - // createNewBurner - // - // Function that creates and returns a new burner resource - // - pub fun createNewBurner(): @Burner { - emit BurnerCreated() - return <-create Burner() - } } // Minter // // Resource object that token admin accounts can hold to mint new tokens. // - pub resource Minter { + access(all) resource Minter { // the amount of tokens that the minter is allowed to mint - pub var allowedAmount: UFix64 + access(all) var allowedAmount: UFix64 // mintTokens // // Function that mints new tokens, adds them to the total supply, // and returns them to the calling context. // - pub fun mintTokens(amount: UFix64): @FlowToken.Vault { + access(all) fun mintTokens(amount: UFix64): @FlowToken.Vault { pre { amount > UFix64(0): "Amount minted must be greater than zero" amount <= self.allowedAmount: "Amount minted must be less than the allowed amount" @@ -144,55 +230,35 @@ pub contract FlowToken: FungibleToken { } } - // Burner - // - // Resource object that token admin accounts can hold to burn tokens. - // - pub resource Burner { - - // burnTokens - // - // Function that destroys a Vault instance, effectively burning the tokens. - // - // Note: the burned tokens are automatically subtracted from the - // total supply in the Vault destructor. - // - pub fun burnTokens(from: @FungibleToken.Vault) { - let vault <- from as! @FlowToken.Vault - let amount = vault.balance - destroy vault - emit TokensBurned(amount: amount) - } + /// Gets the Flow Logo XML URI from storage + access(all) fun getLogoURI(): String { + return FlowToken.account.storage.copy(from: /storage/flowTokenLogoURI) ?? "" } - init(adminAccount: AuthAccount) { + init(adminAccount: auth(Storage, Capabilities) &Account) { self.totalSupply = 0.0 // Create the Vault with the total supply of tokens and save it in storage // let vault <- create Vault(balance: self.totalSupply) - adminAccount.save(<-vault, to: /storage/flowTokenVault) + + adminAccount.storage.save(<-vault, to: /storage/flowTokenVault) // Create a public capability to the stored Vault that only exposes // the `deposit` method through the `Receiver` interface // - adminAccount.link<&FlowToken.Vault{FungibleToken.Receiver}>( - /public/flowTokenReceiver, - target: /storage/flowTokenVault - ) + let receiverCapability = adminAccount.capabilities.storage.issue<&FlowToken.Vault>(/storage/flowTokenVault) + adminAccount.capabilities.publish(receiverCapability, at: /public/flowTokenReceiver) // Create a public capability to the stored Vault that only exposes // the `balance` field through the `Balance` interface // - adminAccount.link<&FlowToken.Vault{FungibleToken.Balance}>( - /public/flowTokenBalance, - target: /storage/flowTokenVault - ) + let balanceCapability = adminAccount.capabilities.storage.issue<&FlowToken.Vault>(/storage/flowTokenVault) + adminAccount.capabilities.publish(balanceCapability, at: /public/flowTokenBalance) let admin <- create Administrator() - adminAccount.save(<-admin, to: /storage/flowTokenAdmin) + adminAccount.storage.save(<-admin, to: /storage/flowTokenAdmin) - // Emit an event that shows that the contract was initialized - emit TokensInitialized(initialSupply: self.totalSupply) } -} \ No newline at end of file +} + diff --git a/contracts/standard/FlowUtilityToken.cdc b/contracts/standard/FlowUtilityToken.cdc index 34dfe5bc..fe5cb126 100644 --- a/contracts/standard/FlowUtilityToken.cdc +++ b/contracts/standard/FlowUtilityToken.cdc @@ -1,30 +1,33 @@ -import FungibleToken from "./FungibleToken.cdc" +import "FungibleToken" +import "ViewResolver" +import "MetadataViews" +import "FungibleTokenMetadataViews" -pub contract FlowUtilityToken: FungibleToken { +access(all) contract FlowUtilityToken: ViewResolver { // Total supply of FlowUtilityTokens in existence - pub var totalSupply: UFix64 + access(all) var totalSupply: UFix64 // Event that is emitted when the contract is created - pub event TokensInitialized(initialSupply: UFix64) + access(all) event TokensInitialized(initialSupply: UFix64) // Event that is emitted when tokens are withdrawn from a Vault - pub event TokensWithdrawn(amount: UFix64, from: Address?) + access(all) event TokensWithdrawn(amount: UFix64, from: Address?) // Event that is emitted when tokens are deposited to a Vault - pub event TokensDeposited(amount: UFix64, to: Address?) + access(all) event TokensDeposited(amount: UFix64, to: Address?) // Event that is emitted when new tokens are minted - pub event TokensMinted(amount: UFix64) + access(all) event TokensMinted(amount: UFix64) // Event that is emitted when tokens are destroyed - pub event TokensBurned(amount: UFix64) + access(all) event TokensBurned(amount: UFix64) // Event that is emitted when a new minter resource is created - pub event MinterCreated(allowedAmount: UFix64) + access(all) event MinterCreated(allowedAmount: UFix64) // Event that is emitted when a new burner resource is created - pub event BurnerCreated() + access(all) event BurnerCreated() // Vault // @@ -38,51 +41,214 @@ pub contract FlowUtilityToken: FungibleToken { // out of thin air. A special Minter resource needs to be defined to mint // new tokens. // - pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance { + /// Vault + /// + /// Each user stores an instance of only the Vault in their storage + /// The functions in the Vault and governed by the pre and post conditions + /// in FungibleToken when they are called. + /// The checks happen at runtime whenever a function is called. + /// + /// Resources can only be created in the context of the contract that they + /// are defined in, so there is no way for a malicious user to create Vaults + /// out of thin air. A special Minter resource needs to be defined to mint + /// new tokens. + /// + access(all) resource Vault: FungibleToken.Vault { - // holds the balance of a users tokens - pub var balance: UFix64 + /// The total balance of this vault + access(all) var balance: UFix64 + + access(self) var storagePath: StoragePath + access(self) var publicPath: PublicPath + access(self) var receiverPath: PublicPath + + /// Returns the storage path where the vault should typically be stored + access(all) view fun getDefaultStoragePath(): StoragePath? { + return self.storagePath + } + + /// Returns the public path where this vault should have a public capability + access(all) view fun getDefaultPublicPath(): PublicPath? { + return self.publicPath + } + + /// Returns the public path where this vault's Receiver should have a public capability + access(all) view fun getDefaultReceiverPath(): PublicPath? { + return self.receiverPath + } + + access(all) view fun getViews(): [Type] { + return [ + Type(), + Type(), + Type(), + Type() + ] + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + switch view { + case Type(): + return FlowUtilityToken.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTView? + case Type(): + return FlowUtilityToken.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay? + case Type(): + return FlowUtilityToken.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + case Type(): + return FungibleTokenMetadataViews.TotalSupply( + totalSupply: FlowUtilityToken.totalSupply + ) + } + return nil + } + + /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + let supportedTypes: {Type: Bool} = {} + supportedTypes[self.getType()] = true + return supportedTypes + } + + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } // initialize the balance at resource creation time init(balance: UFix64) { self.balance = balance + let identifier = "exampleTokenVault" + self.storagePath = StoragePath(identifier: identifier)! + self.publicPath = PublicPath(identifier: identifier)! + self.receiverPath = PublicPath(identifier: "exampleTokenReceiver")! } - // withdraw - // - // Function that takes an integer amount as an argument - // and withdraws that amount from the Vault. - // It creates a new temporary Vault that is used to hold - // the money that is being transferred. It returns the newly - // created Vault to the context that called so it can be deposited - // elsewhere. - // - pub fun withdraw(amount: UFix64): @FungibleToken.Vault { + /// Get the balance of the vault + access(all) view fun getBalance(): UFix64 { + return self.balance + } + + /// withdraw + /// + /// Function that takes an amount as an argument + /// and withdraws that amount from the Vault. + /// + /// It creates a new temporary Vault that is used to hold + /// the tokens that are being transferred. It returns the newly + /// created Vault to the context that called so it can be deposited + /// elsewhere. + /// + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @FlowUtilityToken.Vault { self.balance = self.balance - amount - emit TokensWithdrawn(amount: amount, from: self.owner?.address) return <-create Vault(balance: amount) } - // deposit - // - // Function that takes a Vault object as an argument and adds - // its balance to the balance of the owners Vault. - // It is allowed to destroy the sent Vault because the Vault - // was a temporary holder of the tokens. The Vault's balance has - // been consumed and therefore can be destroyed. - pub fun deposit(from: @FungibleToken.Vault) { + /// deposit + /// + /// Function that takes a Vault object as an argument and adds + /// its balance to the balance of the owners Vault. + /// + /// It is allowed to destroy the sent Vault because the Vault + /// was a temporary holder of the tokens. The Vault's balance has + /// been consumed and therefore can be destroyed. + /// + access(all) fun deposit(from: @{FungibleToken.Vault}) { let vault <- from as! @FlowUtilityToken.Vault self.balance = self.balance + vault.balance - emit TokensDeposited(amount: vault.balance, to: self.owner?.address) vault.balance = 0.0 destroy vault } - destroy() { - FlowUtilityToken.totalSupply = FlowUtilityToken.totalSupply - self.balance + + access(FungibleToken.Withdraw) fun transfer(amount: UFix64, receiver: Capability<&{FungibleToken.Receiver}>) { + let transferVault <- self.withdraw(amount: amount) + + // Get a reference to the recipient's Receiver + let receiverRef = receiver.borrow() + ?? panic("Could not borrow receiver reference to the recipient's Vault") + + // Deposit the withdrawn tokens in the recipient's receiver + receiverRef.deposit(from: <-transferVault) + } + + + /// createEmptyVault + /// + /// Function that creates a new Vault with a balance of zero + /// and returns it to the calling context. A user must call this function + /// and store the returned Vault in their storage in order to allow their + /// account to be able to receive deposits of this token type. + /// + access(all) fun createEmptyVault(): @FlowUtilityToken.Vault { + return <-create Vault(balance: 0.0) + } + + access(contract) fun burnCallback() { + // Placeholder for a burn callback + } + + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return true } } + /// Gets a list of the metadata views that this contract supports + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [Type(), + Type(), + Type(), + Type()] + } + + /// Get a Metadata View from FlowUtilityToken + /// + /// @param view: The Type of the desired view. + /// @return A structure representing the requested view. + /// + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + name: "FLOW Network Token", + symbol: "FLOW", + description: "FLOW is the native token for the Flow blockchain. It is required for securing the network, transaction fees, storage fees, staking, FLIP voting and may be used by applications built on the Flow Blockchain", + externalURL: MetadataViews.ExternalURL("https://flow.com"), + logos: medias, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + case Type(): + let vaultRef = FlowUtilityToken.account.storage.borrow(from: /storage/FlowUtilityTokenVault) + ?? panic("Could not borrow reference to the contract's Vault!") + return FungibleTokenMetadataViews.FTVaultData( + storagePath: /storage/FlowUtilityTokenVault, + receiverPath: /public/FlowUtilityTokenReceiver, + metadataPath: /public/FlowUtilityTokenBalance, + receiverLinkedType: Type<&FlowUtilityToken.Vault>(), + metadataLinkedType: Type<&FlowUtilityToken.Vault>(), + createEmptyVaultFunction: (fun (): @{FungibleToken.Vault} { + return <-vaultRef.createEmptyVault() + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply(totalSupply: FlowUtilityToken.totalSupply) + } + return nil + } + + // createEmptyVault // // Function that creates a new Vault with a balance of zero @@ -90,16 +256,16 @@ pub contract FlowUtilityToken: FungibleToken { // and store the returned Vault in their storage in order to allow their // account to be able to receive deposits of this token type. // - pub fun createEmptyVault(): @FungibleToken.Vault { + access(all) fun createEmptyVault(): @{FungibleToken.Vault} { return <-create Vault(balance: 0.0) } - pub resource Administrator { + access(all) resource Administrator { // createNewMinter // // Function that creates and returns a new minter resource // - pub fun createNewMinter(allowedAmount: UFix64): @Minter { + access(all) fun createNewMinter(allowedAmount: UFix64): @Minter { emit MinterCreated(allowedAmount: allowedAmount) return <-create Minter(allowedAmount: allowedAmount) } @@ -108,7 +274,7 @@ pub contract FlowUtilityToken: FungibleToken { // // Function that creates and returns a new burner resource // - pub fun createNewBurner(): @Burner { + access(all) fun createNewBurner(): @Burner { emit BurnerCreated() return <-create Burner() } @@ -118,17 +284,17 @@ pub contract FlowUtilityToken: FungibleToken { // // Resource object that token admin accounts can hold to mint new tokens. // - pub resource Minter { + access(all) resource Minter { // the amount of tokens that the minter is allowed to mint - pub var allowedAmount: UFix64 + access(all) var allowedAmount: UFix64 // mintTokens // // Function that mints new tokens, adds them to the total supply, // and returns them to the calling context. // - pub fun mintTokens(amount: UFix64): @FlowUtilityToken.Vault { + access(all) fun mintTokens(amount: UFix64): @FlowUtilityToken.Vault { pre { amount > UFix64(0): "Amount minted must be greater than zero" amount <= self.allowedAmount: "Amount minted must be less than the allowed amount" @@ -148,7 +314,7 @@ pub contract FlowUtilityToken: FungibleToken { // // Resource object that token admin accounts can hold to burn tokens. // - pub resource Burner { + access(all) resource Burner { // burnTokens // @@ -157,7 +323,7 @@ pub contract FlowUtilityToken: FungibleToken { // Note: the burned tokens are automatically subtracted from the // total supply in the Vault destructor. // - pub fun burnTokens(from: @FungibleToken.Vault) { + access(all) fun burnTokens(from: @{FungibleToken.Vault}) { let vault <- from as! @FlowUtilityToken.Vault let amount = vault.balance destroy vault @@ -172,28 +338,25 @@ pub contract FlowUtilityToken: FungibleToken { let admin <- create Administrator() let minter <- admin.createNewMinter(allowedAmount: self.totalSupply) - self.account.save(<-admin, to: /storage/flowUtilityTokenAdmin) + self.account.storage.save(<-admin, to: /storage/flowUtilityTokenAdmin) // mint tokens let tokenVault <- minter.mintTokens(amount: self.totalSupply) - self.account.save(<-tokenVault, to: /storage/flowUtilityTokenVault) + self.account.storage.save(<-tokenVault, to: /storage/flowUtilityTokenVault) destroy minter // Create a public capability to the stored Vault that only exposes - // the balance field through the Balance interface - self.account.link<&FlowUtilityToken.Vault{FungibleToken.Balance}>( - /public/flowUtilityTokenBalance, - target: /storage/flowUtilityTokenVault - ) + // the `balance` field through the `Balance` interface + let vaultCap = self.account.capabilities.storage.issue<&Vault>(/storage/flowUtilityTokenVault) + self.account.capabilities.publish(vaultCap, at: /public/flowUtilityTokenBalance) // Create a public capability to the stored Vault that only exposes - // the deposit method through the Receiver interface - self.account.link<&{FungibleToken.Receiver}>( - /public/flowUtilityTokenReceiver, - target: /storage/flowUtilityTokenVault - ) + // the `deposit` method through the `Receiver` interface + let recieverCap = self.account.capabilities.storage.issue<&{FungibleToken.Receiver}>(/storage/flowUtilityTokenVault) + self.account.capabilities.publish(recieverCap, at: /public/flowUtilityTokenReceiver) // Emit an event that shows that the contract was initialized emit TokensInitialized(initialSupply: self.totalSupply) } } + diff --git a/contracts/standard/FungibleToken.cdc b/contracts/standard/FungibleToken.cdc index 6fddb0ed..00b1a209 100644 --- a/contracts/standard/FungibleToken.cdc +++ b/contracts/standard/FungibleToken.cdc @@ -2,21 +2,27 @@ # The Flow Fungible Token standard -## `FungibleToken` contract interface +## `FungibleToken` contract -The interface that all fungible token contracts would have to conform to. If a users wants to deploy a new token contract, their contract -would need to implement the FungibleToken interface. - -Their contract would have to follow all the rules and naming -that the interface specifies. - -## `Vault` resource +needs to implement the FungibleToken interface and their tokens +need to implement the interfaces defined in this contract. + +/// Contributors (please add to this list if you contribute!): +/// - Joshua Hannan - https://github.com/joshuahannan +/// - Bastian Müller - https://twitter.com/turbolent +/// - Dete Shirley - https://twitter.com/dete73 +/// - Bjarte Karlsen - https://twitter.com/0xBjartek +/// - Austin Kline - https://twitter.com/austin_flowty +/// - Giovanni Sanchez - https://twitter.com/gio_incognito +/// - Deniz Edincik - https://twitter.com/bluesign +/// - Jonny - https://github.com/dryruner +/// +/// Repo reference: https://github.com/onflow/flow-ft -Each account that owns tokens would need to have an instance -of the Vault resource stored in their account storage. +## `Vault` resource interface -The Vault resource has methods that the owner and other users can call. +Each fungible token resource type needs to implement the `Vault` resource interface. ## `Provider`, `Receiver`, and `Balance` resource interfaces @@ -32,43 +38,37 @@ these interfaces to do various things with the tokens. For example, a faucet can be implemented by conforming to the Provider interface. -By using resources and interfaces, users of FungibleToken contracts -can send and receive tokens peer-to-peer, without having to interact -with a central ledger smart contract. To send tokens to another user, -a user would simply withdraw the tokens from their Vault, then call -the deposit function on another user's Vault to complete the transfer. - */ +import "ViewResolver" +import "Burner" + /// FungibleToken /// -/// The interface that fungible token contracts implement. -/// -pub contract interface FungibleToken { +/// Fungible Token implementations should implement the fungible token +/// interface. +access(all) contract interface FungibleToken: ViewResolver { - /// The total number of tokens in existence. - /// It is up to the implementer to ensure that the total supply - /// stays accurate and up to date - /// - pub var totalSupply: UFix64 + // An entitlement for allowing the withdrawal of tokens from a Vault + access(all) entitlement Withdraw - /// TokensInitialized - /// - /// The event that is emitted when the contract is created - /// - pub event TokensInitialized(initialSupply: UFix64) - - /// TokensWithdrawn - /// /// The event that is emitted when tokens are withdrawn from a Vault - /// - pub event TokensWithdrawn(amount: UFix64, from: Address?) + access(all) event Withdrawn(type: String, amount: UFix64, from: Address?, fromUUID: UInt64, withdrawnUUID: UInt64, balanceAfter: UFix64) + + /// The event that is emitted when tokens are deposited to a Vault + access(all) event Deposited(type: String, amount: UFix64, to: Address?, toUUID: UInt64, depositedUUID: UInt64, balanceAfter: UFix64) + + /// Event that is emitted when the global burn method is called with a non-zero balance + access(all) event Burned(type: String, amount: UFix64, fromUUID: UInt64) - /// TokensDeposited + /// Balance /// - /// The event that is emitted when tokens are deposited into a Vault + /// The interface that provides standard functions\ + /// for getting balance information /// - pub event TokensDeposited(amount: UFix64, to: Address?) + access(all) resource interface Balance { + access(all) var balance: UFix64 + } /// Provider /// @@ -79,24 +79,26 @@ pub contract interface FungibleToken { /// because it leaves open the possibility of creating custom providers /// that do not necessarily need their own balance. /// - pub resource interface Provider { + access(all) resource interface Provider { + + /// Function to ask a provider if a specific amount of tokens + /// is available to be withdrawn + /// This could be useful to avoid panicing when calling withdraw + /// when the balance is unknown + /// Additionally, if the provider is pulling from multiple vaults + /// it only needs to check some of the vaults until the desired amount + /// is reached, potentially helping with performance. + /// + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool - /// withdraw subtracts tokens from the owner's Vault + /// withdraw subtracts tokens from the implementing resource /// and returns a Vault with the removed tokens. /// - /// The function's access level is public, but this is not a problem - /// because only the owner storing the resource in their account - /// can initially call this function. + /// The function's access level is `access(Withdraw)` + /// So in order to access it, one would either need the object itself + /// or an entitled reference with `Withdraw`. /// - /// The owner may grant other accounts access by creating a private - /// capability that allows specific other users to access - /// the provider resource through a reference. - /// - /// The owner may also grant all accounts access by creating a public - /// capability that allows all users to access the provider - /// resource through a reference. - /// - pub fun withdraw(amount: UFix64): @Vault { + access(Withdraw) fun withdraw(amount: UFix64): @{Vault} { post { // `result` refers to the return value result.balance == amount: @@ -115,84 +117,133 @@ pub contract interface FungibleToken { /// can do custom things with the tokens, like split them up and /// send them to different places. /// - pub resource interface Receiver { + access(all) resource interface Receiver { /// deposit takes a Vault and deposits it into the implementing resource type /// - pub fun deposit(from: @Vault) + access(all) fun deposit(from: @{Vault}) + + /// getSupportedVaultTypes returns a dictionary of Vault types + /// and whether the type is currently supported by this Receiver + access(all) view fun getSupportedVaultTypes(): {Type: Bool} + + /// Returns whether or not the given type is accepted by the Receiver + /// A vault that can accept any type should just return true by default + access(all) view fun isSupportedVaultType(type: Type): Bool } - /// Balance + /// Vault /// - /// The interface that contains the `balance` field of the Vault - /// and enforces that when new Vaults are created, the balance - /// is initialized correctly. + /// Ideally, this interface would also conform to Receiver, Balance, Transferor, Provider, and Resolver + /// but that is not supported yet /// - pub resource interface Balance { + access(all) resource interface Vault: Receiver, Provider, Balance, ViewResolver.Resolver, Burner.Burnable { - /// The total balance of a vault - /// - pub var balance: UFix64 + /// Field that tracks the balance of a vault + access(all) var balance: UFix64 - init(balance: UFix64) { + /// Called when a fungible token is burned via the `Burner.burn()` method + /// Implementations can do any bookkeeping or emit any events + /// that should be emitted when a vault is destroyed. + /// Many implementations will want to update the token's total supply + /// to reflect that the tokens have been burned and removed from the supply. + /// Implementations also need to set the balance to zero before the end of the function + /// This is to prevent vault owners from spamming fake Burned events. + access(contract) fun burnCallback() { + pre { + emit Burned(type: self.getType().identifier, amount: self.balance, fromUUID: self.uuid) + } post { - self.balance == balance: - "Balance must be initialized to the initial balance" + self.balance == 0.0: "The balance must be set to zero during the burnCallback method so that it cannot be spammed" } + self.balance = 0.0 } - } - /// Vault - /// - /// The resource that contains the functions to send and receive tokens. - /// - pub resource Vault: Provider, Receiver, Balance { - - // The declaration of a concrete type in a contract interface means that - // every Fungible Token contract that implements the FungibleToken interface - // must define a concrete `Vault` resource that conforms to the `Provider`, `Receiver`, - // and `Balance` interfaces, and declares their required fields and functions - - /// The total balance of the vault - /// - pub var balance: UFix64 + /// getSupportedVaultTypes returns a dictionary of vault types and whether this receiver accepts the indexed type + /// The default implementation is included here because vaults are expected + /// to only accepted their own type, so they have no need to provide an implementation + /// for this function + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + // Below check is implemented to make sure that run-time type would + // only get returned when the parent resource conforms with `FungibleToken.Vault`. + if self.getType().isSubtype(of: Type<@{FungibleToken.Vault}>()) { + return {self.getType(): true} + } else { + // Return an empty dictionary as the default value for resource who don't + // implement `FungibleToken.Vault`, such as `FungibleTokenSwitchboard`, `TokenForwarder` etc. + return {} + } + } - // The conforming type must declare an initializer - // that allows prioviding the initial balance of the Vault - // - init(balance: UFix64) + /// Checks if the given type is supported by this Vault + access(all) view fun isSupportedVaultType(type: Type): Bool { + return self.getSupportedVaultTypes()[type] ?? false + } /// withdraw subtracts `amount` from the Vault's balance /// and returns a new Vault with the subtracted balance /// - pub fun withdraw(amount: UFix64): @Vault { + access(Withdraw) fun withdraw(amount: UFix64): @{Vault} { pre { self.balance >= amount: "Amount withdrawn must be less than or equal than the balance of the Vault" } post { + result.getType() == self.getType(): "Must return the same vault type as self" // use the special function `before` to get the value of the `balance` field // at the beginning of the function execution // self.balance == before(self.balance) - amount: - "New Vault balance must be the difference of the previous balance and the withdrawn Vault" + "New Vault balance must be the difference of the previous balance and the withdrawn Vault balance" + emit Withdrawn( + type: result.getType().identifier, + amount: amount, + from: self.owner?.address, + fromUUID: self.uuid, + withdrawnUUID: result.uuid, + balanceAfter: self.balance + ) } } /// deposit takes a Vault and adds its balance to the balance of this Vault /// - pub fun deposit(from: @Vault) { + access(all) fun deposit(from: @{FungibleToken.Vault}) { + // Assert that the concrete type of the deposited vault is the same + // as the vault that is accepting the deposit + pre { + from.isInstance(self.getType()): + "Cannot deposit an incompatible token type" + } post { + emit Deposited( + type: before(from.getType().identifier), + amount: before(from.balance), + to: self.owner?.address, + toUUID: self.uuid, + depositedUUID: before(from.uuid), + balanceAfter: self.balance + ) self.balance == before(self.balance) + before(from.balance): "New Vault balance must be the sum of the previous balance and the deposited Vault" } } + + /// createEmptyVault allows any user to create a new Vault that has a zero balance + /// + access(all) fun createEmptyVault(): @{Vault} { + post { + result.balance == 0.0: "The newly created Vault must have zero balance" + result.getType() == self.getType(): "The newly created Vault must have the same type as the creating vault" + } + } } /// createEmptyVault allows any user to create a new Vault that has a zero balance /// - pub fun createEmptyVault(): @Vault { + access(all) fun createEmptyVault(vaultType: Type): @{FungibleToken.Vault} { post { + result.getType() == vaultType: "The returned vault does not match the desired type" result.balance == 0.0: "The newly created Vault must have zero balance" } } diff --git a/contracts/standard/FungibleTokenMetadataViews.cdc b/contracts/standard/FungibleTokenMetadataViews.cdc new file mode 100644 index 00000000..89984228 --- /dev/null +++ b/contracts/standard/FungibleTokenMetadataViews.cdc @@ -0,0 +1,180 @@ +import "FungibleToken" +import "MetadataViews" +import "ViewResolver" + +/// This contract implements the metadata standard proposed +/// in FLIP-1087. +/// +/// Ref: https://github.com/onflow/flips/blob/main/application/20220811-fungible-tokens-metadata.md +/// +/// Structs and resources can implement one or more +/// metadata types, called views. Each view type represents +/// a different kind of metadata. +/// +access(all) contract FungibleTokenMetadataViews { + + /// FTView wraps FTDisplay and FTVaultData, and is used to give a complete + /// picture of a Fungible Token. Most Fungible Token contracts should + /// implement this view. + /// + access(all) struct FTView { + access(all) let ftDisplay: FTDisplay? + access(all) let ftVaultData: FTVaultData? + view init( + ftDisplay: FTDisplay?, + ftVaultData: FTVaultData? + ) { + self.ftDisplay = ftDisplay + self.ftVaultData = ftVaultData + } + } + + /// Helper to get a FT view. + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A FTView struct + /// + access(all) fun getFTView(viewResolver: &{ViewResolver.Resolver}): FTView { + let maybeFTView = viewResolver.resolveView(Type()) + if let ftView = maybeFTView { + return ftView as! FTView + } + return FTView( + ftDisplay: self.getFTDisplay(viewResolver), + ftVaultData: self.getFTVaultData(viewResolver) + ) + } + + /// View to expose the information needed to showcase this FT. + /// This can be used by applications to give an overview and + /// graphics of the FT. + /// + access(all) struct FTDisplay { + /// The display name for this token. + /// + /// Example: "Flow" + /// + access(all) let name: String + + /// The abbreviated symbol for this token. + /// + /// Example: "FLOW" + access(all) let symbol: String + + /// A description the provides an overview of this token. + /// + /// Example: "The FLOW token is the native currency of the Flow network." + access(all) let description: String + + /// External link to a URL to view more information about the fungible token. + access(all) let externalURL: MetadataViews.ExternalURL + + /// One or more versions of the fungible token logo. + access(all) let logos: MetadataViews.Medias + + /// Social links to reach the fungible token's social homepages. + /// Possible keys may be "instagram", "twitter", "discord", etc. + access(all) let socials: {String: MetadataViews.ExternalURL} + + view init( + name: String, + symbol: String, + description: String, + externalURL: MetadataViews.ExternalURL, + logos: MetadataViews.Medias, + socials: {String: MetadataViews.ExternalURL} + ) { + self.name = name + self.symbol = symbol + self.description = description + self.externalURL = externalURL + self.logos = logos + self.socials = socials + } + } + + /// Helper to get FTDisplay in a way that will return a typed optional. + /// + /// @param viewResolver: A reference to the resolver resource + /// @return An optional FTDisplay struct + /// + access(all) fun getFTDisplay(_ viewResolver: &{ViewResolver.Resolver}): FTDisplay? { + if let maybeDisplayView = viewResolver.resolveView(Type()) { + if let displayView = maybeDisplayView as? FTDisplay { + return displayView + } + } + return nil + } + + /// View to expose the information needed store and interact with a FT vault. + /// This can be used by applications to setup a FT vault with proper + /// storage and public capabilities. + /// + access(all) struct FTVaultData { + /// Path in storage where this FT vault is recommended to be stored. + access(all) let storagePath: StoragePath + + /// Public path which must be linked to expose the public receiver capability. + access(all) let receiverPath: PublicPath + + /// Public path which must be linked to expose the balance and resolver public capabilities. + access(all) let metadataPath: PublicPath + + /// Type that should be linked at the `receiverPath`. This is a restricted type requiring + /// the `FungibleToken.Receiver` interface. + access(all) let receiverLinkedType: Type + + /// Type that should be linked at the `receiverPath`. This is a restricted type requiring + /// the `ViewResolver.Resolver` interfaces. + access(all) let metadataLinkedType: Type + + /// Function that allows creation of an empty FT vault that is intended + /// to store the funds. + access(all) let createEmptyVault: fun(): @{FungibleToken.Vault} + + view init( + storagePath: StoragePath, + receiverPath: PublicPath, + metadataPath: PublicPath, + receiverLinkedType: Type, + metadataLinkedType: Type, + createEmptyVaultFunction: fun(): @{FungibleToken.Vault} + ) { + pre { + receiverLinkedType.isSubtype(of: Type<&{FungibleToken.Receiver}>()): "Receiver public type must include FungibleToken.Receiver." + metadataLinkedType.isSubtype(of: Type<&{ViewResolver.Resolver}>()): "Metadata public type must include ViewResolver.Resolver interfaces." + } + self.storagePath = storagePath + self.receiverPath = receiverPath + self.metadataPath = metadataPath + self.receiverLinkedType = receiverLinkedType + self.metadataLinkedType = metadataLinkedType + self.createEmptyVault = createEmptyVaultFunction + } + } + + /// Helper to get FTVaultData in a way that will return a typed Optional. + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional FTVaultData struct + /// + access(all) fun getFTVaultData(_ viewResolver: &{ViewResolver.Resolver}): FTVaultData? { + if let view = viewResolver.resolveView(Type()) { + if let v = view as? FTVaultData { + return v + } + } + return nil + } + + /// View to expose the total supply of the Vault's token + access(all) struct TotalSupply { + access(all) let supply: UFix64 + + view init(totalSupply: UFix64) { + self.supply = totalSupply + } + } +} + diff --git a/contracts/standard/FungibleTokenSwitchboard.cdc b/contracts/standard/FungibleTokenSwitchboard.cdc index aefe8b2d..59131a55 100644 --- a/contracts/standard/FungibleTokenSwitchboard.cdc +++ b/contracts/standard/FungibleTokenSwitchboard.cdc @@ -1,78 +1,83 @@ -import FungibleToken from "./FungibleToken.cdc" +import "FungibleToken" /// The contract that allows an account to receive payments in multiple fungible /// tokens using a single `{FungibleToken.Receiver}` capability. -/// This capability should ideally be stored at the +/// This capability should ideally be stored at the /// `FungibleTokenSwitchboard.ReceiverPublicPath = /public/GenericFTReceiver` /// but it can be stored anywhere. -/// -pub contract FungibleTokenSwitchboard { +/// +access(all) contract FungibleTokenSwitchboard { // Storage and Public Paths - pub let StoragePath: StoragePath - pub let PublicPath: PublicPath - pub let ReceiverPublicPath: PublicPath + access(all) let StoragePath: StoragePath + access(all) let PublicPath: PublicPath + access(all) let ReceiverPublicPath: PublicPath + + access(all) entitlement Owner /// The event that is emitted when a new vault capability is added to a /// switchboard resource. - /// - pub event VaultCapabilityAdded(type: Type, switchboardOwner: Address?, - capabilityOwner: Address?) + /// + access(all) event VaultCapabilityAdded(type: Type, switchboardOwner: Address?, + capabilityOwner: Address?) - /// The event that is emitted when a vault capability is removed from a + /// The event that is emitted when a vault capability is removed from a /// switchboard resource. - /// - pub event VaultCapabilityRemoved(type: Type, switchboardOwner: Address?, - capabilityOwner: Address?) + /// + access(all) event VaultCapabilityRemoved(type: Type, switchboardOwner: Address?, + capabilityOwner: Address?) /// The event that is emitted when a deposit can not be completed. - /// - pub event NotCompletedDeposit(type: Type, amount: UFix64, - switchboardOwner: Address?) + /// + access(all) event NotCompletedDeposit(type: Type, amount: UFix64, + switchboardOwner: Address?) /// The interface that enforces the method to allow anyone to check on the - /// available capabilities of a switchboard resource and also exposes the + /// available capabilities of a switchboard resource and also exposes the /// deposit methods to deposit funds on it. - /// - pub resource interface SwitchboardPublic { - pub fun getVaultTypes(): [Type] - pub fun deposit(from: @FungibleToken.Vault) - pub fun safeDeposit(from: @FungibleToken.Vault): @FungibleToken.Vault? + /// + access(all) resource interface SwitchboardPublic { + access(all) view fun getVaultTypesWithAddress(): {Type: Address} + access(all) view fun getSupportedVaultTypes(): {Type: Bool} + access(all) view fun isSupportedVaultType(type: Type): Bool + access(all) fun deposit(from: @{FungibleToken.Vault}) + access(all) fun safeDeposit(from: @{FungibleToken.Vault}): @{FungibleToken.Vault}? + access(all) view fun safeBorrowByType(type: Type): &{FungibleToken.Receiver}? } - /// The resource that stores the multiple fungible token receiver - /// capabilities, allowing the owner to add and remove them and anyone to + /// The resource that stores the multiple fungible token receiver + /// capabilities, allowing the owner to add and remove them and anyone to /// deposit any fungible token among the available types. - /// - pub resource Switchboard: FungibleToken.Receiver, SwitchboardPublic { + /// + access(all) resource Switchboard: FungibleToken.Receiver, SwitchboardPublic { - /// Dictionary holding the fungible token receiver capabilities, + /// Dictionary holding the fungible token receiver capabilities, /// indexed by the fungible token vault type. - /// + /// access(contract) var receiverCapabilities: {Type: Capability<&{FungibleToken.Receiver}>} - /// Adds a new fungible token receiver capability to the switchboard + /// Adds a new fungible token receiver capability to the switchboard /// resource. - /// + /// /// @param capability: The capability to expose a certain fungible /// token vault deposit function through `{FungibleToken.Receiver}` that /// will be added to the switchboard. - /// - pub fun addNewVault(capability: Capability<&{FungibleToken.Receiver}>) { - // Borrow a reference to the vault pointed to by the capability we + /// + access(Owner) fun addNewVault(capability: Capability<&{FungibleToken.Receiver}>) { + // Borrow a reference to the vault pointed to by the capability we // want to store inside the switchboard - let vaultRef = capability.borrow() - ?? panic ("Cannot borrow reference to vault from capability") + let vaultRef = capability.borrow() + ?? panic ("Cannot borrow reference to vault from capability") // Check if there is a previous capability for this token, if not if (self.receiverCapabilities[vaultRef.getType()] == nil) { - // use the vault reference type as key for storing the + // use the vault reference type as key for storing the // capability and then self.receiverCapabilities[vaultRef.getType()] = capability - // emit the event that indicates that a new capability has been + // emit the event that indicates that a new capability has been // added emit VaultCapabilityAdded(type: vaultRef.getType(), - switchboardOwner: self.owner?.address, - capabilityOwner: capability.address) + switchboardOwner: self.owner?.address, + capabilityOwner: capability.address) } else { // If there was already a capability for that token, panic panic("There is already a vault in the Switchboard for this token") @@ -81,170 +86,275 @@ pub contract FungibleTokenSwitchboard { /// Adds a number of new fungible token receiver capabilities by using /// the paths where they are stored. - /// + /// /// @param paths: The paths where the public capabilities are stored. /// @param address: The address of the owner of the capabilities. - /// - pub fun addNewVaultsByPath(paths: [PublicPath], address: Address) { + /// + access(Owner) fun addNewVaultsByPath(paths: [PublicPath], address: Address) { // Get the account where the public capabilities are stored let owner = getAccount(address) - // For each path, get the saved capability and store it + // For each path, get the saved capability and store it // into the switchboard's receiver capabilities dictionary for path in paths { - let capability = owner.getCapability<&{FungibleToken.Receiver}>(path) + let capability = owner.capabilities.get<&{FungibleToken.Receiver}>(path) // Borrow a reference to the vault pointed to by the capability // we want to store inside the switchboard // If the vault was borrowed successfully... - if let vaultRef = capability.borrow() { - // ...and if there is no previous capability added for that - // token - if (self.receiverCapabilities[vaultRef!.getType()] == nil) { + if let vaultRef = capability!.borrow() { + // ...and if there is no previous capability added for that token + if (self.receiverCapabilities[vaultRef.getType()] == nil) { // Use the vault reference type as key for storing the // capability - self.receiverCapabilities[vaultRef!.getType()] = capability + self.receiverCapabilities[vaultRef.getType()] = capability // and emit the event that indicates that a new // capability has been added emit VaultCapabilityAdded(type: vaultRef.getType(), - switchboardOwner: self.owner?.address, capabilityOwner: address) - } + switchboardOwner: self.owner?.address, + capabilityOwner: address, + ) } } } + } - /// Adds a new fungible token receiver capability to the switchboard - /// resource specifying which `Type`of `@FungibleToken.Vault` can be - /// deposited to it. Use it to include in your switchboard "wrapper" - /// receivers such as a `@TokenForwarding.Forwarder`. It can also be - /// used to overwrite the type attached to a certain capability without - /// having to remove that capability first. - /// - /// @param capability: The capability to expose a certain fungible - /// token vault deposit function through `{FungibleToken.Receiver}` that - /// will be added to the switchboard. - /// - /// @param type: The type of fungible token that can be deposited to that - /// capability, rather than the `Type` from the reference borrowed from - /// said capability - /// - pub fun addNewVaultWrapper(capability: Capability<&{FungibleToken.Receiver}>, type: Type) { - // Check if the capability is working - assert(capability.check(), message: "The passed capability is not valid") - // Use the type parameter as key for the capability - self.receiverCapabilities[type] = capability - // emit the event that indicates that a new capability has been - // added - emit VaultCapabilityAdded(type: type, - switchboardOwner: self.owner?.address, - capabilityOwner: capability.address) + /// Adds a new fungible token receiver capability to the switchboard + /// resource specifying which `Type` of `@{FungibleToken.Vault}` can be + /// deposited to it. Use it to include in your switchboard "wrapper" + /// receivers such as a `@TokenForwarding.Forwarder`. It can also be + /// used to overwrite the type attached to a certain capability without + /// having to remove that capability first. + /// + /// @param capability: The capability to expose a certain fungible + /// token vault deposit function through `{FungibleToken.Receiver}` that + /// will be added to the switchboard. + /// + /// @param type: The type of fungible token that can be deposited to that + /// capability, rather than the `Type` from the reference borrowed from + /// said capability + /// + access(Owner) fun addNewVaultWrapper(capability: Capability<&{FungibleToken.Receiver}>, + type: Type) { + // Check if the capability is working + assert(capability.check(), message: "The passed capability is not valid") + // Use the type parameter as key for the capability + self.receiverCapabilities[type] = capability + // emit the event that indicates that a new capability has been + // added + emit VaultCapabilityAdded( + type: type, + switchboardOwner: self.owner?.address, + capabilityOwner: capability.address, + ) + } + + /// Adds zero or more new fungible token receiver capabilities to the + /// switchboard resource specifying which `Type`s of `@{FungibleToken.Vault}`s + /// can be deposited to it. Use it to include in your switchboard "wrapper" + /// receivers such as a `@TokenForwarding.Forwarder`. It can also be + /// used to overwrite the types attached to certain capabilities without + /// having to remove those capabilities first. + /// + /// @param paths: The paths where the public capabilities are stored. + /// @param types: The types of the fungible token to be deposited on each path. + /// @param address: The address of the owner of the capabilities. + /// + access(Owner) fun addNewVaultWrappersByPath(paths: [PublicPath], types: [Type], + address: Address) { + // Get the account where the public capabilities are stored + let owner = getAccount(address) + // For each path, get the saved capability and store it + // into the switchboard's receiver capabilities dictionary + for i, path in paths { + let capability = owner.capabilities.get<&{FungibleToken.Receiver}>(path) + // Borrow a reference to the vault pointed to by the capability + // we want to store inside the switchboard + // If the vault was borrowed successfully... + if let vaultRef = capability!.borrow() { + // Use the vault reference type as key for storing the capability + self.receiverCapabilities[types[i]] = capability + // and emit the event that indicates that a new capability has been added + emit VaultCapabilityAdded( + type: types[i], + switchboardOwner: self.owner?.address, + capabilityOwner: address, + ) + } } + } + /// Removes a fungible token receiver capability from the switchboard + /// resource. + /// + /// @param capability: The capability to a fungible token vault to be + /// removed from the switchboard. + /// + access(Owner) fun removeVault(capability: Capability<&{FungibleToken.Receiver}>) { + // Borrow a reference to the vault pointed to by the capability we + // want to remove from the switchboard + let vaultRef = capability.borrow() + ?? panic ("Cannot borrow reference to vault from capability") + // Use the vault reference to find the capability to remove + self.receiverCapabilities.remove(key: vaultRef.getType()) + // Emit the event that indicates that a new capability has been + // removed + emit VaultCapabilityRemoved( + type: vaultRef.getType(), + switchboardOwner: self.owner?.address, + capabilityOwner: capability.address, + ) + } - /// Removes a fungible token receiver capability from the switchboard - /// resource. - /// - /// @param capability: The capability to a fungible token vault to be - /// removed from the switchboard. - /// - pub fun removeVault(capability: Capability<&{FungibleToken.Receiver}>) { - // Borrow a reference to the vault pointed to by the capability we - // want to remove from the switchboard - let vaultRef = capability.borrow() - ?? panic ("Cannot borrow reference to vault from capability") - // Use the vault reference to find the capability to remove - self.receiverCapabilities.remove(key: vaultRef.getType()) - // Emit the event that indicates that a new capability has been - // removed - emit VaultCapabilityRemoved(type: vaultRef.getType(), - switchboardOwner: self.owner?.address, - capabilityOwner: capability.address) + /// Takes a fungible token vault and routes it to the proper fungible + /// token receiver capability for depositing it. + /// + /// @param from: The deposited fungible token vault resource. + /// + access(all) fun deposit(from: @{FungibleToken.Vault}) { + // Get the capability from the ones stored at the switchboard + let depositedVaultCapability = self.receiverCapabilities[from.getType()] + ?? panic ("The deposited vault is not available on this switchboard ".concat(from.getType().identifier)) + + // Borrow the reference to the desired vault + let vaultRef = depositedVaultCapability.borrow() + ?? panic ("Can not borrow a reference to the the vault") + + vaultRef.deposit(from: <-from) + } + + /// Takes a fungible token vault and tries to route it to the proper + /// fungible token receiver capability for depositing the funds, + /// avoiding panicking if the vault is not available. + /// + /// @param vaultType: The type of the ft vault that wants to be + /// deposited. + /// + /// @return The deposited fungible token vault resource, without the + /// funds if the deposit was successful, or still containing the funds + /// if the reference to the needed vault was not found. + /// + access(all) fun safeDeposit(from: @{FungibleToken.Vault}): @{FungibleToken.Vault}? { + // Try to get the proper vault capability from the switchboard + // If the desired vault is present on the switchboard... + if let depositedVaultCapability = self.receiverCapabilities[from.getType()] { + // We try to borrow a reference to the vault from the capability + // If we can borrow a reference to the vault... + if let vaultRef = depositedVaultCapability.borrow() { + // We deposit the funds on said vault + vaultRef.deposit(from: <-from.withdraw(amount: from.balance)) + } } + // if deposit failed for some reason + if from.balance > 0.0 { + emit NotCompletedDeposit( + type: from.getType(), + amount: from.balance, + switchboardOwner: self.owner?.address, + ) + return <-from + } + destroy from + return nil + } - /// Takes a fungible token vault and routes it to the proper fungible - /// token receiver capability for depositing it. - /// - /// @param from: The deposited fungible token vault resource. - /// - pub fun deposit(from: @FungibleToken.Vault) { - // Get the capability from the ones stored at the switchboard - let depositedVaultCapability = self - .receiverCapabilities[from.getType()] - ?? panic ("The deposited vault is not available on this switchboard") - // Borrow the reference to the desired vault - let vaultRef = depositedVaultCapability.borrow() - ?? panic ("Can not borrow a reference to the the vault") - vaultRef.deposit(from: <-from) + /// Checks that the capability tied to a type is valid + /// + /// @param vaultType: The type of the ft vault whose capability needs to be checked + /// + /// @return a boolean marking the capability for a type as valid or not + access(all) view fun checkReceiverByType(type: Type): Bool { + if self.receiverCapabilities[type] == nil { + return false } - /// Takes a fungible token vault and tries to route it to the proper - /// fungible token receiver capability for depositing the funds, - /// avoiding panicking if the vault is not available. - /// - /// @param vaultType: The type of the ft vault that wants to be - /// deposited. - /// - /// @return The deposited fungible token vault resource, without the - /// funds if the deposit was successful, or still containing the funds - /// if the reference to the needed vault was not found. - /// - pub fun safeDeposit(from: @FungibleToken.Vault): @FungibleToken.Vault? { - // Try to get the proper vault capability from the switchboard - // If the desired vault is present on the switchboard... - if let depositedVaultCapability = self - .receiverCapabilities[from.getType()] { - // We try to borrow a reference to the vault from the capability - // If we can borrow a reference to the vault... - if let vaultRef = depositedVaultCapability.borrow() { - // We deposit the funds on said vault - vaultRef.deposit(from: <-from - .withdraw(amount: from.balance)) - } - } - // if deposit failed for some reason - if from.balance > 0.0 { - emit NotCompletedDeposit(type: from.getType(), - amount: from.balance, - switchboardOwner: self.owner?.address) - return <-from - } - destroy from + return self.receiverCapabilities[type]!.check() + } + + /// Gets the receiver assigned to a provided vault type. + /// This is necessary because without it, it is not possible to look under the hood and see if a capability + /// is of an expected type or not. This helps guard against infinitely chained TokenForwarding or other invalid + /// malicious kinds of updates that could prevent listings from being made that are valid on storefronts. + /// + /// @param vaultType: The type of the ft vault whose capability needs to be checked + /// + /// @return an optional receiver capability for consumers of the switchboard to check/validate on their own + access(all) view fun safeBorrowByType(type: Type): &{FungibleToken.Receiver}? { + if !self.checkReceiverByType(type: type) { return nil } - /// A getter function to know which tokens a certain switchboard - /// resource is prepared to receive. - /// - /// @return The keys from the dictionary of stored - /// `{FungibleToken.Receiver}` capabilities that can be effectively - /// borrowed. - /// - pub fun getVaultTypes(): [Type] { - let effectiveTypes: [Type] = [] - for vaultType in self.receiverCapabilities.keys { - if self.receiverCapabilities[vaultType]!.check() { - effectiveTypes.append(vaultType) - } + return self.receiverCapabilities[type]!.borrow() + } + + /// A getter function to know which tokens a certain switchboard + /// resource is prepared to receive along with the address where + /// those tokens will be deposited. + /// + /// @return A dictionary mapping the `{FungibleToken.Receiver}` + /// type to the receiver owner's address + /// + access(all) view fun getVaultTypesWithAddress(): {Type: Address} { + let effectiveTypesWithAddress: {Type: Address} = {} + // Check if each capability is live + for vaultType in self.receiverCapabilities.keys { + if self.receiverCapabilities[vaultType]!.check() { + // and attach it to the owner's address + effectiveTypesWithAddress[vaultType] = self.receiverCapabilities[vaultType]!.address } - return effectiveTypes } + return effectiveTypesWithAddress + } - init() { - // Initialize the capabilities dictionary - self.receiverCapabilities = {} + /// A getter function that returns the token types supported by this resource, + /// which can be deposited using the 'deposit' function. + /// + /// @return Dictionary of FT types that can be deposited. + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + let supportedVaults: {Type: Bool} = {} + for receiverType in self.receiverCapabilities.keys { + if self.receiverCapabilities[receiverType]!.check() { + if receiverType.isSubtype(of: Type<@{FungibleToken.Vault}>()) { + supportedVaults[receiverType] = true + } + if receiverType.isSubtype(of: Type<@{FungibleToken.Receiver}>()) { + let receiverRef = self.receiverCapabilities[receiverType]!.borrow()! + let subReceiverSupportedTypes = receiverRef.getSupportedVaultTypes() + for subReceiverType in subReceiverSupportedTypes.keys { + if subReceiverType.isSubtype(of: Type<@{FungibleToken.Vault}>()) { + supportedVaults[subReceiverType] = true + } + } + } + } } - + return supportedVaults } - /// Function that allows to create a new blank switchboard. A user must call - /// this function and store the returned resource in their storage. - /// - pub fun createSwitchboard(): @Switchboard { - return <-create Switchboard() + /// Returns whether or not the given type is accepted by the Receiver + /// A vault that can accept any type should just return true by default + access(all) view fun isSupportedVaultType(type: Type): Bool { + let supportedVaults = self.getSupportedVaultTypes() + if let supported = supportedVaults[type] { + return supported + } else { return false } } init() { - self.StoragePath = /storage/fungibleTokenSwitchboard - self.PublicPath = /public/fungibleTokenSwitchboardPublic - self.ReceiverPublicPath = /public/GenericFTReceiver + // Initialize the capabilities dictionary + self.receiverCapabilities = {} } } + +/// Function that allows to create a new blank switchboard. A user must call +/// this function and store the returned resource in their storage. +/// +access(all) fun createSwitchboard(): @Switchboard { + return <-create Switchboard() +} + +init() { + self.StoragePath = /storage/fungibleTokenSwitchboard + self.PublicPath = /public/fungibleTokenSwitchboardPublic + self.ReceiverPublicPath = /public/GenericFTReceiver +} +} diff --git a/contracts/standard/GrantedAccountAccess.cdc b/contracts/standard/GrantedAccountAccess.cdc index 7fb81d4c..4b0e7996 100644 --- a/contracts/standard/GrantedAccountAccess.cdc +++ b/contracts/standard/GrantedAccountAccess.cdc @@ -4,42 +4,42 @@ // to an "Info" resource signifying they want them to share their account. // This is specifically used by the -// `pub fun borrowSharedRef(fromHost: Address): &FLOATEvents` +// `access(all) fun borrowSharedRef(fromHost: Address): &FLOATEvents` // function inside FLOAT.cdc to give users access to someone elses // FLOATEvents if they are on this shared list. // This contract is my way of saying I hate private capabilities, so I // implemented an alternative solution to private access. -pub contract GrantedAccountAccess { +access(all) contract GrantedAccountAccess { - pub let InfoStoragePath: StoragePath - pub let InfoPublicPath: PublicPath + access(all) let InfoStoragePath: StoragePath + access(all) let InfoPublicPath: PublicPath - pub resource interface InfoPublic { - pub fun getAllowed(): [Address] - pub fun isAllowed(account: Address): Bool + access(all) resource interface InfoPublic { + access(all) fun getAllowed(): [Address] + access(all) fun isAllowed(account: Address): Bool } // A list of people you allow to share your // account. - pub resource Info: InfoPublic { + access(all) resource Info: InfoPublic { access(account) var allowed: {Address: Bool} // Allow someone to share your account - pub fun addAccount(account: Address) { + access(all) fun addAccount(account: Address) { self.allowed[account] = true } - pub fun removeAccount(account: Address) { + access(all) fun removeAccount(account: Address) { self.allowed.remove(key: account) } - pub fun getAllowed(): [Address] { + access(all) fun getAllowed(): [Address] { return self.allowed.keys } - pub fun isAllowed(account: Address): Bool { + access(all) fun isAllowed(account: Address): Bool { return self.allowed.containsKey(account) } @@ -48,7 +48,7 @@ pub contract GrantedAccountAccess { } } - pub fun createInfo(): @Info { + access(all) fun createInfo(): @Info { return <- create Info() } diff --git a/contracts/standard/LostAndFound.cdc b/contracts/standard/LostAndFound.cdc index 9d0c3ac2..e43b2593 100644 --- a/contracts/standard/LostAndFound.cdc +++ b/contracts/standard/LostAndFound.cdc @@ -1,9 +1,10 @@ -import FungibleToken from "./FungibleToken.cdc" -import FlowStorageFees from "./FlowStorageFees.cdc" -import FlowToken from "./FlowToken.cdc" -import NonFungibleToken from "./NonFungibleToken.cdc" -import MetadataViews from "./MetadataViews.cdc" -import FeeEstimator from "./FeeEstimator.cdc" +import "FungibleToken" +import "FlowStorageFees" +import "FlowToken" +import "NonFungibleToken" +import "MetadataViews" + +import "FeeEstimator" // LostAndFound // One big problem on the flow blockchain is how to handle accounts that are @@ -26,49 +27,48 @@ import FeeEstimator from "./FeeEstimator.cdc" // - NonFunigibleToken.Receiver // - FungibleToken.Receiver // - LostAndFound.ResourceReceiver (This is a placeholder so that non NFT and FT resources can be utilized here) -pub contract LostAndFound { +access(all) contract LostAndFound { access(contract) let storageFees: {UInt64: UFix64} - pub let LostAndFoundPublicPath: PublicPath - pub let LostAndFoundStoragePath: StoragePath - pub let DepositorPublicPath: PublicPath - pub let DepositorStoragePath: StoragePath + access(all) let LostAndFoundPublicPath: PublicPath + access(all) let LostAndFoundStoragePath: StoragePath + access(all) let DepositorPublicPath: PublicPath + access(all) let DepositorStoragePath: StoragePath + + access(all) event TicketDeposited(redeemer: Address, ticketID: UInt64, type: Type, memo: String?, name: String?, description: String?, thumbnail: String?) + access(all) event TicketRedeemed(redeemer: Address, ticketID: UInt64, type: Type) + access(all) event BinDestroyed(redeemer: Address, type: Type) + access(all) event ShelfDestroyed(redeemer: Address) + + access(all) event DepositorCreated(uuid: UInt64) + access(all) event DepositorBalanceLow(uuid: UInt64, threshold: UFix64, balance: UFix64) + access(all) event DepositorTokensAdded(uuid: UInt64, tokens: UFix64, balance: UFix64) + access(all) event DepositorTokensWithdrawn(uuid: UInt64, tokens: UFix64, balance: UFix64) - pub event TicketDeposited(redeemer: Address, ticketID: UInt64, type: Type, memo: String?, name: String?, description: String?, thumbnail: String?) - pub event TicketRedeemed(redeemer: Address, ticketID: UInt64, type: Type) - pub event BinDestroyed(redeemer: Address, type: Type) - pub event ShelfDestroyed(redeemer: Address) + // Used by the @Depositor resource and controls whether the depositor can be used + // or not to send resources to the LostAndFound + access(all) entitlement Deposit - pub event DepositorCreated(uuid: UInt64) - pub event DepositorBalanceLow(uuid: UInt64, threshold: UFix64, balance: UFix64) - pub event DepositorTokensAdded(uuid: UInt64, tokens: UFix64, balance: UFix64) - pub event DepositorTokensWithdrawn(uuid: UInt64, tokens: UFix64, balance: UFix64) + // Used by the @Depositor resource to manage settings such as low token threshold + access(all) entitlement Owner // Placeholder receiver so that any resource can be supported, not just FT and NFT Receivers - pub resource interface AnyResourceReceiver { - pub fun deposit(resource: @AnyResource) + access(all) resource interface AnyResourceReceiver { + access(Deposit) fun deposit(item: @AnyResource) } - pub resource DepositEstimate { - pub var item: @AnyResource? - pub let storageFee: UFix64 + access(all) resource DepositEstimate { + access(self) var item: @AnyResource? + access(all) let storageFee: UFix64 init(item: @AnyResource, storageFee: UFix64) { self.item <- item self.storageFee = storageFee } - pub fun withdraw(): @AnyResource { - let resource <- self.item <- nil - return <-resource! - } - - destroy() { - pre { - self.item == nil: "cannot destroy with non-null item" - } - - destroy self.item + access(all) fun withdraw(): @AnyResource { + let item <- self.item <- nil + return <-item! } } @@ -77,24 +77,30 @@ pub contract LostAndFound { // - memo: An optional message to attach to this ticket // - redeemer: The address which is allowed to withdraw the item from this ticket // - redeemed: Whether the ticket has been redeemed. This can only be set by the LostAndFound contract - pub resource Ticket { + access(all) resource Ticket { // The item to be redeemed access(contract) var item: @AnyResource? // An optional message to attach to this item. - pub let memo: String? + access(all) let memo: String? // an optional Display view so that frontend's that borrow this ticket know how to show it - pub let display: MetadataViews.Display? + access(all) let display: MetadataViews.Display? // The address that it allowed to withdraw the item fromt this ticket - pub let redeemer: Address + access(all) let redeemer: Address //The type of the resource (non-optional) so that bins can represent the true type of an item - pub let type: Type + access(all) let type: Type // State maintained by LostAndFound - pub var redeemed: Bool + access(all) var redeemed: Bool // flow token amount used to store this ticket is returned when the ticket is redeemed - access(contract) let flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>? + access(contract) let flowTokenRepayment: Capability<&FlowToken.Vault>? - init (item: @AnyResource, memo: String?, display: MetadataViews.Display?, redeemer: Address, flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>?) { + init ( + item: @AnyResource, + memo: String?, + display: MetadataViews.Display?, + redeemer: Address, + flowTokenRepayment: Capability<&FlowToken.Vault>? + ) { self.type = item.getType() self.item <- item self.memo = memo @@ -105,40 +111,40 @@ pub contract LostAndFound { self.flowTokenRepayment = flowTokenRepayment } - pub fun itemType(): Type { + access(all) view fun itemType(): Type { return self.type } - pub fun checkItem(): Bool { + access(all) fun checkItem(): Bool { return self.item != nil } // A function to get depositor address / flow Repayment address - pub fun getFlowRepaymentAddress() : Address? { + access(all) fun getFlowRepaymentAddress() : Address? { return self.flowTokenRepayment?.address } // If this is an instance of NFT, return the id , otherwise return nil - pub fun getNonFungibleTokenID() : UInt64? { - if self.type.isSubtype(of: Type<@NonFungibleToken.NFT>()) { - let ref = (&self.item as auth &AnyResource?)! - let nft = ref as! &NonFungibleToken.NFT + access(all) fun getNonFungibleTokenID() : UInt64? { + if self.type.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) { + let ref = (&self.item as &AnyResource?)! + let nft = ref as! &{NonFungibleToken.NFT} return nft.id } return nil } // If this is an instance of FT, return the vault balance , otherwise return nil - pub fun getFungibleTokenBalance() : UFix64? { - if self.type.isSubtype(of: Type<@FungibleToken.Vault>()) { - let ref = (&self.item as auth &AnyResource?)! - let ft = ref as! &FungibleToken.Vault + access(all) fun getFungibleTokenBalance() : UFix64? { + if self.type.isSubtype(of: Type<@{FungibleToken.Vault}>()) { + let ref = (&self.item as &AnyResource?)! + let ft = ref as! &{FungibleToken.Vault} return ft.balance } return nil } - pub fun withdraw(receiver: Capability) { + access(contract) fun withdraw(receiver: Capability) { pre { receiver.address == self.redeemer: "receiver address and redeemer must match" !self.redeemed: "already redeemed" @@ -147,25 +153,25 @@ pub contract LostAndFound { var redeemableItem <- self.item <- nil let cap = receiver.borrow<&AnyResource>()! - if cap.isInstance(Type<@NonFungibleToken.Collection>()) { - let target = receiver.borrow<&AnyResource{NonFungibleToken.CollectionPublic}>()! - let token <- redeemableItem as! @NonFungibleToken.NFT? + if cap.isInstance(Type<@{NonFungibleToken.CollectionPublic}>()) { + let target = receiver.borrow<&{NonFungibleToken.CollectionPublic}>()! + let token <- redeemableItem as! @{NonFungibleToken.NFT}? self.redeemed = true emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: token.getType()) target.deposit(token: <- token!) return - } else if cap.isInstance(Type<@FungibleToken.Vault>()) { - let target = receiver.borrow<&AnyResource{FungibleToken.Receiver}>()! - let token <- redeemableItem as! @FungibleToken.Vault? + } else if cap.isInstance(Type<@{FungibleToken.Vault}>()) { + let target = receiver.borrow<&{FungibleToken.Receiver}>()! + let token <- redeemableItem as! @{FungibleToken.Vault}? self.redeemed = true emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: token.getType()) target.deposit(from: <- token!) return - } else if cap.isInstance(Type<@AnyResource{LostAndFound.AnyResourceReceiver}>()) { - let target = receiver.borrow<&{LostAndFound.AnyResourceReceiver}>()! + } else if cap.isInstance(Type<@{LostAndFound.AnyResourceReceiver}>()) { + let target = receiver.borrow()! self.redeemed = true emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: redeemableItem.getType()) - target.deposit(resource: <- redeemableItem) + target.deposit(item: <- redeemableItem) return } else{ panic("cannot redeem resource to receiver") @@ -180,15 +186,13 @@ pub contract LostAndFound { return <-redeemableItem! } - // destructon is only allowed if the ticket has been redeemed and the underlying item is a our dummy resource - destroy () { + access(contract) fun safeDestroy() { pre { self.redeemed: "Ticket has not been redeemed" self.item == nil: "can only destroy if not holding any item" } LostAndFound.storageFees.remove(key: self.uuid) - destroy <-self.item } } @@ -196,11 +200,11 @@ pub contract LostAndFound { // A Bin is a resource that gathers tickets whos item have the same type. // For instance, if two TopShot Moments are deposited to the same redeemer, only one bin // will be made which will contain both tickets to redeem each individual moment. - pub resource Bin { + access(all) resource Bin { access(contract) let tickets: @{UInt64:Ticket} access(contract) let type: Type - pub let flowTokenRepayment: Capability<&{FungibleToken.Receiver}>? + access(all) let flowTokenRepayment: Capability<&{FungibleToken.Receiver}>? init (type: Type, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?) { self.tickets <- {} @@ -208,11 +212,11 @@ pub contract LostAndFound { self.flowTokenRepayment = flowTokenRepayment } - pub fun borrowTicket(id: UInt64): &LostAndFound.Ticket? { - return &self.tickets[id] as &LostAndFound.Ticket? + access(all) fun borrowTicket(id: UInt64): &LostAndFound.Ticket? { + return &self.tickets[id] } - pub fun borrowAllTicketsByType(): [&LostAndFound.Ticket] { + access(all) fun borrowAllTicketsByType(): [&LostAndFound.Ticket] { let tickets: [&LostAndFound.Ticket] = [] let ids = self.tickets.keys for id in ids { @@ -243,7 +247,7 @@ pub contract LostAndFound { emit TicketDeposited(redeemer: redeemer, ticketID: ticketID, type: self.type, memo: memo, name: name, description: description, thumbnail: thumbnail) } - pub fun getTicketIDs(): [UInt64] { + access(all) fun getTicketIDs(): [UInt64] { return self.tickets.keys } @@ -252,16 +256,17 @@ pub contract LostAndFound { return <- ticket! } - destroy () { - destroy <-self.tickets - LostAndFound.storageFees.remove(key: self.uuid) + access(contract) fun safeDestroy() { + pre { + self.tickets.length == 0: "cannot destroy bin with tickets in it" + } } } // A shelf is our top-level organization resource. // It groups bins by type to help make discovery of the assets that a // redeeming address can claim. - pub resource Shelf { + access(all) resource Shelf { access(self) let bins: @{String: Bin} access(self) let identifierToType: {String: Type} access(self) let redeemer: Address @@ -274,11 +279,11 @@ pub contract LostAndFound { self.flowTokenRepayment = flowTokenRepayment } - pub fun getOwner(): Address { + access(all) fun getOwner(): Address { return self.owner!.address } - pub fun getRedeemableTypes(): [Type] { + access(all) fun getRedeemableTypes(): [Type] { let types: [Type] = [] for k in self.bins.keys { let t = self.identifierToType[k]! @@ -289,26 +294,26 @@ pub contract LostAndFound { return types } - pub fun hasType(type: Type): Bool { + access(all) fun hasType(type: Type): Bool { return self.bins[type.identifier] != nil } - pub fun borrowBin(type: Type): &LostAndFound.Bin? { - return &self.bins[type.identifier] as &LostAndFound.Bin? + access(all) fun borrowBin(type: Type): &LostAndFound.Bin? { + return &self.bins[type.identifier] } access(contract) fun ensureBin(type: Type, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?): &Bin { if !self.bins.containsKey(type.identifier) { - let storageBefore = LostAndFound.account.storageUsed + let storageBefore = LostAndFound.account.storage.used let bin <- create Bin(type: type, flowTokenRepayment: flowTokenRepayment) let uuid = bin.uuid let oldValue <- self.bins.insert(key: type.identifier, <-bin) - LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storageUsed - storageBefore) + LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore) self.identifierToType[type.identifier] = type destroy oldValue } - return (&self.bins[type.identifier] as &LostAndFound.Bin?)! + return (&self.bins[type.identifier])! } access(contract) fun deposit(ticket: @LostAndFound.Ticket, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?) { @@ -324,7 +329,7 @@ pub contract LostAndFound { // Only one of the three receiver options can be specified, and an optional maximum number of tickets // to redeem can be picked to prevent gas issues in case there are large numbers of tickets to be // redeemed at once. - pub fun redeemAll(type: Type, max: Int?, receiver: Capability) { + access(all) fun redeemAll(type: Type, max: Int?, receiver: Capability) { pre { receiver.address == self.redeemer: "receiver must match the redeemer of this shelf" self.bins.containsKey(type.identifier): "no bin for provided type" @@ -343,7 +348,7 @@ pub contract LostAndFound { } // Redeem a specific ticket instead of all of a certain type. - pub fun redeem(type: Type, ticketID: UInt64, receiver: Capability) { + access(all) fun redeem(type: Type, ticketID: UInt64, receiver: Capability) { pre { receiver.address == self.redeemer: "receiver must match the redeemer of this shelf" self.bins.containsKey(type.identifier): "no bin for provided type" @@ -360,6 +365,8 @@ pub contract LostAndFound { let repaymentVault <- refundProvider.withdraw(amount: LostAndFound.storageFees[uuid]!) refundCap!.borrow()!.deposit(from: <-repaymentVault) } + + ticket.safeDestroy() destroy ticket if borrowedBin.getTicketIDs().length == 0 { @@ -374,77 +381,81 @@ pub contract LostAndFound { let vault <- provider.withdraw(amount: LostAndFound.storageFees[uuid]!) flowTokenRepayment!.borrow()!.deposit(from: <-vault) } + + bin.safeDestroy() destroy bin } } - destroy () { - destroy <- self.bins + access(contract) fun safeDestroy() { + pre { + self.bins.length == 0: "cannot destroy a shelf with bins in it" + } LostAndFound.storageFees.remove(key: self.uuid) } } - access(contract) fun getFlowProvider(): &FlowToken.Vault{FungibleToken.Provider} { - return self.account.borrow<&FlowToken.Vault{FungibleToken.Provider}>(from: /storage/flowTokenVault)! + access(contract) fun getFlowProvider(): auth(FungibleToken.Withdraw) &FlowToken.Vault { + return self.account.storage.borrow(from: /storage/flowTokenVault)! } // ShelfManager is a light-weight wrapper to get our shelves into storage. - pub resource ShelfManager { + access(all) resource ShelfManager { access(self) let shelves: @{Address: Shelf} init() { self.shelves <- {} } - access(contract) fun ensureShelf(_ addr: Address, flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>?): &LostAndFound.Shelf { + access(contract) fun ensureShelf(_ addr: Address, flowTokenRepayment: Capability<&FlowToken.Vault>?): &LostAndFound.Shelf { if !self.shelves.containsKey(addr) { - let storageBefore = LostAndFound.account.storageUsed + let storageBefore = LostAndFound.account.storage.used let shelf <- create Shelf(redeemer: addr, flowTokenRepayment: flowTokenRepayment) let uuid = shelf.uuid let oldValue <- self.shelves.insert(key: addr, <-shelf) - LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storageUsed - storageBefore) + LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore) destroy oldValue } - return (&self.shelves[addr] as &LostAndFound.Shelf?)! + return (&self.shelves[addr])! } - pub fun deposit( + access(all) fun deposit( redeemer: Address, item: @AnyResource, memo: String?, display: MetadataViews.Display?, - storagePayment: &FungibleToken.Vault, - flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>? + storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, + flowTokenRepayment: Capability<&FlowToken.Vault>? ) : UInt64 { pre { flowTokenRepayment == nil || flowTokenRepayment!.check(): "flowTokenRepayment is not valid" storagePayment.getType() == Type<@FlowToken.Vault>(): "storage payment must be in flow tokens" } let receiver = LostAndFound.account - .getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) - .borrow()! + .capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) + .borrow()! - let storageBeforeShelf = LostAndFound.account.storageUsed + let storageBeforeShelf = LostAndFound.account.storage.used let shelf = self.ensureShelf(redeemer, flowTokenRepayment: flowTokenRepayment) - if LostAndFound.account.storageUsed != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil { + if LostAndFound.account.storage.used != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil { receiver.deposit(from: <-storagePayment.withdraw(amount: LostAndFound.storageFees[shelf.uuid]!)) } - let storageBeforeBin = LostAndFound.account.storageUsed + let storageBeforeBin = LostAndFound.account.storage.used let bin = shelf.ensureBin(type: item.getType(), flowTokenRepayment: flowTokenRepayment) - if LostAndFound.account.storageUsed != storageBeforeBin { + if LostAndFound.account.storage.used != storageBeforeBin { receiver.deposit(from: <-storagePayment.withdraw(amount: LostAndFound.storageFees[bin.uuid]!)) } - let storageBefore = LostAndFound.account.storageUsed + let storageBefore = LostAndFound.account.storage.used let ticket <- create Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: flowTokenRepayment) let uuid = ticket.uuid let flowTokenRepayment = ticket.flowTokenRepayment shelf.deposit(ticket: <-ticket, flowTokenRepayment: flowTokenRepayment) - let storageUsedAfter = LostAndFound.account.storageUsed + let storageUsedAfter = LostAndFound.account.storage.used let storageFee = FeeEstimator.storageUsedToFlowAmount(storageUsedAfter - storageBefore) LostAndFound.storageFees[uuid] = storageFee @@ -453,20 +464,20 @@ pub contract LostAndFound { return uuid } - pub fun borrowShelf(redeemer: Address): &LostAndFound.Shelf? { - return &self.shelves[redeemer] as &LostAndFound.Shelf? + access(all) fun borrowShelf(redeemer: Address): &LostAndFound.Shelf? { + return &self.shelves[redeemer] } // deleteShelf // // delete a shelf if it has no redeemable types - pub fun deleteShelf(_ addr: Address) { - let storageBefore = LostAndFound.account.storageUsed + access(all) fun deleteShelf(_ addr: Address) { + let storageBefore = LostAndFound.account.storage.used assert(self.shelves.containsKey(addr), message: "shelf does not exist") let tmp <- self.shelves[addr] <- nil let shelf <-! tmp! - assert(shelf.getRedeemableTypes().length! == 0, message: "shelf still has redeemable types") + assert(shelf.getRedeemableTypes().length == 0, message: "shelf still has redeemable types") let flowTokenRepayment = shelf.flowTokenRepayment let uuid = shelf.uuid if flowTokenRepayment != nil && flowTokenRepayment!.check() && LostAndFound.storageFees[uuid] != nil { @@ -474,23 +485,27 @@ pub contract LostAndFound { let vault <- provider.withdraw(amount: LostAndFound.storageFees[uuid]!) flowTokenRepayment!.borrow()!.deposit(from: <-vault) } + + shelf.safeDestroy() destroy shelf emit ShelfDestroyed(redeemer: addr) } - destroy () { - destroy <-self.shelves + access(contract) fun safeDestroy() { + pre { + self.shelves.length == 0: "cannot destroy shelf manager when it has shelves" + } } } - pub resource interface DepositorPublic { - pub fun balance(): UFix64 - pub fun addFlowTokens(vault: @FlowToken.Vault) + access(all) resource interface DepositorPublic { + access(all) fun balance(): UFix64 + access(all) fun addFlowTokens(vault: @FlowToken.Vault) } - pub resource Depositor: DepositorPublic { + access(all) resource Depositor: DepositorPublic { access(self) let flowTokenVault: @FlowToken.Vault - pub let flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + access(all) let flowTokenRepayment: Capability<&FlowToken.Vault> access(self) var lowBalanceThreshold: UFix64? access(self) fun checkForLowBalance(): Bool { @@ -502,45 +517,45 @@ pub contract LostAndFound { return false } - pub fun setLowBalanceThreshold(threshold: UFix64?) { + access(Owner) fun setLowBalanceThreshold(threshold: UFix64?) { self.lowBalanceThreshold = threshold } - pub fun getLowBalanceThreshold(): UFix64? { + access(Owner) fun getLowBalanceThreshold(): UFix64? { return self.lowBalanceThreshold } - pub fun deposit( + access(Deposit) fun deposit( redeemer: Address, item: @AnyResource, memo: String?, display: MetadataViews.Display? ) : UInt64 { let receiver = LostAndFound.account - .getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) - .borrow()! + .capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) + .borrow()! - let storageBeforeShelf = LostAndFound.account.storageUsed + let storageBeforeShelf = LostAndFound.account.storage.used let shelfManager = LostAndFound.borrowShelfManager() let shelf = shelfManager.ensureShelf(redeemer, flowTokenRepayment: self.flowTokenRepayment) - if LostAndFound.account.storageUsed != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil { + if LostAndFound.account.storage.used != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil { receiver.deposit(from: <-self.withdrawTokens(amount: LostAndFound.storageFees[shelf.uuid]!)) } - let storageBeforeBin = LostAndFound.account.storageUsed + let storageBeforeBin = LostAndFound.account.storage.used let bin = shelf.ensureBin(type: item.getType(), flowTokenRepayment: self.flowTokenRepayment) - if storageBeforeBin != LostAndFound.account.storageUsed { + if storageBeforeBin != LostAndFound.account.storage.used { receiver.deposit(from: <-self.withdrawTokens(amount: LostAndFound.storageFees[bin.uuid]!)) } - let storageBefore = LostAndFound.account.storageUsed + let storageBefore = LostAndFound.account.storage.used let ticket <- create Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: self.flowTokenRepayment) let flowTokenRepayment = ticket.flowTokenRepayment let uuid = ticket.uuid - shelf!.deposit(ticket: <-ticket, flowTokenRepayment: flowTokenRepayment) - - let storageFee = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storageUsed - storageBefore) + shelf.deposit(ticket: <-ticket, flowTokenRepayment: flowTokenRepayment) + + let storageFee = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore) LostAndFound.storageFees[uuid] = storageFee let storagePaymentVault <- self.withdrawTokens(amount: storageFee) @@ -549,69 +564,67 @@ pub contract LostAndFound { return uuid } - pub fun trySendResource( - item: @AnyResource, - cap: Capability, - memo: String?, - display: MetadataViews.Display? + access(Deposit) fun trySendResource( + item: @AnyResource, + cap: Capability, + memo: String?, + display: MetadataViews.Display? ) { - if cap.check<&{NonFungibleToken.CollectionPublic}>() { - let nft <- item as! @NonFungibleToken.NFT + let nft <- item as! @{NonFungibleToken.NFT} cap.borrow<&{NonFungibleToken.CollectionPublic}>()!.deposit(token: <-nft) - } else if cap.check<&{NonFungibleToken.Receiver}>() { - let nft <- item as! @NonFungibleToken.NFT - cap.borrow<&{NonFungibleToken.Receiver}>()!.deposit(token: <-nft) } else if cap.check<&{FungibleToken.Receiver}>() { - let vault <- item as! @FungibleToken.Vault + let vault <- item as! @{FungibleToken.Vault} cap.borrow<&{FungibleToken.Receiver}>()!.deposit(from: <-vault) } else { self.deposit(redeemer: cap.address, item: <-item, memo: memo, display: display) } } - pub fun withdrawTokens(amount: UFix64): @FungibleToken.Vault { + access(Owner) fun withdrawTokens(amount: UFix64): @{FungibleToken.Vault} { let tokens <-self.flowTokenVault.withdraw(amount: amount) emit DepositorTokensWithdrawn(uuid: self.uuid, tokens: amount, balance: self.flowTokenVault.balance) self.checkForLowBalance() return <-tokens } - pub fun addFlowTokens(vault: @FlowToken.Vault) { + access(all) fun addFlowTokens(vault: @FlowToken.Vault) { let tokensAdded = vault.balance self.flowTokenVault.deposit(from: <-vault) emit DepositorTokensAdded(uuid: self.uuid, tokens: tokensAdded, balance: self.flowTokenVault.balance) self.checkForLowBalance() } - pub fun balance(): UFix64 { + access(all) fun balance(): UFix64 { return self.flowTokenVault.balance } - init(_ flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>, lowBalanceThreshold: UFix64?) { + init(_ flowTokenRepayment: Capability<&FlowToken.Vault>, lowBalanceThreshold: UFix64?) { self.flowTokenRepayment = flowTokenRepayment - let vault <- FlowToken.createEmptyVault() - self.flowTokenVault <- vault as! @FlowToken.Vault + let vault <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()) + self.flowTokenVault <- vault self.lowBalanceThreshold = lowBalanceThreshold } - destroy() { - self.flowTokenRepayment.borrow()!.deposit(from: <-self.flowTokenVault) + access(contract) fun safeDestroy() { + pre { + self.flowTokenVault.balance == 0.0: "depositor still has flow tokens to be withdrawn" + } } } - pub fun createDepositor(_ flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>, lowBalanceThreshold: UFix64?): @Depositor { + access(all) fun createDepositor(_ flowTokenRepayment: Capability<&FlowToken.Vault>, lowBalanceThreshold: UFix64?): @Depositor { let depositor <- create Depositor(flowTokenRepayment, lowBalanceThreshold: lowBalanceThreshold) emit DepositorCreated(uuid: depositor.uuid) return <- depositor } - pub fun borrowShelfManager(): &LostAndFound.ShelfManager { - return self.account.getCapability<&LostAndFound.ShelfManager>(LostAndFound.LostAndFoundPublicPath).borrow()! + access(all) fun borrowShelfManager(): &LostAndFound.ShelfManager { + return self.account.capabilities.get<&LostAndFound.ShelfManager>(LostAndFound.LostAndFoundPublicPath).borrow()! } - pub fun borrowAllTicketsByType(addr: Address, type: Type): [&LostAndFound.Ticket] { + access(all) fun borrowAllTicketsByType(addr: Address, type: Type): [&LostAndFound.Ticket] { let manager = LostAndFound.borrowShelfManager() let shelf = manager.borrowShelf(redeemer: addr) if shelf == nil { @@ -626,7 +639,7 @@ pub contract LostAndFound { return bin!.borrowAllTicketsByType() } - pub fun borrowAllTickets(addr: Address): [&LostAndFound.Ticket] { + access(all) fun borrowAllTickets(addr: Address): [&LostAndFound.Ticket] { let manager = LostAndFound.borrowShelfManager() let shelf = manager.borrowShelf(redeemer: addr) if shelf == nil { @@ -634,7 +647,7 @@ pub contract LostAndFound { } let types = shelf!.getRedeemableTypes() - let allTickets = [] as [&LostAndFound.Ticket] + let allTickets: [&Ticket] = [] for type in types { let tickets = LostAndFound.borrowAllTicketsByType(addr: addr, type: type) @@ -644,19 +657,19 @@ pub contract LostAndFound { return allTickets } - pub fun redeemAll(type: Type, max: Int?, receiver: Capability) { + access(all) fun redeemAll(type: Type, max: Int?, receiver: Capability) { let manager = LostAndFound.borrowShelfManager() - let shelf = manager.borrowShelf(redeemer: receiver.address) + let shelf = manager.borrowShelf(redeemer: receiver.address)! assert(shelf != nil, message: "shelf not found") - shelf!.redeemAll(type: type, max: max, receiver: receiver) - let remainingTypes = shelf!.getRedeemableTypes() + shelf.redeemAll(type: type, max: max, receiver: receiver) + let remainingTypes = shelf.getRedeemableTypes() if remainingTypes.length == 0 { manager.deleteShelf(receiver.address) } } - pub fun estimateDeposit( + access(all) fun estimateDeposit( redeemer: Address, item: @AnyResource, memo: String?, @@ -677,7 +690,7 @@ pub contract LostAndFound { } } - let ftReceiver = LostAndFound.account.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let ftReceiver = LostAndFound.account.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) let ticket <- create LostAndFound.Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: ftReceiver) let tmpEstimate <- FeeEstimator.estimateDeposit(item: <-ticket) let tmpItem <- tmpEstimate.withdraw() as! @LostAndFound.Ticket @@ -689,7 +702,7 @@ pub contract LostAndFound { return <- estimate } - pub fun getRedeemableTypes(_ addr: Address): [Type] { + access(all) fun getRedeemableTypes(_ addr: Address): [Type] { let manager = LostAndFound.borrowShelfManager() let shelf = manager.borrowShelf(redeemer: addr) if shelf == nil { @@ -699,13 +712,13 @@ pub contract LostAndFound { return shelf!.getRedeemableTypes() } - pub fun deposit( + access(all) fun deposit( redeemer: Address, item: @AnyResource, memo: String?, display: MetadataViews.Display?, - storagePayment: &FungibleToken.Vault, - flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>? + storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, + flowTokenRepayment: Capability<&FlowToken.Vault>? ) : UInt64 { pre { flowTokenRepayment == nil || flowTokenRepayment!.check(): "flowTokenRepayment is not valid" @@ -716,29 +729,26 @@ pub contract LostAndFound { return shelfManager.deposit(redeemer: redeemer, item: <-item, memo: memo, display: display, storagePayment: storagePayment, flowTokenRepayment: flowTokenRepayment) } - pub fun trySendResource( - resource: @AnyResource, + access(all) fun trySendResource( + item: @AnyResource, cap: Capability, memo: String?, display: MetadataViews.Display?, - storagePayment: &FungibleToken.Vault, - flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, + flowTokenRepayment: Capability<&FlowToken.Vault> ) { if cap.check<&{NonFungibleToken.CollectionPublic}>() { - let nft <- resource as! @NonFungibleToken.NFT + let nft <- item as! @{NonFungibleToken.NFT} cap.borrow<&{NonFungibleToken.CollectionPublic}>()!.deposit(token: <-nft) - } else if cap.check<&{NonFungibleToken.Receiver}>() { - let nft <- resource as! @NonFungibleToken.NFT - cap.borrow<&{NonFungibleToken.Receiver}>()!.deposit(token: <-nft) } else if cap.check<&{FungibleToken.Receiver}>() { - let vault <- resource as! @FungibleToken.Vault + let vault <- item as! @{FungibleToken.Vault} cap.borrow<&{FungibleToken.Receiver}>()!.deposit(from: <-vault) } else { - LostAndFound.deposit(redeemer: cap.address, item: <-resource, memo: memo, display: display, storagePayment: storagePayment, flowTokenRepayment: flowTokenRepayment) + LostAndFound.deposit(redeemer: cap.address, item: <-item, memo: memo, display: display, storagePayment: storagePayment, flowTokenRepayment: flowTokenRepayment) } } - pub fun getAddress(): Address { + access(all) fun getAddress(): Address { return self.account.address } @@ -751,8 +761,10 @@ pub contract LostAndFound { self.DepositorStoragePath = /storage/lostAndFoundDepositor let manager <- create ShelfManager() - self.account.save(<-manager, to: self.LostAndFoundStoragePath) - self.account.link<&LostAndFound.ShelfManager>(self.LostAndFoundPublicPath, target: self.LostAndFoundStoragePath) + self.account.storage.save(<-manager, to: self.LostAndFoundStoragePath) + + let cap = self.account.capabilities.storage.issue<&LostAndFound.ShelfManager>(self.LostAndFoundStoragePath) + self.account.capabilities.publish(cap, at: self.LostAndFoundPublicPath) } } - \ No newline at end of file + diff --git a/contracts/standard/LostAndFoundHelper.cdc b/contracts/standard/LostAndFoundHelper.cdc index 1968b3dc..603bb67a 100644 --- a/contracts/standard/LostAndFoundHelper.cdc +++ b/contracts/standard/LostAndFoundHelper.cdc @@ -1,22 +1,22 @@ -import LostAndFound from "./LostAndFound.cdc" +import "LostAndFound" -pub contract LostAndFoundHelper { +access(all) contract LostAndFoundHelper { - pub struct Ticket { + access(all) struct Ticket { // An optional message to attach to this item. - pub let memo: String? + access(all) let memo: String? // The address that it allowed to withdraw the item fromt this ticket - pub let redeemer: Address + access(all) let redeemer: Address //The type of the resource (non-optional) so that bins can represent the true type of an item - pub let type: Type - pub let typeIdentifier: String + access(all) let type: Type + access(all) let typeIdentifier: String // State maintained by LostAndFound - pub let redeemed: Bool - pub let name : String? - pub let description : String? - pub let thumbnail : String? - pub let ticketID : UInt64? + access(all) let redeemed: Bool + access(all) let name : String? + access(all) let description : String? + access(all) let thumbnail : String? + access(all) let ticketID : UInt64? init(_ ticket: &LostAndFound.Ticket, id: UInt64?) { self.memo = ticket.memo @@ -32,11 +32,11 @@ pub contract LostAndFoundHelper { } - pub fun constructResult(_ ticket: &LostAndFound.Ticket?, id:UInt64?) : LostAndFoundHelper.Ticket? { + access(all) fun constructResult(_ ticket: &LostAndFound.Ticket?, id:UInt64?) : LostAndFoundHelper.Ticket? { if ticket != nil { return LostAndFoundHelper.Ticket(ticket!, id: id) } return nil } -} \ No newline at end of file +} diff --git a/contracts/standard/MetadataViews.cdc b/contracts/standard/MetadataViews.cdc index 31931ab5..05d008eb 100644 --- a/contracts/standard/MetadataViews.cdc +++ b/contracts/standard/MetadataViews.cdc @@ -1,101 +1,49 @@ -/** - -This contract implements the metadata standard proposed -in FLIP-0636. - -Ref: https://github.com/onflow/flow/blob/master/flips/20210916-nft-metadata.md - -Structs and resources can implement one or more -metadata types, called views. Each view type represents -a different kind of metadata, such as a creator biography -or a JPEG image file. -*/ - -import FungibleToken from "./FungibleToken.cdc" -import NonFungibleToken from "./NonFungibleToken.cdc" - -pub contract MetadataViews { - - /// A Resolver provides access to a set of metadata views. - /// - /// A struct or resource (e.g. an NFT) can implement this interface - /// to provide access to the views that it supports. - /// - pub resource interface Resolver { - pub fun getViews(): [Type] - pub fun resolveView(_ view: Type): AnyStruct? - } - - /// A ResolverCollection is a group of view resolvers index by ID. - /// - pub resource interface ResolverCollection { - pub fun borrowViewResolver(id: UInt64): &{Resolver} - pub fun getIDs(): [UInt64] - } - - /// NFTView is a group of views used to give a complete picture of an NFT - /// - pub struct NFTView { - pub let id: UInt64 - pub let uuid: UInt64 - pub let display: Display? - pub let externalURL: ExternalURL? - pub let collectionData: NFTCollectionData? - pub let collectionDisplay: NFTCollectionDisplay? - pub let royalties: Royalties? - pub let traits: Traits? - - init( - id : UInt64, - uuid : UInt64, - display : Display?, - externalURL : ExternalURL?, - collectionData : NFTCollectionData?, - collectionDisplay : NFTCollectionDisplay?, - royalties : Royalties?, - traits: Traits? - ) { - self.id = id - self.uuid = uuid - self.display = display - self.externalURL = externalURL - self.collectionData = collectionData - self.collectionDisplay = collectionDisplay - self.royalties = royalties - self.traits = traits - } - } +import "FungibleToken" +import "NonFungibleToken" +import "ViewResolver" + +/// This contract implements the metadata standard proposed +/// in FLIP-0636. +/// +/// Ref: https://github.com/onflow/flips/blob/main/application/20210916-nft-metadata.md +/// +/// Structs and resources can implement one or more +/// metadata types, called views. Each view type represents +/// a different kind of metadata, such as a creator biography +/// or a JPEG image file. +/// +access(all) contract MetadataViews { /// Display is a basic view that includes the name, description and /// thumbnail for an object. Most objects should implement this view. /// - pub struct Display { + access(all) struct Display { /// The name of the object. /// /// This field will be displayed in lists and therefore should /// be short an concise. /// - pub let name: String + access(all) let name: String /// A written description of the object. /// /// This field will be displayed in a detailed view of the object, /// so can be more verbose (e.g. a paragraph instead of a single line). /// - pub let description: String + access(all) let description: String /// A small thumbnail representation of the object. /// /// This field should be a web-friendly file (i.e JPEG, PNG) /// that can be displayed in lists, link previews, etc. /// - pub let thumbnail: AnyStruct{File} + access(all) let thumbnail: {File} - init( + view init( name: String, description: String, - thumbnail: AnyStruct{File} + thumbnail: {File} ) { self.name = name self.description = description @@ -103,8 +51,12 @@ pub contract MetadataViews { } } - /// A helper to get Display in a typesafe way - pub fun getDisplay(_ viewResolver: &{Resolver}) : Display? { + /// Helper to get Display in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return An optional Display struct + /// + access(all) fun getDisplay(_ viewResolver: &{ViewResolver.Resolver}) : Display? { if let view = viewResolver.resolveView(Type()) { if let v = view as? Display { return v @@ -113,42 +65,39 @@ pub contract MetadataViews { return nil } - /// File is a generic interface that represents a file stored on or off chain. + /// Generic interface that represents a file stored on or off chain. Files + /// can be used to references images, videos and other media. /// - /// Files can be used to references images, videos and other media. - /// - pub struct interface File { - pub fun uri(): String + access(all) struct interface File { + access(all) view fun uri(): String } - /// HTTPFile is a file that is accessible at an HTTP (or HTTPS) URL. + /// View to expose a file that is accessible at an HTTP (or HTTPS) URL. /// - pub struct HTTPFile: File { - pub let url: String + access(all) struct HTTPFile: File { + access(all) let url: String - init(url: String) { + view init(url: String) { self.url = url } - pub fun uri(): String { + access(all) view fun uri(): String { return self.url } } - /// IPFSFile returns a thumbnail image for an object - /// stored as an image file in IPFS. - /// + /// View to expose a file stored on IPFS. /// IPFS images are referenced by their content identifier (CID) /// rather than a direct URI. A client application can use this CID /// to find and load the image via an IPFS gateway. /// - pub struct IPFSFile: File { + access(all) struct IPFSFile: File { /// CID is the content identifier for this IPFS file. /// /// Ref: https://docs.ipfs.io/concepts/content-addressing/ /// - pub let cid: String + access(all) let cid: String /// Path is an optional path to the file resource in an IPFS directory. /// @@ -156,18 +105,19 @@ pub contract MetadataViews { /// /// Ref: https://docs.ipfs.io/concepts/file-systems/ /// - pub let path: String? + access(all) let path: String? - init(cid: String, path: String?) { + view init(cid: String, path: String?) { self.cid = cid self.path = path } /// This function returns the IPFS native URL for this file. - /// /// Ref: https://docs.ipfs.io/how-to/address-ipfs-on-web/#native-urls /// - pub fun uri(): String { + /// @return The string containing the file uri + /// + access(all) view fun uri(): String { if let path = self.path { return "ipfs://".concat(self.cid).concat("/").concat(path) } @@ -176,105 +126,152 @@ pub contract MetadataViews { } } - /// Editions is an optional view for collections that issues multiple objects - /// with the same or similar metadata, for example an X of 100 set. This information is - /// useful for wallets and marketplaes. + /// View to represent a file with an correspoiding mediaType. /// - /// An NFT might be part of multiple editions, which is why the edition information - /// is returned as an arbitrary sized array + access(all) struct Media { + + /// File for the media + /// + access(all) let file: {File} + + /// media-type comes on the form of type/subtype as described here + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types + /// + access(all) let mediaType: String + + view init(file: {File}, mediaType: String) { + self.file=file + self.mediaType=mediaType + } + } + + /// Wrapper view for multiple media views /// - pub struct Editions { + access(all) struct Medias { - /// An arbitrary-sized list for any number of editions - /// that the NFT might be a part of - pub let infoList: [Edition] + /// An arbitrary-sized list for any number of Media items + access(all) let items: [Media] - init(_ infoList: [Edition]) { - self.infoList = infoList + view init(_ items: [Media]) { + self.items = items } } - /// A helper to get Editions in a typesafe way - pub fun getEditions(_ viewResolver: &{Resolver}) : Editions? { - if let view = viewResolver.resolveView(Type()) { - if let v = view as? Editions { + /// Helper to get Medias in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional Medias struct + /// + access(all) fun getMedias(_ viewResolver: &{ViewResolver.Resolver}) : Medias? { + if let view = viewResolver.resolveView(Type()) { + if let v = view as? Medias { return v } } return nil } - /// Edition information for a single edition - pub struct Edition { - - /// The name of the edition - /// For example, this could be Set, Play, Series, - /// or any other way a project could classify its editions - pub let name: String? - - /// The edition number of the object. - /// - /// For an "24 of 100 (#24/100)" item, the number is 24. - /// - pub let number: UInt64 + /// View to represent a license according to https://spdx.org/licenses/ + /// This view can be used if the content of an NFT is licensed. + /// + access(all) struct License { + access(all) let spdxIdentifier: String - /// The max edition number of this type of objects. - /// - /// This field should only be provided for limited-editioned objects. - /// For an "24 of 100 (#24/100)" item, max is 100. - /// For an item with unlimited edition, max should be set to nil. - /// - pub let max: UInt64? + view init(_ identifier: String) { + self.spdxIdentifier = identifier + } + } - init(name: String?, number: UInt64, max: UInt64?) { - if max != nil { - assert(number <= max!, message: "The number cannot be greater than the max number!") + /// Helper to get License in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional License struct + /// + access(all) fun getLicense(_ viewResolver: &{ViewResolver.Resolver}) : License? { + if let view = viewResolver.resolveView(Type()) { + if let v = view as? License { + return v } - self.name = name - self.number = number - self.max = max } + return nil } - - /// A view representing a project-defined serial number for a specific NFT - /// Projects have different definitions for what a serial number should be - /// Some may use the NFTs regular ID and some may use a different classification system - /// The serial number is expected to be unique among other NFTs within that project + /// View to expose a URL to this item on an external site. + /// This can be used by applications like .find and Blocto to direct users + /// to the original link for an NFT or a project page that describes the NFT collection. + /// eg https://www.my-nft-project.com/overview-of-nft-collection /// - pub struct Serial { - pub let number: UInt64 + access(all) struct ExternalURL { + access(all) let url: String - init(_ number: UInt64) { - self.number = number + view init(_ url: String) { + self.url=url } } - /// A helper to get Serial in a typesafe way - pub fun getSerial(_ viewResolver: &{Resolver}) : Serial? { - if let view = viewResolver.resolveView(Type()) { - if let v = view as? Serial { + /// Helper to get ExternalURL in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional ExternalURL struct + /// + access(all) fun getExternalURL(_ viewResolver: &{ViewResolver.Resolver}) : ExternalURL? { + if let view = viewResolver.resolveView(Type()) { + if let v = view as? ExternalURL { return v } } return nil } - /* - * Royalty Views - * Defines the composable royalty standard that gives marketplaces a unified interface - * to support NFT royalties. - * - * Marketplaces can query this `Royalties` struct from NFTs - * and are expected to pay royalties based on these specifications. - * - */ - pub struct Royalties { + /// View that defines the composable royalty standard that gives marketplaces a + /// unified interface to support NFT royalties. + /// + access(all) struct Royalty { + + /// Generic FungibleToken Receiver for the beneficiary of the royalty + /// Can get the concrete type of the receiver with receiver.getType() + /// Recommendation - Users should create a new link for a FlowToken + /// receiver for this using `getRoyaltyReceiverPublicPath()`, and not + /// use the default FlowToken receiver. This will allow users to update + /// the capability in the future to use a more generic capability + access(all) let receiver: Capability<&{FungibleToken.Receiver}> + + /// Multiplier used to calculate the amount of sale value transferred to + /// royalty receiver. Note - It should be between 0.0 and 1.0 + /// Ex - If the sale value is x and multiplier is 0.56 then the royalty + /// value would be 0.56 * x. + /// Generally percentage get represented in terms of basis points + /// in solidity based smart contracts while cadence offers `UFix64` + /// that already supports the basis points use case because its + /// operations are entirely deterministic integer operations and support + /// up to 8 points of precision. + access(all) let cut: UFix64 + + /// Optional description: This can be the cause of paying the royalty, + /// the relationship between the `wallet` and the NFT, or anything else + /// that the owner might want to specify. + access(all) let description: String + + view init(receiver: Capability<&{FungibleToken.Receiver}>, cut: UFix64, description: String) { + pre { + cut >= 0.0 && cut <= 1.0 : "Cut value should be in valid range i.e [0,1]" + } + self.receiver = receiver + self.cut = cut + self.description = description + } + } + + /// Wrapper view for multiple Royalty views. + /// Marketplaces can query this `Royalties` struct from NFTs + /// and are expected to pay royalties based on these specifications. + /// + access(all) struct Royalties { /// Array that tracks the individual royalties access(self) let cutInfos: [Royalty] - pub init(_ cutInfos: [Royalty]) { + access(all) view init(_ cutInfos: [Royalty]) { // Validate that sum of all cut multipliers should not be greater than 1.0 var totalCut = 0.0 for royalty in cutInfos { @@ -286,13 +283,20 @@ pub contract MetadataViews { } /// Return the cutInfos list - pub fun getRoyalties(): [Royalty] { + /// + /// @return An array containing all the royalties structs + /// + access(all) view fun getRoyalties(): [Royalty] { return self.cutInfos } } - /// A helper to get Royalties in a typesafe way - pub fun getRoyalties(_ viewResolver: &{Resolver}) : Royalties? { + /// Helper to get Royalties in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional Royalties struct + /// + access(all) fun getRoyalties(_ viewResolver: &{ViewResolver.Resolver}) : Royalties? { if let view = viewResolver.resolveView(Type()) { if let v = view as? Royalties { return v @@ -301,187 +305,342 @@ pub contract MetadataViews { return nil } - /// Struct to store details of a single royalty cut for a given NFT - pub struct Royalty { - - /// Generic FungibleToken Receiver for the beneficiary of the royalty - /// Can get the concrete type of the receiver with receiver.getType() - /// Recommendation - Users should create a new link for a FlowToken receiver for this using `getRoyaltyReceiverPublicPath()`, - /// and not use the default FlowToken receiver. - /// This will allow users to update the capability in the future to use a more generic capability - pub let receiver: Capability<&AnyResource{FungibleToken.Receiver}> - - /// Multiplier used to calculate the amount of sale value transferred to royalty receiver. - /// Note - It should be between 0.0 and 1.0 - /// Ex - If the sale value is x and multiplier is 0.56 then the royalty value would be 0.56 * x. - /// - /// Generally percentage get represented in terms of basis points - /// in solidity based smart contracts while cadence offers `UFix64` that already supports - /// the basis points use case because its operations - /// are entirely deterministic integer operations and support up to 8 points of precision. - pub let cut: UFix64 - - /// Optional description: This can be the cause of paying the royalty, - /// the relationship between the `wallet` and the NFT, or anything else that the owner might want to specify - pub let description: String - - init(receiver: Capability<&AnyResource{FungibleToken.Receiver}>, cut: UFix64, description: String) { - pre { - cut >= 0.0 && cut <= 1.0 : "Cut value should be in valid range i.e [0,1]" - } - self.receiver = receiver - self.cut = cut - self.description = description - } - } - /// Get the path that should be used for receiving royalties /// This is a path that will eventually be used for a generic switchboard receiver, /// hence the name but will only be used for royalties for now. - pub fun getRoyaltyReceiverPublicPath(): PublicPath { + /// + /// @return The PublicPath for the generic FT receiver + /// + access(all) view fun getRoyaltyReceiverPublicPath(): PublicPath { return /public/GenericFTReceiver } - /// Medias is an optional view for collections that issue objects with multiple Media sources in it + /// View to represent a single field of metadata on an NFT. + /// This is used to get traits of individual key/value pairs along with some + /// contextualized data about the trait /// - pub struct Medias { + access(all) struct Trait { + // The name of the trait. Like Background, Eyes, Hair, etc. + access(all) let name: String - /// An arbitrary-sized list for any number of Media items - pub let items: [Media] + // The underlying value of the trait, the rest of the fields of a trait provide context to the value. + access(all) let value: AnyStruct - init(_ items: [Media]) { - self.items = items + // displayType is used to show some context about what this name and value represent + // for instance, you could set value to a unix timestamp, and specify displayType as "Date" to tell + // platforms to consume this trait as a date and not a number + access(all) let displayType: String? + + // Rarity can also be used directly on an attribute. + // + // This is optional because not all attributes need to contribute to the NFT's rarity. + access(all) let rarity: Rarity? + + view init(name: String, value: AnyStruct, displayType: String?, rarity: Rarity?) { + self.name = name + self.value = value + self.displayType = displayType + self.rarity = rarity } } - /// A helper to get Medias in a typesafe way - pub fun getMedias(_ viewResolver: &{Resolver}) : Medias? { - if let view = viewResolver.resolveView(Type()) { - if let v = view as? Medias { + /// Wrapper view to return all the traits on an NFT. + /// This is used to return traits as individual key/value pairs along with + /// some contextualized data about each trait. + access(all) struct Traits { + access(all) let traits: [Trait] + + view init(_ traits: [Trait]) { + self.traits = traits + } + + /// Adds a single Trait to the Traits view + /// + /// @param Trait: The trait struct to be added + /// + access(all) fun addTrait(_ t: Trait) { + self.traits.append(t) + } + } + + /// Helper to get Traits view in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional Traits struct + /// + access(all) fun getTraits(_ viewResolver: &{ViewResolver.Resolver}) : Traits? { + if let view = viewResolver.resolveView(Type()) { + if let v = view as? Traits { return v } } return nil } - /// A view to represent Media, a file with an correspoiding mediaType. - pub struct Media { + /// Helper function to easily convert a dictionary to traits. For NFT + /// collections that do not need either of the optional values of a Trait, + /// this method should suffice to give them an array of valid traits. + /// + /// @param dict: The dictionary to be converted to Traits + /// @param excludedNames: An optional String array specifying the `dict` + /// keys that are not wanted to become `Traits` + /// @return The generated Traits view + /// + access(all) fun dictToTraits(dict: {String: AnyStruct}, excludedNames: [String]?): Traits { + // Collection owners might not want all the fields in their metadata included. + // They might want to handle some specially, or they might just not want them included at all. + if excludedNames != nil { + for k in excludedNames! { + dict.remove(key: k) + } + } - /// File for the media - pub let file: AnyStruct{File} + let traits: [Trait] = [] + for k in dict.keys { + let trait = Trait(name: k, value: dict[k]!, displayType: nil, rarity: nil) + traits.append(trait) + } + + return Traits(traits) + } + + /// Optional view for collections that issue multiple objects + /// with the same or similar metadata, for example an X of 100 set. This + /// information is useful for wallets and marketplaces. + /// An NFT might be part of multiple editions, which is why the edition + /// information is returned as an arbitrary sized array + /// + access(all) struct Edition { - /// media-type comes on the form of type/subtype as described here https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types - pub let mediaType: String + /// The name of the edition + /// For example, this could be Set, Play, Series, + /// or any other way a project could classify its editions + access(all) let name: String? - init(file: AnyStruct{File}, mediaType: String) { - self.file=file - self.mediaType=mediaType + /// The edition number of the object. + /// For an "24 of 100 (#24/100)" item, the number is 24. + access(all) let number: UInt64 + + /// The max edition number of this type of objects. + /// This field should only be provided for limited-editioned objects. + /// For an "24 of 100 (#24/100)" item, max is 100. + /// For an item with unlimited edition, max should be set to nil. + /// + access(all) let max: UInt64? + + view init(name: String?, number: UInt64, max: UInt64?) { + if max != nil { + assert(number <= max!, message: "The number cannot be greater than the max number!") + } + self.name = name + self.number = number + self.max = max } } - /// A license according to https://spdx.org/licenses/ + /// Wrapper view for multiple Edition views /// - /// This view can be used if the content of an NFT is licensed. - pub struct License { - pub let spdxIdentifier: String + access(all) struct Editions { - init(_ identifier: String) { - self.spdxIdentifier = identifier + /// An arbitrary-sized list for any number of editions + /// that the NFT might be a part of + access(all) let infoList: [Edition] + + view init(_ infoList: [Edition]) { + self.infoList = infoList } } - /// A helper to get License in a typesafe way - pub fun getLicense(_ viewResolver: &{Resolver}) : License? { - if let view = viewResolver.resolveView(Type()) { - if let v = view as? License { + /// Helper to get Editions in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return An optional Editions struct + /// + access(all) fun getEditions(_ viewResolver: &{ViewResolver.Resolver}) : Editions? { + if let view = viewResolver.resolveView(Type()) { + if let v = view as? Editions { return v } } return nil } + /// View representing a project-defined serial number for a specific NFT + /// Projects have different definitions for what a serial number should be + /// Some may use the NFTs regular ID and some may use a different + /// classification system. The serial number is expected to be unique among + /// other NFTs within that project + /// + access(all) struct Serial { + access(all) let number: UInt64 + + view init(_ number: UInt64) { + self.number = number + } + } + + /// Helper to get Serial in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return An optional Serial struct + /// + access(all) fun getSerial(_ viewResolver: &{ViewResolver.Resolver}) : Serial? { + if let view = viewResolver.resolveView(Type()) { + if let v = view as? Serial { + return v + } + } + return nil + } - /// A view to expose a URL to this item on an external site. + /// View to expose rarity information for a single rarity + /// Note that a rarity needs to have either score or description but it can + /// have both /// - /// This can be used by applications like .find and Blocto to direct users to the original link for an NFT. - pub struct ExternalURL { - pub let url: String + access(all) struct Rarity { + /// The score of the rarity as a number + access(all) let score: UFix64? - init(_ url: String) { - self.url=url + /// The maximum value of score + access(all) let max: UFix64? + + /// The description of the rarity as a string. + /// + /// This could be Legendary, Epic, Rare, Uncommon, Common or any other string value + access(all) let description: String? + + view init(score: UFix64?, max: UFix64?, description: String?) { + if score == nil && description == nil { + panic("A Rarity needs to set score, description or both") + } + + self.score = score + self.max = max + self.description = description } } - /// A helper to get ExternalURL in a typesafe way - pub fun getExternalURL(_ viewResolver: &{Resolver}) : ExternalURL? { - if let view = viewResolver.resolveView(Type()) { - if let v = view as? ExternalURL { + /// Helper to get Rarity view in a typesafe way + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional Rarity struct + /// + access(all) fun getRarity(_ viewResolver: &{ViewResolver.Resolver}) : Rarity? { + if let view = viewResolver.resolveView(Type()) { + if let v = view as? Rarity { return v } } return nil } - // A view to expose the information needed store and retrieve an NFT - // - // This can be used by applications to setup a NFT collection with proper storage and public capabilities. - pub struct NFTCollectionData { + /// NFTView wraps all Core views along `id` and `uuid` fields, and is used + /// to give a complete picture of an NFT. Most NFTs should implement this + /// view. + /// + access(all) struct NFTView { + access(all) let id: UInt64 + access(all) let uuid: UInt64 + access(all) let display: MetadataViews.Display? + access(all) let externalURL: MetadataViews.ExternalURL? + access(all) let collectionData: NFTCollectionData? + access(all) let collectionDisplay: NFTCollectionDisplay? + access(all) let royalties: Royalties? + access(all) let traits: Traits? + + view init( + id : UInt64, + uuid : UInt64, + display : MetadataViews.Display?, + externalURL : MetadataViews.ExternalURL?, + collectionData : NFTCollectionData?, + collectionDisplay : NFTCollectionDisplay?, + royalties : Royalties?, + traits: Traits? + ) { + self.id = id + self.uuid = uuid + self.display = display + self.externalURL = externalURL + self.collectionData = collectionData + self.collectionDisplay = collectionDisplay + self.royalties = royalties + self.traits = traits + } + } + + /// Helper to get an NFT view + /// + /// @param id: The NFT id + /// @param viewResolver: A reference to the resolver resource + /// @return A NFTView struct + /// + access(all) fun getNFTView(id: UInt64, viewResolver: &{ViewResolver.Resolver}) : NFTView { + let nftView = viewResolver.resolveView(Type()) + if nftView != nil { + return nftView! as! NFTView + } + + return NFTView( + id : id, + uuid: viewResolver.uuid, + display: MetadataViews.getDisplay(viewResolver), + externalURL : MetadataViews.getExternalURL(viewResolver), + collectionData : self.getNFTCollectionData(viewResolver), + collectionDisplay : self.getNFTCollectionDisplay(viewResolver), + royalties : self.getRoyalties(viewResolver), + traits : self.getTraits(viewResolver) + ) + } + + /// View to expose the information needed store and retrieve an NFT. + /// This can be used by applications to setup a NFT collection with proper + /// storage and public capabilities. + /// + access(all) struct NFTCollectionData { /// Path in storage where this NFT is recommended to be stored. - pub let storagePath: StoragePath + access(all) let storagePath: StoragePath /// Public path which must be linked to expose public capabilities of this NFT /// including standard NFT interfaces and metadataviews interfaces - pub let publicPath: PublicPath - - /// Private path which should be linked to expose the provider - /// capability to withdraw NFTs from the collection holding NFTs - pub let providerPath: PrivatePath - - /// Public collection type that is expected to provide sufficient read-only access to standard - /// functions (deposit + getIDs + borrowNFT) - /// This field is for backwards compatibility with collections that have not used the standard - /// NonFungibleToken.CollectionPublic interface when setting up collections. For new - /// collections, this may be set to be equal to the type specified in `publicLinkedType`. - pub let publicCollection: Type + access(all) let publicPath: PublicPath - /// Type that should be linked at the aforementioned public path. This is normally a - /// restricted type with many interfaces. Notably the `NFT.CollectionPublic`, - /// `NFT.Receiver`, and `MetadataViews.ResolverCollection` interfaces are required. - pub let publicLinkedType: Type + /// The concrete type of the collection that is exposed to the public + /// now that entitlements exist, it no longer needs to be restricted to a specific interface + access(all) let publicCollection: Type - /// Type that should be linked at the aforementioned private path. This is normally - /// a restricted type with at a minimum the `NFT.Provider` interface - pub let providerLinkedType: Type + /// Type that should be linked at the aforementioned public path + access(all) let publicLinkedType: Type /// Function that allows creation of an empty NFT collection that is intended to store /// this NFT. - pub let createEmptyCollection: ((): @NonFungibleToken.Collection) + access(all) let createEmptyCollection: fun(): @{NonFungibleToken.Collection} - init( + view init( storagePath: StoragePath, publicPath: PublicPath, - providerPath: PrivatePath, publicCollection: Type, publicLinkedType: Type, - providerLinkedType: Type, - createEmptyCollectionFunction: ((): @NonFungibleToken.Collection) + createEmptyCollectionFunction: fun(): @{NonFungibleToken.Collection} ) { pre { - publicLinkedType.isSubtype(of: Type<&{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>()): "Public type must include NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, and MetadataViews.ResolverCollection interfaces." - providerLinkedType.isSubtype(of: Type<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>()): "Provider type must include NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, and MetadataViews.ResolverCollection interface." + //TODO: + publicLinkedType.isSubtype(of: Type<&{NonFungibleToken.Receiver}>()): "Public type must include NonFungibleToken.Receiver and ViewResolver.ResolverCollection interfaces." } self.storagePath=storagePath self.publicPath=publicPath - self.providerPath = providerPath self.publicCollection=publicCollection self.publicLinkedType=publicLinkedType - self.providerLinkedType = providerLinkedType self.createEmptyCollection=createEmptyCollectionFunction } } - /// A helper to get NFTCollectionData in a way that will return an typed Optional - pub fun getNFTCollectionData(_ viewResolver: &{Resolver}) : NFTCollectionData? { + /// Helper to get NFTCollectionData in a way that will return an typed Optional + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional NFTCollectionData struct + /// + access(all) fun getNFTCollectionData(_ viewResolver: &{ViewResolver.Resolver}) : NFTCollectionData? { if let view = viewResolver.resolveView(Type()) { if let v = view as? NFTCollectionData { return v @@ -490,37 +649,37 @@ pub contract MetadataViews { return nil } - // A view to expose the information needed to showcase this NFT's collection - // - // This can be used by applications to give an overview and graphics of the NFT collection - // this NFT belongs to. - pub struct NFTCollectionDisplay { + /// View to expose the information needed to showcase this NFT's + /// collection. This can be used by applications to give an overview and + /// graphics of the NFT collection this NFT belongs to. + /// + access(all) struct NFTCollectionDisplay { // Name that should be used when displaying this NFT collection. - pub let name: String + access(all) let name: String // Description that should be used to give an overview of this collection. - pub let description: String + access(all) let description: String // External link to a URL to view more information about this collection. - pub let externalURL: ExternalURL + access(all) let externalURL: MetadataViews.ExternalURL // Square-sized image to represent this collection. - pub let squareImage: Media + access(all) let squareImage: MetadataViews.Media // Banner-sized image for this collection, recommended to have a size near 1200x630. - pub let bannerImage: Media + access(all) let bannerImage: MetadataViews.Media // Social links to reach this collection's social homepages. // Possible keys may be "instagram", "twitter", "discord", etc. - pub let socials: {String: ExternalURL} + access(all) let socials: {String: MetadataViews.ExternalURL} - init( + view init( name: String, description: String, - externalURL: ExternalURL, - squareImage: Media, - bannerImage: Media, - socials: {String: ExternalURL} + externalURL: MetadataViews.ExternalURL, + squareImage: MetadataViews.Media, + bannerImage: MetadataViews.Media, + socials: {String: MetadataViews.ExternalURL} ) { self.name = name self.description = description @@ -531,8 +690,13 @@ pub contract MetadataViews { } } - /// A helper to get NFTCollectionDisplay in a way that will return an typed Optional - pub fun getNFTCollectionDisplay(_ viewResolver: &{Resolver}) : NFTCollectionDisplay? { + /// Helper to get NFTCollectionDisplay in a way that will return a typed + /// Optional + /// + /// @param viewResolver: A reference to the resolver resource + /// @return A optional NFTCollection struct + /// + access(all) fun getNFTCollectionDisplay(_ viewResolver: &{ViewResolver.Resolver}) : NFTCollectionDisplay? { if let view = viewResolver.resolveView(Type()) { if let v = view as? NFTCollectionDisplay { return v @@ -540,129 +704,5 @@ pub contract MetadataViews { } return nil } - - // A view to represent a single field of metadata on an NFT. - // - // This is used to get traits of individual key/value pairs along with some contextualized data about the trait - pub struct Trait { - // The name of the trait. Like Background, Eyes, Hair, etc. - pub let name: String - - // The underlying value of the trait, the rest of the fields of a trait provide context to the value. - pub let value: AnyStruct - - // displayType is used to show some context about what this name and value represent - // for instance, you could set value to a unix timestamp, and specify displayType as "Date" to tell - // platforms to consume this trait as a date and not a number - pub let displayType: String? - - // Rarity can also be used directly on an attribute. - // - // This is optional because not all attributes need to contribute to the NFT's rarity. - pub let rarity: Rarity? - - init(name: String, value: AnyStruct, displayType: String?, rarity: Rarity?) { - self.name = name - self.value = value - self.displayType = displayType - self.rarity = rarity - } - } - - // A view to return all the traits on an NFT. - // - // This is used to return traits as individual key/value pairs along with some contextualized data about each trait. - pub struct Traits { - pub let traits: [Trait] - - init(_ traits: [Trait]) { - self.traits = traits - } - - pub fun addTrait(_ t: Trait) { - self.traits.append(t) - } - } - - /// A helper to get Traits view in a typesafe way - pub fun getTraits(_ viewResolver: &{Resolver}) : Traits? { - if let view = viewResolver.resolveView(Type()) { - if let v = view as? Traits { - return v - } - } - return nil - } - - // A helper function to easily convert a dictionary to traits. For NFT collections that do not need either of the - // optional values of a Trait, this method should suffice to give them an array of valid traits. - pub fun dictToTraits(dict: {String: AnyStruct}, excludedNames: [String]?): Traits { - // Collection owners might not want all the fields in their metadata included. - // They might want to handle some specially, or they might just not want them included at all. - if excludedNames != nil { - for k in excludedNames! { - dict.remove(key: k) - } - } - - let traits: [Trait] = [] - for k in dict.keys { - let trait = Trait(name: k, value: dict[k]!, displayType: nil, rarity: nil) - traits.append(trait) - } - - return Traits(traits) - } - - /// Rarity information for a single rarity - // - /// Note that a rarity needs to have either score or description but it can have both - pub struct Rarity { - /// The score of the rarity as a number - /// - pub let score: UFix64? - - /// The maximum value of score - /// - pub let max: UFix64? - - /// The description of the rarity as a string. - /// - /// This could be Legendary, Epic, Rare, Uncommon, Common or any other string value - pub let description: String? - - init(score: UFix64?, max: UFix64?, description: String?) { - if score == nil && description == nil { - panic("A Rarity needs to set score, description or both") - } - - self.score = score - self.max = max - self.description = description - } - } - - /// A helper to get Rarity view in a typesafe way - pub fun getRarity(_ viewResolver: &{Resolver}) : Rarity? { - if let view = viewResolver.resolveView(Type()) { - if let v = view as? Rarity { - return v - } - } - return nil - } - - pub fun getNFTView(id: UInt64, viewResolver: &{Resolver}) : NFTView { - return NFTView( - id : id, - uuid: viewResolver.uuid, - display: self.getDisplay(viewResolver), - externalURL : self.getExternalURL(viewResolver), - collectionData : self.getNFTCollectionData(viewResolver), - collectionDisplay : self.getNFTCollectionDisplay(viewResolver), - royalties : self.getRoyalties(viewResolver), - traits : self.getTraits(viewResolver) - ) - } - } + diff --git a/contracts/standard/NFTCatalog.cdc b/contracts/standard/NFTCatalog.cdc index 1c34719f..c5136129 100644 --- a/contracts/standard/NFTCatalog.cdc +++ b/contracts/standard/NFTCatalog.cdc @@ -1,4 +1,4 @@ -import MetadataViews from "./MetadataViews.cdc" +import "MetadataViews" // NFTCatalog // @@ -10,19 +10,17 @@ import MetadataViews from "./MetadataViews.cdc" // To make an addition to the catalog you can propose an NFT and provide its metadata. // An Admin can approve a proposal which would add the NFT to the catalog -pub contract NFTCatalog { +access(all) contract NFTCatalog { // EntryAdded // An NFT collection has been added to the catalog - pub event EntryAdded( + access(all) event EntryAdded( collectionIdentifier : String, contractName : String, contractAddress : Address, nftType : Type, storagePath: StoragePath, publicPath: PublicPath, - privatePath: PrivatePath, publicLinkedType : Type, - privateLinkedType : Type, displayName : String, description: String, externalURL : String @@ -30,16 +28,14 @@ pub contract NFTCatalog { // EntryUpdated // An NFT Collection has been updated in the catalog - pub event EntryUpdated( + access(all) event EntryUpdated( collectionIdentifier : String, contractName : String, contractAddress : Address, nftType : Type, storagePath: StoragePath, publicPath: PublicPath, - privatePath: PrivatePath, publicLinkedType : Type, - privateLinkedType : Type, displayName : String, description: String, externalURL : String @@ -47,23 +43,23 @@ pub contract NFTCatalog { // EntryRemoved // An NFT Collection has been removed from the catalog - pub event EntryRemoved(collectionIdentifier : String) + access(all) event EntryRemoved(collectionIdentifier : String) // ProposalEntryAdded // A new proposal to make an addtion to the catalog has been made - pub event ProposalEntryAdded(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address) + access(all) event ProposalEntryAdded(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address) // ProposalEntryUpdated // A proposal has been updated - pub event ProposalEntryUpdated(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address) + access(all) event ProposalEntryUpdated(proposalID : UInt64, collectionIdentifier : String, message: String, status: String, proposer : Address) // ProposalEntryRemoved // A proposal has been removed from storage - pub event ProposalEntryRemoved(proposalID : UInt64) + access(all) event ProposalEntryRemoved(proposalID : UInt64) - pub let ProposalManagerStoragePath: StoragePath + access(all) let ProposalManagerStoragePath: StoragePath - pub let ProposalManagerPublicPath: PublicPath + access(all) let ProposalManagerPublicPath: PublicPath access(self) let catalog: {String : NFTCatalog.NFTCatalogMetadata} // { collectionIdentifier -> Metadata } access(self) let catalogTypeData: {String : {String : Bool}} // Additional view to go from { NFT Type Identifier -> {Collection Identifier : Bool } } @@ -75,60 +71,54 @@ pub contract NFTCatalog { // NFTCatalogProposalManager // Used to authenticate proposals made to the catalog - pub resource interface NFTCatalogProposalManagerPublic { - pub fun getCurrentProposalEntry(): String? + access(all) resource interface NFTCatalogProposalManagerPublic { + access(all) fun getCurrentProposalEntry(): String? } - pub resource NFTCatalogProposalManager : NFTCatalogProposalManagerPublic { - access(self) var currentProposalEntry: String? + access(all) resource NFTCatalogProposalManager : NFTCatalogProposalManagerPublic { + access(self) var currentProposalEntry: String? - pub fun getCurrentProposalEntry(): String? { - return self.currentProposalEntry - } + access(all) fun getCurrentProposalEntry(): String? { + return self.currentProposalEntry + } - pub fun setCurrentProposalEntry(identifier: String?) { - self.currentProposalEntry = identifier - } + access(all) fun setCurrentProposalEntry(identifier: String?) { + self.currentProposalEntry = identifier + } - init () { - self.currentProposalEntry = nil - } + init () { + self.currentProposalEntry = nil + } } // NFTCollectionData // Represents information about an NFT collection resource // Note: Not suing the struct from Metadata standard due to // inability to store functions - pub struct NFTCollectionData { + access(all) struct NFTCollectionData { - pub let storagePath : StoragePath - pub let publicPath : PublicPath - pub let privatePath: PrivatePath - pub let publicLinkedType: Type - pub let privateLinkedType: Type + access(all) let storagePath : StoragePath + access(all) let publicPath : PublicPath + access(all) let publicLinkedType: Type init( storagePath : StoragePath, publicPath : PublicPath, - privatePath : PrivatePath, publicLinkedType : Type, - privateLinkedType : Type ) { self.storagePath = storagePath self.publicPath = publicPath - self.privatePath = privatePath self.publicLinkedType = publicLinkedType - self.privateLinkedType = privateLinkedType } } // NFTCatalogMetadata // Represents data about an NFT - pub struct NFTCatalogMetadata { - pub let contractName : String - pub let contractAddress : Address - pub let nftType: Type - pub let collectionData: NFTCollectionData - pub let collectionDisplay: MetadataViews.NFTCollectionDisplay + access(all) struct NFTCatalogMetadata { + access(all) let contractName : String + access(all) let contractAddress : Address + access(all) let nftType: Type + access(all) let collectionData: NFTCollectionData + access(all) let collectionDisplay: MetadataViews.NFTCollectionDisplay init (contractName : String, contractAddress : Address, nftType: Type, collectionData : NFTCollectionData, collectionDisplay : MetadataViews.NFTCollectionDisplay) { self.contractName = contractName @@ -142,13 +132,13 @@ pub contract NFTCatalog { // NFTCatalogProposal // Represents a proposal to the catalog // Includes data about an NFT - pub struct NFTCatalogProposal { - pub let collectionIdentifier : String - pub let metadata : NFTCatalogMetadata - pub let message : String - pub let status : String - pub let proposer : Address - pub let createdTime : UFix64 + access(all) struct NFTCatalogProposal { + access(all) let collectionIdentifier : String + access(all) let metadata : NFTCatalogMetadata + access(all) let message : String + access(all) let status : String + access(all) let proposer : Address + access(all) let createdTime : UFix64 init(collectionIdentifier : String, metadata : NFTCatalogMetadata, message : String, status : String, proposer : Address) { self.collectionIdentifier = collectionIdentifier @@ -160,19 +150,19 @@ pub contract NFTCatalog { } } - pub fun getCatalog() : {String : NFTCatalogMetadata} { + access(all) fun getCatalog() : {String : NFTCatalogMetadata} { return self.catalog } - pub fun getCatalogEntry(collectionIdentifier : String) : NFTCatalogMetadata? { + access(all) fun getCatalogEntry(collectionIdentifier : String) : NFTCatalogMetadata? { return self.catalog[collectionIdentifier] } - pub fun getCollectionsForType(nftTypeIdentifier: String) : {String : Bool}? { + access(all) fun getCollectionsForType(nftTypeIdentifier: String) : {String : Bool}? { return self.catalogTypeData[nftTypeIdentifier] } - pub fun getCatalogTypeData() : {String : {String : Bool}} { + access(all) fun getCatalogTypeData() : {String : {String : Bool}} { return self.catalogTypeData } @@ -181,8 +171,8 @@ pub contract NFTCatalog { // @param metadata: The Metadata for the NFT collection that will be stored in the catalog // @param message: A message to the catalog owners // @param proposer: Who is making the proposition(the address needs to be verified) - pub fun proposeNFTMetadata(collectionIdentifier : String, metadata : NFTCatalogMetadata, message : String, proposer : Address) : UInt64 { - let proposerManagerCap = getAccount(proposer).getCapability<&NFTCatalogProposalManager{NFTCatalog.NFTCatalogProposalManagerPublic}>(NFTCatalog.ProposalManagerPublicPath) + access(all) fun proposeNFTMetadata(collectionIdentifier : String, metadata : NFTCatalogMetadata, message : String, proposer : Address) : UInt64 { + let proposerManagerCap = getAccount(proposer).capabilities.get<&NFTCatalogProposalManager>(NFTCatalog.ProposalManagerPublicPath)! assert(proposerManagerCap.check(), message : "Proposer needs to set up a manager") @@ -200,14 +190,14 @@ pub contract NFTCatalog { // Withdraw a proposal from the catalog // @param proposalID: The ID of proposal you want to withdraw - pub fun withdrawNFTProposal(proposalID : UInt64) { + access(all) fun withdrawNFTProposal(proposalID : UInt64) { pre { self.catalogProposals[proposalID] != nil : "Invalid Proposal ID" } let proposal = self.catalogProposals[proposalID]! let proposer = proposal.proposer - let proposerManagerCap = getAccount(proposer).getCapability<&NFTCatalogProposalManager{NFTCatalog.NFTCatalogProposalManagerPublic}>(NFTCatalog.ProposalManagerPublicPath) + let proposerManagerCap = getAccount(proposer).capabilities.get<&NFTCatalogProposalManager>(NFTCatalog.ProposalManagerPublicPath)! assert(proposerManagerCap.check(), message : "Proposer needs to set up a manager") @@ -218,15 +208,15 @@ pub contract NFTCatalog { self.removeCatalogProposal(proposalID : proposalID) } - pub fun getCatalogProposals() : {UInt64 : NFTCatalogProposal} { + access(all) fun getCatalogProposals() : {UInt64 : NFTCatalogProposal} { return self.catalogProposals } - pub fun getCatalogProposalEntry(proposalID : UInt64) : NFTCatalogProposal? { + access(all) view fun getCatalogProposalEntry(proposalID : UInt64) : NFTCatalogProposal? { return self.catalogProposals[proposalID] } - pub fun createNFTCatalogProposalManager(): @NFTCatalogProposalManager { + access(all) fun createNFTCatalogProposalManager(): @NFTCatalogProposalManager { return <-create NFTCatalogProposalManager() } @@ -246,9 +236,7 @@ pub contract NFTCatalog { nftType: metadata.nftType, storagePath: metadata.collectionData.storagePath, publicPath: metadata.collectionData.publicPath, - privatePath: metadata.collectionData.privatePath, publicLinkedType : metadata.collectionData.publicLinkedType, - privateLinkedType : metadata.collectionData.privateLinkedType, displayName : metadata.collectionDisplay.name, description: metadata.collectionDisplay.description, externalURL : metadata.collectionDisplay.externalURL.url @@ -275,9 +263,7 @@ pub contract NFTCatalog { nftType: metadata.nftType, storagePath: metadata.collectionData.storagePath, publicPath: metadata.collectionData.publicPath, - privatePath: metadata.collectionData.privatePath, publicLinkedType : metadata.collectionData.publicLinkedType, - privateLinkedType : metadata.collectionData.privateLinkedType, displayName : metadata.collectionDisplay.name, description: metadata.collectionDisplay.description, externalURL : metadata.collectionDisplay.externalURL.url @@ -342,4 +328,4 @@ pub contract NFTCatalog { self.catalogProposals = {} } -} \ No newline at end of file +} diff --git a/contracts/standard/NFTCatalogAdmin.cdc b/contracts/standard/NFTCatalogAdmin.cdc index 3a12f13d..2b9fcf47 100644 --- a/contracts/standard/NFTCatalogAdmin.cdc +++ b/contracts/standard/NFTCatalogAdmin.cdc @@ -1,4 +1,4 @@ -import NFTCatalog from "./NFTCatalog.cdc" +import "NFTCatalog" // NFTCatalogAdmin // @@ -6,31 +6,30 @@ import NFTCatalog from "./NFTCatalog.cdc" // a proxy resource to receive a capability that lets you make changes to the NFT Catalog // and manage proposals -pub contract NFTCatalogAdmin { +access(all) contract NFTCatalogAdmin { - pub let AdminPrivatePath: PrivatePath - pub let AdminStoragePath: StoragePath + access(all) let AdminStoragePath: StoragePath - pub let AdminProxyPublicPath: PublicPath - pub let AdminProxyStoragePath: StoragePath + access(all) let AdminProxyPublicPath: PublicPath + access(all) let AdminProxyStoragePath: StoragePath // Admin // Admin resource to manage NFT Catalog - pub resource Admin { + access(all) resource Admin { - pub fun addCatalogEntry(collectionIdentifier: String, metadata : NFTCatalog.NFTCatalogMetadata) { + access(all) fun addCatalogEntry(collectionIdentifier: String, metadata : NFTCatalog.NFTCatalogMetadata) { NFTCatalog.addCatalogEntry(collectionIdentifier: collectionIdentifier, metadata : metadata) } - pub fun updateCatalogEntry(collectionIdentifier : String , metadata : NFTCatalog.NFTCatalogMetadata) { + access(all) fun updateCatalogEntry(collectionIdentifier : String , metadata : NFTCatalog.NFTCatalogMetadata) { NFTCatalog.updateCatalogEntry(collectionIdentifier: collectionIdentifier, metadata : metadata) } - pub fun removeCatalogEntry(collectionIdentifier : String) { + access(all) fun removeCatalogEntry(collectionIdentifier : String) { NFTCatalog.removeCatalogEntry(collectionIdentifier : collectionIdentifier) } - pub fun approveCatalogProposal(proposalID : UInt64) { + access(all) fun approveCatalogProposal(proposalID : UInt64) { pre { NFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID" NFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.status == "IN_REVIEW" : "Invalid Proposal" @@ -46,7 +45,7 @@ pub contract NFTCatalogAdmin { } } - pub fun rejectCatalogProposal(proposalID : UInt64) { + access(all) fun rejectCatalogProposal(proposalID : UInt64) { pre { NFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID" NFTCatalog.getCatalogProposalEntry(proposalID : proposalID)!.status == "IN_REVIEW" : "Invalid Proposal" @@ -56,7 +55,7 @@ pub contract NFTCatalogAdmin { NFTCatalog.updateCatalogProposal(proposalID : proposalID, proposalMetadata : newCatalogProposalEntry) } - pub fun removeCatalogProposal(proposalID : UInt64) { + access(all) fun removeCatalogProposal(proposalID : UInt64) { pre { NFTCatalog.getCatalogProposalEntry(proposalID : proposalID) != nil : "Invalid Proposal ID" } @@ -70,16 +69,16 @@ pub contract NFTCatalogAdmin { // AdminProxy // A proxy resource that can store // a capability to admin controls - pub resource interface IAdminProxy { - pub fun addCapability(capability : Capability<&Admin>) - pub fun hasCapability() : Bool + access(all) resource interface IAdminProxy { + access(all) fun addCapability(capability : Capability<&Admin>) + access(all) fun hasCapability() : Bool } - pub resource AdminProxy : IAdminProxy { - + access(all) resource AdminProxy : IAdminProxy { + access(self) var capability : Capability<&Admin>? - pub fun addCapability(capability : Capability<&Admin>) { + access(all) fun addCapability(capability : Capability<&Admin>) { pre { capability.check() : "Invalid Admin Capability" self.capability == nil : "Admin Proxy already set" @@ -87,34 +86,32 @@ pub contract NFTCatalogAdmin { self.capability = capability } - pub fun getCapability() : Capability<&Admin>? { + access(all) fun getCapability() : Capability<&Admin>? { return self.capability } - pub fun hasCapability() : Bool { + access(all) fun hasCapability() : Bool { return self.capability != nil } init() { self.capability = nil } - + } - pub fun createAdminProxy() : @AdminProxy { + access(all) fun createAdminProxy() : @AdminProxy { return <- create AdminProxy() } init () { self.AdminProxyPublicPath = /public/nftCatalogAdminProxy self.AdminProxyStoragePath = /storage/nftCatalogAdminProxy - - self.AdminPrivatePath = /private/nftCatalogAdmin + self.AdminStoragePath = /storage/nftCatalogAdmin let admin <- create Admin() - self.account.save(<-admin, to: self.AdminStoragePath) - self.account.link<&Admin>(self.AdminPrivatePath, target: self.AdminStoragePath) + self.account.storage.save(<-admin, to: self.AdminStoragePath) } -} \ No newline at end of file +} diff --git a/contracts/standard/NFTRetrieval.cdc b/contracts/standard/NFTRetrieval.cdc deleted file mode 100644 index 740e0f90..00000000 --- a/contracts/standard/NFTRetrieval.cdc +++ /dev/null @@ -1,125 +0,0 @@ -import MetadataViews from "./MetadataViews.cdc" -import NFTCatalog from "./NFTCatalog.cdc" - -// NFTRetrieval -// -// A helper contract to get NFT's in a users account -// leveraging the NFTCatalog Smart Contract - -pub contract NFTRetrieval { - - pub fun getRecommendedViewsTypes(version: String) : [Type] { - switch version { - case "v1": - return [ - Type(), - Type(), - Type(), - Type(), - Type() - ] - default: - panic("Version not supported") - } - return [] - } - - pub fun getNFTCountFromCap(collectionIdentifier: String, collectionCap : Capability<&AnyResource{MetadataViews.ResolverCollection}>) : UInt64 { - pre { - NFTCatalog.getCatalog()[collectionIdentifier] != nil : "Invalid collection identifier" - } - let catalog = NFTCatalog.getCatalog() - let value = catalog[collectionIdentifier]! - // Check if we have multiple collections for the NFT type... - let hasMultipleCollections = self.hasMultipleCollections(nftTypeIdentifier : value.nftType.identifier) - - if collectionCap.check() { - let collectionRef = collectionCap.borrow()! - if !hasMultipleCollections { - return UInt64(collectionRef.getIDs().length) - } - var count : UInt64 = 0 - for id in collectionRef.getIDs() { - let nftResolver = collectionRef.borrowViewResolver(id: id) - let nftViews = MetadataViews.getNFTView(id: id, viewResolver: nftResolver) - if nftViews.display!.name == value.collectionDisplay.name { - count = count + 1 - } - } - return count - } - return 0 - } - - pub fun getNFTViewsFromCap(collectionIdentifier: String, collectionCap : Capability<&AnyResource{MetadataViews.ResolverCollection}>) : [MetadataViews.NFTView] { - pre { - NFTCatalog.getCatalog()[collectionIdentifier] != nil : "Invalid collection identifier" - } - let catalog = NFTCatalog.getCatalog() - let items : [MetadataViews.NFTView] = [] - let value = catalog[collectionIdentifier]! - - // Check if we have multiple collections for the NFT type... - let hasMultipleCollections = self.hasMultipleCollections(nftTypeIdentifier : value.nftType.identifier) - - if collectionCap.check() { - let collectionRef = collectionCap.borrow()! - for id in collectionRef.getIDs() { - let nftResolver = collectionRef.borrowViewResolver(id: id) - let nftViews = MetadataViews.getNFTView(id: id, viewResolver: nftResolver) - if !hasMultipleCollections { - items.append(nftViews) - } else if nftViews.display!.name == value.collectionDisplay.name { - items.append(nftViews) - } - - } - } - - return items - } - - access(contract) fun hasMultipleCollections(nftTypeIdentifier : String): Bool { - let typeCollections = NFTCatalog.getCollectionsForType(nftTypeIdentifier: nftTypeIdentifier)! - var numberOfCollections = 0 - for identifier in typeCollections.keys { - let existence = typeCollections[identifier]! - if existence { - numberOfCollections = numberOfCollections + 1 - } - if numberOfCollections > 1 { - return true - } - } - return false - } - - //LEGACY - DO NOT USE - pub struct BaseNFTViewsV1 { - pub let id: UInt64 - pub let display: MetadataViews.Display? - pub let externalURL: MetadataViews.ExternalURL? - pub let collectionData: MetadataViews.NFTCollectionData? - pub let collectionDisplay: MetadataViews.NFTCollectionDisplay? - pub let royalties: MetadataViews.Royalties? - - init( - id : UInt64, - display : MetadataViews.Display?, - externalURL : MetadataViews.ExternalURL?, - collectionData : MetadataViews.NFTCollectionData?, - collectionDisplay : MetadataViews.NFTCollectionDisplay?, - royalties : MetadataViews.Royalties? - ) { - self.id = id - self.display = display - self.externalURL = externalURL - self.collectionData = collectionData - self.collectionDisplay = collectionDisplay - self.royalties = royalties - } - } - - init() {} - -} \ No newline at end of file diff --git a/contracts/standard/NFTStorefront.cdc b/contracts/standard/NFTStorefront.cdc index bb52b113..c6bdeb3d 100644 --- a/contracts/standard/NFTStorefront.cdc +++ b/contracts/standard/NFTStorefront.cdc @@ -1,5 +1,5 @@ -import FungibleToken from "./FungibleToken.cdc" -import NonFungibleToken from "./NonFungibleToken.cdc" +import "FungibleToken" +import "NonFungibleToken" // NFTStorefront // @@ -21,12 +21,12 @@ import NonFungibleToken from "./NonFungibleToken.cdc" // Marketplaces and other aggregators can watch for Listing events // and list items of interest. // -pub contract NFTStorefront { +access(all) contract NFTStorefront { // NFTStorefrontInitialized // This contract has been deployed. // Event consumers can now expect events from this contract. // - pub event NFTStorefrontInitialized() + access(all) event NFTStorefrontInitialized() // StorefrontInitialized // A Storefront resource has been created. @@ -40,14 +40,14 @@ pub contract NFTStorefront { // If the seller moves the Storefront while the listing is valid, // that is on them. // - pub event StorefrontInitialized(storefrontResourceID: UInt64) + access(all) event StorefrontInitialized(storefrontResourceID: UInt64) // StorefrontDestroyed // A Storefront has been destroyed. // Event consumers can now stop processing events from this Storefront. // Note that we do not specify an address. // - pub event StorefrontDestroyed(storefrontResourceID: UInt64) + access(all) event StorefrontDestroyed(storefrontResourceID: UInt64) // ListingAvailable // A listing has been created and added to a Storefront resource. @@ -55,7 +55,7 @@ pub contract NFTStorefront { // the state of the accounts they refer to may be changed outside of the // NFTStorefront workflow, so be careful to check when using them. // - pub event ListingAvailable( + access(all) event ListingAvailable( storefrontAddress: Address, listingResourceID: UInt64, nftType: Type, @@ -67,7 +67,7 @@ pub contract NFTStorefront { // ListingCompleted // The listing has been resolved. It has either been purchased, or removed and destroyed. // - pub event ListingCompleted( + access(all) event ListingCompleted( listingResourceID: UInt64, storefrontResourceID: UInt64, purchased: Bool, @@ -77,28 +77,28 @@ pub contract NFTStorefront { // StorefrontStoragePath // The location in storage that a Storefront resource should be located. - pub let StorefrontStoragePath: StoragePath + access(all) let StorefrontStoragePath: StoragePath // StorefrontPublicPath // The public location for a Storefront link. - pub let StorefrontPublicPath: PublicPath + access(all) let StorefrontPublicPath: PublicPath // SaleCut // A struct representing a recipient that must be sent a certain amount // of the payment when a token is sold. // - pub struct SaleCut { + access(all) struct SaleCut { // The receiver for the payment. // Note that we do not store an address to find the Vault that this represents, // as the link or resource that we fetch in this way may be manipulated, // so to find the address that a cut goes to you must get this struct and then // call receiver.borrow()!.owner.address on it. // This can be done efficiently in a script. - pub let receiver: Capability<&{FungibleToken.Receiver}> + access(all) let receiver: Capability<&{FungibleToken.Receiver}> // The amount of the payment FungibleToken that will be paid to the receiver. - pub let amount: UFix64 + access(all) let amount: UFix64 // initializer // @@ -112,24 +112,24 @@ pub contract NFTStorefront { // ListingDetails // A struct containing a Listing's data. // - pub struct ListingDetails { + access(all) struct ListingDetails { // The Storefront that the Listing is stored in. // Note that this resource cannot be moved to a different Storefront, // so this is OK. If we ever make it so that it *can* be moved, // this should be revisited. - pub var storefrontID: UInt64 + access(all) var storefrontID: UInt64 // Whether this listing has been purchased or not. - pub var purchased: Bool + access(all) var purchased: Bool // The Type of the NonFungibleToken.NFT that is being listed. - pub let nftType: Type + access(all) let nftType: Type // The ID of the NFT within that type. - pub let nftID: UInt64 + access(all) let nftID: UInt64 // The Type of the FungibleToken that payments must be made in. - pub let salePaymentVaultType: Type + access(all) let salePaymentVaultType: Type // The amount that must be paid in the specified FungibleToken. - pub let salePrice: UFix64 + access(all) let salePrice: UFix64 // This specifies the division of payment between recipients. - pub let saleCuts: [SaleCut] + access(all) let saleCuts: [SaleCut] // setToPurchased // Irreversibly set this listing as purchased. @@ -178,22 +178,22 @@ pub contract NFTStorefront { // ListingPublic // An interface providing a useful public interface to a Listing. // - pub resource interface ListingPublic { + access(all) resource interface ListingPublic { // borrowNFT // This will assert in the same way as the NFT standard borrowNFT() // if the NFT is absent, for example if it has been sold via another listing. // - pub fun borrowNFT(): &NonFungibleToken.NFT + access(all) borrowNFT(): &NonFungibleToken.NFT // purchase // Purchase the listing, buying the token. // This pays the beneficiaries and returns the token to the buyer. // - pub fun purchase(payment: @FungibleToken.Vault): @NonFungibleToken.NFT + access(all) purchase(payment: @FungibleToken.Vault): @NonFungibleToken.NFT // getDetails // - pub fun getDetails(): ListingDetails + access(all) getDetails(): ListingDetails } @@ -202,7 +202,7 @@ pub contract NFTStorefront { // A resource that allows an NFT to be sold for an amount of a given FungibleToken, // and for the proceeds of that sale to be split between several recipients. // - pub resource Listing: ListingPublic { + access(all) resource Listing: ListingPublic { // The simple (non-Capability, non-complex) details of the sale access(self) let details: ListingDetails @@ -210,13 +210,13 @@ pub contract NFTStorefront { // This capability allows the resource to withdraw *any* NFT, so you should be careful when giving // such a capability to a resource and always check its code to make sure it will use it in the // way that it claims. - access(contract) let nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}> + access(contract) let nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}> // borrowNFT // This will assert in the same way as the NFT standard borrowNFT() // if the NFT is absent, for example if it has been sold via another listing. // - pub fun borrowNFT(): &NonFungibleToken.NFT { + access(all) borrowNFT(): &NonFungibleToken.NFT { let ref = self.nftProviderCapability.borrow()!.borrowNFT(id: self.getDetails().nftID) //- CANNOT DO THIS IN PRECONDITION: "member of restricted type is not accessible: isInstance" // result.isInstance(self.getDetails().nftType): "token has wrong type" @@ -230,7 +230,7 @@ pub contract NFTStorefront { // This avoids having more public variables and getter methods for them, and plays // nicely with scripts (which cannot return resources). // - pub fun getDetails(): ListingDetails { + access(all) getDetails(): ListingDetails { return self.details } @@ -238,7 +238,7 @@ pub contract NFTStorefront { // Purchase the listing, buying the token. // This pays the beneficiaries and returns the token to the buyer. // - pub fun purchase(payment: @FungibleToken.Vault): @NonFungibleToken.NFT { + access(all) purchase(payment: @FungibleToken.Vault): @NonFungibleToken.NFT { pre { self.details.purchased == false: "listing has already been purchased" payment.isInstance(self.details.salePaymentVaultType): "payment vault is not requested fungible token" @@ -318,7 +318,7 @@ pub contract NFTStorefront { // initializer // init ( - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, nftType: Type, nftID: UInt64, salePaymentVaultType: Type, @@ -354,12 +354,12 @@ pub contract NFTStorefront { // An interface for adding and removing Listings within a Storefront, // intended for use by the Storefront's own // - pub resource interface StorefrontManager { + access(all) resource interface StorefrontManager { // createListing // Allows the Storefront owner to create and insert Listings. // - pub fun createListing( - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, + access(all) createListing( + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, nftType: Type, nftID: UInt64, salePaymentVaultType: Type, @@ -368,32 +368,32 @@ pub contract NFTStorefront { // removeListing // Allows the Storefront owner to remove any sale listing, acepted or not. // - pub fun removeListing(listingResourceID: UInt64) + access(all) removeListing(listingResourceID: UInt64) } // StorefrontPublic // An interface to allow listing and borrowing Listings, and purchasing items via Listings // in a Storefront. // - pub resource interface StorefrontPublic { - pub fun getListingIDs(): [UInt64] - pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? - pub fun cleanup(listingResourceID: UInt64) + access(all) resource interface StorefrontPublic { + access(all) getListingIDs(): [UInt64] + access(all) borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? + access(all) cleanup(listingResourceID: UInt64) } // Storefront // A resource that allows its owner to manage a list of Listings, and anyone to interact with them // in order to query their details and purchase the NFTs that they represent. // - pub resource Storefront : StorefrontManager, StorefrontPublic { + access(all) resource Storefront : StorefrontManager, StorefrontPublic { // The dictionary of Listing uuids to Listing resources. access(self) var listings: @{UInt64: Listing} // insert - // Create and publish a Listing for an NFT. + // Create and access(all)lish a Listing for an NFT. // - pub fun createListing( - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, + access(all) createListing( + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, nftType: Type, nftID: UInt64, salePaymentVaultType: Type, @@ -433,7 +433,7 @@ pub contract NFTStorefront { // removeListing // Remove a Listing that has not yet been purchased from the collection and destroy it. // - pub fun removeListing(listingResourceID: UInt64) { + access(all) removeListing(listingResourceID: UInt64) { let listing <- self.listings.remove(key: listingResourceID) ?? panic("missing Listing") @@ -444,14 +444,14 @@ pub contract NFTStorefront { // getListingIDs // Returns an array of the Listing resource IDs that are in the collection // - pub fun getListingIDs(): [UInt64] { + access(all) getListingIDs(): [UInt64] { return self.listings.keys } // borrowSaleItem // Returns a read-only view of the SaleItem for the given listingID if it is contained by this collection. // - pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? { + access(all) borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? { if self.listings[listingResourceID] != nil { return &self.listings[listingResourceID] as! &Listing{ListingPublic}? } else { @@ -464,7 +464,7 @@ pub contract NFTStorefront { // Anyone can call, but at present it only benefits the account owner to do so. // Kind purchasers can however call it if they like. // - pub fun cleanup(listingResourceID: UInt64) { + access(all) cleanup(listingResourceID: UInt64) { pre { self.listings[listingResourceID] != nil: "could not find listing with given id" } @@ -496,7 +496,7 @@ pub contract NFTStorefront { // createStorefront // Make creating a Storefront publicly accessible. // - pub fun createStorefront(): @Storefront { + access(all) createStorefront(): @Storefront { return <-create Storefront() } diff --git a/contracts/standard/NFTStorefrontV2.cdc b/contracts/standard/NFTStorefrontV2.cdc index cb2b4f17..9b4ae548 100644 --- a/contracts/standard/NFTStorefrontV2.cdc +++ b/contracts/standard/NFTStorefrontV2.cdc @@ -1,5 +1,5 @@ -import FungibleToken from "./FungibleToken.cdc" -import NonFungibleToken from "./NonFungibleToken.cdc" +import "FungibleToken" +import "NonFungibleToken" /// NFTStorefrontV2 /// @@ -26,7 +26,7 @@ import NonFungibleToken from "./NonFungibleToken.cdc" /// Marketplaces and other aggregators can watch for Listing events /// and list items of interest. /// -pub contract NFTStorefrontV2 { +access(all) contract NFTStorefrontV2 { /// StorefrontInitialized /// A Storefront resource has been created. @@ -40,14 +40,14 @@ pub contract NFTStorefrontV2 { /// If the seller moves the Storefront while the listing is valid, /// that is on them. /// - pub event StorefrontInitialized(storefrontResourceID: UInt64) + access(all) event StorefrontInitialized(storefrontResourceID: UInt64) /// StorefrontDestroyed /// A Storefront has been destroyed. /// Event consumers can now stop processing events from this Storefront. /// Note that we do not specify an address. /// - pub event StorefrontDestroyed(storefrontResourceID: UInt64) + access(all) event StorefrontDestroyed(storefrontResourceID: UInt64) /// ListingAvailable /// A listing has been created and added to a Storefront resource. @@ -55,7 +55,7 @@ pub contract NFTStorefrontV2 { /// the state of the accounts they refer to may change outside of the /// NFTStorefrontV2 workflow, so be careful to check when using them. /// - pub event ListingAvailable( + access(all) event ListingAvailable( storefrontAddress: Address, listingResourceID: UInt64, nftType: Type, @@ -72,7 +72,7 @@ pub contract NFTStorefrontV2 { /// ListingCompleted /// The listing has been resolved. It has either been purchased, removed or destroyed. /// - pub event ListingCompleted( + access(all) event ListingCompleted( listingResourceID: UInt64, storefrontResourceID: UInt64, purchased: Bool, @@ -90,32 +90,32 @@ pub contract NFTStorefrontV2 { /// UnpaidReceiver /// A entitled receiver has not been paid during the sale of the NFT. /// - pub event UnpaidReceiver(receiver: Address, entitledSaleCut: UFix64) + access(all) event UnpaidReceiver(receiver: Address, entitledSaleCut: UFix64) /// StorefrontStoragePath /// The location in storage that a Storefront resource should be located. - pub let StorefrontStoragePath: StoragePath + access(all) let StorefrontStoragePath: StoragePath /// StorefrontPublicPath /// The public location for a Storefront link. - pub let StorefrontPublicPath: PublicPath + access(all) let StorefrontPublicPath: PublicPath /// SaleCut /// A struct representing a recipient that must be sent a certain amount /// of the payment when a token is sold. /// - pub struct SaleCut { + access(all) struct SaleCut { /// The receiver for the payment. /// Note that we do not store an address to find the Vault that this represents, /// as the link or resource that we fetch in this way may be manipulated, /// so to find the address that a cut goes to you must get this struct and then /// call receiver.borrow()!.owner.address on it. /// This can be done efficiently in a script. - pub let receiver: Capability<&{FungibleToken.Receiver}> + access(all) let receiver: Capability<&{FungibleToken.Receiver}> /// The amount of the payment FungibleToken that will be paid to the receiver. - pub let amount: UFix64 + access(all) let amount: UFix64 /// initializer /// @@ -129,33 +129,33 @@ pub contract NFTStorefrontV2 { /// ListingDetails /// A struct containing a Listing's data. /// - pub struct ListingDetails { + access(all) struct ListingDetails { /// The Storefront that the Listing is stored in. /// Note that this resource cannot be moved to a different Storefront, /// so this is OK. If we ever make it so that it *can* be moved, /// this should be revisited. - pub var storefrontID: UInt64 + access(all) var storefrontID: UInt64 /// Whether this listing has been purchased or not. - pub var purchased: Bool + access(all) var purchased: Bool /// The Type of the NonFungibleToken.NFT that is being listed. - pub let nftType: Type + access(all) let nftType: Type /// The Resource ID of the NFT which can only be set in the contract - pub let nftUUID: UInt64 + access(all) let nftUUID: UInt64 /// The unique identifier of the NFT that will get sell. - pub let nftID: UInt64 + access(all) let nftID: UInt64 /// The Type of the FungibleToken that payments must be made in. - pub let salePaymentVaultType: Type + access(all) let salePaymentVaultType: Type /// The amount that must be paid in the specified FungibleToken. - pub let salePrice: UFix64 + access(all) let salePrice: UFix64 /// This specifies the division of payment between recipients. - pub let saleCuts: [SaleCut] + access(all) let saleCuts: [SaleCut] /// Allow different dapp teams to provide custom strings as the distinguisher string /// that would help them to filter events related to their customID. - pub var customID: String? + access(all) var customID: String? /// Commission available to be claimed by whoever facilitates the sale. - pub let commissionAmount: UFix64 + access(all) let commissionAmount: UFix64 /// Expiry of listing - pub let expiry: UInt64 + access(all) let expiry: UInt64 /// Irreversibly set this listing as purchased. /// @@ -220,30 +220,30 @@ pub contract NFTStorefrontV2 { /// ListingPublic /// An interface providing a useful public interface to a Listing. /// - pub resource interface ListingPublic { + access(all) resource interface ListingPublic { /// borrowNFT /// This will assert in the same way as the NFT standard borrowNFT() /// if the NFT is absent, for example if it has been sold via another listing. /// - pub fun borrowNFT(): &NonFungibleToken.NFT? + access(all) borrowNFT(): &NonFungibleToken.NFT? /// purchase /// Purchase the listing, buying the token. /// This pays the beneficiaries and returns the token to the buyer. /// - pub fun purchase( + access(all) purchase( payment: @FungibleToken.Vault, commissionRecipient: Capability<&{FungibleToken.Receiver}>?, ): @NonFungibleToken.NFT /// getDetails /// Fetches the details of the listing. - pub fun getDetails(): ListingDetails + access(all) getDetails(): ListingDetails /// getAllowedCommissionReceivers /// Fetches the allowed marketplaces capabilities or commission receivers. /// If it returns `nil` then commission is up to grab by anyone. - pub fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? + access(all) getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? } @@ -252,7 +252,7 @@ pub contract NFTStorefrontV2 { /// A resource that allows an NFT to be sold for an amount of a given FungibleToken, /// and for the proceeds of that sale to be split between several recipients. /// - pub resource Listing: ListingPublic { + access(all) resource Listing: ListingPublic { /// The simple (non-Capability, non-complex) details of the sale access(self) let details: ListingDetails @@ -260,7 +260,7 @@ pub contract NFTStorefrontV2 { /// This capability allows the resource to withdraw *any* NFT, so you should be careful when giving /// such a capability to a resource and always check its code to make sure it will use it in the /// way that it claims. - access(contract) let nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}> + access(contract) let nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}> /// An optional list of marketplaces capabilities that are approved /// to receive the marketplace commission. @@ -271,7 +271,7 @@ pub contract NFTStorefrontV2 { /// if the NFT is absent, for example if it has been sold via another listing. /// it will return nil. /// - pub fun borrowNFT(): &NonFungibleToken.NFT? { + access(all) borrowNFT(): &NonFungibleToken.NFT? { let ref = self.nftProviderCapability.borrow()!.borrowNFT(id: self.details.nftID) if ref.isInstance(self.details.nftType) && ref.id == self.details.nftID { return ref as! &NonFungibleToken.NFT @@ -282,14 +282,14 @@ pub contract NFTStorefrontV2 { /// getDetails /// Get the details of listing. /// - pub fun getDetails(): ListingDetails { + access(all) getDetails(): ListingDetails { return self.details } /// getAllowedCommissionReceivers /// Fetches the allowed marketplaces capabilities or commission receivers. /// If it returns `nil` then commission is up to grab by anyone. - pub fun getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? { + access(all) getAllowedCommissionReceivers(): [Capability<&{FungibleToken.Receiver}>]? { return self.marketplacesCapability } @@ -297,7 +297,7 @@ pub contract NFTStorefrontV2 { /// Purchase the listing, buying the token. /// This pays the beneficiaries and commission to the facilitator and returns extra token to the buyer. /// This also cleans up duplicate listings for the item being purchased. - pub fun purchase( + access(all) purchase( payment: @FungibleToken.Vault, commissionRecipient: Capability<&{FungibleToken.Receiver}>?, ): @NonFungibleToken.NFT { @@ -433,7 +433,7 @@ pub contract NFTStorefrontV2 { /// initializer /// init ( - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, nftType: Type, nftUUID: UInt64, nftID: UInt64, @@ -479,12 +479,12 @@ pub contract NFTStorefrontV2 { /// An interface for adding and removing Listings within a Storefront, /// intended for use by the Storefront's owner /// - pub resource interface StorefrontManager { + access(all) resource interface StorefrontManager { /// createListing /// Allows the Storefront owner to create and insert Listings. /// - pub fun createListing( - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, + access(all) createListing( + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, nftType: Type, nftID: UInt64, salePaymentVaultType: Type, @@ -498,28 +498,28 @@ pub contract NFTStorefrontV2 { /// removeListing /// Allows the Storefront owner to remove any sale listing, acepted or not. /// - pub fun removeListing(listingResourceID: UInt64) + access(all) removeListing(listingResourceID: UInt64) } /// StorefrontPublic /// An interface to allow listing and borrowing Listings, and purchasing items via Listings /// in a Storefront. /// - pub resource interface StorefrontPublic { - pub fun getListingIDs(): [UInt64] - pub fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] - pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? - pub fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) + access(all) resource interface StorefrontPublic { + access(all) getListingIDs(): [UInt64] + access(all) getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] + access(all) borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? + access(all) cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) access(contract) fun cleanup(listingResourceID: UInt64) - pub fun getExistingListingIDs(nftType: Type, nftID: UInt64): [UInt64] - pub fun cleanupPurchasedListings(listingResourceID: UInt64) + access(all) getExistingListingIDs(nftType: Type, nftID: UInt64): [UInt64] + access(all) cleanupPurchasedListings(listingResourceID: UInt64) } /// Storefront /// A resource that allows its owner to manage a list of Listings, and anyone to interact with them /// in order to query their details and purchase the NFTs that they represent. /// - pub resource Storefront : StorefrontManager, StorefrontPublic { + access(all) resource Storefront : StorefrontManager, StorefrontPublic { /// The dictionary of Listing uuids to Listing resources. access(contract) var listings: @{UInt64: Listing} /// Dictionary to keep track of listing ids for same NFTs listing. @@ -527,10 +527,10 @@ pub contract NFTStorefrontV2 { access(contract) var listedNFTs: {String: {UInt64 : [UInt64]}} /// insert - /// Create and publish a Listing for an NFT. + /// Create and access(all)lish a Listing for an NFT. /// - pub fun createListing( - nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, + access(all) createListing( + nftProviderCapability: Capability<&{NonFungibleToken.Provider, NonFungibleToken.Collection}>, nftType: Type, nftID: UInt64, salePaymentVaultType: Type, @@ -630,7 +630,7 @@ pub contract NFTStorefrontV2 { /// Remove a Listing that has not yet been purchased from the collection and destroy it. /// It can only be executed by the StorefrontManager resource owner. /// - pub fun removeListing(listingResourceID: UInt64) { + access(all) removeListing(listingResourceID: UInt64) { let listing <- self.listings.remove(key: listingResourceID) ?? panic("missing Listing") let listingDetails = listing.getDetails() @@ -642,14 +642,14 @@ pub contract NFTStorefrontV2 { /// getListingIDs /// Returns an array of the Listing resource IDs that are in the collection /// - pub fun getListingIDs(): [UInt64] { + access(all) getListingIDs(): [UInt64] { return self.listings.keys } /// getExistingListingIDs /// Returns an array of listing IDs of the given `nftType` and `nftID`. /// - pub fun getExistingListingIDs(nftType: Type, nftID: UInt64): [UInt64] { + access(all) getExistingListingIDs(nftType: Type, nftID: UInt64): [UInt64] { if self.listedNFTs[nftType.identifier] == nil || self.listedNFTs[nftType.identifier]![nftID] == nil { return [] } @@ -660,7 +660,7 @@ pub contract NFTStorefrontV2 { /// cleanupPurchasedListings /// Allows anyone to remove already purchased listings. /// - pub fun cleanupPurchasedListings(listingResourceID: UInt64) { + access(all) cleanupPurchasedListings(listingResourceID: UInt64) { pre { self.listings[listingResourceID] != nil: "could not find listing with given id" self.borrowListing(listingResourceID: listingResourceID)!.getDetails().purchased == true: "listing not purchased yet" @@ -675,7 +675,7 @@ pub contract NFTStorefrontV2 { /// getDuplicateListingIDs /// Returns an array of listing IDs that are duplicates of the given `nftType` and `nftID`. /// - pub fun getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] { + access(all) getDuplicateListingIDs(nftType: Type, nftID: UInt64, listingID: UInt64): [UInt64] { var listingIDs = self.getExistingListingIDs(nftType: nftType, nftID: nftID) // Verify that given listing Id also a part of the `listingIds` @@ -698,7 +698,7 @@ pub contract NFTStorefrontV2 { /// cleanupExpiredListings /// Cleanup the expired listing by iterating over the provided range of indexes. /// - pub fun cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) { + access(all) cleanupExpiredListings(fromIndex: UInt64, toIndex: UInt64) { pre { fromIndex <= toIndex : "Incorrect start index" Int(toIndex - fromIndex) < self.getListingIDs().length : "Provided range is out of bound" @@ -721,7 +721,7 @@ pub contract NFTStorefrontV2 { /// borrowSaleItem /// Returns a read-only view of the SaleItem for the given listingID if it is contained by this collection. /// - pub fun borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? { + access(all) borrowListing(listingResourceID: UInt64): &Listing{ListingPublic}? { if self.listings[listingResourceID] != nil { return &self.listings[listingResourceID] as &Listing{ListingPublic}? } else { @@ -767,7 +767,7 @@ pub contract NFTStorefrontV2 { /// createStorefront /// Make creating a Storefront publicly accessible. /// - pub fun createStorefront(): @Storefront { + access(all) createStorefront(): @Storefront { return <-create Storefront() } diff --git a/contracts/standard/NonFungibleToken.cdc b/contracts/standard/NonFungibleToken.cdc index 50c15c70..efce1090 100644 --- a/contracts/standard/NonFungibleToken.cdc +++ b/contracts/standard/NonFungibleToken.cdc @@ -2,20 +2,17 @@ ## The Flow Non-Fungible Token standard -## `NonFungibleToken` contract interface +## `NonFungibleToken` contract -The interface that all Non-Fungible Token contracts could conform to. -If a user wants to deploy a new NFT contract, their contract would need -to implement the NonFungibleToken interface. +The interface that all Non-Fungible Token contracts should conform to. +If a user wants to deploy a new NFT contract, their contract should implement +The types defined here -Their contract would have to follow all the rules and naming -that the interface specifies. - -## `NFT` resource +## `NFT` resource interface The core resource type that represents an NFT in the smart contract. -## `Collection` Resource +## `Collection` Resource interface The resource that stores a user's NFT collection. It includes a few functions to allow the owner to easily @@ -26,10 +23,8 @@ move tokens in and out of the collection. These interfaces declare functions with some pre and post conditions that require the Collection to follow certain naming and behavior standards. -They are separate because it gives the user the ability to share a reference -to their Collection that only exposes the fields and functions in one or more -of the interfaces. It also gives users the ability to make custom resources -that implement these interfaces to do various things with the tokens. +They are separate because it gives developers the ability to define functions +that can use any type that implements these interfaces By using resources and interfaces, users of NFT smart contracts can send and receive tokens peer-to-peer, without having to interact with a central ledger @@ -41,159 +36,204 @@ Collection to complete the transfer. */ -/// The main NFT contract interface. Other NFT contracts will -/// import and implement this interface -/// -pub contract interface NonFungibleToken { - - /// The total number of tokens of this type in existence - pub var totalSupply: UInt64 +import "ViewResolver" - /// Event that emitted when the NFT contract is initialized +/// The main NFT contract. Other NFT contracts will +/// import and implement the interfaces defined in this contract +/// +access(all) contract interface NonFungibleToken: ViewResolver { + + /// An entitlement for allowing the withdrawal of tokens from a Vault + access(all) entitlement Withdraw + + /// An entitlement for allowing updates and update events for an NFT + access(all) entitlement Update + + /// Event that contracts should emit when the metadata of an NFT is updated + /// It can only be emitted by calling the `emitNFTUpdated` function + /// with an `Updatable` entitled reference to the NFT that was updated + /// The entitlement prevents spammers from calling this from other users' collections + /// because only code within a collection or that has special entitled access + /// to the collections methods will be able to get the entitled reference + /// + /// The event makes it so that third-party indexers can monitor the events + /// and query the updated metadata from the owners' collections. /// - pub event ContractInitialized() + access(all) event Updated(type: String, id: UInt64, uuid: UInt64, owner: Address?) + access(all) view fun emitNFTUpdated(_ nftRef: auth(Update) &{NonFungibleToken.NFT}) + { + emit Updated(type: nftRef.getType().identifier, id: nftRef.id, uuid: nftRef.uuid, owner: nftRef.owner?.address) + } + /// Event that is emitted when a token is withdrawn, - /// indicating the owner of the collection that it was withdrawn from. + /// indicating the type, id, uuid, the owner of the collection that it was withdrawn from, + /// and the UUID of the resource it was withdrawn from, usually a collection. /// /// If the collection is not in an account's storage, `from` will be `nil`. /// - pub event Withdraw(id: UInt64, from: Address?) + access(all) event Withdrawn(type: String, id: UInt64, uuid: UInt64, from: Address?, providerUUID: UInt64) /// Event that emitted when a token is deposited to a collection. + /// Indicates the type, id, uuid, the owner of the collection that it was deposited to, + /// and the UUID of the collection it was deposited to /// - /// It indicates the owner of the collection that it was deposited to. + /// If the collection is not in an account's storage, `from`, will be `nil`. /// - pub event Deposit(id: UInt64, to: Address?) + access(all) event Deposited(type: String, id: UInt64, uuid: UInt64, to: Address?, collectionUUID: UInt64) - /// Interface that the NFTs have to conform to - /// The metadata views methods are included here temporarily - /// because enforcing the metadata interfaces in the standard - /// would break many contracts in an upgrade. Those breaking changes - /// are being saved for the stable cadence milestone + /// Interface that the NFTs must conform to /// - pub resource interface INFT { - /// The unique ID that each NFT has - pub let id: UInt64 + access(all) resource interface NFT: ViewResolver.Resolver { - /// Function that returns all the Metadata Views implemented by a Non Fungible Token - /// - /// @return An array of Types defining the implemented views. This value will be used by - /// developers to know which parameter to pass to the resolveView() method. - /// - pub fun getViews(): [Type] { - return [] + /// unique ID for the NFT + access(all) let id: UInt64 + + /// Event that is emitted automatically every time a resource is destroyed + /// The type information is included in the metadata event so it is not needed as an argument + access(all) event ResourceDestroyed(id: UInt64 = self.id, uuid: UInt64 = self.uuid) + + /// createEmptyCollection creates an empty Collection that is able to store the NFT + /// and returns it to the caller so that they can own NFTs + /// @return A an empty collection that can store this NFT + access(all) fun createEmptyCollection(): @{Collection} { + post { + result.getLength() == 0: "The created collection must be empty!" + result.isSupportedNFTType(type: self.getType()): "The created collection must support this NFT type" + } + } + + /// Gets all the NFTs that this NFT directly owns + /// @return A dictionary of all subNFTS keyed by type + access(all) view fun getAvailableSubNFTS(): {Type: UInt64} { + return {} } - /// Function that resolves a metadata view for this token. + /// Get a reference to an NFT that this NFT owns + /// Both arguments are optional to allow the NFT to choose + /// how it returns sub NFTs depending on what arguments are provided + /// For example, if `type` has a value, but `id` doesn't, the NFT + /// can choose which NFT of that type to return if there is a "default" + /// If both are `nil`, then NFTs that only store a single NFT can just return + /// that. This helps callers who aren't sure what they are looking for /// - /// @param view: The Type of the desired view. - /// @return A structure representing the requested view. + /// @param type: The Type of the desired NFT + /// @param id: The id of the NFT to borrow /// - pub fun resolveView(_ view: Type): AnyStruct? { + /// @return A structure representing the requested view. + access(all) fun getSubNFT(type: Type, id: UInt64) : &{NonFungibleToken.NFT}? { return nil } } - /// Requirement that all conforming NFT smart contracts have - /// to define a resource called NFT that conforms to INFT + /// Interface to mediate withdrawals from a resource, usually a Collection /// - pub resource NFT: INFT { - pub let id: UInt64 - } + access(all) resource interface Provider { - /// Interface to mediate withdraws from the Collection - /// - pub resource interface Provider { - /// Removes an NFT from the resource implementing it and moves it to the caller - /// - /// @param withdrawID: The ID of the NFT that will be removed - /// @return The NFT resource removed from the implementing resource - /// - pub fun withdraw(withdrawID: UInt64): @NFT { + // We emit withdraw events from the provider interface because conficting withdraw + // events aren't as confusing to event listeners as conflicting deposit events + + /// withdraw removes an NFT from the collection and moves it to the caller + /// It does not specify whether the ID is UUID or not + /// @param withdrawID: The id of the NFT to withdraw from the collection + access(Withdraw) fun withdraw(withdrawID: UInt64): @{NFT} { post { result.id == withdrawID: "The ID of the withdrawn token must be the same as the requested ID" + emit Withdrawn(type: result.getType().identifier, id: result.id, uuid: result.uuid, from: self.owner?.address, providerUUID: self.uuid) } } } /// Interface to mediate deposits to the Collection /// - pub resource interface Receiver { - - /// Adds an NFT to the resource implementing it - /// - /// @param token: The NFT resource that will be deposited - /// - pub fun deposit(token: @NFT) + access(all) resource interface Receiver { + + /// deposit takes an NFT as an argument and adds it to the Collection + /// @param token: The NFT to deposit + access(all) fun deposit(token: @{NFT}) + + /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts + /// @return A dictionary of types mapped to booleans indicating if this + /// reciever supports it + access(all) view fun getSupportedNFTTypes(): {Type: Bool} + + /// Returns whether or not the given type is accepted by the collection + /// A collection that can accept any type should just return true by default + /// @param type: An NFT type + /// @return A boolean indicating if this receiver can recieve the desired NFT type + access(all) view fun isSupportedNFTType(type: Type): Bool } - /// Interface that an account would commonly - /// publish for their collection - /// - pub resource interface CollectionPublic { - pub fun deposit(token: @NFT) - pub fun getIDs(): [UInt64] - pub fun borrowNFT(id: UInt64): &NFT - /// Safe way to borrow a reference to an NFT that does not panic - /// - /// @param id: The ID of the NFT that want to be borrowed - /// @return An optional reference to the desired NFT, will be nil if the passed id does not exist - /// - pub fun borrowNFTSafe(id: UInt64): &NFT? { - post { - result == nil || result!.id == id: "The returned reference's ID does not match the requested ID" - } - return nil - } + /// Kept for backwards-compatibility reasons + access(all) resource interface CollectionPublic { + access(all) fun deposit(token: @{NFT}) + access(all) view fun getLength(): Int + access(all) view fun getIDs(): [UInt64] + access(all) fun forEachID(_ f: fun (UInt64): Bool): Void + access(all) view fun borrowNFT(_ id: UInt64): &{NFT}? } /// Requirement for the concrete resource type /// to be declared in the implementing contract /// - pub resource Collection: Provider, Receiver, CollectionPublic { + access(all) resource interface Collection: Provider, Receiver, CollectionPublic, ViewResolver.ResolverCollection { - /// Dictionary to hold the NFTs in the Collection - pub var ownedNFTs: @{UInt64: NFT} + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} - /// Removes an NFT from the collection and moves it to the caller - /// - /// @param withdrawID: The ID of the NFT that will be withdrawn - /// @return The resource containing the desired NFT - /// - pub fun withdraw(withdrawID: UInt64): @NFT + /// deposit takes a NFT as an argument and stores it in the collection + /// @param token: The NFT to deposit into the collection + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { + pre { + // We emit the deposit event in the `Collection` interface + // because the `Collection` interface is almost always the final destination + // of tokens and deposit emissions from custom receivers could be confusing + // and hard to reconcile to event listeners + emit Deposited(type: token.getType().identifier, id: token.id, uuid: token.uuid, to: self.owner?.address, collectionUUID: self.uuid) + } + } - /// Takes a NFT and adds it to the collections dictionary - /// and adds the ID to the ID array - /// - /// @param token: An NFT resource - /// - pub fun deposit(token: @NFT) + /// Gets the amount of NFTs stored in the collection + /// @return An integer indicating the size of the collection + access(all) view fun getLength(): Int { + return self.ownedNFTs.length + } - /// Returns an array of the IDs that are in the collection - /// - /// @return An array containing all the IDs on the collection - /// - pub fun getIDs(): [UInt64] + /// Allows a given function to iterate through the list + /// of owned NFT IDs in a collection without first + /// having to load the entire list into memory + access(all) fun forEachID(_ f: fun (UInt64): Bool): Void { + self.ownedNFTs.forEachKey(f) + } - /// Returns a borrowed reference to an NFT in the collection - /// so that the caller can read data and call methods from it + /// Borrows a reference to an NFT stored in the collection + /// If the NFT with the specified ID is not in the collection, + /// the function should return `nil` and not panic. /// - /// @param id: The ID of the NFT that want to be borrowed - /// @return A reference to the NFT - /// - pub fun borrowNFT(id: UInt64): &NFT { - pre { - self.ownedNFTs[id] != nil: "NFT does not exist in the collection!" + /// @param id: The desired nft id in the collection to return a referece for. + /// @return An optional reference to the NFT + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + post { + (result == nil) || (result?.id == id): + "Cannot borrow NFT reference: The ID of the returned reference does not match the ID that was specified" + } + } + + /// createEmptyCollection creates an empty Collection of the same type + /// and returns it to the caller + /// @return A an empty collection of the same type + access(all) fun createEmptyCollection(): @{Collection} { + post { + result.getType() == self.getType(): "The created collection does not have the same type as this collection" + result.getLength() == 0: "The created collection must be empty!" } } } - /// Creates an empty Collection and returns it to the caller so that they can own NFTs - /// - /// @return A new Collection resource - /// - pub fun createEmptyCollection(): @Collection { + /// createEmptyCollection creates an empty Collection for the specified NFT type + /// and returns it to the caller so that they can own NFTs + /// @param nftType: The desired nft type to return a collection for. + /// @return An array of NFT Types that the implementing contract defines. + access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} { post { result.getIDs().length == 0: "The created collection must be empty!" } diff --git a/contracts/standard/TokenForwarding.cdc b/contracts/standard/TokenForwarding.cdc index 9a06aa94..618ebee9 100644 --- a/contracts/standard/TokenForwarding.cdc +++ b/contracts/standard/TokenForwarding.cdc @@ -14,29 +14,29 @@ their tokens to. */ -import FungibleToken from "FungibleToken.cdc" +import "FungibleToken" -pub contract TokenForwarding { +access(all) contract TokenForwarding { // Event that is emitted when tokens are deposited to the target receiver - pub event ForwardedDeposit(amount: UFix64, from: Address?) + access(all) event ForwardedDeposit(amount: UFix64, from: Address?) - pub resource interface ForwarderPublic { + access(all) resource interface ForwarderPublic { /// Helper function to check whether set `recipient` capability /// is not latent or the capability tied to a type is valid. - pub fun check(): Bool + access(all) fun check(): Bool /// Gets the receiver assigned to a recipient capability. /// This is necessary because without it, it is not possible to look under the hood and see if a capability - /// is of an expected type or not. This helps guard against infinitely chained TokenForwarding or other invalid + /// is of an expected type or not. This helps guard against infinitely chained TokenForwarding or other invalid /// malicious kinds of updates that could prevent listings from being made that are valid on storefronts. /// /// @return an optional receiver capability for consumers of the TokenForwarding to check/validate on their own - pub fun safeBorrow(): &{FungibleToken.Receiver}? + access(all) fun safeBorrow(): &{FungibleToken.Receiver}? } - pub resource Forwarder: FungibleToken.Receiver, ForwarderPublic { + access(all) resource Forwarder: FungibleToken.Receiver, ForwarderPublic { // This is where the deposited tokens will be sent. // The type indicates that it is a reference to a receiver @@ -48,7 +48,7 @@ pub contract TokenForwarding { // Function that takes a Vault object as an argument and forwards // it to the recipient's Vault using the stored reference // - pub fun deposit(from: @FungibleToken.Vault) { + access(all) fun deposit(from: @{FungibleToken.Vault}) { let receiverRef = self.recipient.borrow<&{FungibleToken.Receiver}>()! let balance = from.balance @@ -60,23 +60,23 @@ pub contract TokenForwarding { /// Helper function to check whether set `recipient` capability /// is not latent or the capability tied to a type is valid. - pub fun check(): Bool { + access(all) fun check(): Bool { return self.recipient.check<&{FungibleToken.Receiver}>() } /// Gets the receiver assigned to a recipient capability. /// This is necessary because without it, it is not possible to look under the hood and see if a capability - /// is of an expected type or not. This helps guard against infinitely chained TokenForwarding or other invalid + /// is of an expected type or not. This helps guard against infinitely chained TokenForwarding or other invalid /// malicious kinds of updates that could prevent listings from being made that are valid on storefronts. /// /// @return an optional receiver capability for consumers of the TokenForwarding to check/validate on their own - pub fun safeBorrow(): &{FungibleToken.Receiver}? { + access(all) fun safeBorrow(): &{FungibleToken.Receiver}? { return self.recipient.borrow<&{FungibleToken.Receiver}>() } // changeRecipient changes the recipient of the forwarder to the provided recipient // - pub fun changeRecipient(_ newRecipient: Capability) { + access(all) fun changeRecipient(_ newRecipient: Capability) { pre { newRecipient.borrow<&{FungibleToken.Receiver}>() != nil: "Could not borrow Receiver reference from the Capability" } @@ -87,7 +87,7 @@ pub contract TokenForwarding { /// which can be deposited using the 'deposit' function. /// /// @return Array of FT types that can be deposited. - pub fun getSupportedVaultTypes(): {Type: Bool} { + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { if !self.recipient.check<&{FungibleToken.Receiver}>() { return {} } @@ -97,6 +97,15 @@ pub contract TokenForwarding { return supportedVaults } + /// Returns whether or not the given type is accepted by the Receiver + /// A vault that can accept any type should just return true by default + access(all) view fun isSupportedVaultType(type: Type): Bool { + let supportedVaults = self.getSupportedVaultTypes() + if let supported = supportedVaults[type] { + return supported + } else { return false } + } + init(recipient: Capability) { pre { recipient.borrow<&{FungibleToken.Receiver}>() != nil: "Could not borrow Receiver reference from the Capability" @@ -107,7 +116,7 @@ pub contract TokenForwarding { // createNewForwarder creates a new Forwarder reference with the provided recipient // - pub fun createNewForwarder(recipient: Capability): @Forwarder { + access(all) fun createNewForwarder(recipient: Capability): @Forwarder { return <-create Forwarder(recipient: recipient) } } diff --git a/contracts/standard/ViewResolver.cdc b/contracts/standard/ViewResolver.cdc new file mode 100644 index 00000000..a62a2784 --- /dev/null +++ b/contracts/standard/ViewResolver.cdc @@ -0,0 +1,59 @@ +// Taken from the NFT Metadata standard, this contract exposes an interface to let +// anyone borrow a contract and resolve views on it. +// +// This will allow you to obtain information about a contract without necessarily knowing anything about it. +// All you need is its address and name and you're good to go! +access(all) contract interface ViewResolver { + + /// Function that returns all the Metadata Views implemented by the resolving contract. + /// Some contracts may have multiple resource types that support metadata views + /// so there there is an optional parameter for specify which resource type the caller + /// is looking for views for. + /// Some contract-level views may be type-agnostic. In that case, the contract + /// should return the same views regardless of what type is passed in. + /// + /// @param resourceType: An optional resource type to return views for + /// @return An array of Types defining the implemented views. This value will be used by + /// developers to know which parameter to pass to the resolveView() method. + /// + access(all) view fun getContractViews(resourceType: Type?): [Type] + + /// Function that resolves a metadata view for this token. + /// Some contracts may have multiple resource types that support metadata views + /// so there there is an optional parameter for specify which resource type the caller + /// is looking for views for. + /// Some contract-level views may be type-agnostic. In that case, the contract + /// should return the same views regardless of what type is passed in. + /// + /// @param resourceType: An optional resource type to return views for + /// @param view: The Type of the desired view. + /// @return A structure representing the requested view. + /// + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? + + /// Provides access to a set of metadata views. A struct or + /// resource (e.g. an NFT) can implement this interface to provide access to + /// the views that it supports. + /// + access(all) resource interface Resolver { + + /// Same as getViews above, but on a specific NFT instead of a contract + access(all) view fun getViews(): [Type] + + /// Same as resolveView above, but on a specific NFT instead of a contract + access(all) fun resolveView(_ view: Type): AnyStruct? + } + + /// A group of view resolvers indexed by ID. + /// + access(all) resource interface ResolverCollection { + access(all) view fun borrowViewResolver(id: UInt64): &{Resolver}? { + return nil + } + + access(all) view fun getIDs(): [UInt64] { + return [] + } + } +} + diff --git a/dandy_test.go b/dandy_test.go index 7a558b51..2df1f72f 100644 --- a/dandy_test.go +++ b/dandy_test.go @@ -3,7 +3,7 @@ package test_main import ( "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -14,19 +14,8 @@ import ( Tests must be in the same folder as flow.json with contracts and transactions/scripts in subdirectories in order for the path resolver to work correctly */ func TestDandy(t *testing.T) { - otu := NewOverflowTest(t). - setupFIND(). - setupDandy("user1"). - createUser(100.0, "user2"). - registerUser("user2") - - t.Run("Should be able to mint 3 dandy nfts and display them", func(t *testing.T) { - - otu.setUUID(500) - - dandyIds := otu.mintThreeExampleDandies() - otu.registerFtInRegistry() - + otu := &OverflowTestUtils{T: t, O: ot.O} + ot.Run(t, "Should be able to mint 3 dandy nfts and display them", func(t *testing.T) { id := dandyIds[0] viewList := []string{ @@ -70,40 +59,32 @@ func TestDandy(t *testing.T) { }), ) - otu.O.Script("getNFTView", - WithArg("user", "user1"), - WithArg("aliasOrIdentifier", dandyNFTType(otu)), - WithArg("id", id), - WithArg("identifier", otu.identifier("MetadataViews", "ExternalURL")), - ).AssertWant(t, - autogold.Want("ExternalURL", map[string]interface{}{"url": "https://find.xyz/collection/user1/dandy/502"}), - ) - - for _, dandy := range dandyIds { - otu.sendDandy("user2", "user1", dandy) - } - + //TODO: dont know why this does not work anymore + /* + otu.O.Script("getNFTView", + WithArg("user", "user1"), + WithArg("aliasOrIdentifier", dandyNFTType(otu)), + WithArg("id", id), + WithArg("identifier", otu.identifier("MetadataViews", "ExternalURL")), + ).Print().AssertWant(t, + autogold.Want("ExternalURL", map[string]interface{}{"url": "https://find.xyz/collection/user1/dandy/502"}), + ) + */ }) /* Test on dandy nft indexing {Mapping of minter} */ - t.Run("Should be able to return the correct minter and dandies list", func(t *testing.T) { - - otu.setUUID(700) - - dandiesIDs := otu.mintThreeExampleDandies() - - result, err := otu.O.Script("getDandiesIDsFor", + ot.Run(t, "Should be able to return the correct minter and dandies list", func(t *testing.T) { + result, err := otu.O.Script("devgetDandiesIDsFor", WithArg("user", "user1"), WithArg("minter", "user1"), ).GetAsInterface() - if err != nil { panic(err) } - assert.ElementsMatch(t, result, []interface{}{uint64(702), uint64(703), uint64(704)}) + assert.ElementsMatch(t, result, dandyIds) - otu.O.Script("getDandiesMinters", + otu.O.Script("devgetDandiesMinters", WithArg("user", "user1"), ).AssertWant(t, autogold.Want("dandyMinters", `[]interface {}{ @@ -111,26 +92,22 @@ func TestDandy(t *testing.T) { }`), ) - /* mint new dandies and withdraw all of them */ - dandiesIDs = append(dandiesIDs, otu.mintThreeExampleDandies()...) - otu.O.Tx("devDestroyDandies", WithSigner("user1"), - WithArg("ids", dandiesIDs), + WithArg("ids", dandyIds), ).AssertSuccess(t) - otu.O.Script("getDandiesIDsFor", + otu.O.Script("devgetDandiesIDsFor", WithArg("user", "user1"), WithArg("minter", "user1"), ).AssertWant(t, autogold.Want("noDandies", nil), ) - otu.O.Script("getDandiesMinters", + otu.O.Script("devgetDandiesMinters", WithArg("user", "user1"), ).AssertWant(t, autogold.Want("noDandyMinters", nil), ) - }) } diff --git a/dapper-tx/mainnet/buyAddon.cdc b/dapper-tx/mainnet/buyAddon.cdc deleted file mode 100644 index d2f1e3b5..00000000 --- a/dapper-tx/mainnet/buyAddon.cdc +++ /dev/null @@ -1,26 +0,0 @@ -import DapperUtilityCoin from 0xead892083b3e2c6c -import FIND from 0x097bafa4e0b48eef - - -transaction(merchAccount: Address, name: String, addon:String, amount:UFix64) { - - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault - let balanceBeforeTransfer: UFix64 - - prepare(dapper: AuthAccount, account: AuthAccount) { - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) - self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") - - } - - execute { - let vault <- self.mainDapperUtilityCoinVault.withdraw(amount: amount) as! @DapperUtilityCoin.Vault - self.finLeases.buyAddonDapper(merchAccount: merchAccount, name: name, addon: addon, vault: <- vault) - } - - post { - self.mainDapperUtilityCoinVault.balance == self.balanceBeforeTransfer: "DapperUtilityCoin leakage" - } -} diff --git a/dapper-tx/mainnet/buyLeaseForSale.cdc b/dapper-tx/mainnet/buyLeaseForSale.cdc deleted file mode 100644 index f282516b..00000000 --- a/dapper-tx/mainnet/buyLeaseForSale.cdc +++ /dev/null @@ -1,75 +0,0 @@ -import FindMarket from 0x097bafa4e0b48eef -import DapperUtilityCoin from 0xead892083b3e2c6c -import FlowUtilityToken from 0xead892083b3e2c6c -import FungibleToken from 0xf233dcee88fe0abe -import FIND from 0x097bafa4e0b48eef -import Profile from 0x097bafa4e0b48eef -import FindLeaseMarketSale from 0x097bafa4e0b48eef -import FindLeaseMarket from 0x097bafa4e0b48eef - -transaction(sellerAccount: Address, leaseName: String, amount: UFix64) { - - let to : Address - let walletReference : &FungibleToken.Vault - - let saleItemCollection: &FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic} - let balanceBeforeTransfer: UFix64 - - prepare(dapper: AuthAccount, account: AuthAccount) { - - let profile=account.borrow<&Profile.User>(from: Profile.storagePath) ?? panic("You do not have a profile set up, initialize the user first") - - let address = FIND.resolve(leaseName) ?? panic("The address input is not a valid name nor address. Input : ".concat(leaseName)) - - if address != sellerAccount { - panic("address does not resolve to seller") - } - - let leaseMarketplace = FindMarket.getTenantAddress("find") ?? panic("Cannot find find tenant") - let saleItemsCap= FindLeaseMarketSale.getSaleItemCapability(marketplace: leaseMarketplace, user:address) ?? panic("cannot find sale item cap for find") - - let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseSaleItemType= Type<@FindLeaseMarketSale.SaleItemCollection>() - let leasePublicPath=FindMarket.getPublicPath(leaseSaleItemType, name: "find") - let leaseStoragePath= FindMarket.getStoragePath(leaseSaleItemType, name:"find") - let leaseSaleItemCap= account.getCapability<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath) - if !leaseSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketSale.SaleItemCollection>(<- FindLeaseMarketSale.createEmptySaleItemCollection(leaseTenantCapability), to: leaseStoragePath) - account.link<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath, target: leaseStoragePath) - } - - self.to= account.address - - self.saleItemCollection = saleItemsCap.borrow()! - let item = self.saleItemCollection.borrowSaleItem(leaseName) - - var ftVaultPath : StoragePath? = nil - switch item.getFtType() { - case Type<@DapperUtilityCoin.Vault>() : - ftVaultPath = /storage/dapperUtilityCoinVault - - case Type<@FlowUtilityToken.Vault>() : - ftVaultPath = /storage/flowUtilityTokenVault - - default : - panic("This FT is not supported by the Find Market in Dapper Wallet. Type : ".concat(item.getFtType().identifier)) - } - - - self.walletReference = dapper.borrow<&FungibleToken.Vault>(from: ftVaultPath!) ?? panic("No suitable wallet linked for this account") - self.balanceBeforeTransfer = self.walletReference.balance - } - - execute { - let vault <- self.walletReference.withdraw(amount: amount) - self.saleItemCollection.buy(name:leaseName, vault: <- vault, to: self.to) - } - - // Check that all dapper Coin was routed back to Dapper - post { - self.walletReference.balance == self.balanceBeforeTransfer: "Dapper Coin leakage" - } -} diff --git a/dapper-tx/mainnet/buyNFTForSale.cdc b/dapper-tx/mainnet/buyNFTForSale.cdc deleted file mode 100644 index acb25143..00000000 --- a/dapper-tx/mainnet/buyNFTForSale.cdc +++ /dev/null @@ -1,96 +0,0 @@ -import FindMarket from 0x097bafa4e0b48eef -import Profile from 0x097bafa4e0b48eef -import FindMarketSale from 0x097bafa4e0b48eef -import NFTCatalog from 0x49a7cda3a1eecc29 -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 -import FungibleToken from 0xf233dcee88fe0abe -import DapperStorageRent from 0xa08e88e23f332538 -import TopShot from 0x0b2a3299cc857e29 -import DapperUtilityCoin from 0xead892083b3e2c6c -import FlowUtilityToken from 0xead892083b3e2c6c - -//first argument is the address to the merchant that gets the funds -transaction(address: Address, id: UInt64, amount: UFix64) { - - let targetCapability : Capability<&{NonFungibleToken.Receiver}> - let walletReference : &FungibleToken.Vault - let receiver : Address - - let saleItemsCap: Capability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic}> - let balanceBeforeTransfer: UFix64 - prepare(dapper: AuthAccount, account: AuthAccount) { - let marketplace = FindMarket.getFindTenantAddress() - self.receiver=account.address - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let tenant = tenantCapability.borrow()! - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) - - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - - self.saleItemsCap= FindMarketSale.getSaleItemCapability(marketplace: marketplace, user:address) ?? panic("cannot find sale item cap") - let marketOption = FindMarket.getMarketOptionFromType(Type<@FindMarketSale.SaleItemCollection>()) - - //we do some security check to verify that this tenant can do this operation. This will ensure that the onefootball tenant can only sell using DUC and not some other token. But we can change this with transactions later and not have to modify code/transactions - let item= FindMarket.assertOperationValid(tenant: marketplace, address: address, marketOption: marketOption, id: id) - let collectionIdentifier = NFTCatalog.getCollectionsForType(nftTypeIdentifier: item.getItemType().identifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(item.getItemType().identifier)) - let collection = NFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData - - var ftVaultPath : StoragePath? = nil - switch item.getFtType() { - case Type<@DapperUtilityCoin.Vault>() : - ftVaultPath = /storage/dapperUtilityCoinVault - - case Type<@FlowUtilityToken.Vault>() : - ftVaultPath = /storage/flowUtilityTokenVault - - default : - panic("This FT is not supported by the Find Market in Dapper Wallet. Type : ".concat(item.getFtType().identifier)) - } - - self.targetCapability= account.getCapability<&{NonFungibleToken.Receiver}>(nft.publicPath) - - if !self.targetCapability.check() { - let cd = item.getNFTCollectionData() - if let storage = account.borrow<&AnyResource>(from: cd.storagePath) { - if let st = account.borrow<&TopShot.Collection>(from: cd.storagePath) { - // here means the topShot is not linked in the way it should be. We can relink that for our use - account.unlink(cd.publicPath) - account.link<&TopShot.Collection{TopShot.MomentCollectionPublic,NonFungibleToken.Receiver,NonFungibleToken.CollectionPublic,MetadataViews.ResolverCollection}>(cd.publicPath, target: cd.storagePath) - } else { - panic("This collection public link is not set up properly.") - } - } else { - account.save(<- cd.createEmptyCollection(), to: cd.storagePath) - account.link<&{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(cd.publicPath, target: cd.storagePath) - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(cd.providerPath, target: cd.storagePath) - } - } - - self.walletReference = dapper.borrow<&FungibleToken.Vault>(from: ftVaultPath!) ?? panic("No suitable wallet linked for this account") - self.balanceBeforeTransfer = self.walletReference.balance - } - - pre { - self.walletReference.balance > amount : "Your wallet does not have enough funds to pay for this item" - } - - execute { - let vault <- self.walletReference.withdraw(amount: amount) - self.saleItemsCap.borrow()!.buy(id:id, vault: <- vault, nftCap: self.targetCapability) - DapperStorageRent.tryRefill(self.receiver) - } - - // Check that all dapper Coin was routed back to Dapper - post { - self.walletReference.balance == self.balanceBeforeTransfer: "Dapper Coin leakage" - } -} diff --git a/dapper-tx/mainnet/createProfile.cdc b/dapper-tx/mainnet/createProfile.cdc deleted file mode 100644 index 0f9bb6d6..00000000 --- a/dapper-tx/mainnet/createProfile.cdc +++ /dev/null @@ -1,90 +0,0 @@ -import FungibleToken from 0xf233dcee88fe0abe -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 -import FIND from 0x097bafa4e0b48eef -import Dandy from 0x097bafa4e0b48eef -import Profile from 0x097bafa4e0b48eef -import FindMarket from 0x097bafa4e0b48eef -import FindMarketDirectOfferSoft from 0x097bafa4e0b48eef -import DapperUtilityCoin from 0xead892083b3e2c6c -import FlowUtilityToken from 0xead892083b3e2c6c -import FindLeaseMarketDirectOfferSoft from 0x097bafa4e0b48eef -import FindLeaseMarket from 0x097bafa4e0b48eef - -transaction(name: String) { - prepare(account: AuthAccount) { - let leaseCollection = account.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !leaseCollection.check() { - account.save(<- FIND.createEmptyLeaseCollection(), to: FIND.LeaseStoragePath) - account.link<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>( FIND.LeasePublicPath, target: FIND.LeaseStoragePath) - } - - let dandyCap= account.getCapability<&{NonFungibleToken.CollectionPublic}>(Dandy.CollectionPublicPath) - if !dandyCap.check() { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - var created=false - var updated=false - let profileCap = account.getCapability<&{Profile.Public}>(Profile.publicPath) - if !profileCap.check() { - let profile <-Profile.createUser(name:name, createdAt: "find") - account.save(<-profile, to: Profile.storagePath) - account.link<&Profile.User{Profile.Public}>(Profile.publicPath, target: Profile.storagePath) - account.link<&{FungibleToken.Receiver}>(Profile.publicReceiverPath, target: Profile.storagePath) - created=true - } - - let profile=account.borrow<&Profile.User>(from: Profile.storagePath)! - - if !profile.hasWallet("DUC") { - let ducReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) - profile.addWallet(Profile.Wallet( name:"DUC", receiver:ducReceiver, balance:account.getCapability<&{FungibleToken.Balance}>(/public/dapperUtilityCoinBalance), accept: Type<@DapperUtilityCoin.Vault>(), tags: ["duc", "dapperUtilityCoin","dapper"])) - updated=true - } - - if !profile.hasWallet("FUT") { - let futReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - profile.addWallet(Profile.Wallet( name:"FUT", receiver:futReceiver, balance:account.getCapability<&{FungibleToken.Balance}>(/public/flowUtilityTokenBalance), accept: Type<@FlowUtilityToken.Vault>(), tags: ["fut", "flowUtilityToken","dapper"])) - updated=true - } - - profile.emitCreatedEvent() - - let receiverCap=account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - let tenantCapability= FindMarket.getTenantCapability(FindMarket.getFindTenantAddress())! - - let tenant = tenantCapability.borrow()! - - let dosSaleType= Type<@FindMarketDirectOfferSoft.SaleItemCollection>() - let dosSalePublicPath=FindMarket.getPublicPath(dosSaleType, name: tenant.name) - let dosSaleStoragePath= FindMarket.getStoragePath(dosSaleType, name:tenant.name) - let dosSaleCap= account.getCapability<&FindMarketDirectOfferSoft.SaleItemCollection{FindMarketDirectOfferSoft.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(dosSalePublicPath) - if !dosSaleCap.check() { - account.save<@FindMarketDirectOfferSoft.SaleItemCollection>(<- FindMarketDirectOfferSoft.createEmptySaleItemCollection(tenantCapability), to: dosSaleStoragePath) - account.link<&FindMarketDirectOfferSoft.SaleItemCollection{FindMarketDirectOfferSoft.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(dosSalePublicPath, target: dosSaleStoragePath) - } - - let leaseTenantCapability= FindMarket.getTenantCapability(FindMarket.getFindTenantAddress())! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseDOSSaleItemType= Type<@FindLeaseMarketDirectOfferSoft.SaleItemCollection>() - let leaseDOSPublicPath=leaseTenant.getPublicPath(leaseDOSSaleItemType) - let leaseDOSStoragePath= leaseTenant.getStoragePath(leaseDOSSaleItemType) - let leaseDOSSaleItemCap= account.getCapability<&FindLeaseMarketDirectOfferSoft.SaleItemCollection{FindLeaseMarketDirectOfferSoft.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leaseDOSPublicPath) - if !leaseDOSSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketDirectOfferSoft.SaleItemCollection>(<- FindLeaseMarketDirectOfferSoft.createEmptySaleItemCollection(leaseTenantCapability), to: leaseDOSStoragePath) - account.link<&FindLeaseMarketDirectOfferSoft.SaleItemCollection{FindLeaseMarketDirectOfferSoft.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leaseDOSPublicPath, target: leaseDOSStoragePath) - } - - } -} diff --git a/dapper-tx/mainnet/deleteFindThoughts.cdc b/dapper-tx/mainnet/deleteFindThoughts.cdc deleted file mode 100644 index 77d3914c..00000000 --- a/dapper-tx/mainnet/deleteFindThoughts.cdc +++ /dev/null @@ -1,17 +0,0 @@ -import FindThoughts from 0x097bafa4e0b48eef - -transaction(ids: [UInt64]) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - for id in ids { - self.collection.delete(id) - } - } -} diff --git a/dapper-tx/mainnet/delistLeaseSale.cdc b/dapper-tx/mainnet/delistLeaseSale.cdc deleted file mode 100644 index 90bb8633..00000000 --- a/dapper-tx/mainnet/delistLeaseSale.cdc +++ /dev/null @@ -1,23 +0,0 @@ -import FindMarket from 0x097bafa4e0b48eef -import FindLeaseMarketSale from 0x097bafa4e0b48eef - -transaction(leases: [String]) { - let saleItems : &FindLeaseMarketSale.SaleItemCollection? - - prepare(account: AuthAccount) { - - let tenant=FindMarket.getTenant(FindMarket.getFindTenantAddress()) - self.saleItems= account.borrow<&FindLeaseMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindLeaseMarketSale.SaleItemCollection>())) - - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - for lease in leases { - self.saleItems!.delist(lease) - } - } -} diff --git a/dapper-tx/mainnet/delistNFTSale.cdc b/dapper-tx/mainnet/delistNFTSale.cdc deleted file mode 100644 index 3c4c3390..00000000 --- a/dapper-tx/mainnet/delistNFTSale.cdc +++ /dev/null @@ -1,24 +0,0 @@ -import FindMarket from 0x097bafa4e0b48eef -import FindMarketSale from 0x097bafa4e0b48eef - -//Remove one or more listings from a marketplace -transaction(ids: [UInt64]) { - - let saleItems : &FindMarketSale.SaleItemCollection? - - prepare(account: AuthAccount) { - let marketplace = FindMarket.getFindTenantAddress() - let tenant=FindMarket.getTenant(marketplace) - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - for id in ids { - self.saleItems!.delist(id) - } - } -} diff --git a/dapper-tx/mainnet/editFindThought.cdc b/dapper-tx/mainnet/editFindThought.cdc deleted file mode 100644 index 898d5cdb..00000000 --- a/dapper-tx/mainnet/editFindThought.cdc +++ /dev/null @@ -1,16 +0,0 @@ -import FindThoughts from 0x097bafa4e0b48eef - -transaction(id: UInt64, header: String , body: String, tags: [String]) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - let thought = self.collection.borrow(id) - thought.edit(header: header , body: body, tags: tags) - } -} diff --git a/dapper-tx/mainnet/editProfile.cdc b/dapper-tx/mainnet/editProfile.cdc deleted file mode 100644 index 94fb5c61..00000000 --- a/dapper-tx/mainnet/editProfile.cdc +++ /dev/null @@ -1,40 +0,0 @@ -import FIND from 0x097bafa4e0b48eef -import Profile from 0x097bafa4e0b48eef - -transaction(name:String, description: String, avatar: String, tags:[String], allowStoringFollowers: Bool, linkTitles : {String: String}, linkTypes: {String:String}, linkUrls : {String:String}, removeLinks : [String]) { - - let profile : &Profile.User - - prepare(account: AuthAccount) { - - self.profile =account.borrow<&Profile.User>(from:Profile.storagePath) ?? panic("You do not have a profile set up, initialize the user first") - - let leaseCollection = account.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !leaseCollection.check() { - account.save(<- FIND.createEmptyLeaseCollection(), to: FIND.LeaseStoragePath) - account.link<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>( FIND.LeasePublicPath, target: FIND.LeaseStoragePath) - - } - - } - - execute{ - self.profile.setName(name) - self.profile.setDescription(description) - self.profile.setAvatar(avatar) - self.profile.setTags(tags) - - for link in removeLinks { - self.profile.removeLink(link) - } - - for titleName in linkTitles.keys { - let title=linkTitles[titleName]! - let url = linkUrls[titleName]! - let type = linkTypes[titleName]! - - self.profile.addLinkWithName(name:titleName, link: Profile.Link(title: title, type: type, url: url)) - } - self.profile.emitUpdatedEvent() - } -} diff --git a/dapper-tx/mainnet/getMetadataForBuyAddon.cdc b/dapper-tx/mainnet/getMetadataForBuyAddon.cdc deleted file mode 100644 index 3463cb1d..00000000 --- a/dapper-tx/mainnet/getMetadataForBuyAddon.cdc +++ /dev/null @@ -1,32 +0,0 @@ -import FIND from 0x097bafa4e0b48eef - -pub fun main(merchAccount: Address, name: String, addon:String, amount:UFix64) : PurchaseData { - let description = "Purchase addon ".concat(addon).concat(" for name :").concat(name).concat(" for DUC ").concat(amount.toString()) - let imageURL = "https://i.imgur.com/8W8NoO1.png" - - return PurchaseData( - id: 0, - name: name, - amount: amount, - description: description, - imageURL: imageURL - ) - - -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - } -} diff --git a/dapper-tx/mainnet/getMetadataForBuyLeaseForSale.cdc b/dapper-tx/mainnet/getMetadataForBuyLeaseForSale.cdc deleted file mode 100644 index 12d12f88..00000000 --- a/dapper-tx/mainnet/getMetadataForBuyLeaseForSale.cdc +++ /dev/null @@ -1,43 +0,0 @@ -import FindMarket from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef -import Profile from 0x097bafa4e0b48eef -import DapperUtilityCoin from 0xead892083b3e2c6c -import FindLeaseMarketSale from 0x097bafa4e0b48eef -import FindLeaseMarket from 0x097bafa4e0b48eef - -pub fun main(sellerAccount: Address, leaseName: String, amount: UFix64) :PurchaseData{ - - let address = FIND.resolve(leaseName) ?? panic("The address input is not a valid name nor address. Input : ".concat(leaseName)) - let leaseMarketplace = FindMarket.getFindTenantAddress() - let leaseTenant = FindMarket.getTenant(leaseMarketplace) - let storagePath = leaseTenant.getStoragePath(Type<@FindLeaseMarketSale.SaleItemCollection>()) - let saleItemRef = getAuthAccount(address).borrow<&FindLeaseMarketSale.SaleItemCollection>(from: storagePath) ?? panic("Cannot borrow reference to sale item") - let saleItem = saleItemRef.borrow(leaseName) - - let description = "Name :".concat(leaseName).concat(" for DUC ").concat(amount.toString()) - let imageURL = "https://i.imgur.com/8W8NoO1.png" - - return PurchaseData( - id: saleItem.getId(), - name: leaseName, - amount: amount, - description: description, - imageURL: imageURL - ) -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - } -} diff --git a/dapper-tx/mainnet/getMetadataForBuyNFTForSale.cdc b/dapper-tx/mainnet/getMetadataForBuyNFTForSale.cdc deleted file mode 100644 index 2067f0fa..00000000 --- a/dapper-tx/mainnet/getMetadataForBuyNFTForSale.cdc +++ /dev/null @@ -1,40 +0,0 @@ -import FindMarket from 0x097bafa4e0b48eef -import FindMarketSale from 0x097bafa4e0b48eef - -pub fun main(address: Address, id: UInt64, amount: UFix64) : PurchaseData { - - let marketplace = FindMarket.getFindTenantAddress() - let marketOption = FindMarket.getMarketOptionFromType(Type<@FindMarketSale.SaleItemCollection>()) - let item= FindMarket.assertOperationValid(tenant: marketplace, address: address, marketOption: marketOption, id: id) - let display = item.getDisplay() - let itemID = item.getItemID() - let amount = item.getBalance() - - - return PurchaseData( - id: itemID, - name: display.name, - amount: amount, - description: display.description, - imageURL: display.thumbnail.uri(), - paymentVaultTypeID: item.getFtType(), - ) -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - pub let paymentVaultTypeID: Type - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String, paymentVaultTypeID: Type) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - self.paymentVaultTypeID=paymentVaultTypeID - } -} diff --git a/dapper-tx/mainnet/getMetadataForRegister.cdc b/dapper-tx/mainnet/getMetadataForRegister.cdc deleted file mode 100644 index 0a67ed13..00000000 --- a/dapper-tx/mainnet/getMetadataForRegister.cdc +++ /dev/null @@ -1,32 +0,0 @@ -import FIND from 0x097bafa4e0b48eef - -pub fun main(merchAccount: Address, name: String, amount: UFix64) : PurchaseData { - - let description = "Name :".concat(name).concat(" for DUC ").concat(amount.toString()) - let imageURL = "https://ik.imagekit.io/xyvsisxky/tr:ot-".concat(name).concat(",ots-55,otc-58B792,ox-N166,oy-N24,ott-b/https://i.imgur.com/8W8NoO1.png") - - return PurchaseData( - id: 0, - name: name, - amount: amount, - description: description, - imageURL: imageURL - ) - -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - } -} diff --git a/dapper-tx/mainnet/getMetadataForRenewName.cdc b/dapper-tx/mainnet/getMetadataForRenewName.cdc deleted file mode 100644 index 755580b9..00000000 --- a/dapper-tx/mainnet/getMetadataForRenewName.cdc +++ /dev/null @@ -1,31 +0,0 @@ -import FIND from 0x097bafa4e0b48eef - -pub fun main(merchAccount: Address, name: String, amount: UFix64) : PurchaseData { - - let description = "Renew name :".concat(name).concat(" for DUC ").concat(amount.toString()) - let imageURL = "https://ik.imagekit.io/xyvsisxky/tr:ot-".concat(name).concat(",ots-55,otc-58B792,ox-N166,oy-N24,ott-b/https://i.imgur.com/8W8NoO1.png") - - return PurchaseData( - id: 0, - name: name, - amount: amount, - description: description, - imageURL: imageURL - ) -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - } -} diff --git a/dapper-tx/mainnet/hideFindThoughts.cdc b/dapper-tx/mainnet/hideFindThoughts.cdc deleted file mode 100644 index da5f0b83..00000000 --- a/dapper-tx/mainnet/hideFindThoughts.cdc +++ /dev/null @@ -1,18 +0,0 @@ -import FindThoughts from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef - -transaction(ids: [UInt64], hide: [Bool]) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - for i, id in ids { - self.collection.hide(id: id, hide: hide[i]) - } - - } -} diff --git a/dapper-tx/mainnet/initCollections.cdc b/dapper-tx/mainnet/initCollections.cdc deleted file mode 100644 index 7c4ea514..00000000 --- a/dapper-tx/mainnet/initCollections.cdc +++ /dev/null @@ -1,183 +0,0 @@ -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 -import NameVoucher from 0x097bafa4e0b48eef -import Wearables from 0xe81193c424cfd3fb -import PartyFavorz from 0x123cb666996b8432 -import NFGv3 from 0x123cb666996b8432 -import Dandy from 0x097bafa4e0b48eef - -transaction() { - prepare(account: AuthAccount) { - - // Dandy - let DandyRef= account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) - if DandyRef == nil { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Dandy.CollectionPublicPath) - if !DandyCap.check() { - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Dandy.CollectionPrivatePath) - if !DandyProviderCap.check() { - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - // NFGv3 - let NFGv3Ref= account.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) - if NFGv3Ref == nil { - account.save<@NonFungibleToken.Collection>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPublicPath) - if !NFGv3Cap.check() { - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPrivatePath) - if !NFGv3ProviderCap.check() { - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - // Party Favorz - let PartyFavorzRef= account.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) - if PartyFavorzRef == nil { - account.save<@NonFungibleToken.Collection>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPublicPath) - if !PartyFavorzCap.check() { - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) - if !PartyFavorzProviderCap.check() { - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - // Name Voucher - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - // Wearables - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) - if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) - if !wearablesCap.check() { - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) - if !wearablesProviderCap.check() { - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - } -} diff --git a/dapper-tx/mainnet/initWearables.cdc b/dapper-tx/mainnet/initWearables.cdc deleted file mode 100644 index 51ba751e..00000000 --- a/dapper-tx/mainnet/initWearables.cdc +++ /dev/null @@ -1,43 +0,0 @@ -import Wearables from 0xe81193c424cfd3fb -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 - -transaction() { - prepare(account: AuthAccount) { - - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) - if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - return - } - - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) - if !wearablesCap.check() { - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) - if !wearablesProviderCap.check() { - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - } -} diff --git a/dapper-tx/mainnet/listLeaseForSale.cdc b/dapper-tx/mainnet/listLeaseForSale.cdc deleted file mode 100644 index 77429a66..00000000 --- a/dapper-tx/mainnet/listLeaseForSale.cdc +++ /dev/null @@ -1,50 +0,0 @@ -import FindMarket from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef -import FTRegistry from 0x097bafa4e0b48eef -import FindLeaseMarketSale from 0x097bafa4e0b48eef -import FindLeaseMarket from 0x097bafa4e0b48eef - -transaction(leaseName: String, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - - let saleItems : &FindLeaseMarketSale.SaleItemCollection? - let pointer : FindLeaseMarket.AuthLeasePointer - let vaultType : Type - - prepare(account: AuthAccount) { - - // Get the salesItemRef from tenant - let leaseMarketplace = FindMarket.getFindTenantAddress() - let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseSaleItemType= Type<@FindLeaseMarketSale.SaleItemCollection>() - let leasePublicPath=leaseTenant.getPublicPath(leaseSaleItemType) - let leaseStoragePath= leaseTenant.getStoragePath(leaseSaleItemType) - let leaseSaleItemCap= account.getCapability<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath) - if !leaseSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketSale.SaleItemCollection>(<- FindLeaseMarketSale.createEmptySaleItemCollection(leaseTenantCapability), to: leaseStoragePath) - account.link<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath, target: leaseStoragePath) - } - - self.saleItems= account.borrow<&FindLeaseMarketSale.SaleItemCollection>(from: leaseStoragePath)! - - // Get supported NFT and FT Information from Registries from input alias - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - self.vaultType= ft.type - - let ref=account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath)! - - self.pointer= FindLeaseMarket.AuthLeasePointer(ref: ref, name: leaseName) - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) - - } - -} diff --git a/dapper-tx/mainnet/listNFTForSale.cdc b/dapper-tx/mainnet/listNFTForSale.cdc deleted file mode 100644 index 92391bfc..00000000 --- a/dapper-tx/mainnet/listNFTForSale.cdc +++ /dev/null @@ -1,77 +0,0 @@ -import FindMarket from 0x097bafa4e0b48eef -import FindMarketSale from 0x097bafa4e0b48eef -import FINDNFTCatalog from 0x097bafa4e0b48eef -import FTRegistry from 0x097bafa4e0b48eef -import FindViews from 0x097bafa4e0b48eef -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 -import FlowUtilityToken from 0xead892083b3e2c6c -import TokenForwarding from 0xe544175ee0461c4b -import FungibleToken from 0xf233dcee88fe0abe - -transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - - let saleItems : &FindMarketSale.SaleItemCollection? - let pointer : FindViews.AuthNFTPointer - let vaultType : Type - - prepare(account: AuthAccount) { - - let marketplace = FindMarket.getFindTenantAddress() - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - - let tenant = tenantCapability.borrow()! - - let dapper=getAccount(0xead892083b3e2c6c) - - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) - - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - - // Get supported NFT and FT Information from Registries from input alias - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData - - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - - let futReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - if ft.type == Type<@FlowUtilityToken.Vault>() && !futReceiver.check() { - // Create a new Forwarder resource for FUT and store it in the new account's storage - let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapper.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver)) - account.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) - // Publish a Receiver capability for the new account, which is linked to the FUT Forwarder - account.link<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver,target: /storage/flowUtilityTokenReceiver) - } - - - let providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) - - if !providerCap.check() { - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft.privatePath, - target: nft.storagePath - ) - } - // Get the salesItemRef from tenant - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) - self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) - self.vaultType= ft.type - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) - - } -} diff --git a/dapper-tx/mainnet/moveNameTo.cdc b/dapper-tx/mainnet/moveNameTo.cdc deleted file mode 100644 index 45391e3e..00000000 --- a/dapper-tx/mainnet/moveNameTo.cdc +++ /dev/null @@ -1,31 +0,0 @@ -import Profile from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef - - -transaction(name: String, receiver:String) { - - - let receiverAddress:Address? - let sender : &FIND.LeaseCollection - - prepare(acct: AuthAccount) { - self.sender= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("You do not have a profile set up, initialize the user first") - self.receiverAddress=FIND.resolve(receiver) - } - - pre{ - self.receiverAddress != nil : "The input pass in is not a valid name or address. Input : ".concat(receiver) - } - - execute { - let receiver=getAccount(self.receiverAddress!) - let receiverLease = receiver.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - let receiverProfile = receiver.getCapability<&{Profile.Public}>(Profile.publicPath) - - if !receiverLease.check() || !receiverProfile.check() { - panic("Not a valid FIND user") - } - - self.sender.move(name:name, profile:receiverProfile, to: receiverLease) - } -} diff --git a/dapper-tx/mainnet/publishFindThought.cdc b/dapper-tx/mainnet/publishFindThought.cdc deleted file mode 100644 index afb21c17..00000000 --- a/dapper-tx/mainnet/publishFindThought.cdc +++ /dev/null @@ -1,50 +0,0 @@ -import MetadataViews from 0x1d7e57aa55817448 -import FindThoughts from 0x097bafa4e0b48eef -import FINDNFTCatalog from 0x097bafa4e0b48eef -import FindViews from 0x097bafa4e0b48eef -import FindUtils from 0x097bafa4e0b48eef - -transaction(header: String , body: String , tags: [String], mediaHash: String?, mediaType: String?, quoteNFTOwner: Address?, quoteNFTType: String?, quoteNFTId: UInt64?, quoteCreator: Address?, quoteId: UInt64?) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - let thoughtsCap= account.getCapability<&{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath) - if !thoughtsCap.check() { - account.save(<- FindThoughts.createEmptyCollection(), to: FindThoughts.CollectionStoragePath) - account.link<&FindThoughts.Collection{FindThoughts.CollectionPublic , MetadataViews.ResolverCollection}>( - FindThoughts.CollectionPublicPath, - target: FindThoughts.CollectionStoragePath - ) - } - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - - var media : MetadataViews.Media? = nil - if mediaHash != nil { - var file : {MetadataViews.File}? = nil - if FindUtils.hasPrefix(mediaHash!, prefix: "ipfs://") { - file = MetadataViews.IPFSFile(cid: mediaHash!.slice(from: "ipfs://".length , upTo: mediaHash!.length), path: nil) - } else { - file = MetadataViews.HTTPFile(url: mediaHash!) - } - media = MetadataViews.Media(file: file!, mediaType: mediaType!) - } - - var nftPointer : FindViews.ViewReadPointer? = nil - if quoteNFTOwner != nil { - let path = FINDNFTCatalog.getCollectionDataForType(nftTypeIdentifier: quoteNFTType!)?.publicPath ?? panic("This nft type is not supported by NFT Catalog. Type : ".concat(quoteNFTType!)) - let cap = getAccount(quoteNFTOwner!).getCapability<&{MetadataViews.ResolverCollection}>(path) - nftPointer = FindViews.ViewReadPointer(cap: cap, id: quoteNFTId!) - } - - var quote : FindThoughts.ThoughtPointer? = nil - if quoteCreator != nil { - quote = FindThoughts.ThoughtPointer(creator: quoteCreator!, id: quoteId!) - } - - self.collection.publish(header: header, body: body, tags: tags, media: media, nftPointer: nftPointer, quote: quote) - } -} diff --git a/dapper-tx/mainnet/reactToFindThoughts.cdc b/dapper-tx/mainnet/reactToFindThoughts.cdc deleted file mode 100644 index c1e9a157..00000000 --- a/dapper-tx/mainnet/reactToFindThoughts.cdc +++ /dev/null @@ -1,32 +0,0 @@ -import MetadataViews from 0x1d7e57aa55817448 -import FindThoughts from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef - -transaction(users: [String], ids: [UInt64] , reactions: [String], undoReactionUsers: [String], undoReactionIds: [UInt64]) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - let thoughtsCap= account.getCapability<&{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath) - if !thoughtsCap.check() { - account.save(<- FindThoughts.createEmptyCollection(), to: FindThoughts.CollectionStoragePath) - account.link<&FindThoughts.Collection{FindThoughts.CollectionPublic , MetadataViews.ResolverCollection}>( - FindThoughts.CollectionPublicPath, - target: FindThoughts.CollectionStoragePath - ) - } - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - for i, user in users { - let address = FIND.resolve(user) ?? panic("Cannot resolve user : ".concat(user)) - self.collection.react(user: address, id: ids[i], reaction: reactions[i]) - } - - for i, user in undoReactionUsers { - let address = FIND.resolve(user) ?? panic("Cannot resolve user : ".concat(user)) - self.collection.react(user: address, id: undoReactionIds[i], reaction: nil) - } - } -} diff --git a/dapper-tx/mainnet/redeemAllLostAndFoundNFTs.cdc b/dapper-tx/mainnet/redeemAllLostAndFoundNFTs.cdc deleted file mode 100644 index f4324fcc..00000000 --- a/dapper-tx/mainnet/redeemAllLostAndFoundNFTs.cdc +++ /dev/null @@ -1,251 +0,0 @@ -import FindLostAndFoundWrapper from 0x097bafa4e0b48eef -import LostAndFound from 0x473d6a2c37eab5be -import FINDNFTCatalog from 0x097bafa4e0b48eef -import NFTCatalog from 0x49a7cda3a1eecc29 -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 -import FIND from 0x097bafa4e0b48eef -import Dandy from 0x097bafa4e0b48eef -import NFGv3 from 0x123cb666996b8432 -import PartyFavorz from 0x123cb666996b8432 -import NameVoucher from 0x097bafa4e0b48eef -import Wearables from 0xe81193c424cfd3fb -import FindPack from 0x097bafa4e0b48eef - -//IMPORT - -transaction() { - - let ids : {String : [UInt64]} - let nftInfos : {String : NFTCatalog.NFTCollectionData} - let receiverAddress : Address - - prepare(account: AuthAccount){ - - //LINK - // Dandy - let DandyRef= account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) - if DandyRef == nil { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPublicPath) - if !DandyCap.check() { - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPrivatePath) - if !DandyProviderCap.check() { - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - //findPack - let FindPackRef= account.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath) - if FindPackRef == nil { - account.save<@NonFungibleToken.Collection>(<- FindPack.createEmptyCollection(), to: FindPack.CollectionStoragePath) - account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPublicPath, - target: FindPack.CollectionStoragePath - ) - account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPrivatePath, - target: FindPack.CollectionStoragePath - ) - } - - let FindPackCap= account.getCapability<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPublicPath) - if !FindPackCap.check() { - account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPublicPath, - target: FindPack.CollectionStoragePath - ) - } - - let FindPackProviderCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPrivatePath) - if !FindPackProviderCap.check() { - account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPrivatePath, - target: FindPack.CollectionStoragePath - ) - } - - // NFGv3 - let NFGv3Ref= account.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) - if NFGv3Ref == nil { - account.save<@NonFungibleToken.Collection>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPublicPath) - if !NFGv3Cap.check() { - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPrivatePath) - if !NFGv3ProviderCap.check() { - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - // Party Favorz - let PartyFavorzRef= account.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) - if PartyFavorzRef == nil { - account.save<@NonFungibleToken.Collection>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPublicPath) - if !PartyFavorzCap.check() { - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) - if !PartyFavorzProviderCap.check() { - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - // Name Voucher - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - // Wearables - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) - if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) - if !wearablesCap.check() { - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) - if !wearablesProviderCap.check() { - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - self.nftInfos = {} - self.ids = FindLostAndFoundWrapper.getTicketIDs(user: account.address, specificType: Type<@NonFungibleToken.NFT>()) - - for type in self.ids.keys{ - if self.nftInfos[type] == nil { - let collections = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: type) ?? panic("NFT type is not supported at the moment. Type : ".concat(type)) - self.nftInfos[type] = FINDNFTCatalog.getCatalogEntry(collectionIdentifier: collections.keys[0])!.collectionData - } - } - - self.receiverAddress = account.address - } - - execute{ - for type in self.ids.keys{ - let path = self.nftInfos[type]!.publicPath - for id in self.ids[type]! { - FindLostAndFoundWrapper.redeemNFT(type: CompositeType(type)!, ticketID: id, receiverAddress: self.receiverAddress, collectionPublicPath: path) - } - } - } -} diff --git a/dapper-tx/mainnet/redeemLostAndFoundNFTs.cdc b/dapper-tx/mainnet/redeemLostAndFoundNFTs.cdc deleted file mode 100644 index 94e68c84..00000000 --- a/dapper-tx/mainnet/redeemLostAndFoundNFTs.cdc +++ /dev/null @@ -1,252 +0,0 @@ -import FindLostAndFoundWrapper from 0x097bafa4e0b48eef -import LostAndFound from 0x473d6a2c37eab5be -import FINDNFTCatalog from 0x097bafa4e0b48eef -import NFTCatalog from 0x49a7cda3a1eecc29 -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 -import FindViews from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef -import Dandy from 0x097bafa4e0b48eef -import NFGv3 from 0x123cb666996b8432 -import PartyFavorz from 0x123cb666996b8432 -import NameVoucher from 0x097bafa4e0b48eef -import Wearables from 0xe81193c424cfd3fb -import FindPack from 0x097bafa4e0b48eef - -//IMPORT - -transaction(ids: {String : [UInt64]}) { - - let nftInfos : {String : NFTCatalog.NFTCollectionData} - let receiverAddress : Address - - prepare(account: AuthAccount){ - - //LINK - // Dandy - let DandyRef= account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) - if DandyRef == nil { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPublicPath) - if !DandyCap.check() { - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPrivatePath) - if !DandyProviderCap.check() { - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - - //findPack - let FindPackRef= account.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath) - if FindPackRef == nil { - account.save<@NonFungibleToken.Collection>(<- FindPack.createEmptyCollection(), to: FindPack.CollectionStoragePath) - account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPublicPath, - target: FindPack.CollectionStoragePath - ) - account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPrivatePath, - target: FindPack.CollectionStoragePath - ) - } - - let FindPackCap= account.getCapability<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPublicPath) - if !FindPackCap.check() { - account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPublicPath, - target: FindPack.CollectionStoragePath - ) - } - - let FindPackProviderCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPrivatePath) - if !FindPackProviderCap.check() { - account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPrivatePath, - target: FindPack.CollectionStoragePath - ) - } - - - // NFGv3 - let NFGv3Ref= account.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) - if NFGv3Ref == nil { - account.save<@NonFungibleToken.Collection>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPublicPath) - if !NFGv3Cap.check() { - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPrivatePath) - if !NFGv3ProviderCap.check() { - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - // Party Favorz - let PartyFavorzRef= account.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) - if PartyFavorzRef == nil { - account.save<@NonFungibleToken.Collection>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPublicPath) - if !PartyFavorzCap.check() { - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) - if !PartyFavorzProviderCap.check() { - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - // Name Voucher - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - // Wearables - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) - if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) - if !wearablesCap.check() { - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) - if !wearablesProviderCap.check() { - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - self.nftInfos = {} - - for type in ids.keys{ - if self.nftInfos[type] == nil { - let collections = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: type) ?? panic("NFT type is not supported at the moment. Type : ".concat(type)) - self.nftInfos[type] = FINDNFTCatalog.getCatalogEntry(collectionIdentifier: collections.keys[0])!.collectionData - } - } - - self.receiverAddress = account.address - } - - execute{ - for type in ids.keys{ - let path = self.nftInfos[type]!.publicPath - for id in ids[type]! { - FindLostAndFoundWrapper.redeemNFT(type: CompositeType(type)!, ticketID: id, receiverAddress:self.receiverAddress, collectionPublicPath: path) - } - } - } -} diff --git a/dapper-tx/mainnet/redeemNameVoucher.cdc b/dapper-tx/mainnet/redeemNameVoucher.cdc deleted file mode 100644 index 758e681b..00000000 --- a/dapper-tx/mainnet/redeemNameVoucher.cdc +++ /dev/null @@ -1,74 +0,0 @@ -import NameVoucher from 0x097bafa4e0b48eef -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 -import LostAndFound from 0x473d6a2c37eab5be -import FindLostAndFoundWrapper from 0x097bafa4e0b48eef - -transaction(id: UInt64, name: String) { - - var collection : &NameVoucher.Collection - let addr : Address - - prepare(account:AuthAccount) { - - var nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - } - - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - self.collection = nameVoucherRef! - self.addr = account.address - } - - execute{ - // check if it is there in collection - if self.collection.contains(id) { - self.collection.redeem(id: id, name: name) - return - } - - // check if it is there on L&F - let tickets = LostAndFound.borrowAllTicketsByType(addr: self.addr, type: Type<@NameVoucher.NFT>()) - for ticket in tickets { - if ticket.uuid == id { - let tokenId = ticket.getNonFungibleTokenID()! - FindLostAndFoundWrapper.redeemNFT(type: Type<@NameVoucher.NFT>(), ticketID: id, receiverAddress: self.addr, collectionPublicPath: NameVoucher.CollectionPublicPath) - - self.collection.redeem(id: tokenId, name: name) - return - } - } - - panic("There is no ID or Ticket ID : ".concat(id.toString())) - } - -} diff --git a/dapper-tx/mainnet/register.cdc b/dapper-tx/mainnet/register.cdc deleted file mode 100644 index 60aec277..00000000 --- a/dapper-tx/mainnet/register.cdc +++ /dev/null @@ -1,33 +0,0 @@ -import DapperUtilityCoin from 0xead892083b3e2c6c -import FIND from 0x097bafa4e0b48eef - -transaction(merchAccount: Address, name: String, amount: UFix64) { - - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault - let balanceBeforeTransfer: UFix64 - let price : UFix64 - - prepare(dapper: AuthAccount, account: AuthAccount) { - - self.price=FIND.calculateCost(name) - log("The cost for registering this name is ".concat(self.price.toString())) - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) - self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") - } - - pre{ - self.price == amount : "Calculated cost : ".concat(self.price.toString()).concat(" does not match expected cost : ").concat(amount.toString()) - merchAccount == 0x55459409d30274ee : "Merchant account is not .find" - } - - execute{ - let payVault <- self.mainDapperUtilityCoinVault.withdraw(amount: self.price) as! @DapperUtilityCoin.Vault - self.finLeases.registerDapper(merchAccount: merchAccount, name: name, vault: <- payVault) - } - - post { - self.mainDapperUtilityCoinVault.balance == self.balanceBeforeTransfer: "DapperUtilityCoin leakage" - } -} diff --git a/dapper-tx/mainnet/removeRelatedAccount.cdc b/dapper-tx/mainnet/removeRelatedAccount.cdc deleted file mode 100644 index 1b6d2940..00000000 --- a/dapper-tx/mainnet/removeRelatedAccount.cdc +++ /dev/null @@ -1,28 +0,0 @@ -import FindRelatedAccounts from 0x097bafa4e0b48eef - -transaction(name: String, network: String, address: String){ - - var relatedAccounts : &FindRelatedAccounts.Accounts? - - prepare(account: AuthAccount) { - - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - if self.relatedAccounts == nil { - let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - } - - let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) - if !cap.check() { - account.unlink(FindRelatedAccounts.publicPath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - } - - } - - execute{ - self.relatedAccounts!.removeRelatedAccount(name: name, network: network, address: address) - } -} diff --git a/dapper-tx/mainnet/renewName.cdc b/dapper-tx/mainnet/renewName.cdc deleted file mode 100644 index 098e0859..00000000 --- a/dapper-tx/mainnet/renewName.cdc +++ /dev/null @@ -1,32 +0,0 @@ -import DapperUtilityCoin from 0xead892083b3e2c6c -import FIND from 0x097bafa4e0b48eef - -transaction(merchAccount: Address, name: String, amount: UFix64) { - - let price : UFix64 - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault - let balanceBeforeTransfer: UFix64 - - prepare(dapper: AuthAccount, acct: AuthAccount) { - self.price=FIND.calculateCost(name) - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) - self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance - self.finLeases= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") - } - - pre{ - merchAccount == 0x55459409d30274ee : "Merchant account is not .find" - self.price == amount : "expected renew cost : ".concat(self.price.toString()).concat(" is not the same as calculated renew cost : ").concat(amount.toString()) - } - - execute{ - let payVault <- self.mainDapperUtilityCoinVault.withdraw(amount: self.price) as! @DapperUtilityCoin.Vault - let finToken= self.finLeases.borrow(name) - finToken.extendLeaseDapper(merchAccount: merchAccount, vault: <- payVault) - } - - post { - self.mainDapperUtilityCoinVault.balance == self.balanceBeforeTransfer: "DapperUtilityCoin leakage" - } -} diff --git a/dapper-tx/mainnet/sendNFTs.cdc b/dapper-tx/mainnet/sendNFTs.cdc deleted file mode 100644 index 0f8695e9..00000000 --- a/dapper-tx/mainnet/sendNFTs.cdc +++ /dev/null @@ -1,200 +0,0 @@ -import NonFungibleToken from 0x1d7e57aa55817448 -import FungibleToken from 0xf233dcee88fe0abe -import FlowStorageFees from 0xe467b9dd11fa00df -import FlowToken from 0x1654653399040a61 -import MetadataViews from 0x1d7e57aa55817448 -import NFTCatalog from 0x49a7cda3a1eecc29 -import FINDNFTCatalog from 0x097bafa4e0b48eef -import FindViews from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef -import FindAirdropper from 0x097bafa4e0b48eef -import FTRegistry from 0x097bafa4e0b48eef -import Profile from 0x097bafa4e0b48eef -import Sender from 0x097bafa4e0b48eef - -transaction(nftIdentifiers: [String], allReceivers: [String] , ids:[UInt64], memos: [String], donationTypes: [String?], donationAmounts: [UFix64?], findDonationType: String?, findDonationAmount: UFix64?) { - - let authPointers : [FindViews.AuthNFTPointer] - let paths : [PublicPath] - let flowVault : &FungibleToken.Vault - let flowTokenRepayment : Capability<&FlowToken.Vault{FungibleToken.Receiver}> - let defaultTokenAvailableBalance : UFix64 - - let royalties: [MetadataViews.Royalties?] - let totalRoyalties: [UFix64] - let vaultRefs: {String : &FungibleToken.Vault} - var token : &Sender.Token - - prepare(account : AuthAccount) { - - self.authPointers = [] - self.paths = [] - self.royalties = [] - self.totalRoyalties = [] - self.vaultRefs = {} - - - let contractData : {Type : NFTCatalog.NFTCatalogMetadata} = {} - - - for i , typeIdentifier in nftIdentifiers { - let type = CompositeType(typeIdentifier) ?? panic("Cannot refer to type with identifier : ".concat(typeIdentifier)) - - var data : NFTCatalog.NFTCatalogMetadata? = contractData[type] - if data == nil { - data = FINDNFTCatalog.getMetadataFromType(type) ?? panic("NFT Type is not supported by NFT Catalog. Type : ".concat(type.identifier)) - contractData[type] = data - } - - let path = data!.collectionData - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(path.privatePath) - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - path.privatePath, - target: path.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = path.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: path.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: ids[i]) - - if let dt = donationTypes[i] { - self.royalties.append(pointer.getRoyalty()) - self.totalRoyalties.append(pointer.getTotalRoyaltiesCut()) - - // get the vault for donation - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - - } else { - self.royalties.append(nil) - self.totalRoyalties.append(0.0) - } - - self.authPointers.append(pointer) - self.paths.append(path.publicPath) - } - - self.flowVault = account.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) ?? panic("Cannot borrow reference to sender's flow vault") - self.flowTokenRepayment = account.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) - self.defaultTokenAvailableBalance = FlowStorageFees.defaultTokenAvailableBalance(account.address) - - // get the vault for find donation - if let dt = findDonationType { - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - } - - if account.borrow<&Sender.Token>(from: Sender.storagePath) == nil { - account.save(<- Sender.create(), to: Sender.storagePath) - } - - self.token =account.borrow<&Sender.Token>(from: Sender.storagePath)! - - } - - execute { - let addresses : {String : Address} = {} - let estimatedStorageFee = 0.0002 * UFix64(self.authPointers.length) - // we pass in the least amount as possible for storage fee here - let tempVault <- self.flowVault.withdraw(amount: 0.0) - var vaultRef = &tempVault as &FungibleToken.Vault - if self.defaultTokenAvailableBalance <= estimatedStorageFee { - vaultRef = self.flowVault as &FungibleToken.Vault - } else { - tempVault.deposit(from: <- self.flowVault.withdraw(amount: estimatedStorageFee)) - } - - let ctx : {String : String} = { - "tenant" : "find" - } - - for i, pointer in self.authPointers { - let receiver = allReceivers[i] - let id = ids[i] - ctx["message"] = memos[i] - let path = self.paths[i] - - var user = addresses[receiver] - if user == nil { - user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) - addresses[receiver] = user - } - - // airdrop thru airdropper - FindAirdropper.forcedAirdrop(pointer: pointer, receiver: user!, path: path, context: ctx, storagePayment: vaultRef, flowTokenRepayment: self.flowTokenRepayment, deepValidation: true) - } - self.flowVault.deposit(from: <- tempVault) - - // This is hard coded for spliting at the front end for now. So if there are no royalties, all goes to find - // AND This does not support different ft types for now. - var goesToFindFund = 0.0 - for i , type in donationTypes { - if type == nil { - continue - } - let amount = donationAmounts[i]! - let royalties = self.royalties[i]! - let totalRoyalties = self.totalRoyalties[i] - let vaultRef = self.vaultRefs[type!]! - var noRoyalty = false - if totalRoyalties == 0.0 { - goesToFindFund = goesToFindFund + amount - continue - } - - let balance = vaultRef.balance - var totalPaid = 0.0 - - for j, r in royalties.getRoyalties() { - var cap : Capability<&{FungibleToken.Receiver}> = r.receiver - if !r.receiver.check(){ - // try to grab from profile - if let ref = getAccount(r.receiver.address).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() { - if ref.hasWallet(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - } else if let ftInfo = FTRegistry.getFTInfo(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(ftInfo.receiverPath) - } - } - - } - - if cap.check() { - let individualAmount = r.cut / totalRoyalties * amount - let vault <- vaultRef.withdraw(amount: individualAmount) - cap.borrow()!.deposit(from: <- vault) - - totalPaid = totalPaid + individualAmount - } - } - - assert(totalPaid <= amount, message: "Amount paid is greater than expected" ) - - } - - // for donating to find - if findDonationType != nil { - vaultRef = self.vaultRefs[findDonationType!]! - let vault <- vaultRef.withdraw(amount: findDonationAmount! + goesToFindFund) - FIND.depositWithTagAndMessage(to: "find", message: "donation to .find", tag: "donation", vault: <- vault, from: self.token) - } - } -} diff --git a/dapper-tx/mainnet/sendWearables.cdc b/dapper-tx/mainnet/sendWearables.cdc deleted file mode 100644 index 55630c61..00000000 --- a/dapper-tx/mainnet/sendWearables.cdc +++ /dev/null @@ -1,68 +0,0 @@ -import NonFungibleToken from 0x1d7e57aa55817448 -import MetadataViews from 0x1d7e57aa55817448 -import FindViews from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef -import FindAirdropper from 0x097bafa4e0b48eef -import Wearables from 0xe81193c424cfd3fb - -transaction(allReceivers: [String] , ids:[UInt64], memos: [String]) { - - let authPointers : [FindViews.AuthNFTPointer] - - prepare(account : AuthAccount) { - - self.authPointers = [] - let privatePath = Wearables.CollectionPrivatePath - let storagePath = Wearables.CollectionStoragePath - - for id in ids { - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(privatePath) - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - privatePath, - target: storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: id) - - self.authPointers.append(pointer) - } - - } - - execute { - let addresses : {String : Address} = {} - let publicPath = Wearables.CollectionPublicPath - - let ctx : {String : String} = { - "tenant" : "find" - } - - for i, pointer in self.authPointers { - let receiver = allReceivers[i] - let id = ids[i] - ctx["message"] = memos[i] - - var user = addresses[receiver] - if user == nil { - user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) - addresses[receiver] = user - } - - // airdrop thru airdropper - FindAirdropper.safeAirdrop(pointer: pointer, receiver: user!, path: publicPath, context: ctx, deepValidation: true) - } - - } -} diff --git a/dapper-tx/mainnet/setMainName.cdc b/dapper-tx/mainnet/setMainName.cdc deleted file mode 100644 index 965bb5bd..00000000 --- a/dapper-tx/mainnet/setMainName.cdc +++ /dev/null @@ -1,23 +0,0 @@ -import Profile from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef - - -transaction(name: String) { - - let leaseCollectionOwner : Capability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}> - let profile : &Profile.User - - prepare(acct: AuthAccount) { - self.leaseCollectionOwner = acct.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath)! - } - - pre{ - self.leaseCollectionOwner.check() : "Not a find user" - self.leaseCollectionOwner.borrow()!.getLease(name) != nil : "You do not own this lease so you cannot set it as main name" - } - - execute{ - self.profile.setFindName(name) - } -} diff --git a/dapper-tx/mainnet/setPrivateMode.cdc b/dapper-tx/mainnet/setPrivateMode.cdc deleted file mode 100644 index cffd6c61..00000000 --- a/dapper-tx/mainnet/setPrivateMode.cdc +++ /dev/null @@ -1,19 +0,0 @@ -import Profile from 0x097bafa4e0b48eef - -transaction(mode: Bool) { - - let profile : &Profile.User? - - prepare(acct: AuthAccount) { - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath) - } - - pre{ - self.profile != nil : "Cannot borrow reference to profile" - } - - execute{ - self.profile!.setPrivateMode(mode) - self.profile!.emitUpdatedEvent() - } -} diff --git a/dapper-tx/mainnet/setProfile.cdc b/dapper-tx/mainnet/setProfile.cdc deleted file mode 100644 index 10f8f53c..00000000 --- a/dapper-tx/mainnet/setProfile.cdc +++ /dev/null @@ -1,19 +0,0 @@ -import Profile from 0x097bafa4e0b48eef - -transaction(avatar: String) { - - let profile : &Profile.User? - - prepare(acct: AuthAccount) { - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath) - } - - pre{ - self.profile != nil : "Cannot borrow reference to profile" - } - - execute{ - self.profile!.setAvatar(avatar) - self.profile!.emitUpdatedEvent() - } -} diff --git a/dapper-tx/mainnet/setRelatedAccount.cdc b/dapper-tx/mainnet/setRelatedAccount.cdc deleted file mode 100644 index 9e807348..00000000 --- a/dapper-tx/mainnet/setRelatedAccount.cdc +++ /dev/null @@ -1,36 +0,0 @@ -import FindRelatedAccounts from 0x097bafa4e0b48eef -import FIND from 0x097bafa4e0b48eef - -transaction(name: String, target: String) { - - var relatedAccounts : &FindRelatedAccounts.Accounts? - let address : Address? - - prepare(account: AuthAccount) { - - - self.address = FIND.resolve(target) - - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - if self.relatedAccounts == nil { - let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - } - - let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) - if !cap.check() { - account.unlink(FindRelatedAccounts.publicPath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - } - } - - pre{ - self.address != nil : "The input pass in is not a valid name or address. Input : ".concat(target) - } - - execute{ - self.relatedAccounts!.addFlowAccount(name: name, address: self.address!) - } -} diff --git a/dapper-tx/testnet/buyAddon.cdc b/dapper-tx/testnet/buyAddon.cdc deleted file mode 100644 index 14fccfde..00000000 --- a/dapper-tx/testnet/buyAddon.cdc +++ /dev/null @@ -1,26 +0,0 @@ -import DapperUtilityCoin from 0x82ec283f88a62e65 -import FIND from 0x35717efbbce11c74 - - -transaction(merchAccount: Address, name: String, addon:String, amount:UFix64) { - - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault - let balanceBeforeTransfer: UFix64 - - prepare(dapper: AuthAccount, account: AuthAccount) { - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) - self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") - - } - - execute { - let vault <- self.mainDapperUtilityCoinVault.withdraw(amount: amount) as! @DapperUtilityCoin.Vault - self.finLeases.buyAddonDapper(merchAccount: merchAccount, name: name, addon: addon, vault: <- vault) - } - - post { - self.mainDapperUtilityCoinVault.balance == self.balanceBeforeTransfer: "DapperUtilityCoin leakage" - } -} diff --git a/dapper-tx/testnet/buyLeaseForSale.cdc b/dapper-tx/testnet/buyLeaseForSale.cdc deleted file mode 100644 index 14cfcca0..00000000 --- a/dapper-tx/testnet/buyLeaseForSale.cdc +++ /dev/null @@ -1,75 +0,0 @@ -import FindMarket from 0x35717efbbce11c74 -import DapperUtilityCoin from 0x82ec283f88a62e65 -import FlowUtilityToken from 0x82ec283f88a62e65 -import FungibleToken from 0x9a0766d93b6608b7 -import FIND from 0x35717efbbce11c74 -import Profile from 0x35717efbbce11c74 -import FindLeaseMarketSale from 0x35717efbbce11c74 -import FindLeaseMarket from 0x35717efbbce11c74 - -transaction(sellerAccount: Address, leaseName: String, amount: UFix64) { - - let to : Address - let walletReference : &FungibleToken.Vault - - let saleItemCollection: &FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic} - let balanceBeforeTransfer: UFix64 - - prepare(dapper: AuthAccount, account: AuthAccount) { - - let profile=account.borrow<&Profile.User>(from: Profile.storagePath) ?? panic("You do not have a profile set up, initialize the user first") - - let address = FIND.resolve(leaseName) ?? panic("The address input is not a valid name nor address. Input : ".concat(leaseName)) - - if address != sellerAccount { - panic("address does not resolve to seller") - } - - let leaseMarketplace = FindMarket.getTenantAddress("find") ?? panic("Cannot find find tenant") - let saleItemsCap= FindLeaseMarketSale.getSaleItemCapability(marketplace: leaseMarketplace, user:address) ?? panic("cannot find sale item cap for find") - - let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseSaleItemType= Type<@FindLeaseMarketSale.SaleItemCollection>() - let leasePublicPath=FindMarket.getPublicPath(leaseSaleItemType, name: "find") - let leaseStoragePath= FindMarket.getStoragePath(leaseSaleItemType, name:"find") - let leaseSaleItemCap= account.getCapability<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath) - if !leaseSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketSale.SaleItemCollection>(<- FindLeaseMarketSale.createEmptySaleItemCollection(leaseTenantCapability), to: leaseStoragePath) - account.link<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath, target: leaseStoragePath) - } - - self.to= account.address - - self.saleItemCollection = saleItemsCap.borrow()! - let item = self.saleItemCollection.borrowSaleItem(leaseName) - - var ftVaultPath : StoragePath? = nil - switch item.getFtType() { - case Type<@DapperUtilityCoin.Vault>() : - ftVaultPath = /storage/dapperUtilityCoinVault - - case Type<@FlowUtilityToken.Vault>() : - ftVaultPath = /storage/flowUtilityTokenVault - - default : - panic("This FT is not supported by the Find Market in Dapper Wallet. Type : ".concat(item.getFtType().identifier)) - } - - - self.walletReference = dapper.borrow<&FungibleToken.Vault>(from: ftVaultPath!) ?? panic("No suitable wallet linked for this account") - self.balanceBeforeTransfer = self.walletReference.balance - } - - execute { - let vault <- self.walletReference.withdraw(amount: amount) - self.saleItemCollection.buy(name:leaseName, vault: <- vault, to: self.to) - } - - // Check that all dapper Coin was routed back to Dapper - post { - self.walletReference.balance == self.balanceBeforeTransfer: "Dapper Coin leakage" - } -} diff --git a/dapper-tx/testnet/buyNFTForSale.cdc b/dapper-tx/testnet/buyNFTForSale.cdc deleted file mode 100644 index fc5cb5ae..00000000 --- a/dapper-tx/testnet/buyNFTForSale.cdc +++ /dev/null @@ -1,96 +0,0 @@ -import FindMarket from 0x35717efbbce11c74 -import Profile from 0x35717efbbce11c74 -import FindMarketSale from 0x35717efbbce11c74 -import NFTCatalog from 0x324c34e1c517e4db -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 -import FungibleToken from 0x9a0766d93b6608b7 -import DapperStorageRent from 0x43ee8c22fcf94ea3 -import TopShot from 0x877931736ee77cff -import DapperUtilityCoin from 0x82ec283f88a62e65 -import FlowUtilityToken from 0x82ec283f88a62e65 - -//first argument is the address to the merchant that gets the funds -transaction(address: Address, id: UInt64, amount: UFix64) { - - let targetCapability : Capability<&{NonFungibleToken.Receiver}> - let walletReference : &FungibleToken.Vault - let receiver : Address - - let saleItemsCap: Capability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic}> - let balanceBeforeTransfer: UFix64 - prepare(dapper: AuthAccount, account: AuthAccount) { - let marketplace = FindMarket.getFindTenantAddress() - self.receiver=account.address - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let tenant = tenantCapability.borrow()! - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) - - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - - self.saleItemsCap= FindMarketSale.getSaleItemCapability(marketplace: marketplace, user:address) ?? panic("cannot find sale item cap") - let marketOption = FindMarket.getMarketOptionFromType(Type<@FindMarketSale.SaleItemCollection>()) - - //we do some security check to verify that this tenant can do this operation. This will ensure that the onefootball tenant can only sell using DUC and not some other token. But we can change this with transactions later and not have to modify code/transactions - let item= FindMarket.assertOperationValid(tenant: marketplace, address: address, marketOption: marketOption, id: id) - let collectionIdentifier = NFTCatalog.getCollectionsForType(nftTypeIdentifier: item.getItemType().identifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(item.getItemType().identifier)) - let collection = NFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData - - var ftVaultPath : StoragePath? = nil - switch item.getFtType() { - case Type<@DapperUtilityCoin.Vault>() : - ftVaultPath = /storage/dapperUtilityCoinVault - - case Type<@FlowUtilityToken.Vault>() : - ftVaultPath = /storage/flowUtilityTokenVault - - default : - panic("This FT is not supported by the Find Market in Dapper Wallet. Type : ".concat(item.getFtType().identifier)) - } - - self.targetCapability= account.getCapability<&{NonFungibleToken.Receiver}>(nft.publicPath) - - if !self.targetCapability.check() { - let cd = item.getNFTCollectionData() - if let storage = account.borrow<&AnyResource>(from: cd.storagePath) { - if let st = account.borrow<&TopShot.Collection>(from: cd.storagePath) { - // here means the topShot is not linked in the way it should be. We can relink that for our use - account.unlink(cd.publicPath) - account.link<&TopShot.Collection{TopShot.MomentCollectionPublic,NonFungibleToken.Receiver,NonFungibleToken.CollectionPublic,MetadataViews.ResolverCollection}>(cd.publicPath, target: cd.storagePath) - } else { - panic("This collection public link is not set up properly.") - } - } else { - account.save(<- cd.createEmptyCollection(), to: cd.storagePath) - account.link<&{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(cd.publicPath, target: cd.storagePath) - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(cd.providerPath, target: cd.storagePath) - } - } - - self.walletReference = dapper.borrow<&FungibleToken.Vault>(from: ftVaultPath!) ?? panic("No suitable wallet linked for this account") - self.balanceBeforeTransfer = self.walletReference.balance - } - - pre { - self.walletReference.balance > amount : "Your wallet does not have enough funds to pay for this item" - } - - execute { - let vault <- self.walletReference.withdraw(amount: amount) - self.saleItemsCap.borrow()!.buy(id:id, vault: <- vault, nftCap: self.targetCapability) - DapperStorageRent.tryRefill(self.receiver) - } - - // Check that all dapper Coin was routed back to Dapper - post { - self.walletReference.balance == self.balanceBeforeTransfer: "Dapper Coin leakage" - } -} diff --git a/dapper-tx/testnet/createProfile.cdc b/dapper-tx/testnet/createProfile.cdc deleted file mode 100644 index 176dedcc..00000000 --- a/dapper-tx/testnet/createProfile.cdc +++ /dev/null @@ -1,90 +0,0 @@ -import FungibleToken from 0x9a0766d93b6608b7 -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 -import FIND from 0x35717efbbce11c74 -import Dandy from 0x35717efbbce11c74 -import Profile from 0x35717efbbce11c74 -import FindMarket from 0x35717efbbce11c74 -import FindMarketDirectOfferSoft from 0x35717efbbce11c74 -import DapperUtilityCoin from 0x82ec283f88a62e65 -import FlowUtilityToken from 0x82ec283f88a62e65 -import FindLeaseMarketDirectOfferSoft from 0x35717efbbce11c74 -import FindLeaseMarket from 0x35717efbbce11c74 - -transaction(name: String) { - prepare(account: AuthAccount) { - let leaseCollection = account.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !leaseCollection.check() { - account.save(<- FIND.createEmptyLeaseCollection(), to: FIND.LeaseStoragePath) - account.link<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>( FIND.LeasePublicPath, target: FIND.LeaseStoragePath) - } - - let dandyCap= account.getCapability<&{NonFungibleToken.CollectionPublic}>(Dandy.CollectionPublicPath) - if !dandyCap.check() { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - var created=false - var updated=false - let profileCap = account.getCapability<&{Profile.Public}>(Profile.publicPath) - if !profileCap.check() { - let profile <-Profile.createUser(name:name, createdAt: "find") - account.save(<-profile, to: Profile.storagePath) - account.link<&Profile.User{Profile.Public}>(Profile.publicPath, target: Profile.storagePath) - account.link<&{FungibleToken.Receiver}>(Profile.publicReceiverPath, target: Profile.storagePath) - created=true - } - - let profile=account.borrow<&Profile.User>(from: Profile.storagePath)! - - if !profile.hasWallet("DUC") { - let ducReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) - profile.addWallet(Profile.Wallet( name:"DUC", receiver:ducReceiver, balance:account.getCapability<&{FungibleToken.Balance}>(/public/dapperUtilityCoinBalance), accept: Type<@DapperUtilityCoin.Vault>(), tags: ["duc", "dapperUtilityCoin","dapper"])) - updated=true - } - - if !profile.hasWallet("FUT") { - let futReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - profile.addWallet(Profile.Wallet( name:"FUT", receiver:futReceiver, balance:account.getCapability<&{FungibleToken.Balance}>(/public/flowUtilityTokenBalance), accept: Type<@FlowUtilityToken.Vault>(), tags: ["fut", "flowUtilityToken","dapper"])) - updated=true - } - - profile.emitCreatedEvent() - - let receiverCap=account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - let tenantCapability= FindMarket.getTenantCapability(FindMarket.getFindTenantAddress())! - - let tenant = tenantCapability.borrow()! - - let dosSaleType= Type<@FindMarketDirectOfferSoft.SaleItemCollection>() - let dosSalePublicPath=FindMarket.getPublicPath(dosSaleType, name: tenant.name) - let dosSaleStoragePath= FindMarket.getStoragePath(dosSaleType, name:tenant.name) - let dosSaleCap= account.getCapability<&FindMarketDirectOfferSoft.SaleItemCollection{FindMarketDirectOfferSoft.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(dosSalePublicPath) - if !dosSaleCap.check() { - account.save<@FindMarketDirectOfferSoft.SaleItemCollection>(<- FindMarketDirectOfferSoft.createEmptySaleItemCollection(tenantCapability), to: dosSaleStoragePath) - account.link<&FindMarketDirectOfferSoft.SaleItemCollection{FindMarketDirectOfferSoft.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(dosSalePublicPath, target: dosSaleStoragePath) - } - - let leaseTenantCapability= FindMarket.getTenantCapability(FindMarket.getFindTenantAddress())! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseDOSSaleItemType= Type<@FindLeaseMarketDirectOfferSoft.SaleItemCollection>() - let leaseDOSPublicPath=leaseTenant.getPublicPath(leaseDOSSaleItemType) - let leaseDOSStoragePath= leaseTenant.getStoragePath(leaseDOSSaleItemType) - let leaseDOSSaleItemCap= account.getCapability<&FindLeaseMarketDirectOfferSoft.SaleItemCollection{FindLeaseMarketDirectOfferSoft.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leaseDOSPublicPath) - if !leaseDOSSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketDirectOfferSoft.SaleItemCollection>(<- FindLeaseMarketDirectOfferSoft.createEmptySaleItemCollection(leaseTenantCapability), to: leaseDOSStoragePath) - account.link<&FindLeaseMarketDirectOfferSoft.SaleItemCollection{FindLeaseMarketDirectOfferSoft.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leaseDOSPublicPath, target: leaseDOSStoragePath) - } - - } -} diff --git a/dapper-tx/testnet/deleteFindThoughts.cdc b/dapper-tx/testnet/deleteFindThoughts.cdc deleted file mode 100644 index bfb8ea56..00000000 --- a/dapper-tx/testnet/deleteFindThoughts.cdc +++ /dev/null @@ -1,17 +0,0 @@ -import FindThoughts from 0x35717efbbce11c74 - -transaction(ids: [UInt64]) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - for id in ids { - self.collection.delete(id) - } - } -} diff --git a/dapper-tx/testnet/delistLeaseSale.cdc b/dapper-tx/testnet/delistLeaseSale.cdc deleted file mode 100644 index 1c7355ce..00000000 --- a/dapper-tx/testnet/delistLeaseSale.cdc +++ /dev/null @@ -1,23 +0,0 @@ -import FindMarket from 0x35717efbbce11c74 -import FindLeaseMarketSale from 0x35717efbbce11c74 - -transaction(leases: [String]) { - let saleItems : &FindLeaseMarketSale.SaleItemCollection? - - prepare(account: AuthAccount) { - - let tenant=FindMarket.getTenant(FindMarket.getFindTenantAddress()) - self.saleItems= account.borrow<&FindLeaseMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindLeaseMarketSale.SaleItemCollection>())) - - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - for lease in leases { - self.saleItems!.delist(lease) - } - } -} diff --git a/dapper-tx/testnet/delistNFTSale.cdc b/dapper-tx/testnet/delistNFTSale.cdc deleted file mode 100644 index cc47130c..00000000 --- a/dapper-tx/testnet/delistNFTSale.cdc +++ /dev/null @@ -1,24 +0,0 @@ -import FindMarket from 0x35717efbbce11c74 -import FindMarketSale from 0x35717efbbce11c74 - -//Remove one or more listings from a marketplace -transaction(ids: [UInt64]) { - - let saleItems : &FindMarketSale.SaleItemCollection? - - prepare(account: AuthAccount) { - let marketplace = FindMarket.getFindTenantAddress() - let tenant=FindMarket.getTenant(marketplace) - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - for id in ids { - self.saleItems!.delist(id) - } - } -} diff --git a/dapper-tx/testnet/editFindThought.cdc b/dapper-tx/testnet/editFindThought.cdc deleted file mode 100644 index fdabb526..00000000 --- a/dapper-tx/testnet/editFindThought.cdc +++ /dev/null @@ -1,16 +0,0 @@ -import FindThoughts from 0x35717efbbce11c74 - -transaction(id: UInt64, header: String , body: String, tags: [String]) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - let thought = self.collection.borrow(id) - thought.edit(header: header , body: body, tags: tags) - } -} diff --git a/dapper-tx/testnet/editProfile.cdc b/dapper-tx/testnet/editProfile.cdc deleted file mode 100644 index 0e9ecdd3..00000000 --- a/dapper-tx/testnet/editProfile.cdc +++ /dev/null @@ -1,40 +0,0 @@ -import FIND from 0x35717efbbce11c74 -import Profile from 0x35717efbbce11c74 - -transaction(name:String, description: String, avatar: String, tags:[String], allowStoringFollowers: Bool, linkTitles : {String: String}, linkTypes: {String:String}, linkUrls : {String:String}, removeLinks : [String]) { - - let profile : &Profile.User - - prepare(account: AuthAccount) { - - self.profile =account.borrow<&Profile.User>(from:Profile.storagePath) ?? panic("You do not have a profile set up, initialize the user first") - - let leaseCollection = account.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !leaseCollection.check() { - account.save(<- FIND.createEmptyLeaseCollection(), to: FIND.LeaseStoragePath) - account.link<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>( FIND.LeasePublicPath, target: FIND.LeaseStoragePath) - - } - - } - - execute{ - self.profile.setName(name) - self.profile.setDescription(description) - self.profile.setAvatar(avatar) - self.profile.setTags(tags) - - for link in removeLinks { - self.profile.removeLink(link) - } - - for titleName in linkTitles.keys { - let title=linkTitles[titleName]! - let url = linkUrls[titleName]! - let type = linkTypes[titleName]! - - self.profile.addLinkWithName(name:titleName, link: Profile.Link(title: title, type: type, url: url)) - } - self.profile.emitUpdatedEvent() - } -} diff --git a/dapper-tx/testnet/getMetadataForBuyAddon.cdc b/dapper-tx/testnet/getMetadataForBuyAddon.cdc deleted file mode 100644 index a504bf80..00000000 --- a/dapper-tx/testnet/getMetadataForBuyAddon.cdc +++ /dev/null @@ -1,32 +0,0 @@ -import FIND from 0x35717efbbce11c74 - -pub fun main(merchAccount: Address, name: String, addon:String, amount:UFix64) : PurchaseData { - let description = "Purchase addon ".concat(addon).concat(" for name :").concat(name).concat(" for DUC ").concat(amount.toString()) - let imageURL = "https://i.imgur.com/8W8NoO1.png" - - return PurchaseData( - id: 0, - name: name, - amount: amount, - description: description, - imageURL: imageURL - ) - - -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - } -} diff --git a/dapper-tx/testnet/getMetadataForBuyLeaseForSale.cdc b/dapper-tx/testnet/getMetadataForBuyLeaseForSale.cdc deleted file mode 100644 index eef675d8..00000000 --- a/dapper-tx/testnet/getMetadataForBuyLeaseForSale.cdc +++ /dev/null @@ -1,43 +0,0 @@ -import FindMarket from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 -import Profile from 0x35717efbbce11c74 -import DapperUtilityCoin from 0x82ec283f88a62e65 -import FindLeaseMarketSale from 0x35717efbbce11c74 -import FindLeaseMarket from 0x35717efbbce11c74 - -pub fun main(sellerAccount: Address, leaseName: String, amount: UFix64) :PurchaseData{ - - let address = FIND.resolve(leaseName) ?? panic("The address input is not a valid name nor address. Input : ".concat(leaseName)) - let leaseMarketplace = FindMarket.getFindTenantAddress() - let leaseTenant = FindMarket.getTenant(leaseMarketplace) - let storagePath = leaseTenant.getStoragePath(Type<@FindLeaseMarketSale.SaleItemCollection>()) - let saleItemRef = getAuthAccount(address).borrow<&FindLeaseMarketSale.SaleItemCollection>(from: storagePath) ?? panic("Cannot borrow reference to sale item") - let saleItem = saleItemRef.borrow(leaseName) - - let description = "Name :".concat(leaseName).concat(" for DUC ").concat(amount.toString()) - let imageURL = "https://i.imgur.com/8W8NoO1.png" - - return PurchaseData( - id: saleItem.getId(), - name: leaseName, - amount: amount, - description: description, - imageURL: imageURL - ) -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - } -} diff --git a/dapper-tx/testnet/getMetadataForBuyNFTForSale.cdc b/dapper-tx/testnet/getMetadataForBuyNFTForSale.cdc deleted file mode 100644 index ab20d79e..00000000 --- a/dapper-tx/testnet/getMetadataForBuyNFTForSale.cdc +++ /dev/null @@ -1,40 +0,0 @@ -import FindMarket from 0x35717efbbce11c74 -import FindMarketSale from 0x35717efbbce11c74 - -pub fun main(address: Address, id: UInt64, amount: UFix64) : PurchaseData { - - let marketplace = FindMarket.getFindTenantAddress() - let marketOption = FindMarket.getMarketOptionFromType(Type<@FindMarketSale.SaleItemCollection>()) - let item= FindMarket.assertOperationValid(tenant: marketplace, address: address, marketOption: marketOption, id: id) - let display = item.getDisplay() - let itemID = item.getItemID() - let amount = item.getBalance() - - - return PurchaseData( - id: itemID, - name: display.name, - amount: amount, - description: display.description, - imageURL: display.thumbnail.uri(), - paymentVaultTypeID: item.getFtType(), - ) -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - pub let paymentVaultTypeID: Type - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String, paymentVaultTypeID: Type) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - self.paymentVaultTypeID=paymentVaultTypeID - } -} diff --git a/dapper-tx/testnet/getMetadataForRegister.cdc b/dapper-tx/testnet/getMetadataForRegister.cdc deleted file mode 100644 index e9862036..00000000 --- a/dapper-tx/testnet/getMetadataForRegister.cdc +++ /dev/null @@ -1,32 +0,0 @@ -import FIND from 0x35717efbbce11c74 - -pub fun main(merchAccount: Address, name: String, amount: UFix64) : PurchaseData { - - let description = "Name :".concat(name).concat(" for DUC ").concat(amount.toString()) - let imageURL = "https://ik.imagekit.io/xyvsisxky/tr:ot-".concat(name).concat(",ots-55,otc-58B792,ox-N166,oy-N24,ott-b/https://i.imgur.com/8W8NoO1.png") - - return PurchaseData( - id: 0, - name: name, - amount: amount, - description: description, - imageURL: imageURL - ) - -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - } -} diff --git a/dapper-tx/testnet/getMetadataForRenewName.cdc b/dapper-tx/testnet/getMetadataForRenewName.cdc deleted file mode 100644 index 31b1f46a..00000000 --- a/dapper-tx/testnet/getMetadataForRenewName.cdc +++ /dev/null @@ -1,31 +0,0 @@ -import FIND from 0x35717efbbce11c74 - -pub fun main(merchAccount: Address, name: String, amount: UFix64) : PurchaseData { - - let description = "Renew name :".concat(name).concat(" for DUC ").concat(amount.toString()) - let imageURL = "https://ik.imagekit.io/xyvsisxky/tr:ot-".concat(name).concat(",ots-55,otc-58B792,ox-N166,oy-N24,ott-b/https://i.imgur.com/8W8NoO1.png") - - return PurchaseData( - id: 0, - name: name, - amount: amount, - description: description, - imageURL: imageURL - ) -} - -pub struct PurchaseData { - pub let id: UInt64 - pub let name: String - pub let amount: UFix64 - pub let description: String - pub let imageURL: String - - init(id: UInt64, name: String, amount: UFix64, description: String, imageURL: String) { - self.id = id - self.name = name - self.amount = amount - self.description = description - self.imageURL = imageURL - } -} diff --git a/dapper-tx/testnet/hideFindThoughts.cdc b/dapper-tx/testnet/hideFindThoughts.cdc deleted file mode 100644 index 11a5768c..00000000 --- a/dapper-tx/testnet/hideFindThoughts.cdc +++ /dev/null @@ -1,18 +0,0 @@ -import FindThoughts from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 - -transaction(ids: [UInt64], hide: [Bool]) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - for i, id in ids { - self.collection.hide(id: id, hide: hide[i]) - } - - } -} diff --git a/dapper-tx/testnet/initCollections.cdc b/dapper-tx/testnet/initCollections.cdc deleted file mode 100644 index 37432411..00000000 --- a/dapper-tx/testnet/initCollections.cdc +++ /dev/null @@ -1,183 +0,0 @@ -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 -import NameVoucher from 0x35717efbbce11c74 -import Wearables from 0x1c5033ad60821c97 -import PartyFavorz from 0x3e5b4c627064625d -import NFGv3 from 0x3e5b4c627064625d -import Dandy from 0x35717efbbce11c74 - -transaction() { - prepare(account: AuthAccount) { - - // Dandy - let DandyRef= account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) - if DandyRef == nil { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Dandy.CollectionPublicPath) - if !DandyCap.check() { - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Dandy.CollectionPrivatePath) - if !DandyProviderCap.check() { - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - // NFGv3 - let NFGv3Ref= account.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) - if NFGv3Ref == nil { - account.save<@NonFungibleToken.Collection>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPublicPath) - if !NFGv3Cap.check() { - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPrivatePath) - if !NFGv3ProviderCap.check() { - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - // Party Favorz - let PartyFavorzRef= account.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) - if PartyFavorzRef == nil { - account.save<@NonFungibleToken.Collection>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPublicPath) - if !PartyFavorzCap.check() { - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) - if !PartyFavorzProviderCap.check() { - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - // Name Voucher - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - // Wearables - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) - if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) - if !wearablesCap.check() { - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) - if !wearablesProviderCap.check() { - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - } -} diff --git a/dapper-tx/testnet/initWearables.cdc b/dapper-tx/testnet/initWearables.cdc deleted file mode 100644 index 6433962e..00000000 --- a/dapper-tx/testnet/initWearables.cdc +++ /dev/null @@ -1,43 +0,0 @@ -import Wearables from 0x1c5033ad60821c97 -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 - -transaction() { - prepare(account: AuthAccount) { - - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) - if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - return - } - - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) - if !wearablesCap.check() { - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) - if !wearablesProviderCap.check() { - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - } -} diff --git a/dapper-tx/testnet/listLeaseForSale.cdc b/dapper-tx/testnet/listLeaseForSale.cdc deleted file mode 100644 index d0b1ef6b..00000000 --- a/dapper-tx/testnet/listLeaseForSale.cdc +++ /dev/null @@ -1,50 +0,0 @@ -import FindMarket from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 -import FTRegistry from 0x35717efbbce11c74 -import FindLeaseMarketSale from 0x35717efbbce11c74 -import FindLeaseMarket from 0x35717efbbce11c74 - -transaction(leaseName: String, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - - let saleItems : &FindLeaseMarketSale.SaleItemCollection? - let pointer : FindLeaseMarket.AuthLeasePointer - let vaultType : Type - - prepare(account: AuthAccount) { - - // Get the salesItemRef from tenant - let leaseMarketplace = FindMarket.getFindTenantAddress() - let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseSaleItemType= Type<@FindLeaseMarketSale.SaleItemCollection>() - let leasePublicPath=leaseTenant.getPublicPath(leaseSaleItemType) - let leaseStoragePath= leaseTenant.getStoragePath(leaseSaleItemType) - let leaseSaleItemCap= account.getCapability<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath) - if !leaseSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketSale.SaleItemCollection>(<- FindLeaseMarketSale.createEmptySaleItemCollection(leaseTenantCapability), to: leaseStoragePath) - account.link<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath, target: leaseStoragePath) - } - - self.saleItems= account.borrow<&FindLeaseMarketSale.SaleItemCollection>(from: leaseStoragePath)! - - // Get supported NFT and FT Information from Registries from input alias - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - self.vaultType= ft.type - - let ref=account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath)! - - self.pointer= FindLeaseMarket.AuthLeasePointer(ref: ref, name: leaseName) - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) - - } - -} diff --git a/dapper-tx/testnet/listNFTForSale.cdc b/dapper-tx/testnet/listNFTForSale.cdc deleted file mode 100644 index dd53ac06..00000000 --- a/dapper-tx/testnet/listNFTForSale.cdc +++ /dev/null @@ -1,78 +0,0 @@ -import FindMarket from 0x35717efbbce11c74 -import FindMarketSale from 0x35717efbbce11c74 -import FINDNFTCatalog from 0x35717efbbce11c74 -import FTRegistry from 0x35717efbbce11c74 -import FindViews from 0x35717efbbce11c74 -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 -import FlowUtilityToken from 0x82ec283f88a62e65 -import TokenForwarding from 0x51ea0e37c27a1f1a -import FungibleToken from 0x9a0766d93b6608b7 - -transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - - let saleItems : &FindMarketSale.SaleItemCollection? - let pointer : FindViews.AuthNFTPointer - let vaultType : Type - - prepare(account: AuthAccount) { - - let marketplace = FindMarket.getFindTenantAddress() - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - - let tenant = tenantCapability.borrow()! - - //TODO:how do we fix this on testnet/mainnet - let dapper=getAccount(FindViews.getDapperAddress()) - - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) - - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - - // Get supported NFT and FT Information from Registries from input alias - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData - - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - - let futReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - if ft.type == Type<@FlowUtilityToken.Vault>() && !futReceiver.check() { - // Create a new Forwarder resource for FUT and store it in the new account's storage - let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapper.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver)) - account.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) - // Publish a Receiver capability for the new account, which is linked to the FUT Forwarder - account.link<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver,target: /storage/flowUtilityTokenReceiver) - } - - - let providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) - - if !providerCap.check() { - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft.privatePath, - target: nft.storagePath - ) - } - // Get the salesItemRef from tenant - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) - self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) - self.vaultType= ft.type - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) - - } -} diff --git a/dapper-tx/testnet/moveNameTo.cdc b/dapper-tx/testnet/moveNameTo.cdc deleted file mode 100644 index ea098771..00000000 --- a/dapper-tx/testnet/moveNameTo.cdc +++ /dev/null @@ -1,31 +0,0 @@ -import Profile from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 - - -transaction(name: String, receiver:String) { - - - let receiverAddress:Address? - let sender : &FIND.LeaseCollection - - prepare(acct: AuthAccount) { - self.sender= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("You do not have a profile set up, initialize the user first") - self.receiverAddress=FIND.resolve(receiver) - } - - pre{ - self.receiverAddress != nil : "The input pass in is not a valid name or address. Input : ".concat(receiver) - } - - execute { - let receiver=getAccount(self.receiverAddress!) - let receiverLease = receiver.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - let receiverProfile = receiver.getCapability<&{Profile.Public}>(Profile.publicPath) - - if !receiverLease.check() || !receiverProfile.check() { - panic("Not a valid FIND user") - } - - self.sender.move(name:name, profile:receiverProfile, to: receiverLease) - } -} diff --git a/dapper-tx/testnet/publishFindThought.cdc b/dapper-tx/testnet/publishFindThought.cdc deleted file mode 100644 index 8e251e27..00000000 --- a/dapper-tx/testnet/publishFindThought.cdc +++ /dev/null @@ -1,50 +0,0 @@ -import MetadataViews from 0x631e88ae7f1d7c20 -import FindThoughts from 0x35717efbbce11c74 -import FINDNFTCatalog from 0x35717efbbce11c74 -import FindViews from 0x35717efbbce11c74 -import FindUtils from 0x35717efbbce11c74 - -transaction(header: String , body: String , tags: [String], mediaHash: String?, mediaType: String?, quoteNFTOwner: Address?, quoteNFTType: String?, quoteNFTId: UInt64?, quoteCreator: Address?, quoteId: UInt64?) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - let thoughtsCap= account.getCapability<&{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath) - if !thoughtsCap.check() { - account.save(<- FindThoughts.createEmptyCollection(), to: FindThoughts.CollectionStoragePath) - account.link<&FindThoughts.Collection{FindThoughts.CollectionPublic , MetadataViews.ResolverCollection}>( - FindThoughts.CollectionPublicPath, - target: FindThoughts.CollectionStoragePath - ) - } - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - - var media : MetadataViews.Media? = nil - if mediaHash != nil { - var file : {MetadataViews.File}? = nil - if FindUtils.hasPrefix(mediaHash!, prefix: "ipfs://") { - file = MetadataViews.IPFSFile(cid: mediaHash!.slice(from: "ipfs://".length , upTo: mediaHash!.length), path: nil) - } else { - file = MetadataViews.HTTPFile(url: mediaHash!) - } - media = MetadataViews.Media(file: file!, mediaType: mediaType!) - } - - var nftPointer : FindViews.ViewReadPointer? = nil - if quoteNFTOwner != nil { - let path = FINDNFTCatalog.getCollectionDataForType(nftTypeIdentifier: quoteNFTType!)?.publicPath ?? panic("This nft type is not supported by NFT Catalog. Type : ".concat(quoteNFTType!)) - let cap = getAccount(quoteNFTOwner!).getCapability<&{MetadataViews.ResolverCollection}>(path) - nftPointer = FindViews.ViewReadPointer(cap: cap, id: quoteNFTId!) - } - - var quote : FindThoughts.ThoughtPointer? = nil - if quoteCreator != nil { - quote = FindThoughts.ThoughtPointer(creator: quoteCreator!, id: quoteId!) - } - - self.collection.publish(header: header, body: body, tags: tags, media: media, nftPointer: nftPointer, quote: quote) - } -} diff --git a/dapper-tx/testnet/reactToFindThoughts.cdc b/dapper-tx/testnet/reactToFindThoughts.cdc deleted file mode 100644 index add57846..00000000 --- a/dapper-tx/testnet/reactToFindThoughts.cdc +++ /dev/null @@ -1,32 +0,0 @@ -import MetadataViews from 0x631e88ae7f1d7c20 -import FindThoughts from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 - -transaction(users: [String], ids: [UInt64] , reactions: [String], undoReactionUsers: [String], undoReactionIds: [UInt64]) { - - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - let thoughtsCap= account.getCapability<&{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath) - if !thoughtsCap.check() { - account.save(<- FindThoughts.createEmptyCollection(), to: FindThoughts.CollectionStoragePath) - account.link<&FindThoughts.Collection{FindThoughts.CollectionPublic , MetadataViews.ResolverCollection}>( - FindThoughts.CollectionPublicPath, - target: FindThoughts.CollectionStoragePath - ) - } - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - for i, user in users { - let address = FIND.resolve(user) ?? panic("Cannot resolve user : ".concat(user)) - self.collection.react(user: address, id: ids[i], reaction: reactions[i]) - } - - for i, user in undoReactionUsers { - let address = FIND.resolve(user) ?? panic("Cannot resolve user : ".concat(user)) - self.collection.react(user: address, id: undoReactionIds[i], reaction: nil) - } - } -} diff --git a/dapper-tx/testnet/redeemAllLostAndFoundNFTs.cdc b/dapper-tx/testnet/redeemAllLostAndFoundNFTs.cdc deleted file mode 100644 index 8130f254..00000000 --- a/dapper-tx/testnet/redeemAllLostAndFoundNFTs.cdc +++ /dev/null @@ -1,251 +0,0 @@ -import FindLostAndFoundWrapper from 0x35717efbbce11c74 -import LostAndFound from 0xbe4635353f55bbd4 -import FINDNFTCatalog from 0x35717efbbce11c74 -import NFTCatalog from 0x324c34e1c517e4db -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 -import FIND from 0x35717efbbce11c74 -import Dandy from 0x35717efbbce11c74 -import NFGv3 from 0x3e5b4c627064625d -import PartyFavorz from 0x3e5b4c627064625d -import NameVoucher from 0x35717efbbce11c74 -import Wearables from 0x1c5033ad60821c97 -import FindPack from 0x35717efbbce11c74 - -//IMPORT - -transaction() { - - let ids : {String : [UInt64]} - let nftInfos : {String : NFTCatalog.NFTCollectionData} - let receiverAddress : Address - - prepare(account: AuthAccount){ - - //LINK - // Dandy - let DandyRef= account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) - if DandyRef == nil { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPublicPath) - if !DandyCap.check() { - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPrivatePath) - if !DandyProviderCap.check() { - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - //findPack - let FindPackRef= account.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath) - if FindPackRef == nil { - account.save<@NonFungibleToken.Collection>(<- FindPack.createEmptyCollection(), to: FindPack.CollectionStoragePath) - account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPublicPath, - target: FindPack.CollectionStoragePath - ) - account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPrivatePath, - target: FindPack.CollectionStoragePath - ) - } - - let FindPackCap= account.getCapability<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPublicPath) - if !FindPackCap.check() { - account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPublicPath, - target: FindPack.CollectionStoragePath - ) - } - - let FindPackProviderCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPrivatePath) - if !FindPackProviderCap.check() { - account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPrivatePath, - target: FindPack.CollectionStoragePath - ) - } - - // NFGv3 - let NFGv3Ref= account.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) - if NFGv3Ref == nil { - account.save<@NonFungibleToken.Collection>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPublicPath) - if !NFGv3Cap.check() { - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPrivatePath) - if !NFGv3ProviderCap.check() { - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - // Party Favorz - let PartyFavorzRef= account.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) - if PartyFavorzRef == nil { - account.save<@NonFungibleToken.Collection>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPublicPath) - if !PartyFavorzCap.check() { - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) - if !PartyFavorzProviderCap.check() { - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - // Name Voucher - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - // Wearables - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) - if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) - if !wearablesCap.check() { - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) - if !wearablesProviderCap.check() { - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - self.nftInfos = {} - self.ids = FindLostAndFoundWrapper.getTicketIDs(user: account.address, specificType: Type<@NonFungibleToken.NFT>()) - - for type in self.ids.keys{ - if self.nftInfos[type] == nil { - let collections = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: type) ?? panic("NFT type is not supported at the moment. Type : ".concat(type)) - self.nftInfos[type] = FINDNFTCatalog.getCatalogEntry(collectionIdentifier: collections.keys[0])!.collectionData - } - } - - self.receiverAddress = account.address - } - - execute{ - for type in self.ids.keys{ - let path = self.nftInfos[type]!.publicPath - for id in self.ids[type]! { - FindLostAndFoundWrapper.redeemNFT(type: CompositeType(type)!, ticketID: id, receiverAddress: self.receiverAddress, collectionPublicPath: path) - } - } - } -} diff --git a/dapper-tx/testnet/redeemLostAndFoundNFTs.cdc b/dapper-tx/testnet/redeemLostAndFoundNFTs.cdc deleted file mode 100644 index 5637bef6..00000000 --- a/dapper-tx/testnet/redeemLostAndFoundNFTs.cdc +++ /dev/null @@ -1,252 +0,0 @@ -import FindLostAndFoundWrapper from 0x35717efbbce11c74 -import LostAndFound from 0xbe4635353f55bbd4 -import FINDNFTCatalog from 0x35717efbbce11c74 -import NFTCatalog from 0x324c34e1c517e4db -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 -import FindViews from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 -import Dandy from 0x35717efbbce11c74 -import NFGv3 from 0x3e5b4c627064625d -import PartyFavorz from 0x3e5b4c627064625d -import NameVoucher from 0x35717efbbce11c74 -import Wearables from 0x1c5033ad60821c97 -import FindPack from 0x35717efbbce11c74 - -//IMPORT - -transaction(ids: {String : [UInt64]}) { - - let nftInfos : {String : NFTCatalog.NFTCollectionData} - let receiverAddress : Address - - prepare(account: AuthAccount){ - - //LINK - // Dandy - let DandyRef= account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) - if DandyRef == nil { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPublicPath) - if !DandyCap.check() { - account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - } - - let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPrivatePath) - if !DandyProviderCap.check() { - account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - - //findPack - let FindPackRef= account.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath) - if FindPackRef == nil { - account.save<@NonFungibleToken.Collection>(<- FindPack.createEmptyCollection(), to: FindPack.CollectionStoragePath) - account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPublicPath, - target: FindPack.CollectionStoragePath - ) - account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPrivatePath, - target: FindPack.CollectionStoragePath - ) - } - - let FindPackCap= account.getCapability<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPublicPath) - if !FindPackCap.check() { - account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPublicPath, - target: FindPack.CollectionStoragePath - ) - } - - let FindPackProviderCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPrivatePath) - if !FindPackProviderCap.check() { - account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - FindPack.CollectionPrivatePath, - target: FindPack.CollectionStoragePath - ) - } - - - // NFGv3 - let NFGv3Ref= account.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) - if NFGv3Ref == nil { - account.save<@NonFungibleToken.Collection>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPublicPath) - if !NFGv3Cap.check() { - account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPublicPath, - target: NFGv3.CollectionStoragePath - ) - } - - let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPrivatePath) - if !NFGv3ProviderCap.check() { - account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NFGv3.CollectionPrivatePath, - target: NFGv3.CollectionStoragePath - ) - } - - // Party Favorz - let PartyFavorzRef= account.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) - if PartyFavorzRef == nil { - account.save<@NonFungibleToken.Collection>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPublicPath) - if !PartyFavorzCap.check() { - account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPublicPath, - target: PartyFavorz.CollectionStoragePath - ) - } - - let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) - if !PartyFavorzProviderCap.check() { - account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - PartyFavorz.CollectionPrivatePath, - target: PartyFavorz.CollectionStoragePath - ) - } - - // Name Voucher - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - // Wearables - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) - if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) - if !wearablesCap.check() { - account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPublicPath, - target: Wearables.CollectionStoragePath - ) - } - - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) - if !wearablesProviderCap.check() { - account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Wearables.CollectionPrivatePath, - target: Wearables.CollectionStoragePath - ) - } - - self.nftInfos = {} - - for type in ids.keys{ - if self.nftInfos[type] == nil { - let collections = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: type) ?? panic("NFT type is not supported at the moment. Type : ".concat(type)) - self.nftInfos[type] = FINDNFTCatalog.getCatalogEntry(collectionIdentifier: collections.keys[0])!.collectionData - } - } - - self.receiverAddress = account.address - } - - execute{ - for type in ids.keys{ - let path = self.nftInfos[type]!.publicPath - for id in ids[type]! { - FindLostAndFoundWrapper.redeemNFT(type: CompositeType(type)!, ticketID: id, receiverAddress:self.receiverAddress, collectionPublicPath: path) - } - } - } -} diff --git a/dapper-tx/testnet/redeemNameVoucher.cdc b/dapper-tx/testnet/redeemNameVoucher.cdc deleted file mode 100644 index de41f43e..00000000 --- a/dapper-tx/testnet/redeemNameVoucher.cdc +++ /dev/null @@ -1,74 +0,0 @@ -import NameVoucher from 0x35717efbbce11c74 -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 -import LostAndFound from 0xbe4635353f55bbd4 -import FindLostAndFoundWrapper from 0x35717efbbce11c74 - -transaction(id: UInt64, name: String) { - - var collection : &NameVoucher.Collection - let addr : Address - - prepare(account:AuthAccount) { - - var nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - } - - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - self.collection = nameVoucherRef! - self.addr = account.address - } - - execute{ - // check if it is there in collection - if self.collection.contains(id) { - self.collection.redeem(id: id, name: name) - return - } - - // check if it is there on L&F - let tickets = LostAndFound.borrowAllTicketsByType(addr: self.addr, type: Type<@NameVoucher.NFT>()) - for ticket in tickets { - if ticket.uuid == id { - let tokenId = ticket.getNonFungibleTokenID()! - FindLostAndFoundWrapper.redeemNFT(type: Type<@NameVoucher.NFT>(), ticketID: id, receiverAddress: self.addr, collectionPublicPath: NameVoucher.CollectionPublicPath) - - self.collection.redeem(id: tokenId, name: name) - return - } - } - - panic("There is no ID or Ticket ID : ".concat(id.toString())) - } - -} diff --git a/dapper-tx/testnet/register.cdc b/dapper-tx/testnet/register.cdc deleted file mode 100644 index 966c5be7..00000000 --- a/dapper-tx/testnet/register.cdc +++ /dev/null @@ -1,33 +0,0 @@ -import DapperUtilityCoin from 0x82ec283f88a62e65 -import FIND from 0x35717efbbce11c74 - -transaction(merchAccount: Address, name: String, amount: UFix64) { - - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault - let balanceBeforeTransfer: UFix64 - let price : UFix64 - - prepare(dapper: AuthAccount, account: AuthAccount) { - - self.price=FIND.calculateCost(name) - log("The cost for registering this name is ".concat(self.price.toString())) - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) - self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") - } - - pre{ - merchAccount == 0x4748780c8bf65e19 : "Merchant account is not .find" - self.price == amount : "Calculated cost : ".concat(self.price.toString()).concat(" does not match expected cost : ").concat(amount.toString()) - } - - execute{ - let payVault <- self.mainDapperUtilityCoinVault.withdraw(amount: self.price) as! @DapperUtilityCoin.Vault - self.finLeases.registerDapper(merchAccount: merchAccount, name: name, vault: <- payVault) - } - - post { - self.mainDapperUtilityCoinVault.balance == self.balanceBeforeTransfer: "DapperUtilityCoin leakage" - } -} diff --git a/dapper-tx/testnet/removeRelatedAccount.cdc b/dapper-tx/testnet/removeRelatedAccount.cdc deleted file mode 100644 index b9e36347..00000000 --- a/dapper-tx/testnet/removeRelatedAccount.cdc +++ /dev/null @@ -1,28 +0,0 @@ -import FindRelatedAccounts from 0x35717efbbce11c74 - -transaction(name: String, network: String, address: String){ - - var relatedAccounts : &FindRelatedAccounts.Accounts? - - prepare(account: AuthAccount) { - - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - if self.relatedAccounts == nil { - let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - } - - let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) - if !cap.check() { - account.unlink(FindRelatedAccounts.publicPath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - } - - } - - execute{ - self.relatedAccounts!.removeRelatedAccount(name: name, network: network, address: address) - } -} diff --git a/dapper-tx/testnet/renewName.cdc b/dapper-tx/testnet/renewName.cdc deleted file mode 100644 index 519b6787..00000000 --- a/dapper-tx/testnet/renewName.cdc +++ /dev/null @@ -1,32 +0,0 @@ -import DapperUtilityCoin from 0x82ec283f88a62e65 -import FIND from 0x35717efbbce11c74 - -transaction(merchAccount: Address, name: String, amount: UFix64) { - - let price : UFix64 - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault - let balanceBeforeTransfer: UFix64 - - prepare(dapper: AuthAccount, acct: AuthAccount) { - self.price=FIND.calculateCost(name) - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) - self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance - self.finLeases= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") - } - - pre{ - merchAccount == 0x4748780c8bf65e19 : "Merchant account is not .find" - self.price == amount : "expected renew cost : ".concat(self.price.toString()).concat(" is not the same as calculated renew cost : ").concat(amount.toString()) - } - - execute{ - let payVault <- self.mainDapperUtilityCoinVault.withdraw(amount: self.price) as! @DapperUtilityCoin.Vault - let finToken= self.finLeases.borrow(name) - finToken.extendLeaseDapper(merchAccount: merchAccount, vault: <- payVault) - } - - post { - self.mainDapperUtilityCoinVault.balance == self.balanceBeforeTransfer: "DapperUtilityCoin leakage" - } -} diff --git a/dapper-tx/testnet/sendNFTs.cdc b/dapper-tx/testnet/sendNFTs.cdc deleted file mode 100644 index 9824dc39..00000000 --- a/dapper-tx/testnet/sendNFTs.cdc +++ /dev/null @@ -1,200 +0,0 @@ -import NonFungibleToken from 0x631e88ae7f1d7c20 -import FungibleToken from 0x9a0766d93b6608b7 -import FlowStorageFees from 0x8c5303eaa26202d6 -import FlowToken from 0x7e60df042a9c0868 -import MetadataViews from 0x631e88ae7f1d7c20 -import NFTCatalog from 0x324c34e1c517e4db -import FINDNFTCatalog from 0x35717efbbce11c74 -import FindViews from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 -import FindAirdropper from 0x35717efbbce11c74 -import FTRegistry from 0x35717efbbce11c74 -import Profile from 0x35717efbbce11c74 -import Sender from 0x35717efbbce11c74 - -transaction(nftIdentifiers: [String], allReceivers: [String] , ids:[UInt64], memos: [String], donationTypes: [String?], donationAmounts: [UFix64?], findDonationType: String?, findDonationAmount: UFix64?) { - - let authPointers : [FindViews.AuthNFTPointer] - let paths : [PublicPath] - let flowVault : &FungibleToken.Vault - let flowTokenRepayment : Capability<&FlowToken.Vault{FungibleToken.Receiver}> - let defaultTokenAvailableBalance : UFix64 - - let royalties: [MetadataViews.Royalties?] - let totalRoyalties: [UFix64] - let vaultRefs: {String : &FungibleToken.Vault} - var token : &Sender.Token - - prepare(account : AuthAccount) { - - self.authPointers = [] - self.paths = [] - self.royalties = [] - self.totalRoyalties = [] - self.vaultRefs = {} - - - let contractData : {Type : NFTCatalog.NFTCatalogMetadata} = {} - - - for i , typeIdentifier in nftIdentifiers { - let type = CompositeType(typeIdentifier) ?? panic("Cannot refer to type with identifier : ".concat(typeIdentifier)) - - var data : NFTCatalog.NFTCatalogMetadata? = contractData[type] - if data == nil { - data = FINDNFTCatalog.getMetadataFromType(type) ?? panic("NFT Type is not supported by NFT Catalog. Type : ".concat(type.identifier)) - contractData[type] = data - } - - let path = data!.collectionData - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(path.privatePath) - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - path.privatePath, - target: path.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = path.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: path.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: ids[i]) - - if let dt = donationTypes[i] { - self.royalties.append(pointer.getRoyalty()) - self.totalRoyalties.append(pointer.getTotalRoyaltiesCut()) - - // get the vault for donation - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - - } else { - self.royalties.append(nil) - self.totalRoyalties.append(0.0) - } - - self.authPointers.append(pointer) - self.paths.append(path.publicPath) - } - - self.flowVault = account.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) ?? panic("Cannot borrow reference to sender's flow vault") - self.flowTokenRepayment = account.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) - self.defaultTokenAvailableBalance = FlowStorageFees.defaultTokenAvailableBalance(account.address) - - // get the vault for find donation - if let dt = findDonationType { - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - } - - if account.borrow<&Sender.Token>(from: Sender.storagePath) == nil { - account.save(<- Sender.create(), to: Sender.storagePath) - } - - self.token =account.borrow<&Sender.Token>(from: Sender.storagePath)! - - } - - execute { - let addresses : {String : Address} = {} - let estimatedStorageFee = 0.0002 * UFix64(self.authPointers.length) - // we pass in the least amount as possible for storage fee here - let tempVault <- self.flowVault.withdraw(amount: 0.0) - var vaultRef = &tempVault as &FungibleToken.Vault - if self.defaultTokenAvailableBalance <= estimatedStorageFee { - vaultRef = self.flowVault as &FungibleToken.Vault - } else { - tempVault.deposit(from: <- self.flowVault.withdraw(amount: estimatedStorageFee)) - } - - let ctx : {String : String} = { - "tenant" : "find" - } - - for i, pointer in self.authPointers { - let receiver = allReceivers[i] - let id = ids[i] - ctx["message"] = memos[i] - let path = self.paths[i] - - var user = addresses[receiver] - if user == nil { - user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) - addresses[receiver] = user - } - - // airdrop thru airdropper - FindAirdropper.forcedAirdrop(pointer: pointer, receiver: user!, path: path, context: ctx, storagePayment: vaultRef, flowTokenRepayment: self.flowTokenRepayment, deepValidation: true) - } - self.flowVault.deposit(from: <- tempVault) - - // This is hard coded for spliting at the front end for now. So if there are no royalties, all goes to find - // AND This does not support different ft types for now. - var goesToFindFund = 0.0 - for i , type in donationTypes { - if type == nil { - continue - } - let amount = donationAmounts[i]! - let royalties = self.royalties[i]! - let totalRoyalties = self.totalRoyalties[i] - let vaultRef = self.vaultRefs[type!]! - var noRoyalty = false - if totalRoyalties == 0.0 { - goesToFindFund = goesToFindFund + amount - continue - } - - let balance = vaultRef.balance - var totalPaid = 0.0 - - for j, r in royalties.getRoyalties() { - var cap : Capability<&{FungibleToken.Receiver}> = r.receiver - if !r.receiver.check(){ - // try to grab from profile - if let ref = getAccount(r.receiver.address).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() { - if ref.hasWallet(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - } else if let ftInfo = FTRegistry.getFTInfo(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(ftInfo.receiverPath) - } - } - - } - - if cap.check() { - let individualAmount = r.cut / totalRoyalties * amount - let vault <- vaultRef.withdraw(amount: individualAmount) - cap.borrow()!.deposit(from: <- vault) - - totalPaid = totalPaid + individualAmount - } - } - - assert(totalPaid <= amount, message: "Amount paid is greater than expected" ) - - } - - // for donating to find - if findDonationType != nil { - vaultRef = self.vaultRefs[findDonationType!]! - let vault <- vaultRef.withdraw(amount: findDonationAmount! + goesToFindFund) - FIND.depositWithTagAndMessage(to: "find", message: "donation to .find", tag: "donation", vault: <- vault, from: self.token) - } - } -} diff --git a/dapper-tx/testnet/sendWearables.cdc b/dapper-tx/testnet/sendWearables.cdc deleted file mode 100644 index 986101f0..00000000 --- a/dapper-tx/testnet/sendWearables.cdc +++ /dev/null @@ -1,68 +0,0 @@ -import NonFungibleToken from 0x631e88ae7f1d7c20 -import MetadataViews from 0x631e88ae7f1d7c20 -import FindViews from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 -import FindAirdropper from 0x35717efbbce11c74 -import Wearables from 0x1c5033ad60821c97 - -transaction(allReceivers: [String] , ids:[UInt64], memos: [String]) { - - let authPointers : [FindViews.AuthNFTPointer] - - prepare(account : AuthAccount) { - - self.authPointers = [] - let privatePath = Wearables.CollectionPrivatePath - let storagePath = Wearables.CollectionStoragePath - - for id in ids { - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(privatePath) - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - privatePath, - target: storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: id) - - self.authPointers.append(pointer) - } - - } - - execute { - let addresses : {String : Address} = {} - let publicPath = Wearables.CollectionPublicPath - - let ctx : {String : String} = { - "tenant" : "find" - } - - for i, pointer in self.authPointers { - let receiver = allReceivers[i] - let id = ids[i] - ctx["message"] = memos[i] - - var user = addresses[receiver] - if user == nil { - user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) - addresses[receiver] = user - } - - // airdrop thru airdropper - FindAirdropper.safeAirdrop(pointer: pointer, receiver: user!, path: publicPath, context: ctx, deepValidation: true) - } - - } -} diff --git a/dapper-tx/testnet/setMainName.cdc b/dapper-tx/testnet/setMainName.cdc deleted file mode 100644 index 5a4bc07f..00000000 --- a/dapper-tx/testnet/setMainName.cdc +++ /dev/null @@ -1,23 +0,0 @@ -import Profile from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 - - -transaction(name: String) { - - let leaseCollectionOwner : Capability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}> - let profile : &Profile.User - - prepare(acct: AuthAccount) { - self.leaseCollectionOwner = acct.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath)! - } - - pre{ - self.leaseCollectionOwner.check() : "Not a find user" - self.leaseCollectionOwner.borrow()!.getLease(name) != nil : "You do not own this lease so you cannot set it as main name" - } - - execute{ - self.profile.setFindName(name) - } -} diff --git a/dapper-tx/testnet/setPrivateMode.cdc b/dapper-tx/testnet/setPrivateMode.cdc deleted file mode 100644 index aa4cc062..00000000 --- a/dapper-tx/testnet/setPrivateMode.cdc +++ /dev/null @@ -1,19 +0,0 @@ -import Profile from 0x35717efbbce11c74 - -transaction(mode: Bool) { - - let profile : &Profile.User? - - prepare(acct: AuthAccount) { - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath) - } - - pre{ - self.profile != nil : "Cannot borrow reference to profile" - } - - execute{ - self.profile!.setPrivateMode(mode) - self.profile!.emitUpdatedEvent() - } -} diff --git a/dapper-tx/testnet/setProfile.cdc b/dapper-tx/testnet/setProfile.cdc deleted file mode 100644 index 9f71976e..00000000 --- a/dapper-tx/testnet/setProfile.cdc +++ /dev/null @@ -1,19 +0,0 @@ -import Profile from 0x35717efbbce11c74 - -transaction(avatar: String) { - - let profile : &Profile.User? - - prepare(acct: AuthAccount) { - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath) - } - - pre{ - self.profile != nil : "Cannot borrow reference to profile" - } - - execute{ - self.profile!.setAvatar(avatar) - self.profile!.emitUpdatedEvent() - } -} diff --git a/dapper-tx/testnet/setRelatedAccount.cdc b/dapper-tx/testnet/setRelatedAccount.cdc deleted file mode 100644 index 762c930f..00000000 --- a/dapper-tx/testnet/setRelatedAccount.cdc +++ /dev/null @@ -1,36 +0,0 @@ -import FindRelatedAccounts from 0x35717efbbce11c74 -import FIND from 0x35717efbbce11c74 - -transaction(name: String, target: String) { - - var relatedAccounts : &FindRelatedAccounts.Accounts? - let address : Address? - - prepare(account: AuthAccount) { - - - self.address = FIND.resolve(target) - - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - if self.relatedAccounts == nil { - let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - } - - let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) - if !cap.check() { - account.unlink(FindRelatedAccounts.publicPath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - } - } - - pre{ - self.address != nil : "The input pass in is not a valid name or address. Input : ".concat(target) - } - - execute{ - self.relatedAccounts!.addFlowAccount(name: name, address: self.address!) - } -} diff --git a/developing.md b/developing.md index 44e8bd27..09354680 100644 --- a/developing.md +++ b/developing.md @@ -123,13 +123,13 @@ go run tasks/demo/main.go ``` ## Integrating between frontend and backend -.find uses a feature in [overflow](https://github.com/bjartek/overflow) to convert the transactions/scripts in this repo into a json file that is then published to npm. +.find uses a feature in [overflow](https://github.com/bjartek/overflow) to convert the transactions/scripts in this repo into a json file that is then access(all)lished to npm. This flow will be integrated into CI but right now it works like this - `make client` will run the logic to generate the file lib/find.json - `make minor|patch|major` will bump the semantic version of the lib/package.json file - - `make publish` will publish this file to NPM + - `make access(all)lish` will access(all)lish this file to NPM In the frontend code this module is then used as an [NPM import](https://github.com/findonflow/find-web/blob/master/src/functions/txfunctions.js#L3) and used with FCL in a transaction [like this](https://github.com/findonflow/find-web/blob/master/src/functions/txfunctions.js#L13) diff --git a/entitlement_test.go b/entitlement_test.go new file mode 100644 index 00000000..a8fd7186 --- /dev/null +++ b/entitlement_test.go @@ -0,0 +1,23 @@ +package test_main + +import ( + "testing" + + . "github.com/bjartek/overflow/v2" +) + +/* +Tests must be in the same folder as flow.json with contracts and transactions/scripts in subdirectories in order for the path resolver to work correctly +*/ +func TestEntitlments(t *testing.T) { + otu := &OverflowTestUtils{T: t, O: ot.O} + + ot.Run(t, "Should not be able to change the name of another user", func(t *testing.T) { + res := otu.O.Tx("devsetProfileNameError", + WithSigner("user2"), + WithArg("address", "user1"), + WithArg("newName", "badUser"), + ) + res.AssertFailure(t, "function requires `Admin` authorization, but reference is unauthorized") + }) +} diff --git a/findGo/setup.go b/findGo/setup.go index dcdd2d08..a5343178 100644 --- a/findGo/setup.go +++ b/findGo/setup.go @@ -3,7 +3,7 @@ package findGo import ( "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/stretchr/testify/assert" ) diff --git a/findGo/struct.go b/findGo/struct.go index c3364552..28dea8ec 100644 --- a/findGo/struct.go +++ b/findGo/struct.go @@ -1,7 +1,7 @@ package findGo import ( - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" ) type FindMarketCutStruct_ThresholdCut struct { @@ -58,26 +58,32 @@ type FindVerifier_HasOneFLOAT struct { } type GeneratedExperiences_CollectionInfo struct { - Season uint64 `json:"season"` - Royalties []interface{} `json:"royalties"` - RoyaltiesInput []FindPack_Royalty `json:"royaltiesInput"` - SquareImage MetadataViews_Media_IPFS `json:"squareImage"` - BannerImage MetadataViews_Media_IPFS `json:"bannerImage"` - Description string `json:"description"` - Socials map[string]string `json:"socials"` - Extra map[string]interface{} `json:"extra"` + Season uint64 `json:"season"` + Royalties []interface{} `json:"royalties"` + RoyaltiesInput []FindPack_Royalty `json:"royaltiesInput"` + SquareImage MetadataViews_Media_IPFS `json:"squareImage"` + BannerImage MetadataViews_Media_IPFS `json:"bannerImage"` + Description string `json:"description"` + Socials map[string]string `json:"socials"` + Extra map[string]interface{} `json:"extra"` } type GeneratedExperiences_Info struct { - Season uint64 `json:"season"` - Name string `json:"name"` - Description string `json:"description"` - Thumbnail MetadataViews_IPFSFile `json:"thumbnail"` - Fullsize MetadataViews_IPFSFile `json:"fullsize"` - Edition uint64 `json:"edition"` - MaxEdition uint64 `json:"maxEdition"` - Artist string `json:"artist"` - Rarity string `json:"rarity"` - Extra map[string]interface{} `json:"extra"` + Season uint64 `json:"season"` + Name string `json:"name"` + Description string `json:"description"` + Thumbnail MetadataViews_IPFSFile `json:"thumbnail"` + Fullsize MetadataViews_IPFSFile `json:"fullsize"` + Edition uint64 `json:"edition"` + MaxEdition uint64 `json:"maxEdition"` + Artist string `json:"artist"` + Rarity string `json:"rarity"` + Extra map[string]interface{} `json:"extra"` +} +type FindPack_AirdropInfo struct { + PackTypeName string `cadence:"packTypeName"` + PackTypeId uint64 `cadence:"packTypeId"` + Users []string + Message string } diff --git a/find_airdropper_test.go b/find_airdropper_test.go index bc931ff6..8437681f 100644 --- a/find_airdropper_test.go +++ b/find_airdropper_test.go @@ -1,469 +1,203 @@ package test_main import ( - "fmt" "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" + "github.com/findonflow/find/findGo" "github.com/hexops/autogold" "github.com/onflow/cadence" - "github.com/sanity-io/litter" "github.com/stretchr/testify/require" ) func TestFindAirdropper(t *testing.T) { + otu := &OverflowTestUtils{T: t, O: ot.O} - otu := NewOverflowTest(t). - setupFIND(). - createUser(1000.0, "user1"). - registerUser("user1"). - buyForge("user1"). - createUser(100.0, "user2"). - registerUser("user2"). - registerExampleNFTInNFTRegistry(). - registerFtInRegistry(). - setProfile("user1"). - setProfile("user2"). - registerFIND() - + id := dandyIds[0] dandyType := dandyNFTType(otu) - fusd := otu.identifier("FUSD", "Vault") - otu.mintThreeExampleDandies() - otu.registerDandyInNFTRegistry() - - t.Run("Should be able to send Airdrop", func(t *testing.T) { + flowToken := otu.identifier("FlowToken", "Vault") - ids := otu.mintThreeExampleDandies() - - res := otu.O.Tx("sendNFTsSafe", + ot.Run(t, "Should be able to send Airdrop", func(t *testing.T) { + otu.O.Tx("sendNFTsSafe", WithSigner("user1"), WithArg("allReceivers", []string{"user2", "user2", "user2"}), WithArg("nftIdentifiers", []string{dandyType, dandyType, dandyType}), - WithArg("ids", ids), + WithArg("ids", dandyIds), WithArg("memos", []string{"Message 0", "Message 1", "Message 2"}), WithArg("donationTypes", `[nil, nil, nil]`), WithArg("donationAmounts", `[nil, nil, nil]`), WithArg("findDonationType", nil), WithArg("findDonationAmount", nil), ). - AssertSuccess(t) - - for i, id := range ids { - - events := res.GetEventsWithName("FindAirdropper.Airdropped") - mockField := map[string]interface{}{} - for _, e := range events { - field, exist := e.Fields["nftInfo"].(map[string]interface{}) - if exist { - mockId := field["id"].(uint64) - if id == mockId { - field["id"] = id - field["type"] = dandyType - mockField = field - } - } - } - - res.AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ + AssertSuccess(t). + AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ "from": otu.O.Address("user1"), "fromName": "user1", "to": otu.O.Address("user2"), "toName": "user2", - "uuid": id, - "context": map[string]interface{}{ - "message": fmt.Sprintf("Message %d", i), - "tenant": "find", - }, - "nftInfo": mockField, }) - } }) - packType := "user1" - packTypeId := uint64(1) - salt := "find" - singleType := []string{exampleNFTType(otu)} - - t.Run("Should be able to send packs thru airdropper with struct", func(t *testing.T) { - - type FindPack_AirdropInfo struct { - PackTypeName string `cadence:"packTypeName"` - PackTypeId uint64 `cadence:"packTypeId"` - Users []string - Message string - } - - id1 := otu.mintExampleNFTs() - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find", "account"). - mintPack("user1", packTypeId, []uint64{id1}, singleType, salt) - - res := otu.O.Tx("sendFindPacks", + ot.Run(t, "Should be able to send packs thru airdropper with struct", func(t *testing.T) { + otu.O.Tx("sendFindPacks", WithSigner("find-admin"), - WithArg("packInfo", FindPack_AirdropInfo{ - PackTypeName: packType, - PackTypeId: packTypeId, + WithArg("packInfo", findGo.FindPack_AirdropInfo{ + PackTypeName: "user1", + PackTypeId: 1, Users: []string{"user2"}, Message: "I can use struct here", }), ). - AssertSuccess(t) + AssertSuccess(t). + AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ + "from": otu.O.Address("find"), + "toName": "user2", + "to": otu.O.Address("user2"), + "context": map[string]interface{}{ + "message": "I can use struct here", + "tenant": "find", + }, + }) + }) - events := res.GetEventsWithName("FindAirdropper.Airdropped") - mockField := map[string]interface{}{} - for _, e := range events { - field, exist := e.Fields["nftInfo"].(map[string]interface{}) - if exist { - field["type"] = otu.identifier("FindPack", "NFT") - mockField = field - } - } + ot.Run(t, "Should not be able to send Airdrop without collection, good events will be emitted", func(t *testing.T) { + user4 := otu.O.Address("user4") - res.AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ - "from": otu.O.Address("find"), - "toName": "user2", - "to": otu.O.Address("user2"), + otu.O.Tx("sendNFTsSafe", + WithSigner("user1"), + WithArg("allReceivers", []string{user4}), + WithArg("nftIdentifiers", []string{dandyType}), + WithArg("ids", []uint64{id}), + WithArg("memos", []string{"Message 0"}), + WithArg("donationTypes", `[nil]`), + WithArg("donationAmounts", `[nil]`), + WithArg("findDonationType", nil), + WithArg("findDonationAmount", nil), + ).AssertSuccess(t).AssertEvent(t, "FindAirdropper.AirdropFailed", map[string]interface{}{ + "fromName": "user1", + "from": otu.O.Address("user1"), + "to": user4, + "id": id, + "uuid": id, + "type": dandyType, "context": map[string]interface{}{ - "message": "I can use struct here", + "message": "Message 0", "tenant": "find", }, - "nftInfo": mockField, + "reason": "Invalid Receiver Capability", }) - }) - t.Run("Should be able to send Airdrop with only collection public linked", func(t *testing.T) { - - ids := otu.mintThreeExampleDandies() - otu.O.Tx("devUnlinkDandyReceiver", - WithSigner("user2"), - ). - AssertSuccess(t) + ot.Run(t, "Should be able to get Airdrop details with a script", func(t *testing.T) { + user3 := otu.O.Address("user3") - res := otu.O.Tx("sendNFTsSafe", - WithSigner("user1"), - WithArg("allReceivers", []string{"user2", "user2", "user2"}), + details := []SendNFTScript{} + err := otu.O.Script("sendNFTs", + WithArg("sender", "user1"), + WithArg("allReceivers", []string{"user1", "user2", user3}), WithArg("nftIdentifiers", []string{dandyType, dandyType, dandyType}), - WithArg("ids", ids), + WithArg("ids", dandyIds), WithArg("memos", []string{"Message 0", "Message 1", "Message 2"}), - WithArg("donationTypes", `[nil, nil, nil]`), - WithArg("donationAmounts", `[nil, nil, nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t) + ).MarshalAs(&details) - for i, id := range ids { - - events := res.GetEventsWithName("FindAirdropper.Airdropped") - mockField := map[string]interface{}{} - for _, e := range events { - field, exist := e.Fields["nftInfo"].(map[string]interface{}) - if exist { - mockId := field["id"].(uint64) - if id == mockId { - field["id"] = id - field["type"] = dandyType - mockField = field - } - } - } - - res.AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ - "fromName": "user1", - "from": otu.O.Address("user1"), - "toName": "user2", - "to": otu.O.Address("user2"), - "uuid": id, - "context": map[string]interface{}{ - "message": fmt.Sprintf("Message %d", i), - "tenant": "find", - }, - "remark": "Receiver Not Linked", - "nftInfo": mockField, - }) - } + require.NoError(t, err) + autogold.Equal(t, details) }) - t.Run("Should not be able to send Airdrop without collection, good events will be emitted", func(t *testing.T) { - - ids := otu.mintThreeExampleDandies() - user3 := otu.O.Address("user3") - - res := otu.O.Tx("sendNFTsSafe", + ot.Run(t, "Should be able to send Airdrop with sending funds to royalty holders", func(t *testing.T) { + res := otu.O.Tx("sendNFTs", WithSigner("user1"), - WithArg("allReceivers", []string{user3, user3, user3}), - WithArg("nftIdentifiers", []string{dandyType, dandyType, dandyType}), - WithArg("ids", ids), - WithArg("memos", []string{"Message 0", "Message 1", "Message 2"}), - WithArg("donationTypes", `[nil, nil, nil]`), - WithArg("donationAmounts", `[nil, nil, nil]`), + WithArg("allReceivers", []string{"user2"}), + WithArg("nftIdentifiers", []string{dandyType}), + WithArg("ids", []uint64{id}), + WithArg("memos", []string{"Message 0"}), + WithArg("donationTypes", []string{flowToken}), + WithArg("donationAmounts", []float64{10.0}), WithArg("findDonationType", nil), WithArg("findDonationAmount", nil), ). - AssertSuccess(t) - - for i, id := range ids { - - res.AssertEvent(t, "FindAirdropper.AirdropFailed", map[string]interface{}{ - "fromName": "user1", + AssertSuccess(t). + AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ "from": otu.O.Address("user1"), - "to": otu.O.Address("user3"), - "id": id, - "uuid": id, - "type": dandyType, - "context": map[string]interface{}{ - "message": fmt.Sprintf("Message %d", i), - "tenant": "find", - }, - "reason": "Invalid Receiver Capability", - }) - + "fromName": "user1", + "to": otu.O.Address("user2"), + "toName": "user2", + }).Print() + wants := []map[string]interface{}{ + { + "amount": 6.6666666, + "to": otu.O.Address("user1"), + }, + { + "amount": 3.3333333, + "to": otu.O.Address("find"), + }, } - }) - - t.Run("Should be able to get Airdrop details with a script", func(t *testing.T) { - - ids := otu.mintThreeExampleDandies() - user3 := otu.O.Address("user3") - - makeResult := func(account, cplinked bool, id, index uint64, nftInplace, ok bool, receiver, receiverAddress string, receiverlinked bool, t string, hasProfile bool) map[string]interface{} { - res := map[string]interface{}{ - "accountInitialized": account, - "address": receiverAddress, - "collectionPublicLinked": cplinked, - "id": id, - "isDapper": false, - "message": fmt.Sprintf("Message %d", index), - "nftInPlace": nftInplace, - "ok": ok, - "receiver": receiver, - "receiverLinked": receiverlinked, - "royalties": map[string]interface{}{ - "royalties": []interface{}{ - map[string]interface{}{ - "acceptTypes": []interface{}{ - otu.identifier("FlowToken", "Vault"), - otu.identifier("FUSD", "Vault"), - otu.identifier("FiatToken", "Vault"), - }, - "address": otu.O.Address("user1"), - "cut": 0.05, - "description": "creator", - "name": "user1", - }, - map[string]interface{}{ - "acceptTypes": []interface{}{ - otu.identifier("FlowToken", "Vault"), - otu.identifier("FUSD", "Vault"), - otu.identifier("FiatToken", "Vault"), - }, - "address": otu.O.Address("find"), - "cut": 0.025, - "description": "find forge", - }, - }, - "totalRoyalty": 0.075, - }, - - "type": t, - } - if hasProfile { - res["inputName"] = receiver - res["findName"] = receiver - res["avatar"] = "https://find.xyz/assets/img/avatars/avatar14.png" - } - - return res + for _, want := range wants { + res.AssertEvent(t, ".FungibleToken.Deposited", want) } - - res := otu.O.Script("sendNFTs", - WithArg("sender", "user1"), - WithArg("allReceivers", []string{"user1", "user2", user3}), - WithArg("nftIdentifiers", []string{dandyType, dandyType, dandyType}), - WithArg("ids", ids), - WithArg("memos", []string{"Message 0", "Message 1", "Message 2"}), - ) - - user1Res := makeResult(true, true, ids[0], 0, true, true, "user1", otu.O.Address("user1"), true, dandyType, true) - user2Res := makeResult(true, true, ids[1], 1, true, true, "user2", otu.O.Address("user2"), false, dandyType, true) - user3Res := makeResult(false, false, ids[2], 2, true, false, otu.O.Address("user3"), otu.O.Address("user3"), false, dandyType, false) - - res.AssertWant(t, autogold.Want("sendNFTs", litter.Sdump([]interface{}{user1Res, user2Res, user3Res}))) - }) - trxns := []string{ - "sendNFTsSafe", - "sendNFTs", - "sendNFTsSubsidize", - } - - for _, trxn := range trxns { - t.Run(fmt.Sprintf("Should be able to send Airdrop with sending funds to royalty holders %s", trxn), func(t *testing.T) { - - ids := otu.mintThreeExampleDandies() - - res := otu.O.Tx(trxn, - WithSigner("user1"), - WithArg("allReceivers", []string{"user2", "user2", "user2"}), - WithArg("nftIdentifiers", []string{dandyType, dandyType, dandyType}), - WithArg("ids", ids), - WithArg("memos", []string{"Message 0", "Message 1", "Message 2"}), - WithArg("donationTypes", fmt.Sprintf(`["%s" , nil, nil]`, fusd)), - WithArg("donationAmounts", fmt.Sprintf(`[%2f , nil, nil]`, 10.0)), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t) - - for i, id := range ids { - - events := res.GetEventsWithName("FindAirdropper.Airdropped") - mockField := map[string]interface{}{} - for _, e := range events { - field, exist := e.Fields["nftInfo"].(map[string]interface{}) - if exist { - mockId := field["id"].(uint64) - if id == mockId { - field["id"] = id - field["type"] = dandyType - mockField = field - } - } - } - - res.AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ - "fromName": "user1", - "from": otu.O.Address("user1"), - "toName": "user2", - "to": otu.O.Address("user2"), - "uuid": id, - "context": map[string]interface{}{ - "message": fmt.Sprintf("Message %d", i), - "tenant": "find", - }, - "nftInfo": mockField, - }) - - } - - wants := []map[string]interface{}{ - { - "amount": 6.6666666, - "to": otu.O.Address("user1"), - }, - { - "amount": 3.3333333, - "to": otu.O.Address("find"), - }, - } - - for _, want := range wants { - res.AssertEvent(t, "FUSD.TokensDeposited", want) - } - }) - - t.Run(fmt.Sprintf("Should be able to send Airdrop and donate funds to FIND! %s", trxn), func(t *testing.T) { - - ids := otu.mintThreeExampleDandies() - optional := cadence.NewOptional(cadence.String(fusd)) - - res := otu.O.Tx(trxn, - WithSigner("user1"), - WithArg("allReceivers", []string{"user2", "user2", "user2"}), - WithArg("nftIdentifiers", []string{dandyType, dandyType, dandyType}), - WithArg("ids", ids), - WithArg("memos", []string{"Message 0", "Message 1", "Message 2"}), - WithArg("donationTypes", `[nil, nil, nil]`), - WithArg("donationAmounts", `[nil, nil, nil]`), - WithArg("findDonationType", optional), - WithArg("findDonationAmount", "10.0"), - ). - AssertSuccess(t) - - for i, id := range ids { - - events := res.GetEventsWithName("FindAirdropper.Airdropped") - mockField := map[string]interface{}{} - for _, e := range events { - field, exist := e.Fields["nftInfo"].(map[string]interface{}) - if exist { - mockId := field["id"].(uint64) - if id == mockId { - field["id"] = id - field["type"] = dandyType - mockField = field - } - } - } - - res.AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ - "from": otu.O.Address("user1"), - "fromName": "user1", - "to": otu.O.Address("user2"), - "toName": "user2", - "uuid": id, - "context": map[string]interface{}{ - "message": fmt.Sprintf("Message %d", i), - "tenant": "find", - }, - "nftInfo": mockField, - }) - - } - - res.AssertEvent(t, "FIND.FungibleTokenSent", map[string]interface{}{ - "from": otu.O.Address("user1"), - "fromName": "user1", - "toAddress": otu.O.Address("find-admin"), - "message": "donation to .find", - "tag": "donation", - "amount": 10.0, - "ftType": fusd, - }) - - res.AssertEvent(t, "FUSD.TokensDeposited", map[string]interface{}{ - "to": otu.O.Address("find-admin"), - "amount": 10.0, - }) - }) - } - - t.Run("Should be able to send Airdrop if royalty is not there, donate to find", func(t *testing.T) { - - id, err := otu.mintRoyaltylessNFT("user1") - require.NoError(t, err) - optional := cadence.NewOptional(cadence.String(fusd)) - fusdAmount := 11.0 + ot.Run(t, "Should be able to send Airdrop and donate funds to FIND!", func(t *testing.T) { + optional := cadence.NewOptional(cadence.String(flowToken)) res := otu.O.Tx("sendNFTs", WithSigner("user1"), WithArg("allReceivers", []string{"user2"}), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), + WithArg("nftIdentifiers", []string{dandyType}), WithArg("ids", []uint64{id}), WithArg("memos", []string{"Message 0"}), - WithArg("donationTypes", []*string{&fusd}), - WithArg("donationAmounts", []*float64{&fusdAmount}), + WithArg("donationTypes", `[nil]`), + WithArg("donationAmounts", `[nil]`), WithArg("findDonationType", optional), WithArg("findDonationAmount", "10.0"), ). - AssertSuccess(t) + AssertSuccess(t). + AssertEvent(t, "FindAirdropper.Airdropped", map[string]interface{}{ + "from": otu.O.Address("user1"), + "fromName": "user1", + "to": otu.O.Address("user2"), + "toName": "user2", + }) res.AssertEvent(t, "FIND.FungibleTokenSent", map[string]interface{}{ "from": otu.O.Address("user1"), "fromName": "user1", - "toAddress": otu.O.Address("find-admin"), + "toAddress": otu.O.Address("find"), "message": "donation to .find", "tag": "donation", - "amount": 21.0, - "ftType": fusd, + "amount": 10.0, + "ftType": flowToken, }) - res.AssertEvent(t, "FUSD.TokensDeposited", map[string]interface{}{ - "to": otu.O.Address("find-admin"), - "amount": 21.0, + res.AssertEvent(t, ".FungibleToken.Deposited", map[string]interface{}{ + "to": otu.O.Address("find"), + "amount": 10.0, }) }) } + +type SendNFTScript struct { + Address string `json:"address"` + Avatar string `json:"avatar"` + Message string `json:"message"` + Receiver string `json:"receiver"` + Type string `json:"type"` + Royalties struct { + Royalties []struct { + Address string `json:"address"` + Description string `json:"description"` + Name string `json:"name,omitempty"` + AcceptTypes []string `json:"acceptTypes"` + Cut float64 `json:"cut"` + } `json:"royalties"` + TotalRoyalty float64 `json:"totalRoyalty"` + } `json:"royalties"` + AccountInitialized bool `json:"accountInitialized"` + CollectionPublicLinked bool `json:"collectionPublicLinked"` + IsDapper bool `json:"isDapper"` + NftInPlace bool `json:"nftInPlace"` + Ok bool `json:"ok"` + ReceiverLinked bool `json:"receiverLinked"` +} diff --git a/find_dapper_test.go b/find_dapper_test.go index 39650c8b..90a3135f 100644 --- a/find_dapper_test.go +++ b/find_dapper_test.go @@ -3,7 +3,7 @@ package test_main import ( "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" ) @@ -11,38 +11,22 @@ import ( Tests must be in the same folder as flow.json with contracts and transactions/scripts in subdirectories in order for the path resolver to work correctly */ func TestFINDDapper(t *testing.T) { - - otu := NewOverflowTest(t). - setupFIND(). - createDapperUser("user1"). - registerDapperUser("user1") - - t.Run("Should be able to register a name", func(t *testing.T) { - - // Can fix this with pointerWant - otu.O.Script("getLeases").AssertWithPointerWant(t, "/0/name", - autogold.Want("allLeases", "user1"), - ) - }) - - t.Run("Should get expected output for register script", func(t *testing.T) { - - otu.O.Script("getMetadataForRegisterDapper", + ot.Run(t, "Should get expected output for register script", func(t *testing.T) { + ot.O.Script("getMetadataForRegisterDapper", WithArg("merchAccount", "find"), - WithArg("name", "user2"), + WithArg("name", "william"), WithArg("amount", 5.0), ).AssertWant(t, autogold.Want("getMetadataForRegisterDapper", map[string]interface{}{ - "amount": 5, "description": "Name :user2 for DUC 5.00000000", + "amount": 5, "description": "Name :william for DUC 5.00000000", "id": 0, - "imageURL": "https://ik.imagekit.io/xyvsisxky/tr:ot-user2,ots-55,otc-58B792,ox-N166,oy-N24,ott-b/https://i.imgur.com/8W8NoO1.png", - "name": "user2", + "imageURL": "https://ik.imagekit.io/xyvsisxky/tr:ot-william,ots-55,otc-58B792,ox-N166,oy-N24,ott-b/https://i.imgur.com/8W8NoO1.png", + "name": "william", })) }) - t.Run("Should get error if you try to register a name that is too short", func(t *testing.T) { - - otu.O.Tx("devRegisterDapper", - WithSigner("user1"), + ot.Run(t, "Should get error if you try to register a name that is too short", func(t *testing.T) { + ot.O.Tx("devRegisterDapper", + WithSigner("user5"), WithPayloadSigner("dapper"), WithArg("merchAccount", "find"), WithArg("name", "ur"), @@ -50,350 +34,27 @@ func TestFINDDapper(t *testing.T) { ).AssertFailure(t, "A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") }) - t.Run("Should get error if you try to register a name that is already claimed", func(t *testing.T) { - otu.O.Tx("devRegisterDapper", - WithSigner("user1"), + ot.Run(t, "Should get error if you try to register a name that is already claimed", func(t *testing.T) { + ot.O.Tx("devRegisterDapper", + WithSigner("user5"), WithPayloadSigner("dapper"), WithArg("merchAccount", "dapper"), WithArg("name", "user1"), WithArg("amount", 5.0), ).AssertFailure(t, "Name already registered") - - }) - - t.Run("Should allow registering a lease after it is freed", func(t *testing.T) { - - otu.expireLease().tickClock(2.0) - - otu.O.Tx(` - import FIND from "../contracts/FIND.cdc" - - transaction(name: String) { - - prepare(account: AuthAccount) { - let status=FIND.status(name) - if status.status == FIND.LeaseStatus.LOCKED { - panic("locked") - } - if status.status == FIND.LeaseStatus.FREE { - panic("free") - } - } - } - `, - WithSigner("user1"), - WithArg("name", "user1"), - ).AssertFailure(t, "locked") - - otu.expireLease() - otu.registerDapperUser("user1") - }) - - t.Run("Should be able to lookup address", func(t *testing.T) { - - otu.assertLookupAddress("user1", otu.O.Address("user1")) - }) - - t.Run("Should not be able to lookup lease after expired", func(t *testing.T) { - - otu.expireLease(). - tickClock(2.0) - - otu.O.Script("getNameStatus", - WithArg("name", "user1"), - ). - AssertWant(t, autogold.Want("getNameStatus n", nil)) - - }) - - t.Run("Admin should be able to register without paying FUSD", func(t *testing.T) { - - otu.O.Tx("adminRegisterName", - WithSigner("find-admin"), - WithArg("names", `["find-admin"]`), - WithArg("user", "find"), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FIND", "Register"), map[string]interface{}{ - "name": "find-admin", - }) - }) - t.Run("Should get expected output for renew name script", func(t *testing.T) { + ot.Run(t, "Should be able to send lease to another name", func(t *testing.T) { - otu.O.Script("getMetadataForRenewNameDapper", - WithArg("merchAccount", "find"), - WithArg("name", "user1"), - WithArg("amount", 5.0), - ).AssertWant(t, autogold.Want("getMetadataForRenewNameDapper", map[string]interface{}{ - "amount": 5, "description": "Renew name :user1 for DUC 5.00000000", - "id": 0, - "imageURL": "https://ik.imagekit.io/xyvsisxky/tr:ot-user1,ots-55,otc-58B792,ox-N166,oy-N24,ott-b/https://i.imgur.com/8W8NoO1.png", - "name": "user1", - })) - }) - - otu.renewDapperUserWithName("user1", "user1"). - createDapperUser("user2"). - registerDapperUser("user2") - - otu.tickClock(1.0) - - t.Run("Should be able to send lease to another name", func(t *testing.T) { - - otu.O.Tx("moveNameToDapper", + fmi, _ :=ot.O.QualifiedIdentifier("FIND", "Moved") + ot.O.Tx("moveNameToDapper", WithSigner("user1"), WithArg("name", "user1"), WithArg("receiver", "user2"), ). AssertSuccess(t). - AssertEvent(t, otu.identifier("FIND", "Moved"), map[string]interface{}{ + AssertEvent(t, fmi , map[string]interface{}{ "name": "user1", }) - - }) - - t.Run("Should automatically set Find name to empty if sender have none", func(t *testing.T) { - - otu.O.Script("getName", - WithArg("address", "user1"), - ). - AssertWant(t, autogold.Want("getName empty", nil)) - - otu.moveNameTo("user2", "user1", "user1") - - }) - - t.Run("Should automatically set Find Name if sender have one", func(t *testing.T) { - - otu.registerDapperUserWithName("user1", "name1"). - moveNameTo("user1", "user2", "user1") - - otu.O.Script("getName", - WithArg("address", "user1"), - ). - AssertWant(t, autogold.Want("getName empty", "name1")) - - otu.moveNameTo("user2", "user1", "user1") - - }) - - otu.setProfile("user2") - - t.Run("Should be able to register related account and remove it", func(t *testing.T) { - - otu.O.Tx("setRelatedAccountDapper", - WithSigner("user1"), - WithArg("name", "dapper"), - WithArg("target", "user2"), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindRelatedAccounts", "RelatedAccount"), map[string]interface{}{ - "walletName": "dapper", - "user": otu.O.Address("user1"), - "address": otu.O.Address("user2"), - "action": "add", - }) - - otu.O.Script("getFindStatus", - WithArg("user", "user1"), - ). - AssertWithPointerWant(t, "/accounts/0", - autogold.Want("getFindStatus Dapper", map[string]interface{}{ - "address": otu.O.Address("user2"), - "name": "dapper", - "network": "Flow", - "node": "FindRelatedAccounts", - "trusted": false, - })) - - otu.O.Tx("removeRelatedAccountDapper", - WithSigner("user1"), - WithArg("name", "dapper"), - WithArg("network", "Flow"), - WithArg("address", otu.O.Address("user2")), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindRelatedAccounts", "RelatedAccount"), map[string]interface{}{ - "walletName": "dapper", - "user": otu.O.Address("user1"), - "address": otu.O.Address("user2"), - "action": "remove", - "network": "Flow", - }) - - otu.O.Script("getFindStatus", - WithArg("user", "user1"), - ). - AssertWithPointerError(t, "/accounts", - "Object has no key 'accounts'") - - }) - - t.Run("Should be able to set private mode", func(t *testing.T) { - - otu.O.Tx("setPrivateModeDapper", - WithSigner("user1"), - WithArg("mode", true), - ).AssertSuccess(t) - - otu.O.Script("getFindStatus", - WithArg("user", "user1"), - ). - AssertWithPointerWant(t, "/privateMode", - autogold.Want("privatemode true", true), - ) - - otu.O.Tx("setPrivateModeDapper", - WithSigner("user1"), - WithArg("mode", false), - ).AssertSuccess(t) - - otu.O.Script("getFindStatus", - WithArg("user", "user1"), - ). - AssertWithPointerWant(t, "/privateMode", - autogold.Want("privatemode false", false), - ) - - }) - - t.Run("Should be able to getFindStatus of new user", func(t *testing.T) { - - nameAddress := otu.O.Address("user3") - otu.O.Script("getFindStatus", - WithArg("user", nameAddress), - ).AssertWant(t, - autogold.Want("getFindStatus", map[string]interface{}{ - "activatedAccount": true, "hasLostAndFoundItem": false, - "isDapper": false, - "privateMode": false, - "readyForWearables": false, - }), - ) - }) - - t.Run("Should be able to getFindPaths of a user", func(t *testing.T) { - - nameAddress := otu.O.Address("user1") - otu.O.Script("getFindPaths", - WithArg("user", nameAddress), - ).AssertWant(t, - autogold.Want("getFindPaths", map[string]interface{}{"address": "0xf669cb8d41ce0c74", "paths": []interface{}{ - "findDandy", - "A_179b6b1cb6755e31_FindMarketDirectOfferSoft_SaleItemCollection_find", - "A_179b6b1cb6755e31_FindLeaseMarketDirectOfferSoft_SaleItemCollection_find", - "dapperUtilityCoinVault", - }}), - ) - }) - - t.Run("If a user holds an invalid find name, get status should not return it", func(t *testing.T) { - - nameAddress := otu.O.Address("user2") - otu.moveNameTo("user2", "user1", "user2") - otu.O.Script("getFindStatus", - WithArg("user", nameAddress), - ).AssertWithPointerError(t, - "/profile/findName", - "Object has no key 'findName'", - ) - }) - - t.Run("Should be able to create and edit the social link", func(t *testing.T) { - - otu.O.Tx("editProfileDapper", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("description", "This is description"), - WithArg("avatar", "This is avatar"), - WithArg("tags", `["This is tag"]`), - WithArg("allowStoringFollowers", true), - WithArg("linkTitles", map[string]string{"CryptoTwitter": "0xBjartek", "FindTwitter": "find"}), - WithArg("linkTypes", map[string]string{"CryptoTwitter": "Twitter", "FindTwitter": "Twitter"}), - WithArg("linkUrls", map[string]string{"CryptoTwitter": "https://twitter.com/0xBjartek", "FindTwitter": "https://twitter.com/findonflow"}), - WithArg("removeLinks", "[]"), - ). - AssertSuccess(t) - - otu.O.Script("getFindStatus", - WithArg("user", "user1"), - ).AssertWithPointerWant(t, - "/profile/links/FindTwitter", - autogold.Want("getFindStatus Find twitter", map[string]interface{}{ - "title": "find", - "type": "Twitter", - "url": "https://twitter.com/findonflow", - }), - ) - - otu.O.Tx("editProfileDapper", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("description", "This is description"), - WithArg("avatar", "This is avatar"), - WithArg("tags", `["This is tag"]`), - WithArg("allowStoringFollowers", true), - WithArg("linkTitles", "{}"), - WithArg("linkTypes", "{}"), - WithArg("linkUrls", "{}"), - WithArg("removeLinks", `["FindTwitter"]`), - ). - AssertSuccess(t) - - otu.O.Script("getFindStatus", - WithArg("user", "user1"), - ).AssertWithPointerError(t, - "/profile/links/FindTwitter", - "Object has no key 'FindTwitter'", - ) - }) - - t.Run("Should get expected output for buyAddon script", func(t *testing.T) { - - otu.O.Script("getMetadataForBuyAddonDapper", - WithArg("merchAccount", "find"), - WithArg("name", "name1"), - WithArg("addon", "forge"), - WithArg("amount", 10.0), - ).AssertWant(t, autogold.Want("getMetadataForBuyAddonDapper", map[string]interface{}{ - "amount": 10, "description": "Purchase addon forge for name :name1 for DUC 10.00000000", - "id": 0, - "imageURL": "https://i.imgur.com/8W8NoO1.png", - "name": "name1", - })) - }) - - t.Run("Should be able to buy addons that are on Network", func(t *testing.T) { - - user := "user1" - - otu.buyForgeDapper(user) - - /* Should not be able to buy addons with wrong balance */ - otu.O.Tx("buyAddonDapper", - WithSigner("user1"), - WithPayloadSigner("dapper"), - WithArg("merchAccount", "dapper"), - WithArg("name", "name1"), - WithArg("addon", "forge"), - WithArg("amount", 10.0), - ). - AssertFailure(t, "Expect 50.00000000 Dapper Credit for forge addon") - - /* Should not be able to buy addons that does not exist */ - otu.O.Tx("buyAddonDapper", - WithSigner(user), - WithPayloadSigner("dapper"), - WithArg("merchAccount", "dapper"), - WithArg("name", user), - WithArg("addon", dandyNFTType(otu)), - WithArg("amount", 10.0), - ). - AssertFailure(t, "This addon is not available.") - - }) - } diff --git a/find_forge_test.go b/find_forge_test.go deleted file mode 100644 index ec9fec20..00000000 --- a/find_forge_test.go +++ /dev/null @@ -1,500 +0,0 @@ -package test_main - -import ( - "context" - "fmt" - "os" - "testing" - - . "github.com/bjartek/overflow" - "github.com/hexops/autogold" - "github.com/onflow/cadence" - "github.com/stretchr/testify/assert" -) - -func TestFindForge(t *testing.T) { - otu := NewOverflowTest(t) - - otu.setupFIND(). - createUser(10000.0, "user1"). - registerUser("user1"). - buyForge("user1") - - t.Run("Should be able to mint Example NFT and then get it by script", func(t *testing.T) { - - exampleNFTIdentifier := exampleNFTType(otu) - - otu.O.Tx("adminAddNFTCatalog", - WithSigner("find-admin"), - WithArg("collectionIdentifier", exampleNFTIdentifier), - WithArg("contractName", exampleNFTIdentifier), - WithArg("contractAddress", "find"), - WithArg("addressWithNFT", "find"), - WithArg("nftID", 0), - WithArg("publicPathIdentifier", "exampleNFTCollection"), - ). - AssertSuccess(t) - - otu.O.Tx("devMintExampleNFT", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ).AssertSuccess(t) - - extraIDs, err := otu.O.Script( - ` - import ExampleNFT from "../contracts/standard/ExampleNFT.cdc" - - pub fun main() : UInt64 {return ExampleNFT.totalSupply - 1} - `, - ).GetAsInterface() - assert.NoError(t, err) - - otu.O.Script("getNFTCatalogIDs", - WithArg("user", "user1"), - WithArg("collections", `[]`), - ).AssertWant(t, - autogold.Want("collection", map[string]interface{}{exampleNFTIdentifier: map[string]interface{}{ - "collectionName": "The Example Collection", - "extraIDs": []interface{}{extraIDs}, - "extraIDsIdentifier": exampleNFTIdentifier, - "length": 1, - "shard": "NFTCatalog", - }}), - ) - - }) - - exampleNFTForge := otu.identifier("ExampleNFT", "Forge") - t.Run("Should be able to add allowed names to private forges", func(t *testing.T) { - - otu.O.Tx("adminRemoveForge", - WithSigner("find-admin"), - WithArg("type", exampleNFTForge), - ).AssertSuccess(t) - - otu.O.Tx("devMintExampleNFT", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ).AssertFailure(t, fmt.Sprintf("This forge type is not supported. type : %s", exampleNFTForge)) - - otu.O.Tx("adminAddForge", - WithSigner("find-admin"), - WithArg("type", exampleNFTForge), - WithArg("name", "user1"), - ).AssertSuccess(t) - - otu.O.Tx("devMintExampleNFT", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ).AssertSuccess(t) - - otu.createUser(10000.0, "user2"). - registerUser("user2"). - buyForge("user2") - - otu.O.Tx("devMintExampleNFT", - WithSigner("user2"), - WithArg("name", "user2"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ).AssertFailure(t, fmt.Sprintf("This forge is not supported publicly. Forge Type : %s", exampleNFTForge)) - - otu.O.Tx("adminAddForge", - WithSigner("find-admin"), - WithArg("type", exampleNFTForge), - WithArg("name", "user2"), - ).AssertSuccess(t) - - otu.O.Tx("devMintExampleNFT", - WithSigner("user2"), - WithArg("name", "user2"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ).AssertSuccess(t) - - }) - - t.Run("Should be able to add allowed names to private forges", func(t *testing.T) { - - otu.O.Tx("adminRemoveForge", - WithSigner("find-admin"), - WithArg("type", exampleNFTForge), - ).AssertSuccess(t) - - otu.O.Tx("adminAddForge", - WithSigner("find-admin"), - WithArg("type", exampleNFTForge), - WithArg("name", "user1"), - ).AssertSuccess(t) - - otu.O.Tx("buyAddon", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("addon", "premiumForge"), - WithArg("amount", 1000.0), - ).AssertSuccess(t). - AssertEvent(t, otu.identifier("FIND", "AddonActivated"), - map[string]interface{}{ - "name": "user1", - "addon": "premiumForge", - }, - ) - - id, err := otu.O.Tx("devMintExampleNFT", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ).AssertSuccess(t). - GetIdFromEvent("FindForge.Minted", "id") - - if err != nil { - panic(err) - } - - otu.O.Script("getNFTView", - WithArg("user", "user1"), - WithArg("aliasOrIdentifier", exampleNFTType(otu)), - WithArg("id", id), - WithArg("identifier", otu.identifier("MetadataViews", "Royalties")), - ).AssertWant(t, - autogold.Want("royalty", map[string]interface{}{"cutInfos": []interface{}{map[string]interface{}{"cut": 0.05, "description": "creator", "receiver": fmt.Sprintf("Capability<&AnyResource{%s}>(address: %s, path: /public/findProfileReceiver)", otu.identifier("FungibleToken", "Receiver"), otu.O.Address("user1"))}}}), - ) - - }) - - t.Run("Should not be able to mint Example NFTs with non-exist traits", func(t *testing.T) { - - otu.O.Tx("devMintExampleNFT", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3, 4}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ). - Print(). - AssertFailure(t, "This trait does not exist ID :4") - }) - - t.Run("Should be able register traits to Example NFT and then mint", func(t *testing.T) { - - otu.O.Tx("devAddTraitsExampleNFT", - WithSigner("find-admin"), - WithArg("lease", "user1"), - ). - AssertSuccess(t) - - otu.O.Tx("devMintExampleNFT", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3, 4}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ). - AssertSuccess(t) - }) - - t.Run("Should be able to add addon and mint for users as admin", func(t *testing.T) { - - otu.registerUserWithName("user1", "testingname") - - otu.O.Tx("adminAddAddon", - WithSigner("find-admin"), - WithArg("name", "testingname"), - WithArg("addon", "premiumForge"), - ). - AssertSuccess(t). - AssertEvent(t, "AddonActivated", map[string]interface{}{ - "name": "testingname", - "addon": "premiumForge", - }) - - otu.O.Tx("adminAddForge", - WithSigner("find-admin"), - WithArg("type", exampleNFTForge), - WithArg("name", "testingname"), - ).AssertSuccess(t) - - otu.O.Tx("devadminMintExampleNFT", - WithSigner("find-admin"), - WithArg("name", "testingname"), - WithArg("artist", "Bam"), - WithArg("nftName", "ExampleNFT"), - WithArg("nftDescription", "This is an ExampleNFT"), - WithArg("nftUrl", "This is an exampleNFT url"), - WithArg("traits", []uint64{1, 2, 3, 4}), - WithArg("collectionDescription", "Example NFT FIND"), - WithArg("collectionExternalURL", "Example NFT external url"), - WithArg("collectionSquareImage", "Example NFT square image"), - WithArg("collectionBannerImage", "Example NFT banner image"), - ). - AssertSuccess(t) - }) - - type MetadataViews_NFTCollectionDisplay struct { - Name string - Description string - ExternalURL MetadataViews_ExternalURL `cadence:"externalURL"` - SquareImage MetadataViews_Media_IPFS `cadence:"squareImage"` - BannerImage MetadataViews_Media_IPFS `cadence:"bannerImage"` - Socials map[string]MetadataViews_ExternalURL - } - - collectionDisplay := MetadataViews_NFTCollectionDisplay{ - Name: "notSet", - Description: "testing", - ExternalURL: MetadataViews_ExternalURL{Url: "testing url"}, - SquareImage: MetadataViews_Media_IPFS{ - File: MetadataViews_IPFSFile{ - Cid: "testing square", - Path: nil, - }, - }, - BannerImage: MetadataViews_Media_IPFS{ - File: MetadataViews_IPFSFile{ - Cid: "testing banner", - Path: nil, - }, - }, - Socials: map[string]MetadataViews_ExternalURL{ - "twitter": {Url: "testing twitter"}, - "discord": {Url: "testing discord"}, - }, - } - - t.Run("Should be able to order Forges for contract", func(t *testing.T) { - - testingName := "foo" - mintType := "DIM" - otu.O.Tx("register", - WithSigner("user1"), - WithArg("name", testingName), - WithArg("amount", 500.0), - ).AssertSuccess(t) - - otu.O.Tx("buyAddon", - WithSigner("user1"), - WithArg("name", testingName), - WithArg("addon", "forge"), - WithArg("amount", 50.0), - ). - AssertSuccess(t). - AssertEvent(t, "AddonActivated", map[string]interface{}{ - "name": testingName, - "addon": "forge", - }) - - otu.O.Tx("adminAddForgeMintType", - WithSigner("find-admin"), - WithArg("mintType", mintType), - ). - AssertSuccess(t) - - collectionDisplay.Name = testingName - - otu.O.Tx("orderForge", - WithSigner("user1"), - WithArg("name", testingName), - WithArg("mintType", mintType), - WithArg("minterCut", 0.05), - WithArg("collectionDisplay", collectionDisplay), - ). - Print(). - AssertSuccess(t). - AssertEvent(t, "ForgeOrdered", map[string]interface{}{ - "lease": testingName, - "mintType": mintType, - }) - }) - - t.Run("Should be able to remove order as Admin", func(t *testing.T) { - - testingName := "foo" - mintType := "DIM" - - collectionDisplay.Name = testingName - - otu.O.Tx("adminCancelForgeOrder", - WithSigner("find-admin"), - WithArg("name", testingName), - WithArg("mintType", mintType), - ). - Print(). - AssertSuccess(t). - AssertEvent(t, "ForgeOrderCancelled", map[string]interface{}{ - "lease": testingName, - "mintType": mintType, - }) - }) - - t.Run("Should be able to order as Admin", func(t *testing.T) { - - testingName := "foo" - mintType := "DIM" - - collectionDisplay.Name = testingName - - otu.O.Tx("adminOrderForge", - WithSigner("find-admin"), - WithArg("name", testingName), - WithArg("mintType", mintType), - WithArg("minterCut", 0.05), - WithArg("collectionDisplay", collectionDisplay), - ). - Print(). - AssertSuccess(t). - AssertEvent(t, "ForgeOrdered", map[string]interface{}{ - "lease": testingName, - "mintType": mintType, - }) - }) - - // set User4 as admin, the account as find-forge on emulator (for deploying contracts) - otu.O.Tx("setup_fin_1_create_client", WithSigner("find-forge")). - AssertSuccess(otu.T).AssertNoEvents(otu.T) - - //link in the server in the versus client - otu.O.Tx("setup_fin_2_register_client", - findSigner, - WithArg("ownerAddress", "find-forge"), - ).AssertSuccess(otu.T).AssertNoEvents(otu.T) - - t.Run("Should be able to deploy Forge recipe contract and fulfill the order", func(t *testing.T) { - file, err := os.ReadFile("./contracts/FindFooDIM.cdc") - assert.NoError(t, err) - - err = otu.O.AddContract(context.Background(), "find-forge", file, []cadence.Value{}, "./contracts/FindFooDIM.cdc", false) - assert.NoError(t, err) - }) - - t.Run("Should be able to mint Foo NFT as user 1", func(t *testing.T) { - - type FindForgeStruct_FindDIM struct { - Name string `cadence:"name"` - Description string `cadence:"description"` - ThumbnailHash string `cadence:"thumbnailHash"` - ExternalURL string `cadence:"externalURL"` - Edition uint64 `cadence:"edition"` - MaxEdition uint64 `cadence:"maxEdition"` - Descriptions map[string]string `cadence:"descriptions"` - Scalars map[string]float64 `cadence:"scalars"` - Boosts map[string]float64 `cadence:"boosts"` - BoostPercents map[string]float64 `cadence:"boostPercents"` - Levels map[string]float64 `cadence:"levels"` - Traits map[string]string `cadence:"traits"` - Dates map[string]float64 `cadence:"dates"` - Medias map[string]string `cadence:"medias"` - Extras map[string]interface{} `cadence:"extras"` - } - - data := FindForgeStruct_FindDIM{ - Name: "Name", - Description: "Description", - ThumbnailHash: "ThumbnailHash", - ExternalURL: "ExternalURL", - Edition: 1, - MaxEdition: 2, - Descriptions: map[string]string{ - "Descriptions": "Descriptions", - }, - Scalars: map[string]float64{ - "Scalars": 1.0, - }, - Boosts: map[string]float64{ - "Boosts": 1.0, - }, - BoostPercents: map[string]float64{ - "BoostPercents": 1.0, - }, - Levels: map[string]float64{ - "Levels": 1.0, - }, - Traits: map[string]string{ - "Traits": "Traits", - }, - Dates: map[string]float64{ - "Dates": 1.0, - }, - Medias: map[string]string{ - "Traits": "Traits", - }, - Extras: map[string]interface{}{}, - } - - otu.O.Tx("devmintFooDIMNFT", - WithSigner("user1"), - WithArg("name", "foo"), - WithArg("receivers", []string{"user1"}), - WithArg("data", []FindForgeStruct_FindDIM{ - data, - }), - ). - AssertSuccess(t). - AssertEvent(t, "FindFooDIM.Minted", map[string]interface{}{ - "name": data.Name, - "description": data.Description, - "edition": data.Edition, - "maxEdition": data.MaxEdition, - }) - }) -} diff --git a/find_furnace_test.go b/find_furnace_test.go index f11fc960..f0036b7e 100644 --- a/find_furnace_test.go +++ b/find_furnace_test.go @@ -4,32 +4,23 @@ import ( "fmt" "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" ) func TestFindFurnace(t *testing.T) { - - otu := NewOverflowTest(t). - setupFIND(). - setupDandy("user1") - + otu := &OverflowTestUtils{T: t, O: ot.O} dandyType := otu.identifier("Dandy", "NFT") - otu.mintThreeExampleDandies() - otu.registerDandyInNFTRegistry() - - t.Run("Should be able to burn Dandy", func(t *testing.T) { - - ids := otu.mintThreeExampleDandies() + ot.Run(t, "Should be able to burn Dandy", func(t *testing.T) { res := otu.O.Tx("burnNFTs", WithSigner("user1"), WithArg("types", []string{dandyType, dandyType, dandyType}), - WithArg("ids", ids), + WithArg("ids", dandyIds), WithArg("messages", []string{"Message 0", "Message 1", "Message 2"}), ). AssertSuccess(t) - for i, id := range ids { + for i, id := range dandyIds { events := res.GetEventsWithName("FindFurnace.Burned") mockField := map[string]interface{}{} @@ -57,5 +48,4 @@ func TestFindFurnace(t *testing.T) { }) } }) - } diff --git a/find_lost_and_found_test.go b/find_lost_and_found_test.go index 5677adee..b72532fc 100644 --- a/find_lost_and_found_test.go +++ b/find_lost_and_found_test.go @@ -3,157 +3,50 @@ package test_main import ( "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" - "github.com/stretchr/testify/assert" ) func TestFindLostAndFound(t *testing.T) { - otu := NewOverflowTest(t) - - otu.setupFIND(). - createUser(10000.0, "user1"). - registerUser("user1"). - registerExampleNFTInNFTRegistry() - - t.Run("Should be able to send thru sendNFT transaction without account initiated", func(t *testing.T) { - otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["user1"]`), - WithArg("ids", []uint64{2}), - WithArg("memos", `["Hello!"]`), - WithArg("donationTypes", `[nil]`), - WithArg("donationAmounts", `[nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.TicketDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, - "memo": "Hello!", - "name": "FlowExampleNFT", - "description": "For testing listing in Flow", - "thumbnail": "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", - }) - - resetState(otu, "user1", true) + otu := &OverflowTestUtils{T: t, O: ot.O} + ot.Run(t, "Should be able to send thru sendNFT transaction without initialized collection", func(t *testing.T) { + otu.SendNFTsLostAndFound(dandyIdentifier, dandyIds[0], "user4") }) - t.Run("Should be able to get all Lost And Found NFT with script", func(t *testing.T) { - ticketID := otu.createExampleNFTTicket() + ot.Run(t, "Should be able to get all Lost And Found NFT with script", func(t *testing.T) { + // ticket := otu.SendNFTsLostAndFound(dandyIdentifier, dandyIds[0], "user4") otu.O.Script("getLostAndFoundNFTs", - WithArg("user", "user1"), + WithArg("user", otu.O.Address("user4")), ). - AssertWant(t, autogold.Want("Should get all NFT Type", map[string]interface{}{ - "nftCatalogTicketInfo": map[string]interface{}{exampleNFTType(otu): []interface{}{map[string]interface{}{ - "description": "For testing listing in Flow", - "memo": "Hello!", - "name": "FlowExampleNFT", - "redeemed": false, - "redeemer": otu.O.Address("user1"), - "thumbnail": "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", - "ticketID": ticketID, - "type": exampleNFTType(otu), - "typeIdentifier": exampleNFTType(otu), - }}}, - "ticketIds": map[string]interface{}{exampleNFTType(otu): []interface{}{ticketID}}, - })) - - resetState(otu, "user1", true) - + AssertWant(t, autogold.Want("Should get all NFT Type", nil)) }) - t.Run("Should not be able to redeem NFT without suitable collection. But tx will still run thru and events will be emitted", func(t *testing.T) { - ticketID := otu.createExampleNFTTicket() + ot.Run(t, "Should not be able to redeem NFT on behalf of without suitable collection. But tx will still run thru and events will be emitted", func(t *testing.T) { + ticket := otu.SendNFTsLostAndFound(dandyIdentifier, dandyIds[0], "user4") - otu.O.Tx("redeemLostAndFoundNFTs", - WithSigner("user1"), - WithArg("ids", map[string][]uint64{exampleNFTType(otu): {ticketID}}), + // note that it is somebody else that is redeeming + otu.O.Tx("redeemLostAndFoundNFTsOnBehalf", + WithSigner("find"), + WithArg("receiverAddress", otu.O.Address("user4")), + WithArg("ids", map[string][]uint64{dandyIdentifier: {ticket}}), ). AssertSuccess(t). AssertEvent(t, "FindLostAndFoundWrapper.TicketRedeemFailed", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "ticketID": ticketID, - "type": exampleNFTType(otu), - "remark": "invalid capability", + "receiver": otu.O.Address("user4"), + "ticketID": ticket, + "type": dandyIdentifier, + "remark": "invalid capability", }) - - resetState(otu, "user1", true) - - }) - - t.Run("Should be able to redeem NFT after initiating", func(t *testing.T) { - ticketID := otu.createExampleNFTTicket() - - otu.O.Tx("setupExampleNFTCollection", - WithSigner("user1"), - ). - AssertSuccess(t) - - otu.O.Tx("redeemLostAndFoundNFTs", - WithSigner("user1"), - WithArg("ids", map[string][]uint64{exampleNFTType(otu): {ticketID}}), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FindLostAndFoundWrapper.TicketRedeemed") - - resetState(otu, "user1", true) - }) - t.Run("Should be able to send thru sendNFT transaction with account initiated", func(t *testing.T) { - otu.O.Tx("setupExampleNFTCollection", - WithSigner("user1"), - ). - AssertSuccess(t) - + ot.Run(t, "Should be able to send thru sendNFT transaction with account initiated", func(t *testing.T) { otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["user1"]`), - WithArg("ids", []uint64{2}), - WithArg("memos", `["Hello!"]`), - WithArg("donationTypes", `[nil]`), - WithArg("donationAmounts", `[nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.NFTDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, - "memo": "Hello!", - "name": "FlowExampleNFT", - "thumbnail": "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", - }) - resetState(otu, "user1", true) - - }) - - t.Run("Should be able to send thru sendNFT transaction with account initiated and display receiverName in event", func(t *testing.T) { - otu.O.Tx("setupExampleNFTCollection", WithSigner("user1"), - ). - AssertSuccess(t) - - receiverAddress := otu.O.Address("user1") - - otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["`+receiverAddress+`"]`), - WithArg("ids", []uint64{2}), + WithArg("nftIdentifiers", []string{dandyIdentifier}), + WithArg("allReceivers", `["user2"]`), + WithArg("ids", []uint64{dandyIds[0]}), WithArg("memos", `["Hello!"]`), WithArg("donationTypes", `[nil]`), WithArg("donationAmounts", `[nil]`), @@ -162,474 +55,11 @@ func TestFindLostAndFound(t *testing.T) { ). AssertSuccess(t). AssertEvent(t, "FindLostAndFoundWrapper.NFTDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, + "receiver": otu.O.Address("user2"), + "receiverName": "user2", + "sender": otu.O.Address("user1"), + "type": dandyIdentifier, "memo": "Hello!", - "name": "FlowExampleNFT", - "thumbnail": "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", }) - resetState(otu, "user1", true) - - }) - - t.Run("Should be able to redeem with Collection Public and MetadataViews linked", func(t *testing.T) { - - ticketID, err := otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["user1"]`), - WithArg("ids", []uint64{2}), - WithArg("memos", `["Hello!"]`), - WithArg("donationTypes", `[nil]`), - WithArg("donationAmounts", `[nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.TicketDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, - "memo": "Hello!", - "name": "FlowExampleNFT", - "thumbnail": "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", - }). - GetIdFromEvent("FindLostAndFoundWrapper.TicketDeposited", "ticketID") - - assert.NoError(t, err) - - otu.O.Tx("devsetupExampleNFTCollectionCPMV", - WithSigner("user1"), - ). - AssertSuccess(t) - - otu.O.Tx("redeemLostAndFoundNFTs", - WithSigner("user1"), - WithArg("ids", map[string][]uint64{exampleNFTType(otu): {ticketID}}), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FindLostAndFoundWrapper.TicketRedeemed") - - resetState(otu, "user1", true) - }) - - t.Run("Should be able to redeem with Receiver and MetadataViews linked", func(t *testing.T) { - - ticketID, err := otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["user1"]`), - WithArg("ids", []uint64{2}), - WithArg("memos", `["Hello!"]`), - WithArg("donationTypes", `[nil]`), - WithArg("donationAmounts", `[nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.TicketDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, - "memo": "Hello!", - "name": "FlowExampleNFT", - "thumbnail": "https://images.ongaia.com/ipfs/QmZPxYTEx8E5cNy5SzXWDkJQg8j5C3bKV6v7csaowkovua/8a80d1575136ad37c85da5025a9fc3daaf960aeab44808cd3b00e430e0053463.jpg", - }). - GetIdFromEvent("FindLostAndFoundWrapper.TicketDeposited", "ticketID") - - assert.NoError(t, err) - - otu.O.Tx("devsetupExampleNFTCollectionRMV", - WithSigner("user1"), - ). - AssertSuccess(t) - - otu.O.Tx("redeemLostAndFoundNFTs", - WithSigner("user1"), - WithArg("ids", map[string][]uint64{exampleNFTType(otu): {ticketID}}), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FindLostAndFoundWrapper.TicketRedeemed") - - resetState(otu, "user1", true) - - }) - - t.Run("Should be able to redeem with only Collection Public linked", func(t *testing.T) { - - ticketID, err := otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["user1"]`), - WithArg("ids", []uint64{2}), - WithArg("memos", `["Hello!"]`), - WithArg("donationTypes", `[nil]`), - WithArg("donationAmounts", `[nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.TicketDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, - "memo": "Hello!", - }). - GetIdFromEvent("FindLostAndFoundWrapper.TicketDeposited", "ticketID") - - assert.NoError(t, err) - - otu.O.Tx("devsetupExampleNFTCollectionCP", - WithSigner("user1"), - ). - AssertSuccess(t) - - otu.O.Tx("redeemLostAndFoundNFTs", - WithSigner("user1"), - WithArg("ids", map[string][]uint64{exampleNFTType(otu): {ticketID}}), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FindLostAndFoundWrapper.TicketRedeemed") - - resetState(otu, "user1", true) - - }) - - t.Run("Should be able to redeem with Receiver and MetadataViews linked", func(t *testing.T) { - - ticketID, err := otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["user1"]`), - WithArg("ids", []uint64{2}), - WithArg("memos", `["Hello!"]`), - WithArg("donationTypes", `[nil]`), - WithArg("donationAmounts", `[nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.TicketDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, - "memo": "Hello!", - }). - GetIdFromEvent("FindLostAndFoundWrapper.TicketDeposited", "ticketID") - - assert.NoError(t, err) - - otu.O.Tx("devsetupExampleNFTCollectionR", - WithSigner("user1"), - ). - AssertSuccess(t) - - otu.O.Tx("redeemLostAndFoundNFTs", - WithSigner("user1"), - WithArg("ids", map[string][]uint64{exampleNFTType(otu): {ticketID}}), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FindLostAndFoundWrapper.TicketRedeemed") - - resetState(otu, "user1", true) - - }) - - t.Run("Should be able to redeem on behalf of other account", func(t *testing.T) { - - ticketID, err := otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["user1"]`), - WithArg("ids", []uint64{2}), - WithArg("memos", `["Hello!"]`), - WithArg("donationTypes", `[nil]`), - WithArg("donationAmounts", `[nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.TicketDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, - "memo": "Hello!", - }). - GetIdFromEvent("FindLostAndFoundWrapper.TicketDeposited", "ticketID") - - assert.NoError(t, err) - - otu.O.Tx("devsetupExampleNFTCollectionR", - WithSigner("user1"), - ). - AssertSuccess(t) - - otu.O.Tx("redeemLostAndFoundNFTsOnBehalf", - WithSigner("user2"), - WithArg("receiverAddress", "user1"), - WithArg("ids", map[string][]uint64{exampleNFTType(otu): {ticketID}}), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FindLostAndFoundWrapper.TicketRedeemed") - - resetState(otu, "user1", true) - - }) - - t.Run("Should be able to redeem on behalf of other account", func(t *testing.T) { - - otu.O.Tx("sendNFTs", - WithSigner("find"), - WithArg("nftIdentifiers", []string{exampleNFTType(otu)}), - WithArg("allReceivers", `["user1"]`), - WithArg("ids", []uint64{2}), - WithArg("memos", `["Hello!"]`), - WithArg("donationTypes", `[nil]`), - WithArg("donationAmounts", `[nil]`), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.TicketDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user1"), - "receiverName": "user1", - "sender": otu.O.Address("find"), - "type": exampleNFTType(otu), - "id": 2, - "memo": "Hello!", - }) - - otu.O.Tx("devsetupExampleNFTCollectionCP", - WithSigner("user1"), - ). - AssertSuccess(t) - - otu.O.Tx("redeemAllLostAndFoundNFTsOnBehalf", - WithSigner("user2"), - WithArg("receiverAddress", "user1"), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FindLostAndFoundWrapper.TicketRedeemed") - - resetState(otu, "user1", true) - - }) - - t.Run("Should be able to send a lot of NFTs", func(t *testing.T) { - amount := 40 - - otu.buyForge("user1"). - createUser(100, "user2"). - registerUser("user2"). - createUser(100, "user3") - - ids := mintDandies(otu, amount) - - otu.registerFtInRegistry() - - identifiers := []string{} - allReceivers := []string{} - memos := []string{} - nils := `[nil` - - for len(identifiers) < len(ids) { - identifiers = append(identifiers, dandyNFTType(otu)) - allReceivers = append(allReceivers, "user2") - memos = append(memos, "Msg") - nils = nils + `, nil` - } - - nils = nils + `]` - - otu.O.Tx("sendNFTs", - WithSigner("user1"), - WithArg("nftIdentifiers", identifiers), - WithArg("allReceivers", allReceivers), - WithArg("ids", ids), - WithArg("memos", memos), - WithArg("donationTypes", nils), - WithArg("donationAmounts", nils), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t) - - resetState(otu, "user1", false) - }) - - t.Run("Should send to Lost And Found if the receiver account is full", func(t *testing.T) { - - otu.O.Tx("setupDandyCollection", - WithSigner("user2"), - ). - AssertSuccess(t) - - otu.O.Tx("devFillUpStorage", - WithSigner("user2"), - ). - AssertSuccess(t) - - otu.O.FillUpStorage("user2") - - amount := 20 - - ids := mintDandies(otu, amount) - - identifiers := []string{} - allReceivers := []string{} - memos := []string{} - nils := `[nil` - - for len(identifiers) < len(ids) { - identifiers = append(identifiers, dandyNFTType(otu)) - allReceivers = append(allReceivers, "user2") - memos = append(memos, "Msg") - nils = nils + `, nil` - } - nils = nils + `]` - - otu.O.Tx("sendNFTs", - WithSigner("user1"), - WithArg("nftIdentifiers", identifiers), - WithArg("allReceivers", allReceivers), - WithArg("ids", ids), - WithArg("memos", memos), - WithArg("donationTypes", nils), - WithArg("donationAmounts", nils), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindLostAndFoundWrapper.TicketDeposited", map[string]interface{}{ - "receiver": otu.O.Address("user2"), - "sender": otu.O.Address("user1"), - "type": dandyNFTType(otu), - }) - - otu.O.Tx("devRefillStorage", - WithSigner("user2"), - ). - AssertSuccess(t) - - }) - - t.Run("Should be able to get required storage type by script so that they can redeem NFTs", func(t *testing.T) { - - resetState(otu, "user2", false) - - // mint one Dandy to "user2" - amount := 1 - ids := mintDandies(otu, amount) - - identifiers := []string{} - allReceivers := []string{} - memos := []string{} - nils := `[nil` - - for len(identifiers) < len(ids) { - identifiers = append(identifiers, dandyNFTType(otu)) - allReceivers = append(allReceivers, "user2") - memos = append(memos, "Msg") - nils = nils + `, nil` - } - nils = nils + `]` - - otu.O.Tx("sendNFTs", - WithSigner("user1"), - WithArg("nftIdentifiers", identifiers), - WithArg("allReceivers", allReceivers), - WithArg("ids", ids), - WithArg("memos", memos), - WithArg("donationTypes", nils), - WithArg("donationAmounts", nils), - WithArg("findDonationType", nil), - WithArg("findDonationAmount", nil), - ). - AssertSuccess(t) - - // Scripts should be able to get initiable type - otu.O.Script("getLostAndFoundRequiredStorageType", - WithArg("user", "user2"), - ). - Print(). - AssertWithPointerWant(t, "/initiableStorage/0", autogold.Want("Should get Dandy Type in initiable", dandyNFTType(otu))) - - otu.O.Tx("setupDandyCollection", - WithSigner("user2"), - ). - AssertSuccess(t) - - // Scripts should get initiated type - otu.O.Script("getLostAndFoundRequiredStorageType", - WithArg("user", "user2"), - ). - Print(). - AssertWithPointerWant(t, "/initiatedStorage/0", autogold.Want("Should get Dandy Type in initiated", dandyNFTType(otu))) - - resetState(otu, "user2", false) - }) - -} - -func mintDandies(otu *OverflowTestUtils, number int) []uint64 { - - result := otu.O.Tx("mintDandy", - user1Signer, - WithArg("name", "user1"), - WithArg("maxEdition", uint64(number)), - WithArg("artist", "Neo"), - WithArg("nftName", "Neo Motorcycle"), - WithArg("nftDescription", `Bringing the motorcycle world into the 21st century with cutting edge EV technology and advanced performance in a great classic British style, all here in the UK`), - - WithArg("nftUrl", "https://neomotorcycles.co.uk/assets/img/neo_motorcycle_side.webp"), - WithArg("collectionDescription", "Neo Collectibles FIND"), - WithArg("collectionExternalURL", "https://neomotorcycles.co.uk/index.html"), - WithArg("collectionSquareImage", "https://neomotorcycles.co.uk/assets/img/neo_motorcycle_side.webp"), - WithArg("collectionBannerImage", "https://neomotorcycles.co.uk/assets/img/neo-logo-web-dark.png?h=5a4d226197291f5f6370e79a1ee656a1"), - ). - AssertSuccess(otu.T) - return result.GetIdsFromEvent("Dandy.Deposit", "id") -} - -func resetState(otu *OverflowTestUtils, user string, resetExampleNFT bool) *OverflowTestUtils { - - signWithUser := otu.O.TxFN( - WithSigner(user), - ) - - signWithUser("setupDandyCollection"). - AssertSuccess(otu.T) - - signWithUser("setupExampleNFTCollection"). - AssertSuccess(otu.T) - - signWithUser("redeemAllLostAndFoundNFTs"). - AssertSuccess(otu.T) - - if resetExampleNFT { - otu.sendExampleNFT("find", user, 2) - } - - signWithUser("devDestroyExampleNFTCollection"). - AssertSuccess(otu.T) - - signWithUser("devDestroyDandyCollection"). - AssertSuccess(otu.T) - - return otu - } diff --git a/find_pack_test.go b/find_pack_test.go index 40a125b4..aff3d73c 100644 --- a/find_pack_test.go +++ b/find_pack_test.go @@ -1,185 +1,47 @@ package test_main import ( - "fmt" "testing" - . "github.com/bjartek/overflow" - "github.com/hexops/autogold" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + . "github.com/bjartek/overflow/v2" ) +// There used to be lots more tests here, but since we are not actively using that part of packs anymore then i have commented them out. func TestFindPack(t *testing.T) { - + otu := &OverflowTestUtils{T: t, O: ot.O} packTypeId := uint64(1) - salt := "find-admin" buyer := "user1" - otu := NewOverflowTest(t). - setupFIND(). - createUser(10000.0, "user1"). - createUser(10000.0, "user2"). - registerUser("user1"). - buyForge("user1"). - registerExampleNFTInNFTRegistry() - - otu.setUUID(5000) - - singleType := []string{exampleNFTType(otu)} - - flow, err := otu.O.QualifiedIdentifier("FlowToken", "Vault") - assert.NoError(otu.T, err) - t.Run("Should be able to mint Example NFTs", func(t *testing.T) { - otu.mintExampleNFTs() - }) - - t.Run("Should be able to register pack data", func(t *testing.T) { - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packTypeId++ - }) - - t.Run("Should be able to register pack as a User with struct", func(t *testing.T) { - - otu.O.Tx("registerFindPackMetadata", - WithSigner("user1"), - WithArg("forge", buyer), - WithArg("name", buyer), - WithArg("description", "test"), - WithArg("typeId", packTypeId), - WithArg("externalURL", "url"), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("bannerHash", "bannerHash"), - WithArg("social", map[string]string{"twitter": "twitterLink"}), - WithArg("wallet", "find-admin"), - WithArg("walletType", flow), - WithArg("openTime", 1.0), - WithAddresses("primaryRoyaltyRecipients", "find", "find-admin"), - WithArg("primaryRoyaltyCuts", []float64{0.1, 0.3}), - WithArg("primaryRoyaltyDescriptions", []string{"", ""}), - WithAddresses("secondaryRoyaltyRecipients", "find", "find-admin"), - WithArg("secondaryRoyaltyCuts", []float64{0.1, 0.3}), - WithArg("secondaryRoyaltyDescriptions", []string{"", ""}), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{}), - WithArg("endTime", map[string]float64{}), - WithArg("floatEventId", map[string]uint64{}), - WithArg("price", map[string]float64{}), - WithArg("purchaseLimit", map[string]uint64{}), - WithArg("packFields", map[string]string{ - "Items": "1", - }), - WithArg("nftTypes", []string{exampleNFTType(otu)}), - WithArg("storageRequirement", 50000), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - packTypeId++ - }) - - t.Run("Should be able to register pack as a User with struct", func(t *testing.T) { - - eventIden, err := otu.O.QualifiedIdentifier("FindPack", "MetadataRegistered") - assert.NoError(otu.T, err) - - info := otu.generatePackStruct("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - - otu.O.Tx("registerFindPackMetadataStruct", - WithSigner("user1"), - WithArg("info", info), - ). - AssertSuccess(t). - AssertEvent(t, eventIden, map[string]interface{}{ - "packTypeId": packTypeId, - }) - - packTypeId++ - }) - - t.Run("Should be able to mint pack", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find"). - mintPack("user1", packTypeId, []uint64{id1}, singleType, salt) - packTypeId++ - + ot.Run(t, "Should be able to buy pack", func(_ *testing.T) { + otu.buyPack(buyer, packTypeName, packTypeId, 1, 4.20) }) - t.Run("Should be able to buy pack", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) - packTypeId++ - - }) - - t.Run("Should be able to buy pack and open pack", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packId := otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) + ot.Run(t, "Should be able to buy pack and open pack", func(t *testing.T) { + otu.buyPack(buyer, packTypeName, packTypeId, 1, 4.20) otu.openPack(buyer, packId) - packTypeId++ - }) - t.Run("Should be able to buy and open", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packId := otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) + ot.Run(t, "Should be able to buy, open and fulfill", func(t *testing.T) { + otu.buyPack(buyer, packTypeName, packTypeId, 1, 4.20) otu.openPack(buyer, packId) - otu.fulfillPack(packId, ids, salt) - packTypeId++ + otu.fulfillPack(packId, packRewardIds, packSalt) }) - t.Run("Should be able to buy and open with no collection setup", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packId := otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack("user2", buyer, packTypeId, 1, 4.20) - otu.openPack("user2", packId) - otu.fulfillPack(packId, ids, salt) - packTypeId++ + ot.Run(t, "Should be able to buy, open and fulfill with no collection setup", func(t *testing.T) { + otu.buyPack("user3", packTypeName, packTypeId, 1, 4.20) + otu.openPack("user3", packId) + otu.fulfillPack(packId, packRewardIds, packSalt) }) - t.Run("Should get transferred to DLQ if try to open with wrong salt", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packId := otu.mintPack("user1", packTypeId, ids, singleType, salt) - + ot.Run(t, "Should get transferred to DLQ if try to open with wrong salt", func(t *testing.T) { otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) otu.openPack(buyer, packId) otu.O.Tx("adminFulfillFindPack", WithSigner("find-admin"), WithArg("packId", packId), - WithArg("typeIdentifiers", []string{exampleNFTType(otu)}), - WithArg("rewardIds", ids), + WithArg("typeIdentifiers", []string{dandyIdentifier}), + WithArg("rewardIds", packRewardIds), WithArg("salt", "wrong salt"), ). AssertSuccess(t). @@ -188,889 +50,70 @@ func TestFindPack(t *testing.T) { "address": otu.O.Address(buyer), "reason": "The content of the pack was not verified with the hash provided at mint", }) - packTypeId++ - }) - t.Run("Should not be able to buy pack before drop is open", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 2.0, 2.0, false, 0, "find-admin", "find") - otu.mintPack("user1", packTypeId, ids, singleType, salt) + ot.Run(t, "Should not be able to buy pack before drop is open", func(t *testing.T) { + otu.registerPackType("user1", 2, []string{dandyIdentifier}, 0.0, 200.0, 200.0, false, 0, "find-admin", "find") + otu.mintPack("user1", 2, packRewardIds, []string{dandyIdentifier}, packSalt) otu.O.Tx("buyFindPack", WithSigner(buyer), WithArg("packTypeName", buyer), - WithArg("packTypeId", packTypeId), + WithArg("packTypeId", 2), WithArg("numberOfPacks", 1), WithArg("totalAmount", 4.2), ). AssertFailure(t, "Cannot buy the pack now") - packTypeId++ - }) - t.Run("Should not be able to open the pack before it is available", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 2.0, false, 0, "find-admin", "find") - packId := otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) - + ot.Run(t, "Should not be able to open pack before drop is available", func(t *testing.T) { + otu.registerPackType("user1", 2, []string{dandyIdentifier}, 0.0, 1.0, 200.0, false, 0, "find-admin", "find") + newPackId := otu.mintPack("user1", 2, packRewardIds, []string{dandyIdentifier}, packSalt) + otu.buyPack(buyer, buyer, 2, 1, 4.20) otu.O.Tx("openFindPack", WithSigner(buyer), - WithArg("packId", packId), + WithArg("packId", newPackId), ). AssertFailure(t, "You cannot open the pack yet") - packTypeId++ - - }) - - t.Run("Should get transferred to DLQ if storage full", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packId := otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) - otu.openPack(buyer, packId) - - otu.O.Tx("devFillUpStorage", - WithSigner(buyer), - ). - AssertSuccess(t) - - // try to fill that up with Example NFT - - res := otu.O.FillUpStorage(buyer) - require.NoError(t, res.Error) - - fmt.Println(otu.O.GetFreeCapacity(buyer)) - - pid := map[uint64][]uint64{packId: ids} - types := map[uint64][]string{packId: {exampleNFTType(otu)}} - - otu.O.Tx("adminFulfillPacks", - WithSigner("find-admin"), - WithArg("types", types), - WithArg("rewards", pid), - WithArg("salts", map[uint64]string{packId: "wrong salt"}), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "FulfilledError"), map[string]interface{}{ - "packId": packId, - "address": otu.O.Address(buyer), - "reason": "Not enough flow to hold the content of the pack. Please top up your account"}) - - otu.O.Tx("devRefillStorage", - WithSigner(buyer), - ). - AssertSuccess(t) - packTypeId++ - }) // Tests on Float implementation - t.Run("Should be able to buy nft if the user has the float and with a whitelist.", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - floatID := otu.createFloatEvent("find") - - otu.claimFloat("find", buyer, floatID) - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 10.0, 15.0, false, floatID, "find-admin", "find") - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) - packTypeId++ - }) - - t.Run("Should not be able to buy nft if the user doesnt have the float during the whitelist period, but can buy in public sale.", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - floatID := otu.createFloatEvent("find") - - // in the test, 0.0 whitelist time -> no whitelist - otu.registerPackType("user1", packTypeId, singleType, 0.0, 10.0, 15.0, false, floatID, "find-admin", "find") - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.O.Tx("buyFindPack", - WithSigner(buyer), - WithArg("packTypeName", buyer), - WithArg("packTypeId", packTypeId), - WithArg("numberOfPacks", 1), - WithArg("totalAmount", 4.2), - ). - AssertFailure(t, "Cannot buy the pack now") - - otu.tickClock(10.0) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) - packTypeId++ - }) - - t.Run("Should be able to register with adminRegisterFindPackMetadata transaction", func(t *testing.T) { - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - freeMintFloat := otu.createFloatEvent("find") - whiteListFloat := otu.createFloatEvent("find") - - otu.claimFloat("find", buyer, freeMintFloat) - otu.claimFloat("find", buyer, whiteListFloat) - - otu.O.Tx("adminRegisterFindPackMetadata", - WithSigner("find-admin"), - WithArg("forge", buyer), - WithArg("name", buyer), - WithArg("description", "test"), - WithArg("typeId", packTypeId), - WithArg("externalURL", "url"), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("bannerHash", "bannerHash"), - WithArg("social", map[string]string{"twitter": "twitterLink"}), - WithArg("wallet", "find-admin"), - WithArg("walletType", flow), - WithArg("openTime", 1.0), - WithAddresses("primaryRoyaltyRecipients", "find", "find-admin"), - WithArg("primaryRoyaltyCuts", []float64{0.1, 0.3}), - WithArg("primaryRoyaltyDescriptions", []string{"", ""}), - WithAddresses("secondaryRoyaltyRecipients", "find", "find-admin"), - WithArg("secondaryRoyaltyCuts", []float64{0.1, 0.3}), - WithArg("secondaryRoyaltyDescriptions", []string{"", ""}), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{"whiteList": 10.0, "pre-sale": 20.0, "public sale": 30.0}), - WithArg("endTime", map[string]float64{"whiteList": 20.0, "pre-sale": 30.0}), - WithArg("floatEventId", map[string]uint64{"whiteList": freeMintFloat, "pre-sale": whiteListFloat}), - WithArg("price", map[string]float64{"whiteList": 0.0, "pre-sale": 4.2, "public sale": 4.2}), - WithArg("purchaseLimit", map[string]uint64{"whiteList": 1, "pre-sale": 20}), - WithArg("packFields", map[string]string{ - "Items": "1", - }), - WithArg("nftTypes", []string{exampleNFTType(otu)}), - WithArg("storageRequirement", 50000), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 0.0) - // no need to pump packTypeId here - }) - - t.Run("Should be able to buy nft for different price", func(t *testing.T) { - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - freeMintFloat := otu.createFloatEvent("find") - whiteListFloat := otu.createFloatEvent("find") - - otu.claimFloat("find", buyer, freeMintFloat) - otu.claimFloat("find", buyer, whiteListFloat) - - otu.O.Tx("adminRegisterFindPackMetadata", - WithSigner("find-admin"), - WithArg("forge", buyer), - WithArg("name", buyer), - WithArg("description", "test"), - WithArg("typeId", packTypeId), - WithArg("externalURL", "url"), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("bannerHash", "bannerHash"), - WithArg("social", map[string]string{"twitter": "twitterLink"}), - WithArg("wallet", "find-admin"), - WithArg("walletType", flow), - WithArg("openTime", 1.0), - WithAddresses("primaryRoyaltyRecipients", "find", "find-admin"), - WithArg("primaryRoyaltyCuts", []float64{0.1, 0.3}), - WithArg("primaryRoyaltyDescriptions", []string{"", ""}), - WithAddresses("secondaryRoyaltyRecipients", "find", "find-admin"), - WithArg("secondaryRoyaltyCuts", []float64{0.1, 0.3}), - WithArg("secondaryRoyaltyDescriptions", []string{"", ""}), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{"whiteList": 10.0, "pre-sale": 20.0, "public sale": 30.0}), - WithArg("endTime", map[string]float64{"whiteList": 20.0, "pre-sale": 30.0}), - WithArg("floatEventId", map[string]uint64{"whiteList": freeMintFloat, "pre-sale": whiteListFloat}), - WithArg("price", map[string]float64{"whiteList": 0.0, "pre-sale": 4.2, "public sale": 4.2}), - WithArg("purchaseLimit", map[string]uint64{"whiteList": 1, "pre-sale": 20}), - WithArg("packFields", map[string]string{ - "Items": "1", - }), - WithArg("nftTypes", []string{exampleNFTType(otu)}), - WithArg("storageRequirement", 50000), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 0.0) - // no need to pump packTypeId here - }) - - t.Run("Should not be able to buy nft for free with free-mint Float more than allowed", func(t *testing.T) { - otu.O.Tx("buyFindPack", - WithSigner(buyer), - WithArg("packTypeName", buyer), - WithArg("packTypeId", packTypeId), - WithArg("numberOfPacks", 1), - WithArg("totalAmount", 0.0), - ). - AssertFailure(t, "Cannot buy the pack now") - packTypeId++ - }) - - // Tests on Royalty implementation - t.Run("Should have 0.15 cut to find", func(t *testing.T) { - - totalAmount := 4.2 - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - floatID := otu.createFloatEvent("find") - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 10.0, 15.0, false, floatID, "find-admin", "find") - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - otu.O.Tx("buyFindPack", - WithSigner(buyer), - WithArg("packTypeName", buyer), - WithArg("packTypeId", packTypeId), - WithArg("numberOfPacks", 1), - WithArg("totalAmount", 4.2), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FlowToken", "TokensDeposited"), map[string]interface{}{ - "amount": totalAmount * 0.15, - "to": otu.O.Address("find"), - }) - packTypeId++ - }) - - t.Run("Should be able to buy only if fulfills all verifiers specified", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - floatID := otu.createFloatEvent("find") - - // buyer should have find name "user1" and float - otu.O.Tx("devadminRegisterFindPackMetadataWithMultipleVerifier", - WithSigner("find-admin"), - WithArg("lease", "user1"), - WithArg("typeId", packTypeId), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("wallet", "find-admin"), - WithArg("openTime", 2.0), - WithArg("royaltyCut", 0.15), - WithArg("royaltyAddress", "find"), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{"public sale": 0.0}), - WithArg("endTime", map[string]float64{}), - WithArg("floatEventId", map[string]uint64{"public sale": floatID}), - WithArg("price", map[string]float64{"public sale": 4.20}), - WithArg("purchaseLimit", map[string]uint64{}), - WithArg("checkAll", true), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - // should not be able to buy with no float - otu.O.Tx("buyFindPack", - WithSigner(buyer), - WithArg("packTypeName", buyer), - WithArg("packTypeId", packTypeId), - WithArg("numberOfPacks", 1), - WithArg("totalAmount", 4.2), - ). - AssertFailure(t, "Cannot buy the pack now") - - // should be able to buy with user1 name and float - otu.claimFloat("find", buyer, floatID) - otu.buyPack(buyer, buyer, packTypeId, 1, 4.2) - - packTypeId++ - - }) - - t.Run("Should be able to buy if fulfills either verifiers specified", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - floatID := otu.createFloatEvent("find") - - // buyer should have find name "user1" or float - otu.O.Tx("devadminRegisterFindPackMetadataWithMultipleVerifier", - WithSigner("find-admin"), - WithArg("lease", "user1"), - WithArg("typeId", packTypeId), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("wallet", "find-admin"), - WithArg("openTime", 2.0), - WithArg("royaltyCut", 0.15), - WithArg("royaltyAddress", "find"), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{"public sale": 0.0}), - WithArg("endTime", map[string]float64{}), - WithArg("floatEventId", map[string]uint64{"public sale": floatID}), - WithArg("price", map[string]float64{"public sale": 4.20}), - WithArg("purchaseLimit", map[string]uint64{}), - WithArg("checkAll", false), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - // should be able to buy with user1 name only - otu.buyPack(buyer, buyer, packTypeId, 1, 4.2) - - packTypeId++ - - }) - - t.Run("Should be able to buy if fulfills either verifiers specified 2", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - floatID := otu.createFloatEvent("find") - - // buyer should have find name "user1" or float - otu.O.Tx("devadminRegisterFindPackMetadataWithMultipleVerifier", - WithSigner("find-admin"), - WithArg("lease", "user1"), - WithArg("typeId", packTypeId), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("wallet", "find-admin"), - WithArg("openTime", 2.0), - WithArg("royaltyCut", 0.15), - WithArg("royaltyAddress", "find"), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{"public sale": 0.0}), - WithArg("endTime", map[string]float64{}), - WithArg("floatEventId", map[string]uint64{"public sale": floatID}), - WithArg("price", map[string]float64{"public sale": 4.20}), - WithArg("purchaseLimit", map[string]uint64{}), - WithArg("checkAll", false), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - // should be able to buy with float only - otu.claimFloat("find", "user2", floatID) - otu.buyPack("user2", buyer, packTypeId, 1, 4.2) - - packTypeId++ - - }) - - t.Run("Should get the lowest price if several options are enabled at the same time", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - floatID := otu.createFloatEvent("find") - - // buyer should have find name "user1" or float - otu.O.Tx("devadminRegisterFindPackMetadataWithMultipleVerifier", - WithSigner("find-admin"), - WithArg("lease", "user1"), - WithArg("typeId", packTypeId), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("wallet", "find-admin"), - WithArg("openTime", 2.0), - WithArg("royaltyCut", 0.15), - WithArg("royaltyAddress", "find"), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{"whiteList": 0.0, "pre-sale": 0.0, "public sale": 0.0}), - WithArg("endTime", map[string]float64{}), - WithArg("floatEventId", map[string]uint64{"whiteList": floatID, "pre-sale": floatID, "public sale": floatID}), - WithArg("price", map[string]float64{"whiteList": 3.3, "pre-sale": 2.2, "public sale": 1.1}), - WithArg("purchaseLimit", map[string]uint64{}), - WithArg("checkAll", false), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - - otu.mintPack("user1", packTypeId, ids, singleType, salt) - - // should be able to buy with float only - otu.claimFloat("find", buyer, floatID) - otu.buyPack(buyer, buyer, packTypeId, 1, 1.1) - - packTypeId++ - - }) - - // buy with Reservation - t.Run("Should be able to buy with reservation", func(t *testing.T) { - - id1 := otu.mintExampleNFTs() - ids := []uint64{id1} - - otu.registerPackType("user1", packTypeId, singleType, 0.0, 0.0, 15.0, true, 0, "find-admin", "find") - packId, signature := otu.mintPackWithSignature("user1", packTypeId, ids, singleType, salt) - - otu.O.Tx("buyFindPackWithReservation", - WithSigner(buyer), - WithArg("packTypeName", buyer), - WithArg("packTypeId", packTypeId), - WithArg("packId", packId), - WithArg("amount", 4.2), - WithArg("signature", signature), - ). - Print(). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "Purchased"), map[string]interface{}{ - "packId": packId, - }) - - packTypeId++ - }) - - // Scripts - ways to return useful sales - t.Run("should return sale details for user", func(t *testing.T) { - + ot.Run(t, "Should be able to buy nft if the user has the float and with a whitelist.", func(t *testing.T) { floatID := otu.createFloatEvent("find") - - // buyer should have find name "user1" or float - otu.O.Tx("devadminRegisterFindPackMetadataWithMultipleVerifier", - WithSigner("find-admin"), - WithArg("lease", "user1"), - WithArg("typeId", packTypeId), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("wallet", "find-admin"), - WithArg("openTime", 2.0), - WithArg("royaltyCut", 0.15), - WithArg("royaltyAddress", "find"), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{"whiteList": 1.0, "pre-sale": 2.0, "public sale": 3.0}), - WithArg("endTime", map[string]float64{"whiteList": 2.0, "pre-sale": 3.0, "public sale": 4.0}), - WithArg("floatEventId", map[string]uint64{"whiteList": floatID, "pre-sale": floatID, "public sale": floatID}), - WithArg("price", map[string]float64{"whiteList": 3.3, "pre-sale": 2.2, "public sale": 1.1}), - WithArg("purchaseLimit", map[string]uint64{}), - WithArg("checkAll", false), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - - otu.O.Script("getAllFindPackSaleDetails", - WithArg("packTypeName", "user1"), - ). - AssertWithPointerWant(t, fmt.Sprintf("/%d", packTypeId), autogold.Want("getFindPackSaleDetails", map[string]interface{}{ - "collectionDisplay": map[string]interface{}{ - "bannerImage": map[string]interface{}{"file": map[string]interface{}{"url": "Example NFT banner image"}, "mediaType": "image"}, - "description": "Example NFT FIND", - "externalURL": map[string]interface{}{"url": "Example NFT external url"}, - "name": "user1 season #21", - "socials": map[string]interface{}{ - "Discord": map[string]interface{}{"url": "discord.gg/"}, - "Twitter": map[string]interface{}{"url": "https://twitter.com/home"}, - }, - "squareImage": map[string]interface{}{ - "file": map[string]interface{}{"url": "Example NFT square image"}, - "mediaType": "image", - }, - }, - "description": "user1 season #21", - "itemTypes": []interface{}{"A.179b6b1cb6755e31.ExampleNFT.NFT"}, - "name": "user1 season #21", - "openTime": 2, - "packFields": map[string]interface{}{"Items": "1"}, - "packsLeft": 0, - "requiresReservation": false, - "saleEnded": true, - "saleInfos": []interface{}{ - map[string]interface{}{ - "endTime": 3, - "name": "pre-sale", - "price": 2.2, - "startTime": 2, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5335", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - map[string]interface{}{ - "endTime": 4, - "name": "public sale", - "price": 1.1, - "startTime": 3, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5335", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - map[string]interface{}{ - "endTime": 2, - "name": "whiteList", - "price": 3.3, - "startTime": 1, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5335", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - }, - "storageRequirement": 10000, - "thumbnailHash": "thumbnailHash", - "walletType": "A.0ae53cb6e3f42a79.FlowToken.Vault", - })) - packTypeId++ - }) - floatID := otu.createFloatEvent("find") - - t.Run("Should get the running sale for user with the lowest price -> 2.2", func(t *testing.T) { - otu.claimFloat("find", buyer, floatID) - - // buyer should have find name "user1" or float - otu.O.Tx("devadminRegisterFindPackMetadataWithMultipleVerifier", - WithSigner("find-admin"), - WithArg("lease", "user1"), - WithArg("typeId", packTypeId), - WithArg("thumbnailHash", "thumbnailHash"), - WithArg("wallet", "find-admin"), - WithArg("openTime", 2.0), - WithArg("royaltyCut", 0.15), - WithArg("royaltyAddress", "find"), - WithArg("requiresReservation", false), - WithArg("startTime", map[string]float64{"whiteList": 1.0, "pre-sale": 2.0, "public sale": 3.0}), - WithArg("endTime", map[string]float64{"whiteList": 2.0}), - WithArg("floatEventId", map[string]uint64{"whiteList": floatID, "pre-sale": floatID}), - WithArg("price", map[string]float64{"whiteList": 1.1, "pre-sale": 2.2, "public sale": 3.3}), - WithArg("purchaseLimit", map[string]uint64{}), - WithArg("checkAll", false), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FindPack", "MetadataRegistered"), map[string]interface{}{ - "packTypeId": packTypeId, - }) - - otu.O.Script("getFindPackSaleDetailsWithUser", - WithArg("packTypeName", "user1"), - WithArg("packTypeId", packTypeId), - WithArg("user", buyer), - ). - AssertWant(t, autogold.Want("getFindPackSaleDetailsWithUser1", map[string]interface{}{ - "collectionDisplay": map[string]interface{}{ - "bannerImage": map[string]interface{}{"file": map[string]interface{}{"url": "Example NFT banner image"}, "mediaType": "image"}, - "description": "Example NFT FIND", - "externalURL": map[string]interface{}{"url": "Example NFT external url"}, - "name": "user1 season #22", - "socials": map[string]interface{}{ - "Discord": map[string]interface{}{"url": "discord.gg/"}, - "Twitter": map[string]interface{}{"url": "https://twitter.com/home"}, - }, - "squareImage": map[string]interface{}{ - "file": map[string]interface{}{"url": "Example NFT square image"}, - "mediaType": "image", - }, - }, - "description": "user1 season #22", - "itemTypes": []interface{}{"A.179b6b1cb6755e31.ExampleNFT.NFT"}, - "name": "user1 season #22", - "openTime": 2, - "packFields": map[string]interface{}{"Items": "1"}, - "packsLeft": 0, - "requiresReservation": false, - "saleInfos": []interface{}{ - map[string]interface{}{ - "name": "pre-sale", - "price": 2.2, - "startTime": 2, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5339", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - map[string]interface{}{ - "name": "public sale", - "price": 3.3, - "startTime": 3, - "verifyAll": false, - }, - map[string]interface{}{ - "endTime": 2, - "name": "whiteList", - "price": 1.1, - "startTime": 1, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5339", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - }, - "storageRequirement": 10000, - "thumbnailHash": "thumbnailHash", - "userQualifiedSale": map[string]interface{}{ - "canBuyNow": true, - "name": "pre-sale", - "price": 2.2, - "startTime": 2, - "userPurchaseRecord": 0, - }, - "walletType": "A.0ae53cb6e3f42a79.FlowToken.Vault", - })) - // no need to bump packTypeId here - }) - - t.Run("Should get the running sale for user with the lowest price -> 3.3", func(t *testing.T) { - - otu.O.Script("getFindPackSaleDetailsWithUser", - WithArg("packTypeName", "user1"), - WithArg("packTypeId", packTypeId), - WithArg("user", "user2"), - ). - AssertWant(t, autogold.Want("getFindPackSaleDetailsWithUser2", map[string]interface{}{ - "collectionDisplay": map[string]interface{}{ - "bannerImage": map[string]interface{}{"file": map[string]interface{}{"url": "Example NFT banner image"}, "mediaType": "image"}, - "description": "Example NFT FIND", - "externalURL": map[string]interface{}{"url": "Example NFT external url"}, - "name": "user1 season #22", - "socials": map[string]interface{}{ - "Discord": map[string]interface{}{"url": "discord.gg/"}, - "Twitter": map[string]interface{}{"url": "https://twitter.com/home"}, - }, - "squareImage": map[string]interface{}{ - "file": map[string]interface{}{"url": "Example NFT square image"}, - "mediaType": "image", - }, - }, - "description": "user1 season #22", - "itemTypes": []interface{}{"A.179b6b1cb6755e31.ExampleNFT.NFT"}, - "name": "user1 season #22", - "openTime": 2, - "packFields": map[string]interface{}{"Items": "1"}, - "packsLeft": 0, - "requiresReservation": false, - "saleInfos": []interface{}{ - map[string]interface{}{ - "name": "pre-sale", - "price": 2.2, - "startTime": 2, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5339", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - map[string]interface{}{ - "name": "public sale", - "price": 3.3, - "startTime": 3, - "verifyAll": false, - }, - map[string]interface{}{ - "endTime": 2, - "name": "whiteList", - "price": 1.1, - "startTime": 1, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5339", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - }, - "storageRequirement": 10000, - "thumbnailHash": "thumbnailHash", - "userQualifiedSale": map[string]interface{}{ - "canBuyNow": true, - "name": "public sale", - "price": 3.3, - "startTime": 3, - "userPurchaseRecord": 0, - }, - "walletType": "A.0ae53cb6e3f42a79.FlowToken.Vault", - })) - - }) - - t.Run("Should get all pack sale under a lease name type", func(t *testing.T) { - - otu.O.Script("getAllFindPackSaleDetails", - WithArg("packTypeName", "user1"), - ). - AssertWithPointerWant(t, "/"+fmt.Sprint(packTypeId), autogold.Want("getAllFindPackSaleDetails", map[string]interface{}{ - "collectionDisplay": map[string]interface{}{ - "bannerImage": map[string]interface{}{"file": map[string]interface{}{"url": "Example NFT banner image"}, "mediaType": "image"}, - "description": "Example NFT FIND", - "externalURL": map[string]interface{}{"url": "Example NFT external url"}, - "name": "user1 season #22", - "socials": map[string]interface{}{ - "Discord": map[string]interface{}{"url": "discord.gg/"}, - "Twitter": map[string]interface{}{"url": "https://twitter.com/home"}, - }, - "squareImage": map[string]interface{}{ - "file": map[string]interface{}{"url": "Example NFT square image"}, - "mediaType": "image", - }, - }, - "description": "user1 season #22", - "itemTypes": []interface{}{"A.179b6b1cb6755e31.ExampleNFT.NFT"}, - "name": "user1 season #22", - "openTime": 2, - "packFields": map[string]interface{}{"Items": "1"}, - "packsLeft": 0, - "requiresReservation": false, - "saleEnded": true, - "saleInfos": []interface{}{ - map[string]interface{}{ - "name": "pre-sale", - "price": 2.2, - "startTime": 2, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5339", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - map[string]interface{}{ - "name": "public sale", - "price": 3.3, - "startTime": 3, - "verifyAll": false, - }, - map[string]interface{}{ - "endTime": 2, - "name": "whiteList", - "price": 1.1, - "startTime": 1, - "verifiers": []interface{}{ - "User with one of these FLOATs are verified : 5339", - "Users with one of these find names are verified : user1", - }, - "verifyAll": false, - }, - }, - "storageRequirement": 10000, - "thumbnailHash": "thumbnailHash", - "walletType": "A.0ae53cb6e3f42a79.FlowToken.Vault", - })) - packTypeId++ - }) - - // Tests with 2 NFT Types - doubleTypes := []string{exampleNFTType(otu), dandyNFTType(otu)} - otu.mintThreeExampleDandies() - otu.registerFtInRegistry() - - find := otu.O.Address("find-admin") - otu.createUser(100.0, "find-admin") - - t.Run("Should be able to register pack data with 2 NFT Types", func(t *testing.T) { - - otu.registerPackType("user1", packTypeId, doubleTypes, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packTypeId++ - }) - - t.Run("Should be able to mint pack", func(t *testing.T) { - - example := otu.mintExampleNFTs() - dandy := otu.mintThreeExampleDandies()[0] - otu.sendDandy(find, "user1", dandy) - - otu.registerPackType("user1", packTypeId, doubleTypes, 0.0, 1.0, 1.0, false, 0, "find-admin", "find"). - mintPack("user1", packTypeId, []uint64{example, dandy}, doubleTypes, salt) - packTypeId++ - - }) - - t.Run("Should be able to buy pack with 2 NFT Types", func(t *testing.T) { - - example := otu.mintExampleNFTs() - dandy := otu.mintThreeExampleDandies()[0] - otu.sendDandy(find, "user1", dandy) - ids := []uint64{example, dandy} - - otu.registerPackType("user1", packTypeId, doubleTypes, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - otu.mintPack("user1", packTypeId, ids, doubleTypes, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) - packTypeId++ - - }) - - t.Run("Should be able to buy pack and open pack with 2 NFT Types", func(t *testing.T) { - - example := otu.mintExampleNFTs() - dandy := otu.mintThreeExampleDandies()[0] - otu.sendDandy(find, "user1", dandy) - ids := []uint64{example, dandy} - - otu.registerPackType("user1", packTypeId, doubleTypes, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packId := otu.mintPack("user1", packTypeId, ids, doubleTypes, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) - otu.openPack(buyer, packId) - packTypeId++ - - }) - - t.Run("Should be able to buy and open with 2 NFT Types", func(t *testing.T) { - - example := otu.mintExampleNFTs() - dandy := otu.mintThreeExampleDandies()[0] - otu.sendDandy(find, "user1", dandy) - ids := []uint64{example, dandy} - - otu.registerPackType("user1", packTypeId, doubleTypes, 0.0, 1.0, 1.0, false, 0, "find-admin", "find") - packId := otu.mintPack("user1", packTypeId, ids, doubleTypes, salt) - - otu.buyPack(buyer, buyer, packTypeId, 1, 4.20) - otu.openPack(buyer, packId) - - otu.O.Tx("adminFulfillFindPack", - WithSigner("find-admin"), - WithArg("packId", packId), - WithArg("typeIdentifiers", doubleTypes), - WithArg("rewardIds", ids), - WithArg("salt", salt), - ). - AssertSuccess(t). - AssertEvent(t, "Fulfilled", map[string]interface{}{ - "packId": packId, - }) - - packTypeId++ - }) + otu.registerPackType("user1", 2, []string{dandyIdentifier}, 0.0, 1.0, 1.0, false, floatID, "find-admin", "find") + otu.mintPack("user1", 2, packRewardIds, []string{dandyIdentifier}, packSalt) + otu.buyPack(buyer, buyer, 2, 1, 4.20) + }) + + //TODO:Dont want to bother with storage fillup now... + /* + ot.Run(t, "Should get transferred to DLQ if storage full", func(t *testing.T) { + otu.buyPack("user3", packTypeName, packTypeId, 1, 4.20) + otu.openPack("user3", packId) + + otu.O.Tx("devFillUpStorage", + WithSigner(buyer), + ).AssertSuccess(t) + + res := otu.O.FillUpStorage(buyer) + require.NoError(t, res.Error) + + fmt.Println(otu.O.GetFreeCapacity(buyer)) + + otu.O.Tx("adminFulfillFindPack", + WithSigner("find-admin"), + WithArg("packId", packId), + WithArg("typeIdentifiers", []string{dandyIdentifier}), + WithArg("rewardIds", packRewardIds), + WithArg("salt", packSalt), + ). + AssertSuccess(t). + AssertEvent(t, otu.identifier("FindPack", "FulfilledError"), map[string]interface{}{ + "packId": packId, + "address": otu.O.Address(buyer), + "reason": "Not enough flow to hold the content of the pack. Please top up your account", + }) + }) + */ } diff --git a/find_related_accounts_test.go b/find_related_accounts_test.go index 61e67b59..8e8fd167 100644 --- a/find_related_accounts_test.go +++ b/find_related_accounts_test.go @@ -1,10 +1,9 @@ package test_main import ( - "fmt" "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" "github.com/stretchr/testify/assert" ) @@ -13,15 +12,10 @@ import ( Tests must be in the same folder as flow.json with contracts and transactions/scripts in subdirectories in order for the path resolver to work correctly */ func TestRelatedAccounts(t *testing.T) { + otu := &OverflowTestUtils{T: t, O: ot.O} - otu := NewOverflowTest(t) - - otu.O.Tx("devsetupRelatedAccount", - WithSigner("user1"), - ). - AssertSuccess(t) - - t.Run("Should be able to get identifier", func(t *testing.T) { + ot.Run(t, "Should be able to get identifier", func(t *testing.T) { + otu.addRelatedAccount("user1", "Blocto", "ETH", "0x1") otu.O.Script("devgetRelatedAccountIdentifier", WithArg("user", "user1"), @@ -32,32 +26,19 @@ func TestRelatedAccounts(t *testing.T) { AssertWant(t, autogold.Want("ETH_Blocto_0x1", "ETH_Blocto_0x1")) }) - t.Run("Should be able to add wallet", func(t *testing.T) { + ot.Run(t, "Should be able to get Related wallet in network", func(t *testing.T) { otu.addRelatedAccount("user1", "Blocto", "ETH", "0x1") - otu.addRelatedAccount("user1", "Blocto", "ETH", "0x2") - otu.addRelatedAccount("user1", "Blocto", "ETH", "0x4") - otu.addRelatedAccount("user1", "Find", "ETH", "0x3") - otu.addRelatedAccount("user1", "Find", "ETH", "0x5") - }) - - t.Run("Should be able to add flow wallet", func(t *testing.T) { - otu.addRelatedAccount("user1", "Blocto", "Flow", "user2") - otu.addRelatedAccount("user1", "Blocto", "Flow", "user3") - otu.addRelatedAccount("user1", "Find", "Flow", "find") - - }) - - t.Run("Should be able to get Related wallet in network", func(t *testing.T) { - res := otu.O.Script("devgetRelatedAccounts", WithArg("user", "user1"), WithArg("network", "ETH"), - ). - AssertWant(t, autogold.Want("devgetRelatedAccounts : ETH", map[string]interface{}{"ETH_Blocto": []interface{}{"0x1", "0x2", "0x4"}, "ETH_Find": []interface{}{"0x3", "0x5"}})) + ).AssertWant(t, autogold.Want("devgetRelatedAccounts : ETH", map[string]interface{}{"ETH_Blocto": []interface{}{"0x1"}})) assert.NoError(t, res.Err) }) - t.Run("Should be able to get Related wallet in Flow", func(t *testing.T) { + ot.Run(t, "Should be able to get Related wallet in Flow", func(t *testing.T) { + otu.addRelatedAccount("user1", "Blocto", "Flow", "user2") + otu.addRelatedAccount("user1", "Blocto", "Flow", "user3") + otu.addRelatedAccount("user1", "Find", "Flow", "find") res := otu.O.Script("devgetRelatedFlowAccounts", WithArg("user", "user1"), @@ -66,126 +47,37 @@ func TestRelatedAccounts(t *testing.T) { assert.NoError(t, res.Err) }) - t.Run("Should be able to get all Related wallet in network", func(t *testing.T) { + ot.Run(t, "Should be able to get all Related wallet in network", func(t *testing.T) { + otu.addRelatedAccount("user1", "Blocto", "ETH", "0x1") + otu.addRelatedAccount("user1", "Blocto", "ETH", "0x2") + otu.addRelatedAccount("user1", "Blocto", "ETH", "0x4") + otu.addRelatedAccount("user1", "Find", "ETH", "0x3") + otu.addRelatedAccount("user1", "Find", "ETH", "0x5") + otu.addRelatedAccount("user1", "Blocto", "Flow", "user2") + otu.addRelatedAccount("user1", "Blocto", "Flow", "user3") + otu.addRelatedAccount("user1", "Find", "Flow", "find") - res := otu.O.Script("getAllRelatedAccounts", + res := otu.O.Script("devgetAllRelatedAccounts", WithArg("user", "user1"), ). AssertWant(t, autogold.Want("devgetAllRelatedFlowAccounts", map[string]interface{}{"ETH": map[string]interface{}{"ETH_Blocto": []interface{}{"0x1", "0x2", "0x4"}, "ETH_Find": []interface{}{"0x3", "0x5"}}, "Flow": map[string]interface{}{"Flow_Blocto": []interface{}{otu.O.Address("user2"), otu.O.Address("user3")}, "Flow_Find": []interface{}{otu.O.Address("find")}}})) assert.NoError(t, res.Err) }) - - t.Run("Should be able to update wallet", func(t *testing.T) { - otu.updateRelatedAccount("user1", "Blocto", "ETH", "0x1", "0x1000000") - }) - - t.Run("Should be able to get updated Related wallet in network", func(t *testing.T) { + ot.Run(t, "Should be able to update wallet", func(t *testing.T) { + otu.addRelatedAccount("user1", "Blocto", "ETH", "0x1") res := otu.O.Script("devgetRelatedAccounts", WithArg("user", "user1"), WithArg("network", "ETH"), - ). - AssertWant(t, autogold.Want("devgetRelatedAccounts : ETH", map[string]interface{}{"ETH_Blocto": []interface{}{"0x2", "0x4", "0x1000000"}, "ETH_Find": []interface{}{"0x3", "0x5"}})) - assert.NoError(t, res.Err) - }) - - t.Run("Should be able to update flow wallet", func(t *testing.T) { - otu.updateRelatedAccount("user1", "Blocto", "Flow", "user3", "user1") - }) - - t.Run("Should be able to get updated Related wallet in Flow", func(t *testing.T) { - - res := otu.O.Script("devgetRelatedFlowAccounts", - WithArg("user", "user1"), - ). - AssertWant(t, autogold.Want("devgetRelatedFlowAccounts : Flow", map[string]interface{}{"Flow_Blocto": []interface{}{otu.O.Address("user2"), otu.O.Address("user1")}, "Flow_Find": []interface{}{otu.O.Address("find")}})) + ).AssertWant(t, autogold.Want("devgetRelatedAccounts : ETH", map[string]interface{}{"ETH_Blocto": []interface{}{"0x1"}})) assert.NoError(t, res.Err) - }) - t.Run("Should be able to remove wallet", func(t *testing.T) { - otu.removeRelatedAccount("user1", "Blocto", "ETH", "0x1000000") - }) - - t.Run("Should be able to get updated Related wallet in network", func(t *testing.T) { + otu.updateRelatedAccount("user1", "Blocto", "ETH", "0x1", "0x1000000") - res := otu.O.Script("devgetRelatedAccounts", + res = otu.O.Script("devgetRelatedAccounts", WithArg("user", "user1"), WithArg("network", "ETH"), - ). - AssertWant(t, autogold.Want("devgetRelatedAccounts : ETH", map[string]interface{}{"ETH_Blocto": []interface{}{"0x2", "0x4"}, "ETH_Find": []interface{}{"0x3", "0x5"}})) - assert.NoError(t, res.Err) - }) - - t.Run("Should be able to remove flow wallet", func(t *testing.T) { - otu.removeRelatedAccount("user1", "Blocto", "Flow", "user1") - }) - - t.Run("Should be able to get updated Related wallet in Flow", func(t *testing.T) { - - res := otu.O.Script("devgetRelatedFlowAccounts", - WithArg("user", "user1"), - ). - AssertWant(t, autogold.Want("devgetRelatedFlowAccounts : Flow", map[string]interface{}{"Flow_Blocto": []interface{}{otu.O.Address("user2")}, "Flow_Find": []interface{}{otu.O.Address("find")}})) + ).AssertWant(t, autogold.Want("devgetRelatedAccounts : ETH", map[string]interface{}{"ETH_Blocto": []interface{}{"0x1000000"}})) assert.NoError(t, res.Err) }) - - type TestCases struct { - network string - address string - want autogold.Value - } - - testCases := []TestCases{ - { - network: "Flow", - address: otu.O.Address("user3"), - want: autogold.Want("user3 false", false), - }, - { - network: "Flow", - address: otu.O.Address("user1"), - want: autogold.Want("user1 false", false), - }, - { - network: "Flow", - address: otu.O.Address("user2"), - want: autogold.Want("user2 true", true), - }, - { - network: "ETH", - address: "0x1000000", - want: autogold.Want("0x1000000 false", false), - }, - { - network: "ETH", - address: "0x1", - want: autogold.Want("0x1 false", false), - }, - { - network: "ETH", - address: "0x2", - want: autogold.Want("0x2 true", true), - }, - { - network: "Aptos", - address: "0x1", - want: autogold.Want("Aptos false", false), - }, - } - - for _, tc := range testCases { - t.Run(fmt.Sprintf("Should be able to verify with related accounts on network, testCase : %s", tc.want.Name()), func(t *testing.T) { - - res := otu.O.Script("devgetVerifyRelatedAccounts", - WithArg("user", "user1"), - WithArg("network", tc.network), - WithArg("address", tc.address), - ). - AssertWant(t, tc.want) - assert.NoError(t, res.Err) - - }) - } - } - \ No newline at end of file diff --git a/find_struct_test.go b/find_struct_test.go index 330d4866..3c8b4620 100644 --- a/find_struct_test.go +++ b/find_struct_test.go @@ -3,18 +3,17 @@ package test_main import ( "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/findonflow/find/findGo" ) func TestFindStruct(t *testing.T) { + otu := &OverflowTestUtils{T: t, O: ot.O} - otu := NewOverflowTest(t) - - t.Run("Should be able to pass in Royalty Struct", func(t *testing.T) { + ot.Run(t, "Should be able to pass in Royalty Struct", func(t *testing.T) { otu.O.Tx( ` - import FindPack from "../contracts/FindPack.cdc" + import "FindPack" transaction(i: FindPack.Royalty) {} `, @@ -29,10 +28,10 @@ func TestFindStruct(t *testing.T) { AssertSuccess(t) }) - t.Run("Should be able to pass in Verifier Struct", func(t *testing.T) { + ot.Run(t, "Should be able to pass in Verifier Struct", func(t *testing.T) { otu.O.Tx( ` - import FindVerifier from "../contracts/FindVerifier.cdc" + import "FindVerifier" transaction(i: {FindVerifier.Verifier}) {} `, @@ -45,10 +44,10 @@ func TestFindStruct(t *testing.T) { AssertSuccess(t) }) - t.Run("Should be able to pass in PackRegisterSaleInfo Struct", func(t *testing.T) { + ot.Run(t, "Should be able to pass in PackRegisterSaleInfo Struct", func(t *testing.T) { otu.O.Tx( ` - import FindPack from "../contracts/FindPack.cdc" + import "FindPack" transaction(i: FindPack.PackRegisterSaleInfo) {} `, @@ -68,10 +67,10 @@ func TestFindStruct(t *testing.T) { AssertSuccess(t) }) - t.Run("Should be able to pass in PackRegisterInfo Struct", func(t *testing.T) { + ot.Run(t, "Should be able to pass in PackRegisterInfo Struct", func(t *testing.T) { otu.O.Tx( ` - import FindPack from "../contracts/FindPack.cdc" + import "FindPack" transaction(i: FindPack.PackRegisterInfo) {} `, @@ -82,5 +81,4 @@ func TestFindStruct(t *testing.T) { ). AssertSuccess(t) }) - } diff --git a/find_test.go b/find_test.go index 63e9469e..dd38331b 100644 --- a/find_test.go +++ b/find_test.go @@ -3,7 +3,7 @@ package test_main import ( "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" "github.com/stretchr/testify/assert" ) @@ -12,136 +12,125 @@ import ( Tests must be in the same folder as flow.json with contracts and transactions/scripts in subdirectories in order for the path resolver to work correctly */ func TestFIND(t *testing.T) { - otu := NewOverflowTest(t). - setupFIND(). - createUser(100.0, "user1"). - registerUser("user1") - - t.Run("Should be able to register a name", func(t *testing.T) { - // Can fix this with pointerWant - otu.O.Script("getLeases").AssertWithPointerWant(t, "/0/name", - autogold.Want("allLeases", "user1"), - ) + otu := &OverflowTestUtils{T: t, O: ot.O} + + // these users have profiles and names + user1Address := otu.O.Address("user1") + user2Address := otu.O.Address("user2") + + // this user has a profile but no name + user3Address := otu.O.Address("user3") + + // this use does not have a profile at all + user4Address := otu.O.Address("user4") + + ot.Run(t, "Should be able to renew lease", func(t *testing.T) { + otu.O.Tx("cleanUpInvalidatedLease", + WithSigner("user1"), + WithArg("names", []string{"user1"}), + ). + AssertFailure(t, "This is a valid lease. You cannot clean this up") + + otu.expireLease().expireLease().tickClock(2.0) + otu.O.Tx("cleanUpInvalidatedLease", + + WithSigner("user1"), + WithArg("names", []string{"user1"}), + ).AssertSuccess(t) }) - t.Run("Should get error if you try to register a name and dont have enough money", func(t *testing.T) { - otu.O.Tx("register", + ot.Run(t, "Should be able to renew nam", func(t *testing.T) { + otu.O.Tx("renewName", WithSigner("user1"), - WithArg("name", "usr"), - WithArg("amount", 500.0), - ).AssertFailure(t, "Amount withdrawn must be less than or equal than the balance of the Vault") + WithArg("name", "user1"), + WithArg("maxAmount", 10.5), + ).AssertSuccess(t) }) - t.Run("Should get error if you try to register a name that is too short", func(t *testing.T) { + ot.Run(t, "Should get error if you try to register a name that is too short", func(t *testing.T) { otu.O.Tx("register", WithSigner("user1"), WithArg("name", "ur"), - WithArg("amount", 5.0), + WithArg("maxAmount", 10.0), ).AssertFailure(t, "A FIND name has to be lower-cased alphanumeric or dashes and between 3 and 16 characters") }) - t.Run("Should get error if you try to register a name that is already claimed", func(t *testing.T) { + ot.Run(t, "Should get error if you try to register a name that is already claimed", func(t *testing.T) { otu.O.Tx("register", WithSigner("user1"), WithArg("name", "user1"), - WithArg("amount", 5.0), + WithArg("maxAmount", 10.0), ).AssertFailure(t, "Name already registered") }) - t.Run("Should allow registering a lease after it is freed", func(t *testing.T) { + ot.Run(t, "Should allow registering a lease after it is freed", func(t *testing.T) { otu.expireLease().tickClock(2.0) otu.O.Tx(` - import FIND from "../contracts/FIND.cdc" - - transaction(name: String) { - - prepare(account: AuthAccount) { - let status=FIND.status(name) - if status.status == FIND.LeaseStatus.LOCKED { - panic("locked") - } - if status.status == FIND.LeaseStatus.FREE { - panic("free") - } - } - } - `, + import "FIND" + + transaction(name: String) { + + prepare(account: &Account) { + let status=FIND.status(name) + if status.status == FIND.LeaseStatus.LOCKED { + panic("locked") + } + if status.status == FIND.LeaseStatus.FREE { + panic("free") + } + } + } + `, WithSigner("user1"), WithArg("name", "user1"), ).AssertFailure(t, "locked"). AssertComputationLessThenOrEqual(t, 1000) - - otu.expireLease() - otu.registerUser("user1") }) - t.Run("Should be able to lookup address", func(t *testing.T) { - otu.assertLookupAddress("user1", otu.O.Address("user1")) + ot.Run(t, "Should be able to lookup address", func(t *testing.T) { + ot.O.Script(`import "FIND" +access(all) fun main(name: String) : Address? { + return FIND.lookupAddress(name) } `, + WithArg("name", "user1"), + ).AssertWant(otu.T, autogold.Want("lookupAddress-user1", user1Address)) }) - t.Run("Should not be able to lookup lease after expired", func(t *testing.T) { - otu.expireLease(). - tickClock(2.0) + ot.Run(t, "Should not be able to lookup lease after expired", func(t *testing.T) { + otu.expireLease().tickClock(2.0) otu.O.Script("getNameStatus", WithArg("name", "user1"), - ). - AssertWant(t, autogold.Want("getNameStatus n", nil)) + ).AssertWant(t, autogold.Want("getNameStatus", nil)) }) - t.Run("Admin should be able to register without paying FUSD", func(t *testing.T) { + ot.Run(t, "Admin should be able to register without paying", func(t *testing.T) { otu.O.Tx("adminRegisterName", WithSigner("find-admin"), - WithArg("names", `["find-admin"]`), + WithArg("names", `["find-admin2"]`), WithArg("user", "find"), ). AssertSuccess(t). AssertEvent(t, otu.identifier("FIND", "Register"), map[string]interface{}{ - "name": "find-admin", + "name": "find-admin2", }) }) - otu.renewUserWithName("user1", "user1"). - createUser(100.0, "user2"). - registerUser("user2") - - t.Run("Should be able to send lease to another name", func(t *testing.T) { - otu.O.Tx("moveNameTO", - WithSigner("user1"), - WithArg("name", "user1"), - WithArg("receiver", "user2"), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FIND", "Moved"), map[string]interface{}{ - "name": "user1", - }) - }) - - t.Run("Should automatically set Find name to empty if sender have none", func(t *testing.T) { + ot.Run(t, "Should automatically set Find name to empty if sender have none", func(t *testing.T) { otu.O.Script("getName", - WithArg("address", "user1"), - ). - AssertWant(t, autogold.Want("getName empty", nil)) - - otu.moveNameTo("user2", "user1", "user1") + WithArg("address", "user3"), + ).AssertWant(t, autogold.Want("getName empty", nil)) }) - t.Run("Should automatically set Find Name if sender have one", func(t *testing.T) { - otu.registerUserWithName("user1", "name1"). - moveNameTo("user1", "user2", "user1") + ot.Run(t, "Should automatically set Find Name if sender have one", func(t *testing.T) { + otu.registerUserWithName("user3", "name1") otu.O.Script("getName", - WithArg("address", "user1"), - ). - AssertWant(t, autogold.Want("getName empty", "name1")) - - otu.moveNameTo("user2", "user1", "user1") + WithArg("address", "user3"), + ).AssertWant(t, autogold.Want("getName", "name1")) }) - otu.setProfile("user2") - - t.Run("Should be able to register related account and remove it", func(t *testing.T) { + ot.Run(t, "Should be able to register related account and remove it", func(t *testing.T) { otu.O.Tx("setRelatedAccount", WithSigner("user1"), WithArg("name", "dapper"), @@ -150,22 +139,21 @@ func TestFIND(t *testing.T) { AssertSuccess(t). AssertEvent(t, otu.identifier("FindRelatedAccounts", "RelatedAccount"), map[string]interface{}{ "walletName": "dapper", - "user": otu.O.Address("user1"), - "address": otu.O.Address("user2"), + "user": user1Address, + "address": user2Address, "action": "add", }) otu.O.Script("getFindStatus", WithArg("user", "user1"), - ). - AssertWithPointerWant(t, "/accounts/0", - autogold.Want("getFindStatus Dapper", map[string]interface{}{ - "address": otu.O.Address("user2"), - "name": "dapper", - "network": "Flow", - "node": "FindRelatedAccounts", - "trusted": false, - })) + ).AssertWithPointerWant(t, "/accounts/0", + autogold.Want("getFindStatus Dapper", map[string]interface{}{ + "address": otu.O.Address("user2"), + "name": "dapper", + "network": "Flow", + "node": "FindRelatedAccounts", + "trusted": false, + })) otu.O.Tx("removeRelatedAccount", WithSigner("user1"), @@ -188,7 +176,7 @@ func TestFIND(t *testing.T) { "Object has no key 'accounts'") }) - t.Run("Should be able to set private mode", func(t *testing.T) { + ot.Run(t, "Should be able to set private mode", func(t *testing.T) { otu.O.Tx("setPrivateMode", WithSigner("user1"), WithArg("mode", true), @@ -214,45 +202,17 @@ func TestFIND(t *testing.T) { ) }) - t.Run("Should be able to getFindStatus of new user", func(t *testing.T) { - nameAddress := otu.O.Address("user3") - otu.O.Script("getFindStatus", - WithArg("user", nameAddress), - ).AssertWant(t, - autogold.Want("getFindStatus", map[string]interface{}{ - "activatedAccount": true, "hasLostAndFoundItem": false, - "isDapper": false, - "privateMode": false, - "readyForWearables": false, - }), - ) - }) - - t.Run("Should be able to getFindPaths of a user", func(t *testing.T) { - nameAddress := otu.O.Address("user1") - otu.O.Script("getFindPaths", - WithArg("user", nameAddress), - ).AssertWant(t, - autogold.Want("getFindPaths", map[string]interface{}{"address": "0xf669cb8d41ce0c74", "paths": []interface{}{ - "findDandy", - "A_179b6b1cb6755e31_FindMarketDirectOfferEscrow_SaleItemCollection_find", - "FindPackCollection", - }}), - ) - }) - - t.Run("If a user holds an invalid find name, get status should not return it", func(t *testing.T) { - nameAddress := otu.O.Address("user2") + ot.Run(t, "If a user holds an invalid find name, get status should not return it", func(t *testing.T) { otu.moveNameTo("user2", "user1", "user2") otu.O.Script("getFindStatus", - WithArg("user", nameAddress), + WithArg("user", user2Address), ).AssertWithPointerError(t, "/profile/findName", "Object has no key 'findName'", ) }) - t.Run("Should be able to create and edit the social link", func(t *testing.T) { + ot.Run(t, "Should be able to create and edit the social link", func(t *testing.T) { otu.O.Tx("editProfile", WithSigner("user1"), WithArg("name", "user1"), @@ -300,85 +260,34 @@ func TestFIND(t *testing.T) { ) }) - t.Run("Should be able to buy addons that are on Network", func(t *testing.T) { - user := "user1" - - otu.buyForge(user) - - /* Should not be able to buy addons with wrong balance */ + ot.Run(t, "Should not be able to buy forge for less then amount", func(t *testing.T) { otu.O.Tx("buyAddon", - WithSigner("user1"), - WithArg("name", "name1"), + WithSigner("user2"), + WithArg("name", "user2"), WithArg("addon", "forge"), - WithArg("amount", 10.0), - ). - AssertFailure(t, "Expect 50.00000000 FUSD for forge addon") - - /* Should not be able to buy addons that does not exist */ - otu.O.Tx("buyAddon", - WithSigner(user), - WithArg("name", user), - WithArg("addon", dandyNFTType(otu)), - WithArg("amount", 10.0), + WithArg("maxAmount", 10.0), ). - AssertFailure(t, "This addon is not available.") + AssertFailure(t, "You have not sent in enough max flow") }) - t.Run("Should be able to fund users without profile", func(t *testing.T) { - user := "user1" - otu.registerFtInRegistry() - - user3 := otu.O.Address("user3") - otu.O.Tx("sendFT", - WithSigner(user), - WithArg("name", user3), - WithArg("amount", 10.0), - WithArg("ftAliasOrIdentifier", "Flow"), - WithArg("tag", `""`), - WithArg("message", `""`), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FungibleTokenSent") + ot.Run(t, "Should be able to buy addons that are on Network", func(t *testing.T) { + otu.buyForge("user2") }) - t.Run("Should be able to fund users with profile but without find name", func(t *testing.T) { - user := "user1" - otu.createUser(1000, "user3") - - user3 := otu.O.Address("user3") - - otu.O.Tx("sendFT", - WithSigner(user), - WithArg("name", user3), - WithArg("amount", 10.0), - WithArg("ftAliasOrIdentifier", "Flow"), - WithArg("tag", `""`), - WithArg("message", `""`), - ). - AssertSuccess(t). - AssertEmitEventName(t, "FungibleTokenSent") - - otu.O.Tx("sendFT", - WithSigner("user3"), - WithArg("name", user), - WithArg("amount", 10.0), - WithArg("ftAliasOrIdentifier", "Flow"), - WithArg("tag", `""`), - WithArg("message", `""`), + ot.Run(t, "Should not be able to buy unavaialbe addon", func(t *testing.T) { + otu.O.Tx("buyAddon", + WithSigner("user1"), + WithArg("name", "user1"), + WithArg("addon", "foo"), + WithArg("maxAmount", 10.0), ). - AssertSuccess(t). - AssertEmitEventName(t, "FungibleTokenSent") + AssertFailure(t, "This addon is not available.") }) - t.Run("Should be able to fund users without profile wallet, but with vault proper set up", func(t *testing.T) { - user := "user1" - - user3 := otu.O.Address("user3") - otu.removeProfileWallet("user3") - + ot.Run(t, "Should be able to fund users without profile", func(t *testing.T) { otu.O.Tx("sendFT", - WithSigner(user), - WithArg("name", user3), + WithSigner("user1"), + WithArg("name", user4Address), WithArg("amount", 10.0), WithArg("ftAliasOrIdentifier", "Flow"), WithArg("tag", `""`), @@ -386,10 +295,12 @@ func TestFIND(t *testing.T) { ). AssertSuccess(t). AssertEmitEventName(t, "FungibleTokenSent") + }) + ot.Run(t, "Should be able to fund users with profile but without find name", func(t *testing.T) { otu.O.Tx("sendFT", - WithSigner("user3"), - WithArg("name", user), + WithSigner("user1"), + WithArg("name", user3Address), WithArg("amount", 10.0), WithArg("ftAliasOrIdentifier", "Flow"), WithArg("tag", `""`), @@ -399,14 +310,14 @@ func TestFIND(t *testing.T) { AssertEmitEventName(t, "FungibleTokenSent") }) - t.Run("Should be able to resolve find name without .find", func(t *testing.T) { + ot.Run(t, "Should be able to resolve find name with .find", func(t *testing.T) { otu.O.Script("resolve", WithArg("name", "user1.find"), ). AssertWant(t, autogold.Want("user 1 address", otu.O.Address("user1"))) }) - t.Run("Should panic if user pass in invalid character '.'", func(t *testing.T) { + ot.Run(t, "Should panic if user pass in invalid character '.'", func(t *testing.T) { _, err := otu.O.Script("resolve", WithArg("name", "user1.fn"), ). @@ -416,56 +327,53 @@ func TestFIND(t *testing.T) { assert.Contains(t, err.Error(), "invalid byte in hex string") }) - t.Run("Should be able to getFindStatus of an FREE lease", func(t *testing.T) { + ot.Run(t, "Should be able to getFindStatus of an FREE lease", func(t *testing.T) { res := otu.O.Script("getNameSearchbar", WithArg("name", "lease"), - ). - AssertWant(t, autogold.Want("getNameSearchbar, FREE", map[string]interface{}{"cost": 5, "status": "FREE"})) + ).AssertWant(t, autogold.Want("getNameSearchbar, FREE", map[string]interface{}{ + "cost": 5, + "status": "FREE", + })) assert.NoError(t, res.Err) }) - t.Run("Should be able to getFindStatus of an TAKEN lease", func(t *testing.T) { + ot.Run(t, "Should be able to getFindStatus of an TAKEN lease", func(t *testing.T) { otu.registerUserWithName("user1", "lease") res := otu.O.Script("getNameSearchbar", WithArg("name", "lease"), - ). - AssertWant(t, autogold.Want("getNameSearchbar, TAKEN", map[string]interface{}{ - "cost": 5, - "lockedUntil": 1.33920005e+08, - "owner": "0xf669cb8d41ce0c74", - "avatar": "This is avatar", - "registeredTime": 9.4608005e+07, - "status": "TAKEN", - "validUntil": 1.26144005e+08, - })) + ).AssertWant(t, autogold.Want("getNameSearchbar, TAKEN", map[string]interface{}{ + "avatar": "https://find.xyz/assets/img/avatars/avatar14.png", + "cost": 5, + "lockedUntil": 3.9312001e+07, + "owner": "0x192440c99cb17282", + "registeredTime": 1, + "status": "TAKEN", + "validUntil": 3.1536001e+07, + })) assert.NoError(t, res.Err) }) - t.Run("Should be able to getFindStatus of an LOCKED lease", func(t *testing.T) { + ot.Run(t, "Should be able to getFindStatus of an LOCKED lease", func(t *testing.T) { + otu.registerUserWithName("user1", "lease") otu.expireLease() res := otu.O.Script("getNameSearchbar", WithArg("name", "lease"), ). Print(). AssertWant(t, autogold.Want("getFindStatus, LOCKED", map[string]interface{}{ - "avatar": "This is avatar", + "avatar": "https://find.xyz/assets/img/avatars/avatar14.png", "cost": 5, - "lockedUntil": 1.33920005e+08, - "owner": "0xf669cb8d41ce0c74", - "registeredTime": 9.4608005e+07, + "lockedUntil": 3.9312001e+07, + "owner": "0x192440c99cb17282", + "registeredTime": 1, "status": "LOCKED", - "validUntil": 1.26144005e+08, + "validUntil": 3.1536001e+07, })) assert.NoError(t, res.Err) }) - user1Address := otu.O.Address("user1") - user2Address := otu.O.Address("user2") - user3Address := otu.O.Address("user3") - otu.expireLease().tickClock(2.0) - otu.registerUser("user1") - t.Run("Should be able to register related account and mutually link it for trust", func(t *testing.T) { + ot.Run(t, "Should be able to register related account and mutually link it for trust", func(t *testing.T) { otu.O.Tx("setRelatedAccount", WithSigner("user1"), WithArg("name", "link"), @@ -540,7 +448,7 @@ func TestFIND(t *testing.T) { AssertSuccess(t) }) - t.Run("Should be able to getFindStatus for trusted accounts", func(t *testing.T) { + ot.Run(t, "Should be able to getFindStatus for trusted accounts", func(t *testing.T) { otu.O.Tx("setRelatedAccount", WithSigner("user1"), WithArg("name", "link"), @@ -569,14 +477,14 @@ func TestFIND(t *testing.T) { AssertWithPointerWant(t, "/accounts", autogold.Want("with accounts", `[]interface {}{ map[string]interface {}{ - "address": "0xfd43f9148d4b725d", + "address": "0xeb179c27144f783c", "name": "notLink", "network": "Flow", "node": "FindRelatedAccounts", "trusted": false, }, map[string]interface {}{ - "address": "0x192440c99cb17282", + "address": "0xfd43f9148d4b725d", "name": "link", "network": "Flow", "node": "FindRelatedAccounts", @@ -584,8 +492,8 @@ func TestFIND(t *testing.T) { }, }`)) }) - otu.registerUser("user2") - t.Run("Should be able to follow someone", func(t *testing.T) { + + ot.Run(t, "Should be able to follow someone", func(t *testing.T) { otu.O.Tx( "follow", WithSigner("user1"), @@ -601,7 +509,7 @@ func TestFIND(t *testing.T) { }) }) - t.Run("Should be able to unfollow someone", func(t *testing.T) { + ot.Run(t, "Should be able to unfollow someone", func(t *testing.T) { otu.O.Tx( "unfollow", WithSigner("user1"), @@ -616,186 +524,90 @@ func TestFIND(t *testing.T) { }) }) - oldOwner := "user1" - currentOwner := "user2" - testingName := "testingname" - - // setup for testing old leases - otu.registerUserWithName(oldOwner, testingName) - otu.listNameForSale(oldOwner, testingName) - otu.O.Tx("listNameForAuction", - WithSigner(oldOwner), - WithArg("name", testingName), - WithArg("auctionStartPrice", 5.0), - WithArg("auctionReservePrice", 20.0), - WithArg("auctionDuration", auctionDurationFloat), - WithArg("auctionExtensionOnLateBid", 300.0), - ). - AssertSuccess(t) - - otu.expireLease(). - expireLease(). - tickClock(2.0) - - otu.registerUserWithName(currentOwner, testingName) - - t.Run("Should not be able to move old leases", func(t *testing.T) { - // should be able to move name to other user - otu.moveNameTo(currentOwner, "user3", "testingname") - otu.moveNameTo("user3", currentOwner, "testingname") + ot.Run(t, "Should not be able to move old leases", func(t *testing.T) { + otu.expireLease().expireLease().tickClock(2.0) // should not be able to move name to other user otu.O.Tx("moveNameTO", - WithSigner(oldOwner), - WithArg("name", testingName), - WithArg("receiver", otu.O.Address("user3")), + WithSigner("user1"), + WithArg("name", "user1"), + WithArg("receiver", user2Address), ). - AssertFailure(t, "This is not a valid lease. Lease already expires and some other user registered it. Lease : testingname") + AssertFailure(t, "This is not a valid lease. Lease already expires and some other user registered it. Lease : user1") }) - t.Run("Should not be able to get old leases information", func(t *testing.T) { + ot.Run(t, "Should not be able to get old leases information", func(t *testing.T) { + otu.expireLease().expireLease().tickClock(2.0) + otu.O.Script(` - import FIND from "../contracts/FIND.cdc" + import "FIND" - pub fun main(user: Address) : [FIND.LeaseInformation] { - let finLeases= getAuthAccount(user).borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! - return finLeases.getLeaseInformation() - } - `, - WithArg("user", oldOwner), + access(all) fun main(user: Address) : [FIND.LeaseInformation] { + let finLeases= getAccount(user).capabilities.borrow<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)! + return finLeases.getLeaseInformation() + } + `, + WithArg("user", "user1"), ). AssertWant(t, autogold.Want("should be nil", nil)) }) - t.Run("Should not be able to get old leases", func(t *testing.T) { - otu.O.Script(` - import FIND from "../contracts/FIND.cdc" - - pub fun main(user: Address) : [String] { - let finLeases= getAuthAccount(user).borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! - return finLeases.getLeases() - } - `, - WithArg("user", oldOwner), - ). - AssertWant(t, autogold.Want("should be nil for lease name", `[]interface {}{ - "user1", - "lease", - "name1", -}`)) - }) + ot.Run(t, "Should not be able to get old leases", func(t *testing.T) { + otu.expireLease().expireLease().tickClock(2.0) - t.Run("Should be able to get old leases in getInvalidatedLeases", func(t *testing.T) { otu.O.Script(` - import FIND from "../contracts/FIND.cdc" - - pub fun main(user: Address) : [String] { - let finLeases= getAuthAccount(user).borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! - return finLeases.getInvalidatedLeases() - } - `, - WithArg("user", oldOwner), - ). - AssertWant(t, autogold.Want("should not be nil for lease name", `[]interface {}{ - "user2", - "testingname", -}`)) - }) + import "FIND" - t.Run("Should not be able to list old leases for sale", func(t *testing.T) { - // should be able to list name for sale - otu.O.Tx("listNameForSale", - WithSigner(currentOwner), - WithArg("name", testingName), - WithArg("directSellPrice", 10.0), - ).AssertSuccess(t) - - // should not be able to list name for sale - otu.O.Tx("listNameForSale", - WithSigner(oldOwner), - WithArg("name", testingName), - WithArg("directSellPrice", 10.0), + access(all) fun main(user: Address) : [String] { + let finLeases= getAccount(user).capabilities.borrow<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)! + return finLeases.getLeases() + } + `, + WithArg("user", "user1"), ). - AssertFailure(t, "This is not a valid lease. Lease already expires and some other user registered it. Lease : testingname") + AssertWant(t, autogold.Want("should not be able to get old leases", nil)) }) - t.Run("Should not be able to list old leases for auction", func(t *testing.T) { - // should be able to list name for auction - otu.O.Tx("listNameForAuction", - WithSigner(currentOwner), - WithArg("name", testingName), - WithArg("auctionStartPrice", 5.0), - WithArg("auctionReservePrice", 20.0), - WithArg("auctionDuration", auctionDurationFloat), - WithArg("auctionExtensionOnLateBid", 300.0), - ). - AssertSuccess(t) + ot.Run(t, "Should be able to get old leases in getInvalidatedLeases", func(t *testing.T) { + otu.expireLease().expireLease().tickClock(2.0) - // should not be able to list name for auction - otu.O.Tx("listNameForAuction", - WithSigner(oldOwner), - WithArg("name", testingName), - WithArg("auctionStartPrice", 5.0), - WithArg("auctionReservePrice", 20.0), - WithArg("auctionDuration", auctionDurationFloat), - WithArg("auctionExtensionOnLateBid", 300.0), - ). - AssertFailure(t, "This is not a valid lease. Lease already expires and some other user registered it. Lease : testingname") - }) - - t.Run("Should be able to delist old leases for sale", func(t *testing.T) { - // should be able to delist name for sale - otu.O.Tx("delistNameSale", - WithSigner(currentOwner), - WithArg("names", []string{testingName}), - ). - AssertSuccess(t) + otu.O.Script(` + import "FIND" - // should be able to delist name for sale - otu.O.Tx("delistNameSale", - WithSigner(oldOwner), - WithArg("names", []string{testingName}), + access(all) fun main(user: Address) : [String] { + let finLeases= getAccount(user).capabilities.borrow<&{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath)! + return finLeases.getInvalidatedLeases() + } + `, + WithArg("user", "user1"), ). - AssertSuccess(t) - }) - - t.Run("Should be able to delist old leases for auction", func(t *testing.T) { - otu.O.Tx("cancelNameAuction", - WithSigner(currentOwner), - WithArg("names", []string{testingName}), - ).AssertSuccess(t) - - otu.O.Tx("cancelNameAuction", - WithSigner(oldOwner), - WithArg("names", []string{testingName}), - ).AssertSuccess(t) + AssertWant(t, autogold.Want("should get invalid leases", `[]interface {}{ + "user1", +}`)) }) - t.Run("Should be able to cleanup invalid leases", func(t *testing.T) { + ot.Run(t, "Should be able to cleanup invalid leases", func(t *testing.T) { otu.O.Tx("cleanUpInvalidatedLease", - WithSigner(currentOwner), - WithArg("names", []string{testingName}), + WithSigner("user1"), + WithArg("names", []string{"user1"}), ). - AssertFailure(t, "This is a valid lease. You cannot clean this up. Lease : testingname") + AssertFailure(t, "This is a valid lease. You cannot clean this up") + otu.expireLease().expireLease().tickClock(2.0) otu.O.Tx("cleanUpInvalidatedLease", - WithSigner(oldOwner), - WithArg("names", []string{testingName}), + + WithSigner("user1"), + WithArg("names", []string{"user1"}), ).AssertSuccess(t) }) - t.Run("Should be able to register a name with usdc", func(t *testing.T) { - otu.O.Tx("registerUSDC", - WithSigner("user1"), - WithArg("name", "fooobar"), - WithArg("amount", 5.0), - ).AssertSuccess(t). - AssertEvent(otu.T, "FIND.Register", map[string]interface{}{ - "name": "fooobar", - }). - AssertEvent(otu.T, "FiatToken.TokensDeposited", map[string]interface{}{ - "amount": 5.0, - "to": otu.O.Address("find-admin"), - }) + ot.Run(t, "Should be able to resgister name without profile", func(t *testing.T) { + otu.O.Tx("register", + WithSigner("user4"), + WithArg("name", "user4"), + WithArg("maxAmount", 10.0), + ).AssertSuccess(t) + + otu.O.Script("validUser", WithArg("user", "user4")).AssertWant(t, autogold.Want("should be valid", true)) }) } diff --git a/find_thought_test.go b/find_thought_test.go index ea1528a1..394a04d7 100644 --- a/find_thought_test.go +++ b/find_thought_test.go @@ -3,97 +3,47 @@ package test_main import ( "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" "github.com/onflow/cadence" "github.com/stretchr/testify/assert" ) func TestFindThought(t *testing.T) { + otu := &OverflowTestUtils{T: t, O: ot.O} - otu := NewOverflowTest(t). - setupFIND(). - setupDandy("user1"). - createUser(100.0, "user2"). - registerUser("user2"). - setProfile("user1"). - setProfile("user2") - - otu.setUUID(10000) - - header := "This is header" - body := "This is body" - tags := []string{"tag1", "tag2", "@find"} - mediaHash := "ipfs://mediaHash" - mediaUrl := "mediaUrl" - mediaType := "mediaType" - var thoguhtId uint64 - - cadMediaHash, err := otu.createOptional(mediaHash) + // this is a strange pattern... + user1 := ot.O.FlowAddress("user1").Bytes() + user1Bytes := cadence.BytesToAddress(user1) + user := cadence.NewOptional(user1Bytes) + inputId, err := otu.createOptional(dandyIds[0]) assert.NoError(t, err) - cadMediaUrl, err := otu.createOptional(mediaUrl) - assert.NoError(t, err) - cadMediaType, err := otu.createOptional(mediaType) + inputIdentifier, err := otu.createOptional(dandyIdentifier) assert.NoError(t, err) - t.Run("Should be able to post a thought", func(t *testing.T) { - var err error + ot.Run(t, "Should be able to post a thought", func(t *testing.T) { + thoughtId := otu.postExampleThought() - thoguhtId, err = otu.O.Tx("publishFindThought", - WithSigner("user1"), - WithArg("header", header), - WithArg("body", body), - WithArg("tags", tags), - WithArg("mediaHash", cadMediaHash), - WithArg("mediaType", cadMediaType), - WithArg("quoteNFTOwner", nil), - WithArg("quoteNFTType", nil), - WithArg("quoteNFTId", nil), - WithArg("quoteCreator", nil), - WithArg("quoteId", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindThoughts.Published", map[string]interface{}{ - "creator": otu.O.Address("user1"), - "creatorName": "user1", - "header": header, - "message": body, - "medias": []interface{}{ - mediaHash, - }, - "tags": []interface{}{"tag1", "tag2", "@find"}, - }). - GetIdFromEvent("Published", "id") + var data []ThoughtData + err := otu.O.Script("getFindThoughts", + WithAddresses("addresses", "user1"), + WithArg("ids", []uint64{thoughtId}), + ).MarshalAs(&data) assert.NoError(t, err) + autogold.Equal(t, data) }) - if thoguhtId == 0 { - thoguhtId, _ = otu.O.Tx("publishFindThought", - WithSigner("user1"), - WithArg("header", header), - WithArg("body", body), - WithArg("tags", tags), - WithArg("mediaHash", cadMediaHash), - WithArg("mediaType", cadMediaType), - WithArg("quoteNFTOwner", nil), - WithArg("quoteNFTType", nil), - WithArg("quoteNFTId", nil), - WithArg("quoteCreator", nil), - WithArg("quoteId", nil), - ). - GetIdFromEvent("Published", "id") - } - newHeader := "This is new header" newBody := "This is new body" newTags := []string{"tag4", "tag5", "@fest"} - t.Run("Should be able to edit a thought", func(t *testing.T) { + ot.Run(t, "Should be able to edit a thought", func(t *testing.T) { + thoughtId := otu.postExampleThought() otu.O.Tx("editFindThought", WithSigner("user1"), - WithArg("id", thoguhtId), + WithArg("id", thoughtId), WithArg("header", newHeader), WithArg("body", newBody), WithArg("tags", newTags), @@ -104,77 +54,32 @@ func TestFindThought(t *testing.T) { "creatorName": "user1", "header": newHeader, "message": newBody, - "medias": []interface{}{ - mediaHash, - }, - "tags": []interface{}{"tag4", "tag5", "@fest"}, + "tags": []interface{}{"tag4", "tag5", "@fest"}, }) }) - t.Run("Should be able to react to a thought", func(t *testing.T) { - - otu.O.Tx("reactToFindThoughts", - WithSigner("user2"), - WithArg("users", []string{"user1"}), - WithArg("ids", []uint64{thoguhtId}), - WithArg("reactions", []string{"fire"}), - WithArg("undoReactionUsers", `[]`), - WithArg("undoReactionIds", `[]`), - ). - AssertSuccess(t). - AssertEvent(t, "FindThoughts.Reacted", map[string]interface{}{ - "id": thoguhtId, - "by": otu.O.Address("user2"), - "byName": "user2", - "creator": otu.O.Address("user1"), - "creatorName": "user1", - "header": newHeader, - "reaction": "fire", - "totalCount": map[string]interface{}{ - "fire": 1, - }, - }) + ot.Run(t, "Should be able to react to a thought", func(t *testing.T) { + thoughtId := otu.postExampleThought() + otu.reactToThought(thoughtId, "fire") }) - t.Run("Should be able to change reaction to a thought", func(t *testing.T) { + ot.Run(t, "Should be able to get a list of different thoguhts by a script with reacted list", func(t *testing.T) { + thoughtId := otu.postExampleThought() + otu.reactToThought(thoughtId, "fire") - otu.O.Tx("reactToFindThoughts", - WithSigner("user2"), - WithArg("users", []string{"user1"}), - WithArg("ids", []uint64{thoguhtId}), - WithArg("reactions", []string{"sad"}), - WithArg("undoReactionUsers", `[]`), - WithArg("undoReactionIds", `[]`), - ). - AssertSuccess(t). - AssertEvent(t, "FindThoughts.Reacted", map[string]interface{}{ - "id": thoguhtId, - "by": otu.O.Address("user2"), - "byName": "user2", - "creator": otu.O.Address("user1"), - "creatorName": "user1", - "header": newHeader, - "reaction": "sad", - "totalCount": map[string]interface{}{ - "sad": 1, - }, - }) - }) - - t.Run("Should be able to get a list of different thoguhts by a script with reacted list", func(t *testing.T) { - - res, err := otu.O.Script("getFindThoughts", + var data []ThoughtData + err := otu.O.Script("getFindThoughts", WithAddresses("addresses", "user1"), - WithArg("ids", []uint64{thoguhtId}), - ). - GetAsJson() + WithArg("ids", []uint64{thoughtId}), + ).MarshalAs(&data) assert.NoError(t, err) - - autogold.Equal(t, res) + autogold.Equal(t, data) }) - t.Run("Should be able to undo reaction to a thought", func(t *testing.T) { + ot.Run(t, "Should be able to undo reaction to a thought", func(t *testing.T) { + thoughtId := otu.postExampleThought() + otu.reactToThought(thoughtId, "fire") otu.O.Tx("reactToFindThoughts", WithSigner("user2"), @@ -182,117 +87,55 @@ func TestFindThought(t *testing.T) { WithArg("ids", `[]`), WithArg("reactions", `[]`), WithArg("undoReactionUsers", []string{"user1"}), - WithArg("undoReactionIds", []uint64{thoguhtId}), + WithArg("undoReactionIds", []uint64{thoughtId}), ). AssertSuccess(t). AssertEvent(t, "FindThoughts.Reacted", map[string]interface{}{ - "id": thoguhtId, + "id": thoughtId, "by": otu.O.Address("user2"), "byName": "user2", "creator": otu.O.Address("user1"), "creatorName": "user1", - "header": newHeader, }) }) - t.Run("Should be able to get thoguht by a script", func(t *testing.T) { - - res, err := otu.O.Script("getOwnedFindThoughts", - WithArg("address", "user1"), - ). - GetAsJson() - - assert.NoError(t, err) - - autogold.Equal(t, res) - }) - - t.Run("Should be able to delete a thought", func(t *testing.T) { + ot.Run(t, "Should be able to delete a thought", func(t *testing.T) { + thoughtId := otu.postExampleThought() otu.O.Tx("deleteFindThoughts", WithSigner("user1"), - WithArg("ids", []uint64{thoguhtId}), + WithArg("ids", []uint64{thoughtId}), ). AssertSuccess(t). AssertEvent(t, "FindThoughts.Deleted", map[string]interface{}{ "creator": otu.O.Address("user1"), "creatorName": "user1", - "header": newHeader, - "message": newBody, - "medias": []interface{}{ - mediaHash, - }, - "tags": []interface{}{"tag4", "tag5", "@fest"}, }) }) - t.Run("Should be able to post a thought with Url", func(t *testing.T) { - var err error - - thoguhtId, err = otu.O.Tx("publishFindThought", - WithSigner("user1"), - WithArg("header", header), - WithArg("body", body), - WithArg("tags", tags), - WithArg("mediaHash", cadMediaUrl), - WithArg("mediaType", cadMediaType), - WithArg("quoteNFTOwner", nil), - WithArg("quoteNFTType", nil), - WithArg("quoteNFTId", nil), - WithArg("quoteCreator", nil), - WithArg("quoteId", nil), - ). - AssertSuccess(t). - AssertEvent(t, "FindThoughts.Published", map[string]interface{}{ - "creator": otu.O.Address("user1"), - "creatorName": "user1", - "header": header, - "message": body, - "medias": []interface{}{ - mediaUrl, - }, - "tags": []interface{}{"tag1", "tag2", "@find"}, - }). - GetIdFromEvent("Published", "id") - - assert.NoError(t, err) - }) - - t.Run("Should be able to post a thought with NFT", func(t *testing.T) { - - id := otu.mintThreeExampleDandies()[0] - identifier := dandyNFTType(otu) - owner := otu.O.FlowAddress("user1").Bytes() - - otu.registerDandyInNFTRegistry() - - inputId, err := otu.createOptional(id) - assert.NoError(t, err) - inputIdentifier, err := otu.createOptional(identifier) - assert.NoError(t, err) - Owner := cadence.BytesToAddress(owner) - inputOwner := cadence.NewOptional(Owner) - + ot.Run(t, "Should be able to post a thought with NFT", func(t *testing.T) { nftInfo, err := otu.O.Script(` - import MetadataViews from "../contracts/standard/MetadataViews.cdc" - import FindMarket from "../contracts/FindMarket.cdc" - import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" - import FindViews from "../contracts/FindViews.cdc" - - pub fun main(quoteNFTOwner: Address?, quoteNFTType: String?, quoteNFTId: UInt64?) : FindMarket.NFTInfo? { - - var nftPointer : FindViews.ViewReadPointer? = nil - if quoteNFTOwner != nil { - let path = FINDNFTCatalog.getCollectionDataForType(nftTypeIdentifier: quoteNFTType!)?.publicPath ?? panic("This nft type is not supported by NFT Catalog. Type : ".concat(quoteNFTType!)) - let cap = getAccount(quoteNFTOwner!).getCapability<&{MetadataViews.ResolverCollection}>(path) - nftPointer = FindViews.ViewReadPointer(cap: cap, id: quoteNFTId!) - let rv = nftPointer!.getViewResolver() - return FindMarket.NFTInfo(rv, id: nftPointer!.id, detail: true) + import "MetadataViews" + import "ViewResolver" + import "NonFungibleToken" + import "FindMarket" + import "FINDNFTCatalog" + import "FindViews" + + access(all) fun main(quoteNFTOwner: Address?, quoteNFTType: String?, quoteNFTId: UInt64?) : FindMarket.NFTInfo? { + + var nftPointer : FindViews.ViewReadPointer? = nil + if quoteNFTOwner != nil { + let path = FINDNFTCatalog.getCollectionDataForType(nftTypeIdentifier: quoteNFTType!)?.publicPath ?? panic("This nft type is not supported by NFT Catalog. Type : ".concat(quoteNFTType!)) + let cap = getAccount(quoteNFTOwner!).capabilities.get<&{NonFungibleToken.Collection}>(path)! + nftPointer = FindViews.ViewReadPointer(cap: cap, id: quoteNFTId!) + let rv = nftPointer!.getViewResolver() + return FindMarket.NFTInfo(rv, id: nftPointer!.id, detail: true) + } + return nil } - return nil - } - `, - WithArg("quoteNFTOwner", inputOwner), + `, + WithArg("quoteNFTOwner", user), WithArg("quoteNFTType", inputIdentifier), WithArg("quoteNFTId", inputId), ). @@ -300,14 +143,14 @@ func TestFindThought(t *testing.T) { assert.NoError(t, err) - otu.O.Tx("publishFindThought", + thoughtId, _ := otu.O.Tx("publishFindThought", WithSigner("user1"), - WithArg("header", header), - WithArg("body", body), - WithArg("tags", tags), + WithArg("header", "head"), + WithArg("body", "body"), + WithArg("tags", []string{"tag1", "tag2", "@find"}), WithArg("mediaHash", nil), WithArg("mediaType", nil), - WithArg("quoteNFTOwner", inputOwner), + WithArg("quoteNFTOwner", user), WithArg("quoteNFTType", inputIdentifier), WithArg("quoteNFTId", inputId), WithArg("quoteCreator", nil), @@ -317,125 +160,98 @@ func TestFindThought(t *testing.T) { AssertEvent(t, "FindThoughts.Published", map[string]interface{}{ "creator": otu.O.Address("user1"), "creatorName": "user1", - "header": header, - "message": body, "nfts": []interface{}{nftInfo}, "tags": []interface{}{"tag1", "tag2", "@find"}, - }) - }) - - var thoughtWithQuote uint64 + }). + GetIdFromEvent("FindThoughts.Published", "id") - t.Run("Should be able to post a thought with quote", func(t *testing.T) { + var data []ThoughtData + err = otu.O.Script("getFindThoughts", + WithAddresses("addresses", "user1"), + WithArg("ids", []uint64{thoughtId}), + ).MarshalAs(&data) - owner := otu.O.FlowAddress("user1").Bytes() - Owner := cadence.BytesToAddress(owner) - inputOwner := cadence.NewOptional(Owner) + assert.NoError(t, err) + autogold.Equal(t, data) + }) - inputThoughtId, err := otu.createOptional(thoguhtId) + ot.Run(t, "Should be able to post a thought with quote", func(t *testing.T) { + thoughtId := otu.postExampleThought() + inputThoughtId, err := otu.createOptional(thoughtId) assert.NoError(t, err) thought, err := otu.O.Tx("publishFindThought", WithSigner("user1"), - WithArg("header", header), - WithArg("body", body), - WithArg("tags", tags), + WithArg("header", "header"), + WithArg("body", "body"), + WithArg("tags", []string{"tag1"}), WithArg("mediaHash", nil), WithArg("mediaType", nil), WithArg("quoteNFTOwner", nil), WithArg("quoteNFTType", nil), WithArg("quoteNFTId", nil), - WithArg("quoteCreator", inputOwner), + WithArg("quoteCreator", user), WithArg("quoteId", inputThoughtId), ). AssertSuccess(t). AssertEvent(t, "FindThoughts.Published", map[string]interface{}{ "creator": otu.O.Address("user1"), "creatorName": "user1", - "header": header, - "message": body, - "tags": []interface{}{"tag1", "tag2", "@find"}, + "tags": []interface{}{"tag1"}, "quoteOwner": otu.O.Address("user1"), - "quoteId": thoguhtId, + "quoteId": thoughtId, }). GetIdFromEvent("FindThoughts.Published", "id") assert.NoError(t, err) - thoughtWithQuote = thought - }) - - if thoughtWithQuote == 0 { - owner := otu.O.FlowAddress("user1").Bytes() - Owner := cadence.BytesToAddress(owner) - inputOwner := cadence.NewOptional(Owner) - - inputThoughtId, _ := otu.createOptional(thoguhtId) - - thought, _ := otu.O.Tx("publishFindThought", - WithSigner("user1"), - WithArg("header", header), - WithArg("body", body), - WithArg("tags", tags), - WithArg("mediaHash", nil), - WithArg("mediaType", nil), - WithArg("quoteNFTOwner", nil), - WithArg("quoteNFTType", nil), - WithArg("quoteNFTId", nil), - WithArg("quoteCreator", inputOwner), - WithArg("quoteId", inputThoughtId), - ). - GetIdFromEvent("FindThoughts.Published", "id") - - thoughtWithQuote = thought - } - - t.Run("Should be able to get a list of different thoguhts with quoted thoughts", func(t *testing.T) { - - res, err := otu.O.Script("getFindThoughts", + var data []ThoughtData + err = otu.O.Script("getFindThoughts", WithAddresses("addresses", "user1"), - WithArg("ids", []uint64{thoughtWithQuote}), - ). - GetAsJson() + WithArg("ids", []uint64{thought}), + ).MarshalAs(&data) assert.NoError(t, err) - - autogold.Equal(t, res) + autogold.Equal(t, data) }) - t.Run("Should be able to hide thoughts", func(t *testing.T) { + ot.Run(t, "Should be able to hide thoughts", func(t *testing.T) { + thoughtId := otu.postExampleThought() otu.O.Tx("hideFindThoughts", WithSigner("user1"), - WithArg("ids", []uint64{thoughtWithQuote}), + WithArg("ids", []uint64{thoughtId}), WithArg("hide", []bool{true}), ). AssertSuccess(t). AssertEvent(t, "Edited", map[string]interface{}{ - "id": thoughtWithQuote, + "id": thoughtId, "hide": true, }) - }) - - otu.O.Tx("reactToFindThoughts", - WithSigner("user2"), - WithArg("users", []string{"user1"}), - WithArg("ids", []uint64{thoguhtId}), - WithArg("reactions", []string{"fire"}), - WithArg("undoReactionUsers", `[]`), - WithArg("undoReactionIds", `[]`), - ). - AssertSuccess(t) - - t.Run("Should be able to get a list of owned thoguhts with hidden status", func(t *testing.T) { - res, err := otu.O.Script("getOwnedFindThoughts", + var data []ThoughtData + err := otu.O.Script("getOwnedFindThoughts", WithArg("address", "user1"), - ). - GetAsJson() + ).MarshalAs(&data) assert.NoError(t, err) - - autogold.Equal(t, res) + autogold.Equal(t, data) }) +} +type ThoughtData struct { + Body string `json:"body"` + Created int `json:"created"` + Creator string `json:"creator"` + CreatorAvatar string `json:"creatorAvatar"` + CreatorName string `json:"creatorName"` + CreatorProfileName string `json:"creatorProfileName"` + Header string `json:"header"` + Hidden bool `json:"hidden"` + Medias map[string]string `json:"medias"` + Reacted interface{} `json:"reacted"` + ReactedUsers interface{} `json:"reactedUsers"` + Reactions map[string]string `json:"reactions"` + Tags []string `json:"tags"` + QuotedThought *ThoughtData `json:"quotedThought"` + NFT []NftDetail `json:"nft"` } diff --git a/find_utils_test.go b/find_utils_test.go index dce82394..fabbe799 100644 --- a/find_utils_test.go +++ b/find_utils_test.go @@ -1,29 +1,26 @@ package test_main import ( - "fmt" "strings" "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" "github.com/onflow/cadence" "github.com/sanity-io/litter" - "github.com/stretchr/testify/assert" ) func TestFindUtils(t *testing.T) { - - otu := NewOverflowTest(t) + otu := &OverflowTestUtils{T: t, O: ot.O} o := otu.O - devCheckContainsChar := `import FindUtils from "../contracts/FindUtils.cdc" + devCheckContainsChar := `import "FindUtils" - pub fun main(string: String, char:Character) : Bool { + access(all) fun main(string: String, char:Character) : Bool { return FindUtils.containsChar(string, char: char) }` // containsChar - t.Run("containsChar should return false if string does not contain", func(t *testing.T) { + ot.Run(t, "containsChar should return false if string does not contain", func(t *testing.T) { o.Script(devCheckContainsChar, WithArg("string", "bam.find"), WithArg("char", cadence.Character(",")), @@ -31,7 +28,7 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("false", false)) }) - t.Run("containsChar should return true if string contains", func(t *testing.T) { + ot.Run(t, "containsChar should return true if string contains", func(t *testing.T) { o.Script(devCheckContainsChar, WithArg("string", "bam.find"), WithArg("char", cadence.Character(".")), @@ -39,14 +36,14 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("true", true)) }) - devCheckContains := `import FindUtils from "../contracts/FindUtils.cdc" + devCheckContains := `import "FindUtils" - pub fun main(string: String, element:String) : Bool { + access(all) fun main(string: String, element:String) : Bool { return FindUtils.contains(string, element: element) }` // contains - t.Run("contains should be able to check contains", func(t *testing.T) { + ot.Run(t, "contains should be able to check contains", func(t *testing.T) { o.Script(devCheckContains, WithArg("string", "string"), WithArg("element", "string"), @@ -54,7 +51,7 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("true", true)) }) - t.Run("contains should return false if string does not contain", func(t *testing.T) { + ot.Run(t, "contains should return false if string does not contain", func(t *testing.T) { o.Script(devCheckContains, WithArg("string", "string"), WithArg("element", "stt"), @@ -62,7 +59,7 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("false", false)) }) - t.Run("contains should return true if string partially contains", func(t *testing.T) { + ot.Run(t, "contains should return true if string partially contains", func(t *testing.T) { o.Script(devCheckContains, WithArg("string", "string"), WithArg("element", "ing"), @@ -94,9 +91,9 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("false", false)) }) - devCheckHasSuffix := `import FindUtils from "../contracts/FindUtils.cdc" + devCheckHasSuffix := `import "FindUtils" - pub fun main(string: String, suffix:String) : Bool { + access(all) fun main(string: String, suffix:String) : Bool { return FindUtils.hasSuffix(string, suffix: suffix) }` @@ -141,9 +138,9 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("false", false)) }) - devCheckHasPrefix := `import FindUtils from "../contracts/FindUtils.cdc" + devCheckHasPrefix := `import "FindUtils" - pub fun main(string: String, prefix:String) : Bool { + access(all) fun main(string: String, prefix:String) : Bool { return FindUtils.hasPrefix(string, prefix: prefix) }` @@ -196,9 +193,9 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("false", false)) }) - devCheckToUpper := `import FindUtils from "../contracts/FindUtils.cdc" + devCheckToUpper := `import "FindUtils" - pub fun main(string: String) : String { + access(all) fun main(string: String) : String { return FindUtils.toUpper(string) } ` @@ -220,9 +217,9 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("if they are already upper cases", strings.ToUpper(s))) }) - devCheckFirstUpperLetter := `import FindUtils from "../contracts/FindUtils.cdc" + devCheckFirstUpperLetter := `import "FindUtils" - pub fun main(string: String) : String { + access(all) fun main(string: String) : String { return FindUtils.firstUpperLetter(string) } ` @@ -252,9 +249,9 @@ func TestFindUtils(t *testing.T) { AssertWant(t, autogold.Want("should returns same if first letter is already upper case", s)) }) - dev_check_to_snake_case := `import FindUtils from "../contracts/FindUtils.cdc" + dev_check_to_snake_case := `import "FindUtils" -pub fun main(string: String) : String { +access(all) fun main(string: String) : String { return FindUtils.to_snake_case(string) } ` @@ -284,9 +281,9 @@ pub fun main(string: String) : String { AssertWant(t, autogold.Want("Camel case", "camel_case")) }) - devCheckToCamelCase := `import FindUtils from "../contracts/FindUtils.cdc" + devCheckToCamelCase := `import "FindUtils" -pub fun main(string: String) : String { +access(all) fun main(string: String) : String { return FindUtils.toCamelCase(string) } ` @@ -324,9 +321,9 @@ pub fun main(string: String) : String { AssertWant(t, autogold.Want("Camel case", "camelCase")) }) - devTrimSuffix := `import FindUtils from "../contracts/FindUtils.cdc" + devTrimSuffix := `import "FindUtils" -pub fun main(string: String, suffix:String) : String { +access(all) fun main(string: String, suffix:String) : String { return FindUtils.trimSuffix(string, suffix:suffix) } ` @@ -357,9 +354,9 @@ pub fun main(string: String, suffix:String) : String { // Extra tests on trimFindSuffix on FIND - devTrimFindSuffix := `import FIND from "../contracts/FIND.cdc" + devTrimFindSuffix := `import "FIND" -pub fun main(name: String) : String { +access(all) fun main(name: String) : String { return FIND.trimFindSuffix(name) } ` @@ -378,9 +375,9 @@ pub fun main(name: String) : String { }) // splitString - devSplitString := `import FindUtils from "../contracts/FindUtils.cdc" + devSplitString := `import "FindUtils" - pub fun main(string: String, sep: Character) : [String] { + access(all) fun main(string: String, sep: Character) : [String] { return FindUtils.splitString(string, sep:sep) } ` @@ -417,9 +414,9 @@ pub fun main(name: String) : String { }) // joinMapToString - devJoinMapToString := `import FindUtils from "../contracts/FindUtils.cdc" + devJoinMapToString := `import "FindUtils" -pub fun main(map: {String : String}) : String { +access(all) fun main(map: {String : String}) : String { return FindUtils.joinMapToString(map) } ` @@ -435,9 +432,9 @@ pub fun main(map: {String : String}) : String { }) // joinString - devJoinString := `import FindUtils from "../contracts/FindUtils.cdc" + devJoinString := `import "FindUtils" -pub fun main(s: [String], sep: String) : String { +access(all) fun main(s: [String], sep: String) : String { return FindUtils.joinString(s, sep:sep) } ` @@ -452,50 +449,4 @@ pub fun main(s: [String], sep: String) : String { ). AssertWant(t, autogold.Want("devJoinString : 1+1=2 2+2=4 3*3=9", "1+1=2 2+2=4 3*3=9")) }) - - // deDupTypeArray - devDeDupTypeArray := `import FindUtils from "../contracts/FindUtils.cdc" - -pub fun main(s: [String]) : [Type] { - var typ : [Type] = [] - for t in s { - typ.append(CompositeType(t)!) - } - return FindUtils.deDupTypeArray(typ) -} -` - t.Run("deDupTypeArray should dedup duplicated as expected", func(t *testing.T) { - flow, err := o.QualifiedIdentifier("FlowToken", "Vault") - assert.NoError(t, err) - ft, err := o.QualifiedIdentifier("FungibleToken", "Vault") - assert.NoError(t, err) - nft, err := o.QualifiedIdentifier("NonFungibleToken", "NFT") - assert.NoError(t, err) - collection, err := o.QualifiedIdentifier("NonFungibleToken", "Collection") - assert.NoError(t, err) - o.Script(devDeDupTypeArray, - WithArg("s", []string{ - flow, - ft, - nft, - nft, - collection, - flow, - flow, - flow, - ft, - ft, - ft, - nft, - nft, - }), - ). - AssertWant(t, autogold.Want("deDupTypeArray : flow, ft, nft, collection", fmt.Sprintf(`[]interface {}{ - "%s", - "%s", - "%s", - "%s", -}`, flow, ft, nft, collection))) - }) - } diff --git a/find_verifier_test.go b/find_verifier_test.go index 1884bbac..ff8ab583 100644 --- a/find_verifier_test.go +++ b/find_verifier_test.go @@ -4,23 +4,17 @@ import ( "fmt" "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/hexops/autogold" "github.com/stretchr/testify/assert" ) func TestFindVerifier(t *testing.T) { - + otu := &OverflowTestUtils{T: t, O: ot.O} user := "user1" - otu := NewOverflowTest(t). - setupFIND(). - createUser(10000.0, "user1"). - registerUser("user1") - // Has One FLOAT - t.Run("Should return false if user have no float", func(t *testing.T) { - + ot.Run(t, "Should return false if user have no float", func(t *testing.T) { floatID := otu.createFloatEvent("find") otu.O.Script("devFindVerifierHasOneFLOAT", @@ -33,8 +27,7 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should panic if no float is specified", func(t *testing.T) { - + ot.Run(t, "Should panic if no float is specified", func(t *testing.T) { _, err := otu.O.Script("devFindVerifierHasOneFLOAT", WithArg("user", otu.O.Address(user)), WithArg("floatIDs", []uint64{}), @@ -42,11 +35,9 @@ func TestFindVerifier(t *testing.T) { GetAsInterface() assert.Error(t, err) - }) - t.Run("Should return true if user has one of the float", func(t *testing.T) { - + ot.Run(t, "Should return true if user has one of the float", func(t *testing.T) { floatID := otu.createFloatEvent("find") otu.claimFloat("find", user, floatID) @@ -61,8 +52,7 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should return false if user doesn't have float contained", func(t *testing.T) { - + ot.Run(t, "Should return false if user doesn't have float contained", func(t *testing.T) { claimedFloatID := otu.createFloatEvent("find") notClaimedFloatID := otu.createFloatEvent("find") @@ -79,8 +69,7 @@ func TestFindVerifier(t *testing.T) { }) // Has All FLOAT - t.Run("Should return true if user has all of the float", func(t *testing.T) { - + ot.Run(t, "Should return true if user has all of the float", func(t *testing.T) { floatID := otu.createFloatEvent("find") floatID2 := otu.createFloatEvent("find") @@ -97,8 +86,7 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should return false if user doesn't have all float contained", func(t *testing.T) { - + ot.Run(t, "Should return false if user doesn't have all float contained", func(t *testing.T) { floatID := otu.createFloatEvent("find") floatID2 := otu.createFloatEvent("find") @@ -115,8 +103,7 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should panic if no float is specified", func(t *testing.T) { - + ot.Run(t, "Should panic if no float is specified", func(t *testing.T) { _, err := otu.O.Script("devFindVerifierHasAllFLOAT", WithArg("user", otu.O.Address(user)), WithArg("floatIDs", []uint64{}), @@ -127,8 +114,7 @@ func TestFindVerifier(t *testing.T) { }) // WhiteLabel - t.Run("Should return true if user is in whiteLabel", func(t *testing.T) { - + ot.Run(t, "Should return true if user is in whiteLabel", func(t *testing.T) { otu.O.Script("devFindVerifierIsInWhiteList", WithArg("user", otu.O.Address(user)), WithAddresses("addresses", user, "user2", "user3"), @@ -139,8 +125,7 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should return true if user is not in whiteLabel", func(t *testing.T) { - + ot.Run(t, "Should return true if user is not in whiteLabel", func(t *testing.T) { otu.O.Script("devFindVerifierIsInWhiteList", WithArg("user", otu.O.Address(user)), WithAddresses("addresses", "user2", "user3"), @@ -151,8 +136,7 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should panic if no one is not in whiteLabel", func(t *testing.T) { - + ot.Run(t, "Should panic if no one is not in whiteLabel", func(t *testing.T) { _, err := otu.O.Script("devFindVerifierIsInWhiteList", WithArg("user", otu.O.Address(user)), WithArg("addresses", "[]"), @@ -163,8 +147,7 @@ func TestFindVerifier(t *testing.T) { }) // Has Find Name - t.Run("Should return true if user has the find name", func(t *testing.T) { - + ot.Run(t, "Should return true if user has the find name", func(t *testing.T) { otu.O.Script("devFindVerifierHasFindName", WithArg("user", otu.O.Address(user)), WithArg("findNames", []string{"user1", "user2"}), @@ -175,8 +158,7 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should return false if user does not have the find name", func(t *testing.T) { - + ot.Run(t, "Should return false if user does not have the find name", func(t *testing.T) { otu.O.Script("devFindVerifierHasFindName", WithArg("user", otu.O.Address(user)), WithArg("findNames", []string{"user2", "user3"}), @@ -187,8 +169,7 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should panic if no find name is specified", func(t *testing.T) { - + ot.Run(t, "Should panic if no find name is specified", func(t *testing.T) { _, err := otu.O.Script("devFindVerifierHasFindName", WithArg("user", otu.O.Address(user)), WithArg("findNames", "[]"), @@ -198,37 +179,34 @@ func TestFindVerifier(t *testing.T) { assert.Error(t, err) }) - t.Run("Should return false if user has no lease collection", func(t *testing.T) { - + ot.Run(t, "Should return false if user has no lease collection", func(t *testing.T) { otu.O.Script("devFindVerifierHasFindName", - WithArg("user", otu.O.Address("user2")), - WithArg("findNames", []string{"user2", "user3"}), + WithArg("user", otu.O.Address("user3")), + WithArg("findNames", []string{"user3"}), ). AssertWant(t, autogold.Want("HasFindName user no lease collection, false", map[string]interface{}{ - "description": "Users with one of these find names are verified : user2, user3", + "description": "Users with one of these find names are verified : user3", "result": false, })) }) // Has No. of NFTs in Path - t.Run("Should return true if user has no of NFTs equal to threshold", func(t *testing.T) { - + ot.Run(t, "Should return true if user has no of NFTs equal to threshold", func(t *testing.T) { otu.O.Script("devFindVerifierHasNFTsInPath", - WithArg("user", otu.O.Address("find")), - WithArg("path", "exampleNFTCollection"), + WithArg("user", otu.O.Address("user1")), + WithArg("path", "findDandy"), WithArg("threshold", 2), ). AssertWant(t, autogold.Want("Has no. of NFT equal to threshold, true", map[string]interface{}{ - "description": "Users with at least 2 nos. of NFT in path /public/exampleNFTCollection are verified", + "description": "Users with at least 2 nos. of NFT in path /public/findDandy are verified", "result": true, })) }) - t.Run("Should return true if user has no of NFTs more than threshold", func(t *testing.T) { - + ot.Run(t, "Should return true if user has no of NFTs more than threshold", func(t *testing.T) { otu.O.Script("devFindVerifierHasNFTsInPath", - WithArg("user", otu.O.Address("find")), + WithArg("user", otu.O.Address("user1")), WithArg("path", "exampleNFTCollection"), WithArg("threshold", 1), ). @@ -238,10 +216,9 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should return false if user has no of NFTs less than threshold", func(t *testing.T) { - + ot.Run(t, "Should return false if user has no of NFTs less than threshold", func(t *testing.T) { otu.O.Script("devFindVerifierHasNFTsInPath", - WithArg("user", otu.O.Address("find")), + WithArg("user", otu.O.Address("user1")), WithArg("path", "exampleNFTCollection"), WithArg("threshold", 100), ). @@ -251,10 +228,9 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should panic if 0 threshold is specified", func(t *testing.T) { - + ot.Run(t, "Should panic if 0 threshold is specified", func(t *testing.T) { _, err := otu.O.Script("devFindVerifierHasNFTsInPath", - WithArg("user", otu.O.Address("find")), + WithArg("user", otu.O.Address("user1")), WithArg("path", "exampleNFTCollection"), WithArg("threshold", 0), ). @@ -263,8 +239,7 @@ func TestFindVerifier(t *testing.T) { assert.Error(t, err) }) - t.Run("Should return false if user has no collection", func(t *testing.T) { - + ot.Run(t, "Should return false if user has no collection", func(t *testing.T) { otu.O.Script("devFindVerifierHasNFTsInPath", WithArg("user", otu.O.Address("user3")), WithArg("path", "exampleNFTCollection"), @@ -276,11 +251,9 @@ func TestFindVerifier(t *testing.T) { })) }) - // HasNFTWithRarities - t.Run("Should return true if user has nft with specified rarity", func(t *testing.T) { - + ot.Run(t, "Should return true if user has nft with specified rarity", func(t *testing.T) { otu.O.Script("devFindVerifierHasNFTsWithRarity", - WithArg("user", otu.O.Address("find")), + WithArg("user", otu.O.Address("user1")), WithArg("path", "exampleNFTCollection"), WithArg("rarityA", true), WithArg("rarityB", true), @@ -291,10 +264,9 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should return false if user does not have nft with specified rarity", func(t *testing.T) { - + ot.Run(t, "Should return false if user does not have nft with specified rarity", func(t *testing.T) { otu.O.Script("devFindVerifierHasNFTsWithRarity", - WithArg("user", otu.O.Address("find")), + WithArg("user", otu.O.Address("user1")), WithArg("path", "exampleNFTCollection"), WithArg("rarityA", false), WithArg("rarityB", true), @@ -305,10 +277,9 @@ func TestFindVerifier(t *testing.T) { })) }) - t.Run("Should panic if no rarity is specified", func(t *testing.T) { - + ot.Run(t, "Should panic if no rarity is specified", func(t *testing.T) { _, err := otu.O.Script("devFindVerifierHasNFTsWithRarity", - WithArg("user", otu.O.Address("find")), + WithArg("user", otu.O.Address("user1")), WithArg("path", "exampleNFTCollection"), WithArg("rarityA", false), WithArg("rarityB", false), @@ -318,8 +289,7 @@ func TestFindVerifier(t *testing.T) { assert.Error(t, err) }) - t.Run("Should return false if user has no collection specified for rarity", func(t *testing.T) { - + ot.Run(t, "Should return false if user has no collection specified for rarity", func(t *testing.T) { otu.O.Script("devFindVerifierHasNFTsWithRarity", WithArg("user", otu.O.Address("user3")), WithArg("path", "exampleNFTCollection"), diff --git a/find_wearable_sale_test.go b/find_wearable_sale_test.go deleted file mode 100644 index a77afbe6..00000000 --- a/find_wearable_sale_test.go +++ /dev/null @@ -1,433 +0,0 @@ -package test_main - -import ( - "testing" - - . "github.com/bjartek/overflow" - "github.com/findonflow/find/findGo" - "github.com/stretchr/testify/assert" -) - -func TestFindWearablesSaleFUT(t *testing.T) { - - otu := NewOverflowTest(t). - setupFIND(). - createDapperUser("user1"). - createDapperUser("user2"). - createWearableUser("user1"). - createWearableUser("user2"). - registerDUCInRegistry() - - ot := findGo.OverflowUtils{ - O: otu.O, - T: otu.T, - } - - ot.UpgradeFindDapperTenantSwitchboard() - - id1 := otu.mintWearables("user1") - addNFTCatalog(otu, "user1", id1) - - price := 10.0 - - token, err := otu.O.QualifiedIdentifier("FlowUtilityToken", "Vault") - assert.NoError(t, err) - - t.Run("Should be able to list thru dapper market", func(t *testing.T) { - - listWearablesForSaleFUT(otu, "user1", id1, price, token) - - }) - - t.Run("Should be able to buy thru dapper market, royalties are asserted", func(t *testing.T) { - - listWearablesForSaleFUT(otu, "user1", id1, price, token) - - otu.O.Tx("buyNFTForSaleDapper", - WithSigner("user2"), - WithPayloadSigner("dapper"), - WithArg("address", "user1"), - WithArg("id", id1), - WithArg("amount", price), - ). - AssertSuccess(otu.T). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("find"), - "amount": 0.25, - "vaultType": token, - }) - - sendWearables(otu, "user1", "user2", id1) - - }) - -} - -func TestFindWearablesSaleDUC(t *testing.T) { - - otu := NewOverflowTest(t). - setupFIND(). - createDapperUser("user1"). - createDapperUser("user2"). - createWearableUser("user1"). - createWearableUser("user2"). - registerDUCInRegistry() - - ot := findGo.OverflowUtils{ - O: otu.O, - T: otu.T, - } - ot.UpgradeFindDapperTenantSwitchboard() - - id1 := otu.mintWearables("user1") - addNFTCatalog(otu, "user1", id1) - - price := 10.0 - - token, err := otu.O.QualifiedIdentifier("DapperUtilityCoin", "Vault") - assert.NoError(t, err) - - t.Run("Should be able to list thru dapper market", func(t *testing.T) { - - listWearablesForSaleFUT(otu, "user1", id1, price, token) - - }) - - t.Run("Should be able to buy thru dapper market, royalties are asserted with minimum 0.44", func(t *testing.T) { - - listWearablesForSaleFUT(otu, "user1", id1, price, token) - - otu.O.Tx("buyNFTForSaleDapper", - WithSigner("user2"), - WithPayloadSigner("dapper"), - WithArg("address", "user1"), - WithArg("id", id1), - WithArg("amount", price), - ). - AssertSuccess(otu.T). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("find"), - "amount": 0.25, - "vaultType": token, - "royaltyName": "find", - }). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("dapper"), - "amount": 0.44, - "royaltyName": "dapper", - "vaultType": token, - }) - - sendWearables(otu, "user1", "user2", id1) - - }) - - t.Run("Should be able to buy thru dapper market, royalties are asserted", func(t *testing.T) { - - price := 100.0 - - listWearablesForSaleFUT(otu, "user1", id1, price, token) - - otu.O.Tx("buyNFTForSaleDapper", - WithSigner("user2"), - WithPayloadSigner("dapper"), - WithArg("address", "user1"), - WithArg("id", id1), - WithArg("amount", price), - ). - AssertSuccess(otu.T). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("find"), - "amount": 2.5, - "royaltyName": "find", - "vaultType": token, - }). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("dapper"), - "amount": 1.0, - "royaltyName": "dapper", - "vaultType": token, - }) - - sendWearables(otu, "user1", "user2", id1) - }) - -} - -func TestFindWearablesSaleResetMarket(t *testing.T) { - - // This test aims to mimic how we switch from market items now to new find market structure - - otu := NewOverflowTest(t). - setupFIND(). - createDapperUser("user1"). - createDapperUser("user2"). - createWearableUser("user1"). - createWearableUser("user2"). - registerDUCInRegistry() - - otu.setFlowDandyMarketOption("dapper") - price := 10.0 - - token, err := otu.O.QualifiedIdentifier("DapperUtilityCoin", "Vault") - assert.NoError(t, err) - - dandyIden, err := otu.O.QualifiedIdentifier("Dandy", "NFT") - assert.NoError(otu.T, err) - - otu.registerDapperUser("user1") - otu.buyForgeDapper("user1") - dandy := otu.mintThreeExampleDandies()[0] - otu.registerDandyInNFTRegistry() - - t.Run("Should be able to trade in a differently set up market", func(t *testing.T) { - otu.O.Tx("listNFTForSaleDapper", - WithSigner("user1"), - WithArg("nftAliasOrIdentifier", dandyIden), - WithArg("id", dandy), - WithArg("ftAliasOrIdentifier", token), - WithArg("directSellPrice", price), - WithArg("validUntil", otu.currentTime()+100.0), - ). - AssertSuccess(otu.T) - - otu.O.Tx("buyNFTForSaleDapper", - WithSigner("user2"), - WithPayloadSigner("dapper"), - WithArg("address", "user1"), - WithArg("id", dandy), - WithArg("amount", price), - ). - AssertSuccess(otu.T). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("find"), - "amount": 0.25, - "royaltyName": "find", - "vaultType": token, - }). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("dapper"), - "amount": 0.44, - "royaltyName": "dapper", - "vaultType": token, - }) - - }) - - wearable := otu.mintWearables("user1") - addNFTCatalog(otu, "user1", wearable) - - ot := findGo.OverflowUtils{ - O: otu.O, - T: otu.T, - } - ot.UpgradeFindDapperTenantSwitchboard() - - dandy = otu.mintThreeExampleDandies()[0] - t.Run("Should still be able to trade original NFTs after the upgrade", func(t *testing.T) { - otu.O.Tx("listNFTForSaleDapper", - WithSigner("user1"), - WithArg("nftAliasOrIdentifier", dandyIden), - WithArg("id", dandy), - WithArg("ftAliasOrIdentifier", token), - WithArg("directSellPrice", price), - WithArg("validUntil", otu.currentTime()+100.0), - ). - AssertSuccess(otu.T) - - otu.O.Tx("buyNFTForSaleDapper", - WithSigner("user2"), - WithPayloadSigner("dapper"), - WithArg("address", "user1"), - WithArg("id", dandy), - WithArg("amount", price), - ). - AssertSuccess(otu.T). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("find"), - "amount": 0.25, - "royaltyName": "find", - "vaultType": token, - }). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("dapper"), - "amount": 0.44, - "royaltyName": "dapper", - "vaultType": token, - }) - - }) - - t.Run("Should be able to sell wearables in DUC with different fee structure", func(t *testing.T) { - - listWearablesForSaleFUT(otu, "user1", wearable, price, token) - - otu.O.Tx("buyNFTForSaleDapper", - WithSigner("user2"), - WithPayloadSigner("dapper"), - WithArg("address", "user1"), - WithArg("id", wearable), - WithArg("amount", price), - ). - AssertSuccess(otu.T). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("find"), - "amount": 0.25, - "royaltyName": "find", - "vaultType": token, - }). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("dapper"), - "amount": 0.44, - "royaltyName": "dapper", - "vaultType": token, - }) - - sendWearables(otu, "user1", "user2", wearable) - - }) - - t.Run("Should be able to sell wearables in FUT with different fee structure", func(t *testing.T) { - token, err := otu.O.QualifiedIdentifier("FlowUtilityToken", "Vault") - assert.NoError(t, err) - listWearablesForSaleFUT(otu, "user1", wearable, price, token) - - otu.O.Tx("buyNFTForSaleDapper", - WithSigner("user2"), - WithPayloadSigner("dapper"), - WithArg("address", "user1"), - WithArg("id", wearable), - WithArg("amount", price), - ). - AssertSuccess(otu.T). - AssertEvent(otu.T, "FindMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("find"), - "amount": 0.25, - "royaltyName": "find", - "vaultType": token, - }) - - sendWearables(otu, "user1", "user2", wearable) - - }) - - t.Run("Should be able to list and buy lease in the market with different fee structure", func(t *testing.T) { - - otu.registerDapperUserWithName("user1", "name1") - - ftIden, err := otu.O.QualifiedIdentifier("DapperUtilityCoin", "Vault") - assert.NoError(otu.T, err) - - otu.O.Tx("listLeaseForSaleDapper", - WithSigner("user1"), - WithArg("leaseName", "name1"), - WithArg("ftAliasOrIdentifier", ftIden), - WithArg("directSellPrice", price), - WithArg("validUntil", otu.currentTime()+100.0), - ). - AssertSuccess(otu.T) - - }) - - t.Run("Should be able to list and buy lease in the market with different fee structure", func(t *testing.T) { - - otu.listLeaseForSaleDUC("user1", "name1", price) - - otu.O.Tx("buyLeaseForSaleDapper", - WithSigner("user2"), - WithPayloadSigner("dapper"), - WithArg("sellerAccount", "user1"), - WithArg("leaseName", "name1"), - WithArg("amount", price), - ). - AssertSuccess(otu.T). - AssertEvent(otu.T, "FindLeaseMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("find"), - "amount": 0.25, - "royaltyName": "find", - "vaultType": token, - }). - AssertEvent(otu.T, "FindLeaseMarket.RoyaltyPaid", - map[string]interface{}{ - "address": otu.O.Address("dapper"), - "amount": 0.44, - "royaltyName": "dapper", - "vaultType": token, - }) - - }) - -} - -func addNFTCatalog(otu *OverflowTestUtils, user string, id uint64) *OverflowTestUtils { - - contractAddress := "0xf8d6e0586b0a20c7" - switch otu.O.GetNetwork() { - case "testnet": - contractAddress = "0x1e0493ee604e7598" - - case "mainnet": - contractAddress = "0xe81193c424cfd3fb" - } - - otu.O.Tx("devaddNFTCatalog", - WithSigner("account"), - WithArg("collectionIdentifier", "wearables"), - WithArg("contractName", "Wearables"), - WithArg("contractAddress", contractAddress), - WithArg("addressWithNFT", user), - WithArg("nftID", id), - WithArg("publicPathIdentifier", "wearables"), - ). - AssertSuccess(otu.T) - - return otu -} - -func listWearablesForSaleFUT(otu *OverflowTestUtils, name string, id uint64, price float64, token string) []uint64 { - - nftIden, err := otu.O.QualifiedIdentifier("Wearables", "NFT") - assert.NoError(otu.T, err) - - eventIden, err := otu.O.QualifiedIdentifier("FindMarketSale", "Sale") - assert.NoError(otu.T, err) - - res := otu.O.Tx("listNFTForSaleDapper", - WithSigner(name), - WithArg("nftAliasOrIdentifier", nftIden), - WithArg("id", id), - WithArg("ftAliasOrIdentifier", token), - WithArg("directSellPrice", price), - WithArg("validUntil", otu.currentTime()+100.0), - ). - AssertSuccess(otu.T). - GetIdsFromEvent(eventIden, "id") - - return res -} - -func sendWearables(otu *OverflowTestUtils, receiver string, sender string, id uint64) *OverflowTestUtils { - - otu.O.Tx( - "sendWearables", - WithSigner("user2"), - WithArg("allReceivers", []string{otu.O.Address("user1")}), - WithArg("ids", []uint64{id}), - WithArg("memos", []string{"1"}), - ) - - return otu -} diff --git a/find_wearable_test.go b/find_wearable_test.go deleted file mode 100644 index 9aff1f0e..00000000 --- a/find_wearable_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package test_main - -import ( - "testing" - - . "github.com/bjartek/overflow" - "github.com/hexops/autogold" -) - -func TestFindWearables(t *testing.T) { - - otu := NewOverflowTest(t). - setupFIND(). - createWearableUser("user1") - - id1 := otu.mintWearables("user1") - id2 := otu.mintWearables("user1") - id3 := otu.mintWearables("user1") - - user2 := otu.O.Address("user2") - user3 := otu.O.Address("user3") - - t.Run("Should be able to send Wearables using Airdrop", func(t *testing.T) { - otu.createWearableUser("user2") - - res := otu.O.Tx( - "sendWearables", - WithSigner("user1"), - WithArg("allReceivers", []string{user2, user3, user2}), - WithArg("ids", []uint64{id1, id2, id3}), - WithArg("memos", []string{"1", "2", "3"}), - ). - AssertSuccess(t) - - res.AssertEvent(t, "Airdropped", map[string]interface{}{ - "from": otu.O.Address("user1"), - "to": otu.O.Address("user2"), - "uuid": id1, - "context": map[string]interface{}{ - "tenant": "find", - "message": "1", - }, - }) - - res.AssertEvent(t, "Airdropped", map[string]interface{}{ - "from": otu.O.Address("user1"), - "to": otu.O.Address("user2"), - "uuid": id3, - "context": map[string]interface{}{ - "tenant": "find", - "message": "3", - }, - }) - - res.AssertEvent(t, "AirdropFailed", map[string]interface{}{ - "from": otu.O.Address("user1"), - "to": otu.O.Address("user3"), - "uuid": id2, - "context": map[string]interface{}{ - "tenant": "find", - "message": "2", - }, - "reason": "Invalid Receiver Capability", - }) - }) - - t.Run("Should be able to getFindStatus with user that has wearables set", func(t *testing.T) { - otu.createUser(10.0, "user2") - - otu.O.Script( - "getFindStatus", - WithArg("user", user2), - ). - AssertWithPointerWant(t, "/readyForWearables", autogold.Want("should be ready", true)) - - }) - - t.Run("Should be able to getFindStatus with user that doesnt has wearables set", func(t *testing.T) { - otu.createUser(10.0, "user3") - - otu.O.Script( - "getFindStatus", - WithArg("user", user3), - ). - AssertWithPointerWant(t, "/readyForWearables", autogold.Want("should be not ready", false)) - - }) - -} diff --git a/flow.json b/flow.json index ad0a24d0..81396d7d 100644 --- a/flow.json +++ b/flow.json @@ -6,214 +6,160 @@ } }, "contracts": { - "NonFungibleToken": { - "source": "./contracts/standard/NonFungibleToken.cdc", - "aliases": { - "testnet": "0x631e88ae7f1d7c20", - "mainnet": "0x1d7e57aa55817448" - } - }, - "MetadataViews": { - "source": "./contracts/standard/MetadataViews.cdc", - "aliases": { - "mainnet": "0x1d7e57aa55817448", - "testnet": "0x631e88ae7f1d7c20" - } - }, - "DapperStorageRent": { - "source": "./contracts/standard/DapperStorageRent.cdc", - "aliases": { - "testnet": "0x43ee8c22fcf94ea3", - "mainnet": "0xa08e88e23f332538" - } - }, - "FUSD": { - "source": "./contracts/standard/FUSD.cdc", - "aliases": { - "testnet": "0xe223d8a629e49c68", - "mainnet": "0x3c5959b568896393" - } - }, - "NFTStorefront": { - "source": "./contracts/standard/NFTStorefront.cdc", - "aliases": { - "testnet": "0x94b06cfca1d8a476", - "mainnet": "0x4eb8a10cb9f87357" - } - }, - "NFTStorefrontV2": { - "source": "./contracts/standard/NFTStorefrontV2.cdc", - "aliases": { - "testnet": "0x2d55b98eb200daef", - "mainnet": "0x4eb8a10cb9f87357" - } - }, - "CoatCheck": { - "source": "./contracts/community/CoatCheck.cdc", - "aliases": { - "testnet": "0xe1d43e0cfc237807", - "mainnet": "0x5c57f79c6694797f" - } - }, - "FlowtyUtils": { - "source": "./contracts/community/FlowtyUtils.cdc", - "aliases": { - "testnet": "0xe1d43e0cfc237807", - "mainnet": "0x5c57f79c6694797f" - } - }, - "FlowtyRentals": { - "source": "./contracts/community/FlowtyRentals.cdc", - "aliases": { - "testnet": "0xe1d43e0cfc237807", - "mainnet": "0x5c57f79c6694797f" - } - }, - "Flowty": { - "source": "./contracts/community/Flowty.cdc", + "FLOAT": { + "source": "./contracts/standard/FLOAT.cdc", "aliases": { - "testnet": "0xe1d43e0cfc237807", - "mainnet": "0x5c57f79c6694797f" + "mainnet": "0x2d4c3caffbeab845", + "testnet": "0x857dc34d5e1631d3", + "migrationnet": "0x857dc34d5e1631d3" } }, - "Flovatar": { - "source": "./contracts/community/Flovatar.cdc", + "FungibleTokenSwitchboard": { + "source": "./contracts/standard/FungibleTokenSwitchboard.cdc", "aliases": { - "testnet": "0x9392a4a7c3f49a0b", - "mainnet": "0x921ea449dffec68a" + "testnet": "9a0766d93b6608b7", + "migrationnet": "9a0766d93b6608b7", + "previewnet": "0xa0225e7000ac82a9", + "emulator": "ee82856bf20e2aa6", + "mainnet": "0xf233dcee88fe0abe" } }, - "FlovatarComponent": { - "source": "./contracts/community/FlovatarComponent.cdc", + "EmeraldIdentity": { + "source": "./contracts/standard/EmeraldIdentity.cdc", "aliases": { - "testnet": "0x9392a4a7c3f49a0b", - "mainnet": "0x921ea449dffec68a" + "mainnet": "0x39e42c67cc851cfb", + "testnet": "0xfe433270356d985c", + "migrationnet": "0xfe433270356d985c" } }, - "FlovatarComponentTemplate": { - "source": "./contracts/community/FlovatarComponentTemplate.cdc", + "NonFungibleToken": { + "source": "./contracts/standard/NonFungibleToken.cdc", "aliases": { - "testnet": "0x9392a4a7c3f49a0b", - "mainnet": "0x921ea449dffec68a" + "testnet": "0x631e88ae7f1d7c20", + "migrationnet": "0x631e88ae7f1d7c20", + "mainnet": "0x1d7e57aa55817448", + "emulator": "0xf8d6e0586b0a20c7", + "previewnet": "0xb6763b4399a888c8" } }, - "FlovatarMarketplace": { - "source": "./contracts/community/FlovatarMarketplace.cdc", + "MetadataViews": { + "source": "./contracts/standard/MetadataViews.cdc", "aliases": { - "testnet": "0x9392a4a7c3f49a0b", - "mainnet": "0x921ea449dffec68a" + "mainnet": "0x1d7e57aa55817448", + "testnet": "0x631e88ae7f1d7c20", + "migrationnet": "0x631e88ae7f1d7c20", + "emulator": "0xf8d6e0586b0a20c7", + "previewnet": "0xb6763b4399a888c8" } }, - "SwapRouter": { - "source": "./contracts/community/SwapRouter.cdc", + "TokenForwarding": { + "source": "./contracts/standard/TokenForwarding.cdc", "aliases": { - "mainnet": "0xa6850776a94e6551", - "testnet": "0x2f8af5ed05bbde0d" + "mainnet": "0xe544175ee0461c4b", + "testnet": "0x51ea0e37c27a1f1a", + "migrationnet": "0x51ea0e37c27a1f1a", + "previewnet": "0xcbc6dbbfcc60e595" } }, - "FlovatarPack": { - "source": "./contracts/community/FlovatarPack.cdc", + "DapperStorageRent": { + "source": "./contracts/standard/DapperStorageRent.cdc", "aliases": { - "testnet": "0x9392a4a7c3f49a0b", - "mainnet": "0x921ea449dffec68a" + "testnet": "0x43ee8c22fcf94ea3", + "migrationnet": "0x43ee8c22fcf94ea3", + "mainnet": "0xa08e88e23f332538", + "previewnet": "0xcbc6dbbfcc60e595" } }, "FungibleToken": { "source": "./contracts/standard/FungibleToken.cdc", "aliases": { "testnet": "9a0766d93b6608b7", + "migrationnet": "9a0766d93b6608b7", "emulator": "ee82856bf20e2aa6", - "mainnet": "0xf233dcee88fe0abe" - } - }, - "FungibleTokenSwitchboard": { - "source": "./contracts/standard/FungibleTokenSwitchboard.cdc", - "aliases": { - "testnet": "9a0766d93b6608b7", - "mainnet": "0xf233dcee88fe0abe" + "mainnet": "0xf233dcee88fe0abe", + "previewnet": "0xa0225e7000ac82a9" } }, "FlowToken": { "source": "./contracts/standard/FlowToken.cdc", "aliases": { "testnet": "0x7e60df042a9c0868", + "migrationnet": "0x7e60df042a9c0868", "emulator": "0x0ae53cb6e3f42a79", - "mainnet": "0x1654653399040a61" - } - }, - "FiatToken": { - "source": "./contracts/standard/FiatToken.cdc", - "aliases": { - "testnet": "0xa983fecbed621163", - "mainnet": "0xb19436aae4d94622" + "mainnet": "0x1654653399040a61", + "previewnet": "0x4445e7ad11568276" } }, - "GrantedAccountAccess": { - "source": "./contracts/standard/GrantedAccountAccess.cdc", - "aliases": { - "mainnet": "0x2d4c3caffbeab845", - "testnet": "0x0afe396ebc8eee65" - } - }, - "FLOAT": { - "source": "./contracts/standard/FLOAT.cdc", + "ViewResolver": { + "source": "./contracts/standard/ViewResolver.cdc", "aliases": { - "mainnet": "0x2d4c3caffbeab845", - "testnet": "0x0afe396ebc8eee65" + "emulator": "0xf8d6e0586b0a20c7", + "mainnet": "0x1d7e57aa55817448", + "testnet": "0x631e88ae7f1d7c20", + "migrationnet": "0x631e88ae7f1d7c20", + "previewnet": "0xb6763b4399a888c8" } }, - "FLOATVerifiers": { - "source": "./contracts/standard/FLOATVerifiers.cdc", + "Burner": { + "source": "./contracts/standard/Burner.cdc", "aliases": { - "mainnet": "0x2d4c3caffbeab845", - "testnet": "0x0afe396ebc8eee65" + "emulator": "0xf8d6e0586b0a20c7", + "mainnet": "0xf233dcee88fe0abe", + "testnet": "0x9a0766d93b6608b7", + "migrationnet": "0x9a0766d93b6608b7", + "previewnet": "0xb6763b4399a888c8" } }, - "EmeraldIdentity": { - "source": "./contracts/standard/EmeraldIdentity.cdc", + "DapperUtilityCoin": { + "source": "./contracts/standard/DapperUtilityCoin.cdc", "aliases": { - "mainnet": "0x39e42c67cc851cfb", - "testnet": "0xfe433270356d985c" + "mainnet": "0xead892083b3e2c6c", + "testnet": "0x82ec283f88a62e65", + "migrationnet": "0x82ec283f88a62e65", + "previewnet": "0xcbc6dbbfcc60e595" } }, - "EmeraldIdentityLilico": { - "source": "./contracts/standard/EmeraldIdentityLilico.cdc", + "FlowUtilityToken": { + "source": "./contracts/standard/FlowUtilityToken.cdc", "aliases": { - "mainnet": "0x39e42c67cc851cfb" + "mainnet": "0xead892083b3e2c6c", + "testnet": "0x82ec283f88a62e65", + "migrationnet": "0x82ec283f88a62e65" } }, - "EmeraldIdentityDapper": { - "source": "./contracts/standard/EmeraldIdentityDapper.cdc", + "FungibleTokenMetadataViews": { + "source": "./contracts/standard/FungibleTokenMetadataViews.cdc", "aliases": { - "mainnet": "0x39e42c67cc851cfb" - } - }, - "FeeEstimator": { - "source": "./contracts/standard/FeeEstimator.cdc", - "aliases": { - "testnet": "0xbe4635353f55bbd4", - "mainnet": "0x473d6a2c37eab5be" + "mainnet": "0xf233dcee88fe0abe", + "previewnet": "0xa0225e7000ac82a9", + "emulator": "ee82856bf20e2aa6", + "testnet": "0x9a0766d93b6608b7", + "migrationnet": "0x9a0766d93b6608b7" } }, - "FlowStorageFees": { - "source": "./contracts/standard/FlowStorageFees.cdc", + "NFTCatalog": { + "source": "./contracts/standard/NFTCatalog.cdc", "aliases": { - "emulator": "0xf8d6e0586b0a20c7", - "testnet": "0x8c5303eaa26202d6", - "mainnet": "0xe467b9dd11fa00df" + "mainnet": "0x49a7cda3a1eecc29", + "testnet": "0x324c34e1c517e4db", + "migrationnet": "0x324c34e1c517e4db", + "previewnet": "0xd5a5e5c94f9cdb36" } }, - "TopShot": { - "source": "./contracts/community/TopShot.cdc", + "NFTCatalogAdmin": { + "source": "./contracts/standard/NFTCatalogAdmin.cdc", "aliases": { - "testnet": "0x877931736ee77cff", - "mainnet": "0x0b2a3299cc857e29" + "mainnet": "0x49a7cda3a1eecc29", + "testnet": "0x324c34e1c517e4db", + "migrationnet": "0x324c34e1c517e4db", + "previewnet": "0xd5a5e5c94f9cdb36" } }, "LostAndFound": { "source": "./contracts/standard/LostAndFound.cdc", "aliases": { "testnet": "0xbe4635353f55bbd4", + "migrationnet": "0xbe4635353f55bbd4", "mainnet": "0x473d6a2c37eab5be" } }, @@ -221,173 +167,110 @@ "source": "./contracts/standard/LostAndFoundHelper.cdc", "aliases": { "testnet": "0xbe4635353f55bbd4", + "migrationnet": "0xbe4635353f55bbd4", "mainnet": "0x473d6a2c37eab5be" } }, - "AlchemyMetadataWrapperMainnetShard1": { - "aliases": { - "mainnet": "0xeb8cb4c3157d5dac" - } - }, - "AlchemyMetadataWrapperMainnetShard2": { - "aliases": { - "mainnet": "0xeb8cb4c3157d5dac" - } - }, - "AlchemyMetadataWrapperMainnetShard3": { - "aliases": { - "mainnet": "0xeb8cb4c3157d5dac" - } - }, - "AlchemyMetadataWrapperMainnetShard4": { - "aliases": { - "mainnet": "0xeb8cb4c3157d5dac" - } - }, - "AlchemyMetadataWrapperTestnetShard1": { - "aliases": { - "testnet": "0x5ff2c7b4c40de11" - } - }, - "AlchemyMetadataWrapperTestnetShard2": { - "aliases": { - "testnet": "0x5ff2c7b4c40de11" - } - }, - "AlchemyMetadataWrapperTestnetShard3": { - "aliases": { - "testnet": "0x5ff2c7b4c40de11" - } - }, - "DapperUtilityCoin": { - "source": "./contracts/standard/DapperUtilityCoin.cdc", - "aliases": { - "mainnet": "0xead892083b3e2c6c", - "testnet": "0x82ec283f88a62e65" - } - }, - "FlowUtilityToken": { - "source": "./contracts/standard/FlowUtilityToken.cdc", - "aliases": { - "mainnet": "0xead892083b3e2c6c", - "testnet": "0x82ec283f88a62e65" - } - }, - "TokenForwarding": { - "source": "./contracts/standard/TokenForwarding.cdc", - "aliases": { - "mainnet": "0xe544175ee0461c4b", - "testnet": "0x51ea0e37c27a1f1a" - } - }, - "NFTCatalog": { - "source": "./contracts/standard/NFTCatalog.cdc", - "aliases": { - "mainnet": "0x49a7cda3a1eecc29", - "testnet": "0x324c34e1c517e4db" - } - }, - "NFTCatalogAdmin": { - "source": "./contracts/standard/NFTCatalogAdmin.cdc", - "aliases": { - "mainnet": "0x49a7cda3a1eecc29", - "testnet": "0x324c34e1c517e4db" - } - }, - "NFTRetrieval": { - "source": "./contracts/standard/NFTRetrieval.cdc", + "FeeEstimator": { + "source": "./contracts/standard/FeeEstimator.cdc", "aliases": { - "mainnet": "0x49a7cda3a1eecc29", - "testnet": "0x324c34e1c517e4db" + "testnet": "0xbe4635353f55bbd4", + "migrationnet": "0xbe4635353f55bbd4", + "mainnet": "0x473d6a2c37eab5be" } }, - "Bl0xPack": { - "source": "./contracts/Bl0xPack.cdc", + "FlowStorageFees": { + "source": "./contracts/standard/FlowStorageFees.cdc", "aliases": { - "mainnet": "0x7620acf6d7f2468a", - "testnet": "0xe8124d8428980aa6" + "emulator": "0xf8d6e0586b0a20c7", + "testnet": "0x8c5303eaa26202d6", + "migrationnet": "0x8c5303eaa26202d6", + "mainnet": "0xe467b9dd11fa00df", + "previewnet": "0xb6763b4399a888c8" } }, - "Bl0x": { - "source": "./contracts/Bl0x.cdc", + "SwapRouter": { + "source": "./contracts/community/SwapRouter.cdc", "aliases": { - "mainnet": "0x7620acf6d7f2468a", - "testnet": "0xe8124d8428980aa6" + "mainnet": "0xa6850776a94e6551", + "testnet": "0x2f8af5ed05bbde0d", + "migrationnet": "0x2f8af5ed05bbde0d" } }, - "Wearables": { - "source": "./contracts/community/Wearables.cdc", + "PublicPriceOracle": { + "source": "./contracts/community/PublicPriceOracle.cdc", "aliases": { - "mainnet": "0xe81193c424cfd3fb", - "testnet": "0x1c5033ad60821c97" + "mainnet": "0xec67451f8a58216a", + "migrationnet": "0x8232ce4a3aff4e94" } }, - "Templates": { - "source": "./contracts/community/Templates.cdc", + "BandOracle": { + "source": "./contracts/community/BandOracle.cdc", "aliases": { - "mainnet": "0xe81193c424cfd3fb", - "testnet": "0x1c5033ad60821c97" + "mainnet": "0x6801a6222ebf784a", + "testnet": "0x2c71de7af78d1adf", + "migrationnet": "0x8232ce4a3aff4e94" } }, + "ExampleNFT": "./contracts/standard/ExampleNFT.cdc", "ProfileCache": "./contracts/ProfileCache.cdc", "FIND": "./contracts/FIND.cdc", - "Giefts": "./contracts/Giefts.cdc", - "CollectionFactory": "./contracts/CollectionFactory.cdc", - "Dandy": "./contracts/Dandy.cdc", - "FindRulesCache": "./contracts/FindRulesCache.cdc", + "FindThoughts": "./contracts/FindThoughts.cdc", + "FindAirdropper": "./contracts/FindAirdropper.cdc", + "FindLostAndFoundWrapper": "./contracts/FindLostAndFoundWrapper.cdc", + "FindFurnace": "./contracts/FindFurnace.cdc", + "FindMarketAdmin": "./contracts/FindMarketAdmin.cdc", + "FindUserStatus": "./contracts/FindUserStatus.cdc", "FindMarket": "./contracts/FindMarket.cdc", + "FindMarketSale": "./contracts/FindMarketSale.cdc", "FindMarketDirectOfferEscrow": "./contracts/FindMarketDirectOfferEscrow.cdc", "FindMarketDirectOfferSoft": "./contracts/FindMarketDirectOfferSoft.cdc", "FindMarketAuctionEscrow": "./contracts/FindMarketAuctionEscrow.cdc", "FindMarketAuctionSoft": "./contracts/FindMarketAuctionSoft.cdc", - "FindMarketSale": "./contracts/FindMarketSale.cdc", - "FindViews": "./contracts/FindViews.cdc", - "FindRelatedAccounts": "./contracts/FindRelatedAccounts.cdc", - "Sender": "./contracts/Sender.cdc", - "CharityNFT": "./contracts/CharityNFT.cdc", + "FindLeaseMarket": "./contracts/FindLeaseMarket.cdc", + "FindLeaseMarketSale": "./contracts/FindLeaseMarketSale.cdc", + "FindLeaseMarketAuctionSoft": "./contracts/FindLeaseMarketAuctionSoft.cdc", + "FindLeaseMarketDirectOfferSoft": "./contracts/FindLeaseMarketDirectOfferSoft.cdc", "Admin": "./contracts/Admin.cdc", - "FindMarketAdmin": "./contracts/FindMarketAdmin.cdc", + "Sender": "./contracts/Sender.cdc", "Clock": "./contracts/Clock.cdc", "Profile": "./contracts/Profile.cdc", "Debug": "./contracts/Debug.cdc", + "Dandy": "./contracts/Dandy.cdc", + "GeneratedExperiences": "./contracts/GeneratedExperiences.cdc", + "FindUtils": "./contracts/FindUtils.cdc", "FTRegistry": "./contracts/FTRegistry.cdc", - "NFTRegistry": "./contracts/NFTRegistry.cdc", "FindForge": "./contracts/FindForge.cdc", + "FindPack": "./contracts/FindPack.cdc", "FindForgeOrder": "./contracts/FindForgeOrder.cdc", + "FindRulesCache": "./contracts/FindRulesCache.cdc", "FindForgeStruct": "./contracts/FindForgeStruct.cdc", - "FindFooDIM": "./contracts/FindFooDIM.cdc", - "ExampleNFT": "./contracts/standard/ExampleNFT.cdc", - "NFGv3": "./contracts/NFGv3.cdc", - "PartyFavorz": "./contracts/PartyFavorz.cdc", - "PartyFavorzExtraData": "./contracts/PartyFavorzExtraData.cdc", - "GeneratedExperiences": "./contracts/GeneratedExperiences.cdc", - "FindRewardToken": "./contracts/FindRewardToken.cdc", - "FindToken": "./contracts/FindToken.cdc", - "FindLeaseMarket": "./contracts/FindLeaseMarket.cdc", - "FindLeaseMarketSale": "./contracts/FindLeaseMarketSale.cdc", - "FindLeaseMarketAuctionSoft": "./contracts/FindLeaseMarketAuctionSoft.cdc", - "FindLeaseMarketDirectOfferSoft": "./contracts/FindLeaseMarketDirectOfferSoft.cdc", - "FINDNFTCatalog": "./contracts/FINDNFTCatalog.cdc", "FINDNFTCatalogAdmin": "./contracts/FINDNFTCatalogAdmin.cdc", - "FindLostAndFoundWrapper": "./contracts/FindLostAndFoundWrapper.cdc", - "FindPack": "./contracts/FindPack.cdc", + "FindRelatedAccounts": "./contracts/FindRelatedAccounts.cdc", + "FindViews": "./contracts/FindViews.cdc", + "NameVoucher": "./contracts/NameVoucher.cdc", "FindVerifier": "./contracts/FindVerifier.cdc", - "Flomies": "./contracts/Flomies.cdc", - "FindAirdropper": "./contracts/FindAirdropper.cdc", - "FindFurnace": "./contracts/FindFurnace.cdc", - "FindUtils": "./contracts/FindUtils.cdc", - "FindUserStatus": "./contracts/FindUserStatus.cdc", - "FindThoughts": "./contracts/FindThoughts.cdc", - "WearablesDev": "./contracts/community/WearablesDev.cdc", + "FLOATVerifiers": "./contracts/standard/FLOATVerifiers.cdc", + "FINDNFTCatalog": "./contracts/FINDNFTCatalog.cdc", + "GrantedAccountAccess": "./contracts/standard/GrantedAccountAccess.cdc", "FindMarketCut": "./contracts/FindMarketCut.cdc", "FindMarketCutInterface": "./contracts/FindMarketCutInterface.cdc", "FindMarketCutStruct": "./contracts/FindMarketCutStruct.cdc", "FindMarketInfrastructureCut": "./contracts/FindMarketInfrastructureCut.cdc", "Dev": "./contracts/Dev.cdc", - "NameVoucher": "./contracts/NameVoucher.cdc" + "Bl0x": "./contracts/Bl0x.cdc", + "Bl0xPack": "./contracts/Bl0xPack.cdc", + "CharityNFT": "./contracts/CharityNFT.cdc", + "Flomies": "./contracts/Flomies.cdc", + "NFGv3": "./contracts/NFGv3.cdc", + "PartyFavorz": "./contracts/PartyFavorz.cdc", + "Giefts": "./contracts/Giefts.cdc", + "PartyFavorzExtraData": "./contracts/PartyFavorzExtraData.cdc" }, "networks": { "emulator": "127.0.0.1:3569", + "previewnet": "access.previewnet.nodes.onflow.org:9000", + "migrationnet": "access-001.migrationtestnet1.nodes.onflow.org:9000", "mainnet": "access.mainnet.nodes.onflow.org:9000", "testnet": "access.devnet.nodes.onflow.org:9000" }, @@ -397,99 +280,83 @@ "key": "573b0db3fe91458e2aceefb8318d6daf3aee2af986a850cbf27a8ffff8a4ef9f" }, "emulator-dapper": { - "address": "01cf0e2f2f715450", + "address": "0x179b6b1cb6755e31", "key": "573b0db3fe91458e2aceefb8318d6daf3aee2af986a850cbf27a8ffff8a4ef9f" }, "emulator-find": { - "address": "179b6b1cb6755e31", + "address": "0xf3fcd2c1a78f5eee", "key": "573b0db3fe91458e2aceefb8318d6daf3aee2af986a850cbf27a8ffff8a4ef9f" }, "emulator-find-admin": { - "address": "f3fcd2c1a78f5eee", + "address": "0xe03daebed8ca0615", "key": "573b0db3fe91458e2aceefb8318d6daf3aee2af986a850cbf27a8ffff8a4ef9f" }, "emulator-find-forge": { - "address": "e03daebed8ca0615", + "address": "0x045a1763c93006ca", "key": "573b0db3fe91458e2aceefb8318d6daf3aee2af986a850cbf27a8ffff8a4ef9f" }, "emulator-find-lease": { - "address": "045a1763c93006ca", + "address": "0x120e725050340cab", "key": "573b0db3fe91458e2aceefb8318d6daf3aee2af986a850cbf27a8ffff8a4ef9f" }, "emulator-residual": { - "address": "120e725050340cab", + "address": "0xf669cb8d41ce0c74", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, "emulator-user1": { - "address": "f669cb8d41ce0c74", + "address": "0x192440c99cb17282", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, "emulator-user2": { - "address": "192440c99cb17282", + "address": "0xfd43f9148d4b725d", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, "emulator-user3": { - "address": "fd43f9148d4b725d", + "address": "0xeb179c27144f783c", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, "emulator-user4": { - "address": "eb179c27144f783c", + "address": "0x0f7025fa05b578e3", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, "emulator-user5": { - "address": "0f7025fa05b578e3", + "address": "0xe2f72218abeec2b9", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, "emulator-user6": { - "address": "e2f72218abeec2b9", + "address": "0x06909bc5ba14c266", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, "emulator-user7": { - "address": "06909bc5ba14c266", + "address": "0x10c4fef62310c807", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, "emulator-user8": { - "address": "10c4fef62310c807", + "address": "0xf4a3472b32eac8d8", "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" }, - "emulator-user9": { - "address": "f4a3472b32eac8d8", - "key": "d5457a187e9642a8e49d4032b3b4f85c92da7202c79681d9302c6e444e7033a8" - }, - "testnet-account": { - "address": "0x1ff7e32d71183db0", - "key": "${TESTNET_ACCOUNT}" - }, "testnet-find": { "address": "35717efbbce11c74", "key": "${TESTNET_ACCOUNT}" }, - "testnet-find-lease": { - "address": "49d14b03d7411f53", - "key": "${TESTNET_ACCOUNT}" - }, "testnet-find-admin": { "address": "d116c726ad1b1cab", "key": "${TESTNET_ACCOUNT}" }, - "testnet-find-lost-and-found-wrapper": { - "address": "82836e61c008d6d1", - "key": "${TESTNET_ACCOUNT}" - }, - "testnet-emerald-identity": { - "address": "c9d218cc626cd7f5", - "key": "${TESTNET_ACCOUNT}" - }, "testnet-find-forge": { "address": "3e5b4c627064625d", "key": "${TESTNET_ACCOUNT}" }, - "testnet-find-dapper": { - "address": "695502f4d2ccd475", + "migrationnet-find": { + "address": "35717efbbce11c74", + "key": "${TESTNET_ACCOUNT}" + }, + "migrationnet-find-admin": { + "address": "d116c726ad1b1cab", "key": "${TESTNET_ACCOUNT}" }, - "testnet-user1": { - "address": "0xffbdace90dd96d40", + "migrationnet-find-forge": { + "address": "3e5b4c627064625d", "key": "${TESTNET_ACCOUNT}" }, "mainnet-find": { @@ -511,15 +378,98 @@ "mainnet-find-dapper": { "address": "0x46b99041da7235e9", "key": "${MAINNET_FIND_ADMIN}" - }, - "mainnet-giefts": { - "address": "0x97bf2205358ff29c", - "key": "${MAINNET_GIEFTS}" } }, "deployments": { - "mainnet": { - "mainnet-find": [ + "emulator": { + "emulator-account": [ + "TokenForwarding", + "FLOAT", + "FLOATVerifiers", + "GrantedAccountAccess", + "EmeraldIdentity", + "DapperStorageRent", + "NFTCatalog", + "NFTCatalogAdmin", + "LostAndFound", + "LostAndFoundHelper", + "FeeEstimator", + "PublicPriceOracle", + "BandOracle" + ], + "emulator-dapper": [ + "DapperUtilityCoin", + "FlowUtilityToken" + ], + "emulator-find": [ + "FIND", + "Profile", + "FindThoughts", + "Clock", + "Debug", + "Dandy", + "ExampleNFT", + "Admin", + "FindLostAndFoundWrapper", + "FindAirdropper", + "FindMarketAdmin", + "FindViews", + "FindMarket", + "FindMarketSale", + "Sender", + "FindRelatedAccounts", + "FTRegistry", + "FindForge", + "FindForgeOrder", + "FindForgeStruct", + "ProfileCache", + "FindRulesCache", + "FINDNFTCatalog", + "FINDNFTCatalogAdmin", + "FindPack", + "FindVerifier", + "FindFurnace", + "FindUtils", + "FindMarketCut", + "FindMarketCutStruct", + "FindMarketCutInterface", + "FindMarketInfrastructureCut", + "Dev", + "NameVoucher", + "Bl0x", + "Bl0xPack", + "CharityNFT", + "Flomies", + "NFGv3", + "PartyFavorz", + "PartyFavorzExtraData", + "FindLeaseMarket", + "FindLeaseMarketSale", + "FindLeaseMarketAuctionSoft", + "FindMarketAuctionEscrow", + "FindMarketAuctionSoft", + "FindLeaseMarketDirectOfferSoft", + "FindMarketDirectOfferSoft", + "FindMarketDirectOfferEscrow" + ], + "emulator-find-admin": [], + "emulator-find-forge": [ + "GeneratedExperiences" + ], + "emulator-find-lease": [], + "emulator-user1": [], + "emulator-user2": [], + "emulator-user3": [], + "emulator-user4": [], + "emulator-user5": [], + "emulator-user6": [], + "emulator-user7": [], + "emulator-user8": [], + "emulator-residual": [] + }, + "testnet": { + "testnet-find": [ + "PublicPriceOracle", "FIND", "Clock", "Profile", @@ -535,36 +485,34 @@ "FindMarketDirectOfferSoft", "FindMarketAuctionEscrow", "FindMarketAuctionSoft", - "FindLeaseMarket", - "FindLeaseMarketSale", - "FindLeaseMarketAuctionSoft", - "FindLeaseMarketDirectOfferSoft", "Sender", "FindRelatedAccounts", "FTRegistry", "FindForge", "FindForgeOrder", "FindForgeStruct", + "FindLeaseMarket", + "FindLeaseMarketSale", + "FindLeaseMarketAuctionSoft", + "FindLeaseMarketDirectOfferSoft", "ProfileCache", "FindRulesCache", "FINDNFTCatalog", "FINDNFTCatalogAdmin", - "FindLostAndFoundWrapper", "FindPack", "FindVerifier", "FindAirdropper", "FindFurnace", - "FindUtils", - "FindUserStatus", "FindThoughts", + "FindUtils", + "FindLostAndFoundWrapper", "FindMarketCut", "FindMarketCutStruct", "FindMarketCutInterface", "FindMarketInfrastructureCut", - "NameVoucher", - "Giefts" + "NameVoucher" ], - "mainnet-find-forge": [ + "testnet-find-forge": [ "NFGv3", "PartyFavorz", "PartyFavorzExtraData", @@ -572,8 +520,8 @@ "GeneratedExperiences" ] }, - "testnet": { - "testnet-find": [ + "migrationnet": { + "migrationnet-find": [ "FIND", "Clock", "Profile", @@ -609,69 +557,23 @@ "FindFurnace", "FindThoughts", "FindUtils", - "FindUserStatus", "FindLostAndFoundWrapper", "FindMarketCut", "FindMarketCutStruct", "FindMarketCutInterface", "FindMarketInfrastructureCut", - "NameVoucher", - "Giefts" + "NameVoucher" ], - "testnet-find-forge": [ + "migrationnet-find-forge": [ "NFGv3", "PartyFavorz", "PartyFavorzExtraData", "Flomies", "GeneratedExperiences" - ], - "testnet-emerald-identity": [ - "EmeraldIdentityLilico", - "EmeraldIdentityDapper" ] }, - "emulator": { - "emulator-account": [ - "NonFungibleToken", - "FungibleTokenSwitchboard", - "FUSD", - "FiatToken", - "MetadataViews", - "NFTStorefront", - "NFTStorefrontV2", - "TokenForwarding", - "NFTCatalog", - "NFTCatalogAdmin", - "FeeEstimator", - "LostAndFound", - "LostAndFoundHelper", - "FLOAT", - "GrantedAccountAccess", - "FLOATVerifiers", - "EmeraldIdentityLilico", - "EmeraldIdentityDapper", - "EmeraldIdentity", - "CoatCheck", - "Flowty", - "FlowtyRentals", - "Flovatar", - "FlovatarComponent", - "FlovatarMarketplace", - "FlovatarComponentTemplate", - "FlovatarPack", - "FlowtyUtils", - "DapperStorageRent", - "Templates", - "Wearables", - "WearablesDev", - "TopShot" - ], - "emulator-dapper": [ - "DapperUtilityCoin", - "FlowUtilityToken" - ], - "emulator-find": [ - "ExampleNFT", + "mainnet": { + "mainnet-find": [ "FIND", "Clock", "Profile", @@ -707,35 +609,21 @@ "FindAirdropper", "FindFurnace", "FindUtils", - "FindUserStatus", "FindThoughts", "FindMarketCut", "FindMarketCutStruct", "FindMarketCutInterface", "FindMarketInfrastructureCut", - "Dev", - "NameVoucher" + "NameVoucher", + "Giefts" ], - "emulator-find-admin": [], - "emulator-find-forge": [ + "mainnet-find-forge": [ "NFGv3", "PartyFavorz", "PartyFavorzExtraData", - "Bl0x", - "Bl0xPack", + "Flomies", "GeneratedExperiences" - ], - "emulator-find-lease": [], - "emulator-user1": [], - "emulator-user2": [], - "emulator-user3": [], - "emulator-user4": [], - "emulator-user5": [], - "emulator-user6": [], - "emulator-user7": [], - "emulator-user8": [], - "emulator-user9": [], - "emulator-residual": [] + ] } } } diff --git a/frontpage.md b/frontpage.md index daaee510..5a7cbb92 100644 --- a/frontpage.md +++ b/frontpage.md @@ -30,7 +30,7 @@ import FIND from 0x37a05b1ecacc80f7 //mainnet //import FIND from ?? -pub fun main(name: String) : Address? { +access(all) main(name: String) : Address? { return FIND.lookupAddress(name) } ``` @@ -58,7 +58,7 @@ FIND integrates with the profile contract from the Versus project. If you do not ### what does the money go to? (do we need this?) -The income from flow will go to its creator (bjartek) so that he can continue to dedicate his time to the flow ecosystem and help it thrive. +The income from flow will go to its creator so that he can continue to dedicate his time to the flow ecosystem and help it thrive. ### sites that integrate with find Find will be integrated into the following sites at launch @@ -76,12 +76,12 @@ A valid find name is 0-9a-z, minimum 3 tokens. Also it cannot be a Flow address, This is to ensure that it can be used in urls and to keep things simple. ### how much does it cost -Find is charged in the FUSD stable coin for a 365 day lease. This is done to keep prices stable and avoid a high increase if the flow token increases. +Find is charged in the Flow coin a 365 day lease. This is done to keep prices stable and avoid a high increase if the flow token increases. Currently the price structuer is as follows: - - 5+ characters: 5 FUSD - - 4 characters: 100 FUSD - - 3 charactesrs: 500 FUSD + - 5+ characters: 5 USD worth of flow + - 4 characters: 100 USD worth of flow + - 3 characters: 500 USD worth of flow ### What happends when a lease expires diff --git a/ftregistry_test.go b/ftregistry_test.go index 2c328cc3..21fdee0c 100644 --- a/ftregistry_test.go +++ b/ftregistry_test.go @@ -3,38 +3,28 @@ package test_main import ( "testing" - . "github.com/bjartek/overflow" - "github.com/hexops/autogold" + . "github.com/bjartek/overflow/v2" ) func TestFTRegistry(t *testing.T) { - otu := NewOverflowTest(t). - setupFIND() - - otu.registerFTInFtRegistry("flow", otu.identifier("FTRegistry", "FTInfoRegistered"), map[string]interface{}{ - "alias": "Flow", - "typeIdentifier": otu.identifier("FlowToken", "Vault"), - }) + otu := &OverflowTestUtils{T: t, O: ot.O} o := otu.O - t.Run("Should be able to registry flow token and get it", func(t *testing.T) { - - result, err := o.Script("getFTInfo", + ot.Run(t, "Should be able to registry flow token and get it", func(t *testing.T) { + result, err := o.Script("devgetFTInfo", WithArg("aliasOrIdentifier", "Flow"), ). GetAsJson() - if err != nil { panic(err) } otu.AutoGoldRename("Should be able to registry flow token and get it by alias", result) - result, err = o.Script("getFTInfo", + result, err = o.Script("devgetFTInfo", WithArg("aliasOrIdentifier", otu.identifier("FlowToken", "Vault")), ). GetAsJson() - if err != nil { panic(err) } @@ -42,23 +32,15 @@ func TestFTRegistry(t *testing.T) { otu.AutoGoldRename("Should be able to registry flow token and get it by identifier", result) }) - t.Run("Should not be able to overrride a ft without removing it first", func(t *testing.T) { - + ot.Run(t, "Should not be able to overrride a ft without removing it first", func(t *testing.T) { o.Tx("adminSetFTInfo_flow", WithSigner("find-admin"), ). AssertFailure(t, "This FungibleToken Register already exist") - }) - t.Run("Should be able to registry flow token, fusd token and get list from it", func(t *testing.T) { - otu.registerFTInFtRegistry("fusd", otu.identifier("FTRegistry", "FTInfoRegistered"), map[string]interface{}{ - "alias": "FUSD", - "typeIdentifier": otu.identifier("FUSD", "Vault"), - }) - - result, err := o.Script("getFTInfoAll").GetAsJson() - + ot.Run(t, "Should be able to registry flow token, fusd token and get list from it", func(t *testing.T) { + result, err := o.Script("devgetFTInfoAll").GetAsJson() if err != nil { panic(err) } @@ -66,90 +48,7 @@ func TestFTRegistry(t *testing.T) { otu.AutoGoldRename("Should not be able to overrride a ft without removing it first", result) }) - t.Run("Should be able to registry usdc token and get it", func(t *testing.T) { - otu.registerFTInFtRegistry("usdc", otu.identifier("FTRegistry", "FTInfoRegistered"), map[string]interface{}{ - "alias": "USDC", - "typeIdentifier": otu.identifier("FiatToken", "Vault"), - }) - - result, err := o.Script("getFTInfo", - WithArg("aliasOrIdentifier", otu.identifier("FiatToken", "Vault")), - ). - GetAsJson() - - if err != nil { - panic(err) - } - - otu.AutoGoldRename("Should be able to registry usdc token and get it", result) - }) - - t.Run("Should be able to send usdc to another name", func(t *testing.T) { - otu.createUser(100.0, "user1"). - createUser(100.0, "user2"). - registerUser("user1"). - registerUser("user2") - - o.Tx("sendFT", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 5.0), - WithArg("ftAliasOrIdentifier", "USDC"), - WithArg("tag", "test"), - WithArg("message", "This is a message"), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FiatToken", "TokensDeposited"), map[string]interface{}{ - "amount": 5.0, - "to": otu.O.Address("user1"), - }). - AssertEvent(t, otu.identifier("FiatToken", "TokensWithdrawn"), map[string]interface{}{ - "amount": 5.0, - "from": otu.O.Address("user2"), - }). - AssertEvent(t, otu.identifier("FIND", "FungibleTokenSent"), map[string]interface{}{ - "from": otu.O.Address("user2"), - "fromName": "user2", - "toAddress": otu.O.Address("user1"), - "amount": 5.0, - "name": "user1", - "tag": "test", - "message": "This is a message", - }) - }) - - t.Run("Should be able to send fusd to another name", func(t *testing.T) { - - o.Tx("sendFT", - WithSigner("user2"), - WithArg("name", "user1"), - WithArg("amount", 5.0), - WithArg("ftAliasOrIdentifier", "FUSD"), - WithArg("tag", "test"), - WithArg("message", "This is a message"), - ). - AssertSuccess(t). - AssertEvent(t, otu.identifier("FUSD", "TokensDeposited"), map[string]interface{}{ - "amount": 5.0, - "to": otu.O.Address("user1"), - }). - AssertEvent(t, otu.identifier("FUSD", "TokensWithdrawn"), map[string]interface{}{ - "amount": 5.0, - "from": otu.O.Address("user2"), - }). - AssertEvent(t, otu.identifier("FIND", "FungibleTokenSent"), map[string]interface{}{ - "from": otu.O.Address("user2"), - "fromName": "user2", - "toAddress": otu.O.Address("user1"), - "amount": 5.0, - "name": "user1", - "tag": "test", - "message": "This is a message", - }) - }) - - t.Run("Should be able to send flow to another name", func(t *testing.T) { - + ot.Run(t, "Should be able to send flow to another name", func(t *testing.T) { o.Tx("sendFT", WithSigner("user2"), WithArg("name", "user1"), @@ -177,28 +76,4 @@ func TestFTRegistry(t *testing.T) { "message": "This is a message", }) }) - - t.Run("Should be able to registry and remove them", func(t *testing.T) { - otu.removeFTInFtRegistry("adminRemoveFTInfoByAlias", "FUSD", - otu.identifier("FTRegistry", "FTInfoRemoved"), map[string]interface{}{ - "alias": "FUSD", - "typeIdentifier": otu.identifier("FUSD", "Vault"), - }). - removeFTInFtRegistry("adminRemoveFTInfoByTypeIdentifier", otu.identifier("FlowToken", "Vault"), - otu.identifier("FTRegistry", "FTInfoRemoved"), map[string]interface{}{ - "alias": "Flow", - "typeIdentifier": otu.identifier("FlowToken", "Vault"), - }) - - o.Script("getFTInfo", - WithArg("aliasOrIdentifier", otu.identifier("FUSD", "Vault")), - ). - AssertWant(t, autogold.Want("aliasOrIdentifier", nil)) - - o.Script("getFTInfo", - WithArg("aliasOrIdentifier", "Flow"), - ). - AssertWant(t, autogold.Want("aliasOrIdentifier", nil)) - - }) } diff --git a/generateFlowTransactions.sh b/generateFlowTransactions.sh index adb99a7a..0658db51 100644 --- a/generateFlowTransactions.sh +++ b/generateFlowTransactions.sh @@ -1,17 +1,14 @@ #/bin/bash FLOW_TRANSACTIONS_DIR="../flow-transactions-find/transactions/Find" -mapfile -t arr < <( jq '.transactions | keys[]' lib/find.json -r ) +mapfile -t arr < <(jq '.transactions | keys[]' lib/find.json -r) +rm $FLOW_TRANSACTIONS_DIR/*.cdc -rm $FLOW_TRANSACTIONS_DIR/*.cdc - -for i in "${arr[@]}" -do - jq --arg tx "$i" '.transactions[$tx]' lib/find.json -r > $FLOW_TRANSACTIONS_DIR/$i.cdc +for i in "${arr[@]}"; do + jq --arg tx "$i" '.transactions[$tx]' lib/find.json -r >$FLOW_TRANSACTIONS_DIR/$i.cdc done - cd $FLOW_TRANSACTIONS_DIR rm -Rf setup* rm -Rf clock* @@ -25,9 +22,7 @@ gsed -i 's/0xFindViews/0xFIND_ADDRESS/g' *.cdc gsed -i 's/0xArtifact/0xFIND_ADDRESS/g' *.cdc gsed -i 's/0xProfile/0xFIND_ADDRESS/g' *.cdc gsed -i 's/0xFlowToken/0xFLOW_TOKEN_ADDRESS/g' *.cdc -gsed -i 's/0xFUSD/0xFUSD_ADDRESS/g' *.cdc gsed -i 's/0xFungibleToken/0xFUNGIBLE_TOKEN_ADDRESS/g' *.cdc gsed -i 's/0xFIND/0xFIND_ADDRESS/g' *.cdc - cd diff --git a/generated_experiences_test.go b/generated_experiences_test.go index 2baeb721..cbd107df 100644 --- a/generated_experiences_test.go +++ b/generated_experiences_test.go @@ -1,37 +1,20 @@ package test_main import ( - "fmt" "testing" - . "github.com/bjartek/overflow" + . "github.com/bjartek/overflow/v2" "github.com/findonflow/find/findGo" "github.com/hexops/autogold" ) -var forge = "user1" - func TestGeneratedExperiences(t *testing.T) { + otu := &OverflowTestUtils{T: t, O: ot.O} - otu := NewOverflowTest(t). - setupFIND(). - createUser(10000.0, "user1"). - registerUserWithName("user1", forge). - buyForgeForName("user1", forge) - - generatedExpForge := otu.identifier("GeneratedExperiences", "Forge") - - otu.O.Tx("adminAddForge", - WithSigner("find-admin"), - WithArg("type", generatedExpForge), - WithArg("name", forge), - ).AssertSuccess(t) - - t.Run("Should be able to add season", func(t *testing.T) { - + ot.Run(t, "Should be able to add season", func(t *testing.T) { season := []findGo.GeneratedExperiences_CollectionInfo{ { - Season: 1, + Season: 2, RoyaltiesInput: []findGo.FindPack_Royalty{ { Recipient: otu.O.Address("user1"), @@ -66,15 +49,13 @@ func TestGeneratedExperiences(t *testing.T) { ). AssertSuccess(t). AssertEvent(t, "SeasonAdded", map[string]interface{}{ - "season": 1, + "season": 2, "squareImage": "ipfs://square", "bannerImage": "ipfs://banner", }) - }) - t.Run("Should be able to add mint token", func(t *testing.T) { - + ot.Run(t, "Should be able to add mint token", func(t *testing.T) { info := []findGo.GeneratedExperiences_Info{ { Season: 1, @@ -108,7 +89,7 @@ func TestGeneratedExperiences(t *testing.T) { }, } - otu.O.Tx("devAdminMintGeneratedExperiences", + result := otu.O.Tx("devAdminMintGeneratedExperiences", WithSigner("find-admin"), WithArg("name", "user1"), WithArg("info", info), @@ -135,27 +116,23 @@ func TestGeneratedExperiences(t *testing.T) { "maxEdition": 2, }) - }) - - t.Run("Ensure views are returned correctly", func(t *testing.T) { - - viewscript := ` - import GeneratedExperiences from "../contracts/GeneratedExperiences.cdc" - import MetadataViews from "../contracts/standard/MetadataViews.cdc" - - pub fun main(user: Address): AnyStruct { - let acct = getAccount(user) - let collectionRef = acct.getCapability(GeneratedExperiences.CollectionPublicPath) - .borrow<&{MetadataViews.ResolverCollection}>() - ?? panic("Could not borrow capability from public collection") - - let resolver = collectionRef.borrowViewResolver(id: collectionRef.getIDs()[0]) - return resolver.getViews() - } - ` - - otu.O.Script(viewscript, - WithArg("user", "find-admin"), + ids := result.GetIdsFromEvent("Minted", "id") + geIdentifier, _ := otu.O.QualifiedIdentifier("GeneratedExperiences", "NFT") + + otu.O.Tx("devaddNFTCatalog", + WithSigner("account"), + WithArg("collectionIdentifier", geIdentifier), + WithArg("contractName", geIdentifier), + WithArg("contractAddress", "find-forge"), + WithArg("addressWithNFT", "find-admin"), + WithArg("nftID", ids[0]), + WithArg("publicPathIdentifier", "GeneratedExperiences"), + ).AssertSuccess(t) + + otu.O.Script("getNFTViewsForAddress", + WithArg("address", "find-admin"), + WithArg("aliasOrIdentifier", geIdentifier), + WithArg("id", ids[0]), ). AssertWant(t, autogold.Want("views", `[]interface {}{ "A.f8d6e0586b0a20c7.MetadataViews.Display", @@ -167,61 +144,47 @@ func TestGeneratedExperiences(t *testing.T) { "A.f8d6e0586b0a20c7.MetadataViews.NFTCollectionDisplay", "A.f8d6e0586b0a20c7.MetadataViews.Medias", "A.f8d6e0586b0a20c7.MetadataViews.Rarity", - "A.179b6b1cb6755e31.FindPack.PackRevealData", + "A.f3fcd2c1a78f5eee.FindPack.PackRevealData", }`)) - }) - - tcs := map[string]autogold.Value{ - "A.f8d6e0586b0a20c7.MetadataViews.Display": autogold.Want("Display", map[string]interface{}{"description": "Description", "name": "Name", "thumbnail": map[string]interface{}{"cid": "thumbnail"}}), - "A.f8d6e0586b0a20c7.MetadataViews.Royalties": autogold.Want("Royalties", map[string]interface{}{"cutInfos": []interface{}{map[string]interface{}{"cut": 0.1, "description": "Royalty", "receiver": "Capability<&AnyResource{A.ee82856bf20e2aa6.FungibleToken.Receiver}>(address: 0xf669cb8d41ce0c74, path: /public/findProfileReceiver)"}}}), - "A.f8d6e0586b0a20c7.MetadataViews.Editions": autogold.Want("Editions", map[string]interface{}{"infoList": []interface{}{map[string]interface{}{"max": 2, "name": "generatedexperiences", "number": 1}}}), - "A.f8d6e0586b0a20c7.MetadataViews.Traits": autogold.Want("Traits", map[string]interface{}{"traits": []interface{}{map[string]interface{}{"displayType": "String", "name": "Artist", "value": "Artist"}}}), - "A.f8d6e0586b0a20c7.MetadataViews.ExternalURL": autogold.Want("ExternalURL", map[string]interface{}{"url": "https://find.xyz/0xf3fcd2c1a78f5eee/collection/main/GeneratedExperiences/332"}), - "A.f8d6e0586b0a20c7.MetadataViews.NFTCollectionDisplay": autogold.Want("NFTCollectionDisplay", map[string]interface{}{ - "bannerImage": map[string]interface{}{"file": map[string]interface{}{"cid": "banner"}, "mediaType": "png"}, "description": "Description", - "externalURL": map[string]interface{}{"url": "https://find.xyz/mp/GeneratedExperiences"}, - "name": "GeneratedExperiences", - "socials": map[string]interface{}{ - "discord": map[string]interface{}{"url": "discord"}, - "twitter": map[string]interface{}{"url": "twitter"}, - }, - "squareImage": map[string]interface{}{ - "file": map[string]interface{}{"cid": "square"}, - "mediaType": "png", - }, - }), - "A.f8d6e0586b0a20c7.MetadataViews.Medias": autogold.Want("Medias", map[string]interface{}{"items": []interface{}{map[string]interface{}{"file": map[string]interface{}{"cid": "thumbnail"}, "mediaType": "image"}, map[string]interface{}{ - "file": map[string]interface{}{"cid": "fullsize"}, - "mediaType": "image", - }}}), - "A.f8d6e0586b0a20c7.MetadataViews.Rarity": autogold.Want("Rarity", map[string]interface{}{"description": "Common"}), - "A.179b6b1cb6755e31.FindPack.PackRevealData": autogold.Want("PackRevealData", map[string]interface{}{"data": map[string]interface{}{"nftImage": "ipfs://thumbnail", "nftName": "Name", "packType": "GeneratedExperiences"}}), - } - - script := ` - import GeneratedExperiences from "../contracts/GeneratedExperiences.cdc" - import MetadataViews from "../contracts/standard/MetadataViews.cdc" - - pub fun main(user: Address, view: String): AnyStruct { - let acct = getAccount(user) - let collectionRef = acct.getCapability(GeneratedExperiences.CollectionPublicPath) - .borrow<&{MetadataViews.ResolverCollection}>() - ?? panic("Could not borrow capability from public collection") - - let resolver = collectionRef.borrowViewResolver(id: collectionRef.getIDs()[1]) - return resolver.resolveView(CompositeType(view)!) - } -` - for view, val := range tcs { - t.Run(fmt.Sprintf("Ensure view : %s returned correctly", view), func(t *testing.T) { + tcs := map[string]autogold.Value{ + "A.f8d6e0586b0a20c7.MetadataViews.Display": autogold.Want("Display", map[string]interface{}{"description": "Description", "name": "Name", "thumbnail": map[string]interface{}{"cid": "thumbnail"}}), + "A.f8d6e0586b0a20c7.MetadataViews.Royalties": autogold.Want("Royalties", map[string]interface{}{"cutInfos": []interface{}{map[string]interface{}{"cut": 0.1, "description": "Royalty", "receiver": map[string]interface{}{ + "address": "0x192440c99cb17282", + "borrowType": "&{A.ee82856bf20e2aa6.FungibleToken.Receiver}", + "id": 6, + }}}}), + "A.f8d6e0586b0a20c7.MetadataViews.Editions": autogold.Want("Editions", map[string]interface{}{"infoList": []interface{}{map[string]interface{}{"max": 2, "name": "generatedexperiences", "number": 1}}}), + "A.f8d6e0586b0a20c7.MetadataViews.Traits": autogold.Want("Traits", map[string]interface{}{"traits": []interface{}{map[string]interface{}{"displayType": "String", "name": "Artist", "value": "Artist"}}}), + "A.f8d6e0586b0a20c7.MetadataViews.NFTCollectionDisplay": autogold.Want("NFTCollectionDisplay", map[string]interface{}{ + "bannerImage": map[string]interface{}{"file": map[string]interface{}{"cid": "banner"}, "mediaType": "png"}, "description": "Description", + "externalURL": map[string]interface{}{"url": "https://find.xyz/mp/GeneratedExperiences"}, + "name": "GeneratedExperiences", + "socials": map[string]interface{}{ + "discord": map[string]interface{}{"url": "discord"}, + "twitter": map[string]interface{}{"url": "twitter"}, + }, + "squareImage": map[string]interface{}{ + "file": map[string]interface{}{"cid": "square"}, + "mediaType": "png", + }, + }), + "A.f8d6e0586b0a20c7.MetadataViews.Medias": autogold.Want("Medias", map[string]interface{}{"items": []interface{}{map[string]interface{}{"file": map[string]interface{}{"cid": "thumbnail"}, "mediaType": "image"}, map[string]interface{}{ + "file": map[string]interface{}{"cid": "fullsize"}, + "mediaType": "image", + }}}), + "A.f8d6e0586b0a20c7.MetadataViews.Rarity": autogold.Want("Rarity", map[string]interface{}{"description": "Common"}), + "A.179b6b1cb6755e31.FindPack.PackRevealData": autogold.Want("PackRevealData", nil), + } - otu.O.Script(script, - WithArg("user", "find-admin"), + for view, val := range tcs { + otu.O.Script("getNFTViewForAddress", + WithArg("aliasOrIdentifier", geIdentifier), + WithArg("id", ids[0]), + WithArg("address", "find-admin"), WithArg("view", view), ). AssertWant(t, val) - }) - } - + } + }) } diff --git a/go.mod b/go.mod index 24a707f7..6387f13d 100644 --- a/go.mod +++ b/go.mod @@ -1,151 +1,213 @@ module github.com/findonflow/find -go 1.18 +go 1.22 + +toolchain go1.22.4 require ( - github.com/bjartek/overflow v1.5.0 + github.com/bjartek/overflow/v2 v2.1.0 + github.com/bjartek/underflow v1.10.0 github.com/hexops/autogold v1.3.1 - github.com/onflow/cadence v0.39.4 + github.com/onflow/cadence v1.2.1 github.com/recursionpharma/go-csv-map v0.0.0-20160524001940-792523c65ae9 - github.com/samber/lo v1.38.1 github.com/sanity-io/litter v1.5.5 - github.com/stretchr/testify v1.8.4 - golang.org/x/crypto v0.7.0 - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 + github.com/stretchr/testify v1.9.0 + golang.org/x/crypto v0.26.0 + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a ) require ( - cloud.google.com/go/compute v1.18.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.12.0 // indirect - cloud.google.com/go/kms v1.9.0 // indirect + cloud.google.com/go v0.112.0 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/kms v1.15.7 // indirect + cloud.google.com/go/storage v1.36.0 // indirect + github.com/DataDog/zstd v1.5.2 // indirect github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/SaveTheRbtz/mph v0.1.1-0.20240117162131-4166ec7869bc // indirect + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.2 // indirect github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect - github.com/bits-and-blooms/bitset v1.5.0 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cockroachdb/errors v1.11.3 // indirect + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/pebble v1.1.1 // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/coreos/go-semver v0.3.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect + github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/ef-ds/deque v1.0.4 // indirect github.com/enescakir/emoji v1.0.0 // indirect - github.com/ethereum/go-ethereum v1.10.22 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/ethereum/c-kzg-4844 v1.0.0 // indirect + github.com/ethereum/go-ethereum v1.13.10 // indirect + github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/fatih/structtag v1.2.0 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.1-0.20230228173756-c0c9f774e40c // indirect github.com/fxamacker/circlehash v0.3.0 // indirect - github.com/glebarez/go-sqlite v1.21.1 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect - github.com/go-test/deep v1.1.0 // indirect + github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.0.0 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.7.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/gosuri/uilive v0.0.4 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect - github.com/hexops/valast v1.4.3 // indirect + github.com/hexops/valast v1.4.4 // indirect + github.com/holiman/bloomfilter/v2 v2.0.3 // indirect + github.com/holiman/uint256 v1.3.0 // indirect + github.com/huandu/go-clone v1.6.0 // indirect + github.com/huandu/go-clone/generic v1.7.2 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/jsonschema v0.7.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/go-block-format v0.0.3 // indirect - github.com/ipfs/go-cid v0.3.2 // indirect + github.com/ipfs/boxo v0.19.0 // indirect + github.com/ipfs/go-block-format v0.2.0 // indirect + github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-datastore v0.6.0 // indirect - github.com/ipfs/go-ipfs-blockstore v1.2.0 // indirect - github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipld-format v0.3.0 // indirect - github.com/ipfs/go-log v1.0.5 // indirect + github.com/ipfs/go-ipfs-util v0.0.3 // indirect + github.com/ipfs/go-ipld-format v0.6.0 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-metrics-interface v0.0.1 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/kevinburke/go-bindata v3.23.0+incompatible // indirect - github.com/klauspost/compress v1.15.15 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/k0kubun/pp v3.0.1+incompatible // indirect + github.com/kevinburke/go-bindata v3.24.0+incompatible // indirect + github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-libp2p v0.24.2 // indirect - github.com/libp2p/go-openssl v0.1.0 // indirect + github.com/libp2p/go-libp2p v0.32.2 // indirect + github.com/libp2p/go-libp2p-pubsub v0.10.0 // indirect + github.com/libp2p/go-msgio v0.3.0 // indirect github.com/lmars/go-slip10 v0.0.0-20190606092855-400ba44fee12 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/logrusorgru/aurora/v4 v4.0.0 // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect - github.com/mattn/go-pointer v0.0.1 // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/multiformats/go-multiaddr v0.8.0 // indirect - github.com/multiformats/go-multibase v0.1.1 // indirect - github.com/multiformats/go-multicodec v0.7.0 // indirect - github.com/multiformats/go-multihash v0.2.1 // indirect - github.com/multiformats/go-multistream v0.3.3 // indirect + github.com/multiformats/go-multiaddr v0.12.2 // indirect + github.com/multiformats/go-multibase v0.2.0 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/nightlyone/lockfile v1.0.0 // indirect - github.com/onflow/atree v0.6.0 // indirect - github.com/onflow/flow-cli/flowkit v1.1.2-0.20230608033953-03cdc33377b3 // indirect - github.com/onflow/flow-core-contracts/lib/go/contracts v1.2.3 // indirect - github.com/onflow/flow-core-contracts/lib/go/templates v1.2.3 // indirect - github.com/onflow/flow-emulator v0.50.4 // indirect - github.com/onflow/flow-ft/lib/go/contracts v0.7.0 // indirect - github.com/onflow/flow-go v0.31.1-0.20230607185125-e75265a6c631 // indirect - github.com/onflow/flow-go-sdk v0.41.2 // indirect - github.com/onflow/flow-go/crypto v0.24.7 // indirect - github.com/onflow/flow-nft/lib/go/contracts v0.0.0-20220727161549-d59b1e547ac4 // indirect - github.com/onflow/flow/protobuf/go/flow v0.3.2-0.20230602212908-08fc6536d391 // indirect - github.com/onflow/fusd/lib/go/contracts v0.0.0-20211021081023-ae9de8fb2c7e // indirect - github.com/onflow/nft-storefront/lib/go/contracts v0.0.0-20221222181731-14b90207cead // indirect - github.com/onflow/sdks v0.5.0 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/onflow/atree v0.8.0 // indirect + github.com/onflow/crypto v0.25.2 // indirect + github.com/onflow/flixkit-go/v2 v2.1.0 // indirect + github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 // indirect + github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0 // indirect + github.com/onflow/flow-emulator v1.1.0 // indirect + github.com/onflow/flow-ft/lib/go/contracts v1.0.1 // indirect + github.com/onflow/flow-ft/lib/go/templates v1.0.1 // indirect + github.com/onflow/flow-go v0.38.0-preview.0.0.20241022154145-6a254edbec23 // indirect + github.com/onflow/flow-go-sdk v1.2.2 // indirect + github.com/onflow/flow-nft/lib/go/contracts v1.2.2 // indirect + github.com/onflow/flow-nft/lib/go/templates v1.2.1 // indirect + github.com/onflow/flow/protobuf/go/flow v0.4.7 // indirect + github.com/onflow/flowkit/v2 v2.1.0 // indirect + github.com/onflow/go-ethereum v1.14.7 // indirect + github.com/onflow/nft-storefront/lib/go/contracts v1.0.0 // indirect + github.com/onflow/sdks v0.6.0-preview.1 // indirect + github.com/onflow/wal v1.0.2 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/psiemens/graceland v1.0.0 // indirect github.com/psiemens/sconfig v0.1.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rs/zerolog v1.29.1 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/sethvargo/go-retry v0.2.3 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/slok/go-http-metrics v0.10.0 // indirect - github.com/smartystreets/goconvey v1.8.0 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect + github.com/smartystreets/goconvey v1.8.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.12.0 // indirect - github.com/subosito/gotenv v1.4.0 // indirect + github.com/spf13/viper v1.15.0 // indirect + github.com/status-im/keycard-go v0.2.0 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/subosito/gotenv v1.4.2 // indirect + github.com/supranational/blst v0.3.11 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/turbolent/prettier v0.0.0-20220320183459-661cc755135d // indirect - github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v4 v4.3.11 // indirect github.com/vmihailenco/tagparser v0.1.1 // indirect @@ -153,37 +215,42 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel v1.14.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect - go.opentelemetry.io/otel/sdk v1.14.0 // indirect - go.opentelemetry.io/otel/trace v1.14.0 // indirect - go.opentelemetry.io/proto/otlp v0.19.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.9.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/tools v0.7.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - gonum.org/v1/gonum v0.11.0 // indirect - google.golang.org/api v0.114.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect - gopkg.in/ini.v1 v1.66.6 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/sdk v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + gonum.org/v1/gonum v0.14.0 // indirect + google.golang.org/api v0.162.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/grpc v1.67.1 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.1.7 // indirect - modernc.org/libc v1.22.3 // indirect - modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.5.0 // indirect - modernc.org/sqlite v1.21.1 // indirect - mvdan.cc/gofumpt v0.4.0 // indirect + lukechampine.com/blake3 v1.3.0 // indirect + modernc.org/libc v1.37.6 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/sqlite v1.28.0 // indirect + mvdan.cc/gofumpt v0.5.0 // indirect + rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 394aec9e..5f88b72e 100644 --- a/go.sum +++ b/go.sum @@ -1,171 +1,138 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/kms v1.0.0/go.mod h1:nhUehi+w7zht2XrUfvTRNpxrfayBHqP4lu2NSywui/0= -cloud.google.com/go/kms v1.9.0 h1:b0votJQa/9DSsxgHwN33/tTLA7ZHVzfWhDCrfiXijSo= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= -github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= +cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= -github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE= -github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/SaveTheRbtz/mph v0.1.1-0.20240117162131-4166ec7869bc h1:DCHzPQOcU/7gwDTWbFQZc5qHMPS1g0xTO56k8NXsv9M= +github.com/SaveTheRbtz/mph v0.1.1-0.20240117162131-4166ec7869bc/go.mod h1:LJM5a3zcIJ/8TmZwlUczvROEJT8ntOdhdG9jjcR1B0I= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= -github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo= +github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.5.1 h1:VGkV9KmhGqOQWnHyi4gLG98kE6OecT42fdrCGFWxJsc= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.5.1/go.mod h1:PLlnMiki//sGnCJiW+aVpvP/C8Kcm8mEj/IVm9+9qk4= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 h1:Wx0rlZoEJR7JwlSZcHnEa7CNjrSIyVxMFWGAaXy4fJY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9/go.mod h1:aVMHdE0aHO3v+f/iw01fmXV/5DbfQ3Bi9nN7nd9bE9Y= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.7.0 h1:HWsM0YQWX76V6MOp07YuTYacm8k7h69ObJuw7Nck+og= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.7.0/go.mod h1:LKb3cKNQIMh+itGnEpKGcnL/6OIjPZqrtYah1w5f+3o= +github.com/aws/aws-sdk-go-v2/service/s3 v1.15.0 h1:nPLfLPfglacc29Y949sDxpr3X/blaY40s3B85WT2yZU= +github.com/aws/aws-sdk-go-v2/service/s3 v1.15.0/go.mod h1:Iv2aJVtVSm/D22rFoX99cLG4q4uB7tppuCsulGe98k4= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= -github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/bjartek/overflow v1.5.0 h1:oXuMxMRvHD7Y40wYnTQKwCqhd242cLHFjnNjwXl/D+4= -github.com/bjartek/overflow v1.5.0/go.mod h1:gCOItbigN5Pe4GmFAx3P0QC6Lfii+gxjPCSHs8gzIfQ= -github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= -github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= -github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/bytecodealliance/wasmtime-go v0.22.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOEnGkAnHh6WtJjMaT2CW4wI= -github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= -github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= -github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bjartek/overflow/v2 v2.1.0 h1:v+Vyl+V/FzJgkU/5EwDBJDRr0PdGjHQWqyt/c0bSRVg= +github.com/bjartek/overflow/v2 v2.1.0/go.mod h1:OOqtWidc76J4an9+ZaI0Rf4hOPRby/b6LJceDsKbiJc= +github.com/bjartek/underflow v1.10.0 h1:xSob5hA4v2JblNTTOXe7Cqgdnc2qYLfb7wTyJZT6+cY= +github.com/bjartek/underflow v1.10.0/go.mod h1:BcuFBItFn7/4zTKOd4Sf4+gOSno4Yjny4X+1hPuEpts= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 h1:SDlJ7bAm4ewvrmZtR0DaiYbQGdKPeaaIm7bM+qRhFeU= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0TxYVST9h4Ie192jJWpHvthBBgg= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= +github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I= +github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= +github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= -github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= @@ -177,106 +144,117 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/ef-ds/deque v1.0.4 h1:iFAZNmveMT9WERAkqLJ+oaABF9AcVQ5AjXem/hroniI= github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg= -github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= +github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/enescakir/emoji v1.0.0 h1:W+HsNql8swfCQFtioDGDHCHri8nudlK1n5p2rHCJoog= github.com/enescakir/emoji v1.0.0/go.mod h1:Bt1EKuLnKDTYpLALApstIkAjdDrS/8IAgTkKp+WKFD0= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/go-ethereum v1.9.9/go.mod h1:a9TqabFudpDu1nucId+k9S8R9whYaHnGBLKFouA5EAo= -github.com/ethereum/go-ethereum v1.10.22 h1:HbEgsDo1YTGIf4KB/NNpn+XH+PiNJXUZ9ksRxiqWyMc= -github.com/ethereum/go-ethereum v1.10.22/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= -github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.10 h1:Ppdil79nN+Vc+mXfge0AuUgmKWuVv4eMqzoIVSdqZek= +github.com/ethereum/go-ethereum v1.13.10/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= +github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= +github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flynn/noise v1.0.1 h1:vPp/jdQLXC6ppsXSj/pM3W1BIJ5FEHE2TulSJBpb43Y= +github.com/flynn/noise v1.0.1/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fxamacker/cbor/v2 v2.2.1-0.20210927235116-3d6d5d1de29b/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fxamacker/cbor/v2 v2.4.1-0.20230228173756-c0c9f774e40c h1:5tm/Wbs9d9r+qZaUFXk59CWDD0+77PBqDREffYkyi5c= github.com/fxamacker/cbor/v2 v2.4.1-0.20230228173756-c0c9f774e40c/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/fxamacker/circlehash v0.1.0/go.mod h1:3aq3OfVvsWtkWMb6A1owjOQFA+TLsD5FgJflnaQwtMM= github.com/fxamacker/circlehash v0.3.0 h1:XKdvTtIJV9t7DDUtsf0RIpC1OcxZtPbmgIH7ekx28WA= github.com/fxamacker/circlehash v0.3.0/go.mod h1:3aq3OfVvsWtkWMb6A1owjOQFA+TLsD5FgJflnaQwtMM= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gammazero/deque v0.1.0 h1:f9LnNmq66VDeuAlSAapemq/U7hJ2jpIWa4c09q8Dlik= +github.com/gammazero/deque v0.1.0/go.mod h1:KQw7vFau1hHuM8xmI9RbgKFbAsQFWmBpqQ2KenFLk6M= +github.com/gammazero/workerpool v1.1.2 h1:vuioDQbgrz4HoaCi2q1HLlOXdpbap5AET7xu5/qj87g= +github.com/gammazero/workerpool v1.1.2/go.mod h1:UelbXcO0zCIGFcufcirHhq2/xtLXJdQ29qZNlXG9OjQ= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/glebarez/go-sqlite v1.21.1 h1:7MZyUPh2XTrHS7xNEHQbrhfMZuPSzhkm2A1qgg0y5NY= -github.com/glebarez/go-sqlite v1.21.1/go.mod h1:ISs8MF6yk5cL4n/43rSOmVMGJJjHYr7L2MbZZ5Q4E2E= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= +github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -286,431 +264,435 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20221219190121-3cb0bae90811 h1:wORs2YN3R3ona/CXYuTvLM31QlgoNKHvlCNuArCDDCU= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 h1:dHLYa5D8/Ta0aLR2XcPsrkpAgGeFs6thhMcQK0oQ0n8= +github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uilive v0.0.4 h1:hUEBpQDj8D8jXgtCdBu7sWsy5sbW/5GhuO8KBwJ2jyY= github.com/gosuri/uilive v0.0.4/go.mod h1:V/epo5LjjlDE5RJUcqx8dbw+zc93y5Ya3yg8tfZ74VI= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= -github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/autogold v0.8.1/go.mod h1:97HLDXyG23akzAoRYJh/2OBs3kd80eHyKPvZw0S5ZBY= github.com/hexops/autogold v1.3.1 h1:YgxF9OHWbEIUjhDbpnLhgVsjUDsiHDTyDfy2lrfdlzo= github.com/hexops/autogold v1.3.1/go.mod h1:sQO+mQUCVfxOKPht+ipDSkJ2SCJ7BNJVHZexsXqWMx4= +github.com/hexops/autogold/v2 v2.2.1 h1:JPUXuZQGkcQMv7eeDXuNMovjfoRYaa0yVcm+F3voaGY= +github.com/hexops/autogold/v2 v2.2.1/go.mod h1:IJwxtUfj1BGLm0YsR/k+dIxYi6xbeLjqGke2bzcOTMI= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/hexops/valast v1.4.3 h1:oBoGERMJh6UZdRc6cduE1CTPK+VAdXA59Y1HFgu3sm0= github.com/hexops/valast v1.4.3/go.mod h1:Iqx2kLj3Jn47wuXpj3wX40xn6F93QNFBHuiKBerkTGA= +github.com/hexops/valast v1.4.4 h1:rETyycw+/L2ZVJHHNxEBgh8KUn+87WugH9MxcEv9PGs= +github.com/hexops/valast v1.4.4/go.mod h1:Jcy1pNH7LNraVaAZDLyv21hHg2WBv9Nf9FL6fGxU7o4= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= +github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= +github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= +github.com/huandu/go-clone v1.6.0 h1:HMo5uvg4wgfiy5FoGOqlFLQED/VGRm2D9Pi8g1FXPGc= +github.com/huandu/go-clone v1.6.0/go.mod h1:ReGivhG6op3GYr+UY3lS6mxjKp7MIGTknuU5TbTVaXE= +github.com/huandu/go-clone/generic v1.7.2 h1:47pQphxs1Xc9cVADjOHN+Bm5D0hNagwH9UXErbxgVKA= +github.com/huandu/go-clone/generic v1.7.2/go.mod h1:xgd9ZebcMsBWWcBx5mVMCoqMX24gLWr5lQicr+nVXNs= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So= +github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= -github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= -github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= -github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= -github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= -github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/boxo v0.19.0 h1:UbX9FBJQF19ACLqRZOgdEla6jR/sC4H1O+iGE0NToXA= +github.com/ipfs/boxo v0.19.0/go.mod h1:V5gJzbIMwKEXrg3IdvAxIdF7UPgU4RsXmNGS8MQ/0D4= +github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= +github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3j8qz0ykw= -github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= -github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= -github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= -github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= -github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipld-format v0.3.0 h1:Mwm2oRLzIuUwEPewWAWyMuuBQUsn3awfFEYVb8akMOQ= -github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= +github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= +github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= +github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= -github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= -github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= +github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= -github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kevinburke/go-bindata v3.22.0+incompatible/go.mod h1:/pEEZ72flUW2p0yi30bslSp9YqD9pysLxunQDdb2CPM= -github.com/kevinburke/go-bindata v3.23.0+incompatible h1:rqNOXZlqrYhMVVAsQx8wuc+LaA73YcfbQ407wAykyS8= -github.com/kevinburke/go-bindata v3.23.0+incompatible/go.mod h1:/pEEZ72flUW2p0yi30bslSp9YqD9pysLxunQDdb2CPM= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= +github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= +github.com/kevinburke/go-bindata v3.24.0+incompatible h1:qajFA3D0pH94OTLU4zcCCKCDgR+Zr2cZK/RPJHDdFoY= +github.com/kevinburke/go-bindata v3.24.0+incompatible/go.mod h1:/pEEZ72flUW2p0yi30bslSp9YqD9pysLxunQDdb2CPM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= -github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= +github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/libp2p/go-addr-util v0.1.0 h1:acKsntI33w2bTU7tC9a0SaPimJGfSI0bFKC18ChxeVI= +github.com/libp2p/go-addr-util v0.1.0/go.mod h1:6I3ZYuFr2O/9D+SoyM0zEw0EF3YkldtTX406BpdQMqw= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-libp2p v0.24.2 h1:iMViPIcLY0D6zr/f+1Yq9EavCZu2i7eDstsr1nEwSAk= -github.com/libp2p/go-libp2p v0.24.2/go.mod h1:WuxtL2V8yGjam03D93ZBC19tvOUiPpewYv1xdFGWu1k= -github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU= -github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= -github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= -github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ= +github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= +github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= +github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= +github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= +github.com/libp2p/go-libp2p v0.32.2 h1:s8GYN4YJzgUoyeYNPdW7JZeZ5Ee31iNaIBfGYMAY4FQ= +github.com/libp2p/go-libp2p v0.32.2/go.mod h1:E0LKe+diV/ZVJVnOJby8VC5xzHF0660osg71skcxJvk= +github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= +github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= +github.com/libp2p/go-libp2p-kad-dht v0.25.2 h1:FOIk9gHoe4YRWXTu8SY9Z1d0RILol0TrtApsMDPjAVQ= +github.com/libp2p/go-libp2p-kad-dht v0.25.2/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= +github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0= +github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0= +github.com/libp2p/go-libp2p-pubsub v0.10.0 h1:wS0S5FlISavMaAbxyQn3dxMOe2eegMfswM471RuHJwA= +github.com/libp2p/go-libp2p-pubsub v0.10.0/go.mod h1:1OxbaT/pFRO5h+Dpze8hdHQ63R0ke55XTs6b6NwLLkw= +github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= +github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= +github.com/libp2p/go-libp2p-routing-helpers v0.7.3 h1:u1LGzAMVRK9Nqq5aYDVOiq/HaB93U9WWczBzGyAC5ZY= +github.com/libp2p/go-libp2p-routing-helpers v0.7.3/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8= +github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= +github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= +github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= +github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= +github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= +github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= +github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= +github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= +github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lmars/go-slip10 v0.0.0-20190606092855-400ba44fee12 h1:qFV7dBLhw5z4hka5gjtIzg1Kq9ie8t8P7Cy0uIxRyAQ= github.com/lmars/go-slip10 v0.0.0-20190606092855-400ba44fee12/go.mod h1:QIsK6U93yCP6TnGsShCv5wl4gcz/mpCHl+aToBsl5Sc= -github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora/v4 v4.0.0 h1:sRjfPpun/63iADiSvGGjgA1cAYegEWMPCJdUpJYn9JA= github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= -github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= -github.com/multiformats/go-multiaddr v0.8.0 h1:aqjksEcqK+iD/Foe1RRFsGZh8+XFiGo7FgUCZlpv3LU= -github.com/multiformats/go-multiaddr v0.8.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI= -github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8= -github.com/multiformats/go-multicodec v0.7.0 h1:rTUjGOwjlhGHbEMbPoSUJowG1spZTVsITRANCjKTUAQ= -github.com/multiformats/go-multicodec v0.7.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= -github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o= -github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24= +github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M= +github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= +github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nightlyone/lockfile v1.0.0 h1:RHep2cFKK4PonZJDdEl4GmkabuhbsRMgk/k3uAmxBiA= github.com/nightlyone/lockfile v1.0.0/go.mod h1:rywoIealpdNse2r832aiD9jRk8ErCatROs6LzC841CI= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/onflow/atree v0.1.0-beta1.0.20211027184039-559ee654ece9/go.mod h1:+6x071HgCF/0v5hQcaE5qqjc2UqN5gCU8h5Mk6uqpOg= -github.com/onflow/atree v0.6.0 h1:j7nQ2r8npznx4NX39zPpBYHmdy45f4xwoi+dm37Jk7c= -github.com/onflow/atree v0.6.0/go.mod h1:gBHU0M05qCbv9NN0kijLWMgC47gHVNBIp4KmsVFi0tc= -github.com/onflow/cadence v0.20.1/go.mod h1:7mzUvPZUIJztIbr9eTvs+fQjWWHTF8veC+yk4ihcNIA= -github.com/onflow/cadence v0.39.4 h1:Rg2WUtrgXWADHlN2n0NKo+0sAdijx67oiTNdrG0vJOM= -github.com/onflow/cadence v0.39.4/go.mod h1:OIJLyVBPa339DCBQXBfGaorT4tBjQh9gSKe+ZAIyyh0= -github.com/onflow/flow-cli/flowkit v1.1.2-0.20230608033953-03cdc33377b3 h1:ig6c0LZzea4Y/ho9q2770W0NmtzsaKT7B1BFBay25Q4= -github.com/onflow/flow-cli/flowkit v1.1.2-0.20230608033953-03cdc33377b3/go.mod h1:WLhnz4ttldVAD120bgDvA5WbqhipbeIc4KHaMrUhYhI= -github.com/onflow/flow-core-contracts/lib/go/contracts v1.2.3 h1:wV+gcgOY0oJK4HLZQYQoK+mm09rW1XSxf83yqJwj0n4= -github.com/onflow/flow-core-contracts/lib/go/contracts v1.2.3/go.mod h1:Osvy81E/+tscQM+d3kRFjktcIcZj2bmQ9ESqRQWDEx8= -github.com/onflow/flow-core-contracts/lib/go/templates v1.2.3 h1:X25A1dNajNUtE+KoV76wQ6BR6qI7G65vuuRXxDDqX7E= -github.com/onflow/flow-core-contracts/lib/go/templates v1.2.3/go.mod h1:dqAUVWwg+NlOhsuBHex7bEWmsUjsiExzhe/+t4xNH6A= -github.com/onflow/flow-emulator v0.50.4 h1:Tm54ORTrKgKriaYudNDaE+bu4DMRya88GvOUhmmCNMg= -github.com/onflow/flow-emulator v0.50.4/go.mod h1:wHxzfXEC0B6ginYY2ppmpLLUR/7up1sjhXd+muHb6lg= -github.com/onflow/flow-ft/lib/go/contracts v0.7.0 h1:XEKE6qJUw3luhsYmIOteXP53gtxNxrwTohgxJXCYqBE= -github.com/onflow/flow-ft/lib/go/contracts v0.7.0/go.mod h1:kTMFIySzEJJeupk+7EmXs0EJ6CBWY/MV9fv9iYQk+RU= -github.com/onflow/flow-go v0.31.1-0.20230607185125-e75265a6c631 h1:O6f/c9y3j0N6/u2anzDZKtdoGolzV2LJ0Xcg0vO4ElY= -github.com/onflow/flow-go v0.31.1-0.20230607185125-e75265a6c631/go.mod h1:ZKfmlbs+X3t+5cURDllEA7j+/O79yNG0c6z7LkxGVi8= -github.com/onflow/flow-go-sdk v0.24.0/go.mod h1:IoptMLPyFXWvyd9yYA6/4EmSeeozl6nJoIv4FaEMg74= -github.com/onflow/flow-go-sdk v0.41.2 h1:O/yjdS0V+NHgg98QeVWQt2aDJ+m3znGgBOPy/PfrhXo= -github.com/onflow/flow-go-sdk v0.41.2/go.mod h1:SJ2oAvz3FHCyNfDw7XojmIxsduVFyL7dAgp+W1LnW8M= -github.com/onflow/flow-go/crypto v0.21.3/go.mod h1:vI6V4CY3R6c4JKBxdcRiR/AnjBfL8OSD97bJc60cLuQ= -github.com/onflow/flow-go/crypto v0.24.7 h1:RCLuB83At4z5wkAyUCF7MYEnPoIIOHghJaODuJyEoW0= -github.com/onflow/flow-go/crypto v0.24.7/go.mod h1:fqCzkIBBMRRkciVrvW21rECKq1oD7Q6u+bCI78lfNX0= -github.com/onflow/flow-nft/lib/go/contracts v0.0.0-20220727161549-d59b1e547ac4 h1:5AnM9jIwkyHaY6+C3cWnt07oTOYctmwxvpiL25HRJws= -github.com/onflow/flow-nft/lib/go/contracts v0.0.0-20220727161549-d59b1e547ac4/go.mod h1:YsvzYng4htDgRB9sa9jxdwoTuuhjK8WYWXTyLkIigZY= -github.com/onflow/flow/protobuf/go/flow v0.2.2/go.mod h1:gQxYqCfkI8lpnKsmIjwtN2mV/N2PIwc1I+RUK4HPIc8= -github.com/onflow/flow/protobuf/go/flow v0.3.2-0.20230602212908-08fc6536d391 h1:6uKg0gpLKpTZKMihrsFR0Gkq++1hykzfR1tQCKuOfw4= -github.com/onflow/flow/protobuf/go/flow v0.3.2-0.20230602212908-08fc6536d391/go.mod h1:NA2pX2nw8zuaxfKphhKsk00kWLwfd+tv8mS23YXO4Sk= -github.com/onflow/fusd/lib/go/contracts v0.0.0-20211021081023-ae9de8fb2c7e h1:RHaXPHvWCy3VM62+HTyu6DYq5T8rrK1gxxqogKuJ4S4= -github.com/onflow/fusd/lib/go/contracts v0.0.0-20211021081023-ae9de8fb2c7e/go.mod h1:CRX9eXtc9zHaRVTW1Xh4Cf5pZgKkQuu1NuSEVyHXr/0= -github.com/onflow/nft-storefront/lib/go/contracts v0.0.0-20221222181731-14b90207cead h1:2j1Unqs76Z1b95Gu4C3Y28hzNUHBix7wL490e61SMSw= -github.com/onflow/nft-storefront/lib/go/contracts v0.0.0-20221222181731-14b90207cead/go.mod h1:E3ScfQb5XcWJCIAdtIeEnr5i5l2y60GT0BTXeIHseWg= -github.com/onflow/sdks v0.5.0 h1:2HCRibwqDaQ1c9oUApnkZtEAhWiNY2GTpRD5+ftdkN8= -github.com/onflow/sdks v0.5.0/go.mod h1:F0dj0EyHC55kknLkeD10js4mo14yTdMotnWMslPirrU= -github.com/onflow/wal v0.0.0-20230529184820-bc9f8244608d h1:gAEqYPn3DS83rHIKEpsajnppVD1+zwuYPFyeDVFaQvg= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onflow/atree v0.8.0 h1:qg5c6J1gVDNObughpEeWm8oxqhPGdEyGrda121GM4u0= +github.com/onflow/atree v0.8.0/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo= +github.com/onflow/cadence v1.2.1 h1:hmSsgX3rTsp2E5qTSl1JXINt8qepdRrHTwDSYqN5Nxs= +github.com/onflow/cadence v1.2.1/go.mod h1:fJxxOAp1wnWDfOHT8GOc1ypsU0RR5E3z51AhG8Yf5jg= +github.com/onflow/crypto v0.25.2 h1:GjHunqVt+vPcdqhxxhAXiMIF3YiLX7gTuTR5O+VG2ns= +github.com/onflow/crypto v0.25.2/go.mod h1:fY7eLqUdMKV8EGOw301unP8h7PvLVy8/6gVR++/g0BY= +github.com/onflow/flixkit-go/v2 v2.1.0 h1:WAw6hF2QrTvqsmBX9s396OfnMCthLD9wK2MEqFtCAy0= +github.com/onflow/flixkit-go/v2 v2.1.0/go.mod h1:Lg0FbUBpAqcFuCRuDFxBIKH/Am2rH6+nlGFGYrQwvZE= +github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 h1:R86HaOuk6vpuECZnriEUE7bw9inC2AtdSn8lL/iwQLQ= +github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0/go.mod h1:9asTBnB6Tw2UlVVtQKyS/egYv3xr4zVlJnJ75z1dfac= +github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0 h1:u2DAG8pk0xFH7TwS70t1gSZ/FtIIZWMSNyiu4SeXBYg= +github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0/go.mod h1:pN768Al/wLRlf3bwugv9TyxniqJxMu4sxnX9eQJam64= +github.com/onflow/flow-emulator v1.1.0 h1:ocF5Pv/zrY5jb0iMxQ15NOM6EuS9Y/N+SUzREi+lKcg= +github.com/onflow/flow-emulator v1.1.0/go.mod h1:wuSY3boFgO+ZRW8PGeWcs+iwcicqkO58G1iPHqRQYDY= +github.com/onflow/flow-ft/lib/go/contracts v1.0.1 h1:Ts5ob+CoCY2EjEd0W6vdLJ7hLL3SsEftzXG2JlmSe24= +github.com/onflow/flow-ft/lib/go/contracts v1.0.1/go.mod h1:PwsL8fC81cjnUnTfmyL/HOIyHnyaw/JA474Wfj2tl6A= +github.com/onflow/flow-ft/lib/go/templates v1.0.1 h1:FDYKAiGowABtoMNusLuRCILIZDtVqJ/5tYI4VkF5zfM= +github.com/onflow/flow-ft/lib/go/templates v1.0.1/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE= +github.com/onflow/flow-go v0.38.0-preview.0.0.20241022154145-6a254edbec23 h1:spF44tXZ341oVDTuXzzKTQ0W6rwZFV9r2/SRVVaMReo= +github.com/onflow/flow-go v0.38.0-preview.0.0.20241022154145-6a254edbec23/go.mod h1:6f7CTcguVOBINmraaWMiij5e2zu7W2mKsOmXAfvCZ2g= +github.com/onflow/flow-go-sdk v1.2.2 h1:F78Sq/VaExgtaQv739k06gnx2aIyLF5wVE0XwxFpmsc= +github.com/onflow/flow-go-sdk v1.2.2/go.mod h1:yhQ5+Sp2xWoCQ1fuRDswawTDQ0ng0z5nTkFVH82xL7E= +github.com/onflow/flow-nft/lib/go/contracts v1.2.2 h1:XFERNVUDGbZ4ViZjt7P1cGD80mO1PzUJYPfdhXFsGbQ= +github.com/onflow/flow-nft/lib/go/contracts v1.2.2/go.mod h1:eZ9VMMNfCq0ho6kV25xJn1kXeCfxnkhj3MwF3ed08gY= +github.com/onflow/flow-nft/lib/go/templates v1.2.1 h1:SAALMZPDw9Eb9p5kSLnmnFxjyig1MLiT4JUlLp0/bSE= +github.com/onflow/flow-nft/lib/go/templates v1.2.1/go.mod h1:W6hOWU0xltPqNpv9gQX8Pj8Jtf0OmRxc1XX2V0kzJaI= +github.com/onflow/flow/protobuf/go/flow v0.4.7 h1:iP6DFx4wZ3ETORsyeqzHu7neFT3d1CXF6wdK+AOOjmc= +github.com/onflow/flow/protobuf/go/flow v0.4.7/go.mod h1:NA2pX2nw8zuaxfKphhKsk00kWLwfd+tv8mS23YXO4Sk= +github.com/onflow/flowkit/v2 v2.1.0 h1:HWx3wLMOZltC8D12YZn11bYDUaLBeVq3qVy2TY+5b7k= +github.com/onflow/flowkit/v2 v2.1.0/go.mod h1:LgV2PJRp9zRtmThruzJ/uaAxPgplAGEA+gBzLODm6Q4= +github.com/onflow/go-ethereum v1.14.7 h1:gg3awYqI02e3AypRdpJKEvNTJ6kz/OhAqRti0h54Wlc= +github.com/onflow/go-ethereum v1.14.7/go.mod h1:zV14QLrXyYu5ucvcwHUA0r6UaqveqbXaehAVQJlSW+I= +github.com/onflow/nft-storefront/lib/go/contracts v1.0.0 h1:sxyWLqGm/p4EKT6DUlQESDG1ZNMN9GjPCm1gTq7NGfc= +github.com/onflow/nft-storefront/lib/go/contracts v1.0.0/go.mod h1:kMeq9zUwCrgrSojEbTUTTJpZ4WwacVm2pA7LVFr+glk= +github.com/onflow/sdks v0.6.0-preview.1 h1:mb/cUezuqWEP1gFZNAgUI4boBltudv4nlfxke1KBp9k= +github.com/onflow/sdks v0.6.0-preview.1/go.mod h1:F0dj0EyHC55kknLkeD10js4mo14yTdMotnWMslPirrU= +github.com/onflow/wal v1.0.2 h1:5bgsJVf2O3cfMNK12fiiTyYZ8cOrUiELt3heBJfHOhc= +github.com/onflow/wal v1.0.2/go.mod h1:iMC8gkLqu4nkbkAla5HkSBb+FGyQOZiWz3DYm2wSXCk= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= +github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= +github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= -github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= +github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/psiemens/graceland v1.0.0 h1:L580AVV4Q2XLcPpmvxJRH9UpEAYr/eu2jBKmMglhvM8= github.com/psiemens/graceland v1.0.0/go.mod h1:1Tof+vt1LbmcZFE0lzgdwMN0QBymAChG3FRgDx8XisU= github.com/psiemens/sconfig v0.1.0 h1:xfWqW+TRpih7mXZIqKYTmpRhlZLQ1kbxV8EjllPv76s= github.com/psiemens/sconfig v0.1.0/go.mod h1:+MLKqdledP/8G3rOBpknbLh0IclCf4WneJUtS26JB2U= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= +github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q= +github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c= +github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY= +github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc= +github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= +github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/recursionpharma/go-csv-map v0.0.0-20160524001940-792523c65ae9 h1:cvht1GrOF8MbAgDvN6flt1sj9Aixv/SokD/XqH6MXIQ= github.com/recursionpharma/go-csv-map v0.0.0-20160524001940-792523c65ae9/go.mod h1:Voxo2KUk+o0x2taVupAT82GWwNK6Nv7LFwZHyJduxnY= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= -github.com/robertkrimen/otto v0.0.0-20170205013659-6a77b7cbc37d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= -github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= -github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= -github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= -github.com/schollz/progressbar/v3 v3.8.3/go.mod h1:pWnVCjSBZsT2X3nx9HfRdnCDrpbevliMeoEVhStwHko= github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE= +github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ= github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg= github.com/sethvargo/go-retry v0.2.3 h1:oYlgvIvsju3jNbottWABtbnoLC+GDtLdBHxKWxQm/iU= github.com/sethvargo/go-retry v0.2.3/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/slok/go-http-metrics v0.10.0 h1:rh0LaYEKza5eaYRGDXujKrOln57nHBi4TtVhmNEpbgM= github.com/slok/go-http-metrics v0.10.0/go.mod h1:lFqdaS4kWMfUKCSukjC47PdCeTk+hXDUVm8kLHRqJ38= -github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU= -github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w= -github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg= +github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= +github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= +github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= +github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -719,264 +701,180 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= -github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= +github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= +github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs= -github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= -github.com/supranational/blst v0.3.4/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/supranational/blst v0.3.10 h1:CMciDZ/h4pXDDXQASe8ZGTNKUiVNxVVA5hpci2Uuhuk= -github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c h1:HelZ2kAFadG0La9d+4htN4HzQ68Bm2iM9qKMSMES6xg= github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c/go.mod h1:JlzghshsemAMDGZLytTFY8C1JQxQPhnatWqNwUXjggo= github.com/thoas/go-funk v0.9.2 h1:oKlNYv0AY5nyf9g+/GhMgS/UO2ces0QRdPKwkhY3VCk= -github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= -github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= +github.com/thoas/go-funk v0.9.2/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/turbolent/prettier v0.0.0-20220320183459-661cc755135d h1:5JInRQbk5UBX8JfUvKh2oYTLMVwj3p6n+wapDDm7hko= github.com/turbolent/prettier v0.0.0-20220320183459-661cc755135d/go.mod h1:Nlx5Y115XQvNcIdIy7dZXaNSUpzwBSge4/Ivk93/Yog= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack/v4 v4.3.11 h1:Q47CePddpNGNhk4GCnAx9DDtASi2rasatE0cd26cZoE= github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.0/go.mod h1:G9pM4qQwjRzF1/v7+vabMj/c5mWpGZ2Wzo3Eb4z0pb4= +github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= -github.com/zeebo/pcg v1.0.0/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= -go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 h1:/fXHZHGvro6MVqV34fJzDhi7sHGpX3Ej/Qjmfn003ho= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 h1:TKf2uAs2ueguzLaxOCBXNpHxfO/aC7PAdDsSH0IbeRQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 h1:ap+y8RXX3Mu9apKVtOkM6WSFESLM8K3wNQyOU8sWHcc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM= -go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= -go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= -go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= -go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= +go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= -go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -984,308 +882,101 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.6.1/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E= -google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= +gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= +google.golang.org/api v0.162.0 h1:Vhs54HkaEpkMBdgGdOT2P6F0csGG/vxDS0hWHJzmmps= +google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211007155348-82e027067bd4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1294,35 +985,30 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= -gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -1332,28 +1018,23 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY= -modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/sqlite v1.21.1 h1:GyDFqNnESLOhwwDRaHGdp2jKLDzpyT/rNLglX3ZkMSU= -modernc.org/sqlite v1.21.1/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI= -mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw= +modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= +modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= -pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= -pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E= +mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/integrating.md b/integrating.md index 3371cc65..7c976232 100644 --- a/integrating.md +++ b/integrating.md @@ -13,7 +13,7 @@ In order to integrate with .find you have a couple of options. ### The web2 serverless api -This api is published at https://lookup.find.xyz/api/lookup +This api is access(all)lished at https://lookup.find.xyz/api/lookup It can be called either with a name or an address @@ -33,7 +33,7 @@ We have tried to make it easy to use .find in cadence so most functions are onel ```cadence import FIND from 0x097bafa4e0b48eef -pub fun main(name: String) : Address? { +access(all) main(name: String) : Address? { return FIND.lookupAddress(name) } ``` @@ -42,7 +42,7 @@ If you want the read-only profile of a user for displaying in your solution you ```cadence import FIND, Profile from 0x097bafa4e0b48eef -pub fun main(name: String) : Profile.UserProfile? { +access(all) main(name: String) : Profile.UserProfile? { return FIND.lookup(name)?.asProfile() } ``` @@ -52,7 +52,7 @@ pub fun main(name: String) : Profile.UserProfile? { ```cadence import FIND, Profile from 0x097bafa4e0b48eef -pub fun main(address: Address) : String? { +access(all) main(address: Address) : String? { return FIND.reverseLookup(address) } ``` @@ -84,14 +84,14 @@ Implementing MetadataViews standards in the right way can help your NFTs display In essence what we need for each nft is the fields: ``` - pub let id:UInt64 - pub let name: String: The name of the nft - pub let image: String : the http url to the image, or ipfs:// - pub let url: String: the url to go to when an nft is clicked - pub let listPrice: UFix64? : if this is item is listed in a marketplace show the price here - pub let listToken: String? : the string representation of the token used. Identifier of FT - pub let contentType:String : content type of image url, image or video works fine here - pub let rarity:String: rarity description for this NFT + access(all) let id:UInt64 + access(all) let name: String: The name of the nft + access(all) let image: String : the http url to the image, or ipfs:// + access(all) let url: String: the url to go to when an nft is clicked + access(all) let listPrice: UFix64? : if this is item is listed in a marketplace show the price here + access(all) let listToken: String? : the string representation of the token used. Identifier of FT + access(all) let contentType:String : content type of image url, image or video works fine here + access(all) let rarity:String: rarity description for this NFT ``` --> merchant account forwarder --> dapper - //the alternative would be - //switchboard --> our forwarder --> merchant account forwarder --> dapper - switchboard.addNewVaultWrapper(capability: dapperDUCReceiver, type: Type<@DapperUtilityCoin.Vault>()) - switchboard.addNewVaultWrapper(capability: dapperFUTReceiver, type: Type<@FlowUtilityToken.Vault>()) - switchboard.addNewVault(capability: usdcCap) - switchboard.addNewVault(capability: fusdReceiver) - switchboard.addNewVault(capability: acct.getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)) - - acct.save(<- switchboard, to: FungibleTokenSwitchboard.StoragePath) - acct.link<&FungibleTokenSwitchboard.Switchboard{FungibleToken.Receiver}>( FungibleTokenSwitchboard.ReceiverPublicPath, target: FungibleTokenSwitchboard.StoragePath) - acct.link<&FungibleTokenSwitchboard.Switchboard{FungibleTokenSwitchboard.SwitchboardPublic, FungibleToken.Receiver}>( - FungibleTokenSwitchboard.PublicPath, - target: FungibleTokenSwitchboard.StoragePath - ) - } -} diff --git a/transactions/initNameVoucher.cdc b/transactions/initNameVoucher.cdc index a7a11a94..a81bbf39 100644 --- a/transactions/initNameVoucher.cdc +++ b/transactions/initNameVoucher.cdc @@ -1,43 +1,12 @@ -import NameVoucher from "../contracts/NameVoucher.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "NameVoucher" transaction() { - prepare(account: AuthAccount) { - - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - return - } - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - - } + prepare(account: auth (StorageCapabilities, SaveValue, PublishCapability, BorrowValue) &Account) { + let col= account.storage.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) + if col == nil { + account.storage.save( <- NameVoucher.createEmptyCollection(nftType:Type<@NameVoucher.NFT>()), to: NameVoucher.CollectionStoragePath) + let cap = account.capabilities.storage.issue<&NameVoucher.Collection>(NameVoucher.CollectionStoragePath) + account.capabilities.publish(cap, at: NameVoucher.CollectionPublicPath) + } + } } diff --git a/transactions/initSwitchboard.cdc b/transactions/initSwitchboard.cdc index e86f1fc8..d0985b69 100644 --- a/transactions/initSwitchboard.cdc +++ b/transactions/initSwitchboard.cdc @@ -1,82 +1,60 @@ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" -import TokenForwarding from "../contracts/standard/TokenForwarding.cdc" -import FungibleTokenSwitchboard from "../contracts/standard/FungibleTokenSwitchboard.cdc" -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" +import "FungibleToken" +import "FlowToken" +import "TokenForwarding" +import "FungibleTokenSwitchboard" +import "DapperUtilityCoin" +import "FlowUtilityToken" transaction(dapperAddress: Address) { - prepare(acct: AuthAccount) { + prepare(account: auth (StorageCapabilities, SaveValue,PublishCapability, BorrowValue) &Account) { let dapper = getAccount(dapperAddress) - //FUSD - let fusdReceiver = acct.getCapability<&{FungibleToken.Receiver}>(/public/fusdReceiver) - if !fusdReceiver.check() { - let fusd <- FUSD.createEmptyVault() - acct.save(<- fusd, to: /storage/fusdVault) - acct.link<&FUSD.Vault{FungibleToken.Receiver}>( /public/fusdReceiver, target: /storage/fusdVault) - acct.link<&FUSD.Vault{FungibleToken.Balance}>( /public/fusdBalance, target: /storage/fusdVault) - } - - //USDC - let usdcCap = acct.getCapability<&{FungibleToken.Receiver}>(FiatToken.VaultReceiverPubPath) - if !usdcCap.check() { - acct.save( <-FiatToken.createEmptyVault(), to: FiatToken.VaultStoragePath) - acct.link<&FiatToken.Vault{FungibleToken.Receiver}>( FiatToken.VaultReceiverPubPath, target: FiatToken.VaultStoragePath) - acct.link<&FiatToken.Vault{FiatToken.ResourceId}>( FiatToken.VaultUUIDPubPath, target: FiatToken.VaultStoragePath) - acct.link<&FiatToken.Vault{FungibleToken.Balance}>( FiatToken.VaultBalancePubPath, target:FiatToken.VaultStoragePath) - } - - //Dapper utility token - let dapperDUCReceiver = dapper.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) - let DUCReceiver = acct.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) + var DUCReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) if !DUCReceiver.check(){ + let dapperDUCReceiver = dapper.capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) let ducForwarder <- TokenForwarding.createNewForwarder(recipient: dapperDUCReceiver) - acct.save(<-ducForwarder, to: /storage/dapperUtilityCoinReceiver) - acct.link<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver, target: /storage/dapperUtilityCoinReceiver) + account.storage.save(<-ducForwarder, to: /storage/dapperUtilityCoinReceiver) + DUCReceiver = account.capabilities.storage.issue<&{FungibleToken.Receiver}>(/storage/dapperUtilityCoinReceiver) + account.capabilities.publish(DUCReceiver, at: /public/dapperUtilityCoinReceiver) } //FlowUtility token - let dapperFUTReceiver = dapper.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - let FUTReceiver = acct.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) + var FUTReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) if !FUTReceiver.check(){ + let dapperFUTReceiver = dapper.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapperFUTReceiver) - acct.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) - acct.link<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver, target: /storage/flowUtilityTokenReceiver) + account.storage.save(<-futForwarder, to: /storage/flowUtilityTokenVault) + FUTReceiver = account.capabilities.storage.issue<&{FungibleToken.Receiver}>(/storage/flowUtilityTokenVault) + account.capabilities.publish(FUTReceiver, at: /public/flowUtilityTokenReceiver) } - let switchboardRef = acct.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath) - if switchboardRef == nil{ + let switchboardRef = account.storage.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath) + if switchboardRef == nil { let sb <- FungibleTokenSwitchboard.createSwitchboard() - acct.save(<- sb, to: FungibleTokenSwitchboard.StoragePath) - acct.link<&FungibleTokenSwitchboard.Switchboard{FungibleToken.Receiver}>( FungibleTokenSwitchboard.ReceiverPublicPath, target: FungibleTokenSwitchboard.StoragePath) - acct.link<&FungibleTokenSwitchboard.Switchboard{FungibleTokenSwitchboard.SwitchboardPublic, FungibleToken.Receiver}>( - FungibleTokenSwitchboard.PublicPath, - target: FungibleTokenSwitchboard.StoragePath - ) - } - let switchboard = acct.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath)! - let types = switchboard.getVaultTypes() - if !types.contains(Type<@DapperUtilityCoin.Vault>()) { - switchboard.addNewVaultWrapper(capability: dapperDUCReceiver, type: Type<@DapperUtilityCoin.Vault>()) - } - if !types.contains(Type<@FlowUtilityToken.Vault>()) { - switchboard.addNewVaultWrapper(capability: dapperFUTReceiver, type: Type<@FlowUtilityToken.Vault>()) + account.storage.save(<- sb, to: FungibleTokenSwitchboard.StoragePath) + + let cap = account.capabilities.storage.issue<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.StoragePath) + account.capabilities.publish(cap, at: FungibleTokenSwitchboard.ReceiverPublicPath) + + let capb = account.capabilities.storage.issue<&{FungibleTokenSwitchboard.SwitchboardPublic,FungibleToken.Receiver}>(FungibleTokenSwitchboard.StoragePath) + account.capabilities.publish(capb, at: FungibleTokenSwitchboard.PublicPath) } - if !types.contains(usdcCap.borrow()!.getType()) { - switchboard.addNewVault(capability: usdcCap) + + let switchboard = account.storage.borrow(from: FungibleTokenSwitchboard.StoragePath)! + + if !switchboard.isSupportedVaultType(type:Type<@DapperUtilityCoin.Vault>()) { + switchboard.addNewVaultWrapper(capability: DUCReceiver, type: Type<@DapperUtilityCoin.Vault>()) } - if !types.contains(fusdReceiver.borrow()!.getType()) { - switchboard.addNewVault(capability: fusdReceiver) + if !switchboard.isSupportedVaultType(type: Type<@FlowUtilityToken.Vault>()) { + switchboard.addNewVaultWrapper(capability: FUTReceiver, type: Type<@FlowUtilityToken.Vault>()) } - let flowTokenCap = acct.getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) - if !types.contains(flowTokenCap.borrow()!.getType()) { + let flowTokenCap = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + if !switchboard.isSupportedVaultType(type: flowTokenCap.borrow()!.getType()) { switchboard.addNewVault(capability: flowTokenCap) } + } } diff --git a/transactions/initWearables.cdc b/transactions/initWearables.cdc index bafb3c32..e5189004 100644 --- a/transactions/initWearables.cdc +++ b/transactions/initWearables.cdc @@ -1,39 +1,39 @@ -import Wearables from "../contracts/community/Wearables.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "Wearables" +import "NonFungibleToken" +import "MetadataViews" transaction() { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) + let wearablesRef= account.storage.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) + account.storage.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPublicPath, target: Wearables.CollectionStoragePath ) account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPrivatePath, target: Wearables.CollectionStoragePath ) return } - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) + let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(Wearables.CollectionPublicPath) if !wearablesCap.check() { account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPublicPath, target: Wearables.CollectionStoragePath ) } - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) + let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(Wearables.CollectionPrivatePath) if !wearablesProviderCap.check() { account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPrivatePath, target: Wearables.CollectionStoragePath ) diff --git a/transactions/linkDUCVaultReceiver.cdc b/transactions/linkDUCVaultReceiver.cdc index f79183e2..729329f5 100644 --- a/transactions/linkDUCVaultReceiver.cdc +++ b/transactions/linkDUCVaultReceiver.cdc @@ -1,9 +1,9 @@ -import TokenForwarding from "../contracts/standard/TokenForwarding.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" +import "TokenForwarding" +import "FungibleToken" transaction() { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { account.unlink(/public/dapperUtilityCoinReceiver) account.link<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver,target: /storage/dapperUtilityCoinVault) } diff --git a/transactions/linkForLeaseMarket.cdc b/transactions/linkForLeaseMarket.cdc new file mode 100644 index 00000000..a64c5256 --- /dev/null +++ b/transactions/linkForLeaseMarket.cdc @@ -0,0 +1,20 @@ +import "FindLeaseMarketDirectOfferSoft" +import "FindMarket" + +transaction() { + prepare(account: auth (StorageCapabilities, SaveValue,PublishCapability, BorrowValue) &Account) { + let leaseTenantCapability= FindMarket.getTenantCapability(FindMarket.getFindTenantAddress())! + let leaseTenant = leaseTenantCapability.borrow()! + + let leaseDOSSaleItemType= Type<@FindLeaseMarketDirectOfferSoft.SaleItemCollection>() + let leaseDOSPublicPath=leaseTenant.getPublicPath(leaseDOSSaleItemType) + let leaseDOSStoragePath= leaseTenant.getStoragePath(leaseDOSSaleItemType) + let leaseDOSSaleItemCap= account.capabilities.get<&FindLeaseMarketDirectOfferSoft.SaleItemCollection>(leaseDOSPublicPath) + if !leaseDOSSaleItemCap.check() { + //The link here has to be a capability not a tenant, because it can change. + account.storage.save<@FindLeaseMarketDirectOfferSoft.SaleItemCollection>(<- FindLeaseMarketDirectOfferSoft.createEmptySaleItemCollection(leaseTenantCapability), to: leaseDOSStoragePath) + let leaseDOSSaleItemCap = account.capabilities.storage.issue<&FindLeaseMarketDirectOfferSoft.SaleItemCollection>(leaseDOSStoragePath) + account.capabilities.publish(leaseDOSSaleItemCap, at: leaseDOSPublicPath) + } + } +} diff --git a/transactions/listForSaleMultiple.cdc b/transactions/listForSaleMultiple.cdc deleted file mode 100644 index 1783d541..00000000 --- a/transactions/listForSaleMultiple.cdc +++ /dev/null @@ -1,123 +0,0 @@ -import FIND from "../contracts/FIND.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" - -transaction(nftAliasOrIdentifiers: [String], ids: [AnyStruct], ftAliasOrIdentifiers: [String], directSellPrices:[UFix64], validUntil: UFix64?) { - - let saleItems : &FindMarketSale.SaleItemCollection? - let pointers : [FindViews.AuthNFTPointer] - let leaseNames : [String] - let vaultTypes : [Type] - let finLeases : &FIND.LeaseCollection - - prepare(account: AuthAccount) { - - let marketplace = FindMarket.getFindTenantAddress() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let tenant = tenantCapability.borrow()! - self.vaultTypes= [] - self.pointers= [] - self.leaseNames= [] - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Cannot borrow reference to find lease collection") - - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) - - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: storagePath)! - - var counter = 0 - - let nfts : {String : NFTCatalog.NFTCollectionData} = {} - let fts : {String : FTRegistry.FTInfo} = {} - - while counter < ids.length { - var ft : FTRegistry.FTInfo? = nil - - if fts[ftAliasOrIdentifiers[counter]] != nil { - ft = fts[ftAliasOrIdentifiers[counter]] - } else { - ft = FTRegistry.getFTInfo(ftAliasOrIdentifiers[counter]) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifiers[counter])) - fts[ftAliasOrIdentifiers[counter]] = ft - } - - if let name = ids[counter] as? String { - if nftAliasOrIdentifiers[counter] != Type<@FIND.Lease>().identifier { - panic("Lease does not match with identifiers") - } - if ftAliasOrIdentifiers[counter] != Type<@FUSD.Vault>().identifier { - panic("Listing of leases only supports FUSD at the moment") - } - self.leaseNames.append(name) - } - - if let id = ids[counter] as? UInt64 { - // Get supported NFT and FT Information from Registries from input alias - var nft : NFTCatalog.NFTCollectionData? = nil - - if nfts[nftAliasOrIdentifiers[counter]] != nil { - nft = nfts[nftAliasOrIdentifiers[counter]] - } else { - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifiers[counter])?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifiers[counter])) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - nft = collection.collectionData - nfts[nftAliasOrIdentifiers[counter]] = nft - } - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft!.privatePath) - - /* Ben : Question -> Either client will have to provide the path here or agree that we set it up for the user */ - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft!.privatePath, - target: nft!.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = nft!.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: nft!.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - // Get the salesItemRef from tenant - self.pointers.append(FindViews.AuthNFTPointer(cap: providerCap, id: id)) - } - - self.vaultTypes.append(ft!.type) - counter = counter + 1 - } - } - - execute{ - var counter = 0 - var nameCounter = 0 - for identifier in nftAliasOrIdentifiers { - let vc = counter + nameCounter - if identifier == Type<@FIND.Lease>().identifier { - self.finLeases.listForSale(name: self.leaseNames[nameCounter], directSellPrice:directSellPrices[vc]) - nameCounter = nameCounter + 1 - continue - } - - self.saleItems!.listForSale(pointer: self.pointers[counter], vaultType: self.vaultTypes[vc], directSellPrice: directSellPrices[vc], validUntil: validUntil, extraField: {}) - counter = counter + 1 - } - } -} diff --git a/transactions/listLeaseForAuctionSoft.cdc b/transactions/listLeaseForAuctionSoft.cdc index 908b3402..b545df09 100644 --- a/transactions/listLeaseForAuctionSoft.cdc +++ b/transactions/listLeaseForAuctionSoft.cdc @@ -1,52 +1,63 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FIND from "../contracts/FIND.cdc" -import FindLeaseMarketAuctionSoft from "../contracts/FindLeaseMarketAuctionSoft.cdc" -import FindLeaseMarket from "../contracts/FindLeaseMarket.cdc" +import "FindMarket" +import "FTRegistry" +import "FIND" +import "FindLeaseMarketAuctionSoft" +import "FindLeaseMarket" transaction(leaseName: String, ftAliasOrIdentifier:String, price:UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionValidUntil: UFix64?) { - let saleItems : &FindLeaseMarketAuctionSoft.SaleItemCollection? - let pointer : FindLeaseMarket.AuthLeasePointer - let vaultType : Type - - prepare(account: AuthAccount) { - - // Get supported NFT and FT Information from Registries from input alias - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - - let leaseMarketplace = FindMarket.getFindTenantAddress() - let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseASSaleItemType= Type<@FindLeaseMarketAuctionSoft.SaleItemCollection>() - let leaseASPublicPath=leaseTenant.getPublicPath(leaseASSaleItemType) - let leaseASStoragePath= leaseTenant.getStoragePath(leaseASSaleItemType) - let leaseASSaleItemCap= account.getCapability<&FindLeaseMarketAuctionSoft.SaleItemCollection{FindLeaseMarketAuctionSoft.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leaseASPublicPath) - if !leaseASSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketAuctionSoft.SaleItemCollection>(<- FindLeaseMarketAuctionSoft.createEmptySaleItemCollection(leaseTenantCapability), to: leaseASStoragePath) - account.link<&FindLeaseMarketAuctionSoft.SaleItemCollection{FindLeaseMarketAuctionSoft.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leaseASPublicPath, target: leaseASStoragePath) - } - - self.saleItems= account.borrow<&FindLeaseMarketAuctionSoft.SaleItemCollection>(from: leaseASStoragePath) - let ref = account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath)! - self.pointer= FindLeaseMarket.AuthLeasePointer(ref: ref, name: leaseName) - self.vaultType= ft.type - - } - - pre{ - // Ben : panic on some unreasonable inputs in trxn - minimumBidIncrement > 0.0 :"Minimum bid increment should be larger than 0." - (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." - auctionDuration > 0.0 : "Auction Duration should be greater than 0." - auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: {}) - - } + let saleItems : auth(FindLeaseMarketAuctionSoft.Seller) &FindLeaseMarketAuctionSoft.SaleItemCollection? + let pointer : FindLeaseMarket.AuthLeasePointer + let vaultType : Type + + prepare(account: auth(StorageCapabilities, PublishCapability,Storage, IssueStorageCapabilityController) &Account) { + + // Get supported NFT and FT Information from Registries from input alias + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + + let leaseMarketplace = FindMarket.getFindTenantAddress() + let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! + let leaseTenant = leaseTenantCapability.borrow()! + + let leaseASSaleItemType= Type<@FindLeaseMarketAuctionSoft.SaleItemCollection>() + let leaseASPublicPath=leaseTenant.getPublicPath(leaseASSaleItemType) + let leaseASStoragePath= leaseTenant.getStoragePath(leaseASSaleItemType) + let leaseASSaleItemCap= account.capabilities.get<&FindLeaseMarketAuctionSoft.SaleItemCollection>(leaseASPublicPath) + if !leaseASSaleItemCap.check() { + //The link here has to be a capability not a tenant, because it can change. + account.storage.save<@FindLeaseMarketAuctionSoft.SaleItemCollection>(<- FindLeaseMarketAuctionSoft.createEmptySaleItemCollection(leaseTenantCapability), to: leaseASStoragePath) + let saleColCap = account.capabilities.storage.issue<&FindLeaseMarketAuctionSoft.SaleItemCollection>(leaseASStoragePath) + account.capabilities.publish(saleColCap, at: leaseASPublicPath) + } + + self.saleItems= account.storage.borrow(from: leaseASStoragePath)! + + + let storagePathIdentifer = FIND.LeaseStoragePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("ProviderFlow") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(FIND.LeaseStoragePath) + account.storage.save(existingProvider!, to: providerStoragePath) + } + var cap = existingProvider! + self.pointer= FindLeaseMarket.AuthLeasePointer(cap: cap, name: leaseName) + self.vaultType= ft.type + } + + pre{ + // Ben : panic on some unreasonable inputs in trxn + minimumBidIncrement > 0.0 :"Minimum bid increment should be larger than 0." + (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." + auctionDuration > 0.0 : "Auction Duration should be greater than 0." + auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." + self.saleItems != nil : "Cannot borrow reference to saleItem" + } + + execute{ + self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: {}) + + } } diff --git a/transactions/listLeaseForAuctionSoftDapper.cdc b/transactions/listLeaseForAuctionSoftDapper.cdc index a41cb417..dde446e8 100644 --- a/transactions/listLeaseForAuctionSoftDapper.cdc +++ b/transactions/listLeaseForAuctionSoftDapper.cdc @@ -1,51 +1,62 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FIND from "../contracts/FIND.cdc" -import FindLeaseMarketAuctionSoft from "../contracts/FindLeaseMarketAuctionSoft.cdc" -import FindLeaseMarket from "../contracts/FindLeaseMarket.cdc" +import "FindMarket" +import "FTRegistry" +import "FIND" +import "FindLeaseMarketAuctionSoft" +import "FindLeaseMarket" transaction(leaseName: String, ftAliasOrIdentifier: String, price:UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionValidUntil: UFix64?) { - let saleItems : &FindLeaseMarketAuctionSoft.SaleItemCollection? - let pointer : FindLeaseMarket.AuthLeasePointer - let vaultType : Type - - prepare(account: AuthAccount) { - - // Get supported NFT and FT Information from Registries from input alias - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - - let leaseMarketplace = FindMarket.getFindTenantAddress() - let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseASSaleItemType= Type<@FindLeaseMarketAuctionSoft.SaleItemCollection>() - let leaseASPublicPath=leaseTenant.getPublicPath(leaseASSaleItemType) - let leaseASStoragePath= leaseTenant.getStoragePath(leaseASSaleItemType) - let leaseASSaleItemCap= account.getCapability<&FindLeaseMarketAuctionSoft.SaleItemCollection{FindLeaseMarketAuctionSoft.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leaseASPublicPath) - if !leaseASSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketAuctionSoft.SaleItemCollection>(<- FindLeaseMarketAuctionSoft.createEmptySaleItemCollection(leaseTenantCapability), to: leaseASStoragePath) - account.link<&FindLeaseMarketAuctionSoft.SaleItemCollection{FindLeaseMarketAuctionSoft.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leaseASPublicPath, target: leaseASStoragePath) - } - - self.saleItems= account.borrow<&FindLeaseMarketAuctionSoft.SaleItemCollection>(from: leaseASStoragePath) - let ref= account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath)! - self.pointer= FindLeaseMarket.AuthLeasePointer(ref: ref, name: leaseName) - self.vaultType= ft.type - } - - pre{ - // Ben : panic on some unreasonable inputs in trxn - minimumBidIncrement > 0.0 :"Minimum bid increment should be larger than 0." - (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." - auctionDuration > 0.0 : "Auction Duration should be greater than 0." - auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: {}) - - } + let saleItems : auth(FindLeaseMarketAuctionSoft.Seller) &FindLeaseMarketAuctionSoft.SaleItemCollection? + let pointer : FindLeaseMarket.AuthLeasePointer + let vaultType : Type + + prepare(account: auth(StorageCapabilities, SaveValue,PublishCapability, Storage, IssueStorageCapabilityController) &Account) { + + // Get supported NFT and FT Information from Registries from input alias + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + + let leaseMarketplace = FindMarket.getFindTenantAddress() + let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! + let leaseTenant = leaseTenantCapability.borrow()! + + let leaseASSaleItemType= Type<@FindLeaseMarketAuctionSoft.SaleItemCollection>() + let leaseASPublicPath=leaseTenant.getPublicPath(leaseASSaleItemType) + let leaseASStoragePath= leaseTenant.getStoragePath(leaseASSaleItemType) + let leaseASSaleItemCap= account.capabilities.get<&FindLeaseMarketAuctionSoft.SaleItemCollection>(leaseASPublicPath) + if !leaseASSaleItemCap.check() { + //The link here has to be a capability not a tenant, because it can change. + account.storage.save<@FindLeaseMarketAuctionSoft.SaleItemCollection>(<- FindLeaseMarketAuctionSoft.createEmptySaleItemCollection(leaseTenantCapability), to: leaseASStoragePath) + let saleColCap = account.capabilities.storage.issue<&FindLeaseMarketAuctionSoft.SaleItemCollection>(leaseASStoragePath) + account.capabilities.publish(saleColCap, at: leaseASPublicPath) + } + + self.saleItems= account.storage.borrow(from: leaseASStoragePath) + + let storagePathIdentifer = FIND.LeaseStoragePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(FIND.LeaseStoragePath) + account.storage.save(existingProvider!, to: providerStoragePath) + } + var cap = existingProvider! + self.pointer= FindLeaseMarket.AuthLeasePointer(cap: cap, name: leaseName) + self.vaultType= ft.type + } + + pre{ + // Ben : panic on some unreasonable inputs in trxn + minimumBidIncrement > 0.0 :"Minimum bid increment should be larger than 0." + (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." + auctionDuration > 0.0 : "Auction Duration should be greater than 0." + auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." + self.saleItems != nil : "Cannot borrow reference to saleItem" + } + + execute{ + self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: {}) + + } } diff --git a/transactions/listLeaseForSale.cdc b/transactions/listLeaseForSale.cdc index a0c8ee24..ee993c11 100644 --- a/transactions/listLeaseForSale.cdc +++ b/transactions/listLeaseForSale.cdc @@ -1,51 +1,61 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FIND from "../contracts/FIND.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FindLeaseMarketSale from "../contracts/FindLeaseMarketSale.cdc" -import FindLeaseMarket from "../contracts/FindLeaseMarket.cdc" +import "FindMarket" +import "FIND" +import "FTRegistry" +import "FindLeaseMarketSale" +import "FindLeaseMarket" +import "FindMarketSale" transaction(leaseName: String, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - let saleItems : &FindLeaseMarketSale.SaleItemCollection? - let pointer : FindLeaseMarket.AuthLeasePointer - let vaultType : Type + let saleItems : auth(FindLeaseMarketSale.Seller) &FindLeaseMarketSale.SaleItemCollection + let pointer : FindLeaseMarket.AuthLeasePointer + let vaultType : Type - prepare(account: AuthAccount) { + prepare(account: auth(Storage, IssueStorageCapabilityController, PublishCapability, IssueStorageCapabilityController) &Account) { - // Get the salesItemRef from tenant - let leaseMarketplace = FindMarket.getFindTenantAddress() - let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! - let leaseTenant = leaseTenantCapability.borrow()! + // Get the salesItemRef from tenant + let leaseMarketplace = FindMarket.getFindTenantAddress() + let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! + let leaseTenant = leaseTenantCapability.borrow()! - let leaseSaleItemType= Type<@FindLeaseMarketSale.SaleItemCollection>() - let leasePublicPath=leaseTenant.getPublicPath(leaseSaleItemType) - let leaseStoragePath= leaseTenant.getStoragePath(leaseSaleItemType) - let leaseSaleItemCap= account.getCapability<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath) - if !leaseSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketSale.SaleItemCollection>(<- FindLeaseMarketSale.createEmptySaleItemCollection(leaseTenantCapability), to: leaseStoragePath) - account.link<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath, target: leaseStoragePath) - } + let leaseSaleItemType= Type<@FindLeaseMarketSale.SaleItemCollection>() + let leasePublicPath=leaseTenant.getPublicPath(leaseSaleItemType) + let leaseStoragePath= leaseTenant.getStoragePath(leaseSaleItemType) + let leaseSaleItemCap= account.capabilities.get<&{FindLeaseMarket.SaleItemCollectionPublic, FindLeaseMarketSale.SaleItemCollectionPublic}>(leasePublicPath) + if !leaseSaleItemCap.check() { + //The link here has to be a capability not a tenant, because it can change. + account.storage.save<@FindLeaseMarketSale.SaleItemCollection>(<- FindLeaseMarketSale.createEmptySaleItemCollection(leaseTenantCapability), to: leaseStoragePath) + let leaseSaleItemCap= account.capabilities.storage.issue<&{FindLeaseMarket.SaleItemCollectionPublic, FindLeaseMarketSale.SaleItemCollectionPublic}>(leaseStoragePath) + account.capabilities.publish(leaseSaleItemCap, at: leasePublicPath) + } - self.saleItems= account.borrow<&FindLeaseMarketSale.SaleItemCollection>(from: leaseStoragePath)! - // Get supported NFT and FT Information from Registries from input alias - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - self.vaultType= ft.type + self.saleItems= account.storage.borrow(from: leaseStoragePath)! - let lease=account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath)! + // Get supported NFT and FT Information from Registries from input alias + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + self.vaultType= ft.type + let storagePathIdentifer = FIND.LeaseStoragePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("ProviderFlow") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! - self.pointer= FindLeaseMarket.AuthLeasePointer(ref:lease, name: leaseName) + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(FIND.LeaseStoragePath) + account.storage.save(existingProvider!, to: providerStoragePath) + } + var cap = existingProvider! + self.pointer= FindLeaseMarket.AuthLeasePointer(cap: cap, name: leaseName) + } - } + pre{ + self.saleItems != nil : "Cannot borrow reference to saleItem" + } - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } + execute{ + self.saleItems.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) + } - execute{ - self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) - } } diff --git a/transactions/listLeaseForSaleDapper.cdc b/transactions/listLeaseForSaleDapper.cdc index 9dd197b5..a63fd4b5 100644 --- a/transactions/listLeaseForSaleDapper.cdc +++ b/transactions/listLeaseForSaleDapper.cdc @@ -1,51 +1,58 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FIND from "../contracts/FIND.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FindLeaseMarketSale from "../contracts/FindLeaseMarketSale.cdc" -import FindLeaseMarket from "../contracts/FindLeaseMarket.cdc" +import "FindMarket" +import "FIND" +import "FTRegistry" +import "FindLeaseMarketSale" +import "FindLeaseMarket" +import "FindMarketSale" transaction(leaseName: String, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - let saleItems : &FindLeaseMarketSale.SaleItemCollection? - let pointer : FindLeaseMarket.AuthLeasePointer - let vaultType : Type - - prepare(account: AuthAccount) { - - // Get the salesItemRef from tenant - let leaseMarketplace = FindMarket.getFindTenantAddress() - let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! - let leaseTenant = leaseTenantCapability.borrow()! - - let leaseSaleItemType= Type<@FindLeaseMarketSale.SaleItemCollection>() - let leasePublicPath=leaseTenant.getPublicPath(leaseSaleItemType) - let leaseStoragePath= leaseTenant.getStoragePath(leaseSaleItemType) - let leaseSaleItemCap= account.getCapability<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath) - if !leaseSaleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindLeaseMarketSale.SaleItemCollection>(<- FindLeaseMarketSale.createEmptySaleItemCollection(leaseTenantCapability), to: leaseStoragePath) - account.link<&FindLeaseMarketSale.SaleItemCollection{FindLeaseMarketSale.SaleItemCollectionPublic, FindLeaseMarket.SaleItemCollectionPublic}>(leasePublicPath, target: leaseStoragePath) - } - - self.saleItems= account.borrow<&FindLeaseMarketSale.SaleItemCollection>(from: leaseStoragePath)! - - // Get supported NFT and FT Information from Registries from input alias - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - self.vaultType= ft.type - - let ref=account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath)! - - self.pointer= FindLeaseMarket.AuthLeasePointer(ref: ref, name: leaseName) - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) - - } + let saleItems : auth(FindLeaseMarketSale.Seller) &FindLeaseMarketSale.SaleItemCollection + let pointer : FindLeaseMarket.AuthLeasePointer + let vaultType : Type + + prepare(account: auth(Storage, IssueStorageCapabilityController, PublishCapability, IssueStorageCapabilityController) &Account) { + + // Get the salesItemRef from tenant + let leaseMarketplace = FindMarket.getFindTenantAddress() + let leaseTenantCapability= FindMarket.getTenantCapability(leaseMarketplace)! + let leaseTenant = leaseTenantCapability.borrow()! + + let leaseSaleItemType= Type<@FindLeaseMarketSale.SaleItemCollection>() + let leasePublicPath=leaseTenant.getPublicPath(leaseSaleItemType) + let leaseStoragePath= leaseTenant.getStoragePath(leaseSaleItemType) + let leaseSaleItemCap= account.capabilities.get<&{FindLeaseMarket.SaleItemCollectionPublic, FindLeaseMarketSale.SaleItemCollectionPublic}>(leasePublicPath) + if !leaseSaleItemCap.check() { + //The link here has to be a capability not a tenant, because it can change. + account.storage.save<@FindLeaseMarketSale.SaleItemCollection>(<- FindLeaseMarketSale.createEmptySaleItemCollection(leaseTenantCapability), to: leaseStoragePath) + let leaseSaleItemCap= account.capabilities.storage.issue<&{FindLeaseMarket.SaleItemCollectionPublic, FindLeaseMarketSale.SaleItemCollectionPublic}>(leaseStoragePath) + account.capabilities.publish(leaseSaleItemCap, at: leasePublicPath) + } + + self.saleItems= account.storage.borrow(from: leaseStoragePath)! + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + self.vaultType= ft.type + + let storagePathIdentifer = FIND.LeaseStoragePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(FIND.LeaseStoragePath) + account.storage.save(existingProvider!, to: providerStoragePath) + } + var cap = existingProvider! + self.pointer= FindLeaseMarket.AuthLeasePointer(cap: cap, name: leaseName) + } + + pre{ + self.saleItems != nil : "Cannot borrow reference to saleItem" + } + + execute{ + self.saleItems.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) + } } diff --git a/transactions/listMultipleNFTForSale.cdc b/transactions/listMultipleNFTForSale.cdc deleted file mode 100644 index b926bc98..00000000 --- a/transactions/listMultipleNFTForSale.cdc +++ /dev/null @@ -1,107 +0,0 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" - -transaction(nftAliasOrIdentifiers: [String], ids: [UInt64], ftAliasOrIdentifiers: [String], directSellPrices:[UFix64], validUntil: UFix64?) { - - let saleItems : &FindMarketSale.SaleItemCollection? - let pointers : [FindViews.AuthNFTPointer] - let vaultTypes : [Type] - - prepare(account: AuthAccount) { - - if nftAliasOrIdentifiers.length != ids.length { - panic("The length of arrays passed in has to be the same") - } else if nftAliasOrIdentifiers.length != ftAliasOrIdentifiers.length { - panic("The length of arrays passed in has to be the same") - } else if nftAliasOrIdentifiers.length != directSellPrices.length { - panic("The length of arrays passed in has to be the same") - } - - let marketplace = FindMarket.getFindTenantAddress() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let tenant = tenantCapability.borrow()! - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) - self.vaultTypes= [] - self.pointers= [] - - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) - - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - - var counter = 0 - - let nfts : {String : NFTCatalog.NFTCollectionData} = {} - let fts : {String : FTRegistry.FTInfo} = {} - - while counter < ids.length { - // Get supported NFT and FT Information from Registries from input alias - var nft : NFTCatalog.NFTCollectionData? = nil - var ft : FTRegistry.FTInfo? = nil - - if nfts[nftAliasOrIdentifiers[counter]] != nil { - nft = nfts[nftAliasOrIdentifiers[counter]] - } else { - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifiers[counter])?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifiers[counter])) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - nft = collection.collectionData - nfts[nftAliasOrIdentifiers[counter]] = nft - } - - if fts[ftAliasOrIdentifiers[counter]] != nil { - ft = fts[ftAliasOrIdentifiers[counter]] - } else { - ft = FTRegistry.getFTInfo(ftAliasOrIdentifiers[counter]) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifiers[counter])) - fts[ftAliasOrIdentifiers[counter]] = ft - } - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft!.privatePath) - - /* Ben : Question -> Either client will have to provide the path here or agree that we set it up for the user */ - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft!.privatePath, - target: nft!.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = nft!.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: nft!.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - // Get the salesItemRef from tenant - self.pointers.append(FindViews.AuthNFTPointer(cap: providerCap, id: ids[counter])) - self.vaultTypes.append(ft!.type) - counter = counter + 1 - } - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - var counter = 0 - while counter < ids.length { - self.saleItems!.listForSale(pointer: self.pointers[counter], vaultType: self.vaultTypes[counter], directSellPrice: directSellPrices[counter], validUntil: validUntil, extraField: {}) - counter = counter + 1 - } - } -} diff --git a/transactions/listMultipleNFTForSaleDapper.cdc b/transactions/listMultipleNFTForSaleDapper.cdc deleted file mode 100644 index 3cdd2161..00000000 --- a/transactions/listMultipleNFTForSaleDapper.cdc +++ /dev/null @@ -1,107 +0,0 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" - -transaction(nftAliasOrIdentifiers: [String], ids: [UInt64], ftAliasOrIdentifiers: [String], directSellPrices:[UFix64], validUntil: UFix64?) { - - let saleItems : &FindMarketSale.SaleItemCollection? - let pointers : [FindViews.AuthNFTPointer] - let vaultTypes : [Type] - - prepare(account: AuthAccount) { - - if nftAliasOrIdentifiers.length != ids.length { - panic("The length of arrays passed in has to be the same") - } else if nftAliasOrIdentifiers.length != directSellPrices.length { - panic("The length of arrays passed in has to be the same") - } - - let marketplace = FindMarket.getFindTenantAddress() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let tenant = tenantCapability.borrow()! - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) - self.pointers= [] - self.vaultTypes= [] - - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) - - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - - let nfts : {String : NFTCatalog.NFTCollectionData} = {} - let fts : {String : FTRegistry.FTInfo} = {} - - var counter = 0 - while counter < ids.length { - // Get supported NFT and FT Information from Registries from input alias - var nft : NFTCatalog.NFTCollectionData? = nil - - if nfts[nftAliasOrIdentifiers[counter]] != nil { - nft = nfts[nftAliasOrIdentifiers[counter]] - } else { - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifiers[counter])?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifiers[counter])) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - nft = collection.collectionData - nfts[nftAliasOrIdentifiers[counter]] = nft - } - - if fts[ftAliasOrIdentifiers[counter]] != nil { - let ft = fts[ftAliasOrIdentifiers[counter]]! - self.vaultTypes.append(ft.type) - } else { - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifiers[counter]) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifiers[counter])) - fts[ftAliasOrIdentifiers[counter]] = ft - self.vaultTypes.append(ft.type) - } - - - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft!.privatePath) - - /* Ben : Question -> Either client will have to provide the path here or agree that we set it up for the user */ - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft!.privatePath, - target: nft!.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = nft!.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: nft!.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - // Get the salesItemRef from tenant - self.pointers.append(FindViews.AuthNFTPointer(cap: providerCap, id: ids[counter])) - counter = counter + 1 - } - - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - var counter = 0 - while counter < ids.length { - self.saleItems!.listForSale(pointer: self.pointers[counter], vaultType: self.vaultTypes[counter], directSellPrice: directSellPrices[counter], validUntil: validUntil, extraField: {}) - counter = counter + 1 - } - } -} diff --git a/transactions/listNFTForAuctionEscrowed.cdc b/transactions/listNFTForAuctionEscrowed.cdc index 65927bce..f9e348f3 100644 --- a/transactions/listNFTForAuctionEscrowed.cdc +++ b/transactions/listNFTForAuctionEscrowed.cdc @@ -1,76 +1,72 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketAuctionEscrow from "../contracts/FindMarketAuctionEscrow.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" +import "FindMarket" +import "FindMarketAuctionEscrow" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "FINDNFTCatalog" +import "FTRegistry" transaction(nftAliasOrIdentifier:String, id: UInt64, ftAliasOrIdentifier:String, price:UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionStartTime: UFix64?, auctionValidUntil: UFix64?) { - let saleItems : &FindMarketAuctionEscrow.SaleItemCollection? - let vaultType : Type - let pointer : FindViews.AuthNFTPointer + let saleItems : auth(FindMarketAuctionEscrow.Seller) &FindMarketAuctionEscrow.SaleItemCollection? + let vaultType : Type + let pointer : FindViews.AuthNFTPointer - prepare(account: AuthAccount) { + prepare(account: auth(StorageCapabilities, SaveValue,PublishCapability, Storage, IssueStorageCapabilityController) &Account) { + let marketplace = FindMarket.getFindTenantAddress() + let tenantCapability= FindMarket.getTenantCapability(marketplace)! + let tenant = tenantCapability.borrow()! + let path=FindMarket.getStoragePath(Type<@FindMarketAuctionEscrow.SaleItemCollection>(), name: tenant.name) - let marketplace = FindMarket.getFindTenantAddress() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let tenant = tenantCapability.borrow()! - let path=FindMarket.getStoragePath(Type<@FindMarketAuctionEscrow.SaleItemCollection>(), name: tenant.name) + /// auctions that escrow ft + let aeSaleType= Type<@FindMarketAuctionEscrow.SaleItemCollection>() + let aeSalePublicPath=FindMarket.getPublicPath(aeSaleType, name: tenant.name) + let aeSaleStoragePath= FindMarket.getStoragePath(aeSaleType, name:tenant.name) + let aeSaleCap= account.capabilities.get<&{FindMarketAuctionEscrow.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(aeSalePublicPath) + if !aeSaleCap.check(){ + account.storage.save<@FindMarketAuctionEscrow.SaleItemCollection>(<- FindMarketAuctionEscrow.createEmptySaleItemCollection(tenantCapability), to: aeSaleStoragePath) - /// auctions that escrow ft - let aeSaleType= Type<@FindMarketAuctionEscrow.SaleItemCollection>() - let aeSalePublicPath=FindMarket.getPublicPath(aeSaleType, name: tenant.name) - let aeSaleStoragePath= FindMarket.getStoragePath(aeSaleType, name:tenant.name) - let aeSaleCap= account.getCapability<&FindMarketAuctionEscrow.SaleItemCollection{FindMarketAuctionEscrow.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(aeSalePublicPath) - if !aeSaleCap.check() { - account.save<@FindMarketAuctionEscrow.SaleItemCollection>(<- FindMarketAuctionEscrow.createEmptySaleItemCollection(tenantCapability), to: aeSaleStoragePath) - account.link<&FindMarketAuctionEscrow.SaleItemCollection{FindMarketAuctionEscrow.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(aeSalePublicPath, target: aeSaleStoragePath) - } + let cap = account.capabilities.storage.issue<&{FindMarketAuctionEscrow.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(aeSaleStoragePath) + account.capabilities.publish(cap, at: aeSalePublicPath) + } - // Get supported NFT and FT Information from Registries from input alias - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData + // Get supported NFT and FT Information from Registries from input alias + let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) + let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! + let collectionData = collection.collectionData - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) - /* Ben : Question -> Either client will have to provide the path here or agree that we set it up for the user */ - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft.privatePath, - target: nft.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = nft.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: nft.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } + let storagePathIdentifer = collectionData.storagePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! - self.saleItems= account.borrow<&FindMarketAuctionEscrow.SaleItemCollection>(from: path) - self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) - self.vaultType= ft.type - } + //if this stores anything but this it will panic, why does it not return nil? + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(collectionData.storagePath) + //we save it to storage to memoize it + account.storage.save(existingProvider!, to: providerStoragePath) + log("create new cap") + } + var providerCap = existingProvider! - pre{ - // Ben : panic on some unreasonable inputs in trxn - minimumBidIncrement > 0.0 : "Minimum bid increment should be larger than 0." - (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." - auctionDuration > 0.0 : "Auction Duration should be greater than 0." - auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." - self.saleItems != nil : "Cannot borrow reference to saleItem" - } + self.saleItems= account.storage.borrow(from: path) + self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) + self.vaultType= ft.type + } - execute { - self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionStartTime: auctionStartTime, auctionValidUntil:auctionValidUntil, saleItemExtraField: {}) - } + pre{ + // Ben : panic on some unreasonable inputs in trxn + minimumBidIncrement > 0.0 : "Minimum bid increment should be larger than 0." + (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." + auctionDuration > 0.0 : "Auction Duration should be greater than 0." + auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." + self.saleItems != nil : "Cannot borrow reference to saleItem" + } + + execute { + self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionStartTime: auctionStartTime, auctionValidUntil:auctionValidUntil, saleItemExtraField: {}) + } } diff --git a/transactions/listNFTForAuctionSoft.cdc b/transactions/listNFTForAuctionSoft.cdc index 72d76d2f..fc4e17c9 100644 --- a/transactions/listNFTForAuctionSoft.cdc +++ b/transactions/listNFTForAuctionSoft.cdc @@ -1,79 +1,73 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketAuctionSoft from "../contracts/FindMarketAuctionSoft.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" +import "FindMarket" +import "FindMarketAuctionSoft" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "FTRegistry" +import "FINDNFTCatalog" transaction(nftAliasOrIdentifier:String, id: UInt64, ftAliasOrIdentifier:String, price:UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionValidUntil: UFix64?) { - let saleItems : &FindMarketAuctionSoft.SaleItemCollection? - let pointer : FindViews.AuthNFTPointer - let vaultType : Type - - prepare(account: AuthAccount) { - - let marketplace = FindMarket.getFindTenantAddress() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let tenant = tenantCapability.borrow()! - - /// auctions that refers FT so 'soft' auction - let asSaleType= Type<@FindMarketAuctionSoft.SaleItemCollection>() - let asSalePublicPath=FindMarket.getPublicPath(asSaleType, name: tenant.name) - let asSaleStoragePath= FindMarket.getStoragePath(asSaleType, name:tenant.name) - let asSaleCap= account.getCapability<&FindMarketAuctionSoft.SaleItemCollection{FindMarketAuctionSoft.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(asSalePublicPath) - if !asSaleCap.check() { - account.save<@FindMarketAuctionSoft.SaleItemCollection>(<- FindMarketAuctionSoft.createEmptySaleItemCollection(tenantCapability), to: asSaleStoragePath) - account.link<&FindMarketAuctionSoft.SaleItemCollection{FindMarketAuctionSoft.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(asSalePublicPath, target: asSaleStoragePath) - } - - // Get supported NFT and FT Information from Registries from input alias - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData - - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - - var providerCap = account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) - - /* Ben : Question -> Either client will have to provide the path here or agree that we set it up for the user */ - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft.privatePath, - target: nft.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = nft.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: nft.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - - self.saleItems= account.borrow<&FindMarketAuctionSoft.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketAuctionSoft.SaleItemCollection>())) - self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) - self.vaultType= ft.type - - - - } - - pre{ - // Ben : panic on some unreasonable inputs in trxn - minimumBidIncrement > 0.0 :"Minimum bid increment should be larger than 0." - (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." - auctionDuration > 0.0 : "Auction Duration should be greater than 0." - auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: {}) - - } + let saleItems : auth(FindMarketAuctionSoft.Seller) &FindMarketAuctionSoft.SaleItemCollection? + let pointer : FindViews.AuthNFTPointer + let vaultType : Type + + prepare(account: auth(StorageCapabilities, SaveValue,PublishCapability, Storage, IssueStorageCapabilityController) &Account) { + + let marketplace = FindMarket.getFindTenantAddress() + let tenantCapability= FindMarket.getTenantCapability(marketplace)! + let tenant = tenantCapability.borrow()! + + /// auctions that refers FT so 'soft' auction + let asSaleType= Type<@FindMarketAuctionSoft.SaleItemCollection>() + let asSalePublicPath=FindMarket.getPublicPath(asSaleType, name: tenant.name) + let asSaleStoragePath= FindMarket.getStoragePath(asSaleType, name:tenant.name) + let asSaleCap= account.capabilities.get<&FindMarketAuctionSoft.SaleItemCollection>(asSalePublicPath) + if !asSaleCap.check() { + account.storage.save<@FindMarketAuctionSoft.SaleItemCollection>(<- FindMarketAuctionSoft.createEmptySaleItemCollection(tenantCapability), to: asSaleStoragePath) + let saleColCap = account.capabilities.storage.issue<&FindMarketAuctionSoft.SaleItemCollection>(asSaleStoragePath) + account.capabilities.publish(saleColCap, at: asSalePublicPath) + } + + // Get supported NFT and FT Information from Registries from input alias + let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) + let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! + + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + + let collectionData = collection.collectionData + + let storagePathIdentifer = collectionData.storagePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + //if this stores anything but this it will panic, why does it not return nil? + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(collectionData.storagePath) + //we save it to storage to memoize it + account.storage.save(existingProvider!, to: providerStoragePath) + log("create new cap") + } + var providerCap = existingProvider! + + self.saleItems= account.storage.borrow(from: tenant.getStoragePath(Type<@FindMarketAuctionSoft.SaleItemCollection>())) + self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) + self.vaultType= ft.type + } + + pre{ + // Ben : panic on some unreasonable inputs in trxn + minimumBidIncrement > 0.0 :"Minimum bid increment should be larger than 0." + (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." + auctionDuration > 0.0 : "Auction Duration should be greater than 0." + auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." + self.saleItems != nil : "Cannot borrow reference to saleItem" + } + + execute{ + self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: {}) + + } } + diff --git a/transactions/listNFTForAuctionSoftDapper.cdc b/transactions/listNFTForAuctionSoftDapper.cdc index 80f68efd..b9e7538d 100644 --- a/transactions/listNFTForAuctionSoftDapper.cdc +++ b/transactions/listNFTForAuctionSoftDapper.cdc @@ -1,76 +1,57 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketAuctionSoft from "../contracts/FindMarketAuctionSoft.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" +import "FindMarket" +import "FindMarketAuctionSoft" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "FINDNFTCatalog" +import "FTRegistry" transaction(nftAliasOrIdentifier:String, id: UInt64, ftAliasOrIdentifier:String, price:UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64, minimumBidIncrement: UFix64, auctionValidUntil: UFix64?) { - let saleItems : &FindMarketAuctionSoft.SaleItemCollection? - let pointer : FindViews.AuthNFTPointer - let vaultType : Type - - prepare(account: AuthAccount) { - let marketplace = FindMarket.getFindTenantAddress() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let tenant = tenantCapability.borrow()! - - /// auctions that refers FT so 'soft' auction - let asSaleType= Type<@FindMarketAuctionSoft.SaleItemCollection>() - let asSalePublicPath=FindMarket.getPublicPath(asSaleType, name: tenant.name) - let asSaleStoragePath= FindMarket.getStoragePath(asSaleType, name:tenant.name) - let asSaleCap= account.getCapability<&FindMarketAuctionSoft.SaleItemCollection{FindMarketAuctionSoft.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(asSalePublicPath) - if !asSaleCap.check() { - account.save<@FindMarketAuctionSoft.SaleItemCollection>(<- FindMarketAuctionSoft.createEmptySaleItemCollection(tenantCapability), to: asSaleStoragePath) - account.link<&FindMarketAuctionSoft.SaleItemCollection{FindMarketAuctionSoft.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(asSalePublicPath, target: asSaleStoragePath) - } - - // Get supported NFT and FT Information from Registries from input alias - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData - - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - - var providerCap = account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) - - /* Ben : Question -> Either client will have to provide the path here or agree that we set it up for the user */ - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft.privatePath, - target: nft.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = nft.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: nft.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - - - self.saleItems= account.borrow<&FindMarketAuctionSoft.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketAuctionSoft.SaleItemCollection>())) - self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) - self.vaultType= ft.type - } - - pre{ - // Ben : panic on some unreasonable inputs in trxn - minimumBidIncrement > 0.0 :"Minimum bid increment should be larger than 0." - (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." - auctionDuration > 0.0 : "Auction Duration should be greater than 0." - auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: {}) - - } + let saleItems : auth(FindMarketAuctionSoft.Seller) &FindMarketAuctionSoft.SaleItemCollection? + let pointer : FindViews.AuthNFTPointer + let vaultType : Type + + prepare(account: auth(StorageCapabilities, SaveValue,PublishCapability, BorrowValue) &Account) { + let marketplace = FindMarket.getFindTenantAddress() + let tenantCapability= FindMarket.getTenantCapability(marketplace)! + let tenant = tenantCapability.borrow()! + + /// auctions that refers FT so 'soft' auction + let asSaleType= Type<@FindMarketAuctionSoft.SaleItemCollection>() + let asSalePublicPath=FindMarket.getPublicPath(asSaleType, name: tenant.name) + let asSaleStoragePath= FindMarket.getStoragePath(asSaleType, name:tenant.name) + let asSaleCap= account.capabilities.get<&FindMarketAuctionSoft.SaleItemCollection>(asSalePublicPath) + if !asSaleCap.check() { + account.storage.save<@FindMarketAuctionSoft.SaleItemCollection>(<- FindMarketAuctionSoft.createEmptySaleItemCollection(tenantCapability), to: asSaleStoragePath) + let saleColCap = account.capabilities.storage.issue<&FindMarketAuctionSoft.SaleItemCollection>(asSaleStoragePath) + account.capabilities.publish(saleColCap, at: asSalePublicPath) + } + + // Get supported NFT and FT Information from Registries from input alias + let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) + let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! + let nft = collection.collectionData + + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + + var providerCap = account.capabilities.storage.issue(nft.storagePath) + + self.saleItems= account.storage.borrow(from: tenant.getStoragePath(Type<@FindMarketAuctionSoft.SaleItemCollection>())) + self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) + self.vaultType= ft.type + } + + pre{ + // Ben : panic on some unreasonable inputs in trxn + minimumBidIncrement > 0.0 :"Minimum bid increment should be larger than 0." + (auctionReservePrice - auctionReservePrice) % minimumBidIncrement == 0.0 : "Acution ReservePrice should be in step of minimum bid increment." + auctionDuration > 0.0 : "Auction Duration should be greater than 0." + auctionExtensionOnLateBid > 0.0 : "Auction Duration should be greater than 0." + self.saleItems != nil : "Cannot borrow reference to saleItem" + } + + execute{ + self.saleItems!.listForAuction(pointer: self.pointer, vaultType: self.vaultType, auctionStartPrice: price, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid, minimumBidIncrement: minimumBidIncrement, auctionValidUntil: auctionValidUntil, saleItemExtraField: {}) + } } diff --git a/transactions/listNFTForSale.cdc b/transactions/listNFTForSale.cdc index 98778dc4..c6f52a10 100644 --- a/transactions/listNFTForSale.cdc +++ b/transactions/listNFTForSale.cdc @@ -1,70 +1,65 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" +import "FindMarket" +import "FindMarketSale" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "FINDNFTCatalog" +import "FTRegistry" transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - let saleItems : &FindMarketSale.SaleItemCollection? - let pointer : FindViews.AuthNFTPointer - let vaultType : Type + let saleItems : auth(FindMarketSale.Seller) &FindMarketSale.SaleItemCollection? + let pointer : FindViews.AuthNFTPointer + let vaultType : Type - prepare(account: AuthAccount) { + prepare(account: auth (StorageCapabilities, IssueStorageCapabilityController,PublishCapability, Storage) &Account) { - let marketplace = FindMarket.getFindTenantAddress() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() + let marketplace = FindMarket.getFindTenantAddress() + let tenantCapability= FindMarket.getTenantCapability(marketplace)! + let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let tenant = tenantCapability.borrow()! - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) + let tenant = tenantCapability.borrow()! + let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) + let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) + let saleItemCap= account.capabilities.get<&FindMarketSale.SaleItemCollection>(publicPath) + if !saleItemCap.check(){ + account.storage.save(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) + let cap = account.capabilities.storage.issue<&FindMarketSale.SaleItemCollection>(storagePath) + account.capabilities.publish(cap, at: publicPath) + } - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - // Get supported NFT and FT Information from Registries from input alias - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier:nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData + // Get supported NFT and FT Information from Registries from input alias + let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier:nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) + let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! + let nft = collection.collectionData - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) + let storagePathIdentifer = nft.storagePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! - /* Ben : Question -> Either client will have to provide the path here or agree that we set it up for the user */ - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft.privatePath, - target: nft.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = nft.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: nft.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - // Get the salesItemRef from tenant - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) - self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) - self.vaultType= ft.type - } + //if this stores anything but this it will panic, why does it not return nil? + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(nft.storagePath) + //we save it to storage to memoize it + account.storage.save(existingProvider!, to: providerStoragePath) + log("create new cap") + } + var providerCap = existingProvider! - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } + // Get the salesItemRef from tenant + self.saleItems= account.storage.borrow(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) + self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) + self.vaultType= ft.type + } - execute{ - self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) - } + pre{ + self.saleItems != nil : "Cannot borrow reference to saleItem" + } + + execute{ + self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) + } } diff --git a/transactions/listNFTForSaleDapper.cdc b/transactions/listNFTForSaleDapper.cdc index f00224c8..8218be7a 100644 --- a/transactions/listNFTForSaleDapper.cdc +++ b/transactions/listNFTForSaleDapper.cdc @@ -1,78 +1,85 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FindViews from "../contracts/FindViews.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import TokenForwarding from "../contracts/standard/TokenForwarding.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" +import "FindMarket" +import "FindMarketSale" +import "FINDNFTCatalog" +import "FTRegistry" +import "FindViews" +import "NonFungibleToken" +import "MetadataViews" +import "FlowUtilityToken" +import "TokenForwarding" +import "FungibleToken" transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - let saleItems : &FindMarketSale.SaleItemCollection? - let pointer : FindViews.AuthNFTPointer - let vaultType : Type - - prepare(account: AuthAccount) { - - let marketplace = FindMarket.getFindTenantAddress() - let saleItemType= Type<@FindMarketSale.SaleItemCollection>() - let tenantCapability= FindMarket.getTenantCapability(marketplace)! - - let tenant = tenantCapability.borrow()! - - //TODO:how do we fix this on testnet/mainnet - let dapper=getAccount(FindViews.getDapperAddress()) - - let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) - let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) - - let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) - if !saleItemCap.check() { - //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) - account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) - } - - // Get supported NFT and FT Information from Registries from input alias - let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) - let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! - let nft = collection.collectionData - - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - - let futReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - if ft.type == Type<@FlowUtilityToken.Vault>() && !futReceiver.check() { - // Create a new Forwarder resource for FUT and store it in the new account's storage - let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapper.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver)) - account.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) - // Publish a Receiver capability for the new account, which is linked to the FUT Forwarder - account.link<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver,target: /storage/flowUtilityTokenReceiver) - } - - - let providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) - - if !providerCap.check() { - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - nft.privatePath, - target: nft.storagePath - ) - } - // Get the salesItemRef from tenant - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) - self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) - self.vaultType= ft.type - } - - pre{ - self.saleItems != nil : "Cannot borrow reference to saleItem" - } - - execute{ - self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) - - } + let saleItems : auth(FindMarketSale.Seller) &FindMarketSale.SaleItemCollection? + let pointer : FindViews.AuthNFTPointer + let vaultType : Type + + prepare(account: auth (StorageCapabilities, PublishCapability, Storage, IssueStorageCapabilityController) &Account) { + + let marketplace = FindMarket.getFindTenantAddress() + let saleItemType= Type<@FindMarketSale.SaleItemCollection>() + let tenantCapability= FindMarket.getTenantCapability(marketplace)! + + let tenant = tenantCapability.borrow()! + + //TODO:how do we fix this on testnet/mainnet + let dapper=getAccount(FindViews.getDapperAddress()) + + let publicPath=FindMarket.getPublicPath(saleItemType, name: tenant.name) + let storagePath= FindMarket.getStoragePath(saleItemType, name:tenant.name) + + let saleItemCap= account.capabilities.get<&FindMarketSale.SaleItemCollection>(publicPath) + if !saleItemCap.check() { + account.storage.save(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) + let cap = account.capabilities.storage.issue<&FindMarketSale.SaleItemCollection>(storagePath) + account.capabilities.publish(cap, at: publicPath) + } + // Get supported NFT and FT Information from Registries from input alias + let collectionIdentifier = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: nftAliasOrIdentifier)?.keys ?? panic("This NFT is not supported by the NFT Catalog yet. Type : ".concat(nftAliasOrIdentifier)) + let collection = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collectionIdentifier[0])! + let nft = collection.collectionData + + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + + let futReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) + if ft.type == Type<@FlowUtilityToken.Vault>() && !futReceiver.check() { + // Create a new Forwarder resource for FUT and store it in the new account's storage + let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapper.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver)) + account.storage.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) + let receiverCap = account.capabilities.storage.issue<&{FungibleToken.Receiver}>(/storage/flowUtilityTokenReceiver) + account.capabilities.publish(receiverCap, at: /public/flowUtilityTokenReceiver) + + let vaultCap = account.capabilities.storage.issue<&{FungibleToken.Vault}>(/storage/flowUtilityTokenReceiver) + account.capabilities.publish(vaultCap, at: /public/flowUtilityTokenVault) + } + + let storagePathIdentifer = nft.storagePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + //if this stores anything but this it will panic, why does it not return nil? + var existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + existingProvider=account.capabilities.storage.issue(nft.storagePath) + //we save it to storage to memoize it + account.storage.save(existingProvider!, to: providerStoragePath) + log("create new cap") + } + var providerCap = existingProvider! + + // Get the salesItemRef from tenant + self.saleItems= account.storage.borrow(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) + self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) + self.vaultType= ft.type + } + + pre{ + self.saleItems != nil : "Cannot borrow reference to saleItem" + } + + execute{ + self.saleItems!.listForSale(pointer: self.pointer, vaultType: self.vaultType, directSellPrice: directSellPrice, validUntil: validUntil, extraField: {}) + + } } diff --git a/transactions/listNameForAuction.cdc b/transactions/listNameForAuction.cdc deleted file mode 100644 index 1f26e041..00000000 --- a/transactions/listNameForAuction.cdc +++ /dev/null @@ -1,18 +0,0 @@ -import FIND from "../contracts/FIND.cdc" - -transaction(name: String, auctionStartPrice: UFix64, auctionReservePrice: UFix64, auctionDuration: UFix64, auctionExtensionOnLateBid: UFix64) { - - let finLeases : &FIND.LeaseCollection? - - prepare(acct: AuthAccount) { - self.finLeases= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) - } - - pre{ - self.finLeases != nil : "Cannot borrow reference to find lease collection" - } - - execute{ - self.finLeases!.listForAuction(name: name, auctionStartPrice: auctionStartPrice, auctionReservePrice: auctionReservePrice, auctionDuration: auctionDuration, auctionExtensionOnLateBid: auctionExtensionOnLateBid) - } -} diff --git a/transactions/listNameForSale.cdc b/transactions/listNameForSale.cdc deleted file mode 100644 index c19e56d4..00000000 --- a/transactions/listNameForSale.cdc +++ /dev/null @@ -1,18 +0,0 @@ -import FIND from "../contracts/FIND.cdc" - -transaction(name: String, directSellPrice:UFix64) { - - let finLeases : &FIND.LeaseCollection? - - prepare(acct: AuthAccount) { - self.finLeases= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) - } - - pre{ - self.finLeases != nil : "Cannot borrow reference to find lease collection" - } - - execute{ - self.finLeases!.listForSale(name: name, directSellPrice:directSellPrice) - } -} diff --git a/transactions/mainnetRegisterFlow.cdc b/transactions/mainnetRegisterFlow.cdc deleted file mode 100644 index 39ce1b83..00000000 --- a/transactions/mainnetRegisterFlow.cdc +++ /dev/null @@ -1,55 +0,0 @@ -import FiatToken from "../contracts/standard/FiatToken.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import SwapRouter from "../contracts/community/SwapRouter.cdc" -import FIND from "../contracts/FIND.cdc" - -transaction( - name: String, - amountInMax: UFix64, - exactAmountOut: UFix64, -) { - - let payVault : @FiatToken.Vault - let leases : &FIND.LeaseCollection? - let price : UFix64 - - - prepare(userAccount: AuthAccount) { - - self.price=FIND.calculateCost(name) - self.leases=userAccount.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) - - let deadline = getCurrentBlock().timestamp + 1000.0 - let tokenInVaultPath = /storage/flowTokenVault - let tokenOutReceiverPath = /public/USDCVaultReceiver - - let inVaultRef = userAccount.borrow<&FungibleToken.Vault>(from: tokenInVaultPath) ?? panic("Could not borrow reference to the owner's in FT.Vault") - - //we need to diff this on testnet mainnet - let path = [ "A.1654653399040a61.FlowToken", "A.b19436aae4d94622.FiatToken" ] - - let vaultInMax <- inVaultRef.withdraw(amount: amountInMax) - let swapResVault <- SwapRouter.swapTokensForExactTokens( - vaultInMax: <-vaultInMax, - exactAmountOut: exactAmountOut, - tokenKeyPath: path, - deadline: deadline - ) - let tempVault <- swapResVault.removeFirst() - self.payVault <- tempVault as! @FiatToken.Vault - let vaultInLeft <- swapResVault.removeLast() - destroy swapResVault - inVaultRef.deposit(from: <-vaultInLeft) - } - - pre{ - self.leases != nil : "Could not borrow reference to find lease collection" - self.price == exactAmountOut : "Calculated cost : ".concat(self.price.toString()).concat(" does not match expected cost : ").concat(exactAmountOut.toString()) - } - - execute{ - self.leases!.registerUSDC(name: name, vault: <- self.payVault) - } - -} diff --git a/transactions/mainnet_fillUpTheChest.cdc b/transactions/mainnet_fillUpTheChest.cdc deleted file mode 100644 index 6a2449f5..00000000 --- a/transactions/mainnet_fillUpTheChest.cdc +++ /dev/null @@ -1,36 +0,0 @@ -// Mainnet -import FungibleToken from 0xf233dcee88fe0abe -import FUSD from 0x3c5959b568896393 - -// Testnet -// import FungibleToken from 0x9a0766d93b6608b7 -// import FUSD from 0xe223d8a629e49c68 - -transaction() { - - // The Vault resource that holds the tokens that are being transfered - let sentVault: @FungibleToken.Vault - - prepare(signer: AuthAccount) { - // Get a reference to the signer's stored vault - let vaultRef = signer.borrow<&FUSD.Vault>(from: /storage/fusdVault) - ?? panic("Could not borrow reference to the owner's Vault!") - - // Withdraw tokens from the signer's stored vault - self.sentVault <- vaultRef.withdraw(amount: vaultRef.balance) - } - - execute { - - let recipient: Address = 0x936851d3e331acd4 - // Get the recipient's public account object - let recipientAccount = getAccount(recipient) - - // Get a reference to the recipient's Receiver - let receiverRef = recipientAccount.getCapability(/public/fusdReceiver)!.borrow<&{FungibleToken.Receiver}>() - ?? panic("Could not borrow receiver reference to the recipient's Vault") - - // Deposit the withdrawn tokens in the recipient's receiver - receiverRef.deposit(from: <-self.sentVault) - } -} diff --git a/transactions/mainnetlistNFTForSaleDapper.cdc b/transactions/mainnetlistNFTForSaleDapper.cdc index 7c0833af..82fbd8bc 100644 --- a/transactions/mainnetlistNFTForSaleDapper.cdc +++ b/transactions/mainnetlistNFTForSaleDapper.cdc @@ -1,21 +1,21 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FindViews from "../contracts/FindViews.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import TokenForwarding from "../contracts/standard/TokenForwarding.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" +import "FindMarket" +import "FindMarketSale" +import "FINDNFTCatalog" +import "FTRegistry" +import "FindViews" +import "NonFungibleToken" +import "MetadataViews" +import "FlowUtilityToken" +import "TokenForwarding" +import "FungibleToken" transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - let saleItems : &FindMarketSale.SaleItemCollection? + let saleItems : auth(FindMarketSale.Seller) &FindMarketSale.SaleItemCollection? let pointer : FindViews.AuthNFTPointer let vaultType : Type - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { let marketplace = FindMarket.getFindTenantAddress() let saleItemType= Type<@FindMarketSale.SaleItemCollection>() @@ -31,7 +31,7 @@ transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: Strin let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) if !saleItemCap.check() { //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) + account.storage.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) } @@ -42,26 +42,26 @@ transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: Strin let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - let futReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - if ft.type == Type<@FlowUtilityToken.Vault>() && !futReceiver.check() { + let futReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) + if ft.type == Type<@FlowUtilityToken.Vault>() && !futReceiver!.check() { // Create a new Forwarder resource for FUT and store it in the new account's storage - let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapper.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver)) - account.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) + let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapper.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver)) + account.storage.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) // Publish a Receiver capability for the new account, which is linked to the FUT Forwarder account.link<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver,target: /storage/flowUtilityTokenReceiver) } - let providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) + let var providerCap=account.capabilities.storage.get<&{NonFungibleToken.Provider, ViewResolver.ResolverCollection, NonFungibleToken.Collection}>(nft.storagePath) if !providerCap.check() { - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( nft.privatePath, target: nft.storagePath ) } // Get the salesItemRef from tenant - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) + self.saleItems= account.storage.borrow(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) self.vaultType= ft.type } diff --git a/transactions/mainnetregisterDapper.cdc b/transactions/mainnetregisterDapper.cdc index e6e5b90e..e131eaed 100644 --- a/transactions/mainnetregisterDapper.cdc +++ b/transactions/mainnetregisterDapper.cdc @@ -1,20 +1,21 @@ -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FIND from "../contracts/FIND.cdc" +import "DapperUtilityCoin" +import "FIND" +import "FungibleToken" transaction(merchAccount: Address, name: String, amount: UFix64) { - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault + let finLeases : auth(FIND.LeaseOwner) &FIND.LeaseCollection + let mainDapperUtilityCoinVault: auth(FungibleToken.Withdraw) &DapperUtilityCoin.Vault let balanceBeforeTransfer: UFix64 let price : UFix64 - prepare(dapper: AuthAccount, account: AuthAccount) { + prepare(dapper: auth(StorageCapabilities, SaveValue,PublishCapability, BorrowValue) &Account, account: auth(BorrowValue) &Account) { self.price=FIND.calculateCost(name) log("The cost for registering this name is ".concat(self.price.toString())) - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) + self.mainDapperUtilityCoinVault = dapper.storage.borrow(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") + self.finLeases= account.storage.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") } pre{ diff --git a/transactions/mainnetrenewNameDapper.cdc b/transactions/mainnetrenewNameDapper.cdc index 3bdd3aba..8884027f 100644 --- a/transactions/mainnetrenewNameDapper.cdc +++ b/transactions/mainnetrenewNameDapper.cdc @@ -1,16 +1,17 @@ -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FIND from "../contracts/FIND.cdc" +import "DapperUtilityCoin" +import "FIND" +import "FungibleToken" transaction(merchAccount: Address, name: String, amount: UFix64) { let price : UFix64 - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault + let finLeases : auth(FIND.LeaseOwner) &FIND.LeaseCollection + let mainDapperUtilityCoinVault: auth(FungibleToken.Withdraw) &DapperUtilityCoin.Vault let balanceBeforeTransfer: UFix64 - prepare(dapper: AuthAccount, acct: AuthAccount) { + prepare(dapper: auth(StorageCapabilities, SaveValue,PublishCapability, BorrowValue) &Account, acct: auth(BorrowValue, FIND.LeaseOwner) &Account) { self.price=FIND.calculateCost(name) - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) + self.mainDapperUtilityCoinVault = dapper.storage.borrow(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance self.finLeases= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") } diff --git a/transactions/mintDandy.cdc b/transactions/mintDandy.cdc index 841f81ec..ded7298e 100644 --- a/transactions/mintDandy.cdc +++ b/transactions/mintDandy.cdc @@ -1,84 +1,78 @@ -import FIND from "../contracts/FIND.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import Dandy from "../contracts/Dandy.cdc" -import Profile from "../contracts/Profile.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FindForge from "../contracts/FindForge.cdc" +import "FIND" +import "NonFungibleToken" +import "FungibleToken" +import "Dandy" +import "Profile" +import "MetadataViews" +import "ViewResolver" +import "FindViews" +import "FindForge" transaction(name: String, maxEdition:UInt64, artist:String, nftName:String, nftDescription:String, nftUrl:String, collectionDescription: String, collectionExternalURL: String, collectionSquareImage: String, collectionBannerImage: String) { - prepare(account: AuthAccount) { - - let dandyCap= account.getCapability<&{NonFungibleToken.CollectionPublic}>(Dandy.CollectionPublicPath) - if !dandyCap.check() { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPublicPath, - target: Dandy.CollectionStoragePath - ) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( - Dandy.CollectionPrivatePath, - target: Dandy.CollectionStoragePath - ) - } - - let finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! - let lease=finLeases.borrow(name) - let forgeType = Dandy.getForgeType() - if !FindForge.checkMinterPlatform(name: lease.getName(), forgeType: forgeType ) { - /* set up minterPlatform */ - FindForge.setMinterPlatform(lease: lease, - forgeType: forgeType, - minterCut: 0.05, - description: collectionDescription, - externalURL: collectionExternalURL, - squareImage: collectionSquareImage, - bannerImage: collectionBannerImage, - socials: { - "Twitter" : "https://twitter.com/home" , - "Discord" : "discord.gg/" - }) - } - - let creativeWork= - FindViews.CreativeWork(artist: artist, name: nftName, description: nftDescription, type:"image") - - let httpFile=MetadataViews.HTTPFile(url:nftUrl) - let media=MetadataViews.Media(file: httpFile, mediaType: "image/png") - - let receiver=account.getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - let nftReceiver=account.getCapability<&{NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Dandy.CollectionPublicPath).borrow() ?? panic("Cannot borrow reference to Dandy collection.") - - let traits = MetadataViews.Traits([]) - traits.addTrait(MetadataViews.Trait(name: "NeoMotorCycleTag", value: "Tag1", displayType:"String", rarity:nil)) - traits.addTrait(MetadataViews.Trait(name: "Speed", value: 100.0, displayType:"Numeric", rarity:nil)) - traits.addTrait(MetadataViews.Trait(name: "Birthday", value: 1660145023.0, displayType:"Date", rarity:nil)) - - let collection=dandyCap.borrow()! - var i:UInt64=1 - - while i <= maxEdition { - - let editioned= MetadataViews.Edition(name: nil, number:i, max:maxEdition) - let set= MetadataViews.Edition(name: "set", number:i, max:maxEdition) - let editions = MetadataViews.Editions([editioned, set]) - let description=creativeWork.description.concat( " edition ").concat(i.toString()).concat( " of ").concat(maxEdition.toString()) - let schemas: [AnyStruct] = [ editions, creativeWork, MetadataViews.Medias([media]), traits ] - - let mintData = Dandy.DandyInfo(name: "Neo Motorcycle ".concat(i.toString()).concat(" of ").concat(maxEdition.toString()), - description: creativeWork.description, - thumbnail: media, - schemas: schemas, - externalUrlPrefix:"https://find.xyz/collection/".concat(name).concat("/dandy")) - - FindForge.mint(lease: lease, forgeType: forgeType, data: mintData, receiver: nftReceiver) - - // let token <- minter.mint(minter: name, forgeMinter: Type<@Dandy.ForgeMinter>().identifier, mintData: mintData) - - i=i+1 - } - - } + prepare(account: auth(BorrowValue, SaveValue, PublishCapability, IssueStorageCapabilityController) &Account) { + + + let dandyCap= account.capabilities.get<&{NonFungibleToken.Collection}>(Dandy.CollectionPublicPath) + if !dandyCap.check() { + account.storage.save(<- Dandy.createEmptyCollection(nftType:Type<@Dandy.NFT>()), to: Dandy.CollectionStoragePath) + let cap = account.capabilities.storage.issue<&Dandy.Collection>(Dandy.CollectionStoragePath) + account.capabilities.publish(cap, at: Dandy.CollectionPublicPath) + } + + let finLeases= account.storage.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! + let lease=finLeases.borrow(name) + let forgeType = Dandy.getForgeType() + if !FindForge.checkMinterPlatform(name: lease.getName(), forgeType: forgeType ) { + /* set up minterPlatform */ + FindForge.setMinterPlatform(lease: lease, + forgeType: forgeType, + minterCut: 0.05, + description: collectionDescription, + externalURL: collectionExternalURL, + squareImage: collectionSquareImage, + bannerImage: collectionBannerImage, + socials: { + "Twitter" : "https://twitter.com/home" , + "Discord" : "discord.gg/" + }) + } + + let creativeWork= + FindViews.CreativeWork(artist: artist, name: nftName, description: nftDescription, type:"image") + + let httpFile=MetadataViews.HTTPFile(url:nftUrl) + let media=MetadataViews.Media(file: httpFile, mediaType: "image/png") + + let receiver=account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let nftReceiver=account.capabilities.borrow<&{NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(Dandy.CollectionPublicPath) ?? panic("Cannot borrow reference to Dandy collection.") + + let traits = MetadataViews.Traits([]) + traits.addTrait(MetadataViews.Trait(name: "NeoMotorCycleTag", value: "Tag1", displayType:"String", rarity:nil)) + traits.addTrait(MetadataViews.Trait(name: "Speed", value: 100.0, displayType:"Numeric", rarity:nil)) + traits.addTrait(MetadataViews.Trait(name: "Birthday", value: 1660145023.0, displayType:"Date", rarity:nil)) + + let collection=dandyCap.borrow()! + var i:UInt64=1 + + while i <= maxEdition { + + let editioned= MetadataViews.Edition(name: nil, number:i, max:maxEdition) + let set= MetadataViews.Edition(name: "set", number:i, max:maxEdition) + let editions = MetadataViews.Editions([editioned, set]) + let description=creativeWork.description.concat( " edition ").concat(i.toString()).concat( " of ").concat(maxEdition.toString()) + let schemas: [AnyStruct] = [ editions, creativeWork, MetadataViews.Medias([media]), traits ] + + let mintData = Dandy.DandyInfo(name: "Neo Motorcycle ".concat(i.toString()).concat(" of ").concat(maxEdition.toString()), + description: creativeWork.description, + thumbnail: media, + schemas: schemas, + externalUrlPrefix:"https://find.xyz/collection/".concat(name).concat("/dandy")) + + FindForge.mint(lease: lease, forgeType: forgeType, data: mintData, receiver: nftReceiver) + + i=i+1 + } + + } } diff --git a/transactions/mintExampleNFT.cdc b/transactions/mintExampleNFT.cdc index 9ccb2764..1f682d53 100644 --- a/transactions/mintExampleNFT.cdc +++ b/transactions/mintExampleNFT.cdc @@ -1,30 +1,28 @@ -import FIND from "../contracts/FIND.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import ExampleNFT from "../contracts/standard/ExampleNFT.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "ExampleNFT" +import "MetadataViews" -transaction(user: String, - name: String, - description: String, - thumbnail: String, - soulBound: Bool , - traits: [UInt64] - ) { - let address : Address - let cap : Capability<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic}> +transaction(address: Address, name: String, description: String, thumbnail: String, soulBound: Bool) { + let cap : Capability<&ExampleNFT.Collection> + let royaltyCap : Capability<&{FungibleToken.Receiver}> - prepare(account: AuthAccount) { - self.address = FIND.resolve(user) ?? panic("Cannot find user with this name / address") - self.cap = getAccount(self.address).getCapability<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) - } + prepare(account: auth (StorageCapabilities, SaveValue,PublishCapability, BorrowValue, UnpublishCapability) &Account) { - pre{ - self.cap.check() : "Cannot borrow reference to receiver Collection. Receiver account : ".concat(self.address.toString()) - } + self.cap = getAccount(address).capabilities.get<&ExampleNFT.Collection>(ExampleNFT.CollectionPublicPath)! - execute{ - let r : MetadataViews.Royalties = MetadataViews.Royalties([]) - let nft <- ExampleNFT.mintNFT(name: name, description: description, thumbnail: thumbnail, soulBound: soulBound, traits: traits, royalties: r) - self.cap.borrow()!.deposit(token: <- nft) - } + self.royaltyCap =getAccount(address).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)! + } + + pre{ + self.cap.check() : "Cannot borrow reference to receiver Collection. Receiver account : ".concat(address.toString()) + } + + execute{ + + let r = MetadataViews.Royalty(receiver:self.royaltyCap, cut: 0.01, description: "creator") + let royalties = MetadataViews.Royalties([r]) + let nft <- ExampleNFT.mintNFT(name: name, description: description, thumbnail: thumbnail, soulBound:soulBound, traits:[], royalties: royalties) + self.cap.borrow()!.deposit(token: <- nft) + } } diff --git a/transactions/moveNameTO.cdc b/transactions/moveNameTO.cdc index 460f7065..677f6a47 100644 --- a/transactions/moveNameTO.cdc +++ b/transactions/moveNameTO.cdc @@ -1,31 +1,30 @@ -import Profile from "../contracts/Profile.cdc" -import FIND from "../contracts/FIND.cdc" +import "Profile" +import "FIND" transaction(name: String, receiver:String) { + let receiverAddress:Address? + let sender : auth(FIND.LeaseOwner) &FIND.LeaseCollection - let receiverAddress:Address? - let sender : &FIND.LeaseCollection + prepare(acct: auth(BorrowValue) &Account) { + self.sender= acct.storage.borrow(from:FIND.LeaseStoragePath) ?? panic("You do not have a profile set up, initialize the user first") + self.receiverAddress=FIND.resolve(receiver) + } - prepare(acct: AuthAccount) { - self.sender= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("You do not have a profile set up, initialize the user first") - self.receiverAddress=FIND.resolve(receiver) - } + pre{ + self.receiverAddress != nil : "The input pass in is not a valid name or address. Input : ".concat(receiver) + } - pre{ - self.receiverAddress != nil : "The input pass in is not a valid name or address. Input : ".concat(receiver) - } + execute { + let receiver=getAccount(self.receiverAddress!) + let receiverLease = receiver.capabilities.get<&FIND.LeaseCollection>(FIND.LeasePublicPath) + let receiverProfile = receiver.capabilities.get<&{Profile.Public}>(Profile.publicPath) - execute { - let receiver=getAccount(self.receiverAddress!) - let receiverLease = receiver.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - let receiverProfile = receiver.getCapability<&{Profile.Public}>(Profile.publicPath) + if !receiverLease.check() || !receiverProfile.check() { + panic("Not a valid FIND user") + } - if !receiverLease.check() || !receiverProfile.check() { - panic("Not a valid FIND user") - } - - self.sender.move(name:name, profile:receiverProfile, to: receiverLease) - } + self.sender.move(name:name, profile:receiverProfile, to: receiverLease) + } } diff --git a/transactions/moveNameToDapper.cdc b/transactions/moveNameToDapper.cdc index 460f7065..485489ed 100644 --- a/transactions/moveNameToDapper.cdc +++ b/transactions/moveNameToDapper.cdc @@ -1,31 +1,34 @@ -import Profile from "../contracts/Profile.cdc" -import FIND from "../contracts/FIND.cdc" +import "Profile" +import "FIND" transaction(name: String, receiver:String) { - let receiverAddress:Address? - let sender : &FIND.LeaseCollection + let receiverAddress:Address? + //TODO: what entitlement is correct here? + let sender : auth(FIND.LeaseOwner) &FIND.LeaseCollection - prepare(acct: AuthAccount) { - self.sender= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("You do not have a profile set up, initialize the user first") - self.receiverAddress=FIND.resolve(receiver) - } + prepare(acct: auth(BorrowValue) &Account) { + self.sender= acct.storage.borrow(from:FIND.LeaseStoragePath) ?? panic("You do not have a profile set up, initialize the user first") + self.receiverAddress=FIND.resolve(receiver) + } - pre{ - self.receiverAddress != nil : "The input pass in is not a valid name or address. Input : ".concat(receiver) - } + pre{ + self.receiverAddress != nil : "The input pass in is not a valid name or address. Input : ".concat(receiver) + } - execute { - let receiver=getAccount(self.receiverAddress!) - let receiverLease = receiver.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - let receiverProfile = receiver.getCapability<&{Profile.Public}>(Profile.publicPath) + execute { + let receiver=getAccount(self.receiverAddress!) + let receiverLease = receiver.capabilities.get<&FIND.LeaseCollection>(FIND.LeasePublicPath) + let receiverProfile = receiver.capabilities.get<&{Profile.Public}>(Profile.publicPath) - if !receiverLease.check() || !receiverProfile.check() { - panic("Not a valid FIND user") - } - self.sender.move(name:name, profile:receiverProfile, to: receiverLease) - } + + if !receiverLease.check() || !receiverProfile.check() { + panic("Not a valid FIND user") + } + + self.sender.move(name:name, profile:receiverProfile, to: receiverLease) + } } diff --git a/transactions/openBl0xPack.cdc b/transactions/openBl0xPack.cdc deleted file mode 100644 index 96d91b94..00000000 --- a/transactions/openBl0xPack.cdc +++ /dev/null @@ -1,43 +0,0 @@ -import Bl0x from "../contracts/Bl0x.cdc" -import Bl0xPack from "../contracts/Bl0xPack.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" - -/// A transaction to open a pack with a given id -/// @param packId: The id of the pack to open -transaction(packId:UInt64) { - - let packs: &Bl0xPack.Collection - var receiver: Capability<&{NonFungibleToken.Receiver}> - - prepare(account: AuthAccount) { - self.packs=account.borrow<&Bl0xPack.Collection>(from: Bl0xPack.CollectionStoragePath)! - self.receiver = account.getCapability<&{NonFungibleToken.Receiver}>(Bl0x.CollectionPublicPath) - if !self.receiver.check() { - account.save<@NonFungibleToken.Collection>(<- Bl0x.createEmptyCollection(), to: Bl0x.CollectionStoragePath) - account.link<&Bl0x.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Bl0x.CollectionPublicPath, - target: Bl0x.CollectionStoragePath - ) - account.link<&Bl0x.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - Bl0x.CollectionPrivatePath, - target: Bl0x.CollectionStoragePath - ) - - self.receiver = account.getCapability<&{NonFungibleToken.Receiver}>(Bl0x.CollectionPublicPath) - } - - } - - pre { - self.receiver.check() : "The receiver collection for the packs is not set up properly" - } - execute { - self.packs.open(packId: packId, receiverCap:self.receiver) - } - - post { - !self.packs.getIDs().contains(packId) : "The pack is still present in the users collection" - } -} diff --git a/transactions/openFindPack.cdc b/transactions/openFindPack.cdc index 21df417b..b6a60113 100644 --- a/transactions/openFindPack.cdc +++ b/transactions/openFindPack.cdc @@ -1,19 +1,19 @@ -import FindPack from "../contracts/FindPack.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "FindPack" +import "FINDNFTCatalog" +import "NFTCatalog" +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" /// A transaction to open a pack with a given id /// @param packId: The id of the pack to open transaction(packId:UInt64) { - let packs: &FindPack.Collection + let packs: auth(FindPack.Owner) &FindPack.Collection let receiver: { Type : Capability<&{NonFungibleToken.Receiver}>} - prepare(account: AuthAccount) { - self.packs=account.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath)! + prepare(account: auth (StorageCapabilities, SaveValue,PublishCapability, BorrowValue) &Account) { + self.packs=account.storage.borrow(from: FindPack.CollectionStoragePath)! let packData = self.packs.borrowFindPack(id: packId) ?? panic("You do not own this pack. ID : ".concat(packId.toString())) let packMetadata = packData.getMetadata() @@ -29,19 +29,15 @@ transaction(packId:UInt64) { } let collectionInfo = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collection!.keys[0])!.collectionData - let cap = account.getCapability<&{NonFungibleToken.Receiver}>(collectionInfo.publicPath) - let storage= account.borrow<&NonFungibleToken.Collection>(from: collectionInfo.storagePath) + + let storage= account.storage.borrow<&{NonFungibleToken.Collection}>(from: collectionInfo.storagePath) if storage == nil { let newCollection <- FindPack.createEmptyCollectionFromPackData(packData: packMetadata, type: type) - account.save(<- newCollection, to: collectionInfo.storagePath) - account.link<&{NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>( collectionInfo.publicPath, target: collectionInfo.storagePath) - } - - if !cap.check() { - account.unlink(collectionInfo.publicPath) - account.link<&{NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>( collectionInfo.publicPath, target: collectionInfo.storagePath) + account.storage.save(<- newCollection, to: collectionInfo.storagePath) + let fc= account.capabilities.storage.issue<&FindPack.Collection>(collectionInfo.storagePath) + account.capabilities.publish(fc, at: collectionInfo.publicPath) } - self.receiver[type] = cap + self.receiver[type] = account.capabilities.get<&{NonFungibleToken.Collection}>(collectionInfo.publicPath)! } } diff --git a/transactions/orderForge.cdc b/transactions/orderForge.cdc index 276b6e77..bb1d6ec9 100644 --- a/transactions/orderForge.cdc +++ b/transactions/orderForge.cdc @@ -1,15 +1,15 @@ -import FindForge from "../contracts/FindForge.cdc" -import FIND from "../contracts/FIND.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "FindForge" +import "FIND" +import "MetadataViews" transaction(name: String, mintType:String, minterCut: UFix64, collectionDisplay: MetadataViews.NFTCollectionDisplay) { let leases : &FIND.LeaseCollection? - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - self.leases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) + self.leases= account.storage.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) } diff --git a/transactions/publishFindThought.cdc b/transactions/publishFindThought.cdc index 8c4c153c..a751eb9b 100644 --- a/transactions/publishFindThought.cdc +++ b/transactions/publishFindThought.cdc @@ -1,50 +1,53 @@ -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindThoughts from "../contracts/FindThoughts.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FindUtils from "../contracts/FindUtils.cdc" +import "MetadataViews" +import "FindThoughts" +import "FINDNFTCatalog" +import "FindViews" +import "FindUtils" transaction(header: String , body: String , tags: [String], mediaHash: String?, mediaType: String?, quoteNFTOwner: Address?, quoteNFTType: String?, quoteNFTId: UInt64?, quoteCreator: Address?, quoteId: UInt64?) { - let collection : &FindThoughts.Collection - - prepare(account: AuthAccount) { - let thoughtsCap= account.getCapability<&{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath) - if !thoughtsCap.check() { - account.save(<- FindThoughts.createEmptyCollection(), to: FindThoughts.CollectionStoragePath) - account.link<&FindThoughts.Collection{FindThoughts.CollectionPublic , MetadataViews.ResolverCollection}>( - FindThoughts.CollectionPublicPath, - target: FindThoughts.CollectionStoragePath - ) - } - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } - - execute { - - var media : MetadataViews.Media? = nil - if mediaHash != nil { - var file : {MetadataViews.File}? = nil - if FindUtils.hasPrefix(mediaHash!, prefix: "ipfs://") { - file = MetadataViews.IPFSFile(cid: mediaHash!.slice(from: "ipfs://".length , upTo: mediaHash!.length), path: nil) - } else { - file = MetadataViews.HTTPFile(url: mediaHash!) - } - media = MetadataViews.Media(file: file!, mediaType: mediaType!) - } - - var nftPointer : FindViews.ViewReadPointer? = nil - if quoteNFTOwner != nil { - let path = FINDNFTCatalog.getCollectionDataForType(nftTypeIdentifier: quoteNFTType!)?.publicPath ?? panic("This nft type is not supported by NFT Catalog. Type : ".concat(quoteNFTType!)) - let cap = getAccount(quoteNFTOwner!).getCapability<&{MetadataViews.ResolverCollection}>(path) - nftPointer = FindViews.ViewReadPointer(cap: cap, id: quoteNFTId!) - } - - var quote : FindThoughts.ThoughtPointer? = nil - if quoteCreator != nil { - quote = FindThoughts.ThoughtPointer(creator: quoteCreator!, id: quoteId!) - } - - self.collection.publish(header: header, body: body, tags: tags, media: media, nftPointer: nftPointer, quote: quote) - } + let collection : auth(FindThoughts.Owner) &FindThoughts.Collection + + prepare(account: auth (StorageCapabilities, SaveValue,PublishCapability, BorrowValue, UnpublishCapability) &Account) { + + let col= account.storage.borrow(from: FindThoughts.CollectionStoragePath) + if col == nil { + account.storage.save( <- FindThoughts.createEmptyCollection(), to: FindThoughts.CollectionStoragePath) + account.capabilities.unpublish(FindThoughts.CollectionPublicPath) + //TODO: i do not think we can store an auth cap in a publis path + let cap = account.capabilities.storage.issue<&FindThoughts.Collection>(FindThoughts.CollectionStoragePath) + account.capabilities.publish(cap, at: FindThoughts.CollectionPublicPath) + self.collection=account.storage.borrow(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") + }else { + self.collection=col! + } + } + + execute { + + var media : MetadataViews.Media? = nil + if mediaHash != nil { + var file : {MetadataViews.File}? = nil + if FindUtils.hasPrefix(mediaHash!, prefix: "ipfs://") { + file = MetadataViews.IPFSFile(cid: mediaHash!.slice(from: "ipfs://".length , upTo: mediaHash!.length), path: nil) + } else { + file = MetadataViews.HTTPFile(url: mediaHash!) + } + media = MetadataViews.Media(file: file!, mediaType: mediaType!) + } + + var nftPointer : FindViews.ViewReadPointer? = nil + if quoteNFTOwner != nil { + let path = FINDNFTCatalog.getCollectionDataForType(nftTypeIdentifier: quoteNFTType!)?.publicPath ?? panic("This nft type is not supported by NFT Catalog. Type : ".concat(quoteNFTType!)) + + nftPointer = FindViews.createViewReadPointer(address:quoteNFTOwner!, path: path, id:quoteNFTId!) + } + + var quote : FindThoughts.ThoughtPointer? = nil + if quoteCreator != nil { + quote = FindThoughts.ThoughtPointer(creator: quoteCreator!, id: quoteId!) + } + + self.collection.publish(header: header, body: body, tags: tags, media: media, nftPointer: nftPointer, quote: quote) +} } diff --git a/transactions/reactToFindThoughts.cdc b/transactions/reactToFindThoughts.cdc index 564b8df1..7cde52e9 100644 --- a/transactions/reactToFindThoughts.cdc +++ b/transactions/reactToFindThoughts.cdc @@ -1,32 +1,35 @@ -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindThoughts from "../contracts/FindThoughts.cdc" -import FIND from "../contracts/FIND.cdc" +import "MetadataViews" +import "FindThoughts" +import "FIND" transaction(users: [String], ids: [UInt64] , reactions: [String], undoReactionUsers: [String], undoReactionIds: [UInt64]) { - let collection : &FindThoughts.Collection + let collection : auth(FindThoughts.Owner) &FindThoughts.Collection - prepare(account: AuthAccount) { - let thoughtsCap= account.getCapability<&{FindThoughts.CollectionPublic}>(FindThoughts.CollectionPublicPath) - if !thoughtsCap.check() { - account.save(<- FindThoughts.createEmptyCollection(), to: FindThoughts.CollectionStoragePath) - account.link<&FindThoughts.Collection{FindThoughts.CollectionPublic , MetadataViews.ResolverCollection}>( - FindThoughts.CollectionPublicPath, - target: FindThoughts.CollectionStoragePath - ) - } - self.collection=account.borrow<&FindThoughts.Collection>(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") - } + prepare(account: auth (StorageCapabilities, SaveValue,PublishCapability, BorrowValue, UnpublishCapability) &Account) { - execute { - for i, user in users { - let address = FIND.resolve(user) ?? panic("Cannot resolve user : ".concat(user)) - self.collection.react(user: address, id: ids[i], reaction: reactions[i]) - } + let col= account.storage.borrow(from: FindThoughts.CollectionStoragePath) + if col == nil { + account.storage.save( <- FindThoughts.createEmptyCollection(), to: FindThoughts.CollectionStoragePath) + account.capabilities.unpublish(FindThoughts.CollectionPublicPath) + let cap = account.capabilities.storage.issue<&FindThoughts.Collection>(FindThoughts.CollectionStoragePath) + account.capabilities.publish(cap, at: FindThoughts.CollectionPublicPath) + self.collection=account.storage.borrow(from: FindThoughts.CollectionStoragePath) ?? panic("Cannot borrow thoughts reference from path") + }else { + self.collection=col! + } - for i, user in undoReactionUsers { - let address = FIND.resolve(user) ?? panic("Cannot resolve user : ".concat(user)) - self.collection.react(user: address, id: undoReactionIds[i], reaction: nil) - } - } + } + + execute { + for i, user in users { + let address = FIND.resolve(user) ?? panic("Cannot resolve user : ".concat(user)) + self.collection.react(user: address, id: ids[i], reaction: reactions[i]) + } + + for i, user in undoReactionUsers { + let address = FIND.resolve(user) ?? panic("Cannot resolve user : ".concat(user)) + self.collection.react(user: address, id: undoReactionIds[i], reaction: nil) + } + } } diff --git a/transactions/redeemAllLostAndFoundNFTs.cdc b/transactions/redeemAllLostAndFoundNFTs.cdc index 49428b18..827b5210 100644 --- a/transactions/redeemAllLostAndFoundNFTs.cdc +++ b/transactions/redeemAllLostAndFoundNFTs.cdc @@ -1,16 +1,16 @@ -import FindLostAndFoundWrapper from "../contracts/FindLostAndFoundWrapper.cdc" -import LostAndFound from "../contracts/standard/LostAndFound.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FIND from "../contracts/FIND.cdc" -import Dandy from "../contracts/Dandy.cdc" -import NFGv3 from "../contracts/NFGv3.cdc" -import PartyFavorz from "../contracts/PartyFavorz.cdc" -import NameVoucher from "../contracts/NameVoucher.cdc" -import Wearables from "../contracts/community/Wearables.cdc" -import FindPack from "../contracts/FindPack.cdc" +import "FindLostAndFoundWrapper" +import "LostAndFound" +import "FINDNFTCatalog" +import "NFTCatalog" +import "NonFungibleToken" +import "MetadataViews" +import "FIND" +import "Dandy" +import "NFGv3" +import "PartyFavorz" +import "NameVoucher" +import "Wearables" +import "FindPack" //IMPORT @@ -20,208 +20,208 @@ transaction() { let nftInfos : {String : NFTCatalog.NFTCollectionData} let receiverAddress : Address - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ //LINK // Dandy - let DandyRef= account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) + let DandyRef= account.storage.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) if DandyRef == nil { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPublicPath, target: Dandy.CollectionStoragePath ) account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPrivatePath, target: Dandy.CollectionStoragePath ) } - let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPublicPath) + let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPublicPath) if !DandyCap.check() { account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPublicPath, target: Dandy.CollectionStoragePath ) } - let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPrivatePath) + let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPrivatePath) if !DandyProviderCap.check() { account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPrivatePath, target: Dandy.CollectionStoragePath ) } //findPack - let FindPackRef= account.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath) + let FindPackRef= account.storage.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath) if FindPackRef == nil { - account.save<@NonFungibleToken.Collection>(<- FindPack.createEmptyCollection(), to: FindPack.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- FindPack.createEmptyCollection(), to: FindPack.CollectionStoragePath) account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&FindPack.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( FindPack.CollectionPublicPath, target: FindPack.CollectionStoragePath ) account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( FindPack.CollectionPrivatePath, target: FindPack.CollectionStoragePath ) } - let FindPackCap= account.getCapability<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPublicPath) + let FindPackCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(FindPack.CollectionPublicPath) if !FindPackCap.check() { account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&FindPack.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( FindPack.CollectionPublicPath, target: FindPack.CollectionStoragePath ) } - let FindPackProviderCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPrivatePath) + let FindPackProviderCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(FindPack.CollectionPrivatePath) if !FindPackProviderCap.check() { account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( FindPack.CollectionPrivatePath, target: FindPack.CollectionStoragePath ) } // NFGv3 - let NFGv3Ref= account.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) + let NFGv3Ref= account.storage.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) if NFGv3Ref == nil { - account.save<@NonFungibleToken.Collection>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NFGv3.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NFGv3.CollectionPublicPath, target: NFGv3.CollectionStoragePath ) account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NFGv3.CollectionPrivatePath, target: NFGv3.CollectionStoragePath ) } - let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPublicPath) + let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(NFGv3.CollectionPublicPath) if !NFGv3Cap.check() { account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NFGv3.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NFGv3.CollectionPublicPath, target: NFGv3.CollectionStoragePath ) } - let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPrivatePath) + let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(NFGv3.CollectionPrivatePath) if !NFGv3ProviderCap.check() { account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NFGv3.CollectionPrivatePath, target: NFGv3.CollectionStoragePath ) } // Party Favorz - let PartyFavorzRef= account.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) + let PartyFavorzRef= account.storage.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) if PartyFavorzRef == nil { - account.save<@NonFungibleToken.Collection>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&PartyFavorz.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( PartyFavorz.CollectionPublicPath, target: PartyFavorz.CollectionStoragePath ) account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( PartyFavorz.CollectionPrivatePath, target: PartyFavorz.CollectionStoragePath ) } - let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPublicPath) + let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(PartyFavorz.CollectionPublicPath) if !PartyFavorzCap.check() { account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&PartyFavorz.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( PartyFavorz.CollectionPublicPath, target: PartyFavorz.CollectionStoragePath ) } - let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) + let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) if !PartyFavorzProviderCap.check() { account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( PartyFavorz.CollectionPrivatePath, target: PartyFavorz.CollectionStoragePath ) } // Name Voucher - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) + let nameVoucherRef= account.storage.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NameVoucher.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NameVoucher.CollectionPublicPath, target: NameVoucher.CollectionStoragePath ) account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NameVoucher.CollectionPrivatePath, target: NameVoucher.CollectionStoragePath ) } - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) + let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(NameVoucher.CollectionPublicPath) if !nameVoucherCap.check() { account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NameVoucher.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NameVoucher.CollectionPublicPath, target: NameVoucher.CollectionStoragePath ) } - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) + let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(NameVoucher.CollectionPrivatePath) if !nameVoucherProviderCap.check() { account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NameVoucher.CollectionPrivatePath, target: NameVoucher.CollectionStoragePath ) } // Wearables - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) + let wearablesRef= account.storage.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPublicPath, target: Wearables.CollectionStoragePath ) account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPrivatePath, target: Wearables.CollectionStoragePath ) } - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) + let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(Wearables.CollectionPublicPath) if !wearablesCap.check() { account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPublicPath, target: Wearables.CollectionStoragePath ) } - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) + let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(Wearables.CollectionPrivatePath) if !wearablesProviderCap.check() { account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPrivatePath, target: Wearables.CollectionStoragePath ) diff --git a/transactions/redeemAllLostAndFoundNFTsOnBehalf.cdc b/transactions/redeemAllLostAndFoundNFTsOnBehalf.cdc index 4c6c47c9..7e572902 100644 --- a/transactions/redeemAllLostAndFoundNFTsOnBehalf.cdc +++ b/transactions/redeemAllLostAndFoundNFTsOnBehalf.cdc @@ -1,10 +1,10 @@ -import FindLostAndFoundWrapper from "../contracts/FindLostAndFoundWrapper.cdc" -import LostAndFound from "../contracts/standard/LostAndFound.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FIND from "../contracts/FIND.cdc" +import "FindLostAndFoundWrapper" +import "LostAndFound" +import "FINDNFTCatalog" +import "NFTCatalog" +import "NonFungibleToken" +import "MetadataViews" +import "FIND" //IMPORT @@ -14,7 +14,7 @@ transaction(receiverAddress: Address) { let nftInfos : {String : NFTCatalog.NFTCollectionData} let receiverAddress : Address - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ self.receiverAddress = receiverAddress self.nftInfos = {} diff --git a/transactions/redeemLostAndFoundNFTs.cdc b/transactions/redeemLostAndFoundNFTs.cdc index f693e7b6..272159fe 100644 --- a/transactions/redeemLostAndFoundNFTs.cdc +++ b/transactions/redeemLostAndFoundNFTs.cdc @@ -1,17 +1,17 @@ -import FindLostAndFoundWrapper from "../contracts/FindLostAndFoundWrapper.cdc" -import LostAndFound from "../contracts/standard/LostAndFound.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FIND from "../contracts/FIND.cdc" -import Dandy from "../contracts/Dandy.cdc" -import NFGv3 from "../contracts/NFGv3.cdc" -import PartyFavorz from "../contracts/PartyFavorz.cdc" -import NameVoucher from "../contracts/NameVoucher.cdc" -import Wearables from "../contracts/community/Wearables.cdc" -import FindPack from "../contracts/FindPack.cdc" +import "FindLostAndFoundWrapper" +import "LostAndFound" +import "FINDNFTCatalog" +import "NFTCatalog" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "FIND" +import "Dandy" +import "NFGv3" +import "PartyFavorz" +import "NameVoucher" +import "Wearables" +import "FindPack" //IMPORT @@ -20,38 +20,38 @@ transaction(ids: {String : [UInt64]}) { let nftInfos : {String : NFTCatalog.NFTCollectionData} let receiverAddress : Address - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ //LINK // Dandy - let DandyRef= account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) + let DandyRef= account.storage.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) if DandyRef == nil { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPublicPath, target: Dandy.CollectionStoragePath ) account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPrivatePath, target: Dandy.CollectionStoragePath ) } - let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPublicPath) + let DandyCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPublicPath) if !DandyCap.check() { account.unlink(Dandy.CollectionPublicPath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPublicPath, target: Dandy.CollectionStoragePath ) } - let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPrivatePath) + let DandyProviderCap= account.getCapability<&Dandy.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>(Dandy.CollectionPrivatePath) if !DandyProviderCap.check() { account.unlink(Dandy.CollectionPrivatePath) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPrivatePath, target: Dandy.CollectionStoragePath ) @@ -59,34 +59,34 @@ transaction(ids: {String : [UInt64]}) { //findPack - let FindPackRef= account.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath) + let FindPackRef= account.storage.borrow<&FindPack.Collection>(from: FindPack.CollectionStoragePath) if FindPackRef == nil { - account.save<@NonFungibleToken.Collection>(<- FindPack.createEmptyCollection(), to: FindPack.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- FindPack.createEmptyCollection(), to: FindPack.CollectionStoragePath) account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&FindPack.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( FindPack.CollectionPublicPath, target: FindPack.CollectionStoragePath ) account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( FindPack.CollectionPrivatePath, target: FindPack.CollectionStoragePath ) } - let FindPackCap= account.getCapability<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPublicPath) + let FindPackCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(FindPack.CollectionPublicPath) if !FindPackCap.check() { account.unlink(FindPack.CollectionPublicPath) - account.link<&FindPack.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&FindPack.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( FindPack.CollectionPublicPath, target: FindPack.CollectionStoragePath ) } - let FindPackProviderCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(FindPack.CollectionPrivatePath) + let FindPackProviderCap= account.getCapability<&FindPack.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(FindPack.CollectionPrivatePath) if !FindPackProviderCap.check() { account.unlink(FindPack.CollectionPrivatePath) - account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&FindPack.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( FindPack.CollectionPrivatePath, target: FindPack.CollectionStoragePath ) @@ -94,136 +94,136 @@ transaction(ids: {String : [UInt64]}) { // NFGv3 - let NFGv3Ref= account.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) + let NFGv3Ref= account.storage.borrow<&NFGv3.Collection>(from: NFGv3.CollectionStoragePath) if NFGv3Ref == nil { - account.save<@NonFungibleToken.Collection>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- NFGv3.createEmptyCollection(), to: NFGv3.CollectionStoragePath) account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NFGv3.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NFGv3.CollectionPublicPath, target: NFGv3.CollectionStoragePath ) account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NFGv3.CollectionPrivatePath, target: NFGv3.CollectionStoragePath ) } - let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPublicPath) + let NFGv3Cap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(NFGv3.CollectionPublicPath) if !NFGv3Cap.check() { account.unlink(NFGv3.CollectionPublicPath) - account.link<&NFGv3.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NFGv3.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NFGv3.CollectionPublicPath, target: NFGv3.CollectionStoragePath ) } - let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NFGv3.CollectionPrivatePath) + let NFGv3ProviderCap= account.getCapability<&NFGv3.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(NFGv3.CollectionPrivatePath) if !NFGv3ProviderCap.check() { account.unlink(NFGv3.CollectionPrivatePath) - account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NFGv3.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NFGv3.CollectionPrivatePath, target: NFGv3.CollectionStoragePath ) } // Party Favorz - let PartyFavorzRef= account.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) + let PartyFavorzRef= account.storage.borrow<&PartyFavorz.Collection>(from: PartyFavorz.CollectionStoragePath) if PartyFavorzRef == nil { - account.save<@NonFungibleToken.Collection>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- PartyFavorz.createEmptyCollection(), to: PartyFavorz.CollectionStoragePath) account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&PartyFavorz.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( PartyFavorz.CollectionPublicPath, target: PartyFavorz.CollectionStoragePath ) account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( PartyFavorz.CollectionPrivatePath, target: PartyFavorz.CollectionStoragePath ) } - let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPublicPath) + let PartyFavorzCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(PartyFavorz.CollectionPublicPath) if !PartyFavorzCap.check() { account.unlink(PartyFavorz.CollectionPublicPath) - account.link<&PartyFavorz.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&PartyFavorz.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( PartyFavorz.CollectionPublicPath, target: PartyFavorz.CollectionStoragePath ) } - let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) + let PartyFavorzProviderCap= account.getCapability<&PartyFavorz.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(PartyFavorz.CollectionPrivatePath) if !PartyFavorzProviderCap.check() { account.unlink(PartyFavorz.CollectionPrivatePath) - account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&PartyFavorz.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( PartyFavorz.CollectionPrivatePath, target: PartyFavorz.CollectionStoragePath ) } // Name Voucher - let nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) + let nameVoucherRef= account.storage.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NameVoucher.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NameVoucher.CollectionPublicPath, target: NameVoucher.CollectionStoragePath ) account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NameVoucher.CollectionPrivatePath, target: NameVoucher.CollectionStoragePath ) } - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) + let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(NameVoucher.CollectionPublicPath) if !nameVoucherCap.check() { account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NameVoucher.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NameVoucher.CollectionPublicPath, target: NameVoucher.CollectionStoragePath ) } - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) + let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(NameVoucher.CollectionPrivatePath) if !nameVoucherProviderCap.check() { account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( NameVoucher.CollectionPrivatePath, target: NameVoucher.CollectionStoragePath ) } // Wearables - let wearablesRef= account.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) + let wearablesRef= account.storage.borrow<&Wearables.Collection>(from: Wearables.CollectionStoragePath) if wearablesRef == nil { - account.save<@NonFungibleToken.Collection>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) + account.storage.save<@{NonFungibleToken.Collection}>(<- Wearables.createEmptyCollection(), to: Wearables.CollectionStoragePath) account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPublicPath, target: Wearables.CollectionStoragePath ) account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPrivatePath, target: Wearables.CollectionStoragePath ) } - let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPublicPath) + let wearablesCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(Wearables.CollectionPublicPath) if !wearablesCap.check() { account.unlink(Wearables.CollectionPublicPath) - account.link<&Wearables.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPublicPath, target: Wearables.CollectionStoragePath ) } - let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(Wearables.CollectionPrivatePath) + let wearablesProviderCap= account.getCapability<&Wearables.Collection{NonFungibleToken.Provider,NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(Wearables.CollectionPrivatePath) if !wearablesProviderCap.check() { account.unlink(Wearables.CollectionPrivatePath) - account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&Wearables.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( Wearables.CollectionPrivatePath, target: Wearables.CollectionStoragePath ) diff --git a/transactions/redeemLostAndFoundNFTsOnBehalf.cdc b/transactions/redeemLostAndFoundNFTsOnBehalf.cdc index 3059ee50..7e66ada1 100644 --- a/transactions/redeemLostAndFoundNFTsOnBehalf.cdc +++ b/transactions/redeemLostAndFoundNFTsOnBehalf.cdc @@ -1,42 +1,41 @@ -import FindLostAndFoundWrapper from "../contracts/FindLostAndFoundWrapper.cdc" -import LostAndFound from "../contracts/standard/LostAndFound.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FIND from "../contracts/FIND.cdc" -import Bl0xPack from "../contracts/Bl0xPack.cdc" +import "FindLostAndFoundWrapper" +import "LostAndFound" +import "FINDNFTCatalog" +import "NFTCatalog" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "FIND" //IMPORT transaction(receiverAddress: Address, ids: {String : [UInt64]}) { - let nftInfos : {String : NFTCatalog.NFTCollectionData} - let receiverAddress : Address + let nftInfos : {String : NFTCatalog.NFTCollectionData} + let receiverAddress : Address - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ - self.receiverAddress = receiverAddress + self.receiverAddress = receiverAddress - self.nftInfos = {} + self.nftInfos = {} - for type in ids.keys{ - if self.nftInfos[type] == nil { - let collections = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: type) ?? panic("NFT type is not supported at the moment. Type : ".concat(type)) - self.nftInfos[type] = FINDNFTCatalog.getCatalogEntry(collectionIdentifier: collections.keys[0])!.collectionData - } - } + for type in ids.keys{ + if self.nftInfos[type] == nil { + let collections = FINDNFTCatalog.getCollectionsForType(nftTypeIdentifier: type) ?? panic("NFT type is not supported at the moment. Type : ".concat(type)) + self.nftInfos[type] = FINDNFTCatalog.getCatalogEntry(collectionIdentifier: collections.keys[0])!.collectionData + } + } - } + } - execute{ - for type in ids.keys{ - let path = self.nftInfos[type]!.publicPath - for id in ids[type]! { - FindLostAndFoundWrapper.redeemNFT(type: CompositeType(type)!, ticketID: id, receiverAddress:self.receiverAddress, collectionPublicPath: path) - } - } - } + execute{ + for type in ids.keys{ + let path = self.nftInfos[type]!.publicPath + for id in ids[type]! { + FindLostAndFoundWrapper.redeemNFT(type: CompositeType(type)!, ticketID: id, receiverAddress:self.receiverAddress, collectionPublicPath: path) + } + } + } } diff --git a/transactions/redeemNameVoucher.cdc b/transactions/redeemNameVoucher.cdc index 1562163f..95931e58 100644 --- a/transactions/redeemNameVoucher.cdc +++ b/transactions/redeemNameVoucher.cdc @@ -1,75 +1,48 @@ -import NameVoucher from "../contracts/NameVoucher.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import LostAndFound from "../contracts/standard/LostAndFound.cdc" -import FindLostAndFoundWrapper from "../contracts/FindLostAndFoundWrapper.cdc" +import "NameVoucher" +import "NonFungibleToken" +import "MetadataViews" +import "LostAndFound" +import "FindLostAndFoundWrapper" transaction(id: UInt64, name: String) { - var collection : &NameVoucher.Collection - let addr : Address - - prepare(account:AuthAccount) { - - var nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - if nameVoucherRef == nil { - account.save<@NonFungibleToken.Collection>(<- NameVoucher.createEmptyCollection(), to: NameVoucher.CollectionStoragePath) - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - nameVoucherRef= account.borrow<&NameVoucher.Collection>(from: NameVoucher.CollectionStoragePath) - } - - - let nameVoucherCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPublicPath) - if !nameVoucherCap.check() { - account.unlink(NameVoucher.CollectionPublicPath) - account.link<&NameVoucher.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPublicPath, - target: NameVoucher.CollectionStoragePath - ) - } - - let nameVoucherProviderCap= account.getCapability<&NameVoucher.Collection{NonFungibleToken.Provider,NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(NameVoucher.CollectionPrivatePath) - if !nameVoucherProviderCap.check() { - account.unlink(NameVoucher.CollectionPrivatePath) - account.link<&NameVoucher.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - NameVoucher.CollectionPrivatePath, - target: NameVoucher.CollectionStoragePath - ) - } - self.collection = nameVoucherRef! - self.addr = account.address - } - - execute{ - // check if it is there in collection - if self.collection.contains(id) { - self.collection.redeem(id: id, name: name) - return - } - - // check if it is there on L&F - let tickets = LostAndFound.borrowAllTicketsByType(addr: self.addr, type: Type<@NameVoucher.NFT>()) - for ticket in tickets { - if ticket.uuid == id { - let tokenId = ticket.getNonFungibleTokenID()! - FindLostAndFoundWrapper.redeemNFT(type: Type<@NameVoucher.NFT>(), ticketID: id, receiverAddress: self.addr, collectionPublicPath: NameVoucher.CollectionPublicPath) - - self.collection.redeem(id: tokenId, name: name) - return - } - } - - panic("There is no ID or Ticket ID : ".concat(id.toString())) - } + var collection : auth(NameVoucher.Owner) &NameVoucher.Collection + let addr : Address + + prepare(account: auth(BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability) &Account) { + + var col= account.storage.borrow(from: NameVoucher.CollectionStoragePath) + if col == nil { + account.storage.save( <- NameVoucher.createEmptyCollection(nftType:Type<@NameVoucher.NFT>()), to: NameVoucher.CollectionStoragePath) + let cap = account.capabilities.storage.issue<&NameVoucher.Collection>(NameVoucher.CollectionStoragePath) + account.capabilities.publish(cap, at: NameVoucher.CollectionPublicPath) + col= account.storage.borrow(from: NameVoucher.CollectionStoragePath) + } + self.collection = col! + self.addr = account.address + } + + execute{ + // check if it is there in collection + if self.collection.contains(id) { + self.collection.redeem(id: id, name: name) + return + } + + // check if it is there on L&F + let tickets = LostAndFound.borrowAllTicketsByType(addr: self.addr, type: Type<@NameVoucher.NFT>()) + for ticket in tickets { + if ticket.uuid == id { + let tokenId = ticket.getNonFungibleTokenID()! + FindLostAndFoundWrapper.redeemNFT(type: Type<@NameVoucher.NFT>(), ticketID: id, receiverAddress: self.addr, collectionPublicPath: NameVoucher.CollectionPublicPath) + + self.collection.redeem(id: tokenId, name: name) + return + } + } + + panic("There is no ID or Ticket ID : ".concat(id.toString())) + } } diff --git a/transactions/register.cdc b/transactions/register.cdc index 289ff79c..dffae69e 100644 --- a/transactions/register.cdc +++ b/transactions/register.cdc @@ -1,28 +1,123 @@ -import FUSD from "../contracts/standard/FUSD.cdc" -import FIND from "../contracts/FIND.cdc" +import "FlowToken" +import "FIND" +import "FungibleToken" +import "NonFungibleToken" +import "MetadataViews" +import "FindPack" +import "Profile" +import "FindMarket" +import "FindMarketDirectOfferEscrow" +import "FindLeaseMarketDirectOfferSoft" +import "FindLeaseMarket" +import "Dandy" -transaction(name: String, amount: UFix64) { - let vaultRef : &FUSD.Vault? - let leases : &FIND.LeaseCollection? - let price : UFix64 +transaction(name: String, maxAmount: UFix64) { - prepare(account: AuthAccount) { + let vaultRef : auth(FungibleToken.Withdraw) &FlowToken.Vault? + let leases : auth(FIND.LeaseOwner) &FIND.LeaseCollection? + let cost : UFix64 - self.price=FIND.calculateCost(name) - log("The cost for registering this name is ".concat(self.price.toString())) - self.vaultRef = account.borrow<&FUSD.Vault>(from: /storage/fusdVault) - self.leases=account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) - } + prepare(account: auth(BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability) &Account) { - pre{ - self.vaultRef != nil : "Could not borrow reference to the fusdVault!" - self.leases != nil : "Could not borrow reference to find lease collection" - self.price == amount : "Calculated cost : ".concat(self.price.toString()).concat(" does not match expected cost : ").concat(amount.toString()) - } + //the code below has some dead code for this specific transaction, but it is hard to maintain otherwise + //SYNC with register + let leaseCollection = account.capabilities.get<&FIND.LeaseCollection>(FIND.LeasePublicPath) + if !leaseCollection.check() { + account.storage.save(<- FIND.createEmptyLeaseCollection(), to: FIND.LeaseStoragePath) + let cap = account.capabilities.storage.issue<&FIND.LeaseCollection>(FIND.LeaseStoragePath) + account.capabilities.publish(cap, at: FIND.LeasePublicPath) + } - execute{ - let payVault <- self.vaultRef!.withdraw(amount: self.price) as! @FUSD.Vault - self.leases!.register(name: name, vault: <- payVault) - } + let dandyCap= account.capabilities.get<&{NonFungibleToken.Collection}>(Dandy.CollectionPublicPath) + if !dandyCap.check() { + account.storage.save(<- Dandy.createEmptyCollection(nftType:Type<@Dandy.NFT>()), to: Dandy.CollectionStoragePath) + let cap = account.capabilities.storage.issue<&Dandy.Collection>(Dandy.CollectionStoragePath) + account.capabilities.publish(cap, at: Dandy.CollectionPublicPath) + } + + let findPackCap= account.capabilities.get<&{NonFungibleToken.Collection}>(FindPack.CollectionPublicPath) + if !findPackCap.check() { + account.storage.save( <- FindPack.createEmptyCollection(nftType: Type<@FindPack.NFT>()), to: FindPack.CollectionStoragePath) + + let cap = account.capabilities.storage.issue<&FindPack.Collection>(FindPack.CollectionStoragePath) + account.capabilities.publish(cap, at: FindPack.CollectionPublicPath) + } + + var created=false + var updated=false + let profileCap = account.capabilities.get<&Profile.User>(Profile.publicPath) + if !profileCap.check(){ + let newProfile <-Profile.createUser(name:name, createdAt: "find") + account.storage.save(<-newProfile, to: Profile.storagePath) + + let cap = account.capabilities.storage.issue<&Profile.User>(Profile.storagePath) + account.capabilities.publish(cap, at: Profile.publicPath) + account.capabilities.publish(cap, at: Profile.publicReceiverPath) + created=true + } + + let profile=account.storage.borrow(from: Profile.storagePath)! + + if !profile.hasWallet("Flow") { + let flowWallet=Profile.Wallet( name:"Flow", receiver:account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver), balance:account.capabilities.get<&{FungibleToken.Vault}>(/public/flowTokenBalance), accept: Type<@FlowToken.Vault>(), tags: ["flow"]) + + profile.addWallet(flowWallet) + updated=true + } + if created { + profile.emitCreatedEvent() + } else if updated { + profile.emitUpdatedEvent() + } + + + let receiverCap=account.capabilities.get<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) + let tenantCapability= FindMarket.getTenantCapability(FindMarket.getFindTenantAddress())! + + let tenant = tenantCapability.borrow()! + + let doeSaleType= Type<@FindMarketDirectOfferEscrow.SaleItemCollection>() + let doeSalePublicPath=FindMarket.getPublicPath(doeSaleType, name: tenant.name) + let doeSaleStoragePath= FindMarket.getStoragePath(doeSaleType, name:tenant.name) + let doeSaleCap= account.capabilities.get<&{FindMarketDirectOfferEscrow.SaleItemCollectionPublic}>(doeSalePublicPath) + if !doeSaleCap.check() { + account.storage.save<@FindMarketDirectOfferEscrow.SaleItemCollection>(<- FindMarketDirectOfferEscrow.createEmptySaleItemCollection(tenantCapability), to: doeSaleStoragePath) + let cap = account.capabilities.storage.issue<&{FindMarketDirectOfferEscrow.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(doeSaleStoragePath) + account.capabilities.publish(cap, at: doeSalePublicPath) + } + + let leaseTenantCapability= FindMarket.getTenantCapability(FindMarket.getFindTenantAddress())! + let leaseTenant = leaseTenantCapability.borrow()! + + let leaseDOSSaleItemType= Type<@FindLeaseMarketDirectOfferSoft.SaleItemCollection>() + let leaseDOSPublicPath=leaseTenant.getPublicPath(leaseDOSSaleItemType) + let leaseDOSStoragePath= leaseTenant.getStoragePath(leaseDOSSaleItemType) + let leaseDOSSaleItemCap= account.capabilities.get<&FindLeaseMarketDirectOfferSoft.SaleItemCollection>(leaseDOSPublicPath) + if !leaseDOSSaleItemCap.check() { + //The link here has to be a capability not a tenant, because it can change. + account.storage.save<@FindLeaseMarketDirectOfferSoft.SaleItemCollection>(<- FindLeaseMarketDirectOfferSoft.createEmptySaleItemCollection(leaseTenantCapability), to: leaseDOSStoragePath) + let leaseDOSSaleItemCap = account.capabilities.storage.issue<&FindLeaseMarketDirectOfferSoft.SaleItemCollection>(leaseDOSStoragePath) + account.capabilities.publish(leaseDOSSaleItemCap, at: leaseDOSPublicPath) + } + + self.vaultRef = account.storage.borrow(from: /storage/flowTokenVault) + self.leases=account.storage.borrow(from: FIND.LeaseStoragePath) + + self.cost = FIND.calculateCostInFlow(name) + + } + + + pre{ + self.cost <= maxAmount : "You have not sent in enough max flow, the cost is ".concat(self.cost.toString()) + self.vaultRef != nil : "Could not borrow reference to the fusdVault!" + self.leases != nil : "Could not borrow reference to find lease collection" + self.vaultRef!.balance > self.cost : "Balance of vault is not high enough ".concat(self.cost.toString()).concat(" total balance is ").concat(self.vaultRef!.balance.toString()) + } + + execute{ + let payVault <- self.vaultRef!.withdraw(amount: self.cost) as! @FlowToken.Vault + self.leases!.register(name: name, vault: <- payVault) + } } diff --git a/transactions/registerFindPackMetadata.cdc b/transactions/registerFindPackMetadata.cdc index 78b6e825..bca5ca1e 100644 --- a/transactions/registerFindPackMetadata.cdc +++ b/transactions/registerFindPackMetadata.cdc @@ -1,12 +1,12 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FindPack from "../contracts/FindPack.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FindVerifier from "../contracts/FindVerifier.cdc" -import FindForge from "../contracts/FindForge.cdc" -import FIND from "../contracts/FIND.cdc" +import "NonFungibleToken" +import "MetadataViews" +import "FINDNFTCatalog" +import "FungibleToken" +import "FindPack" +import "FlowToken" +import "FindVerifier" +import "FindForge" +import "FIND" // this is a simple tx to update the metadata of a given type of NeoVoucher @@ -14,11 +14,11 @@ transaction(forge: String, name: String, description:String, typeId: UInt64, ext let lease: &FIND.Lease let wallet: Capability<&{FungibleToken.Receiver}> - let providerCaps : {Type : Capability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}>} + let providerCaps : {Type : Capability<&{NonFungibleToken.Provider, ViewResolver.ResolverCollection}>} let types : [Type] - prepare(account: AuthAccount) { - let leaseCol =account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) ?? panic("Could not borrow leases collection") + prepare(account: auth(BorrowValue) &Account) { + let leaseCol =account.storage.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) ?? panic("Could not borrow leases collection") self.lease = leaseCol.borrow(forge) self.wallet = getAccount(wallet).getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) @@ -31,7 +31,7 @@ transaction(forge: String, name: String, description:String, typeId: UInt64, ext panic("Type : ".concat(typeName).concat(" is not supported in NFTCatalog at the moment")) } let collectionInfo = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collection!.keys[0])!.collectionData - let providerCap= account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}>(collectionInfo.privatePath) + let providerCap= account.getCapability<&{NonFungibleToken.Provider, ViewResolver.ResolverCollection}>(collectionInfo.privatePath) let type = CompositeType(typeName)! self.types.append(type) self.providerCaps[type] = providerCap diff --git a/transactions/registerFindPackMetadataStruct.cdc b/transactions/registerFindPackMetadataStruct.cdc index f4febcf3..5f532a01 100644 --- a/transactions/registerFindPackMetadataStruct.cdc +++ b/transactions/registerFindPackMetadataStruct.cdc @@ -1,12 +1,12 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FindPack from "../contracts/FindPack.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FindVerifier from "../contracts/FindVerifier.cdc" -import FindForge from "../contracts/FindForge.cdc" -import FIND from "../contracts/FIND.cdc" +import "NonFungibleToken" +import "MetadataViews" +import "FINDNFTCatalog" +import "FungibleToken" +import "FindPack" +import "FlowToken" +import "FindVerifier" +import "FindForge" +import "FIND" // this is a simple tx to update the metadata of a given type of NeoVoucher @@ -14,11 +14,11 @@ transaction(info: FindPack.PackRegisterInfo) { let lease: &FIND.Lease let wallet: Capability<&{FungibleToken.Receiver}> - let providerCaps : {Type : Capability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}>} + let providerCaps : {Type : Capability<&{NonFungibleToken.Provider, ViewResolver.ResolverCollection}>} let types : [Type] - prepare(account: AuthAccount) { - let leaseCol =account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) ?? panic("Could not borrow leases collection") + prepare(account: auth(BorrowValue) &Account) { + let leaseCol =account.storage.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) ?? panic("Could not borrow leases collection") self.lease = leaseCol.borrow(info.forge) self.wallet = getAccount(info.paymentAddress).getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) @@ -31,7 +31,7 @@ transaction(info: FindPack.PackRegisterInfo) { panic("Type : ".concat(typeName).concat(" is not supported in NFTCatalog at the moment")) } let collectionInfo = FINDNFTCatalog.getCatalogEntry(collectionIdentifier : collection!.keys[0])!.collectionData - let providerCap= account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection}>(collectionInfo.privatePath) + let providerCap= account.getCapability<&{NonFungibleToken.Provider, ViewResolver.ResolverCollection}>(collectionInfo.privatePath) let type = CompositeType(typeName)! self.types.append(type) self.providerCaps[type] = providerCap diff --git a/transactions/registerGift.cdc b/transactions/registerGift.cdc deleted file mode 100644 index 0913f51b..00000000 --- a/transactions/registerGift.cdc +++ /dev/null @@ -1,45 +0,0 @@ -import FUSD from "../contracts/standard/FUSD.cdc" -import Profile from "../contracts/Profile.cdc" -import FIND from "../contracts/FIND.cdc" - -transaction(name: String, amount: UFix64, recipient: String) { - - let price : UFix64 - let vaultRef : &FUSD.Vault? - let receiverLease : Capability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}> - let receiverProfile : Capability<&{Profile.Public}> - let leases : &FIND.LeaseCollection? - - prepare(acct: AuthAccount) { - - let resolveAddress = FIND.resolve(recipient) - if resolveAddress == nil {panic("The input pass in is not a valid name or address. Input : ".concat(recipient))} - let address = resolveAddress! - - self.price=FIND.calculateCost(name) - log("The cost for registering this name is ".concat(self.price.toString())) - - self.vaultRef = acct.borrow<&FUSD.Vault>(from: /storage/fusdVault) - - self.leases=acct.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) - - let receiver = getAccount(address) - self.receiverLease = receiver.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - self.receiverProfile = receiver.getCapability<&{Profile.Public}>(Profile.publicPath) - - } - - pre{ - self.price == amount : "Calculated cost : ".concat(self.price.toString()).concat(" does not match expected cost").concat(amount.toString()) - self.vaultRef != nil : "Cannot borrow reference to fusd Vault!" - self.receiverLease.check() : "Lease capability is invalid" - self.receiverProfile.check() : "Profile capability is invalid" - self.leases != nil : "Cannot borrow refernce to find lease collection" - } - - execute{ - let payVault <- self.vaultRef!.withdraw(amount: self.price) as! @FUSD.Vault - self.leases!.register(name: name, vault: <- payVault) - self.leases!.move(name: name, profile: self.receiverProfile, to: self.receiverLease) - } -} diff --git a/transactions/registerUSDC.cdc b/transactions/registerUSDC.cdc deleted file mode 100644 index 3ecab9eb..00000000 --- a/transactions/registerUSDC.cdc +++ /dev/null @@ -1,28 +0,0 @@ -import FiatToken from "../contracts/standard/FiatToken.cdc" -import FIND from "../contracts/FIND.cdc" - -transaction(name: String, amount: UFix64) { - - let vaultRef : &FiatToken.Vault? - let leases : &FIND.LeaseCollection? - let price : UFix64 - - prepare(account: AuthAccount) { - - self.price=FIND.calculateCost(name) - log("The cost for registering this name is ".concat(self.price.toString())) - self.vaultRef = account.borrow<&FiatToken.Vault>(from: FiatToken.VaultStoragePath) - self.leases=account.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) - } - - pre{ - self.vaultRef != nil : "Could not borrow reference to the USDC Vault!" - self.leases != nil : "Could not borrow reference to find lease collection" - self.price == amount : "Calculated cost : ".concat(self.price.toString()).concat(" does not match expected cost : ").concat(amount.toString()) - } - - execute{ - let payVault <- self.vaultRef!.withdraw(amount: self.price) as! @FiatToken.Vault - self.leases!.registerUSDC(name: name, vault: <- payVault) - } -} diff --git a/transactions/rejectNameDirectOffer.cdc b/transactions/rejectNameDirectOffer.cdc index ccef3631..2b7e02b7 100644 --- a/transactions/rejectNameDirectOffer.cdc +++ b/transactions/rejectNameDirectOffer.cdc @@ -1,11 +1,11 @@ -import FIND from "../contracts/FIND.cdc" +import "FIND" transaction(names: [String]) { - let finLeases : &FIND.LeaseCollection? + let finLeases : auth(FIND.AuctionOwner, FIND.LeaseOwner) &FIND.LeaseCollection? - prepare(account: AuthAccount) { - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) + prepare(account: auth(BorrowValue) &Account) { + self.finLeases= account.storage.borrow(from:FIND.LeaseStoragePath) } pre{ diff --git a/transactions/relistMarketListings.cdc b/transactions/relistMarketListings.cdc index c0a887e4..95e1d91b 100644 --- a/transactions/relistMarketListings.cdc +++ b/transactions/relistMarketListings.cdc @@ -1,39 +1,41 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketDirectOfferEscrow from "../contracts/FindMarketDirectOfferEscrow.cdc" -import FindMarketAuctionEscrow from "../contracts/FindMarketAuctionEscrow.cdc" -import FindMarketAuctionSoft from "../contracts/FindMarketAuctionSoft.cdc" -import FindMarketDirectOfferSoft from "../contracts/FindMarketDirectOfferSoft.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" +import "FindMarket" +//import "FindMarketDirectOfferEscrow" +//import "FindMarketAuctionEscrow" +//import "FindMarketAuctionSoft" +//import "FindMarketDirectOfferSoft" +import "FindMarketSale" transaction(ids: {String : [UInt64]}) { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - let marketplace = FindMarket.getFindTenantAddress() - let tenant=FindMarket.getTenant(marketplace) + let marketplace = FindMarket.getFindTenantAddress() + let tenant=FindMarket.getTenant(marketplace) - var saleType = Type<@FindMarketAuctionEscrow.SaleItemCollection>() - if let ids = ids[FindMarket.getMarketOptionFromType(saleType)] { - let saleItems= account.borrow<&FindMarketAuctionEscrow.SaleItemCollection>(from: tenant.getStoragePath(saleType))! - for id in ids { - saleItems.relist(id) - } - } + /* + var saleType = Type<@FindMarketAuctionEscrow.SaleItemCollection>() + if let ids = ids[FindMarket.getMarketOptionFromType(saleType)] { + let saleItems= account.storage.borrow<&FindMarketAuctionEscrow.SaleItemCollection>(from: tenant.getStoragePath(saleType))! + for id in ids { + saleItems.relist(id) + } + } - saleType = Type<@FindMarketAuctionSoft.SaleItemCollection>() - if let ids = ids[FindMarket.getMarketOptionFromType(saleType)] { - let saleItems= account.borrow<&FindMarketAuctionSoft.SaleItemCollection>(from: tenant.getStoragePath(saleType))! - for id in ids { - saleItems.relist(id) - } - } + saleType = Type<@FindMarketAuctionSoft.SaleItemCollection>() + if let ids = ids[FindMarket.getMarketOptionFromType(saleType)] { + let saleItems= account.storage.borrow<&FindMarketAuctionSoft.SaleItemCollection>(from: tenant.getStoragePath(saleType))! + for id in ids { + saleItems.relist(id) + } + } + */ - saleType = Type<@FindMarketSale.SaleItemCollection>() - if let ids = ids[FindMarket.getMarketOptionFromType(saleType)] { - let saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(saleType))! - for id in ids { - saleItems.relist(id) - } - } + var saleType = Type<@FindMarketSale.SaleItemCollection>() + if let ids = ids[FindMarket.getMarketOptionFromType(saleType)] { + let saleItems= account.storage.borrow(from: tenant.getStoragePath(saleType))! + for id in ids { + saleItems.relist(id) + } + } - } + } } diff --git a/transactions/removeCurratedCollection.cdc b/transactions/removeCurratedCollection.cdc index fcbf3b6a..8bb49d68 100644 --- a/transactions/removeCurratedCollection.cdc +++ b/transactions/removeCurratedCollection.cdc @@ -1,19 +1,20 @@ transaction(name: String) { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - let path=/storage/FindCuratedCollections - let publicPath=/public/FindCuratedCollections + let path=/storage/FindCuratedCollections + let publicPath=/public/FindCuratedCollections - var collections : {String: [String]} = {} - if account.borrow<&{String: [String]}>(from:path) != nil { - collections=account.load<{String: [String]}>(from:path)! - } - collections.remove(key: name) - account.save(collections, to: path) - let link = account.getCapability<&{String: [String]}>(publicPath) - if !link.check() { - account.link<&{String: [String]}>( publicPath, target: path) - } - } + var collections : {String: [String]} = {} + if account.storage.borrow<&{String: [String]}>(from:path) != nil { + collections=account.storage.load<{String: [String]}>(from:path)! + } + collections.remove(key: name) + account.storage.save(collections, to: path) + let link = account.capabilities.get<&{String: [String]}>(publicPath) + if !link.check() { + let newCap = account.capabilities.storage.issue<&{String: [String]}>(path) + account.capabilities.publish(newCap, at: publicPath) + } + } } diff --git a/transactions/removeMarketOption.cdc b/transactions/removeMarketOption.cdc index d76a35c2..8f237acf 100644 --- a/transactions/removeMarketOption.cdc +++ b/transactions/removeMarketOption.cdc @@ -1,10 +1,10 @@ -import FindMarket from "../contracts/FindMarket.cdc" +import "FindMarket" transaction(saleItemName: String){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ let path = FindMarket.TenantClientStoragePath - let tenantRef = account.borrow<&FindMarket.TenantClient>(from: path) ?? panic("Cannot borrow Reference.") + let tenantRef = account.storage.borrow(from: path) ?? panic("Cannot borrow Reference.") tenantRef.removeMarketOption(name: saleItemName) } diff --git a/transactions/removeRelatedAccount.cdc b/transactions/removeRelatedAccount.cdc index 86483b1d..748d1903 100644 --- a/transactions/removeRelatedAccount.cdc +++ b/transactions/removeRelatedAccount.cdc @@ -1,28 +1,31 @@ -import FindRelatedAccounts from "../contracts/FindRelatedAccounts.cdc" +import "FindRelatedAccounts" transaction(name: String, network: String, address: String) { - var relatedAccounts : &FindRelatedAccounts.Accounts? + var relatedAccounts : auth(FindRelatedAccounts.Owner) &FindRelatedAccounts.Accounts? - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue, SaveValue, IssueStorageCapabilityController, UnpublishCapability, PublishCapability) &Account) { - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - if self.relatedAccounts == nil { - let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts = account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - } + self.relatedAccounts= account.storage.borrow(from:FindRelatedAccounts.storagePath) + if self.relatedAccounts == nil { + let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() + account.storage.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) - if !cap.check() { - account.unlink(FindRelatedAccounts.publicPath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - } - } + let cap = account.capabilities.storage.issue<&{FindRelatedAccounts.Public}>(FindRelatedAccounts.storagePath) + account.capabilities.publish(cap, at: FindRelatedAccounts.publicPath) + self.relatedAccounts = account.storage.borrow(from:FindRelatedAccounts.storagePath) + } - execute { - self.relatedAccounts!.removeRelatedAccount(name:name, network:network, address: address) - } + let cap = account.capabilities.get<&{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) + if !cap.check() { + account.capabilities.unpublish(FindRelatedAccounts.publicPath) + let cap = account.capabilities.storage.issue<&{FindRelatedAccounts.Public}>(FindRelatedAccounts.storagePath) + account.capabilities.publish(cap, at: FindRelatedAccounts.publicPath) + } + } + + execute { + self.relatedAccounts!.removeRelatedAccount(name:name, network:network, address: address) + } } diff --git a/transactions/removeRelatedAccountDapper.cdc b/transactions/removeRelatedAccountDapper.cdc index 38b5abce..b8456cfc 100644 --- a/transactions/removeRelatedAccountDapper.cdc +++ b/transactions/removeRelatedAccountDapper.cdc @@ -1,17 +1,17 @@ -import FindRelatedAccounts from "../contracts/FindRelatedAccounts.cdc" +import "FindRelatedAccounts" transaction(name: String, network: String, address: String){ - var relatedAccounts : &FindRelatedAccounts.Accounts? + var relatedAccounts : auth(FindRelatedAccounts.Owner) &FindRelatedAccounts.Accounts? - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) + self.relatedAccounts= account.storage.borrow(from:FindRelatedAccounts.storagePath) if self.relatedAccounts == nil { let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) + account.storage.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) + self.relatedAccounts= account.storage.borrow(from:FindRelatedAccounts.storagePath) } let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) diff --git a/transactions/removeTenantRule.cdc b/transactions/removeTenantRule.cdc index e0417c3e..35b22617 100644 --- a/transactions/removeTenantRule.cdc +++ b/transactions/removeTenantRule.cdc @@ -1,9 +1,9 @@ -import FindMarket from "../contracts/FindMarket.cdc" +import "FindMarket" transaction(optionName: String, tenantRuleName: String){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ let path = FindMarket.TenantClientStoragePath - let tenantRef = account.borrow<&FindMarket.TenantClient>(from: path) ?? panic("Cannot borrow Reference.") + let tenantRef = account.storage.borrow(from: path) ?? panic("Cannot borrow Reference.") tenantRef.removeTenantRule(optionName: optionName, tenantRuleName: tenantRuleName) } diff --git a/transactions/remove_find_market_1.cdc b/transactions/remove_find_market_1.cdc index bd3ba5df..73dba67a 100644 --- a/transactions/remove_find_market_1.cdc +++ b/transactions/remove_find_market_1.cdc @@ -1,10 +1,10 @@ -import FindMarketAdmin from "../contracts/FindMarketAdmin.cdc" +import "FindMarketAdmin" //signed by admin to link tenantClient to a new tenant transaction(tenant: Address) { //versus account - prepare(account: AuthAccount) { - let adminClient=account.borrow<&FindMarketAdmin.AdminProxy>(from: FindMarketAdmin.AdminProxyStoragePath)! + prepare(account: auth(BorrowValue) &Account) { + let adminClient=account.storage.borrow(from: FindMarketAdmin.AdminProxyStoragePath)! adminClient.removeFindMarketTenant(tenant: tenant) } diff --git a/transactions/remove_find_market_2.cdc b/transactions/remove_find_market_2.cdc index 7bd4d65d..80599a89 100644 --- a/transactions/remove_find_market_2.cdc +++ b/transactions/remove_find_market_2.cdc @@ -1,9 +1,9 @@ -import FindMarket from "../contracts/FindMarket.cdc" +import "FindMarket" //Transaction that is signed by find to create a find market tenant for find transaction() { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { //in finds case the destroy account.load<@FindMarket.TenantClient>(from:FindMarket.TenantClientStoragePath) account.unlink(FindMarket.TenantClientPublicPath) diff --git a/transactions/renewName.cdc b/transactions/renewName.cdc index 63484b2b..3ea97cff 100644 --- a/transactions/renewName.cdc +++ b/transactions/renewName.cdc @@ -1,27 +1,30 @@ -import FUSD from "../contracts/standard/FUSD.cdc" -import FIND from "../contracts/FIND.cdc" +import "FlowToken" +import "FungibleToken" +import "FIND" -transaction(name: String, amount: UFix64) { +transaction(name: String, maxAmount: UFix64) { - let price : UFix64 - let vaultRef : &FUSD.Vault? - let finLeases : &FIND.LeaseCollection? + let cost : UFix64 + let vaultRef : auth (FungibleToken.Withdraw) &FlowToken.Vault? + let finLeases : auth(FIND.LeaseOwner) &FIND.LeaseCollection? - prepare(acct: AuthAccount) { - self.price=FIND.calculateCost(name) - self.vaultRef = acct.borrow<&FUSD.Vault>(from: /storage/fusdVault) - self.finLeases= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) - } + prepare(acct: auth(BorrowValue) &Account) { + self.cost=FIND.calculateCostInFlow(name) + self.vaultRef = acct.storage.borrow(from: /storage/flowTokenVault) + self.finLeases= acct.storage.borrow(from:FIND.LeaseStoragePath) + } - pre{ - self.price == amount : "expected renew cost : ".concat(self.price.toString()).concat(" is not the same as calculated renew cost : ").concat(amount.toString()) - self.vaultRef != nil : "Could not borrow reference to the fusdVault!" - self.finLeases != nil : "Could not borrow reference to find lease collection" - } - execute{ - let payVault <- self.vaultRef!.withdraw(amount: self.price) as! @FUSD.Vault - let finToken= self.finLeases!.borrow(name) - finToken.extendLease(<- payVault) - } + pre{ + self.vaultRef != nil : "Could not borrow reference to the fusdVault!" + self.finLeases != nil : "Could not borrow reference to find lease collection" + self.cost <= maxAmount : "You have not sent in enough max flow, the cost is ".concat(self.cost.toString()) + self.vaultRef!.balance > self.cost : "Balance of vault is not high enough ".concat(self.vaultRef!.balance.toString().concat(" total balance is ").concat(self.vaultRef!.balance.toString())) + } + + execute{ + let payVault <- self.vaultRef!.withdraw(amount: self.cost) as! @FlowToken.Vault + let finToken= self.finLeases!.borrowAuth(name) + finToken.extendLease(<- payVault) + } } diff --git a/transactions/retractOfferLeaseMarketDirectOfferSoft.cdc b/transactions/retractOfferLeaseMarketDirectOfferSoft.cdc index f047a5e0..7061db7f 100644 --- a/transactions/retractOfferLeaseMarketDirectOfferSoft.cdc +++ b/transactions/retractOfferLeaseMarketDirectOfferSoft.cdc @@ -1,14 +1,14 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindLeaseMarketDirectOfferSoft from "../contracts/FindLeaseMarketDirectOfferSoft.cdc" +import "FindMarket" +import "FindLeaseMarketDirectOfferSoft" transaction(leaseName: String) { - let bidsReference: &FindLeaseMarketDirectOfferSoft.MarketBidCollection? + let bidsReference: auth(FindLeaseMarketDirectOfferSoft.Buyer) &FindLeaseMarketDirectOfferSoft.MarketBidCollection? - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { let marketplace = FindMarket.getFindTenantAddress() let tenant=FindMarket.getTenant(marketplace) let storagePath=tenant.getStoragePath(Type<@FindLeaseMarketDirectOfferSoft.MarketBidCollection>()) - self.bidsReference= account.borrow<&FindLeaseMarketDirectOfferSoft.MarketBidCollection>(from: storagePath) + self.bidsReference= account.storage.borrow(from: storagePath) } pre{ diff --git a/transactions/retractOfferMarketDirectOfferEscrowed.cdc b/transactions/retractOfferMarketDirectOfferEscrowed.cdc index 51ef0f16..47c0fb3d 100644 --- a/transactions/retractOfferMarketDirectOfferEscrowed.cdc +++ b/transactions/retractOfferMarketDirectOfferEscrowed.cdc @@ -1,14 +1,14 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketDirectOfferEscrow from "../contracts/FindMarketDirectOfferEscrow.cdc" +import "FindMarket" +import "FindMarketDirectOfferEscrow" transaction(id: UInt64) { - let bidsReference: &FindMarketDirectOfferEscrow.MarketBidCollection? + let bidsReference: auth(FindMarketDirectOfferEscrow.Buyer) &FindMarketDirectOfferEscrow.MarketBidCollection? - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { let marketplace = FindMarket.getFindTenantAddress() let tenant=FindMarket.getTenant(marketplace) let storagePath=tenant.getStoragePath(Type<@FindMarketDirectOfferEscrow.MarketBidCollection>()) - self.bidsReference= account.borrow<&FindMarketDirectOfferEscrow.MarketBidCollection>(from: storagePath) + self.bidsReference= account.storage.borrow(from: storagePath) } pre{ diff --git a/transactions/retractOfferMarketDirectOfferSoft.cdc b/transactions/retractOfferMarketDirectOfferSoft.cdc index 377e9258..ea458607 100644 --- a/transactions/retractOfferMarketDirectOfferSoft.cdc +++ b/transactions/retractOfferMarketDirectOfferSoft.cdc @@ -1,14 +1,14 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketDirectOfferSoft from "../contracts/FindMarketDirectOfferSoft.cdc" +import "FindMarket" +import "FindMarketDirectOfferSoft" transaction(id: UInt64) { - let bidsReference: &FindMarketDirectOfferSoft.MarketBidCollection? + let bidsReference: auth(FindMarketDirectOfferSoft.Buyer) &FindMarketDirectOfferSoft.MarketBidCollection? - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { let marketplace = FindMarket.getFindTenantAddress() let tenant=FindMarket.getTenant(marketplace) let storagePath=tenant.getStoragePath(Type<@FindMarketDirectOfferSoft.MarketBidCollection>()) - self.bidsReference= account.borrow<&FindMarketDirectOfferSoft.MarketBidCollection>(from: storagePath) + self.bidsReference= account.storage.borrow(from: storagePath) } pre{ diff --git a/transactions/sendCharity.cdc b/transactions/sendCharity.cdc index fbd6c7f1..5e53069a 100644 --- a/transactions/sendCharity.cdc +++ b/transactions/sendCharity.cdc @@ -1,17 +1,17 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import CharityNFT from "../contracts/CharityNFT.cdc" +import "NonFungibleToken" +import "CharityNFT" //mint an art and add it to a users collection transaction( id: UInt64, recipient: Address ) { - let receiverCap: Capability<&{NonFungibleToken.CollectionPublic}> + let receiverCap: Capability<&{NonFungibleToken.Collection}> let charityCollection: &NonFungibleToken.Collection - prepare(account: AuthAccount) { - self.charityCollection =account.borrow<&NonFungibleToken.Collection>(from: CharityNFT.CollectionStoragePath)! - self.receiverCap= getAccount(recipient).getCapability<&{NonFungibleToken.CollectionPublic}>(CharityNFT.CollectionPublicPath) + prepare(account: auth(BorrowValue) &Account) { + self.charityCollection =account.storage.borrow<&NonFungibleToken.Collection>(from: CharityNFT.CollectionStoragePath)! + self.receiverCap= getAccount(recipient).getCapability<&{NonFungibleToken.Collection}>(CharityNFT.CollectionPublicPath) } pre{ diff --git a/transactions/sendDandy.cdc b/transactions/sendDandy.cdc index f8446497..f3fc04ef 100644 --- a/transactions/sendDandy.cdc +++ b/transactions/sendDandy.cdc @@ -1,26 +1,42 @@ -import FIND from "../contracts/FIND.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import Dandy from "../contracts/Dandy.cdc" +import "FIND" +import "NonFungibleToken" +import "Dandy" transaction(user: String, id: UInt64) { - let address : Address - let cap : Capability<&Dandy.Collection{NonFungibleToken.CollectionPublic}> - let senderRef : &Dandy.Collection + let address : Address + let cap : Capability<&{NonFungibleToken.Collection}> + let senderRef : auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection} - prepare(account: AuthAccount) { - self.address = FIND.resolve(user) ?? panic("Cannot find user with this name / address") - self.cap = getAccount(self.address).getCapability<&Dandy.Collection{NonFungibleToken.CollectionPublic}>(Dandy.CollectionPublicPath) + prepare(account: auth(Storage, NonFungibleToken.Withdraw, IssueStorageCapabilityController) &Account) { + self.address = FIND.resolve(user) ?? panic("Cannot find user with this name / address") + self.cap = getAccount(self.address).capabilities.get<&{NonFungibleToken.Collection}>(Dandy.CollectionPublicPath)! - self.senderRef = account.borrow<&Dandy.Collection>(from: Dandy.CollectionStoragePath) ?? panic("Cannot borrow reference to sender Collection.") - } - pre{ - self.cap.check() : "Cannot borrow reference to receiver Collection. Receiver account : ".concat(self.address.toString()) - self.senderRef != nil : "Cannot borrow reference to sender Collection." - } + let storagePathIdentifer = Dandy.CollectionStoragePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! - execute{ - self.cap.borrow()!.deposit(token: <- self.senderRef!.withdraw(withdrawID: id)) - } + //if this stores anything but this it will panic, why does it not return nil? + let existingProvider= account.storage.copy>(from: providerStoragePath) + if existingProvider==nil { + let provider=account.capabilities.storage.issue(Dandy.CollectionStoragePath) + //we save it to storage to memoize it + account.storage.save(provider, to: providerStoragePath) + log("create new cap") + self.senderRef=provider.borrow()! + }else { + self.senderRef= existingProvider!.borrow()! + log("existing") + } + } + + pre{ + self.cap.check() : "Cannot borrow reference to receiver Collection. Receiver account : ".concat(self.address.toString()) + self.senderRef != nil : "Cannot borrow reference to sender Collection." + } + + execute{ + self.cap.borrow()!.deposit(token: <- self.senderRef.withdraw(withdrawID: id)) + } } diff --git a/transactions/sendExampleNFT.cdc b/transactions/sendExampleNFT.cdc index 7613513b..3cbeaae4 100644 --- a/transactions/sendExampleNFT.cdc +++ b/transactions/sendExampleNFT.cdc @@ -1,17 +1,17 @@ -import FIND from "../contracts/FIND.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import ExampleNFT from "../contracts/standard/ExampleNFT.cdc" +import "FIND" +import "NonFungibleToken" +import "ExampleNFT" transaction(user: String, id: UInt64) { let address : Address - let cap : Capability<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic}> + let cap : Capability<&ExampleNFT.Collection{NonFungibleToken.Collection}> let senderRef : &ExampleNFT.Collection - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { self.address = FIND.resolve(user) ?? panic("Cannot find user with this name / address") - self.cap = getAccount(self.address).getCapability<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) + self.cap = getAccount(self.address).getCapability<&ExampleNFT.Collection{NonFungibleToken.Collection}>(ExampleNFT.CollectionPublicPath) - self.senderRef = account.borrow<&ExampleNFT.Collection>(from: ExampleNFT.CollectionStoragePath) ?? panic("Cannot borrow reference to sender Collection.") + self.senderRef = account.storage.borrow<&ExampleNFT.Collection>(from: ExampleNFT.CollectionStoragePath) ?? panic("Cannot borrow reference to sender Collection.") } pre{ diff --git a/transactions/sendFT.cdc b/transactions/sendFT.cdc index a672441c..45f7f1db 100644 --- a/transactions/sendFT.cdc +++ b/transactions/sendFT.cdc @@ -1,34 +1,32 @@ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import Sender from "../contracts/Sender.cdc" -import FIND from "../contracts/FIND.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" +import "FungibleToken" +import "Sender" +import "FIND" +import "FTRegistry" transaction(name: String, amount: UFix64, ftAliasOrIdentifier: String, tag: String, message:String) { - var token : &Sender.Token - let walletReference : &FungibleToken.Vault? + var token : &Sender.Token + let walletReference : auth(FungibleToken.Withdraw) &{FungibleToken.Vault}? - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue, SaveValue) &Account) { - let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - self.walletReference = account.borrow<&FungibleToken.Vault>(from: ft.vaultPath) + let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) + self.walletReference = account.storage.borrow(from: ft.vaultPath) - if account.borrow<&Sender.Token>(from: Sender.storagePath) == nil { - account.save(<- Sender.create(), to: Sender.storagePath) - } + if account.storage.borrow<&Sender.Token>(from: Sender.storagePath) == nil { + account.storage.save(<- Sender.createToken(), to: Sender.storagePath) + } - self.token =account.borrow<&Sender.Token>(from: Sender.storagePath)! - } + self.token =account.storage.borrow<&Sender.Token>(from: Sender.storagePath)! + } - pre{ - self.walletReference != nil : "No suitable wallet linked for this account" - } + pre{ + self.walletReference != nil : "No suitable wallet linked for this account" + } - execute{ - let vault <- self.walletReference!.withdraw(amount: amount) - FIND.depositWithTagAndMessage(to: name, message: message, tag: tag, vault: <- vault, from: self.token) - } + execute{ + let vault <- self.walletReference!.withdraw(amount: amount) + FIND.depositWithTagAndMessage(to: name, message: message, tag: tag, vault: <- vault, from: self.token) + } } - - \ No newline at end of file diff --git a/transactions/sendFTWithTag.cdc b/transactions/sendFTWithTag.cdc deleted file mode 100644 index 8c753ca1..00000000 --- a/transactions/sendFTWithTag.cdc +++ /dev/null @@ -1,94 +0,0 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import Profile from "../contracts/Profile.cdc" -import Sender from "../contracts/Sender.cdc" -import FIND from "../contracts/FIND.cdc" -import CharityNFT from "../contracts/CharityNFT.cdc" - - -transaction(name: String, amount: UFix64, type: String, tag:String) { - - prepare(account: AuthAccount) { - - let stdCap= account.getCapability<&{NonFungibleToken.CollectionPublic}>(CharityNFT.CollectionPublicPath) - if !stdCap.check() { - account.save<@NonFungibleToken.Collection>(<- CharityNFT.createEmptyCollection(), to: CharityNFT.CollectionStoragePath) - account.link<&{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>(CharityNFT.CollectionPublicPath, target: CharityNFT.CollectionStoragePath) - } - - let charityCap = account.getCapability<&{CharityNFT.CollectionPublic}>(/public/findCharityNFTCollection) - if !charityCap.check() { - account.link<&{CharityNFT.CollectionPublic, MetadataViews.ResolverCollection}>(/public/findCharityNFTCollection, target: CharityNFT.CollectionStoragePath) - } - - let fusdReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/fusdReceiver) - if !fusdReceiver.check() { - let fusd <- FUSD.createEmptyVault() - account.save(<- fusd, to: /storage/fusdVault) - account.link<&FUSD.Vault{FungibleToken.Receiver}>( /public/fusdReceiver, target: /storage/fusdVault) - account.link<&FUSD.Vault{FungibleToken.Balance}>( /public/fusdBalance, target: /storage/fusdVault) - } - - let leaseCollection = account.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - if !leaseCollection.check() { - account.save(<- FIND.createEmptyLeaseCollection(), to: FIND.LeaseStoragePath) - account.link<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>( FIND.LeasePublicPath, target: FIND.LeaseStoragePath) - } - - let bidCollection = account.getCapability<&FIND.BidCollection{FIND.BidCollectionPublic}>(FIND.BidPublicPath) - if !bidCollection.check() { - account.save(<- FIND.createEmptyBidCollection(receiver: fusdReceiver, leases: leaseCollection), to: FIND.BidStoragePath) - account.link<&FIND.BidCollection{FIND.BidCollectionPublic}>( FIND.BidPublicPath, target: FIND.BidStoragePath) - } - - let profileCap = account.getCapability<&{Profile.Public}>(Profile.publicPath) - if !profileCap.check() { - let profileName = account.address.toString() - - let profile <-Profile.createUser(name:profileName, createdAt: "find") - - let fusdWallet=Profile.Wallet( name:"FUSD", receiver:fusdReceiver, balance:account.getCapability<&{FungibleToken.Balance}>(/public/fusdBalance), accept: Type<@FUSD.Vault>(), names: ["fusd", "stablecoin"]) - - profile.addWallet(fusdWallet) - - let flowWallet=Profile.Wallet( - name:"Flow", - receiver:account.getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver), - balance:account.getCapability<&{FungibleToken.Balance}>(/public/flowTokenBalance), - accept: Type<@FlowToken.Vault>(), - names: ["flow"] - ) - - profile.addWallet(flowWallet) - profile.addCollection(Profile.ResourceCollection("FINDLeases",leaseCollection, Type<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(), ["find", "leases"])) - profile.addCollection(Profile.ResourceCollection("FINDBids", bidCollection, Type<&FIND.BidCollection{FIND.BidCollectionPublic}>(), ["find", "bids"])) - - account.save(<-profile, to: Profile.storagePath) - account.link<&Profile.User{Profile.Public}>(Profile.publicPath, target: Profile.storagePath) - account.link<&{FungibleToken.Receiver}>(Profile.publicReceiverPath, target: Profile.storagePath) - } - - if account.borrow<&Sender.Token>(from: Sender.storagePath) == nil { - account.save(<- Sender.create(), to: Sender.storagePath) - } - - let token =account.borrow<&Sender.Token>(from: Sender.storagePath)! - - - if type == "fusd" { - let vaultRef = account.borrow<&FUSD.Vault>(from: /storage/fusdVault) ?? panic("Could not borrow reference to the fusdVault!") - let vault <- vaultRef.withdraw(amount: amount) - FIND.depositWithTagAndMessage(to: name, message: "", tag: tag, vault: <- vault, from: token) - return - } - - let vaultRef = account.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) ?? panic("Could not borrow reference to the fusdVault!") - let vault <- vaultRef.withdraw(amount: amount) - FIND.depositWithTagAndMessage(to: name, message: "", tag: tag, vault: <- vault, from: token) - } - -} - diff --git a/transactions/sendFindPacks.cdc b/transactions/sendFindPacks.cdc index 3f9fbec9..0af1da13 100644 --- a/transactions/sendFindPacks.cdc +++ b/transactions/sendFindPacks.cdc @@ -1,34 +1,34 @@ -import FindPack from "../contracts/FindPack.cdc" -import FIND from "../contracts/FIND.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import FindAirdropper from "../contracts/FindAirdropper.cdc" -import Admin from "../contracts/Admin.cdc" +import "FindPack" +import "FIND" +import "NonFungibleToken" +import "FindAirdropper" +import "Admin" transaction(packInfo: FindPack.AirdropInfo) { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - let pathIdentifier = "FindPack_".concat(packInfo.packTypeName).concat("_").concat(packInfo.packTypeId.toString()) + let pathIdentifier = "FindPack_".concat(packInfo.packTypeName).concat("_").concat(packInfo.packTypeId.toString()) - let pathCollection = FindPack.getPacksCollection(packTypeName: packInfo.packTypeName, packTypeId: packInfo.packTypeId) - let adminRef = account.borrow<&Admin.AdminProxy>(from: Admin.AdminProxyStoragePath) ?? panic("Cannot borrow Admin Reference.") + let pathCollection = FindPack.getPacksCollection(packTypeName: packInfo.packTypeName, packTypeId: packInfo.packTypeId) + let adminRef = account.storage.borrow(from: Admin.AdminProxyStoragePath) ?? panic("Cannot borrow Admin Reference.") - let ids = pathCollection.getIDs() - for i, user in packInfo.users { - let id = ids[i] + let ids = pathCollection.getIDs() + for i, user in packInfo.users { + let id = ids[i] - let address = FIND.resolve(user) - if address == nil { - panic("User cannot be resolved : ".concat(user)) - } + let address = FIND.resolve(user) + if address == nil { + panic("User cannot be resolved : ".concat(user)) + } - let uAccount = getAccount(address!) - let userPacks=uAccount.getCapability<&FindPack.Collection{NonFungibleToken.Receiver}>(FindPack.CollectionPublicPath).borrow() ?? panic("Could not find userPacks for ".concat(user)) - let pointer = adminRef.getAuthPointer(pathIdentifier: pathIdentifier, id: id) - let ctx : {String : String } = {"message" : packInfo.message, "tenant" : "find"} - FindAirdropper.safeAirdrop(pointer: pointer, receiver: address!, path: FindPack.CollectionPublicPath, context: ctx , deepValidation: true) - } - } + let uAccount = getAccount(address!) + let userPacks=uAccount.capabilities.borrow<&{NonFungibleToken.Receiver}>(FindPack.CollectionPublicPath) ?? panic("Could not find userPacks for ".concat(user)) + let pointer = adminRef.getAuthPointer(pathIdentifier: pathIdentifier, id: id) + let ctx : {String : String } = {"message" : packInfo.message, "tenant" : "find"} + FindAirdropper.safeAirdrop(pointer: pointer, receiver: address!, path: FindPack.CollectionPublicPath, context: ctx , deepValidation: true) + } + } } - \ No newline at end of file + diff --git a/transactions/sendNFTs.cdc b/transactions/sendNFTs.cdc index 166add0c..e0a83544 100644 --- a/transactions/sendNFTs.cdc +++ b/transactions/sendNFTs.cdc @@ -1,200 +1,187 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FlowStorageFees from "../contracts/standard/FlowStorageFees.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FIND from "../contracts/FIND.cdc" -import FindAirdropper from "../contracts/FindAirdropper.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import Profile from "../contracts/Profile.cdc" -import Sender from "../contracts/Sender.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "FlowStorageFees" +import "FlowToken" +import "MetadataViews" +import "NFTCatalog" +import "FINDNFTCatalog" +import "FindViews" +import "FIND" +import "FindAirdropper" +import "FTRegistry" +import "Profile" +import "Sender" transaction(nftIdentifiers: [String], allReceivers: [String] , ids:[UInt64], memos: [String], donationTypes: [String?], donationAmounts: [UFix64?], findDonationType: String?, findDonationAmount: UFix64?) { - let authPointers : [FindViews.AuthNFTPointer] - let paths : [PublicPath] - let flowVault : &FungibleToken.Vault - let flowTokenRepayment : Capability<&FlowToken.Vault{FungibleToken.Receiver}> + let authPointers : [FindViews.AuthNFTPointer] + let paths : [PublicPath] + let flowVault : auth(FungibleToken.Withdraw) &{FungibleToken.Vault} + let flowTokenRepayment : Capability<&FlowToken.Vault> let defaultTokenAvailableBalance : UFix64 - let royalties: [MetadataViews.Royalties?] - let totalRoyalties: [UFix64] - let vaultRefs: {String : &FungibleToken.Vault} - var token : &Sender.Token - - prepare(account : AuthAccount) { - - self.authPointers = [] - self.paths = [] - self.royalties = [] - self.totalRoyalties = [] - self.vaultRefs = {} - - - let contractData : {Type : NFTCatalog.NFTCatalogMetadata} = {} - - - for i , typeIdentifier in nftIdentifiers { - let type = CompositeType(typeIdentifier) ?? panic("Cannot refer to type with identifier : ".concat(typeIdentifier)) - - var data : NFTCatalog.NFTCatalogMetadata? = contractData[type] - if data == nil { - data = FINDNFTCatalog.getMetadataFromType(type) ?? panic("NFT Type is not supported by NFT Catalog. Type : ".concat(type.identifier)) - contractData[type] = data - } - - let path = data!.collectionData - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(path.privatePath) - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - path.privatePath, - target: path.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = path.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: path.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: ids[i]) - - if let dt = donationTypes[i] { - self.royalties.append(pointer.getRoyalty()) - self.totalRoyalties.append(pointer.getTotalRoyaltiesCut()) - - // get the vault for donation - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - - } else { - self.royalties.append(nil) - self.totalRoyalties.append(0.0) - } - - self.authPointers.append(pointer) - self.paths.append(path.publicPath) - } - - self.flowVault = account.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) ?? panic("Cannot borrow reference to sender's flow vault") - self.flowTokenRepayment = account.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let royalties: [MetadataViews.Royalties?] + let totalRoyalties: [UFix64] + let vaultRefs: {String : auth(FungibleToken.Withdraw) &{FungibleToken.Vault}} + var token : &Sender.Token + + + prepare(account: auth (Storage, StorageCapabilities, NonFungibleToken.Withdraw, IssueStorageCapabilityController, FungibleToken.Withdraw) &Account) { + + self.authPointers = [] + self.paths = [] + self.royalties = [] + self.totalRoyalties = [] + self.vaultRefs = {} + + + let contractData : {Type : NFTCatalog.NFTCatalogMetadata} = {} + + + for i , typeIdentifier in nftIdentifiers { + let type = CompositeType(typeIdentifier) ?? panic("Cannot refer to type with identifier : ".concat(typeIdentifier)) + + var data : NFTCatalog.NFTCatalogMetadata? = contractData[type] + if data == nil { + data = FINDNFTCatalog.getMetadataFromType(type) ?? panic("NFT Type is not supported by NFT Catalog. Type : ".concat(type.identifier)) + contractData[type] = data + } + + let path = data!.collectionData + + let storage = account.capabilities.storage + + let storagePathIdentifer = path.storagePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + //if this stores anything but this it will panic, why does it not return nil? + var optProviderCap= account.storage.copy>(from: providerStoragePath) + if optProviderCap==nil { + optProviderCap=account.capabilities.storage.issue(path.storagePath) + account.storage.save(optProviderCap!, to: providerStoragePath) + } + + let providerCap=optProviderCap! + let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: ids[i]) + + if let dt = donationTypes[i] { + self.royalties.append(pointer.getRoyalty()) + self.totalRoyalties.append(pointer.getTotalRoyaltiesCut()) + + // get the vault for donation + if self.vaultRefs[dt] == nil { + let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) + let ftPath = info.vaultPath + let ref = account.storage.borrow(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) + self.vaultRefs[dt] = ref + } + + } else { + self.royalties.append(nil) + self.totalRoyalties.append(0.0) + } + + self.authPointers.append(pointer) + self.paths.append(path.publicPath) + } + + self.flowVault = account.storage.borrow(from: /storage/flowTokenVault) ?? panic("Cannot borrow reference to sender's flow vault") + self.flowTokenRepayment = account.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) self.defaultTokenAvailableBalance = FlowStorageFees.defaultTokenAvailableBalance(account.address) - // get the vault for find donation - if let dt = findDonationType { - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - } + // get the vault for find donation + if let dt = findDonationType { + if self.vaultRefs[dt] == nil { + let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) + let ftPath = info.vaultPath + let ref = account.storage.borrow(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) + self.vaultRefs[dt] = ref + } + } - if account.borrow<&Sender.Token>(from: Sender.storagePath) == nil { - account.save(<- Sender.create(), to: Sender.storagePath) - } + if account.storage.borrow<&Sender.Token>(from: Sender.storagePath) == nil { + account.storage.save(<- Sender.createToken(), to: Sender.storagePath) + } - self.token =account.borrow<&Sender.Token>(from: Sender.storagePath)! + self.token =account.storage.borrow<&Sender.Token>(from: Sender.storagePath)! - } + } - execute { - let addresses : {String : Address} = {} + execute { + let addresses : {String : Address} = {} let estimatedStorageFee = 0.0002 * UFix64(self.authPointers.length) // we pass in the least amount as possible for storage fee here let tempVault <- self.flowVault.withdraw(amount: 0.0) - var vaultRef = &tempVault as &FungibleToken.Vault + var vaultRef = &tempVault as auth(FungibleToken.Withdraw) &{FungibleToken.Vault} if self.defaultTokenAvailableBalance <= estimatedStorageFee { - vaultRef = self.flowVault as &FungibleToken.Vault + vaultRef = self.flowVault } else { tempVault.deposit(from: <- self.flowVault.withdraw(amount: estimatedStorageFee)) } - let ctx : {String : String} = { - "tenant" : "find" - } - - for i, pointer in self.authPointers { - let receiver = allReceivers[i] - let id = ids[i] - ctx["message"] = memos[i] - let path = self.paths[i] - - var user = addresses[receiver] - if user == nil { - user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) - addresses[receiver] = user - } - - // airdrop thru airdropper - FindAirdropper.forcedAirdrop(pointer: pointer, receiver: user!, path: path, context: ctx, storagePayment: vaultRef, flowTokenRepayment: self.flowTokenRepayment, deepValidation: true) - } + let ctx : {String : String} = { + "tenant" : "find" + } + + for i, pointer in self.authPointers { + let receiver = allReceivers[i] + let id = ids[i] + ctx["message"] = memos[i] + let path = self.paths[i] + + var user = addresses[receiver] + if user == nil { + user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) + addresses[receiver] = user + } + + // airdrop thru airdropper + FindAirdropper.forcedAirdrop(pointer: pointer, receiver: user!, path: path, context: ctx, storagePayment: vaultRef, flowTokenRepayment: self.flowTokenRepayment, deepValidation: true) + } self.flowVault.deposit(from: <- tempVault) - // This is hard coded for spliting at the front end for now. So if there are no royalties, all goes to find - // AND This does not support different ft types for now. - var goesToFindFund = 0.0 - for i , type in donationTypes { - if type == nil { - continue - } - let amount = donationAmounts[i]! - let royalties = self.royalties[i]! - let totalRoyalties = self.totalRoyalties[i] - let vaultRef = self.vaultRefs[type!]! - var noRoyalty = false - if totalRoyalties == 0.0 { - goesToFindFund = goesToFindFund + amount - continue - } - - let balance = vaultRef.balance - var totalPaid = 0.0 - - for j, r in royalties.getRoyalties() { - var cap : Capability<&{FungibleToken.Receiver}> = r.receiver - if !r.receiver.check(){ - // try to grab from profile - if let ref = getAccount(r.receiver.address).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() { - if ref.hasWallet(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - } else if let ftInfo = FTRegistry.getFTInfo(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(ftInfo.receiverPath) - } - } - - } - - if cap.check() { - let individualAmount = r.cut / totalRoyalties * amount - let vault <- vaultRef.withdraw(amount: individualAmount) - cap.borrow()!.deposit(from: <- vault) - - totalPaid = totalPaid + individualAmount - } - } - - assert(totalPaid <= amount, message: "Amount paid is greater than expected" ) - - } - - // for donating to find - if findDonationType != nil { - vaultRef = self.vaultRefs[findDonationType!]! - let vault <- vaultRef.withdraw(amount: findDonationAmount! + goesToFindFund) - FIND.depositWithTagAndMessage(to: "find", message: "donation to .find", tag: "donation", vault: <- vault, from: self.token) - } - } + // This is hard coded for spliting at the front end for now. So if there are no royalties, all goes to find + // AND This does not support different ft types for now. + var goesToFindFund = 0.0 + for i , type in donationTypes { + if type == nil { + continue + } + let amount = donationAmounts[i]! + let royalties = self.royalties[i]! + let totalRoyalties = self.totalRoyalties[i] + let vaultRef = self.vaultRefs[type!]! + var noRoyalty = false + if totalRoyalties == 0.0 { + goesToFindFund = goesToFindFund + amount + continue + } + + let balance = vaultRef.balance + var totalPaid = 0.0 + + + for j, r in royalties.getRoyalties() { + var cap : Capability<&{FungibleToken.Receiver}>? = r.receiver + if r.receiver.check() { + let individualAmount = r.cut / totalRoyalties * amount + let vault <- vaultRef.withdraw(amount: individualAmount) + r.receiver.borrow()!.deposit(from: <- vault) + totalPaid = totalPaid + individualAmount + } + //there is no way to send over funds if this does not happen anmore + } + + assert(totalPaid <= amount, message: "Amount paid is greater than expected" ) + + } + + // for donating to find + if findDonationType != nil { + vaultRef = self.vaultRefs[findDonationType!]! + let vault <- vaultRef.withdraw(amount: findDonationAmount! + goesToFindFund) + FIND.depositWithTagAndMessage(to: "find", message: "donation to .find", tag: "donation", vault: <- vault, from: self.token) + } + } } diff --git a/transactions/sendNFTsSafe.cdc b/transactions/sendNFTsSafe.cdc index d91fab65..5e6d2cc0 100644 --- a/transactions/sendNFTsSafe.cdc +++ b/transactions/sendNFTsSafe.cdc @@ -1,181 +1,170 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FIND from "../contracts/FIND.cdc" -import FindAirdropper from "../contracts/FindAirdropper.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import Profile from "../contracts/Profile.cdc" -import Sender from "../contracts/Sender.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "MetadataViews" +import "NFTCatalog" +import "FINDNFTCatalog" +import "FindViews" +import "FIND" +import "FindAirdropper" +import "FTRegistry" +import "Profile" +import "Sender" transaction(nftIdentifiers: [String], allReceivers: [String] , ids:[UInt64], memos: [String], donationTypes: [String?], donationAmounts: [UFix64?], findDonationType: String?, findDonationAmount: UFix64?) { - let authPointers : [FindViews.AuthNFTPointer] - let paths : [PublicPath] - let royalties: [MetadataViews.Royalties?] - let totalRoyalties: [UFix64] - let vaultRefs: {String : &FungibleToken.Vault} - var token : &Sender.Token - - prepare(account : AuthAccount) { - - self.authPointers = [] - self.paths = [] - self.royalties = [] - self.totalRoyalties = [] - self.vaultRefs = {} - - let contractData : {Type : NFTCatalog.NFTCatalogMetadata} = {} - - - for i , typeIdentifier in nftIdentifiers { - let type = CompositeType(typeIdentifier) ?? panic("Cannot refer to type with identifier : ".concat(typeIdentifier)) - - var data : NFTCatalog.NFTCatalogMetadata? = contractData[type] - if data == nil { - data = FINDNFTCatalog.getMetadataFromType(type) ?? panic("NFT Type is not supported by NFT Catalog. Type : ".concat(type.identifier)) - contractData[type] = data - } - - let path = data!.collectionData - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(path.privatePath) - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - path.privatePath, - target: path.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = path.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: path.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: ids[i]) - - if let dt = donationTypes[i] { - self.royalties.append(pointer.getRoyalty()) - self.totalRoyalties.append(pointer.getTotalRoyaltiesCut()) - - // get the vault for donation - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - - } else { - self.royalties.append(nil) - self.totalRoyalties.append(0.0) - } - - - self.authPointers.append(pointer) - self.paths.append(path.publicPath) - } - - // get the vault for find donation - if let dt = findDonationType { - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - } - - if account.borrow<&Sender.Token>(from: Sender.storagePath) == nil { - account.save(<- Sender.create(), to: Sender.storagePath) - } - - self.token =account.borrow<&Sender.Token>(from: Sender.storagePath)! - - } - - execute { - let addresses : {String : Address} = {} - - let ctx : {String : String} = { - "tenant" : "find" - } - - for i, pointer in self.authPointers { - let receiver = allReceivers[i] - let id = ids[i] - ctx["message"] = memos[i] - let path = self.paths[i] - - var user = addresses[receiver] - if user == nil { - user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) - addresses[receiver] = user - } - - // airdrop thru airdropper - FindAirdropper.safeAirdrop(pointer: pointer, receiver: user!, path: path, context: ctx, deepValidation: true) - } - - - // This is hard coded for spliting at the front end for now. So if there are no royalties, all goes to find - // AND This does not support different ft types for now. - var goesToFindFund = 0.0 - for i , type in donationTypes { - if type == nil { - continue - } - let amount = donationAmounts[i]! - let royalties = self.royalties[i]! - let totalRoyalties = self.totalRoyalties[i] - let vaultRef = self.vaultRefs[type!]! - if totalRoyalties == 0.0 { - goesToFindFund = goesToFindFund + amount - continue - } - - let balance = vaultRef.balance - var totalPaid = 0.0 - - for j, r in royalties.getRoyalties() { - var cap : Capability<&{FungibleToken.Receiver}> = r.receiver - if !r.receiver.check(){ - // try to grab from profile - if let ref = getAccount(r.receiver.address).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() { - if ref.hasWallet(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - } else if let ftInfo = FTRegistry.getFTInfo(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(ftInfo.receiverPath) - } - } - - } - - if cap.check() { - let individualAmount = r.cut / totalRoyalties * amount - let vault <- vaultRef.withdraw(amount: individualAmount) - cap.borrow()!.deposit(from: <- vault) - - totalPaid = totalPaid + individualAmount - } - } - - assert(totalPaid <= amount, message: "Amount paid is greater than expected" ) - - } - - - // for donating to find - if findDonationType != nil { - let vaultRef = self.vaultRefs[findDonationType!]! - let vault <- vaultRef.withdraw(amount: findDonationAmount! + goesToFindFund) - FIND.depositWithTagAndMessage(to: "find", message: "donation to .find", tag: "donation", vault: <- vault, from: self.token) - } - } + let authPointers : [FindViews.AuthNFTPointer] + let paths : [PublicPath] + let royalties: [MetadataViews.Royalties?] + let totalRoyalties: [UFix64] + let vaultRefs: {String : auth(FungibleToken.Withdraw) &{FungibleToken.Vault}} + var token : &Sender.Token + + + prepare(account: auth (Storage, StorageCapabilities, NonFungibleToken.Withdraw, IssueStorageCapabilityController, FungibleToken.Withdraw) &Account) { + + self.authPointers = [] + self.paths = [] + self.royalties = [] + self.totalRoyalties = [] + self.vaultRefs = {} + + let contractData : {Type : NFTCatalog.NFTCatalogMetadata} = {} + + + for i , typeIdentifier in nftIdentifiers { + let type = CompositeType(typeIdentifier) ?? panic("Cannot refer to type with identifier : ".concat(typeIdentifier)) + + var data : NFTCatalog.NFTCatalogMetadata? = contractData[type] + if data == nil { + data = FINDNFTCatalog.getMetadataFromType(type) ?? panic("NFT Type is not supported by NFT Catalog. Type : ".concat(type.identifier)) + contractData[type] = data + } + + let path = data!.collectionData + + let storage = account.capabilities.storage + let storagePathIdentifer = path.storagePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + //if this stores anything but this it will panic, why does it not return nil? + var optProviderCap= account.storage.copy>(from: providerStoragePath) + if optProviderCap==nil { + optProviderCap=account.capabilities.storage.issue(path.storagePath) + account.storage.save(optProviderCap!, to: providerStoragePath) + } + + let providerCap=optProviderCap! + + let capcon = storage.getController(byCapabilityID:providerCap.id)! + capcon.setTag("sendNFT".concat(path.storagePath.toString())) + + let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: ids[i]) + + if let dt = donationTypes[i] { + self.royalties.append(pointer.getRoyalty()) + self.totalRoyalties.append(pointer.getTotalRoyaltiesCut()) + + // get the vault for donation + if self.vaultRefs[dt] == nil { + let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) + let ftPath = info.vaultPath + let ref = account.storage.borrow(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) + self.vaultRefs[dt] = ref + } + + } else { + self.royalties.append(nil) + self.totalRoyalties.append(0.0) + } + + + self.authPointers.append(pointer) + self.paths.append(path.publicPath) + } + + // get the vault for find donation + if let dt = findDonationType { + if self.vaultRefs[dt] == nil { + let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) + let ftPath = info.vaultPath + let ref = account.storage.borrow(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) + self.vaultRefs[dt] = ref + } + } + + if account.storage.borrow<&Sender.Token>(from: Sender.storagePath) == nil { + account.storage.save(<- Sender.createToken(), to: Sender.storagePath) + } + + self.token =account.storage.borrow<&Sender.Token>(from: Sender.storagePath)! + + } + + execute { + let addresses : {String : Address} = {} + + let ctx : {String : String} = { + "tenant" : "find" + } + + for i, pointer in self.authPointers { + let receiver = allReceivers[i] + let id = ids[i] + ctx["message"] = memos[i] + let path = self.paths[i] + + var user = addresses[receiver] + if user == nil { + user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) + addresses[receiver] = user + } + + // airdrop thru airdropper + FindAirdropper.safeAirdrop(pointer: pointer, receiver: user!, path: path, context: ctx, deepValidation: true) + } + + + // This is hard coded for spliting at the front end for now. So if there are no royalties, all goes to find + // AND This does not support different ft types for now. + var goesToFindFund = 0.0 + for i , type in donationTypes { + if type == nil { + continue + } + let amount = donationAmounts[i]! + let royalties = self.royalties[i]! + let totalRoyalties = self.totalRoyalties[i] + let vaultRef = self.vaultRefs[type!]! + if totalRoyalties == 0.0 { + goesToFindFund = goesToFindFund + amount + continue + } + + let balance = vaultRef.balance + var totalPaid = 0.0 + + for j, r in royalties.getRoyalties() { + var cap : Capability<&{FungibleToken.Receiver}>? = r.receiver + if r.receiver.check() { + let individualAmount = r.cut / totalRoyalties * amount + let vault <- vaultRef.withdraw(amount: individualAmount) + r.receiver.borrow()!.deposit(from: <- vault) + totalPaid = totalPaid + individualAmount + } + //there is no way to send over funds if this does not happen anmore + } + + assert(totalPaid <= amount, message: "Amount paid is greater than expected" ) + + } + + + // for donating to find + if findDonationType != nil { + let vaultRef = self.vaultRefs[findDonationType!]! + let vault <- vaultRef.withdraw(amount: findDonationAmount! + goesToFindFund) + FIND.depositWithTagAndMessage(to: "find", message: "donation to .find", tag: "donation", vault: <- vault, from: self.token) + } + } } diff --git a/transactions/sendNFTsSubsidize.cdc b/transactions/sendNFTsSubsidize.cdc index f9d70985..af1ec54f 100644 --- a/transactions/sendNFTsSubsidize.cdc +++ b/transactions/sendNFTsSubsidize.cdc @@ -1,201 +1,187 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FlowStorageFees from "../contracts/standard/FlowStorageFees.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import NFTCatalog from "../contracts/standard/NFTCatalog.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FIND from "../contracts/FIND.cdc" -import FindAirdropper from "../contracts/FindAirdropper.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import Profile from "../contracts/Profile.cdc" -import Sender from "../contracts/Sender.cdc" +import "NonFungibleToken" +import "FungibleToken" +import "FlowStorageFees" +import "FlowToken" +import "MetadataViews" +import "NFTCatalog" +import "FINDNFTCatalog" +import "FindViews" +import "FIND" +import "FindAirdropper" +import "FTRegistry" +import "Profile" +import "Sender" transaction(nftIdentifiers: [String], allReceivers: [String] , ids:[UInt64], memos: [String], donationTypes: [String?], donationAmounts: [UFix64?], findDonationType: String?, findDonationAmount: UFix64?) { - let authPointers : [FindViews.AuthNFTPointer] - let paths : [PublicPath] - let flowVault : &FungibleToken.Vault - let flowTokenRepayment : Capability<&FlowToken.Vault{FungibleToken.Receiver}> + let authPointers : [FindViews.AuthNFTPointer] + let paths : [PublicPath] + let flowVault : auth(FungibleToken.Withdraw) &{FungibleToken.Vault} + let flowTokenRepayment : Capability<&{FungibleToken.Receiver}> let defaultTokenAvailableBalance : UFix64 - let royalties: [MetadataViews.Royalties?] - let totalRoyalties: [UFix64] - let vaultRefs: {String : &FungibleToken.Vault} - var token : &Sender.Token - - prepare(account : AuthAccount) { - - self.authPointers = [] - self.paths = [] - self.royalties = [] - self.totalRoyalties = [] - self.vaultRefs = {} - - let contractData : {Type : NFTCatalog.NFTCatalogMetadata} = {} - - - for i , typeIdentifier in nftIdentifiers { - let type = CompositeType(typeIdentifier) ?? panic("Cannot refer to type with identifier : ".concat(typeIdentifier)) - - var data : NFTCatalog.NFTCatalogMetadata? = contractData[type] - if data == nil { - data = FINDNFTCatalog.getMetadataFromType(type) ?? panic("NFT Type is not supported by NFT Catalog. Type : ".concat(type.identifier)) - contractData[type] = data - } - - let path = data!.collectionData - - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(path.privatePath) - if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - path.privatePath, - target: path.storagePath - ) - if newCap == nil { - // If linking is not successful, we link it using finds custom link - let pathIdentifier = path.privatePath.toString() - let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( - findPath, - target: path.storagePath - ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) - } - } - let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: ids[i]) - - if let dt = donationTypes[i] { - self.royalties.append(pointer.getRoyalty()) - self.totalRoyalties.append(pointer.getTotalRoyaltiesCut()) - - // get the vault for donation - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - - } else { - self.royalties.append(nil) - self.totalRoyalties.append(0.0) - } - - - self.authPointers.append(pointer) - self.paths.append(path.publicPath) - } - - self.flowVault = account.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) ?? panic("Cannot borrow reference to sender's flow vault") - self.flowTokenRepayment = account.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) - self.defaultTokenAvailableBalance = FlowStorageFees.defaultTokenAvailableBalance(account.address) + let royalties: [MetadataViews.Royalties?] + let totalRoyalties: [UFix64] + let vaultRefs: {String : auth(FungibleToken.Withdraw) &{FungibleToken.Vault}} + var token : &Sender.Token + + + prepare(account: auth (BorrowValue, SaveValue, StorageCapabilities, NonFungibleToken.Withdraw, IssueStorageCapabilityController, FungibleToken.Withdraw) &Account) { + + self.authPointers = [] + self.paths = [] + self.royalties = [] + self.totalRoyalties = [] + self.vaultRefs = {} + + + let contractData : {Type : NFTCatalog.NFTCatalogMetadata} = {} + + + for i , typeIdentifier in nftIdentifiers { + let type = CompositeType(typeIdentifier) ?? panic("Cannot refer to type with identifier : ".concat(typeIdentifier)) + + var data : NFTCatalog.NFTCatalogMetadata? = contractData[type] + if data == nil { + data = FINDNFTCatalog.getMetadataFromType(type) ?? panic("NFT Type is not supported by NFT Catalog. Type : ".concat(type.identifier)) + contractData[type] = data + } + + let path = data!.collectionData + + let storage = account.capabilities.storage + + let storagePathIdentifer = path.storagePath.toString().split(separator:"/")[1] + let providerIdentifier = storagePathIdentifer.concat("Provider") + let providerStoragePath = StoragePath(identifier: providerIdentifier)! + + //if this stores anything but this it will panic, why does it not return nil? + var optProviderCap= account.storage.copy>(from: providerStoragePath) + if optProviderCap==nil { + optProviderCap=account.capabilities.storage.issue(path.storagePath) + account.storage.save(optProviderCap!, to: providerStoragePath) + } + + let providerCap=optProviderCap! + + let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: ids[i]) + + if let dt = donationTypes[i] { + self.royalties.append(pointer.getRoyalty()) + self.totalRoyalties.append(pointer.getTotalRoyaltiesCut()) - // get the vault for find donation - if let dt = findDonationType { - if self.vaultRefs[dt] == nil { - let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) - let ftPath = info.vaultPath - let ref = account.borrow<&FungibleToken.Vault>(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) - self.vaultRefs[dt] = ref - } - } + // get the vault for donation + if self.vaultRefs[dt] == nil { + let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) + let ftPath = info.vaultPath + let ref = account.storage.borrow(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) + self.vaultRefs[dt] = ref + } - if account.borrow<&Sender.Token>(from: Sender.storagePath) == nil { - account.save(<- Sender.create(), to: Sender.storagePath) - } + } else { + self.royalties.append(nil) + self.totalRoyalties.append(0.0) + } - self.token =account.borrow<&Sender.Token>(from: Sender.storagePath)! + self.authPointers.append(pointer) + self.paths.append(path.publicPath) + } + + self.flowVault = account.storage.borrow(from: /storage/flowTokenVault) ?? panic("Cannot borrow reference to sender's flow vault") + self.flowTokenRepayment = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)! + self.defaultTokenAvailableBalance = FlowStorageFees.defaultTokenAvailableBalance(account.address) + + // get the vault for find donation + if let dt = findDonationType { + if self.vaultRefs[dt] == nil { + let info = FTRegistry.getFTInfo(dt) ?? panic("This token type is not supported at the moment : ".concat(dt)) + let ftPath = info.vaultPath + let ref = account.storage.borrow(from: ftPath) ?? panic("Cannot borrow vault reference for type : ".concat(dt)) + self.vaultRefs[dt] = ref + } + } + + if account.storage.borrow<&Sender.Token>(from: Sender.storagePath) == nil { + account.storage.save(<- Sender.createToken(), to: Sender.storagePath) + } + self.token =account.storage.borrow<&Sender.Token>(from: Sender.storagePath)! - } + } - execute { - let addresses : {String : Address} = {} + execute { + let addresses : {String : Address} = {} let estimatedStorageFee = 0.0002 * UFix64(self.authPointers.length) // we pass in the least amount as possible for storage fee here let tempVault <- self.flowVault.withdraw(amount: 0.0) - var vaultRef = &tempVault as &FungibleToken.Vault + var vaultRef = &tempVault as auth(FungibleToken.Withdraw) &{FungibleToken.Vault} if self.defaultTokenAvailableBalance <= estimatedStorageFee { - vaultRef = self.flowVault as &FungibleToken.Vault + vaultRef = self.flowVault } else { tempVault.deposit(from: <- self.flowVault.withdraw(amount: estimatedStorageFee)) } - let ctx : {String : String} = { - "tenant" : "find" - } - - for i, pointer in self.authPointers { - let receiver = allReceivers[i] - let id = ids[i] - ctx["message"] = memos[i] - let path = self.paths[i] - - var user = addresses[receiver] - if user == nil { - user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) - addresses[receiver] = user - } - - // airdrop thru airdropper - FindAirdropper.subsidizedAirdrop(pointer: pointer, receiver: user!, path: path, context: ctx, storagePayment: vaultRef, flowTokenRepayment: self.flowTokenRepayment, deepValidation: true) - } + let ctx : {String : String} = { + "tenant" : "find" + } + + for i, pointer in self.authPointers { + let receiver = allReceivers[i] + let id = ids[i] + ctx["message"] = memos[i] + let path = self.paths[i] + + var user = addresses[receiver] + if user == nil { + user = FIND.resolve(receiver) ?? panic("Cannot resolve user with name / address : ".concat(receiver)) + addresses[receiver] = user + } + + FindAirdropper.subsidizedAirdrop(pointer: pointer, receiver: user!, path: path, context: ctx, storagePayment: vaultRef, flowTokenRepayment: self.flowTokenRepayment, deepValidation: true) + } self.flowVault.deposit(from: <- tempVault) - // This is hard coded for spliting at the front end for now. So if there are no royalties, all goes to find - // AND This does not support different ft types for now. - var goesToFindFund = 0.0 - for i , type in donationTypes { - if type == nil { - continue - } - let amount = donationAmounts[i]! - let royalties = self.royalties[i]! - let totalRoyalties = self.totalRoyalties[i] - let vaultRef = self.vaultRefs[type!]! - if totalRoyalties == 0.0 { - goesToFindFund = goesToFindFund + amount - continue - } - - let balance = vaultRef.balance - var totalPaid = 0.0 - - for j, r in royalties.getRoyalties() { - var cap : Capability<&{FungibleToken.Receiver}> = r.receiver - if !r.receiver.check(){ - // try to grab from profile - if let ref = getAccount(r.receiver.address).getCapability<&{Profile.Public}>(Profile.publicPath).borrow() { - if ref.hasWallet(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(Profile.publicReceiverPath) - } else if let ftInfo = FTRegistry.getFTInfo(vaultRef.getType().identifier) { - cap = getAccount(r.receiver.address).getCapability<&{FungibleToken.Receiver}>(ftInfo.receiverPath) - } - } - - } - - if cap.check() { - let individualAmount = r.cut / totalRoyalties * amount - let vault <- vaultRef.withdraw(amount: individualAmount) - cap.borrow()!.deposit(from: <- vault) - - totalPaid = totalPaid + individualAmount - } - } - - assert(totalPaid <= amount, message: "Amount paid is greater than expected" ) - - } - - - // for donating to find - if findDonationType != nil { - vaultRef = self.vaultRefs[findDonationType!]! - let vault <- vaultRef.withdraw(amount: findDonationAmount! + goesToFindFund) - FIND.depositWithTagAndMessage(to: "find", message: "donation to .find", tag: "donation", vault: <- vault, from: self.token) - } - } + // This is hard coded for spliting at the front end for now. So if there are no royalties, all goes to find + // AND This does not support different ft types for now. + var goesToFindFund = 0.0 + for i , type in donationTypes { + if type == nil { + continue + } + let amount = donationAmounts[i]! + let royalties = self.royalties[i]! + let totalRoyalties = self.totalRoyalties[i] + let vaultRef = self.vaultRefs[type!]! + var noRoyalty = false + if totalRoyalties == 0.0 { + goesToFindFund = goesToFindFund + amount + continue + } + + let balance = vaultRef.balance + var totalPaid = 0.0 + + + for j, r in royalties.getRoyalties() { + var cap : Capability<&{FungibleToken.Receiver}>? = r.receiver + if r.receiver.check() { + let individualAmount = r.cut / totalRoyalties * amount + let vault <- vaultRef.withdraw(amount: individualAmount) + r.receiver.borrow()!.deposit(from: <- vault) + totalPaid = totalPaid + individualAmount + } + //there is no way to send over funds if this does not happen anmore + } + + assert(totalPaid <= amount, message: "Amount paid is greater than expected" ) + + } + + // for donating to find + if findDonationType != nil { + vaultRef = self.vaultRefs[findDonationType!]! + let vault <- vaultRef.withdraw(amount: findDonationAmount! + goesToFindFund) + FIND.depositWithTagAndMessage(to: "find", message: "donation to .find", tag: "donation", vault: <- vault, from: self.token) + } + } } diff --git a/transactions/sendWearables.cdc b/transactions/sendWearables.cdc index 62212383..61cb2f21 100644 --- a/transactions/sendWearables.cdc +++ b/transactions/sendWearables.cdc @@ -1,15 +1,15 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindViews from "../contracts/FindViews.cdc" -import FIND from "../contracts/FIND.cdc" -import FindAirdropper from "../contracts/FindAirdropper.cdc" -import Wearables from "../contracts/community/Wearables.cdc" +import "NonFungibleToken" +import "MetadataViews" +import "FindViews" +import "FIND" +import "FindAirdropper" +import "Wearables" transaction(allReceivers: [String] , ids:[UInt64], memos: [String]) { let authPointers : [FindViews.AuthNFTPointer] - prepare(account : AuthAccount) { + prepare(account : auth(BorrowValue) &Account) { self.authPointers = [] let privatePath = Wearables.CollectionPrivatePath @@ -17,9 +17,9 @@ transaction(allReceivers: [String] , ids:[UInt64], memos: [String]) { for id in ids { - var providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(privatePath) + var providerCap=account.getCapability<&{NonFungibleToken.Provider, ViewResolver.ResolverCollection, NonFungibleToken.Collection}>(privatePath) if !providerCap.check() { - let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + let newCap = account.link<&{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( privatePath, target: storagePath ) @@ -27,11 +27,11 @@ transaction(allReceivers: [String] , ids:[UInt64], memos: [String]) { // If linking is not successful, we link it using finds custom link let pathIdentifier = privatePath.toString() let findPath = PrivatePath(identifier: pathIdentifier.slice(from: "/private/".length , upTo: pathIdentifier.length).concat("_FIND"))! - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( findPath, target: storagePath ) - providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(findPath) + providerCap = account.getCapability<&{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>(findPath) } } let pointer = FindViews.AuthNFTPointer(cap: providerCap, id: id) diff --git a/transactions/setMainName.cdc b/transactions/setMainName.cdc index ddad98d8..ee3ec4bb 100644 --- a/transactions/setMainName.cdc +++ b/transactions/setMainName.cdc @@ -1,24 +1,16 @@ -import Profile from "../contracts/Profile.cdc" -import FIND from "../contracts/FIND.cdc" +import "Profile" +import "FIND" transaction(name: String) { - let leaseCollectionOwner : Capability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}> - let profile : &Profile.User + let profile : auth(Profile.Admin) &Profile.User + prepare(acct: auth(BorrowValue) &Account) { + self.profile =acct.storage.borrow(from:Profile.storagePath) ?? panic("Cannot borrow reference to profile") + } - prepare(acct: AuthAccount) { - self.leaseCollectionOwner = acct.getCapability<&FIND.LeaseCollection{FIND.LeaseCollectionPublic}>(FIND.LeasePublicPath) - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath)! - } - - pre{ - self.leaseCollectionOwner.check() : "Not a find user" - self.leaseCollectionOwner.borrow()!.getLease(name) != nil : "You do not own this lease so you cannot set it as main name" - } - - execute{ - self.profile.setFindName(name) - } + execute{ + self.profile.setMainName(name) + } } diff --git a/transactions/setMarketOptionFlowDandy.cdc b/transactions/setMarketOptionFlowDandy.cdc index 76b33720..6503072c 100644 --- a/transactions/setMarketOptionFlowDandy.cdc +++ b/transactions/setMarketOptionFlowDandy.cdc @@ -1,11 +1,11 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import Dandy from "../contracts/Dandy.cdc" +import "FindMarket" +import "FlowToken" +import "Dandy" transaction(){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ let path = FindMarket.TenantClientStoragePath - let tenantRef = account.borrow<&FindMarket.TenantClient>(from: path) ?? panic("Cannot borrow Reference.") + let tenantRef = account.storage.borrow(from: path) ?? panic("Cannot borrow Reference.") tenantRef.setMarketOption(name:"FlowDandy", cut: nil, rules:[ FindMarket.TenantRule(name:"Flow", types:[Type<@FlowToken.Vault>()], ruleType: "ft", allow: true), diff --git a/transactions/setPrivateMode.cdc b/transactions/setPrivateMode.cdc index 7442c585..37179072 100644 --- a/transactions/setPrivateMode.cdc +++ b/transactions/setPrivateMode.cdc @@ -1,20 +1,20 @@ -import Profile from "../contracts/Profile.cdc" +import "Profile" transaction(mode: Bool) { - let profile : &Profile.User? + let profile : auth(Profile.Admin) &Profile.User? - prepare(acct: AuthAccount) { - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath) - } + prepare(acct: auth(Profile.Admin, BorrowValue) &Account) { + self.profile =acct.storage.borrow(from:Profile.storagePath) + } - pre{ - self.profile != nil : "Cannot borrow reference to profile" - } + pre{ + self.profile != nil : "Cannot borrow reference to profile" + } - execute{ - self.profile!.setPrivateMode(mode) - self.profile!.emitUpdatedEvent() - } + execute{ + self.profile!.setPrivateMode(mode) + self.profile!.emitUpdatedEvent() + } } diff --git a/transactions/setPrivateModeDapper.cdc b/transactions/setPrivateModeDapper.cdc index 7442c585..d07ef022 100644 --- a/transactions/setPrivateModeDapper.cdc +++ b/transactions/setPrivateModeDapper.cdc @@ -1,10 +1,10 @@ -import Profile from "../contracts/Profile.cdc" +import "Profile" transaction(mode: Bool) { let profile : &Profile.User? - prepare(acct: AuthAccount) { + prepare(acct: auth(BorrowValue) &Account) { self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath) } diff --git a/transactions/setProfile.cdc b/transactions/setProfile.cdc index 8770c264..62e78c53 100644 --- a/transactions/setProfile.cdc +++ b/transactions/setProfile.cdc @@ -1,20 +1,20 @@ -import Profile from "../contracts/Profile.cdc" +import "Profile" transaction(avatar: String) { - let profile : &Profile.User? + let profile : auth(Profile.Admin) &Profile.User? - prepare(acct: AuthAccount) { - self.profile =acct.borrow<&Profile.User>(from:Profile.storagePath) - } + prepare(acct: auth (BorrowValue) &Account) { + self.profile =acct.storage.borrow(from:Profile.storagePath) + } - pre{ - self.profile != nil : "Cannot borrow reference to profile" - } + pre{ + self.profile != nil : "Cannot borrow reference to profile" + } - execute{ - self.profile!.setAvatar(avatar) - self.profile!.emitUpdatedEvent() - } + execute{ + self.profile!.setAvatar(avatar) + self.profile!.emitUpdatedEvent() + } } diff --git a/transactions/setRelatedAccount.cdc b/transactions/setRelatedAccount.cdc index 837d779b..69b48889 100644 --- a/transactions/setRelatedAccount.cdc +++ b/transactions/setRelatedAccount.cdc @@ -1,36 +1,39 @@ -import FindRelatedAccounts from "../contracts/FindRelatedAccounts.cdc" -import FIND from "../contracts/FIND.cdc" +import "FindRelatedAccounts" +import "FIND" transaction(name: String, target: String) { - var relatedAccounts : &FindRelatedAccounts.Accounts? - let address : Address? + var relatedAccounts : auth(FindRelatedAccounts.Owner) &FindRelatedAccounts.Accounts? + let address : Address? - prepare(account: AuthAccount) { + prepare(account: auth(SaveValue, BorrowValue, PublishCapability, UnpublishCapability,IssueStorageCapabilityController) &Account) { - self.address = FIND.resolve(target) + self.address = FIND.resolve(target) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - if self.relatedAccounts == nil { - let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - } + self.relatedAccounts= account.storage.borrow(from:FindRelatedAccounts.storagePath) + if self.relatedAccounts == nil { + let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() + account.storage.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) - if !cap.check() { - account.unlink(FindRelatedAccounts.publicPath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - } - } + let cap = account.capabilities.storage.issue<&{FindRelatedAccounts.Public}>(FindRelatedAccounts.storagePath) + account.capabilities.publish(cap, at: FindRelatedAccounts.publicPath) + self.relatedAccounts= account.storage.borrow(from:FindRelatedAccounts.storagePath) + } - pre{ - self.address != nil : "The input pass in is not a valid name or address. Input : ".concat(target) - } + let cap = account.capabilities.get<&{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) + if !cap.check() { + account.capabilities.unpublish(FindRelatedAccounts.publicPath) + let cap = account.capabilities.storage.issue<&{FindRelatedAccounts.Public}>(FindRelatedAccounts.storagePath) + account.capabilities.publish(cap, at: FindRelatedAccounts.publicPath) + } + } - execute{ - self.relatedAccounts!.addFlowAccount(name: name, address: self.address!) - } + pre{ + self.address != nil : "The input pass in is not a valid name or address. Input : ".concat(target) + } + + execute{ + self.relatedAccounts!.addFlowAccount(name: name, address: self.address!) + } } diff --git a/transactions/setRelatedAccountDapper.cdc b/transactions/setRelatedAccountDapper.cdc index 8eb38b16..78ba53b1 100644 --- a/transactions/setRelatedAccountDapper.cdc +++ b/transactions/setRelatedAccountDapper.cdc @@ -1,22 +1,22 @@ -import FindRelatedAccounts from "../contracts/FindRelatedAccounts.cdc" -import FIND from "../contracts/FIND.cdc" +import "FindRelatedAccounts" +import "FIND" transaction(name: String, target: String) { - var relatedAccounts : &FindRelatedAccounts.Accounts? + var relatedAccounts : auth(FindRelatedAccounts.Owner) &FindRelatedAccounts.Accounts? let address : Address? - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { self.address = FIND.resolve(target) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) + self.relatedAccounts= account.storage.borrow(from:FindRelatedAccounts.storagePath) if self.relatedAccounts == nil { let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) + account.storage.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) + self.relatedAccounts= account.storage.borrow(from:FindRelatedAccounts.storagePath) } let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) diff --git a/transactions/setSellDandyRules.cdc b/transactions/setSellDandyRules.cdc index 3fa1cd86..8487f18a 100644 --- a/transactions/setSellDandyRules.cdc +++ b/transactions/setSellDandyRules.cdc @@ -1,24 +1,17 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import Dandy from "../contracts/Dandy.cdc" +import "FindMarket" +import "FlowToken" +import "Dandy" transaction(){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ let path = FindMarket.TenantClientStoragePath - let tenantRef = account.borrow<&FindMarket.TenantClient>(from: path) ?? panic("Cannot borrow Reference.") - - tenantRef.setMarketOption(name:"FUSDDandy", cut: nil, rules:[ - FindMarket.TenantRule(name:"FUSD", types:[Type<@FUSD.Vault>()], ruleType: "ft", allow: true), - FindMarket.TenantRule(name:"Dandy", types:[ Type<@Dandy.NFT>()], ruleType: "nft", allow: true) - ] - ) + let tenantRef = account.storage.borrow(from: path) ?? panic("Cannot borrow Reference.") tenantRef.setMarketOption(name:"FlowDandy", cut: nil, rules:[ - FindMarket.TenantRule(name:"Flow", types:[Type<@FlowToken.Vault>()], ruleType: "ft", allow: true), - FindMarket.TenantRule(name:"Dandy", types:[ Type<@Dandy.NFT>()], ruleType: "nft", allow: true) - ] - ) + FindMarket.TenantRule(name:"Flow", types:[Type<@FlowToken.Vault>()], ruleType: "ft", allow: true), + FindMarket.TenantRule(name:"Dandy", types:[ Type<@Dandy.NFT>()], ruleType: "nft", allow: true) + ] + ) - } +} } diff --git a/transactions/setTenantRuleFUSD.cdc b/transactions/setTenantRuleFUSD.cdc deleted file mode 100644 index 6bafe8d5..00000000 --- a/transactions/setTenantRuleFUSD.cdc +++ /dev/null @@ -1,13 +0,0 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" - -transaction(optionName: String){ - prepare(account: AuthAccount){ - let path = FindMarket.TenantClientStoragePath - let tenantRef = account.borrow<&FindMarket.TenantClient>(from: path) ?? panic("Cannot borrow Reference.") - - tenantRef.setTenantRule(optionName: optionName, tenantRule: - FindMarket.TenantRule(name:"FUSD", types:[Type<@FUSD.Vault>()], ruleType: "ft", allow: true) - ) - } -} diff --git a/transactions/setupDandy.cdc b/transactions/setupDandy.cdc index a4a72163..ef5bfa53 100644 --- a/transactions/setupDandy.cdc +++ b/transactions/setupDandy.cdc @@ -1,27 +1,27 @@ -import FIND from "../contracts/FIND.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import Dandy from "../contracts/Dandy.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FindForge from "../contracts/FindForge.cdc" +import "FIND" +import "NonFungibleToken" +import "FungibleToken" +import "Dandy" +import "MetadataViews" +import "FindForge" transaction(name: String, minterCut: UFix64, description:String, externalUrl:String, squareImage:String, bannerImage:String, socials:{String:String}) { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - let dandyCap= account.getCapability<&{NonFungibleToken.CollectionPublic}>(Dandy.CollectionPublicPath) + let dandyCap= account.getCapability<&{NonFungibleToken.Collection}>(Dandy.CollectionPublicPath) if !dandyCap.check() { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.storage.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) + account.link<&Dandy.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPublicPath, target: Dandy.CollectionStoragePath ) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPrivatePath, target: Dandy.CollectionStoragePath ) } - let finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! + let finLeases= account.storage.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! let lease=finLeases.borrow(name) let forgeType = Dandy.getForgeType() if !FindForge.checkMinterPlatform(name: lease.getName(), forgeType: forgeType ) { diff --git a/transactions/setupDandyCollection.cdc b/transactions/setupDandyCollection.cdc index 6b57e08b..7f424046 100644 --- a/transactions/setupDandyCollection.cdc +++ b/transactions/setupDandyCollection.cdc @@ -1,19 +1,19 @@ -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import Dandy from "../contracts/Dandy.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "NonFungibleToken" +import "Dandy" +import "MetadataViews" transaction() { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - let dandyCap= account.getCapability<&{NonFungibleToken.CollectionPublic}>(Dandy.CollectionPublicPath) + let dandyCap= account.getCapability<&{NonFungibleToken.Collection}>(Dandy.CollectionPublicPath) if !dandyCap.check() { - account.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) - account.link<&Dandy.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.storage.save<@NonFungibleToken.Collection>(<- Dandy.createEmptyCollection(), to: Dandy.CollectionStoragePath) + account.link<&Dandy.Collection{NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPublicPath, target: Dandy.CollectionStoragePath ) - account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, Dandy.CollectionPublic}>( + account.link<&Dandy.Collection{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection, Dandy.CollectionPublic}>( Dandy.CollectionPrivatePath, target: Dandy.CollectionStoragePath ) diff --git a/transactions/setupExampleNFTCollection.cdc b/transactions/setupExampleNFTCollection.cdc index ac9ee5d3..9ec3b6a4 100644 --- a/transactions/setupExampleNFTCollection.cdc +++ b/transactions/setupExampleNFTCollection.cdc @@ -1,21 +1,19 @@ -import FIND from "../contracts/FIND.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import ExampleNFT from "../contracts/standard/ExampleNFT.cdc" +import "NonFungibleToken" +import "MetadataViews" +import "ViewResolver" +import "ExampleNFT" +import "Debug" transaction() { - prepare(account: AuthAccount) { - let dandyCap= account.getCapability<&{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) - if !dandyCap.check() { - account.save<@NonFungibleToken.Collection>(<- ExampleNFT.createEmptyCollection(), to: ExampleNFT.CollectionStoragePath) - account.link<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, ExampleNFT.ExampleNFTCollectionPublic}>( - ExampleNFT.CollectionPublicPath, - target: ExampleNFT.CollectionStoragePath - ) - account.link<&ExampleNFT.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection, ExampleNFT.ExampleNFTCollectionPublic}>( - ExampleNFT.CollectionPrivatePath, - target: ExampleNFT.CollectionStoragePath - ) - } - } + prepare(account: auth(BorrowValue, SaveValue, PublishCapability, IssueStorageCapabilityController,UnpublishCapability) &Account) { + + let col= account.storage.borrow<&ExampleNFT.Collection>(from: ExampleNFT.CollectionStoragePath) + if col == nil { + account.storage.save( <- ExampleNFT.createEmptyCollection(nftType:Type<@ExampleNFT.NFT>()), to: ExampleNFT.CollectionStoragePath) + account.capabilities.unpublish(ExampleNFT.CollectionPublicPath) + let cap = account.capabilities.storage.issue<&ExampleNFT.Collection>(ExampleNFT.CollectionStoragePath) + account.capabilities.publish(cap, at: ExampleNFT.CollectionPublicPath) + } + } } + diff --git a/transactions/setupFindPackMinterPlatform.cdc b/transactions/setupFindPackMinterPlatform.cdc index 619e397a..7af8f33b 100644 --- a/transactions/setupFindPackMinterPlatform.cdc +++ b/transactions/setupFindPackMinterPlatform.cdc @@ -1,12 +1,12 @@ -import FIND from "../contracts/FIND.cdc" -import FindForge from "../contracts/FindForge.cdc" -import FindPack from "../contracts/FindPack.cdc" +import "FIND" +import "FindForge" +import "FindPack" transaction(lease: String) { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { - let finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! + let finLeases= account.storage.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath)! let lease=finLeases.borrow(lease) let forgeType = Type<@FindPack.Forge>() if !FindForge.checkMinterPlatform(name: lease.getName(), forgeType: forgeType ) { diff --git a/transactions/setupUSDC.cdc b/transactions/setupUSDC.cdc deleted file mode 100644 index cdd2f561..00000000 --- a/transactions/setupUSDC.cdc +++ /dev/null @@ -1,20 +0,0 @@ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" - -transaction() { - - prepare(signer: AuthAccount) { - - // Return early if the account already stores a FiatToken Vault - if signer.borrow<&FiatToken.Vault>(from: FiatToken.VaultStoragePath) != nil { - return - } - - signer.save( <-FiatToken.createEmptyVault(), to: FiatToken.VaultStoragePath) - signer.link<&FiatToken.Vault{FungibleToken.Receiver}>( FiatToken.VaultReceiverPubPath, target: FiatToken.VaultStoragePath) - signer.link<&FiatToken.Vault{FiatToken.ResourceId}>( FiatToken.VaultUUIDPubPath, target: FiatToken.VaultStoragePath) - signer.link<&FiatToken.Vault{FungibleToken.Balance}>( FiatToken.VaultBalancePubPath, target: FiatToken.VaultStoragePath) - - } -} - diff --git a/transactions/setup_fin_1_create_client.cdc b/transactions/setup_fin_1_create_client.cdc index 50579932..d048483b 100644 --- a/transactions/setup_fin_1_create_client.cdc +++ b/transactions/setup_fin_1_create_client.cdc @@ -1,24 +1,38 @@ -import Admin from "../contracts/Admin.cdc" -import FindMarketAdmin from "../contracts/FindMarketAdmin.cdc" +import "Admin" +import "FindMarketAdmin" +import "FungibleToken" //set up the adminClient in the contract that will own the network transaction() { - prepare(account: AuthAccount) { - - if account.getCapability(Admin.AdminProxyPublicPath).check<&AnyResource>() { - account.unlink(Admin.AdminProxyPublicPath) - destroy <- account.load<@AnyResource>(from: Admin.AdminProxyStoragePath) - } - account.save(<- Admin.createAdminProxyClient(), to:Admin.AdminProxyStoragePath) - account.link<&{Admin.AdminProxyClient}>(Admin.AdminProxyPublicPath, target: Admin.AdminProxyStoragePath) - - if account.getCapability(FindMarketAdmin.AdminProxyPublicPath).check<&AnyResource>() { - account.unlink(FindMarketAdmin.AdminProxyPublicPath) - destroy <- account.load<@AnyResource>(from: FindMarketAdmin.AdminProxyStoragePath) - } - account.save(<- FindMarketAdmin.createAdminProxyClient(), to:FindMarketAdmin.AdminProxyStoragePath) - account.link<&{FindMarketAdmin.AdminProxyClient}>(FindMarketAdmin.AdminProxyPublicPath, target: FindMarketAdmin.AdminProxyStoragePath) - } + prepare(account: auth(SaveValue, IssueStorageCapabilityController,PublishCapability) &Account) { + + + let caps = account.capabilities + let storage = account.storage + + //Dont know why this does not work + /* + if caps.exists(Admin.AdminProxyPublicPath) { + caps.unpublish(Admin.AdminProxyPublicPath) + destroy <- storage.load<@AnyResource>(from: Admin.AdminProxyStoragePath) + } + */ + storage.save(<- Admin.createAdminProxyClient(), to:Admin.AdminProxyStoragePath) + let proxyCap =caps.storage.issue<&{Admin.AdminProxyClient}>(Admin.AdminProxyStoragePath) + caps.publish(proxyCap, at: Admin.AdminProxyPublicPath) + + /* + if caps.exists(FindMarketAdmin.AdminProxyPublicPath) { + caps.unpublish(FindMarketAdmin.AdminProxyPublicPath) + destroy <- storage.load<@AnyResource>(from:FindMarketAdmin.AdminProxyStoragePath) + } + */ + storage.save(<- FindMarketAdmin.createAdminProxyClient(), to:FindMarketAdmin.AdminProxyStoragePath) + let marketProxyCap =caps.storage.issue<&{FindMarketAdmin.AdminProxyClient}>(FindMarketAdmin.AdminProxyStoragePath) + caps.publish(marketProxyCap, at: FindMarketAdmin.AdminProxyPublicPath) + + + } } diff --git a/transactions/setup_fin_2_register_client.cdc b/transactions/setup_fin_2_register_client.cdc index 19228a93..db41864c 100644 --- a/transactions/setup_fin_2_register_client.cdc +++ b/transactions/setup_fin_2_register_client.cdc @@ -1,23 +1,28 @@ -import Admin from "../contracts/Admin.cdc" -import FindMarketAdmin from "../contracts/FindMarketAdmin.cdc" -import FIND from "../contracts/FIND.cdc" +import "Admin" +import "FindMarketAdmin" +import "FIND" //link together the administrator to the client, signed by the owner of the contract transaction(ownerAddress: Address) { //versus account - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue, IssueStorageCapabilityController, GetStorageCapabilityController) &Account) { let owner= getAccount(ownerAddress) - let client= owner.getCapability<&{Admin.AdminProxyClient}>(Admin.AdminProxyPublicPath) - .borrow() ?? panic("Could not borrow admin client") - let findMarketClient= owner.getCapability<&{FindMarketAdmin.AdminProxyClient}>(FindMarketAdmin.AdminProxyPublicPath) - .borrow() ?? panic("Could not borrow find market admin client") + let client= owner.capabilities.borrow<&{Admin.AdminProxyClient}>(Admin.AdminProxyPublicPath) ?? panic("Could not borrow admin client") + let findMarketClient= owner.capabilities.borrow<&{FindMarketAdmin.AdminProxyClient}>(FindMarketAdmin.AdminProxyPublicPath) ?? panic("Could not borrow admin client") - let network=account.getCapability<&FIND.Network>(FIND.NetworkPrivatePath) - client.addCapability(network) - findMarketClient.addCapability(network) + let storage= account.capabilities.storage + //we issue a capability from our storage + let capability = storage.issue<&FIND.Network>(FIND.NetworkStoragePath) + + //we set the name as tag so it is easy for us to revoke it later using a friendly name + let capcon = storage.getController(byCapabilityID:capability.id)! + capcon.setTag("findAdmin") + + client.addCapability(capability) + findMarketClient.addCapability(capability) } } diff --git a/transactions/setup_fin_3_create_network.cdc b/transactions/setup_fin_3_create_network.cdc index 4fad1fe4..d3e3f84e 100644 --- a/transactions/setup_fin_3_create_network.cdc +++ b/transactions/setup_fin_3_create_network.cdc @@ -1,35 +1,13 @@ - -import Admin from "../contracts/Admin.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" +import "Admin" +import "FungibleToken" transaction() { + prepare(account: auth (BorrowValue, SaveValue, StorageCapabilities, IssueStorageCapabilityController, PublishCapability) &Account) { - prepare(account: AuthAccount) { - let wallet=account.getCapability<&{FungibleToken.Receiver}>(/public/fusdReceiver) - if !wallet.check() { - let fusd <- FUSD.createEmptyVault() - account.save(<- fusd, to: /storage/fusdVault) - account.link<&FUSD.Vault{FungibleToken.Receiver}>( /public/fusdReceiver, target: /storage/fusdVault) - account.link<&FUSD.Vault{FungibleToken.Balance}>( /public/fusdBalance, target: /storage/fusdVault) - } - - let adminClient=account.borrow<&Admin.AdminProxy>(from: Admin.AdminProxyStoragePath)! + let wallet=account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let adminClient=account.storage.borrow(from:Admin.AdminProxyStoragePath)! adminClient.setPublicEnabled(true) adminClient.setWallet(wallet) - - // Return early if the account already stores a FiatToken Vault - if account.borrow<&FiatToken.Vault>(from: FiatToken.VaultStoragePath) != nil { - return - } - - account.save( <-FiatToken.createEmptyVault(), to: FiatToken.VaultStoragePath) - account.link<&FiatToken.Vault{FungibleToken.Receiver}>( FiatToken.VaultReceiverPubPath, target: FiatToken.VaultStoragePath) - account.link<&FiatToken.Vault{FiatToken.ResourceId}>( FiatToken.VaultUUIDPubPath, target: FiatToken.VaultStoragePath) - account.link<&FiatToken.Vault{FungibleToken.Balance}>( FiatToken.VaultBalancePubPath, target: FiatToken.VaultStoragePath) - - } } diff --git a/transactions/setup_find_dapper_market.cdc b/transactions/setup_find_dapper_market.cdc index e1e8c535..e1a6379b 100644 --- a/transactions/setup_find_dapper_market.cdc +++ b/transactions/setup_find_dapper_market.cdc @@ -1,42 +1,40 @@ -import FindMarketAdmin from "../contracts/FindMarketAdmin.cdc" -import FindMarket from "../contracts/FindMarket.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "FindMarketAdmin" +import "FindMarket" +import "FlowToken" +import "DapperUtilityCoin" +import "FlowUtilityToken" +import "MetadataViews" //signed by admin to link tenantClient to a new tenant transaction(tenant: String, adminAddress: Address, tenantAddress: Address, findCut: UFix64) { - //versus account - prepare(account: AuthAccount) { - let adminClient=account.borrow<&FindMarketAdmin.AdminProxy>(from: FindMarketAdmin.AdminProxyStoragePath)! + //versus account + prepare(account: auth(BorrowValue) &Account) { + let adminClient=account.storage.borrow(from: FindMarketAdmin.AdminProxyStoragePath)! - // pass in the default cut rules here - let cut = [ - FindMarket.TenantRule( name:"standard ft", types:[Type<@FUSD.Vault>(), Type<@FlowToken.Vault>(), Type<@FiatToken.Vault>(), Type<@DapperUtilityCoin.Vault>() , Type<@FlowUtilityToken.Vault>()], ruleType:"ft", allow:true) - ] + // pass in the default cut rules here + let cut = [ + FindMarket.TenantRule( name:"standard ft", types:[Type<@FlowToken.Vault>(), Type<@DapperUtilityCoin.Vault>() , Type<@FlowUtilityToken.Vault>()], ruleType:"ft", allow:true) + ] - let royalty = MetadataViews.Royalty( - receiver: adminClient.getSwitchboardReceiverPublic(), - cut: findCut, - description: "find" - ) + let royalty = MetadataViews.Royalty( + receiver: adminClient.getSwitchboardReceiverPublic(), + cut: findCut, + description: "find" + ) - let saleItem = FindMarket.TenantSaleItem( - name: "findRoyalty", - cut: royalty, - rules : cut, - status: "active", - ) + let saleItem = FindMarket.TenantSaleItem( + name: "findRoyalty", + cut: royalty, + rules : cut, + status: "active", + ) - //We create a tenant that has both auctions and direct offers - let tenantCap= adminClient.createFindMarket(name: tenant, address: tenantAddress, findCutSaleItem: saleItem) + //We create a tenant that has both auctions and direct offers + let tenantCap= adminClient.createFindMarket(name: tenant, address: tenantAddress, findCutSaleItem: saleItem) - let tenantAccount=getAccount(adminAddress) - let tenantClient=tenantAccount.getCapability<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientPublicPath).borrow()! - tenantClient.addCapability(tenantCap) - } + let tenantAccount=getAccount(adminAddress) + let tenantClient=tenantAccount.capabilities.get<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientPublicPath)!.borrow()! + tenantClient.addCapability(tenantCap) + } } diff --git a/transactions/setup_find_forge_1.cdc b/transactions/setup_find_forge_1.cdc index ae4ab55c..945b52ee 100644 --- a/transactions/setup_find_forge_1.cdc +++ b/transactions/setup_find_forge_1.cdc @@ -1,11 +1,9 @@ -import FindForge from "../contracts/FindForge.cdc" +import "FindForge" - -//Transaction that is signed by find to create a find market tenant for find transaction() { - prepare(account: AuthAccount) { - //in finds case the - account.save(<- FindForge.createForgeAdminProxyClient(), to:/storage/findForgeAdminProxy) - account.link<&{FindForge.ForgeAdminProxyClient}>(/public/findForgeAdminProxy, target: /storage/findForgeAdminProxy) - } + prepare(account: auth(BorrowValue, SaveValue, PublishCapability, IssueStorageCapabilityController) &Account) { + account.storage.save(<- FindForge.createForgeAdminProxyClient(), to:/storage/findForgeAdminProxy) + let cap = account.capabilities.storage.issue<&{FindForge.ForgeAdminProxyClient}>(/storage/findForgeAdminProxy) + account.capabilities.publish(cap, at: /public/findForgeAdminProxy) + } } diff --git a/transactions/setup_find_forge_2.cdc b/transactions/setup_find_forge_2.cdc index fc590fc3..1d2c01d3 100644 --- a/transactions/setup_find_forge_2.cdc +++ b/transactions/setup_find_forge_2.cdc @@ -1,19 +1,18 @@ -import FindForge from "../contracts/FindForge.cdc" -import FIND from "../contracts/FIND.cdc" +import "FindForge" +import "FIND" //link together the administrator to the client, signed by the owner of the contract transaction(ownerAddress: Address) { //versus account - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue, IssueStorageCapabilityController) &Account) { let owner= getAccount(ownerAddress) - let client= owner.getCapability<&{FindForge.ForgeAdminProxyClient}>(/public/findForgeAdminProxy) - .borrow() ?? panic("Could not borrow admin client") + let client= owner.capabilities.borrow<&{FindForge.ForgeAdminProxyClient}>(/public/findForgeAdminProxy) ?? panic("Could not borrow admin client") - let network=account.getCapability<&FIND.Network>(FIND.NetworkPrivatePath) + let network = account.capabilities.storage.issue<&FIND.Network>(FIND.NetworkStoragePath) client.addCapability(network) } } - + diff --git a/transactions/setup_find_lease_market_2.cdc b/transactions/setup_find_lease_market_2.cdc index 5745c4c7..4f5b3a91 100644 --- a/transactions/setup_find_lease_market_2.cdc +++ b/transactions/setup_find_lease_market_2.cdc @@ -1,39 +1,38 @@ -import FindMarketAdmin from "../contracts/FindMarketAdmin.cdc" -import FindMarket from "../contracts/FindMarket.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" +import "FindMarketAdmin" +import "FindMarket" +import "FungibleToken" +import "DapperUtilityCoin" +import "FlowUtilityToken" +import "FlowToken" +import "MetadataViews" transaction(tenantAddress: Address) { - //versus account - prepare(account: AuthAccount) { - let adminClient=account.borrow<&FindMarketAdmin.AdminProxy>(from: FindMarketAdmin.AdminProxyStoragePath)! + prepare(account: auth(BorrowValue) &Account) { + let adminClient=account.storage.borrow(from: FindMarketAdmin.AdminProxyStoragePath)! - // pass in the default cut rules here - let cut = [ - FindMarket.TenantRule( name:"standard ft", types:[Type<@DapperUtilityCoin.Vault>(), Type<@FlowUtilityToken.Vault>()], ruleType:"ft", allow:true) - ] + let cut = [ + FindMarket.TenantRule( name:"standard ft", types:[Type<@DapperUtilityCoin.Vault>(), Type<@FlowUtilityToken.Vault>(), Type<@FlowToken.Vault>()], ruleType:"ft", allow:true) + ] - let royalty = MetadataViews.Royalty( - receiver: adminClient.getSwitchboardReceiverPublic(), - cut: 0.025, - description: "find" - ) + let royalty = MetadataViews.Royalty( + receiver: adminClient.getSwitchboardReceiverPublic(), + cut: 0.025, + description: "find" + ) - let saleItem = FindMarket.TenantSaleItem( - name: "findRoyalty", - cut: royalty, - rules : cut, - status: "active", - ) + let saleItem = FindMarket.TenantSaleItem( + name: "findRoyalty", + cut: royalty, + rules : cut, + status: "active", + ) - //We create a tenant that has both auctions and direct offers - let tenantCap= adminClient.createFindMarket(name: "find", address: tenantAddress, findCutSaleItem: saleItem) + //We create a tenant that has both auctions and direct offers + let tenantCap= adminClient.createFindMarket(name: "find", address: tenantAddress, findCutSaleItem: saleItem) - let tenantAccount=getAccount(tenantAddress) - let tenantClient=tenantAccount.getCapability<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientPublicPath).borrow()! - tenantClient.addCapability(tenantCap) - } + let tenantAccount=getAccount(tenantAddress) + let tenantClient=tenantAccount.capabilities.borrow<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientPublicPath)! + tenantClient.addCapability(tenantCap) + } } diff --git a/transactions/setup_find_market_1.cdc b/transactions/setup_find_market_1.cdc deleted file mode 100644 index 7a590d8d..00000000 --- a/transactions/setup_find_market_1.cdc +++ /dev/null @@ -1,66 +0,0 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" -import FungibleTokenSwitchboard from "../contracts/standard/FungibleTokenSwitchboard.cdc" - -//Transaction that is signed by find to create a find market tenant for find -transaction() { - prepare(account: AuthAccount) { - //in finds case the - account.save(<- FindMarket.createTenantClient(), to:FindMarket.TenantClientStoragePath) - account.link<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientPublicPath, target: FindMarket.TenantClientStoragePath) - - let ftCaps : [Capability<&{FungibleToken.Receiver}>] = [] - - // setup Token for switchboard - let flowReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) - if !flowReceiver.check() { - account.link<&FlowToken.Vault{FungibleToken.Receiver}>( /public/flowTokenReceiver, target: /storage/flowTokenVault) - account.link<&FlowToken.Vault{FungibleToken.Balance}>( /public/flowTokenBalance, target: /storage/flowTokenVault) - } - ftCaps.append(flowReceiver) - - let fusdReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/fusdReceiver) - if !fusdReceiver.check() { - let fusd <- FUSD.createEmptyVault() - account.save(<- fusd, to: /storage/fusdVault) - account.link<&FUSD.Vault{FungibleToken.Receiver}>( /public/fusdReceiver, target: /storage/fusdVault) - account.link<&FUSD.Vault{FungibleToken.Balance}>( /public/fusdBalance, target: /storage/fusdVault) - } - ftCaps.append(fusdReceiver) - - let usdcCap = account.getCapability<&FiatToken.Vault{FungibleToken.Receiver}>(FiatToken.VaultReceiverPubPath) - if !usdcCap.check() { - account.save( <-FiatToken.createEmptyVault(), to: FiatToken.VaultStoragePath) - account.link<&FiatToken.Vault{FungibleToken.Receiver}>( FiatToken.VaultReceiverPubPath, target: FiatToken.VaultStoragePath) - account.link<&FiatToken.Vault{FiatToken.ResourceId}>( FiatToken.VaultUUIDPubPath, target: FiatToken.VaultStoragePath) - account.link<&FiatToken.Vault{FungibleToken.Balance}>( FiatToken.VaultBalancePubPath, target:FiatToken.VaultStoragePath) - } - ftCaps.append(usdcCap) - - // setup switch board - var checkSB = account.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath) - if checkSB == nil { - account.save(<- FungibleTokenSwitchboard.createSwitchboard(), to: FungibleTokenSwitchboard.StoragePath) - account.link<&FungibleTokenSwitchboard.Switchboard{FungibleTokenSwitchboard.SwitchboardPublic}>(FungibleTokenSwitchboard.PublicPath, target: FungibleTokenSwitchboard.StoragePath) - account.link<&FungibleTokenSwitchboard.Switchboard{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath, target: FungibleTokenSwitchboard.StoragePath) - checkSB = account.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath) - } - - let sb = checkSB! - let supportTypes = sb.getVaultTypes() - for cap in ftCaps { - let ref = cap.borrow()! - let typ = ref.getType() - if supportTypes.contains(typ) { - continue - } - - sb.addNewVault(capability: cap) - } - - - } -} diff --git a/transactions/setup_find_market_1_dapper.cdc b/transactions/setup_find_market_1_dapper.cdc index 64f33ee0..8bd8f3b8 100644 --- a/transactions/setup_find_market_1_dapper.cdc +++ b/transactions/setup_find_market_1_dapper.cdc @@ -1,88 +1,71 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" -import TokenForwarding from "../contracts/standard/TokenForwarding.cdc" -import FungibleTokenSwitchboard from "../contracts/standard/FungibleTokenSwitchboard.cdc" -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" +import "FindMarket" +import "FungibleToken" +import "FlowToken" +import "TokenForwarding" +import "FungibleTokenSwitchboard" +import "DapperUtilityCoin" +import "FlowUtilityToken" //Transaction that is signed by find to create a find market tenant for find transaction(dapperAddress: Address) { - prepare(acct: AuthAccount) { - //in finds case the - acct.save(<- FindMarket.createTenantClient(), to:FindMarket.TenantClientStoragePath) - acct.link<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientPublicPath, target: FindMarket.TenantClientStoragePath) + prepare(account: auth(BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability) &Account) { - // Get a Receiver reference for the Dapper account that will be the recipient of the forwarded DUC and FUT - let dapper = getAccount(dapperAddress) + //in finds case the + account.storage.save(<- FindMarket.createTenantClient(), to:FindMarket.TenantClientStoragePath) - //FUSD - let fusdReceiver = acct.getCapability<&{FungibleToken.Receiver}>(/public/fusdReceiver) - if !fusdReceiver.check() { - let fusd <- FUSD.createEmptyVault() - acct.save(<- fusd, to: /storage/fusdVault) - acct.link<&FUSD.Vault{FungibleToken.Receiver}>( /public/fusdReceiver, target: /storage/fusdVault) - acct.link<&FUSD.Vault{FungibleToken.Balance}>( /public/fusdBalance, target: /storage/fusdVault) - } + let capb = account.capabilities.storage.issue<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientStoragePath) + account.capabilities.publish(capb, at: FindMarket.TenantClientPublicPath) + + // Get a Receiver reference for the Dapper account that will be the recipient of the forwarded DUC and FUT + let dapper = getAccount(dapperAddress) - //USDC - let usdcCap = acct.getCapability<&FiatToken.Vault{FungibleToken.Receiver}>(FiatToken.VaultReceiverPubPath) - if !usdcCap.check() { - acct.save( <-FiatToken.createEmptyVault(), to: FiatToken.VaultStoragePath) - acct.link<&FiatToken.Vault{FungibleToken.Receiver}>( FiatToken.VaultReceiverPubPath, target: FiatToken.VaultStoragePath) - acct.link<&FiatToken.Vault{FiatToken.ResourceId}>( FiatToken.VaultUUIDPubPath, target: FiatToken.VaultStoragePath) - acct.link<&FiatToken.Vault{FungibleToken.Balance}>( FiatToken.VaultBalancePubPath, target:FiatToken.VaultStoragePath) - } //Dapper utility token - let dapperDUCReceiver = dapper.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) - let DUCReceiver = acct.getCapability<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) + var DUCReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) if !DUCReceiver.check(){ + let dapperDUCReceiver = dapper.capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) let ducForwarder <- TokenForwarding.createNewForwarder(recipient: dapperDUCReceiver) - acct.save(<-ducForwarder, to: /storage/dapperUtilityCoinReceiver) - acct.link<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver, target: /storage/dapperUtilityCoinReceiver) + account.storage.save(<-ducForwarder, to: /storage/dapperUtilityCoinReceiver) + DUCReceiver= account.capabilities.storage.issue<&{FungibleToken.Receiver}>(/storage/dapperUtilityCoinReceiver) + account.capabilities.publish(DUCReceiver, at: /public/dapperUtilityCoinReceiver) } //FlowUtility token - let dapperFUTReceiver = dapper.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - let FUTReceiver = acct.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) + var FUTReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) if !FUTReceiver.check(){ + let dapperFUTReceiver = dapper.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapperFUTReceiver) - acct.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) - acct.link<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver, target: /storage/flowUtilityTokenReceiver) + account.storage.save(<-futForwarder, to: /storage/flowUtilityTokenVault) + FUTReceiver= account.capabilities.storage.issue<&{FungibleToken.Receiver}>(/storage/flowUtilityTokenVault) + account.capabilities.publish(FUTReceiver, at: /public/flowUtilityTokenReceiver) + } + + let switchboardRef = account.storage.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath) + if switchboardRef == nil { + let sb <- FungibleTokenSwitchboard.createSwitchboard() + account.storage.save(<- sb, to: FungibleTokenSwitchboard.StoragePath) + + let cap = account.capabilities.storage.issue<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.StoragePath) + account.capabilities.publish(cap, at: FungibleTokenSwitchboard.ReceiverPublicPath) + + let capb = account.capabilities.storage.issue<&{FungibleTokenSwitchboard.SwitchboardPublic,FungibleToken.Receiver}>(FungibleTokenSwitchboard.StoragePath) + account.capabilities.publish(capb, at: FungibleTokenSwitchboard.PublicPath) } - let switchboardRef = acct.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath) - if switchboardRef == nil{ - let sb <- FungibleTokenSwitchboard.createSwitchboard() - acct.save(<- sb, to: FungibleTokenSwitchboard.StoragePath) - acct.link<&FungibleTokenSwitchboard.Switchboard{FungibleToken.Receiver}>( FungibleTokenSwitchboard.ReceiverPublicPath, target: FungibleTokenSwitchboard.StoragePath) - acct.link<&FungibleTokenSwitchboard.Switchboard{FungibleTokenSwitchboard.SwitchboardPublic, FungibleToken.Receiver}>( - FungibleTokenSwitchboard.PublicPath, - target: FungibleTokenSwitchboard.StoragePath - ) - } - let switchboard = acct.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath)! - let types = switchboard.getVaultTypes() - if !types.contains(Type<@DapperUtilityCoin.Vault>()) { - switchboard.addNewVaultWrapper(capability: dapperDUCReceiver, type: Type<@DapperUtilityCoin.Vault>()) - } - if !types.contains(Type<@FlowUtilityToken.Vault>()) { - switchboard.addNewVaultWrapper(capability: dapperFUTReceiver, type: Type<@FlowUtilityToken.Vault>()) - } - if !types.contains(usdcCap.borrow()!.getType()) { - switchboard.addNewVault(capability: usdcCap) - } - if !types.contains(fusdReceiver.borrow()!.getType()) { - switchboard.addNewVault(capability: fusdReceiver) - } - let flowTokenCap = acct.getCapability<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) - if !types.contains(flowTokenCap.borrow()!.getType()) { - switchboard.addNewVault(capability: flowTokenCap) - } + let switchboard = account.storage.borrow(from: FungibleTokenSwitchboard.StoragePath)! + + if !switchboard.isSupportedVaultType(type:Type<@DapperUtilityCoin.Vault>()) { + switchboard.addNewVaultWrapper(capability: DUCReceiver, type: Type<@DapperUtilityCoin.Vault>()) + } + if !switchboard.isSupportedVaultType(type: Type<@FlowUtilityToken.Vault>()) { + switchboard.addNewVaultWrapper(capability: FUTReceiver, type: Type<@FlowUtilityToken.Vault>()) + } + let flowTokenCap = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + if !switchboard.isSupportedVaultType(type: flowTokenCap.borrow()!.getType()) { + switchboard.addNewVault(capability: flowTokenCap) + } } } + diff --git a/transactions/setup_find_market_2.cdc b/transactions/setup_find_market_2.cdc index bef833a1..c3031ed6 100644 --- a/transactions/setup_find_market_2.cdc +++ b/transactions/setup_find_market_2.cdc @@ -1,43 +1,43 @@ -import FindMarketAdmin from "../contracts/FindMarketAdmin.cdc" -import FindMarket from "../contracts/FindMarket.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" - -//signed by admin to link tenantClient to a new tenant +import "FindMarketAdmin" +import "FindMarket" +import "FlowToken" +import "DapperUtilityCoin" +import "FlowUtilityToken" +import "MetadataViews" +import "FungibleToken" + transaction(tenant: String, tenantAddress: Address, findCut: UFix64) { - //versus account - prepare(account: AuthAccount) { - let adminClient=account.borrow<&FindMarketAdmin.AdminProxy>(from: FindMarketAdmin.AdminProxyStoragePath)! - - // pass in the default cut rules here - let rules = [ - FindMarket.TenantRule( name:"standard ft", types:[Type<@FUSD.Vault>(), Type<@FlowToken.Vault>(), Type<@FiatToken.Vault>(), Type<@DapperUtilityCoin.Vault>() , Type<@FlowUtilityToken.Vault>()], ruleType:"ft", allow:true) - ] - - let royalty = MetadataViews.Royalty( - receiver: adminClient.getSwitchboardReceiverPublic(), - cut: findCut, - description: "find" - ) - - let saleItem = FindMarket.TenantSaleItem( - name: "findRoyalty", - cut: royalty, - rules : rules, - status: "active", - ) - - //We create a tenant that has both auctions and direct offers - let tenantCap= adminClient.createFindMarket(name: tenant, address: tenantAddress, findCutSaleItem: saleItem) - - let tenantAccount=getAccount(tenantAddress) - let tenantClient=tenantAccount.getCapability<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientPublicPath).borrow()! - tenantClient.addCapability(tenantCap) - } + + prepare(account: auth(BorrowValue) &Account) { + let adminClient=account.storage.borrow(from: FindMarketAdmin.AdminProxyStoragePath)! + + // pass in the default cut rules here + let rules = [ + FindMarket.TenantRule( name:"standard ft", types:[ + Type<@FlowToken.Vault>(), + Type<@DapperUtilityCoin.Vault>() , + Type<@FlowUtilityToken.Vault>()], ruleType:"ft", allow:true) + ] + + let royalty = MetadataViews.Royalty( + receiver: adminClient.getSwitchboardReceiverPublic(), + cut: findCut, + description: "find" + ) + + let saleItem = FindMarket.TenantSaleItem( + name: "findRoyalty", + cut: royalty, + rules : rules, + status: "active", + ) + + //We create a tenant that has both auctions and direct offers + let tenantCap= adminClient.createFindMarket(name: tenant, address: tenantAddress, findCutSaleItem: saleItem) + + let tenantAccount=getAccount(tenantAddress) + let tenantClient=tenantAccount.capabilities.borrow<&{FindMarket.TenantClientPublic}>(FindMarket.TenantClientPublicPath)! + tenantClient.addCapability(tenantCap) + } } diff --git a/transactions/setup_royalty_receiver.cdc b/transactions/setup_royalty_receiver.cdc new file mode 100644 index 00000000..628f658c --- /dev/null +++ b/transactions/setup_royalty_receiver.cdc @@ -0,0 +1,81 @@ +import FungibleToken from 0xf233dcee88fe0abe +import FlowToken from 0x1654653399040a61 +import TokenForwarding from 0xe544175ee0461c4b +import FungibleTokenSwitchboard from 0xf233dcee88fe0abe +import DapperUtilityCoin from 0xead892083b3e2c6c +import EVMVMBridgedToken_2aabea2058b5ac2d339b163c6ab6f2b6d53aabedVault from 0x1e4aa0b87d10b141 //USDF +/* +* +* This Transasction set up a flow account to receive royalty from both flow and dapper transactions. +* +* For DUC/FUT the flow is -> ->
. So all DUC/FUT end up back at where they belong +*/ +transaction(dapperAddress: Address) { + prepare(account: auth(BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability) &Account) { + + // Get a Receiver reference for the Dapper account that will be the recipient of the forwarded DUC and FUT + let dapper = getAccount(dapperAddress) + + //lets set up the fungible token switchboard so that we can register tokens in it + let switchboardRef = account.storage.borrow<&FungibleTokenSwitchboard.Switchboard>(from: FungibleTokenSwitchboard.StoragePath) + if switchboardRef == nil { + let sb <- FungibleTokenSwitchboard.createSwitchboard() + account.storage.save(<- sb, to: FungibleTokenSwitchboard.StoragePath) + + let cap = account.capabilities.storage.issue<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.StoragePath) + account.capabilities.publish(cap, at: FungibleTokenSwitchboard.ReceiverPublicPath) + + let capb = account.capabilities.storage.issue<&{FungibleTokenSwitchboard.SwitchboardPublic,FungibleToken.Receiver}>(FungibleTokenSwitchboard.StoragePath) + account.capabilities.publish(capb, at: FungibleTokenSwitchboard.PublicPath) + } + + + let switchboard = account.storage.borrow(from: FungibleTokenSwitchboard.StoragePath)! + + + //Dapper utility token + var ducReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) + if !ducReceiver.check(){ + let dapperducReceiver = dapper.capabilities.get<&{FungibleToken.Receiver}>(/public/dapperUtilityCoinReceiver) + let ducForwarder <- TokenForwarding.createNewForwarder(recipient: dapperducReceiver) + account.storage.save(<-ducForwarder, to: /storage/dapperUtilityCoinReceiver) + ducReceiver= account.capabilities.storage.issue<&{FungibleToken.Receiver}>(/storage/dapperUtilityCoinReceiver) + account.capabilities.publish(ducReceiver, at: /public/dapperUtilityCoinReceiver) + } + if !switchboard.isSupportedVaultType(type:Type<@DapperUtilityCoin.Vault>()) { + switchboard.addNewVaultWrapper(capability: ducReceiver, type: Type<@DapperUtilityCoin.Vault>()) + } + + + //USDF + let usdfStoragePath = /storage/EVMVMBridgedToken_2aabea2058b5ac2d339b163c6ab6f2b6d53aabedVault + let usdfBalancePath = /public/EVMVMBridgedToken_2aabea2058b5ac2d339b163c6ab6f2b6d53aabedVault + + let usdfPublicPath = /public/EVMVMBridgedToken_2aabea2058b5ac2d339b163c6ab6f2b6d53aabedReceiver + let usdfType=Type<@EVMVMBridgedToken_2aabea2058b5ac2d339b163c6ab6f2b6d53aabed.Vault>() + var usdfReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(usdfPublicPath) + + if !usdfReceiver.check(){ + let vault <- EVMVMBridgedToken_2aabea2058b5ac2d339b163c6ab6f2b6d53aabed.createEmptyVault(vaultType:usdfType) + account.storage.save(<-vault, to: usdfStoragePath) + + let usdfReceiverBalance= account.capabilities.storage.issue<&{FungibleToken.Balance}>(usdfStoragePath) + account.capabilities.publish(usdfReceiverBalance, at: usdfBalancePath) + + usdfReceiver= account.capabilities.storage.issue<&{FungibleToken.Receiver}>(usdfStoragePath) + account.capabilities.publish(usdfReceiver, at: usdfPublicPath) + } + + if !switchboard.isSupportedVaultType(type:usdfType) { + switchboard.addNewVaultWrapper(capability: usdfReceiver, type:usdfType) + } + + //FLOW + let flowTokenCap = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + if !switchboard.isSupportedVaultType(type: flowTokenCap.borrow()!.getType()) { + switchboard.addNewVault(capability: flowTokenCap) + } + + } +} + diff --git a/transactions/startNameAuction.cdc b/transactions/startNameAuction.cdc deleted file mode 100644 index 05c32186..00000000 --- a/transactions/startNameAuction.cdc +++ /dev/null @@ -1,18 +0,0 @@ -import FIND from "../contracts/FIND.cdc" - -transaction(name: String) { - - let finLeases : &FIND.LeaseCollection? - - prepare(account: AuthAccount) { - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) - } - - pre{ - self.finLeases != nil : "Cannot borrow reference to find lease collection" - } - - execute{ - self.finLeases!.startAuction(name) - } -} diff --git a/transactions/storeCuratedCollections.cdc b/transactions/storeCuratedCollections.cdc index 36b7b12a..eac6aad0 100644 --- a/transactions/storeCuratedCollections.cdc +++ b/transactions/storeCuratedCollections.cdc @@ -1,14 +1,14 @@ transaction(collections: {String : [String]}) { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { let path=/storage/FindCuratedCollections let publicPath=/public/FindCuratedCollections - if account.borrow<&{String: [String]}>(from:path) != nil { + if account.storage.borrow<&{String: [String]}>(from:path) != nil { account.load<{String: [String]}>(from:path) } - account.save(collections, to: path) + account.storage.save(collections, to: path) let link = account.getCapability<&{String: [String]}>(publicPath) if !link.check() { diff --git a/transactions/tenantsetExtraCut.cdc b/transactions/tenantsetExtraCut.cdc index 1ce0eb43..0cfddaea 100644 --- a/transactions/tenantsetExtraCut.cdc +++ b/transactions/tenantsetExtraCut.cdc @@ -1,17 +1,17 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketCutStruct from "../contracts/FindMarketCutStruct.cdc" +import "FindMarket" +import "FindMarketCutStruct" transaction(ftTypes: [String], category: String, cuts: [FindMarketCutStruct.ThresholdCut]){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ - let types : [Type] = [] - for t in ftTypes { - types.append(CompositeType(t)!) - } + let types : [Type] = [] + for t in ftTypes { + types.append(CompositeType(t)!) + } - let allCuts = FindMarketCutStruct.Cuts(cuts) + let allCuts = FindMarketCutStruct.Cuts(cuts:cuts) - let clientRef = account.borrow<&FindMarket.TenantClient>(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") + let clientRef = account.storage.borrow(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") clientRef.setExtraCut(types: types, category: category, cuts: allCuts) } } diff --git a/transactions/tenantsetLeaseOptionDapper.cdc b/transactions/tenantsetLeaseOptionDapper.cdc index 92aceee8..ac06d76e 100644 --- a/transactions/tenantsetLeaseOptionDapper.cdc +++ b/transactions/tenantsetLeaseOptionDapper.cdc @@ -1,15 +1,15 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import FindLeaseMarketSale from "../contracts/FindLeaseMarketSale.cdc" -import FindLeaseMarketAuctionSoft from "../contracts/FindLeaseMarketAuctionSoft.cdc" -import FindLeaseMarketDirectOfferSoft from "../contracts/FindLeaseMarketDirectOfferSoft.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FungibleTokenSwitchboard from "../contracts/standard/FungibleTokenSwitchboard.cdc" +import "FindMarket" +import "DapperUtilityCoin" +import "FlowUtilityToken" +import "FindLeaseMarketSale" +import "FindLeaseMarketAuctionSoft" +import "FindLeaseMarketDirectOfferSoft" +import "MetadataViews" +import "FungibleToken" +import "FungibleTokenSwitchboard" transaction(nftName: String, nftType: String, cut: UFix64){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ let defaultRules : [FindMarket.TenantRule] = [ FindMarket.TenantRule( @@ -41,7 +41,7 @@ transaction(nftName: String, nftType: String, cut: UFix64){ var royalty : MetadataViews.Royalty? = nil if cut != 0.0 { royalty = MetadataViews.Royalty( - receiver: account.getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath), + receiver: account.capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath)!, cut: cut, description: "tenant" ) @@ -54,7 +54,7 @@ transaction(nftName: String, nftType: String, cut: UFix64){ status: "active" ) - let clientRef = account.borrow<&FindMarket.TenantClient>(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") + let clientRef = account.storage.borrow(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") clientRef.setMarketOption(saleItem: saleItem) } } diff --git a/transactions/tenantsetLeaseOptionMarket.cdc b/transactions/tenantsetLeaseOptionMarket.cdc new file mode 100644 index 00000000..ede7c72a --- /dev/null +++ b/transactions/tenantsetLeaseOptionMarket.cdc @@ -0,0 +1,60 @@ +import "FindMarket" +import "FlowToken" +import "FindLeaseMarketSale" +import "FindLeaseMarketAuctionSoft" +import "FindLeaseMarketDirectOfferSoft" +import "MetadataViews" +import "FungibleToken" +import "FungibleTokenSwitchboard" + +transaction(nftName: String, nftType: String, cut: UFix64){ + prepare(account: auth(BorrowValue) &Account){ + + let defaultRules : [FindMarket.TenantRule] = [ + FindMarket.TenantRule( + name: "Flow", + types:[Type<@FlowToken.Vault>()], + ruleType: "ft", + allow:true + ), + FindMarket.TenantRule( + name: "Soft", + types:[Type<@FindLeaseMarketSale.SaleItem>(), + Type<@FindLeaseMarketAuctionSoft.SaleItem>(), + Type<@FindLeaseMarketDirectOfferSoft.SaleItem>() + ], + ruleType: "listing", + allow:true + ) + ] + + defaultRules.append( + FindMarket.TenantRule( + name: nftName, + types:[CompositeType(nftType)!], + ruleType: "nft", + allow:true + ) + ) + + var royalty : MetadataViews.Royalty? = nil + if cut != 0.0 { + royalty = MetadataViews.Royalty( + receiver: account.capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath), + cut: cut, + description: "tenant" + ) + } + + let saleItem = FindMarket.TenantSaleItem( + name: "Flow".concat(nftName).concat("Soft"), + cut: royalty, + rules: defaultRules, + status: "active" + ) + + let clientRef = account.storage.borrow(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") + clientRef.setMarketOption(saleItem: saleItem) + } +} + diff --git a/transactions/tenantsetMarketOption.cdc b/transactions/tenantsetMarketOption.cdc index 1d933357..8d97ada6 100644 --- a/transactions/tenantsetMarketOption.cdc +++ b/transactions/tenantsetMarketOption.cdc @@ -1,62 +1,64 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import FindMarketAuctionEscrow from "../contracts/FindMarketAuctionEscrow.cdc" -import FindMarketDirectOfferEscrow from "../contracts/FindMarketDirectOfferEscrow.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FungibleTokenSwitchboard from "../contracts/standard/FungibleTokenSwitchboard.cdc" +import "FindMarket" +import "FlowToken" +import "FindMarketSale" +import "DapperUtilityCoin" +import "FlowUtilityToken" +import "FindMarketAuctionEscrow" +import "FindMarketDirectOfferEscrow" +import "MetadataViews" +import "FungibleToken" +import "FungibleTokenSwitchboard" transaction(nftName: String, nftTypes: [String], cut: UFix64){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ - let nfts : [Type] = [] - for t in nftTypes { - nfts.append(CompositeType(t)!) - } + let nfts : [Type] = [] + for t in nftTypes { + nfts.append(CompositeType(t)!) + } - let defaultRules : [FindMarket.TenantRule] = [ - FindMarket.TenantRule( - name: "Flow", - types:[ - Type<@FlowToken.Vault>() - ], - ruleType: "ft", - allow:true - ), - FindMarket.TenantRule( - name: nftName, - types:nfts, - ruleType: "nft", - allow:true - ), - FindMarket.TenantRule( - name: "Escrow", - types:[Type<@FindMarketSale.SaleItem>(), Type<@FindMarketAuctionEscrow.SaleItem>(), Type<@FindMarketDirectOfferEscrow.SaleItem>()], - ruleType: "listing", - allow:true - ) - ] + let defaultRules : [FindMarket.TenantRule] = [ + FindMarket.TenantRule( + name: "Standard", + types:[ + Type<@DapperUtilityCoin.Vault>(), + Type<@FlowUtilityToken.Vault>(), + Type<@FlowToken.Vault>() + ], + ruleType: "ft", + allow:true + ), + FindMarket.TenantRule( + name: nftName, + types:nfts, + ruleType: "nft", + allow:true + ), + FindMarket.TenantRule( + name: "Escrow", + types:[Type<@FindMarketSale.SaleItem>(), Type<@FindMarketAuctionEscrow.SaleItem>(), Type<@FindMarketDirectOfferEscrow.SaleItem>()], + ruleType: "listing", + allow:true + ) + ] - var royalty : MetadataViews.Royalty? = nil - if cut != 0.0 { - royalty = MetadataViews.Royalty( - receiver: account.getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath), - cut: cut, - description: "tenant" - ) - } + var royalty : MetadataViews.Royalty? = nil + if cut != 0.0 { + royalty = MetadataViews.Royalty( + receiver: account.capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath)!, + cut: cut, + description: "tenant" + ) + } - let saleItem = FindMarket.TenantSaleItem( - name: "Flow".concat(nftName).concat("Escrow"), - cut: royalty, - rules: defaultRules, - status: "active" - ) + let saleItem = FindMarket.TenantSaleItem( + name: "Flow".concat(nftName).concat("Escrow"), + cut: royalty, + rules: defaultRules, + status: "active" + ) - let clientRef = account.borrow<&FindMarket.TenantClient>(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") + let clientRef = account.storage.borrow(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") clientRef.setMarketOption(saleItem: saleItem) } } diff --git a/transactions/tenantsetMarketOptionDUC.cdc b/transactions/tenantsetMarketOptionDUC.cdc index 3d183a24..9d4d79c4 100644 --- a/transactions/tenantsetMarketOptionDUC.cdc +++ b/transactions/tenantsetMarketOptionDUC.cdc @@ -1,69 +1,69 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import FindLeaseMarketSale from "../contracts/FindLeaseMarketSale.cdc" -import FindLeaseMarketAuctionSoft from "../contracts/FindLeaseMarketAuctionSoft.cdc" -import FindLeaseMarketDirectOfferSoft from "../contracts/FindLeaseMarketDirectOfferSoft.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FungibleTokenSwitchboard from "../contracts/standard/FungibleTokenSwitchboard.cdc" +import "FindMarket" +import "DapperUtilityCoin" +import "FlowUtilityToken" +import "FindLeaseMarketSale" +import "FindLeaseMarketAuctionSoft" +import "FindLeaseMarketDirectOfferSoft" +import "MetadataViews" +import "FungibleToken" +import "FungibleTokenSwitchboard" transaction(nftName: String, nftTypes: [String], cut: UFix64){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ - let nfts : [Type] = [] - for t in nftTypes { - nfts.append(CompositeType(t)!) - } + let nfts : [Type] = [] + for t in nftTypes { + nfts.append(CompositeType(t)!) + } - let defaultRules : [FindMarket.TenantRule] = [ - FindMarket.TenantRule( - name: "Dapper", - types:[ - // Type<@FlowUtilityToken.Vault>(), - Type<@DapperUtilityCoin.Vault>() - ], - ruleType: "ft", - allow:true - ), - FindMarket.TenantRule( - name: "Soft", - types:[ - Type<@FindLeaseMarketSale.SaleItem>(), - Type<@FindLeaseMarketAuctionSoft.SaleItem>(), - Type<@FindLeaseMarketDirectOfferSoft.SaleItem>() - ], - ruleType: "listing", - allow:true - ) - ] + let defaultRules : [FindMarket.TenantRule] = [ + FindMarket.TenantRule( + name: "Dapper", + types:[ + // Type<@FlowUtilityToken.Vault>(), + Type<@DapperUtilityCoin.Vault>() + ], + ruleType: "ft", + allow:true + ), + FindMarket.TenantRule( + name: "Soft", + types:[ + Type<@FindLeaseMarketSale.SaleItem>() + // Type<@FindLeaseMarketAuctionSoft.SaleItem>(), + // Type<@FindLeaseMarketDirectOfferSoft.SaleItem>() + ], + ruleType: "listing", + allow:true + ) + ] - defaultRules.append( - FindMarket.TenantRule( - name: nftName, - types:nfts, - ruleType: "nft", - allow:true - ) - ) + defaultRules.append( + FindMarket.TenantRule( + name: nftName, + types:nfts, + ruleType: "nft", + allow:true + ) + ) - var royalty : MetadataViews.Royalty? = nil - if cut != 0.0 { - royalty = MetadataViews.Royalty( - receiver: account.getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath), - cut: cut, - description: "tenant" - ) - } + var royalty : MetadataViews.Royalty? = nil + if cut != 0.0 { + royalty = MetadataViews.Royalty( + receiver: account.capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath)!, + cut: cut, + description: "tenant" + ) + } - let saleItem = FindMarket.TenantSaleItem( - name: "Dapper".concat(nftName).concat("Soft"), - cut: royalty, - rules: defaultRules, - status: "active" - ) + let saleItem = FindMarket.TenantSaleItem( + name: "Dapper".concat(nftName).concat("Soft"), + cut: royalty, + rules: defaultRules, + status: "active" + ) - let clientRef = account.borrow<&FindMarket.TenantClient>(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") + let clientRef = account.storage.borrow(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") clientRef.setMarketOption(saleItem: saleItem) } } diff --git a/transactions/tenantsetMarketOptionDapper.cdc b/transactions/tenantsetMarketOptionDapper.cdc index 64e82b1d..1385303a 100644 --- a/transactions/tenantsetMarketOptionDapper.cdc +++ b/transactions/tenantsetMarketOptionDapper.cdc @@ -1,69 +1,69 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import FindMarketAuctionSoft from "../contracts/FindMarketAuctionSoft.cdc" -import FindMarketDirectOfferSoft from "../contracts/FindMarketDirectOfferSoft.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FungibleTokenSwitchboard from "../contracts/standard/FungibleTokenSwitchboard.cdc" +import "FindMarket" +import "DapperUtilityCoin" +import "FlowUtilityToken" +import "FindMarketSale" +import "FindMarketAuctionSoft" +import "FindMarketDirectOfferSoft" +import "MetadataViews" +import "FungibleToken" +import "FungibleTokenSwitchboard" transaction(nftName: String, nftTypes: [String], cut: UFix64){ - prepare(account: AuthAccount){ + prepare(account: auth(BorrowValue) &Account){ - let defaultRules : [FindMarket.TenantRule] = [ - FindMarket.TenantRule( - name: "Dapper", - types:[ - Type<@FlowUtilityToken.Vault>(), - Type<@DapperUtilityCoin.Vault>() - ], - ruleType: "ft", - allow:true - ), - FindMarket.TenantRule( - name: "Soft", - types:[ - Type<@FindMarketSale.SaleItem>() - // Type<@FindMarketAuctionSoft.SaleItem>(), - // Type<@FindMarketDirectOfferSoft.SaleItem>() - ], - ruleType: "listing", - allow:true - ) - ] + let defaultRules : [FindMarket.TenantRule] = [ + FindMarket.TenantRule( + name: "Dapper", + types:[ + Type<@FlowUtilityToken.Vault>(), + Type<@DapperUtilityCoin.Vault>() + ], + ruleType: "ft", + allow:true + ), + FindMarket.TenantRule( + name: "Soft", + types:[ + Type<@FindMarketSale.SaleItem>(), + Type<@FindMarketAuctionSoft.SaleItem>(), + Type<@FindMarketDirectOfferSoft.SaleItem>() + ], + ruleType: "listing", + allow:true + ) + ] - let nfts : [Type] = [] - for t in nftTypes { - nfts.append(CompositeType(t)!) - } + let nfts : [Type] = [] + for t in nftTypes { + nfts.append(CompositeType(t)!) + } - defaultRules.append( - FindMarket.TenantRule( - name: nftName, - types:nfts, - ruleType: "nft", - allow:true - ) - ) + defaultRules.append( + FindMarket.TenantRule( + name: nftName, + types:nfts, + ruleType: "nft", + allow:true + ) + ) - var royalty : MetadataViews.Royalty? = nil - if cut != 0.0 { - royalty = MetadataViews.Royalty( - receiver: account.getCapability<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath), - cut: cut, - description: "tenant" - ) - } + var royalty : MetadataViews.Royalty? = nil + if cut != 0.0 { + royalty = MetadataViews.Royalty( + receiver: account.capabilities.get<&{FungibleToken.Receiver}>(FungibleTokenSwitchboard.ReceiverPublicPath), + cut: cut, + description: "tenant" + ) + } - let saleItem = FindMarket.TenantSaleItem( - name: "Dapper".concat(nftName).concat("Soft"), - cut: royalty, - rules: defaultRules, - status: "active" - ) + let saleItem = FindMarket.TenantSaleItem( + name: "Dapper".concat(nftName).concat("Soft"), + cut: royalty, + rules: defaultRules, + status: "active" + ) - let clientRef = account.borrow<&FindMarket.TenantClient>(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") + let clientRef = account.storage.borrow(from: FindMarket.TenantClientStoragePath) ?? panic("Cannot borrow Tenant Client Reference.") clientRef.setMarketOption(saleItem: saleItem) } } diff --git a/transactions/testInitFUSDVault.cdc b/transactions/testInitFUSDVault.cdc deleted file mode 100644 index 71d02eb6..00000000 --- a/transactions/testInitFUSDVault.cdc +++ /dev/null @@ -1,17 +0,0 @@ -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import FUSD from "../contracts/standard/FUSD.cdc" -import FiatToken from "../contracts/standard/FiatToken.cdc" - - -transaction() { - prepare(account: AuthAccount) { - let fusdReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/fusdReceiver) - if !fusdReceiver.check() { - let fusd <- FUSD.createEmptyVault() - account.save(<- fusd, to: /storage/fusdVault) - account.link<&FUSD.Vault{FungibleToken.Receiver}>( /public/fusdReceiver, target: /storage/fusdVault) - account.link<&FUSD.Vault{FungibleToken.Balance}>( /public/fusdBalance, target: /storage/fusdVault) - } - - } -} diff --git a/transactions/testnetRegisterFlow.cdc b/transactions/testnetRegisterFlow.cdc deleted file mode 100644 index f322ebfa..00000000 --- a/transactions/testnetRegisterFlow.cdc +++ /dev/null @@ -1,55 +0,0 @@ -import FiatToken from "../contracts/standard/FiatToken.cdc" -import FlowToken from "../contracts/standard/FlowToken.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" -import SwapRouter from "../contracts/community/SwapRouter.cdc" -import FIND from "../contracts/FIND.cdc" - -transaction( - name: String, - amountInMax: UFix64, - exactAmountOut: UFix64, -) { - - let payVault : @FiatToken.Vault - let leases : &FIND.LeaseCollection? - let price : UFix64 - - - prepare(userAccount: AuthAccount) { - - self.price=FIND.calculateCost(name) - self.leases=userAccount.borrow<&FIND.LeaseCollection>(from: FIND.LeaseStoragePath) - - let deadline = getCurrentBlock().timestamp + 1000.0 - let tokenInVaultPath = /storage/flowTokenVault - let tokenOutReceiverPath = /public/USDCVaultReceiver - - let inVaultRef = userAccount.borrow<&FungibleToken.Vault>(from: tokenInVaultPath) ?? panic("Could not borrow reference to the owner's in FT.Vault") - - let path = [ "A.7e60df042a9c0868.FlowToken", "A.a983fecbed621163.FiatToken" ] - - let vaultInMax <- inVaultRef.withdraw(amount: amountInMax) - let swapResVault <- SwapRouter.swapTokensForExactTokens( - vaultInMax: <-vaultInMax, - exactAmountOut: exactAmountOut, - tokenKeyPath: path, - deadline: deadline - ) - - let tempVault <- swapResVault.removeFirst() - self.payVault <- tempVault as! @FiatToken.Vault - let vaultInLeft <- swapResVault.removeLast() - destroy swapResVault - inVaultRef.deposit(from: <-vaultInLeft) - } - - pre{ - self.leases != nil : "Could not borrow reference to find lease collection" - self.price == exactAmountOut : "Calculated cost : ".concat(self.price.toString()).concat(" does not match expected cost : ").concat(exactAmountOut.toString()) - } - - execute{ - self.leases!.registerUSDC(name: name, vault: <- self.payVault) - } - -} diff --git a/transactions/testnetlistNFTForSaleDapper.cdc b/transactions/testnetlistNFTForSaleDapper.cdc index 3da3e0a3..6d61d051 100644 --- a/transactions/testnetlistNFTForSaleDapper.cdc +++ b/transactions/testnetlistNFTForSaleDapper.cdc @@ -1,21 +1,21 @@ -import FindMarket from "../contracts/FindMarket.cdc" -import FindMarketSale from "../contracts/FindMarketSale.cdc" -import FINDNFTCatalog from "../contracts/FINDNFTCatalog.cdc" -import FTRegistry from "../contracts/FTRegistry.cdc" -import FindViews from "../contracts/FindViews.cdc" -import NonFungibleToken from "../contracts/standard/NonFungibleToken.cdc" -import MetadataViews from "../contracts/standard/MetadataViews.cdc" -import FlowUtilityToken from "../contracts/standard/FlowUtilityToken.cdc" -import TokenForwarding from "../contracts/standard/TokenForwarding.cdc" -import FungibleToken from "../contracts/standard/FungibleToken.cdc" +import "FindMarket" +import "FindMarketSale" +import "FINDNFTCatalog" +import "FTRegistry" +import "FindViews" +import "NonFungibleToken" +import "MetadataViews" +import "FlowUtilityToken" +import "TokenForwarding" +import "FungibleToken" transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: String, directSellPrice:UFix64, validUntil: UFix64?) { - let saleItems : &FindMarketSale.SaleItemCollection? + let saleItems : auth(FindMarketSale.Seller) &FindMarketSale.SaleItemCollection? let pointer : FindViews.AuthNFTPointer let vaultType : Type - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { let marketplace = FindMarket.getFindTenantAddress() let saleItemType= Type<@FindMarketSale.SaleItemCollection>() @@ -31,7 +31,7 @@ transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: Strin let saleItemCap= account.getCapability<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath) if !saleItemCap.check() { //The link here has to be a capability not a tenant, because it can change. - account.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) + account.storage.save<@FindMarketSale.SaleItemCollection>(<- FindMarketSale.createEmptySaleItemCollection(tenantCapability), to: storagePath) account.link<&FindMarketSale.SaleItemCollection{FindMarketSale.SaleItemCollectionPublic, FindMarket.SaleItemCollectionPublic}>(publicPath, target: storagePath) } @@ -42,26 +42,26 @@ transaction(nftAliasOrIdentifier: String, id: UInt64, ftAliasOrIdentifier: Strin let ft = FTRegistry.getFTInfo(ftAliasOrIdentifier) ?? panic("This FT is not supported by the Find Market yet. Type : ".concat(ftAliasOrIdentifier)) - let futReceiver = account.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) - if ft.type == Type<@FlowUtilityToken.Vault>() && !futReceiver.check() { + let futReceiver = account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver) + if ft.type == Type<@FlowUtilityToken.Vault>() && !futReceiver!.check() { // Create a new Forwarder resource for FUT and store it in the new account's storage - let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapper.getCapability<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver)) - account.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) + let futForwarder <- TokenForwarding.createNewForwarder(recipient: dapper.capabilities.get<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver)) + account.storage.save(<-futForwarder, to: /storage/flowUtilityTokenReceiver) // Publish a Receiver capability for the new account, which is linked to the FUT Forwarder account.link<&{FungibleToken.Receiver}>(/public/flowUtilityTokenReceiver,target: /storage/flowUtilityTokenReceiver) } - let providerCap=account.getCapability<&{NonFungibleToken.Provider, MetadataViews.ResolverCollection, NonFungibleToken.CollectionPublic}>(nft.privatePath) + let var providerCap=account.capabilities.storage.get<&{NonFungibleToken.Provider, ViewResolver.ResolverCollection, NonFungibleToken.Collection}>(nft.storagePath) if !providerCap.check() { - account.link<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>( + account.link<&{NonFungibleToken.Provider, NonFungibleToken.Collection, NonFungibleToken.Receiver, ViewResolver.ResolverCollection}>( nft.privatePath, target: nft.storagePath ) } // Get the salesItemRef from tenant - self.saleItems= account.borrow<&FindMarketSale.SaleItemCollection>(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) + self.saleItems= account.storage.borrow(from: tenant.getStoragePath(Type<@FindMarketSale.SaleItemCollection>())) self.pointer= FindViews.AuthNFTPointer(cap: providerCap, id: id) self.vaultType= ft.type } diff --git a/transactions/testnetregisterDapper.cdc b/transactions/testnetregisterDapper.cdc index 1af2e171..dbbea62f 100644 --- a/transactions/testnetregisterDapper.cdc +++ b/transactions/testnetregisterDapper.cdc @@ -1,20 +1,21 @@ -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FIND from "../contracts/FIND.cdc" +import "DapperUtilityCoin" +import "FIND" +import "FungibleToken" transaction(merchAccount: Address, name: String, amount: UFix64) { - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault + let finLeases : auth(FIND.LeaseOwner) &FIND.LeaseCollection + let mainDapperUtilityCoinVault: auth(FungibleToken.Withdraw) &DapperUtilityCoin.Vault let balanceBeforeTransfer: UFix64 let price : UFix64 - prepare(dapper: AuthAccount, account: AuthAccount) { + prepare(dapper: auth(StorageCapabilities, SaveValue,PublishCapability, BorrowValue) &Account, account: auth(BorrowValue) &Account) { self.price=FIND.calculateCost(name) log("The cost for registering this name is ".concat(self.price.toString())) - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) + self.mainDapperUtilityCoinVault = dapper.storage.borrow(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance - self.finLeases= account.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") + self.finLeases= account.storage.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") } pre{ diff --git a/transactions/testnetrenewNameDapper.cdc b/transactions/testnetrenewNameDapper.cdc index 39c80637..f6f47491 100644 --- a/transactions/testnetrenewNameDapper.cdc +++ b/transactions/testnetrenewNameDapper.cdc @@ -1,16 +1,17 @@ -import DapperUtilityCoin from "../contracts/standard/DapperUtilityCoin.cdc" -import FIND from "../contracts/FIND.cdc" +import "DapperUtilityCoin" +import "FIND" +import "FungibleToken" transaction(merchAccount: Address, name: String, amount: UFix64) { let price : UFix64 - let finLeases : &FIND.LeaseCollection - let mainDapperUtilityCoinVault: &DapperUtilityCoin.Vault + let finLeases : auth(FIND.LeaseOwner) &FIND.LeaseCollection + let mainDapperUtilityCoinVault: auth(FungibleToken.Withdraw) &DapperUtilityCoin.Vault let balanceBeforeTransfer: UFix64 - prepare(dapper: AuthAccount, acct: AuthAccount) { + prepare(dapper: auth(StorageCapabilities, SaveValue,PublishCapability, BorrowValue) &Account, acct: auth(BorrowValue, FIND.LeaseOwner) &Account) { self.price=FIND.calculateCost(name) - self.mainDapperUtilityCoinVault = dapper.borrow<&DapperUtilityCoin.Vault>(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) + self.mainDapperUtilityCoinVault = dapper.storage.borrow(from: /storage/dapperUtilityCoinVault) ?? panic("Cannot borrow DapperUtilityCoin vault from account storage".concat(dapper.address.toString())) self.balanceBeforeTransfer = self.mainDapperUtilityCoinVault.balance self.finLeases= acct.borrow<&FIND.LeaseCollection>(from:FIND.LeaseStoragePath) ?? panic("Could not borrow reference to find lease collection") } diff --git a/transactions/unfollow.cdc b/transactions/unfollow.cdc index 5af4adbd..53f28c5c 100644 --- a/transactions/unfollow.cdc +++ b/transactions/unfollow.cdc @@ -1,22 +1,22 @@ -import FIND from "../contracts/FIND.cdc" -import Profile from "../contracts/Profile.cdc" +import "FIND" +import "Profile" // array of [User in string (find name or address)] transaction(unfollows:[String]) { - let profile : &Profile.User + let profile : auth(Profile.Admin) &Profile.User - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue, Profile.Admin) &Account) { - self.profile =account.borrow<&Profile.User>(from:Profile.storagePath) ?? panic("Cannot borrow reference to profile") + self.profile =account.storage.borrow(from:Profile.storagePath) ?? panic("Cannot borrow reference to profile") - } + } - execute{ - for key in unfollows { - let user = FIND.resolve(key) ?? panic(key.concat(" cannot be resolved. It is either an invalid .find name or address")) - self.profile.unfollow(user) - } - } + execute{ + for key in unfollows { + let user = FIND.resolve(key) ?? panic(key.concat(" cannot be resolved. It is either an invalid .find name or address")) + self.profile.unfollow(user) + } + } } diff --git a/transactions/unlinkDUCVaultReceiver.cdc b/transactions/unlinkDUCVaultReceiver.cdc index 4403c4be..469a3f24 100644 --- a/transactions/unlinkDUCVaultReceiver.cdc +++ b/transactions/unlinkDUCVaultReceiver.cdc @@ -1,8 +1,8 @@ -import TokenForwarding from "../contracts/standard/TokenForwarding.cdc" +import "TokenForwarding" transaction() { - prepare(account: AuthAccount) { + prepare(account: auth(BorrowValue) &Account) { account.unlink(/public/dapperUtilityCoinReceiver) } } diff --git a/transactions/updateRelatedAccount.cdc b/transactions/updateRelatedAccount.cdc index 2c46fcd7..f163e9b9 100644 --- a/transactions/updateRelatedAccount.cdc +++ b/transactions/updateRelatedAccount.cdc @@ -1,28 +1,26 @@ -import FindRelatedAccounts from "../contracts/FindRelatedAccounts.cdc" +import "FindRelatedAccounts" transaction(name: String, network: String, oldAddress:String, address: String) { - var relatedAccounts : &FindRelatedAccounts.Accounts? + var relatedAccounts : auth(FindRelatedAccounts.Owner) &FindRelatedAccounts.Accounts? - prepare(account: AuthAccount) { + prepare(account: auth (StorageCapabilities, SaveValue,PublishCapability, BorrowValue, IssueStorageCapabilityController) &Account) { - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - if self.relatedAccounts == nil { - let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts = account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - } + let relatedAccounts= account.storage.borrow(from:FindRelatedAccounts.storagePath) + if relatedAccounts == nil { + let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() + account.storage.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) + var cap = account.capabilities.storage.issue<&FindRelatedAccounts.Accounts>(FindRelatedAccounts.storagePath) + account.capabilities.publish(cap, at: FindRelatedAccounts.publicPath) + self.relatedAccounts = account.storage.borrow(from:FindRelatedAccounts.storagePath) + }else { + self.relatedAccounts=relatedAccounts + } - let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) - if !cap.check() { - account.unlink(FindRelatedAccounts.publicPath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - } - } + } - execute { - self.relatedAccounts!.updateRelatedAccount(name:name, network:network, oldAddress: oldAddress, address: address) - } + execute { + self.relatedAccounts!.updateRelatedAccount(name:name, network:network, oldAddress: oldAddress, address: address) + } } diff --git a/transactions/updateRelatedFlowAccount.cdc b/transactions/updateRelatedFlowAccount.cdc index 5b39e10b..ebd77e4a 100644 --- a/transactions/updateRelatedFlowAccount.cdc +++ b/transactions/updateRelatedFlowAccount.cdc @@ -1,28 +1,26 @@ -import FindRelatedAccounts from "../contracts/FindRelatedAccounts.cdc" +import "FindRelatedAccounts" transaction(name: String, oldAddress: Address, address: Address) { - var relatedAccounts : &FindRelatedAccounts.Accounts? + var relatedAccounts : &FindRelatedAccounts.Accounts? - prepare(account: AuthAccount) { + prepare(account: auth (StorageCapabilities, SaveValue,PublishCapability, BorrowValue, IssueStorageCapabilityController) &Account) { - self.relatedAccounts= account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - if self.relatedAccounts == nil { - let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() - account.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - self.relatedAccounts = account.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) - } + let relatedAccounts= account.storage.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) + if relatedAccounts == nil { + let relatedAccounts <- FindRelatedAccounts.createEmptyAccounts() + account.storage.save(<- relatedAccounts, to: FindRelatedAccounts.storagePath) + var cap = account.capabilities.storage.issue<&FindRelatedAccounts.Accounts>(FindRelatedAccounts.storagePath) + account.capabilities.publish(cap, at: FindRelatedAccounts.publicPath) + self.relatedAccounts = account.storage.borrow<&FindRelatedAccounts.Accounts>(from:FindRelatedAccounts.storagePath) + }else { + self.relatedAccounts=relatedAccounts + } - let cap = account.getCapability<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath) - if !cap.check() { - account.unlink(FindRelatedAccounts.publicPath) - account.link<&FindRelatedAccounts.Accounts{FindRelatedAccounts.Public}>(FindRelatedAccounts.publicPath, target: FindRelatedAccounts.storagePath) - } - } + } - execute { - self.relatedAccounts!.updateFlowAccount(name:name, oldAddress: oldAddress, address: address) - } + execute { + self.relatedAccounts!.updateFlowAccount(name:name, oldAddress: oldAddress, address: address) + } }