Skip to content

Commit

Permalink
Delist moments before destroying them (#147)
Browse files Browse the repository at this point in the history
* fix unit tests

* delist moments before destroying them

Co-authored-by: Joshua Hannan <[email protected]>
  • Loading branch information
Deewai and joshuahannan authored May 31, 2022
1 parent 337f1f5 commit 28f9a02
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 19 deletions.
6 changes: 3 additions & 3 deletions lib/go/templates/internal/assets/assets.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

158 changes: 145 additions & 13 deletions lib/go/test/topshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

"github.com/onflow/cadence"
jsoncdc "github.com/onflow/cadence/encoding/json"
fungibleToken "github.com/onflow/flow-ft/lib/go/contracts"
fungibleTokenTemplates "github.com/onflow/flow-ft/lib/go/templates"

"github.com/dapperlabs/nba-smart-contracts/lib/go/contracts"
"github.com/dapperlabs/nba-smart-contracts/lib/go/templates"
Expand All @@ -16,6 +18,7 @@ import (

"github.com/onflow/flow-go-sdk"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

const (
Expand Down Expand Up @@ -986,12 +989,93 @@ func TestDestroyMoments(t *testing.T) {

env.TopShotAddress = topshotAddr.String()

// Should be able to deploy the token contract
tokenCode := fungibleToken.CustomToken(defaultfungibleTokenAddr, defaultTokenName, defaultTokenStorage, "1000.0")
tokenAccountKey, tokenSigner := accountKeys.NewWithSigner()
tokenAddr, err := b.CreateAccount([]*flow.AccountKey{tokenAccountKey}, []sdktemplates.Contract{
{
Name: "DapperUtilityCoin",
Source: string(tokenCode),
},
})
if !assert.NoError(t, err) {
t.Log(err.Error())
}
_, err = b.CommitBlock()
assert.NoError(t, err)

env.DUCAddress = tokenAddr.String()

// Setup with the first market contract
marketCode := contracts.GenerateTopShotMarketContract(defaultfungibleTokenAddr, nftAddr.String(), topshotAddr.String(), env.DUCAddress)
marketAddr, err := b.CreateAccount(nil, []sdktemplates.Contract{
{
Name: "Market",
Source: string(marketCode),
},
})
if !assert.Nil(t, err) {
t.Log(err.Error())
}
_, err = b.CommitBlock()
require.NoError(t, err)

env.TopShotMarketAddress = marketAddr.String()

// Should be able to deploy the third market contract
marketV3Code := contracts.GenerateTopShotMarketV3Contract(defaultfungibleTokenAddr, nftAddr.String(), topshotAddr.String(), marketAddr.String(), env.DUCAddress)
marketV3Addr, err := b.CreateAccount(nil, []sdktemplates.Contract{
{
Name: "TopShotMarketV3",
Source: string(marketV3Code),
},
})
if !assert.Nil(t, err) {
t.Log(err.Error())
}
_, err = b.CommitBlock()
require.NoError(t, err)

env.TopShotMarketV3Address = marketV3Addr.String()

// Should be able to deploy the token forwarding contract
forwardingCode := fungibleToken.CustomTokenForwarding(defaultfungibleTokenAddr, defaultTokenName, defaultTokenStorage)
forwardingAddr, err := b.CreateAccount(nil, []sdktemplates.Contract{
{
Name: "TokenForwarding",
Source: string(forwardingCode),
},
})
if !assert.NoError(t, err) {
t.Log(err.Error())
}
_, err = b.CommitBlock()
assert.NoError(t, err)

env.ForwardingAddress = forwardingAddr.String()

// Create a new user account
joshAccountKey, joshSigner := accountKeys.NewWithSigner()
joshAddress, _ := b.CreateAccount([]*flow.AccountKey{joshAccountKey}, nil)

tx := createTxWithTemplateAndAuthorizer(b, fungibleTokenTemplates.GenerateCreateTokenScript(flow.HexToAddress(defaultfungibleTokenAddr), tokenAddr, defaultTokenName), joshAddress)

signAndSubmit(
t, b, tx,
[]flow.Address{b.ServiceKey().Address, joshAddress}, []crypto.Signer{b.ServiceKey().Signer(), joshSigner},
false,
)

tx = createTxWithTemplateAndAuthorizer(b, fungibleTokenTemplates.GenerateMintTokensScript(flow.HexToAddress(defaultfungibleTokenAddr), tokenAddr, joshAddress, defaultTokenName, 80), tokenAddr)

signAndSubmit(
t, b, tx,
[]flow.Address{b.ServiceKey().Address, tokenAddr}, []crypto.Signer{b.ServiceKey().Signer(), tokenSigner},
false,
)

// Create moment collection
tx := createTxWithTemplateAndAuthorizer(b, templates.GenerateSetupAccountScript(env), joshAddress)
tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateSetupAccountScript(env), joshAddress)
signAndSubmit(
t, b, tx,
[]flow.Address{b.ServiceKey().Address, joshAddress}, []crypto.Signer{b.ServiceKey().Signer(), joshSigner},
Expand Down Expand Up @@ -1090,12 +1174,59 @@ func TestDestroyMoments(t *testing.T) {
false,
)

//check that moments with ids 1 and 2 exist in josh's collection
result := executeScriptAndCheck(t, b, templates.GenerateIsIDInCollectionScript(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(1))})
assert.Equal(t, cadence.NewBool(true), result)
result = executeScriptAndCheck(t, b, templates.GenerateIsIDInCollectionScript(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(2))})
assert.Equal(t, cadence.NewBool(true), result)

ducPublicPath := cadence.Path{Domain: "public", Identifier: "dapperUtilityCoinReceiver"}

// Create a marketv1 sale collection for Josh
// setting himself as the beneficiary with a 15% cut
tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateCreateAndStartSaleScript(env), joshAddress)

_ = tx.AddArgument(ducPublicPath)
_ = tx.AddArgument(cadence.NewAddress(joshAddress))
_ = tx.AddArgument(CadenceUFix64("0.15"))
_ = tx.AddArgument(cadence.NewUInt64(2))
_ = tx.AddArgument(CadenceUFix64("50.0"))

signAndSubmit(
t, b, tx,
[]flow.Address{b.ServiceKey().Address, joshAddress}, []crypto.Signer{b.ServiceKey().Signer(), joshSigner},
false,
)

// Create a sale collection for josh's account, setting josh as the beneficiary
// and with a 15% cut
tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateCreateAndStartSaleV3Script(env), joshAddress)

_ = tx.AddArgument(ducPublicPath)
_ = tx.AddArgument(cadence.NewAddress(joshAddress))
_ = tx.AddArgument(CadenceUFix64("0.15"))
_ = tx.AddArgument(cadence.NewUInt64(1))
_ = tx.AddArgument(CadenceUFix64("50.0"))

signAndSubmit(
t, b, tx,
[]flow.Address{b.ServiceKey().Address, joshAddress}, []crypto.Signer{b.ServiceKey().Signer(), joshSigner},
false,
)

momentIDs := []uint64{1, 2}
// check the price, sale length, and the sale's data
result = executeScriptAndCheck(t, b, templates.GenerateGetSaleLenV3Script(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress))})
assertEqual(t, cadence.NewInt(2), result)
for _, momentID := range momentIDs {
result = executeScriptAndCheck(t, b, templates.GenerateGetSalePriceV3Script(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(momentID))})
assertEqual(t, CadenceUFix64("50.0"), result)

result = executeScriptAndCheck(t, b, templates.GenerateGetSaleSetIDV3Script(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(momentID))})
assertEqual(t, cadence.NewUInt32(1), result)
}

t.Run("Should destroy the 2 moments created in Josh account", func(t *testing.T) {
// check that moments with ids 1 and 2 exist in josh's collection
result := executeScriptAndCheck(t, b, templates.GenerateIsIDInCollectionScript(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(1))})
assert.Equal(t, cadence.NewBool(true), result)
result = executeScriptAndCheck(t, b, templates.GenerateIsIDInCollectionScript(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(2))})
assert.Equal(t, cadence.NewBool(true), result)
tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateDestroyMomentsScript(env), joshAddress)
_ = tx.AddArgument(cadence.NewArray([]cadence.Value{cadence.NewUInt64(1), cadence.NewUInt64(2)}))
signAndSubmit(
Expand All @@ -1105,12 +1236,13 @@ func TestDestroyMoments(t *testing.T) {
)

// verify that the moments no longer exist in josh's collection
r, err := b.ExecuteScript(templates.GenerateIsIDInCollectionScript(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(1))})
assert.NoError(t, err)
assert.Contains(t, r.Error.Error(), "NFT does not exist in the collection")
r, err = b.ExecuteScript(templates.GenerateIsIDInCollectionScript(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(2))})
assert.NoError(t, err)
assert.Contains(t, r.Error.Error(), "NFT does not exist in the collection")

for _, momentID := range momentIDs {
r, err := b.ExecuteScript(templates.GenerateIsIDInCollectionScript(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress)), jsoncdc.MustEncode(cadence.UInt64(momentID))})
assert.NoError(t, err)
assert.Contains(t, r.Error.Error(), "NFT does not exist in the collection")
}
// verify no moments in sale collection
result = executeScriptAndCheck(t, b, templates.GenerateGetSaleLenV3Script(env), [][]byte{jsoncdc.MustEncode(cadence.Address(joshAddress))})
assertEqual(t, cadence.NewInt(0), result)
})
}
18 changes: 15 additions & 3 deletions transactions/user/destroy_moments.cdc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import NonFungibleToken from 0xNFTADDRESS
import TopShot from 0xTOPSHOTADDRESS
import TopShotMarketV3 from 0xMARKETV3ADDRESS

// This transaction destroys a number of moments owned by a user
Expand All @@ -9,15 +10,26 @@ import TopShot from 0xTOPSHOTADDRESS
transaction(momentIDs: [UInt64]) {

let tokens: @NonFungibleToken.Collection
let collectionRef: &TopShot.Collection

prepare(acct: AuthAccount) {
// delist any of the moments that are listed (this delists for both MarketV1 and Marketv3)
if let topshotSaleV3Collection = acct.borrow<&TopShotMarketV3.SaleCollection>(from: TopShotMarketV3.marketStoragePath) {
for id in momentIDs {
if topshotSaleV3Collection.borrowMoment(id: id) != nil{
// cancel the moment from the sale, thereby de-listing it
topshotSaleV3Collection.cancelSale(tokenID: id)
}
}
}

self.tokens <- acct.borrow<&TopShot.Collection>(from: /storage/MomentCollection)!.batchWithdraw(ids: momentIDs)
self.collectionRef = acct.borrow<&TopShot.Collection>(from: /storage/MomentCollection)
?? panic("Could not borrow from MomentCollection in storage")
}

execute {
let tokens <- self.collectionRef.batchWithdraw(ids: momentIDs)
// destroy the NFTs
destroy self.tokens
destroy tokens
}
}

0 comments on commit 28f9a02

Please sign in to comment.