Skip to content

Commit

Permalink
feat: complete initial joyID NFT view & iframe provider.
Browse files Browse the repository at this point in the history
  • Loading branch information
micwallace committed Oct 17, 2023
1 parent c88a72a commit 52ea04f
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 103 deletions.
68 changes: 68 additions & 0 deletions javascript/tokenscript-viewer/src/assets/test-iframe-provider.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ethers/5.7.2/ethers.umd.min.js" integrity="sha512-FDcVY+g7vc5CXANbrTSg1K5qLyriCsGDYCE02Li1tXEYdNQPvLPHNE+rT2Mjei8N7fZbe0WLhw27j2SrGRpdMg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<div style="width: 600px; margin: 0 auto; min-height: 800px;">
<iframe id="frame" src="https://viewer-staging.tokenscript.org/?viewType=joyid-token&chain=11155111&contract=0xA04664f6191D9A65F5F48c6F9d6Dd81CB636E65c&tokenId=1"
style="border: 0; width: 100%; height: 100%;"></iframe>
</div>
<script>
const provider = new ethers.providers.Web3Provider(window.ethereum);
const iframe = document.getElementById("frame");

window.addEventListener("message", async (message) => {
if (message.origin !== "http://localhost:3333")
return;

console.log("Message received: ", message);

try {
switch (message.data.method) {
case "eth_accounts":
case "eth_requestAccounts":
await window.ethereum.enable();
const accounts = await provider.listAccounts();
sendResponse(message.data, accounts);
break;
case "eth_chainId":
case "eth_blockNumber":
case "eth_estimateGas":
case "eth_sendTransaction":
case "eth_sendRawTransaction":
case "eth_getTransactionByHash":
case "eth_getTransactionReceipt":
case "eth_getTransactionCount":
case "personal_sign":
case "eth_signTypedData":
const result = await provider.send(message.data.method, message.data.params);
sendResponse(message.data, result);
break;

default:
sendResponse(message.data, null, {code: -1, message: "RPC Method " + message.data.method + " is not implemented"});
}
} catch (e){
console.error(e);
sendResponse(message.data, null, {
code: e.code,
message: e.message
});
}
});

function sendResponse(messageData, response, error){

const data = messageData;

if (response){
data.result = response;
} else {
data.error = error;
}

iframe.contentWindow.postMessage(data, "https://viewer-staging.tokenscript.org");
}
</script>
</body>
</html>
20 changes: 15 additions & 5 deletions javascript/tokenscript-viewer/src/components/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {Web3WalletProvider} from "../wallet/Web3WalletProvider";
import {DiscoveryAdapter} from "../../integration/discoveryAdapter";
import {AttestationStorageAdapter} from "../../integration/attestationStorageAdapter";
import {IFrameEthereumProvider} from "../../integration/IframeEthereumProvider";
import {ethers} from "ethers";
import {ITokenDiscoveryAdapter} from "@tokenscript/engine-js/src/tokens/ITokenDiscoveryAdapter";

export type TokenScriptSource = "resolve" | "file" | "url";

Expand All @@ -27,20 +29,28 @@ export class AppRoot {

walletSelector: HTMLWalletSelectorElement;

discoveryAdapter = new DiscoveryAdapter()
discoveryAdapter: ITokenDiscoveryAdapter = new DiscoveryAdapter()
attestationStorageAdapter = new AttestationStorageAdapter();

private iframeProvider: ethers.providers.Web3Provider;

constructor() {
Web3WalletProvider.setWalletSelectorCallback(async () => this.walletSelector.connectWallet());
}

async getWalletAdapter(): Promise<IWalletAdapter> {

console.log("Getting wallet adapter: ", this.viewerType);
const viewerType = new URLSearchParams(document.location.search).get("viewType");

let provider;

const provider = this.viewerType === "joyid-token" ?
new IFrameEthereumProvider() :
(await Web3WalletProvider.getWallet(true)).provider
if (viewerType === "joyid-token"){
if (!this.iframeProvider)
this.iframeProvider = new ethers.providers.Web3Provider(new IFrameEthereumProvider(), "any");
provider = this.iframeProvider;
} else {
provider = (await Web3WalletProvider.getWallet(true)).provider;
}

return new EthersAdapter(async () => {
return provider;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Component, h, JSX, Prop, Watch, Element, Event, EventEmitter} from "@stencil/core";
import {Component, h, JSX, Prop, Watch, Element, Event, EventEmitter, Host} from "@stencil/core";
import {TokenScript} from "@tokenscript/engine-js/src/TokenScript";
import {ViewBinding} from "../../viewers/tabbed/viewBinding";
import {ShowToastEventArgs} from "../../app/app";
Expand Down Expand Up @@ -47,15 +47,15 @@ export class CardModal {
render(){
// TODO: Remove need for view container class (currently referenced in view adapter)
return (
<div class="view-container" style={{display: "none"}}>
<Host class="view-container" style={{display: "none"}}>
<button class="close-btn" onClick={() => {
document.location.hash = "#";
this.tokenScript.getViewController().unloadTokenCard();
}}>X
</button>
<card-view></card-view>
<attribute-table></attribute-table>
</div>
</Host>
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ export class ViewBinding extends AbstractViewBinding {

async showTokenView(card: Card){

(this.view.querySelector(".view-container") as HTMLDivElement).style.display = "block";
(this.view as HTMLDivElement).style.display = "block";

await super.showTokenView(card);

this.renderAttributesTable();
}

async unloadTokenView(){
(this.view.querySelector(".view-container") as HTMLDivElement).style.display = "none";
(this.view as HTMLDivElement).style.display = "none";
await super.unloadTokenView();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ header {

.token-viewer {
max-width: 500px;
width: 100%;
margin: 0 auto;
}

Expand All @@ -13,6 +14,7 @@ header {
font-size: 18px;
color: #000;
padding: 0;
margin: 20px 0;
}

.image-container {
Expand All @@ -34,8 +36,26 @@ header {
}

.attribute-item {
border: 1px solid #000;
border: 2px solid #001AFF;
border-radius: 5px;
min-height: 80px;
padding: 5px;
}

.attribute-item h5 {
margin: 2px 0 5px;
}

.attribute-item span {
font-size: 14px;
}

.actions {
display: flex;
flex-direction: column;
padding: 10px;
}

.actions button {
margin: 5px 0;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {Component, h, JSX, Prop, State} from "@stencil/core";
import {Component, h, Host, JSX, Prop, State} from "@stencil/core";
import {AppRoot} from "../../app/app";
import {ITokenIdContext, ITransactionStatus, TokenScript} from "@tokenscript/engine-js/src/TokenScript";
import {Card} from "@tokenscript/engine-js/src/tokenScript/Card";
import {ITokenDetail} from "@tokenscript/engine-js/src/tokens/ITokenDetail";
import {CHAIN_MAP} from "../../../integration/constants";
import {ITokenCollection} from "@tokenscript/engine-js/src/tokens/ITokenCollection";
import {BASE_TOKEN_DISCOVERY_URL} from "../../../integration/discoveryAdapter";
import {ITokenDiscoveryAdapter} from "@tokenscript/engine-js/src/tokens/ITokenDiscoveryAdapter";

@Component({
tag: 'token-viewer',
Expand Down Expand Up @@ -102,7 +104,7 @@ export class TokenViewer {
private async fetchTokenMetadata(chain: number, contract: string, tokenId: string){

const request = `/get-token?chain=${CHAIN_MAP[chain]}&collectionAddress=${contract}&tokenId=${tokenId}`;
const response = await fetch("http://localhost:3000" + request);
const response = await fetch(BASE_TOKEN_DISCOVERY_URL + request);
const ok = response.status >= 200 && response.status <= 299
if (!ok) {
throw new Error("Failed to load token details");
Expand Down Expand Up @@ -141,9 +143,23 @@ export class TokenViewer {

if (selectedOrigin){
tokenScript.setTokenMetadata(origins);

class StaticDiscoveryAdapter implements ITokenDiscoveryAdapter {
getTokens(initialTokenDetails: ITokenCollection[], refresh: boolean): Promise<ITokenCollection[]> {
return Promise.resolve(origins);
}
}

this.app.discoveryAdapter = new StaticDiscoveryAdapter();

tokenScript.setCurrentTokenContext(selectedOrigin.originId, 0);
this.tokenScript = tokenScript;
await this.loadCardButtons(selectedOrigin)
await this.loadCardButtons(selectedOrigin);

tokenScript.on("TOKENS_UPDATED", () => {
this.cardButtons = undefined;
this.loadCardButtons(selectedOrigin);
})
}

console.log("tokenscript loaded!!");
Expand Down Expand Up @@ -236,32 +252,34 @@ export class TokenViewer {

//if (this.tokenDetails){
return (
<div class="token-viewer">
{ this.tokenDetails ? (<div><div class="image-container">
<token-icon style={{minHeight: "100px;"}} src={this.tokenDetails.image} imageTitle={this.tokenDetails.name} />
</div>
<div class="info-container">
<h1>{this.tokenDetails.name}</h1>
<p>{this.tokenDetails.description}</p>
<div class="attribute-container">
{this.tokenDetails.attributes?.length ? this.tokenDetails.attributes.map((attr) => {
return (
<div class="attribute-item">
{attr.trait_type}<br/>
{attr.value}
</div>
)
}) : ''}
<Host>
<div class="token-viewer">
{ this.tokenDetails ? (<div><div class="image-container">
<token-icon style={{minHeight: "100px;"}} src={this.tokenDetails.image} imageTitle={this.tokenDetails.name} />
</div>
<div class="info-container">
<h1>{this.tokenDetails.name}</h1>
<p>{this.tokenDetails.description}</p>
<div class="attribute-container">
{this.tokenDetails.attributes?.length ? this.tokenDetails.attributes.map((attr) => {
return (
<div class="attribute-item">
<h5>{attr.trait_type}</h5>
<span>{attr.value}</span>
</div>
)
}) : ''}
</div>
</div></div>) : ''}
<div class="actions" style={{textAlign: "center"}}>
{this.cardButtons !== undefined ?
this.cardButtons :
<loading-spinner color={"#595959"} size={"small"} style={{textAlign: "center"}}/>
}
</div>
</div></div>) : ''}
<div class="actions" style={{textAlign: "center"}}>
{this.cardButtons !== undefined ?
this.cardButtons :
<loading-spinner color={"#595959"} size={"small"} style={{textAlign: "center"}}/>
}
</div>
<card-modal tokenScript={this.tokenScript}></card-modal>
</div>
</Host>
)
//}

Expand Down
Loading

0 comments on commit 52ea04f

Please sign in to comment.