diff --git a/.env b/.env new file mode 100644 index 0000000..1d6b028 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +REACT_APP_CLIENT_ID=BKBTX-SmaEFGddZQrwqd65YFoImRQLca_Tj2IdmKyD2UbDpzrtN2WQ-NYLuej6gP0DfF3jSpEkI13wPt1uPedm0 diff --git a/assets/wallets/torus.svg b/assets/wallets/torus.svg new file mode 100644 index 0000000..1c0178e --- /dev/null +++ b/assets/wallets/torus.svg @@ -0,0 +1,19 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + + + + diff --git a/packages/common/src/components/CurrentUserBadge/index.tsx b/packages/common/src/components/CurrentUserBadge/index.tsx index 5ef692d..e2908c7 100644 --- a/packages/common/src/components/CurrentUserBadge/index.tsx +++ b/packages/common/src/components/CurrentUserBadge/index.tsx @@ -21,11 +21,14 @@ export const CurrentUserBadge = (props: { showBalance?: boolean, showAddress?: b { marginLeft: '0.5rem', display: 'flex', - width: props.iconSize + width: props.iconSize, + borderRadius: 50, + } :{ display: 'flex', width: props.iconSize, paddingLeft: 0, + borderRadius: 50, }; const baseWalletKey: React.CSSProperties = { height: props.iconSize, cursor: 'pointer', userSelect: 'none' }; @@ -33,6 +36,21 @@ export const CurrentUserBadge = (props: { showBalance?: boolean, showAddress?: b baseWalletKey :{ ...baseWalletKey, paddingLeft: 0 }; + let name = props.showAddress ? shortenAddress(`${wallet.publicKey}`) : ''; + const unknownWallet = wallet as any; + if(unknownWallet.name) { + name = unknownWallet.name; + } + + let image = ; + + if(unknownWallet.image) { + image = ; + } + return (
{props.showBalance && @@ -46,11 +64,8 @@ export const CurrentUserBadge = (props: { showBalance?: boolean, showAddress?: b trigger="click" >
- {props.showAddress && shortenAddress(`${wallet.publicKey}`)} - + {name && ({name})} + {image}
diff --git a/packages/common/src/components/Identicon/index.tsx b/packages/common/src/components/Identicon/index.tsx index 1e108c9..0c9f476 100644 --- a/packages/common/src/components/Identicon/index.tsx +++ b/packages/common/src/components/Identicon/index.tsx @@ -21,16 +21,16 @@ export const Identicon = (props: { if (address && ref.current) { try { - ref.current.innerHTML = ''; - ref.current.className = className || ''; - ref.current.appendChild( - Jazzicon( - style?.width || 16, - parseInt(bs58.decode(address).toString('hex').slice(5, 15), 16), - ), - ); + ref.current.innerHTML = ''; + ref.current.className = className || ''; + ref.current.appendChild( + Jazzicon( + style?.width || 16, + parseInt(bs58.decode(address).toString('hex').slice(5, 15), 16), + ), + ); - }catch (err) { + } catch (err) { // TODO } } diff --git a/packages/common/src/components/Settings/index.tsx b/packages/common/src/components/Settings/index.tsx index 76d70c0..6e97706 100644 --- a/packages/common/src/components/Settings/index.tsx +++ b/packages/common/src/components/Settings/index.tsx @@ -2,13 +2,17 @@ import React from 'react'; import { Button, Select } from 'antd'; import { useWallet } from '../../contexts/wallet'; import { ENDPOINTS, useConnectionConfig } from '../../contexts/connection'; +import { shortenAddress } from '../../utils'; +import { + CopyOutlined +} from '@ant-design/icons'; export const Settings = ({ additionalSettings, }: { additionalSettings?: JSX.Element; }) => { - const { connected, disconnect } = useWallet(); + const { connected, disconnect, select, wallet } = useWallet(); const { endpoint, setEndpoint } = useConnectionConfig(); return ( @@ -27,9 +31,23 @@ export const Settings = ({ ))} {connected && ( - + <> + Wallet: + {wallet?.publicKey && ()} + + + + )} {additionalSettings} diff --git a/packages/common/src/contexts/accounts.tsx b/packages/common/src/contexts/accounts.tsx index 8a456b3..0bbc1cc 100644 --- a/packages/common/src/contexts/accounts.tsx +++ b/packages/common/src/contexts/accounts.tsx @@ -416,35 +416,35 @@ export function AccountsProvider({ children = null as any }) { if (!connection || !publicKey) { setTokenAccounts([]); } else { - precacheUserTokenAccounts(connection, LEND_HOST_FEE_ADDRESS); + // precacheUserTokenAccounts(connection, LEND_HOST_FEE_ADDRESS); - precacheUserTokenAccounts(connection, publicKey).then(() => { - setTokenAccounts(selectUserAccounts()); - }); + // precacheUserTokenAccounts(connection, publicKey).then(() => { + // setTokenAccounts(selectUserAccounts()); + // }); // This can return different types of accounts: token-account, mint, multisig // TODO: web3.js expose ability to filter. // this should use only filter syntax to only get accounts that are owned by user - const tokenSubID = connection.onProgramAccountChange( - programIds().token, - info => { - // TODO: fix type in web3.js - const id = (info.accountId as unknown) as string; - // TODO: do we need a better way to identify layout (maybe a enum identifing type?) - if (info.accountInfo.data.length === AccountLayout.span) { - const data = deserializeAccount(info.accountInfo.data); + // const tokenSubID = connection.onProgramAccountChange( + // programIds().token, + // info => { + // // TODO: fix type in web3.js + // const id = (info.accountId as unknown) as string; + // // TODO: do we need a better way to identify layout (maybe a enum identifing type?) + // if (info.accountInfo.data.length === AccountLayout.span) { + // const data = deserializeAccount(info.accountInfo.data); - if (PRECACHED_OWNERS.has(data.owner.toBase58())) { - cache.add(id, info.accountInfo, TokenAccountParser); - setTokenAccounts(selectUserAccounts()); - } - } - }, - 'singleGossip', - ); + // if (PRECACHED_OWNERS.has(data.owner.toBase58())) { + // cache.add(id, info.accountInfo, TokenAccountParser); + // setTokenAccounts(selectUserAccounts()); + // } + // } + // }, + // 'singleGossip', + // ); return () => { - connection.removeProgramAccountChangeListener(tokenSubID); + // connection.removeProgramAccountChangeListener(tokenSubID); }; } }, [connection, connected, publicKey, selectUserAccounts]); diff --git a/packages/common/src/contexts/wallet.tsx b/packages/common/src/contexts/wallet.tsx index 62af16a..70e665b 100644 --- a/packages/common/src/contexts/wallet.tsx +++ b/packages/common/src/contexts/wallet.tsx @@ -9,6 +9,8 @@ import { useLocalStorageState } from "../utils/utils"; import { LedgerProvider } from "@solana/wallet-ledger"; import { SolongWalletAdapter } from "../wallet-adapters/solong"; import { PhantomWalletAdapter } from "../wallet-adapters/phantom"; +import { TorusWalletAdapter } from "../wallet-adapters/torus"; +import { useLocation } from "react-router"; const ASSETS_URL = 'https://raw.githubusercontent.com/solana-labs/oyster/main/assets/wallets/'; export const WALLET_PROVIDERS = [ @@ -37,6 +39,12 @@ export const WALLET_PROVIDERS = [ icon: `https://www.phantom.app/img/logo.png`, adapter: PhantomWalletAdapter, }, + { + name: 'Torus', + url: 'https://tor.us', + icon: `${ASSETS_URL}torus.svg`, + adapter: TorusWalletAdapter, + } ]; const WalletContext = React.createContext<{ @@ -53,8 +61,8 @@ const WalletContext = React.createContext<{ export function WalletProvider({ children = null as any }) { const { endpoint } = useConnectionConfig(); - - const [autoConnect, setAutoConnect] = useState(false); + const location = useLocation(); + const [autoConnect, setAutoConnect] = useState(location.pathname.indexOf('result=') >= 0 || false); const [providerUrl, setProviderUrl] = useLocalStorageState("walletProvider"); const provider = useMemo(() => WALLET_PROVIDERS.find(({ url }) => url === providerUrl), [providerUrl]); @@ -90,6 +98,7 @@ export function WalletProvider({ children = null as any }) { wallet.on("disconnect", () => { setConnected(false); + // setProviderUrl(null) notify({ message: "Wallet update", description: "Disconnected from wallet", @@ -99,6 +108,7 @@ export function WalletProvider({ children = null as any }) { return () => { setConnected(false); + // setProviderUrl(null) if (wallet) { wallet.disconnect(); } diff --git a/packages/common/src/wallet-adapters/torus/index.tsx b/packages/common/src/wallet-adapters/torus/index.tsx new file mode 100644 index 0000000..9b426fb --- /dev/null +++ b/packages/common/src/wallet-adapters/torus/index.tsx @@ -0,0 +1,91 @@ +import EventEmitter from "eventemitter3" +import { Account, PublicKey, Transaction } from "@solana/web3.js" +import { WalletAdapter } from "@solana/wallet-base" +import OpenLogin from "@toruslabs/openlogin" +import { getED25519Key } from "@toruslabs/openlogin-ed25519" + +const getSolanaPrivateKey = (openloginKey: string)=>{ + const { sk } = getED25519Key(openloginKey) + return sk +} + +export class TorusWalletAdapter extends EventEmitter implements WalletAdapter { + _provider: OpenLogin | undefined; + endpoint: string; + providerUrl: string; + account: Account | undefined; + image: string = ''; + name: string = ''; + + constructor(providerUrl: string, endpoint: string) { + super() + this.connect = this.connect.bind(this) + this.endpoint = endpoint; + this.providerUrl = providerUrl; + } + + async signAllTransactions(transactions: Transaction[]): Promise { + if(this.account) { + let account = this.account; + transactions.forEach(t => t.partialSign(account)); + } + + return transactions + } + + get publicKey() { + return this.account?.publicKey || null; + } + + async signTransaction(transaction: Transaction) { + if(this.account) { + transaction.partialSign(this.account) + } + + return transaction + } + + connect = async () => { + this._provider = new OpenLogin({ + clientId: process.env.REACT_APP_CLIENT_ID || 'BKBTX-SmaEFGddZQrwqd65YFoImRQLca_Tj2IdmKyD2UbDpzrtN2WQ-NYLuej6gP0DfF3jSpEkI13wPt1uPedm0', + network: "mainnet", // mainnet, testnet, development + }); + + try { + await this._provider.init(); + } catch (ex) { + console.error('init failed', ex) + } + + console.error(this._provider?.state.store); + + if (this._provider.privKey) { + const privateKey = this._provider.privKey; + const secretKey = getSolanaPrivateKey(privateKey); + this.account = new Account(secretKey); + } else { + try { + const { privKey } = await this._provider.login(); + const secretKey = getSolanaPrivateKey(privKey); + this.account = new Account(secretKey); + } catch(ex) { + console.error('login failed', ex); + } + } + + this.name = this._provider?.state.store.get('name');; + this.image = this._provider?.state.store.get('profileImage');; + + this.emit("connect"); + } + + disconnect = async () => { + console.log("Disconnecting...") + if (this._provider) { + await this._provider.logout(); + await this._provider._cleanup(); + this._provider = undefined; + this.emit("disconnect"); + } + } +} diff --git a/packages/metavinci/package.json b/packages/metavinci/package.json index c477027..fedf539 100644 --- a/packages/metavinci/package.json +++ b/packages/metavinci/package.json @@ -18,6 +18,9 @@ "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", + "@toruslabs/openlogin": "^0.7.0", + "@toruslabs/openlogin-ed25519": "^0.7.0", + "@toruslabs/openlogin-utils": "^0.7.0", "@toruslabs/torus-embed": "^1.9.10", "@types/animejs": "^3.1.3", "@types/chart.js": "^2.9.29", diff --git a/packages/metavinci/src/actions/auction.tsx b/packages/metavinci/src/actions/auction.tsx new file mode 100644 index 0000000..f65d7ef --- /dev/null +++ b/packages/metavinci/src/actions/auction.tsx @@ -0,0 +1,3 @@ +export const createAuction = () => { + // TODO: +}; diff --git a/packages/metavinci/src/actions/index.ts b/packages/metavinci/src/actions/index.ts index 41dba20..21033bc 100644 --- a/packages/metavinci/src/actions/index.ts +++ b/packages/metavinci/src/actions/index.ts @@ -1 +1,3 @@ -export const nop = () => {}; +export * from './nft'; +export * from './vault'; +export * from './auction'; diff --git a/packages/metavinci/src/models/nft.tsx b/packages/metavinci/src/actions/nft.tsx similarity index 100% rename from packages/metavinci/src/models/nft.tsx rename to packages/metavinci/src/actions/nft.tsx diff --git a/packages/metavinci/src/actions/vault.tsx b/packages/metavinci/src/actions/vault.tsx new file mode 100644 index 0000000..a5c8ba7 --- /dev/null +++ b/packages/metavinci/src/actions/vault.tsx @@ -0,0 +1,3 @@ +export const createVault = () => { + // TODO: +}; diff --git a/packages/metavinci/src/components/AppBar/index.tsx b/packages/metavinci/src/components/AppBar/index.tsx index 76840cb..df7220a 100644 --- a/packages/metavinci/src/components/AppBar/index.tsx +++ b/packages/metavinci/src/components/AppBar/index.tsx @@ -10,7 +10,7 @@ const UserActions = () => { - + ; diff --git a/packages/metavinci/src/components/ArtCard/index.tsx b/packages/metavinci/src/components/ArtCard/index.tsx index 817ab4e..e7bfe60 100644 --- a/packages/metavinci/src/components/ArtCard/index.tsx +++ b/packages/metavinci/src/components/ArtCard/index.tsx @@ -1,21 +1,12 @@ import React, { useLayoutEffect, useState } from 'react'; -import { Card, Avatar } from 'antd'; +import { Card, Avatar, CardProps } from 'antd'; import { MetadataCategory } from '@oyster/common'; import { ArtContent } from './../ArtContent'; import './index.less'; const { Meta } = Card; -export const ArtCard = ({ - image, - category, - name, - symbol, - description, - artist, - preview, - small, -}: { +export interface ArtCardProps extends CardProps { image?: string; category?: MetadataCategory name?: string; @@ -23,13 +14,17 @@ export const ArtCard = ({ description?: string; artist?: string; preview?: boolean; - small?: boolean -}) => { + small?: boolean; +} + +export const ArtCard = (props: ArtCardProps) => { + const { className, small, category, image, name, preview, artist, ...rest } = props; return ( } + className={`art-card ${small ? 'small' : ''} ${className}`} + cover={} + {...rest} > { +export const ArtContent = ({ + content, + category, + className, + preview + }: { + category?: MetadataCategory, + content?: string, + className?: string, + preview?: boolean, + }) => { return category === 'video' ? -