TokenScript File

TokenScript file is an overlay of XML Mark-up and JavaScript.

A TokenScript file consists of Token Cards, presently in JavaScript and HTML, overlayed with XML mark-up.

The XML mark-up tells a TokenScript Engine to work out how to identify, index and search a token, provide data for its actions and connect it to the web. The JavaScript is used in TokenCards to render token UX and carry out token actions.

The TokenScript is not part of the smart contract which created the token. But it must contain a reference to it and can interact with it.

The TokenScript files are written and signed by the issuer of a token or a trusted party. They can be updated with another signature. Users can download the TokenScript files on any website or the TokenScript repository and validate the signature. This makes it impossible to fake a TokenScript.

Wallets which understand TokenScript can import it and render the user experience according to the TokenScript instructions.

The XML markup

The XML markup is usually expressed in a file and uses standard XML syntax. It is mostly a declarative language, with declarations sometimes being nested.

The XML markup describes properties of the token: The functions it provides, the smart contract it relies upon, the behavior of the token, information of the token and much more.

There is a list of XML declarations developed by TokenScript. For most cases you only need a few of them.

TokenScript uses XML according the the c14n canonicalization. This allows to create standardized digital signatures for XML and to enforce standardized static types like ASN.1 data modules.

The best way to understand how the XML files are structured, study our TokenScript example repo.

Here is a fragmented example for a TokenScript XML file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE token  [
        <!ENTITY style SYSTEM "shared.css">
        <!ENTITY about.en SYSTEM "about.en.js">
        ]>

<ts:token
    xmlns:ts="http://tokenscript.org/2020/06/tokenscript"
    xmlns:xhtml="http://www.w3.org/1999/xhtml"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:asnx="urn:ietf:params:xml:ns:asnx"
    xmlns:ethereum="urn:ethereum:constantinople" xsi:schemaLocation="http://tokenscript.org/2020/06/tokenscript http://tokenscript.org/2020/06/tokenscript.xsd" custodian="false">
    <asnx:module name="Coin-event-Sent">
        <namedType name="Sent">
            <sequence>
                <element name="from" ethereum:type="address" ethereum:indexed="false"></element>
                <element name="to" ethereum:type="address" ethereum:indexed="false"></element>
                <element name="amount" ethereum:type="uint256" ethereum:indexed="false"></element>
            </sequence>
        </namedType>
    </asnx:module>
    <ts:label>
        <ts:string xml:lang="en">Coin</ts:string>
    </ts:label>
    <ts:contract interface="erc20" name="Coin">
        <ts:address network="3">0xe35FE4A1B17d50A8022078d98162DB25bC860834</ts:address>
    </ts:contract>
    <ts:origins>
        <ts:ethereum contract="Coin"/>
    </ts:origins>
    <ts:cards>
        <ts:card type="action">
            <ts:label>
                <ts:string xml:lang="en">Approve</ts:string>
            </ts:label>
            <ts:attribute name="approvalAddress">
                <ts:type>
                    <ts:syntax>1.3.6.1.4.1.1466.115.121.1.36</ts:syntax>
                </ts:type>
                <ts:label>
                    <ts:string xml:lang="en">Approval Address</ts:string>
                </ts:label>
                <ts:origins>
                    <ts:user-entry as="address"/>
                </ts:origins>
            </ts:attribute>
            <ts:transaction>
                <ethereum:transaction function="approve" contract="Coin" as="uint">
                    <ts:data>
                        <ts:address ref="approvalAddress"/>                            <ts:uint256>115792089237316195423570985008687907853269984665640564039457584007913129639935</ts:uint256>
                    </ts:data>
                </ethereum:transaction>
            </ts:transaction>
            <ts:view
                xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
                <style type="text/css">&style;</style>
                <script type="text/javascript">&approve.en;</script>
            </ts:view>
        </ts:card>
    </ts:cards>
    <ts:attribute name="name">
        <ts:type>
            <ts:syntax>1.3.6.1.4.1.1466.115.121.1.26</ts:syntax>
        </ts:type>
        <ts:label>
            <ts:string xml:lang="en">name</ts:string>
        </ts:label>
        <ts:origins>
            <ethereum:call function="name" contract="Coin" as="utf8"></ethereum:call>
        </ts:origins>
    </ts:attribute>
</ts:token>

JavaScript / WebAssembly

The JavaScript part integrates TokenScript in the wallet or dApps. It renders the display of the token and can execute custom offchain functionalities. Broadly, it is the dynamic part of the TokenScript, while XML is the static one.

Everything what happens in the wallet and everything a user can see is described with JavaScript: The rendering of the environment, the display of text and images and so on. In terms of TokenScript, JavaScript is used when a card is triggered.

The creators of TokenScript use JavaScript. But any WeAssembly compatible language like Ruby or C can be used. The wallet importing TokenScript needs to understand these languages.

Again, the best way to learn about how to build the JavaScript files is to inspect them in the TokenScript example repo. Here we present a very simple JavaScript to show an "about" site.

//<![CDATA[
class Token {

    constructor(tokenInstance) {
        this.props = tokenInstance;
        this.setConfirm();
    }

    setConfirm() {
        window.onConfirm = function() {
            window.close();
        }
    }

    render() {
        let message = "Sample about page for your token, fill me up!";
        return`
        <div class="ui container">
          <div class="ui segment">
            <img src="https://www.bitcoin-buch.org/bitcoin-geschichte-front-1.jpg" />
            <span><bold><h1>This is the Token of Christoph!</h1></bold><br /><br />It is a one of the century chance to invest!</span>
          </div>
        </div>
`;
    }
}

web3.tokens.dataChanged = (oldTokens, updatedTokens, tokenIdCard) => {
    const currentTokenInstance = web3.tokens.data.currentInstance;
    document.getElementById(tokenIdCard).innerHTML = new Token(currentTokenInstance).render();
};
//]]>

Merging and signing the files

To deploy TokenScript, the files needs to be merged in a canonicalized XML file. For testing purposes you can load the canonicalized XML file in the AlphaWallet folder on your smart phone. For production you must sign the file and make it available to your users, either by a website or by the TokenScript repo.