forked from dapperlabs/kitty-items-web
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request dapperlabs#16 from dapperlabs/qvvg/buy-stuff
buy stuff
- Loading branch information
Showing
12 changed files
with
376 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import * as fcl from "@onflow/fcl" | ||
import * as t from "@onflow/types" | ||
import {tx} from "./util/tx" | ||
import {invariant} from "@onflow/util-invariant" | ||
|
||
const CODE = fcl.cdc` | ||
import FungibleToken from 0xFungibleToken | ||
import NonFungibleToken from 0xNonFungibleToken | ||
import Kibble from 0xKibble | ||
import KittyItems from 0xKittyItems | ||
import KittyItemsMarket from 0xKittyItemsMarket | ||
transaction(saleItemID: UInt64, marketCollectionAddress: Address) { | ||
let paymentVault: @FungibleToken.Vault | ||
let kittyItemsCollection: &KittyItems.Collection{NonFungibleToken.Receiver} | ||
let marketCollection: &KittyItemsMarket.Collection{KittyItemsMarket.CollectionPublic} | ||
prepare(acct: AuthAccount) { | ||
self.marketCollection = getAccount(marketCollectionAddress) | ||
.getCapability<&KittyItemsMarket.Collection{KittyItemsMarket.CollectionPublic}>( | ||
KittyItemsMarket.CollectionPublicPath | ||
)! | ||
.borrow() | ||
?? panic("Could not borrow market collection from market address") | ||
let price = self.marketCollection.borrowSaleItem(saleItemID: saleItemID).salePrice | ||
let mainKibbleVault = acct.borrow<&Kibble.Vault>(from: Kibble.VaultStoragePath) | ||
?? panic("Cannot borrow Kibble vault from acct storage") | ||
self.paymentVault <- mainKibbleVault.withdraw(amount: price) | ||
self.kittyItemsCollection = acct.borrow<&KittyItems.Collection{NonFungibleToken.Receiver}>( | ||
from: KittyItems.CollectionStoragePath | ||
) ?? panic("Cannot borrow KittyItems collection receiver from acct") | ||
} | ||
execute { | ||
self.marketCollection.purchase( | ||
saleItemID: saleItemID, | ||
buyerCollection: self.kittyItemsCollection, | ||
buyerPayment: <- self.paymentVault | ||
) | ||
} | ||
} | ||
` | ||
|
||
// prettier-ignore | ||
export function buyMarketItem({itemId, ownerAddress}, opts = {}) { | ||
invariant(itemId != null, "buyMarketItem({itemId, ownerAddress}) -- itemId required") | ||
invariant(ownerAddress != null, "buyMarketItem({itemId, ownerAddress}) -- ownerAddress required") | ||
|
||
return tx([ | ||
fcl.transaction(CODE), | ||
fcl.args([ | ||
fcl.arg(Number(itemId), t.UInt64), | ||
fcl.arg(String(ownerAddress), t.Address), | ||
]), | ||
fcl.proposer(fcl.authz), | ||
fcl.payer(fcl.authz), | ||
fcl.authorizations([fcl.authz]), | ||
fcl.limit(1000), | ||
], opts) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import * as fcl from "@onflow/fcl" | ||
import * as t from "@onflow/types" | ||
import {tx} from "./util/tx" | ||
import {invariant} from "@onflow/util-invariant" | ||
|
||
const CODE = fcl.cdc` | ||
import KittyItemsMarket from 0xKittyItemsMarket | ||
transaction(saleItemID: UInt64) { | ||
prepare(account: AuthAccount) { | ||
let listing <- account | ||
.borrow<&KittyItemsMarket.Collection>(from: KittyItemsMarket.CollectionStoragePath)! | ||
.remove(saleItemID: saleItemID) | ||
destroy listing | ||
} | ||
} | ||
` | ||
|
||
// prettier-ignore | ||
export function cancelMarketListing({ itemId }, opts = {}) { | ||
invariant(itemId != null, "cancelMarketListing({itemId}) -- itemId required") | ||
|
||
return tx([ | ||
fcl.transaction(CODE), | ||
fcl.args([ | ||
fcl.arg(Number(itemId), t.UInt64), | ||
]), | ||
fcl.proposer(fcl.authz), | ||
fcl.payer(fcl.authz), | ||
fcl.authorizations([fcl.authz]), | ||
fcl.limit(1000), | ||
], opts) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import * as fcl from "@onflow/fcl" | ||
import * as t from "@onflow/types" | ||
// import {batch} from "./util/batch" | ||
|
||
// const CODE = fcl.cdc` | ||
// import KittyItemsMarket from 0xfcceff21d9532b58 | ||
|
||
// pub struct Item { | ||
// pub let id: UInt64 | ||
// pub let isCompleted: Bool | ||
// pub let price: UFix64 | ||
// pub let owner: Address | ||
|
||
// init(id: UInt64, isCompleted: Bool, price: UFix64, owner: Address) { | ||
// self.id = id | ||
// self.isCompleted = isCompleted | ||
// self.price = price | ||
// self.owner: owner | ||
// } | ||
// } | ||
|
||
// pub fun fetch(address: Address, id: UInt64): Item? { | ||
// let cap = getAccount(address) | ||
// .getCapability<&KittyItemsMarket.Collection{KittyItemsMarket.CollectionPublic}>(KittyItemsMarket.CollectionPublicPath)! | ||
|
||
// if let collection = cap.borrow() { | ||
// // this currently throws as the collection.borrowSaleItem returns a non-optional resource | ||
// if let item = collection.borrowSaleItem(saleItemID: id) { | ||
// return Item(id: id, isCompleted: item.saleCompleted, price: item.salePrice, owner: address) | ||
// } else { | ||
// return nil | ||
// } | ||
// } else { | ||
// return nil | ||
// } | ||
// } | ||
|
||
// pub fun main(keys: [String], addresses: [Address], ids: [UInt64]): {String: Item?} { | ||
// let r: {String: Item?} = {} | ||
// var i = 0 | ||
// while i < keys.length { | ||
// let key = keys[i] | ||
// let address = addresses[i] | ||
// let id = ids[i] | ||
// r[key] = fetch(address: address, id: id) | ||
// i = i + i | ||
// } | ||
// return r | ||
// } | ||
// ` | ||
|
||
// const collate = px => { | ||
// return Object.keys(px).reduce( | ||
// (acc, key) => { | ||
// acc.keys.push(key) | ||
// acc.addresses.push(px[key][0]) | ||
// acc.ids.push(px[key][1]) | ||
// return acc | ||
// }, | ||
// {keys: [], addresses: [], ids: []} | ||
// ) | ||
// } | ||
|
||
// const {enqueue} = batch("FETCH_MARKET_ITEM", async px => { | ||
// const {keys, addresses, ids} = collate(px) | ||
|
||
// // prettier-ignore | ||
// return fcl.send([ | ||
// fcl.script(CODE), | ||
// fcl.args([ | ||
// fcl.arg(keys, t.Array(t.String)), | ||
// fcl.arg(addresses, t.Array(t.Address)), | ||
// fcl.arg(ids.map(Number), t.Array(t.UInt64)), | ||
// ]), | ||
// ]).then(fcl.decode) | ||
// }) | ||
|
||
// export async function fetchMarketItem(address, id) { | ||
// if (address == null) return Promise.resolve(null) | ||
// if (id == null) return Promise.resolve(null) | ||
// return enqueue(address, id) | ||
// } | ||
|
||
export async function fetchMarketItem(address, id) { | ||
return fcl | ||
.send([ | ||
fcl.script` | ||
import KittyItemsMarket from 0xfcceff21d9532b58 | ||
pub struct Item { | ||
pub let id: UInt64 | ||
pub let isCompleted: Bool | ||
pub let price: UFix64 | ||
pub let owner: Address | ||
init(id: UInt64, isCompleted: Bool, price: UFix64, owner: Address) { | ||
self.id = id | ||
self.isCompleted = isCompleted | ||
self.price = price | ||
self.owner = owner | ||
} | ||
} | ||
pub fun main(address: Address, id: UInt64): Item? { | ||
let cap = getAccount(address) | ||
.getCapability<&KittyItemsMarket.Collection{KittyItemsMarket.CollectionPublic}>(KittyItemsMarket.CollectionPublicPath)! | ||
if let collection = cap.borrow() { | ||
let item = collection.borrowSaleItem(saleItemID: id) | ||
return Item(id: id, isCompleted: item.saleCompleted, price: item.salePrice, owner: address) | ||
} else { | ||
return nil | ||
} | ||
} | ||
`, | ||
fcl.args([fcl.arg(address, t.Address), fcl.arg(Number(id), t.UInt64)]), | ||
]) | ||
.then(fcl.decode) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import {atomFamily, selectorFamily, useRecoilState} from "recoil" | ||
import {sansPrefix} from "@onflow/fcl" | ||
import {IDLE, PROCESSING} from "../global/constants" | ||
import {useCurrentUser} from "../hooks/use-current-user.hook" | ||
import {useAccountItems} from "../hooks/use-account-items.hook" | ||
import {useMarketItems} from "../hooks/use-market-items.hook" | ||
import {useKibblesBalance} from "../hooks/use-kibbles-balance.hook" | ||
import {fetchMarketItem} from "../flow/fetch-market-item.script" | ||
import {buyMarketItem} from "../flow/buy-market-item.tx" | ||
import {cancelMarketListing} from "../flow/cancel-market-listing.tx" | ||
|
||
function expand(key) { | ||
return key.split("|") | ||
} | ||
|
||
function comp(address, id) { | ||
return [address, id].join("|") | ||
} | ||
|
||
export const $state = atomFamily({ | ||
key: "market-item::state", | ||
default: selectorFamily({ | ||
key: "market-item::default", | ||
get: key => async () => fetchMarketItem(...expand(key)), | ||
}), | ||
}) | ||
|
||
export const $status = atomFamily({ | ||
key: "market-item::status", | ||
default: IDLE, | ||
}) | ||
|
||
export function useMarketItem(address, id) { | ||
const [cu] = useCurrentUser() | ||
const ownerItems = useAccountItems(address) | ||
const cuItems = useAccountItems(cu.addr) | ||
const ownerMarket = useMarketItems(address) | ||
const cuMarket = useMarketItems(cu.addr) | ||
const kibble = useKibblesBalance(cu.addr) | ||
const key = comp(address, id) | ||
const [item, setItem] = useRecoilState($state(key)) | ||
const [status, setStatus] = useRecoilState($status(key)) | ||
|
||
const owned = sansPrefix(cu.addr) === sansPrefix(address) | ||
|
||
return { | ||
...item, | ||
status, | ||
owned, | ||
async buy() { | ||
await buyMarketItem( | ||
{itemId: id, ownerAddress: address}, | ||
{ | ||
onStart() { | ||
setStatus(PROCESSING) | ||
}, | ||
async onSuccess() { | ||
if (address !== cu.addr) { | ||
ownerItems.refresh() | ||
ownerMarket.refresh() | ||
} | ||
cuItems.refresh() | ||
cuMarket.refresh() | ||
kibble.refresh() | ||
}, | ||
async onComplete() { | ||
setStatus(IDLE) | ||
}, | ||
} | ||
) | ||
}, | ||
async cancelListing() { | ||
await cancelMarketListing( | ||
{itemId: id}, | ||
{ | ||
onStart() { | ||
setStatus(PROCESSING) | ||
}, | ||
async onSuccess() { | ||
cuItems.refresh() | ||
cuMarket.refresh() | ||
kibble.refresh() | ||
}, | ||
async onComplete() { | ||
setStatus(IDLE) | ||
}, | ||
} | ||
) | ||
}, | ||
async refresh() { | ||
setStatus(PROCESSING) | ||
await fetchMarketItem(...expand(key)).then(setItem) | ||
setStatus(IDLE) | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.