Skip to content

Commit

Permalink
feat: Add optional originId parameter onto links
Browse files Browse the repository at this point in the history
This allows linking to a specific origin within a multi-origin tokenscript
without requiring the contract & chain parameters matching that origin.
  • Loading branch information
micwallace committed Oct 22, 2024
1 parent 225af35 commit 4ef994e
Show file tree
Hide file tree
Showing 12 changed files with 51 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,10 @@ export class CardPopover implements IViewBinding {
currentParams.set("card", card.name);

const token = this.tokenScript.getCurrentTokenContext();
if (token && "selectedTokenId" in token){
currentParams.set("tokenId", token.selectedTokenId);
if (token && card.type !== "onboarding"){
currentParams.set("originId", token.originId);
if ("selectedTokenId" in token)
currentParams.set("tokenId", token.selectedTokenId);
}

history.replaceState(undefined, undefined, "#" + currentParams.toString());
Expand All @@ -207,6 +209,7 @@ export class CardPopover implements IViewBinding {
//this.iframe.contentWindow.location.replace("data:text/html;base64,PCFET0NUWVBFIGh0bWw+");
const currentParams = new URLSearchParams(location.hash.substring(1));
currentParams.delete("card");
currentParams.delete("originId");
currentParams.delete("tokenId");
history.replaceState(undefined, undefined, "#" + currentParams.toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class SmartTokenStoreViewer {

async processUrlLoad(){

let {chain, contract, tokenId, scriptId, tokenscriptUrl, emulator} = getTokenUrlParams();
let {chain, contract, originId, tokenId, scriptId, tokenscriptUrl, emulator} = getTokenUrlParams();

this.app.showTsLoader();

Expand All @@ -97,16 +97,16 @@ export class SmartTokenStoreViewer {
const emulatorUrl = new URL(decodeURIComponent(emulator)).origin;
tokenscriptUrl = emulatorUrl + "/tokenscript.tsml";
connectEmulatorSocket(emulatorUrl, async() => {
await this.loadTokenScript(chain, contract, tokenId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
});
}

await this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
}

private async loadTokenScript(chain: number, contract: string, tokenId?: string, scriptId?: string, tokenScriptUrl?: string){
private async loadTokenScript(chain: number, contract: string, originId?: string, tokenId?: string, scriptId?: string, tokenScriptUrl?: string){

this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, this.collectionDetails, this.tokenDetails, tokenId, tokenScriptUrl);
this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, originId, this.collectionDetails, this.tokenDetails, tokenId, tokenScriptUrl);

// Reload cards after the token is updated
this.tokenScript.on("TOKENS_UPDATED", (data) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class TokenViewer {

async processUrlLoad() {

let {query, chain, contract, tokenId, scriptId, tokenscriptUrl, emulator} = getTokenUrlParams();
let {query, chain, contract, originId, tokenId, scriptId, tokenscriptUrl, emulator} = getTokenUrlParams();

if (!tokenId)
throw new Error('Token ID was not provided in the URL');
Expand Down Expand Up @@ -134,17 +134,17 @@ export class TokenViewer {
const emulatorUrl = new URL(decodeURIComponent(emulator)).origin;
tokenscriptUrl = emulatorUrl + "/tokenscript.tsml";
connectEmulatorSocket(emulatorUrl, async() => {
await this.loadTokenScript(chain, contract, tokenId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
});
}

this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
}
}

private async loadTokenScript(chain: number, contract: string, tokenId: string, scriptId?: string, tokenScriptUrl?: string) {
private async loadTokenScript(chain: number, contract: string, originId?: string, tokenId?: string, scriptId?: string, tokenScriptUrl?: string) {
try {
this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, this.tokenDetails.collectionDetails, this.tokenDetails, tokenId, tokenScriptUrl);
this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, originId, this.tokenDetails.collectionDetails, this.tokenDetails, tokenId, tokenScriptUrl);
this.description = await getHardcodedDescription(this.tokenScript, this.tokenDetails);
} catch (e) {
console.warn(e.message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class SmartTokenStoreViewer {

async processUrlLoad(){

let {chain, contract, tokenId, scriptId, tokenscriptUrl, emulator} = getTokenUrlParams();
let {chain, contract, originId, tokenId, scriptId, tokenscriptUrl, emulator} = getTokenUrlParams();

this.app.showTsLoader();

Expand All @@ -98,16 +98,16 @@ export class SmartTokenStoreViewer {
const emulatorUrl = new URL(decodeURIComponent(emulator)).origin;
tokenscriptUrl = emulatorUrl + "/tokenscript.tsml";
connectEmulatorSocket(emulatorUrl, async() => {
await this.loadTokenScript(chain, contract, tokenId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
});
}

await this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
}

private async loadTokenScript(chain: number, contract: string, tokenId: string, scriptId?: string, tokenScriptUrl?: string){
private async loadTokenScript(chain: number, contract: string, originId?: string, tokenId?: string, scriptId?: string, tokenScriptUrl?: string){

this.tokenScript = await getTokenScriptWithProvidedTokenContext(this.app, chain, contract, scriptId, tokenId, tokenScriptUrl);
this.tokenScript = await getTokenScriptWithProvidedTokenContext(this.app, chain, contract, scriptId, originId, tokenId, tokenScriptUrl);

// Reload cards after the token is updated
this.tokenScript.on("TOKENS_UPDATED", (data) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class OpenseaViewer {

async processUrlLoad(){

let {chain, contract, tokenId, scriptId, tokenscriptUrl, emulator} = getTokenUrlParams();
let {chain, contract, originId, tokenId, scriptId, tokenscriptUrl, emulator} = getTokenUrlParams();

if (!tokenId)
throw new Error('Token ID was not provided in the URL');
Expand All @@ -106,17 +106,17 @@ export class OpenseaViewer {
const emulatorUrl = new URL(decodeURIComponent(emulator)).origin;
tokenscriptUrl = emulatorUrl + "/tokenscript.tsml";
connectEmulatorSocket(emulatorUrl, async() => {
await this.loadTokenScript(chain, contract, tokenId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
});
}

await this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
}

private async loadTokenScript(chain: number, contract: string, tokenId: string, scriptId?: string, tokenScriptUrl?: string){
private async loadTokenScript(chain: number, contract: string, originId?: string, tokenId?: string, scriptId?: string, tokenScriptUrl?: string){

try {
this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, this.tokenDetails.collectionDetails, this.tokenDetails, tokenId, tokenScriptUrl);
this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, originId, this.tokenDetails.collectionDetails, this.tokenDetails, tokenId, tokenScriptUrl);
} catch (e){
console.error("Failed to load TokenScript", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export class SmartTokenStoreViewer {

async processUrlLoad() {

let {chain, contract, tokenId, scriptId, tokenscriptUrl, wallet, emulator} = getTokenUrlParams();
let {chain, contract, originId, tokenId, scriptId, tokenscriptUrl, wallet, emulator} = getTokenUrlParams();

let slnAdapter;

Expand Down Expand Up @@ -155,17 +155,17 @@ export class SmartTokenStoreViewer {
const emulatorUrl = new URL(decodeURIComponent(emulator)).origin;
tokenscriptUrl = emulatorUrl + "/tokenscript.tsml";
connectEmulatorSocket(emulatorUrl, async() => {
await this.loadTokenScript(chain, contract, tokenId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
});
}

await this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
}
}

private async loadTokenScript(chain: number, contract: string, tokenId: string, scriptId?: string, tokenScriptUrl?: string) {
private async loadTokenScript(chain: number, contract: string, originId?: string, tokenId?: string, scriptId?: string, tokenScriptUrl?: string) {

this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, this.collectionDetails, this.tokenDetails, tokenId, tokenScriptUrl);
this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, originId, this.collectionDetails, this.tokenDetails, tokenId, tokenScriptUrl);

if (this.tokenScript.getMetadata().backgroundImageUrl){
const body = document.getElementsByTagName("body")[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class TlinkCardViewer {

async processUrlLoad(){

let {chain, contract, tokenId, scriptId, tokenscriptUrl, emulator, card} = getTokenUrlParams();
let {chain, contract, originId, tokenId, scriptId, tokenscriptUrl, emulator, card} = getTokenUrlParams();

this.tokenId = tokenId;
this.card = card;
Expand All @@ -87,18 +87,18 @@ export class TlinkCardViewer {
const emulatorUrl = new URL(decodeURIComponent(emulator)).origin;
tokenscriptUrl = emulatorUrl + "/tokenscript.tsml";
connectEmulatorSocket(emulatorUrl, async() => {
await this.loadTokenScript(chain, contract, tokenId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
});
}

await this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);

this.app.hideTsLoader();
}

private async loadTokenScript(chain: number, contract: string, tokenId: string, scriptId?: string, tokenScriptUrl?: string){
private async loadTokenScript(chain: number, contract: string, originId?: string, tokenId?: string, scriptId?: string, tokenScriptUrl?: string){

this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, null, null, tokenId, tokenScriptUrl);
this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, originId, null, null, tokenId, tokenScriptUrl);

// Reload cards after the token is updated
this.tokenScript.on("TOKENS_UPDATED", (data) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class TlinkViewer {

async processUrlLoad(){

let {chain, contract, tokenId, scriptId, tokenscriptUrl, emulator, card} = getTokenUrlParams();
let {chain, contract, originId, tokenId, scriptId, tokenscriptUrl, emulator, card} = getTokenUrlParams();

this.tokenId = tokenId;
this.card = card;
Expand All @@ -95,18 +95,18 @@ export class TlinkViewer {
const emulatorUrl = new URL(decodeURIComponent(emulator)).origin;
tokenscriptUrl = emulatorUrl + "/tokenscript.tsml";
connectEmulatorSocket(emulatorUrl, async() => {
await this.loadTokenScript(chain, contract, tokenId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);
});
}

await this.loadTokenScript(chain, contract, tokenId, scriptId, tokenscriptUrl);
await this.loadTokenScript(chain, contract, originId, tokenId, scriptId, tokenscriptUrl);

this.app.hideTsLoader();
}

private async loadTokenScript(chain: number, contract: string, tokenId: string, scriptId?: string, tokenScriptUrl?: string){
private async loadTokenScript(chain: number, contract: string, originId?: string, tokenId?: string, scriptId?: string, tokenScriptUrl?: string){

this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, null, null, tokenId, tokenScriptUrl);
this.tokenScript = await getTokenScriptWithSingleTokenContext(this.app, chain, contract, scriptId, originId, null, null, tokenId, tokenScriptUrl);

// Reload cards after the token is updated
this.tokenScript.on("TOKENS_UPDATED", (data) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import {TokenScript} from "@tokenscript/engine-js/src";

export async function getSelectedOriginTokenFromUrlParams(tokenScript: TokenScript, chain: number, contract: string, tokenId: string|null, returnDefault = false){
export async function getSelectedOriginTokenFromUrlParams(tokenScript: TokenScript, chain: number, contract: string, originId?: string, tokenId?: string, returnDefault = false){

const origins = tokenScript.getTokenOriginData();

// TODO: Return the origin specified in the URL

for (const origin of origins) {

if (originId && originId === origin.originId){
return origin;
}

if (
origin.chainId === chain &&
origin.contractAddress.toLowerCase() === contract.toLowerCase() &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ export async function getTokenScriptWithProvidedTokenContext(
chain: number,
contract: string,
scriptId?: string,
originId?: string,
tokenId?: string,
tokenScriptUrl?: string
){

let tokenScript = await getTokenScriptFromUrlParams(app, chain, contract, scriptId, tokenScriptUrl);

let selectedOrigin = await getSelectedOriginTokenFromUrlParams(tokenScript, chain, contract, tokenId, !tokenId);
let selectedOrigin = await getSelectedOriginTokenFromUrlParams(tokenScript, chain, contract, originId, tokenId, !tokenId);

console.log("Selected origin: ", selectedOrigin);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export async function getTokenScriptWithSingleTokenContext(
chain: number,
contract: string,
scriptId?: string,
originId?: string,
collectionDetails?: ITokenCollection,
tokenDetails?: ITokenDetail,
tokenId?: string,
Expand All @@ -19,7 +20,7 @@ export async function getTokenScriptWithSingleTokenContext(

let tokenScript = await getTokenScriptFromUrlParams(app, chain, contract, scriptId, tokenScriptUrl);

let selectedOrigin = await getSelectedOriginTokenFromUrlParams(tokenScript, chain, contract, tokenId, !collectionDetails && !tokenId);
let selectedOrigin = await getSelectedOriginTokenFromUrlParams(tokenScript, chain, contract, originId, tokenId, !collectionDetails && !tokenId && !originId);

if (collectionDetails) {
selectedOrigin = {...collectionDetails, ...selectedOrigin}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function getTokenUrlParams(query?: URLSearchParams){
contract,
tokenId,
scriptId: query.get("scriptId"),
originId: query.get("originId"),
tokenscriptUrl: query.get("tokenscriptUrl"),
emulator: query.get("emulator"),
wallet: query.get('wallet'), // Used to override the wallet address used for display of erc20
Expand Down

0 comments on commit 4ef994e

Please sign in to comment.