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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 112 additions & 4 deletions atlas/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package atlas
import (
_ "embed"
"fmt"
"strings"

"github.com/dapperlabs/studio-platform-smart-contracts/utils"
)
Expand All @@ -15,11 +16,17 @@ var (
//go:embed transactions/user/fulfill_pack_buyback_offer.cdc
AdminFulfillPackBuybackOffer []byte

//go:embed transactions/user/delist_NftStorefront.cdc
//go:embed transactions/user/delist_nftstorefront.cdc
DelistNFTStorefront []byte

//go:embed transactions/user/delist_NftStorefrontV2.cdc
//go:embed transactions/user/delist_nftstorefrontv2.cdc
DelistNFTStorefrontV2 []byte

//go:embed transactions/user/delist_topshotmarketv3.cdc
DelistTopShotMarketV3 []byte

//go:embed transactions/user/list_nftstorefrontv2.cdc
ListNFTStorefrontV2 []byte
)

type UserBuyPacksPrimarySaleParams struct {
Expand Down Expand Up @@ -124,12 +131,12 @@ func DelistNFTStorefrontTxScript(params DelistNFTStorefrontTxScriptParams) (stri
}

type DelistNFTStorefrontV2TxScriptParams struct {
NFTStorefrontAddressV2 string
NFTStorefrontV2Address string
ListingResourceIDs []uint64
}

func (p DelistNFTStorefrontV2TxScriptParams) Validate() error {
if p.NFTStorefrontAddressV2 == "" {
if p.NFTStorefrontV2Address == "" {
return fmt.Errorf("NFTStorefrontAddress must be non-empty")
}

Expand All @@ -149,3 +156,104 @@ func DelistNFTStorefrontV2TxScript(params DelistNFTStorefrontV2TxScriptParams) (
}
return string(bytes), nil
}

type DelistTopShotMarketV3ScriptParams struct {
TopShotContractAddress string
TopShotMarketContractAddress string
NonFungibleTokenContractAddress string
NftIds []uint64
}

func (p DelistTopShotMarketV3ScriptParams) Validate() error {
if p.TopShotContractAddress == "" ||
p.TopShotMarketContractAddress == "" ||
p.NonFungibleTokenContractAddress == "" ||
len(p.NftIds) == 0 {
return fmt.Errorf("all fields in DelistTopShotMarketV3ScriptParams must be non-empty")
}
return nil
}

func DelistTopShotMarketV3Script(params DelistTopShotMarketV3ScriptParams) (string, error) {
if err := params.Validate(); err != nil {
return "", err
}
bytes, err := utils.ParseCadenceTemplate(DelistTopShotMarketV3, params)
if err != nil {
return "", err
}
return string(bytes), nil
}

type ListNFTStorefrontV2Params struct {
FungibleTokenContractAddress string
NonFungibleTokenContractAddress string
MetadataViewsAddress string
DapperUtilityCoinContractAddress string
TokenForwardingContractAddress string
NFTProductName string
NFTContractAddress string
NFTStorefrontV2ContractAddress string
NFTIDs []uint64
PricesInCents []int
SaleCommissionPercent int // e.g. 5 for 5%
Expiry string // Unix timestamp as string
}

// NFTIDsString converts the NFTIDs from an array of uint64 to a string to be used by the template
func (p ListNFTStorefrontV2Params) NFTIDsString() string {
nftIDStrings := make([]string, len(p.NFTIDs))
for i, id := range p.NFTIDs {
nftIDStrings[i] = fmt.Sprintf("%d", id)
}
return strings.Join(nftIDStrings, ", ")
}

// PricesString converts the PricesInCents from an array of int to a string to be used by the template
func (p ListNFTStorefrontV2Params) PricesString() string {
floatPrices := make([]string, len(p.PricesInCents))
for i, price := range p.PricesInCents {
floatPrices[i] = centsToUFix64String(price)
}
return strings.Join(floatPrices, ",")
}

// SaleCommissionPercentString converts the SaleCommissionPercent from an int to a string to be used by the template
func (p ListNFTStorefrontV2Params) SaleCommissionPercentString() string {
return centsToUFix64String(p.SaleCommissionPercent)
}

func (p ListNFTStorefrontV2Params) Validate() error {
if p.FungibleTokenContractAddress == "" ||
p.NonFungibleTokenContractAddress == "" ||
p.MetadataViewsAddress == "" ||
p.DapperUtilityCoinContractAddress == "" ||
p.NFTProductName == "" ||
p.NFTContractAddress == "" ||
p.NFTStorefrontV2ContractAddress == "" ||
len(p.NFTIDs) == 0 ||
len(p.PricesInCents) == 0 {
return fmt.Errorf("all fields in ListNFTStorefrontV2Params must be non-empty")
}
if len(p.NFTIDs) != len(p.PricesInCents) {
return fmt.Errorf("NFTIDs and pricesInCents must have the same length")
}
return nil
}

func ListNFTStorefrontV2TxScript(params ListNFTStorefrontV2Params) (string, error) {
if err := params.Validate(); err != nil {
return "", err
}
bytes, err := utils.ParseCadenceTemplate(ListNFTStorefrontV2, params)
if err != nil {
return "", err
}
return string(bytes), nil
}

func centsToUFix64String(cents int) string {
// cents -> units with 8 decimal places
// 1 cent = 0.01 = 0.01000000
return fmt.Sprintf("%d.%08d", cents/100, (cents%100)*1_000_000)
}
52 changes: 52 additions & 0 deletions atlas/embed_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package atlas

import (
"fmt"
"strings"
"testing"
)
Expand Down Expand Up @@ -36,3 +37,54 @@ func TestBuildFlowTxScript_EmptyParamsError(t *testing.T) {
t.Errorf("expected empty tx string for error case, got: %s", tx)
}
}

func TestDelistNFTStorefrontOutput(t *testing.T) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these tests are not actually testing anything. It just logs stuff

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, it helps see what is getting inputted

params := DelistNFTStorefrontTxScriptParams{
NFTStorefrontAddress: "123",
ListingResourceIDs: []uint64{123, 456, 789},
}

tx, err := DelistNFTStorefrontTxScript(params)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

fmt.Println("Generated transaction script:")
fmt.Println(tx)
t.Logf("Generated output:\n%s", tx)
}

func TestDelistTopShotMarketV3Output(t *testing.T) {
params := DelistTopShotMarketV3ScriptParams{
TopShotContractAddress: "TOPSHOT",
TopShotMarketContractAddress: "MARKET",
NonFungibleTokenContractAddress: "NFT",
NftIds: []uint64{123, 456, 789},
}

tx, err := DelistTopShotMarketV3Script(params)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

fmt.Println("Generated transaction script:")
fmt.Println(tx)
t.Logf("Generated output:\n%s", tx)
}

func TestDelistNFTStorefrontV2Output(t *testing.T) {
// Test what Go's text/template outputs when given a []uint64
params := DelistNFTStorefrontV2TxScriptParams{
NFTStorefrontV2Address: "123",
ListingResourceIDs: []uint64{123, 456, 789},
}

tx, err := DelistNFTStorefrontV2TxScript(params)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

fmt.Println("Generated transaction script:")
fmt.Println(tx)
t.Logf("Generated output:\n%s", tx)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ transaction() {
}

execute {
let listingResourceIDs: [Uint64] = [{{.listingResourceIDs}}]
let listingResourceIDs: [Uint64] = [{{.ListingResourceIDs}}]
for resourceID in listingResourceIDs {
self.storefront.removeListing(listingResourceID: resourceID)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ transaction() {
}

execute {
let listingResourceIDs: [Uint64] = [{{.listingResourceIDs}}]
let listingResourceIDs: [Uint64] = [{{.ListingResourceIDs}}]
for resourceID in listingResourceIDs {
self.storefront.removeListing(listingResourceID: resourceID)
}
Expand Down
42 changes: 42 additions & 0 deletions atlas/transactions/user/delist_topshotmarketv3.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import TopShot from 0x{{.TopShotContractAddress}}
import Market from 0x{{.TopShotMarketContractAddress}}
import TopShotMarketV3 from 0x{{.TopShotMarketContractAddress}}
import NonFungibleToken from 0x{{.NonFungibleTokenContractAddress}}

// This transaction is for a user to stop a moment sale in their account

// Parameters
//
// tokenID: the ID of the moment whose sale is to be delisted

transaction() {

let nftIds: [UInt64]

prepare(acct: auth(Storage, Capabilities) &Account) {
self.nftIds = [{{.NftIds}}]

// borrow a reference to the owner's sale collection
if let topshotSaleV3Collection = acct.storage.borrow<auth(TopShotMarketV3.Cancel) &TopShotMarketV3.SaleCollection>(from: TopShotMarketV3.marketStoragePath) {

// cancel the moments from the sale, thereby de-listing it
for nftId in self.nftIds {
topshotSaleV3Collection.cancelSale(tokenID: nftId)
}

} else if let topshotSaleCollection = acct.storage.borrow<auth(NonFungibleToken.Withdraw) &Market.SaleCollection>(from: /storage/topshotSaleCollection) {
// Borrow a reference to the NFT collection in the signers account
let collectionRef = acct.storage.borrow<&TopShot.Collection>(from: /storage/MomentCollection)
?? panic("Could not borrow from MomentCollection in storage")

// withdraw the moments from the sale, thereby de-listing it
for nftId in self.nftIds {
let token <- topshotSaleCollection.withdraw(tokenID: nftId)

// deposit the moment into the owner's collection
collectionRef.deposit(token: <-token)
}

}
}
}
Loading