Skip to content

Commit 256f2fc

Browse files
author
Weiwu
committed
version obtained from Tore which is based on an earlier version from James
1 parent 882c0a6 commit 256f2fc

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed

ERCs/ERC5XXX draft.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
### eip: 5???
2+
### title: Executable Script extention for Token Contracts
3+
### description: Add a scriptURI to point to point to an executable script associated with the functionality of the token.
4+
### author: James (@JamesSmartCell), Weiwu (@weiwu-zhang), Tore Frederiksen
5+
### discussions-to:
6+
### status: Draft
7+
### type: Standards Track
8+
### category: ERC
9+
### created: 2022-05-03
10+
### requires:
11+
### Abstract
12+
This standard is an interface that adds a scriptURI for locating executable scripts associated with the token.
13+
14+
### Motivation
15+
Often NFT authors want to provide some user functionality to their tokens, e.g. through scripts. This should done in a safe way, without opening the user to potential scams. By packaging a link to official scripts, created by the token minter, within the token itself, users can be sure they are using the correct script.
16+
17+
This ERC proposes adding a scriptURI which is a structure containing an array of URIs to external resources in IPFS, github, a cloud provider, etc.
18+
Each scriptURI semantically contains access information to access a *single* signed script, stored in one or more off-chain locations.
19+
Concretely each element in the array contains a pair of URIs, one to the script itself, and one to a signature of the script.
20+
21+
The script provides a user interface to the hosting token which could for example be either: A 'minidapp', which is a cut down dapp tailored for a single token, or a 'TokenScript' which provides a fuller user experience.
22+
23+
To facilitate a future-proof solution, this ERC also proposes a solution which allows for updating such resources *after* the token has been issued.
24+
To achieve this the token minter can use the signing key associated with the token minting and an associated smart contract, to authenticate a script/scriptURI signing key.
25+
In a similar manner the smart contract singing key can also be used to overwrite the scriptURI signing key, in case it gets compromised or needs to be rolled.
26+
The scriptURI signing key is then used to authenticate the URI towards the smart contract, along with the script itself towards anyone accessing it.
27+
28+
#### Script location
29+
While the simplest solutions to facilitate specific script usage associated with NFTs, is clearly to store such a script on the smart contract. However, this has several disadvantages:
30+
1. The smart contract signing key is needed to make updates. This means that this key becomes more exposed as it is used more often.
31+
2. Updates require smart contract interaction. Simply posting a new transaction on Ethereum is not cheap! When this transaction also includes smart contract logic, the price can quickly become significant. If frequent updates are needed, then smart contract calls can in itself becomes a hurdle.
32+
3. Storage fee. If the script is large, contains special graphics or other large elements, then updates to the script can quickly costs thousands of dollars.
33+
34+
For these reasons it makes sense to store volatile data, such as token enhancing functionality, on an external resource. Such an external resource can be either centralized, such as a cloud provider or private server, or decentralized such as the interplanetary filesystem.
35+
Since using centralized storage for a decentralized functionality goes against the ethos of web3, this ERC handle this this by allowing the token provider to store multiple URIs to the script on-chain. The URIs might point to either multiple centralized storage providers or fully decentralized ones, e.g. the IPFS, another blockchain or even on Ethereum itself. It could also be a mix of centralized and decentralized locations.
36+
37+
While this ERC does not dictate the format of the stored script, it should be noted that the script itself could contain pointers to multiple other scripts and data sources. Hence this allows for advanced and rich expansion of tokens.
38+
39+
#### Script updates
40+
Besides issues of script location, another issue is how the script can be updated in a manner where the caller can be sure it is authentic.
41+
In this ERC we solve this issue by allowing the issuer to sign and update, on-chain, a scriptURI signing key which can be used to authenticate the script pointed to by the on-chain URI *without* requiring interaction with the smart contract.
42+
This approach has multiple advantages:
43+
1. It allows for off-chain updates of the script (as long as the URI does not change), in a way that can be verified by anyone off-chain.
44+
2. It provides a key management functionality, where the smart contract signing key is not required to make updates to the script or its resources. This in turn, provides a key rolling mechanism and implicitly a revocation mechanism in case the script-signing key ever gets compromised.
45+
46+
It is worth noting that if IPFS is used as URI, then updating the script will also result in an updated URI. This requires interaction with the smart contract. However, this can be done without requiring usage of the smart contract signing key, using a public interface method that allows anyone to update the URIs, but _only_ if they sign the parameters (i.e. new URIs) using the scriptURI signing key.
47+
This ensures that even if IPFS is used and URIs need to be updated every time the script is updates, we can still get the key management advantages of using a script signing key.
48+
49+
#### Overview
50+
51+
With the discussion above in mind we outline the solution proposed by the ERC. For this purpose we consider the following variables:
52+
- `SCPrivKey`: The private signing key controlling a smart contract implementing this ERC, which is associated with the tokens issued.
53+
- `scriptPrivKey`: A private signing key which is used to sign the script issued by the smart contract owner/token provider along with the scriptURI.
54+
- `scriptKeyAddr`: The address of the public key associated with `scriptPrivKey`, which is used to verify signatures signed with `scriptPrivKey`.
55+
- `script`: The script supplying additional functionality to the tokens.
56+
- `sigScript`: The signature on `script` after signing it with `scriptPrivKey`.
57+
58+
With these variables in mind we can describe the life cycle of tokens script functionality.
59+
- Issuance
60+
1. The token issuer issues the tokens and a smart contract implementing this ERC, with the controlling key for the smart contract being `SCPrivKey`.
61+
2. The token issuer samples a `scriptPrivKey` and associated `scriptKeyAddr`. They then sign `script`, to get a signature `sigScript` and stores both at one or more URIs, which are consolidated to a scriptURI.
62+
3. The token issuer calls `setVerificationKey(scriptKeyAddr)` on the smart contract to set the initial scriptURI signing key.
63+
4. The token issuer signs the scriptURI with the signing key `scriptPrivKey`. Denote the signature `sigScriptURI`.
64+
4. The token issuer calls `setScriptURI` with the scriptURI, along with `sigScriptURI`.
65+
66+
- Update script
67+
1. The token issuer signs a new script `script2` using `scriptPrivKey` to get a signature `sigScript2`.
68+
2. The token issuer updates `script` and `sigScript` at all its URI locations with `script2` and `sigScript2`.
69+
3. Replace `script` with `script2` and `sigScript` with `sigScript2`.
70+
71+
- Update script signing key
72+
1. The token issuer samples a new script signing key pair denoted `scriptPrivKey2` for the private part and `scriptKeyAddr2` for the public part.
73+
2. The token issuer signs `script` using `scriptPrivKey2` to get `sigScript2` and then replaces `sigScript` with `sigScript2` at all its URI locations.
74+
3. The token issuer calls `setVerificationKey(scriptKeyAddr2)`.
75+
4. Replace `scriptPrivKey` with `scriptPrivKey2`, `scriptKeyAddr` with `scriptKeyAddr2` and `sigScript` with `sigScript2`.
76+
77+
- Update script URI
78+
1. The token issuer moves `script` and `sigScript` from their current URI locations to all new relevant URI locations, and based on this constructs a new scriptURI structure.
79+
2. The token issuer signs the new scriptURI structure with the signing key `scriptPrivKey`. Denote the signature `sigScriptURI2`.
80+
3. The token issuer calls `setScriptURI` with the new scriptURI structure, along with `signScriptURI2`.
81+
4. Replace `scriptPrivKey` with `scriptPrivKey2`.
82+
83+
84+
### Specification
85+
The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY” and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
86+
87+
We define a scriptURI element using the following structs:
88+
89+
```
90+
struct ScriptURI {
91+
ScriptURIElement[] scriptURIElements;
92+
}
93+
struct ScriptURIElement {
94+
string URIOfScript;
95+
string URIOfSignature;
96+
}
97+
```
98+
99+
Based on these elements we define the smart contract interface below:
100+
```
101+
interface IERC5XXX {
102+
/// @dev This event emits when the scriptURI is updated,
103+
/// so wallets implementing this interface can update a cached script
104+
event ScriptUpdate(ScriptURI memory newScriptURI);
105+
106+
/// @dev This event emits when the script/scriptURI signing key is updated,
107+
/// so wallets implementing this interface can update a cached script
108+
event VerificationKeyUpdate(address memory newVerificationKey);
109+
110+
111+
/// @notice Get the scriptURI for the contract
112+
/// @return The scriptURI
113+
function getScriptURI() external view returns(ScriptURI memory);
114+
115+
/// @notice Get the scriptURI for the contract
116+
/// @return The scriptURI
117+
function getVerificationKey) external view returns(address memory);
118+
119+
120+
/// @notice Update the scriptURI
121+
/// emits event ScriptUpdate(ScriptURI memory newScriptURI);
122+
function setScriptURI(ScriptURI memory newScriptURI, bytes memory newSigScriptURI) external;
123+
124+
/// @notice Set the script/scriptURI signing key
125+
/// emits event VerificationKeyUpdate(address memory newVerificationKey);
126+
function setVerificationKey(address memory newVerificationKey)
127+
}
128+
```
129+
The interface MUST be implemented under the following constraints:
130+
131+
- The smart contract implementing `IERC5XXX` MUST store variables `address verificationKey` and `address owner` in its state.
132+
133+
- The smart contract implementing `IERC5XXX` MUST set `owner=msg.sender` in its constructor.
134+
135+
- The ```ScriptUpdate``` event MUST be emitted when the ```setScriptURI``` function updates the scriptURI.
136+
137+
- The ```VerificationKeyUpdate``` event MUST be emitted when the ```setVerificationKey``` function updates the signing key.
138+
139+
- The ```setVerificationKey``` function MUST update the state `verificationKey` to contain `newVerificationKey` if and only if `owner == msg.sender`.
140+
141+
- The `setScriptURI` function MUST validate that `newSigScriptURI` contains a signature on `newScriptURI`, validated against `verificationKey` stored in its state, *before* executing its logic and updating any state.
142+
143+
- The ```getScriptURI()``` function MAY be implemented as pure or view.
144+
145+
- Any user of the script learned from scriptURI MUST, validate the script and its signature against `verificationKey` before trusting it.
146+
147+
148+
### Rationale
149+
Using this method avoids the need for building secure and certified centralised hosting and allow scripts to be hosted anywhere: IPFS, github or cloud storage.
150+
151+
### Backwards Compatibility
152+
This standard is compatible with all Token standards (ERC20, 721, 777, 1155 etc).
153+
154+
### Examples
155+
We here go through a couple of examples of where an authenticated script is relevant for adding additional functionality for tokens.
156+
157+
1. A Utility NFT is a ticket and the authenticated script is a JavaScript 'minidapp' which asks the user to sign a challenge message that shows ownership of the key controlling the ticket. The dapp would then render the signature as a QR code which can be scanned by a ticketing app, which could then mark the ticket used (offchain perhaps).
158+
159+
2. Smart Token Labs uses a framework called TokenScript; one element of which is a user interface description for contract interaction.
160+
Simple example: definition for a 'mint' function. This is a simple verb description similar to a JSON contract ABI definition; where the script gives the verb "Mint" and defines how the contract is called - in this case the contract function name 'mint' and attached value for mint fee. In use: for example a Punks v(x) owner wants to mint another punk, the owner can open their punks in wallet or on supported websites and there will be a 'Mint' verb on the token which when clicked will mint a new Punk without needing to reference the mintFee or connect a wallet etc.
161+
162+
3. Smartlock controlling NFT script which defines an HTML view and two verbs "lock" and "unlock". Each verb has a JavaScript control script. When the token is selected, the HTML view would be displayed and an attached JavaScript would fetch a challenge string from the lock controller. When each verb is selected by the user in the hosting app or website, the relevant script attached to the verb would execute, prompting the user to sign the challenge then sending the challenge to the lock controller, which would reply with a pass or fail and execute an action accordingly. This is an offchain example that uses onchain assets for functionality.
163+
164+
### Test Cases
165+
Test Contract
166+
pragma solidity 0.8.10;
167+
import "./IERC5XXX.sol";
168+
169+
... TODO
170+
171+
172+
### Security Considerations
173+
No security issues found.

0 commit comments

Comments
 (0)