Token Card will be in the top right corner of the screen
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/bootstrap-js/tests/helpers.test.js:
--------------------------------------------------------------------------------
1 | let ts = require("../modules/ts_helpers.js");
2 |
3 | test("Returns string query compared to object", () => {
4 | let str1 = "(&(objectClass=Person)(!(price<=4444))(|(locality=Jensen)(locality=Sydney)(locality=Babs J*)((locality=Sy*))))";
5 | let str2 = "(&(!(price<=4444))(|(locality=Jensen)(locality=Sydney)(locality=Babs J*)((locality=Sy*))))";
6 | let str3 = "(ownerBalance=)";
7 | let props = {
8 | locality: 'Sydney',
9 | state: 'NSW',
10 | price: 15559
11 | }
12 | expect(ts.compareStringToProps(str1, props)).toBe(0);
13 | expect(ts.compareStringToProps(str2, props)).toBe(1);
14 | expect(ts.compareStringToProps(str3, props)).toBe(0);
15 | expect(ts.compareStringToProps(" ", props)).toBe(1);
16 | });
17 |
18 | /**
19 | * @jest-environment jsdom
20 | */
21 | test("test getContractAddress", () => {
22 |
23 |
24 | let tokenXMLText = '\n' +
25 | '' +
31 | ' \n' +
32 | ' 0x63cCEF733a093E5Bd773b41C96D3eCE361464942\n' +
33 | ' 0xFB82A5a2922A249f32222316b9D1F5cbD3838678\n' +
34 | ' 0x59a7a9fd49fabd07c0f8566ae4be96fcf20be5e1\n' +
35 | ' 0x2B58A9403396463404c2e397DBF37c5EcCAb43e5\n' +
36 | ' ' +
37 | '';
38 |
39 | var parser = new DOMParser();
40 | let xmlDoc = parser.parseFromString(tokenXMLText, "text/xml");
41 | let nsResolver = xmlDoc.createNSResolver( xmlDoc.ownerDocument == null ? xmlDoc.documentElement : xmlDoc.ownerDocument.documentElement);
42 | let tokenNodes = xmlDoc.evaluate('/ts:token', xmlDoc, nsResolver, XPathResult.ANY_TYPE, null );
43 | let tokenNode = tokenNodes.iterateNext();
44 |
45 | expect(ts.getContractAddress(xmlDoc, "EntryToken", tokenNode, 3)).toMatchObject({'contractAddress':'0xFB82A5a2922A249f32222316b9D1F5cbD3838678','contractInterface':'erc875'});
46 | expect(ts.getContractAddress(xmlDoc, "EntryToken", tokenNode, 42)).toMatchObject({contractInterface:'erc875',contractAddress:'0x2B58A9403396463404c2e397DBF37c5EcCAb43e5'});
47 | });
48 |
49 | // test("test getJSONAbi", () => {
50 | //
51 | // global.fetch = jest.fn((url) =>
52 | // Promise.resolve({
53 | // status: 400
54 | // })
55 | // );
56 | //
57 | // expect(ts.getJSONAbi('somecontract',{})).toBe(false);
58 | //
59 | //
60 | //
61 | // });
62 |
63 | it('getJSONAbi file not found', () => {
64 | expect.assertions(1);
65 |
66 | global.fetch = jest.fn((url) =>
67 | Promise.resolve({
68 | status: 400
69 | })
70 | );
71 |
72 | return expect(ts.getJSONAbi('somecontract',{})).resolves.toEqual(false);
73 |
74 | });
75 |
76 | it('getJSONAbi already added', async () => {
77 | expect.assertions(1);
78 | const data = await ts.getJSONAbi('somecontract',{somecontract:{val1: 2}});
79 | expect(data).toMatchObject({val1: 2});
80 | });
81 |
82 |
83 |
--------------------------------------------------------------------------------
/bootstrap-js/tests/modules.test.js-off:
--------------------------------------------------------------------------------
1 | let ts = require("../tokenscript-bootstrap");
2 |
3 | test("Returns string query compared to object", () => {
4 | let str1 = "(&(objectClass=Person)(!(price<=4444))(|(locality=Jensen)(locality=Sydney)(locality=Babs J*)((locality=Sy*))))";
5 | let str2 = "(&(!(price<=4444))(|(locality=Jensen)(locality=Sydney)(locality=Babs J*)((locality=Sy*))))";
6 | // str = "locality=Sydney";
7 | let props = {
8 | locality: 'Sydney',
9 | state: 'NSW',
10 | price: 15559
11 | }
12 | expect(ts.compareStringToProps(str1, props)).toBe("0");
13 | expect(ts.compareStringToProps(str2, props)).toBe("1");
14 | });
--------------------------------------------------------------------------------
/bootstrap-js/tests/tokenscript-bootstrap.test.js-off:
--------------------------------------------------------------------------------
1 | let ts = require("../tokenscript-bootstrap");
2 |
3 | test("Returns string query compared to object", () => {
4 | let str1 = "(&(objectClass=Person)(!(price<=4444))(|(locality=Jensen)(locality=Sydney)(locality=Babs J*)((locality=Sy*))))";
5 | let str2 = "(&(!(price<=4444))(|(locality=Jensen)(locality=Sydney)(locality=Babs J*)((locality=Sy*))))";
6 | // str = "locality=Sydney";
7 | let props = {
8 | locality: 'Sydney',
9 | state: 'NSW',
10 | price: 15559
11 | }
12 | expect(ts.compareStringToProps(str1, props)).toBe("0");
13 | expect(ts.compareStringToProps(str2, props)).toBe("1");
14 | });
--------------------------------------------------------------------------------
/bootstrap-js/ts.scss:
--------------------------------------------------------------------------------
1 | .ts_token_bar {
2 | position: absolute;
3 | top:20px;
4 | right: 20px;
5 | //border: 1px solid #eee;
6 | border-radius: 20px;
7 | background: #f5f5f5;
8 |
9 | &.opened {
10 | background-color: #c8dadf;
11 | outline: 2px dashed #92b0b3;
12 | outline-offset: -7px;
13 | padding-bottom: 10px;
14 | }
15 |
16 |
17 | &:not(.opened) {
18 | overflow: hidden;
19 | }
20 |
21 | &_icon {
22 | width: 40px;
23 | height: 40px;
24 | background: #f002;
25 | background-size: 30px 30px;
26 | background-repeat: no-repeat;
27 | background-position: center;
28 | cursor: pointer;
29 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='70' height='50' viewBox='0 0 70 50'%3E%3Cdefs%3E%3Cpath id='prefix__a' d='M0 0.07L48.973 0.07 48.973 49.874 0 49.874z'/%3E%3Cpath id='prefix__c' d='M0 49.93L249.973 49.93 249.973 0.126 0 0.126z'/%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath fill='%23FFD400' d='M51.825 23.33c0 2.75-2.23 4.982-4.982 4.982-2.75 0-4.98-2.232-4.98-4.983 0-2.75 2.23-4.982 4.98-4.982 2.751 0 4.982 2.232 4.982 4.982'/%3E%3Cpath fill='%2381BA28' d='M56.382 20.857c-.06.094-.121.186-.179.28l-.001-.001c.059-.094.119-.185.18-.279'/%3E%3Cpath fill='%23FFF' d='M56.382 20.857c-.06.094-.121.186-.179.28l-.001-.001c.059-.094.119-.185.18-.279'/%3E%3Cpath fill='%2381BA28' d='M68.275 2.142c-.695 1.11-10.003 15.75-10.898 17.154-.207.326-.41.64-.608.955l-.387.605c-.972-3.759-4.108-6.65-8.002-7.26.177-.279 5.638-8.918 7.018-11.112.156-.253.296-.44.645-.438 4.017.013 8.03.013 12.047.016.036 0 .074.03.185.08'/%3E%3Cpath fill='%23E52F2E' d='M70.598 44.588c-2.01 2.386-4.275 4.07-7.153 4.747-3.952.929-7.72.508-11.093-1.935-2.455-1.774-3.95-4.257-5.037-7.02-.032-.081-.07-.178-.113-.294-.008-.022-.019-.045-.026-.069-.281-.74-.769-2.08-1.247-3.527-.389-1.182-.768-2.437-1.022-3.5.627.126 1.275.19 1.938.19 2.925 0 5.555-1.277 7.355-3.301l.022-.022c.663 1.642 1.351 4.22 2.006 6.222l.006.016c.179.547.353 1.052.529 1.483.726 1.814 1.498 3.588 2.956 4.936.097.089.199.176.302.262 1.9 1.574 4.172 1.984 6.544 2.061 1.288.043 2.566-.134 4.033-.25'/%3E%3Cg transform='translate(0 .055)'%3E%3Cmask id='prefix__b' fill='%23fff'%3E%3Cuse xlink:href='%23prefix__a'/%3E%3C/mask%3E%3Cpath fill='%234BBCEC' d='M38.509 28.53c-2.334 3.265-4.867 6.371-7.844 9.126-2.51 2.32-5.184 4.396-8.41 5.648-1.23.48-2.505.742-3.83.73-3.746.009-6.436-2.338-7.232-6.26-.707-3.485-.35-6.918.628-10.277 1.811-6.222 4.993-11.723 9.214-16.613 1.91-2.212 4.103-4.113 6.968-5.024 2.024-.643 4.063-.825 6.042.19 1.526.785 2.588 2.05 3.436 3.498 1.208 2.057 1.956 4.289 2.604 6.56 1.763-1.666 4.141-2.686 6.76-2.686.521 0 1.035.042 1.535.12l.593-.935c-.45-1.035-.83-1.975-1.26-2.89-1.339-2.852-3.17-5.318-5.807-7.098C38.776.508 35.302-.17 31.57.143c-4.755.396-9.191 1.78-13.245 4.282-6.44 3.982-11.497 9.31-15.045 16.005C1.005 24.715-.303 29.278.06 34.189c.47 6.335 3.662 10.866 9.34 13.636 4.417 2.156 9.118 2.35 13.882 1.765 3.958-.486 7.69-1.786 11.13-3.777 4.176-2.416 7.794-5.565 11.164-8.998.116-.12.19-.297.354-.38-.39-1.183-.768-2.437-1.02-3.5-2.69-.535-4.984-2.165-6.401-4.405' mask='url(%23prefix__b)'/%3E%3C/g%3E%3Cmask id='prefix__d' fill='%23fff'%3E%3Cuse xlink:href='%23prefix__c'/%3E%3C/mask%3E%3C/g%3E%3C/svg%3E%0A");
30 | }
31 | & &_head {
32 | position: relative;
33 | &:after {
34 | opacity: 0;
35 | content: '';
36 | display: block;
37 | background-color: #fff8;
38 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512' %3E%3Cpath fill='%23000' d='M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z'%3E%3C/path%3E%3C/svg%3E");
39 | position: absolute;
40 | top: 0;
41 | left: 0;
42 | width: 100%;
43 | height: 100%;
44 | background-repeat: no-repeat;
45 | background-position: center;
46 | background-size: 25px;
47 | transition: opacity 0.3s;
48 | }
49 | &:hover:after {
50 | opacity: 1;
51 | }
52 | }
53 | &.opened &_head:after {
54 | transform: rotate(180deg);
55 | }
56 | &.opened {
57 | border-radius: 4px;
58 | width: 380px;
59 | //height: auto;
60 | }
61 |
62 | &.opened &_icon {
63 | opacity: 0 !important;
64 | display: none;
65 | }
66 | &:not(.opened) &_title,
67 | &:not(.opened) &_body
68 | {
69 | display: none;
70 | }
71 | &.opened &_title {
72 | text-align: center;
73 | font-size: 20px;
74 | padding: 10px;
75 | }
76 | & &_body
77 | {
78 | padding: 10px;
79 | min-height: 150px;
80 | .def {
81 | position: absolute;
82 | }
83 | .ts_token_wrap {
84 | //margin-top: 10px;
85 | margin-bottom: 10px;
86 | background: #fff;
87 | position: relative;
88 | box-sizing: border-box;
89 | .sidebar_toggle {
90 | padding: 2px 5px;
91 | background: #c8dadf;
92 | margin: 5px;
93 | //float: left;
94 | display: inline-block;
95 | border-radius: 4px;
96 | cursor: pointer;
97 | transition: all 0.5s;
98 | position: relative;
99 | &:hover {
100 | box-shadow: inset 0 -3.25em 0 0 #eee;
101 | }
102 | &:after {
103 | content: '';
104 | position: absolute;
105 | display: block;
106 | width: 10px;
107 | height: 10px;
108 | top: -4px;
109 | right: -5px;
110 | background: red;
111 | border-radius: 100px;
112 | border: 1px solid #92b0b3;
113 | opacity: 0;
114 | transition: opacity 0.5s;
115 | }
116 | &.has_events {
117 | &:after {
118 | opacity: 1;
119 | }
120 | }
121 | }
122 |
123 | iframe {
124 | width: 100%;
125 | box-sizing: border-box;
126 | }
127 | .activity_cards {
128 | position: absolute;
129 | right: 100%;
130 | //width: 360px;
131 | background: #eee;
132 | top: 0;
133 | transform: translateX(-20px);
134 | padding: 10px;
135 | max-height: 85vh;
136 | overflow: auto;
137 | max-width: calc(100vw - 460px);
138 | &.opened {
139 | background-color: #c8dadf;
140 | outline: 2px dashed #92b0b3;
141 | outline-offset: -7px;
142 | padding-bottom: 10px;
143 | }
144 | & > div {
145 | min-width: 320px;
146 | padding: 0 5px;
147 | }
148 | &:not(.opened) {
149 | display: none;
150 | }
151 | .sidebar_toggle {
152 | display: none;
153 | }
154 | iframe {
155 | border: none;
156 | height: 45px;
157 | }
158 | h3 {
159 | margin-bottom: 0;
160 | margin-top: 0.2em;
161 | }
162 | }
163 |
164 | }
165 |
166 | .ts_connect {
167 | margin-top: 80px;
168 | }
169 |
170 | }
171 |
172 | }
173 |
174 | .ts_btn_std {
175 | padding: 2px 5px;
176 | background: #ccc;
177 | border-radius: 4px;
178 | cursor: pointer;
179 | transition: all 0.5s;
180 | text-align: center;
181 | &:hover {
182 | box-shadow: inset 0 -3.25em 0 0 #eee;
183 | }
184 | }
185 | /*
186 | #ts_select_token {
187 | width: 100%;
188 | display: flex;
189 | flex-direction: column;
190 | justify-content: center;
191 | align-items: center;
192 | position: fixed;
193 | max-height: 100vh;
194 | overflow-y: auto;
195 | background: #000c;
196 | height: 100vh;
197 | top: 0;
198 | left: 0;
199 | opacity: 1;
200 | transition: opacity 0.3s;
201 | z-index: 10;
202 | &.disabled {
203 | opacity: 0;
204 | pointer-events: none;
205 | }
206 | .ts_select_box {
207 | padding: 30px;
208 | background: #fff;
209 | border-radius: 4px;
210 | border: 1px solid #000;
211 | width: 300px;
212 | text-align: center;
213 | position: relative;
214 | .ts_close {
215 | position: absolute;
216 | top: -10px;
217 | right: -10px;
218 | display: block;
219 | width: 25px;
220 | height: 25px;
221 | border-radius: 50%;
222 | border: 2px solid #9e9e9e;
223 | background: #fff;
224 | background-position: center;
225 | background-repeat: no-repeat;
226 | background-size: 13px;
227 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512' %3E%3Cpath fill='currentColor' d='M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z' class=''%3E%3C/path%3E%3C/svg%3E");
228 | cursor: pointer;
229 | }
230 | h2 {
231 | //color: #fff;
232 |
233 | }
234 |
235 | .ts_token {
236 | border: 1px solid #eee;
237 | background: #f5f5f5;
238 | padding: 10px 20px;
239 | font-size: 20px;
240 | width: 100%;
241 | margin-top: 10px;
242 | text-align: center;
243 | box-sizing: border-box;
244 | transition: 0.25s;
245 | cursor: pointer;
246 | &:hover {
247 | //box-shadow: 0 0.5em 0.5em -0.4em #eee;
248 | //transform: translateY(-0.25em);
249 | box-shadow: inset 0 -3.25em 0 0 #eee;
250 | }
251 | }
252 | }
253 | }
254 | */
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 | .box
263 | {
264 | font-size: 1.25rem; /* 20 */
265 | background-color: #c8dadf;
266 | position: relative;
267 | padding: 40px 20px;
268 | text-align: center;
269 | outline: 2px dashed #92b0b3;
270 | outline-offset: -10px;
271 | -webkit-transition: outline-offset .15s ease-in-out, background-color .15s linear;
272 | transition: outline-offset .15s ease-in-out, background-color .15s linear;
273 |
274 | max-width: 500px;
275 | width: 100%;
276 | }
277 |
278 | .box.is-dragover
279 | {
280 | outline-offset: -20px;
281 | outline-color: #c8dadf;
282 | background-color: #fff;
283 | }
284 | .box__dragndrop,
285 | .box__icon
286 | {
287 | display: none;
288 | }
289 | .box.has-advanced-upload .box__dragndrop
290 | {
291 | display: inline;
292 | }
293 | .box.has-advanced-upload .box__icon
294 | {
295 | width: 100%;
296 | height: 80px;
297 | fill: #92b0b3;
298 | display: block;
299 | margin-bottom: 40px;
300 | }
301 |
302 | .box.is-uploading .box__input,
303 | .box.is-success .box__input,
304 | .box.is-error .box__input
305 | {
306 | visibility: hidden;
307 | }
308 |
309 | .box__uploading,
310 | .box__success,
311 | .box__error
312 | {
313 | display: none;
314 | }
315 | .box.is-uploading .box__uploading,
316 | .box.is-success .box__success,
317 | .box.is-error .box__error
318 | {
319 | display: block;
320 | position: absolute;
321 | top: 50%;
322 | right: 0;
323 | left: 0;
324 |
325 | -webkit-transform: translateY( -50% );
326 | transform: translateY( -50% );
327 | }
328 | .box__uploading
329 | {
330 | font-style: italic;
331 | }
332 | .box__success
333 | {
334 | -webkit-animation: appear-from-inside .25s ease-in-out;
335 | animation: appear-from-inside .25s ease-in-out;
336 | }
337 | @-webkit-keyframes appear-from-inside
338 | {
339 | from { -webkit-transform: translateY( -50% ) scale( 0 ); }
340 | 75% { -webkit-transform: translateY( -50% ) scale( 1.1 ); }
341 | to { -webkit-transform: translateY( -50% ) scale( 1 ); }
342 | }
343 | @keyframes appear-from-inside
344 | {
345 | from { transform: translateY( -50% ) scale( 0 ); }
346 | 75% { transform: translateY( -50% ) scale( 1.1 ); }
347 | to { transform: translateY( -50% ) scale( 1 ); }
348 | }
349 |
350 | .box__restart
351 | {
352 | font-weight: 700;
353 | }
354 | .box__restart:focus,
355 | .box__restart:hover
356 | {
357 | color: #39bfd3;
358 | }
359 |
360 | .js .box__file
361 | {
362 | width: 0.1px;
363 | height: 0.1px;
364 | opacity: 0;
365 | overflow: hidden;
366 | position: absolute;
367 | z-index: -1;
368 | }
369 | .js .box__file + label
370 | {
371 | max-width: 80%;
372 | text-overflow: ellipsis;
373 | white-space: nowrap;
374 | cursor: pointer;
375 | display: inline-block;
376 | overflow: hidden;
377 | }
378 | .js .box__file + label:hover strong,
379 | .box__file:focus + label strong,
380 | .box__file.has-focus + label strong
381 | {
382 | color: #39bfd3;
383 | }
384 | .js .box__file:focus + label,
385 | .js .box__file.has-focus + label
386 | {
387 | outline: 1px dotted #000;
388 | outline: -webkit-focus-ring-color auto 5px;
389 | }
390 | .js .box__file + label *
391 | {
392 | /* pointer-events: none; */ /* in case of FastClick lib use */
393 | }
394 |
395 | .no-js .box__file + label
396 | {
397 | display: none;
398 | }
399 |
400 | .no-js .box__button
401 | {
402 | display: block;
403 | }
404 | .box__button
405 | {
406 | font-weight: 700;
407 | color: #e5edf1;
408 | background-color: #39bfd3;
409 | display: block;
410 | padding: 8px 16px;
411 | margin: 40px auto 0;
412 | }
413 | .box__button:hover,
414 | .box__button:focus
415 | {
416 | background-color: #0f3c4b;
417 | }
418 |
419 | .box {
420 | .submit_btn {
421 | font-weight: 700;
422 | color: #e5edf1;
423 | background-color: #39bfd3;
424 | display: block;
425 | padding: 8px 16px;
426 | margin: 20px auto 0;
427 | cursor: pointer;
428 | }
429 | }
430 |
431 | .options-box {
432 | outline: 2px dashed #92b0b3;
433 | outline-offset: -10px;
434 | -webkit-transition: outline-offset .15s ease-in-out, background-color .15s linear;
435 | transition: outline-offset .15s ease-in-out, background-color .15s linear;
436 | max-width: 500px;
437 | width: 100%;
438 | margin-top: 20px;
439 | font-size: 1.25rem;
440 | background-color: #c8dadf;
441 | position: relative;
442 | padding: 20px;
443 | text-align: center;
444 | textarea {
445 | width: 100%;
446 | box-sizing: border-box;
447 | height: 6em;
448 | padding: 0.2em;
449 | line-height: 1.4em;
450 | }
451 | }
452 |
453 | .remote-download-box {
454 | input {
455 | width: 100%;
456 | box-sizing: border-box;
457 | }
458 | }
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | CJK_FONT=AR PL UMing TW
2 | PANDOC_OPTIONS=-V geometry:margin=1.5in
3 |
4 | # Pandoc uses rsvg-convert to embed SVG in PDF files.
5 | # Make sure that command is installed.
6 |
7 | papers : short_paper.pdf design_paper.pdf
8 |
9 | short_paper.pdf : short_paper.md
10 | pandoc $(PANDOC_OPTIONS) -o short_paper.pdf short_paper.md
11 | design_paper.pdf : design_paper.md
12 | # the design paper has some ideographs
13 | pandoc $(PANDOC_OPTIONS) -V CJKmainfont="$(CJK_FONT)" --pdf-engine=xelatex -o design_paper.pdf design_paper.md
14 |
--------------------------------------------------------------------------------
/doc/The tech Stack.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartTokenLabs/TokenScript/0581e9c0448483c71555139c537cde9c1e99ac28/doc/The tech Stack.docx
--------------------------------------------------------------------------------
/doc/articles/We need a better framework for applications using blockchain 中文:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/doc/articles/data-object.md:
--------------------------------------------------------------------------------
1 | # The way we treat data on the blockchain is wrong—this is how it’s supposed to work (pt1)
2 |
3 | Here in the TokenScript project, we are adapting tried-and-true methods (that have borne fruit in cryptography engineering for decades) to public blockchains.
4 |
5 | Unfortunately, data on the blockchain is not being used for its intended purpose. People are blaming Ethereum “congestion” while writing smart contracts that forward chit-chat messages. But having a blockchain strewn with "crypto-graffiti" isn’t even the biggest problem.
6 |
7 | The biggest problem, in our view, is that the data simply is not structured for interoperability, extensibility and longevity.
8 |
9 | In other words, the data’s structure is tailored for use in only one token project —— this specificity tends to cause problems in other projects that uses the token. Many data structures are abandoned as changes are introduced, and messages already signed can't be used.
10 |
11 | I’ll start with an example data object, illustrate how it could be treated differently, then introduce you to the TokenScript’s data-object (which is a work in progress).
12 |
13 | ## Example of data objects
14 |
15 | We’ll start with an example, which we’ll later generalise.
16 |
17 | Imagine an event ticket as a data object, encoded in JSON:
18 |
19 | 
20 |
21 | This object, a ticket, carries the following information:
22 |
23 | 1. This is the 24th ticket issued.
24 | 2. The ticket is “class 2” (analogous to a VIP-class ticket).
25 | 3. The event commences on January 1, 2020 at 20:00.
26 |
27 | Such a data object may be used in a blockchain transaction. Suppose say we have an Ethereum smart contract that transfers a ticket’s ownership:
28 |
29 | function transfer_ticket(string ticket, address newOwner)
30 |
31 | Having the data object in JSON format will consume a lot of “gas,” however, because it increases the transaction size and the required effort for smart contract parsing. The data object needs to be tightly packed, and to make that happen, we must first separate the data from its schema.
32 |
33 | ## Separation of data and schema
34 |
35 | For the *data*, we encode it into this 20 bytes: 0x3012020118020102180A32303230303130313230. Observe how the 20 bytes contained the 3 pieces of information:
36 |
37 | 0x30 12 02 01 18 0A 01 02 18 0A 32 30 32 30 30 31 30 31 32 30
38 | -- -- +----------------------------
39 | ^ ^ ^
40 | 24 2 2 0 2 0 1 0 1 0 2 0
41 |
42 | Observe the ticket number `24` is encoded as `0x18`; the ticket class "VIP" encoded as `0x02`; the date is encoded in an ASCII string. The in-between structural-bytes are the result of using standard DER encoding rules†.
43 |
44 | For the *schema*, we write it in ASN.X (an XML schema language).
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | Schema has to be stored outside of the smart contract. In our TokenScript project the schema is stored in TokenScript so that wallets and dapp browsers compatible with TokenScript can use the schema to understand the 20 bytes of data. You can store it in other formats‡ but you shouldn’t store it directly in a smart contract, instead, the schema can be *compiled* into a terse piece of solidity bytecode for the smart contract to parse the 20 bytes.[^2]
59 |
60 | ## Using the schema
61 |
62 | Once we have separated the data from its schema, our Ethereum smart contract function becomes:
63 |
64 | function transferTicketing(bytes ticket, address newOwner)
65 |
66 | Where `string` is replaced by `bytes` to accept the DER-encoded 20 bytes.
67 |
68 | Let's take a closer look by showing a few lines before and after the function declaration:
69 |
70 | struct Ticket {
71 | uint numero; // the sequence number of the ticket
72 | uint class; // 0: normal, 1: gifted, 2: VIP
73 | string start; // start time of the event
74 | }
75 |
76 | function transferTicketing(bytes ticket, address newOwner)
77 | {
78 | Ticket ticketObj = parse_ticket(ticket);
79 | ...
80 | }
81 |
82 | The function `parse_ticket` consists of code compiled from the schema. This is considerably more efficient than a JSON parser.
83 |
84 | On the other hand, should a dapp need to construct such DER-encoded bytes for use in a transaction, or should the user’s wallet need to display an already-constructed transaction in a user-readable way, it can rely on the schema.
85 |
86 | ## Why the fuzz?
87 |
88 | So what's the advantage of this DER or ASN fuzz over the following straightforward, newbie-friendly method?
89 |
90 | function transferTicket(uint numero, uint class, string start, address newOwner)
91 |
92 | Or this more structured version?
93 |
94 | function transferTicket(Ticket ticket, address newOnwer)
95 |
96 | Is it just for making the transactions shorter?
97 |
98 | The answer to both these questions is “yes,” and there’s more to that “yes” than one may assume. At the outset, this decreases transaction payload by more than 50%, albeit with more advantages:
99 |
100 |
101 | ## Reason 1: Attestation
102 |
103 | A string of DER-encoded bytes is useful for signing. Why do you need to sign it, though?
104 |
105 | To get an attestation. We call signed data objects "attestation," since it's the signer attesting to something.
106 |
107 | Let's examine the ticket example again. At first, you might imagine that a ticket contract holds all tickets and information regarding their ownership. For example, when "Alice" transfers a ticket to "Bob," Alice initiates a transaction which reassigns the ownership of that ticket to Bob.
108 |
109 | An event organiser might issue thousands, if not tens of thousands of tickets for an event, and most of the people who receive the issued tickets will not then transfer them to someone else. If there isn't a transfer scenario, the ticket need not appear in the blockchain. The event organiser can sign an attestation, where they attest the ticket's ownership to a certain Ethereum key holder. The keyholder can prove their ownership via a challenge-response protocol.
110 |
111 | On the other hand, if data is encoded in JSON, it can’t be signed safely since JSON is not a deterministic encoding.
112 |
113 | Attestation is generally useful. Here are a few examples.
114 |
115 | - You can write a smart contract in such a way that a user attested to be a Sophisticated Investor can make purchases in an ICO pre-sale.
116 |
117 | - A car insurance company can attest to the fact that your car (represented here by an Ethereum token) is insured.
118 |
119 | - If your car is a smart vehicle and you authorises a friend to drive it, you can write an attestation without sending an Ethereum transaction.
120 |
121 | The schema for signing of attestations should be adapted from existing standards, rather than inventing new ones and recreate security issues already solved in existing standards. TokenScript is [working on such an schema adaptation](https://community.tokenscript.org/t/weekly-design-meeting-16-simple-attestation-format/302). There are much further work to be done. For example, we need a format that can do partial attestation by using Merkle Tree, or even zero-knowledge proof of attestation.
122 |
123 | ## Reason 2: Data-Interoperability
124 |
125 | DER-encoded data has better interoperability. Continuing with the ticket attestation example: which systems need to use the attestation? We already know about the following.
126 |
127 | 1. **Smart contracts**. If Alice wishes to sell her ticket (in the form of an attestation), the smart contract needs to check the event organiser’s signature.
128 |
129 | 2. **Wallets**. The attestation’s contents must be properly understood for a correct display in a user’s wallet. Should any transaction involve the attestation, it will inform the user of what’s in the transaction. (Dapp browsers have the same need.)
130 |
131 | That’s not all. The event organiser’s website also needs to know how to read the attestation, since a ticket holder may use it to log in to a website to check for updates. The doorman (or a turnstile, their modern equivalent) needs to read this data (perhaps through a QR code).
132 |
133 | Even the Embassy and border police use these attestations—throughout the last year, fully-attested FIFA tickets (called Fan ID) were used to cross the Russian border in lieu of a VISA.
134 |
135 | It’s not difficult to recognize that there are many systems interested in attestations, and these systems are heterogeneous. For example, a smart contract belongs to blockchain, and a Wallet belongs to mobile app. When it comes to the event organiser’s website, JSON representation may be needed. The turnstile at the gate is an IoT system which accepts QR codes. Since on the system depends on a verified signature, it can’t be converted it at will —— a uniformed presentation of the signed data would be necessary in that circumstance.
136 |
137 | Should there be any alteration of the data schema (such as, for instance, the introduction of an additional ticket class called “VVIP”), one can’t reasonably expect all these decentralised systems to be updated together. If the data is schema-driven, however, the schema can be updated to facilitate a relatively easy update.
138 |
139 | You may think your token ought not to be used across so many systems. The reality is: one can never be sure. One of the major strengths of decentralised platform like Ethereum is the capacity for buidl. There are more than a few systems which uses DAI were developed without MakerDAO’s authorisation. Such buidl wouldn’t be possible with traditional centralised systems like American Express Connect.
140 |
141 | ## Reason 3: Extensibility
142 |
143 | Extensibility is tightly connected to interoperability. Always bear in mind that once data is signed, it can’t be “converted” for the consumption of a new system without invalidating its signature in the process. Thus, the systems must be built to understand old and new data alike (even if their schema has drifted in time).
144 |
145 | Suppose you are the beneficiary of a will that is in the form of crypto attestation. Once your parents pass away, you are ready to cash it out. You certainly don’t want the will contract, after undergoing a variety of upgrades throughout the years your parents lived, to reject the attestation and ask that it be signed again by your (now deceased) parents within a new data structure!
146 |
147 | One data structure that stood the test of time is X.509 certificates. It was invented before SSL, and its underlying data structure survived until now. X.509 certificate is designed as an ASN.1 module, which has built-in support for extensibility.
148 |
149 | Today’s blockchain data objects should also boast this support.
150 | There isn’t enough time to cover how this is done, but to summarize, extensibility depends on schema. For instance, a nicely defined schema enables one to perform tasks such as extending an array of data into a 2-dimensional matrix as required.
151 |
152 | # Where are we going from here?
153 |
154 | Here in TokenScript project we treat data correctly by adapting existing standards. TokenScript itself is designed to be standardized and is being mentored by OASIS (the same standard group behind Open Document ISO standards). To participate you can join:
155 |
156 | - [TokenScript Forum](http://community.tokenscript.org/)
157 | - Participate [the design meeting on Google Hangout Meet](https://meet.google.com/yix-kjmv-gsj) every Thursday 7pm Sydney time
158 | - If you live near Melbourne, Australia, participate [the meet-up on 22th Nov](https://meet.google.com/yix-kjmv-gsj)
159 | - Browse the [TokenScript project website](http://tokenscript.org) and the github repository (linked from that website).
160 |
161 | [^1]: DER is the default way to encode data in cryptography engineering. For example, Bitcoin signatures and X.509 certificates are encoded this way. If you want to inspect DER encodeded data, you can use openssl like this:
162 |
163 | $ echo -n 0x3012020118020102180A32303230303130313230 | xxd -r -p | openssl asn1parse -inform DER -i
164 | 0:d=0 hl=2 l= 18 cons: SEQUENCE
165 | 2:d=1 hl=2 l= 1 prim: INTEGER :18
166 | 5:d=1 hl=2 l= 1 prim: INTEGER :02
167 | 8:d=1 hl=2 l= 10 prim: GENERALIZEDTIME :2020010120
168 |
169 | [^2]: The same schema can be written in a equivalent shorthand format called ASN.1:
170 |
171 | ````
172 | SEQUENCE {
173 | numero INTEGER,
174 | class ENUMERATED { normal(0), gifted(1), vip(2) },
175 | date UTCTime
176 | }
177 | ````
178 | We choose to use XML so we can extend it to allow encoding in ABI as well.
179 |
180 | # The way we treat data on the blockchain is wrong—this is how it’s supposed to work (pt2)
181 |
182 | In my last article I made the following points;
183 |
184 | - Data on the blockchain should be extensible with a schema that can be signed;
185 | - Data itself should be tight and signed.
186 | -
--------------------------------------------------------------------------------
/doc/attribute-processing.md:
--------------------------------------------------------------------------------
1 | # Token Attributes
2 |
3 | A. I describe how to think of attributes and their origins and mappings as a pipeline below. A useful case to think through is a function origin which returns a GeneralisedTime (so we set as="utf8"), but the attribute syntax is GeneralisedTime (and hence the JavaScript object is expected to be our standard JavaScript GeneralisedTime class).
4 |
5 | B. Based on this, it would be good if we add as="address". The matching syntax type should be IA5 String (but Directory String will work too). We can return the JavaScript object as a string or if there's a suitable syntax that defines it as an address, we can create a simple class to wrap it (in the future?)
6 |
7 | C. To preserve precision, Numeric Strings are stored internally as a Big Integer, but returned as a JavaScript string (unless we want to support provide or endorse a big number library. Possibly later?)
8 |
9 | D. Note that according to https://tools.ietf.org/html/rfc4517#section-3.3.23, Numeric String is:
10 |
11 | ```
12 | NumericString = 1*(DIGIT / SPACE)
13 | DIGIT = %x30 / LDIGIT ; "0"-"9"
14 | LDIGIT = %x31-39 ; "1"-"9"
15 | ```
16 |
17 | Attribute as a pipeline:
18 |
19 | One way to look at an attribute type and their origin, and (optional) mapping is as a pipeline of 2 or 3 processing stages.
20 |
21 | With a mapping:
22 |
23 | ```
24 | A. Origin output with
25 | specific type (based on
26 | Inputs with "as"). Attribute
27 | specific B. Convert to string to be value with
28 | types used as mapping's input specific
29 | ─────────────▶ ┌──────────┐ ┌──────────┐ ┌──────────┐ type
30 | │ Origin │───────────▶ │ Mapping │──────────▶│ Syntax │─────────▶
31 | ─────────────▶ └──────────┘ └──────────┘ └──────────┘
32 |
33 | Mapping output is
34 | always a string.
35 |
36 |
37 | ```
38 |
39 |
40 | Without mappings:
41 |
42 | ```
43 | Inputs with Origin output with specific Attribute
44 | specific type (based on "as") value with
45 | types specific
46 | ─────────────▶ ┌──────────┐ ┌──────────┐ type
47 | │ Origin │───────────▶ │ Syntax │─────────▶
48 | ─────────────▶ └──────────┘ └──────────┘
49 |
50 |
51 |
52 | ```
53 |
54 | 1. Each stage has 0 or 1 input (or in the case of function origins, 0 or more inputs) and 1 output
55 |
56 | 2. All input and output are typed.
57 |
58 | 3. Ethereum function origins
59 |
60 | 1. A ethereum function origin's input types are already specified as Solidity types, eg. ``
61 | 2. Ethereum function origin's output type are specified with `as`, with each possible value mapping to exactly 1 Solidity type. Specifically:
62 |
63 | * as="uint" => uint256
64 | * as="int" => int256
65 | * as="utf8" => string
66 | * as="e18" => uint256
67 | * as="bool" => bool
68 |
69 | This type mapping is used to interpret (and validate) the smart contract function call return value.
70 |
71 | 4. User entry origin's output type is specified with `as`, eg. as="e18" and as="uint8"
72 |
73 | 5. Token ID-based origins' output type is specified with `as` similarly to user entry origins
74 |
75 | 6. Similar to ethereum function origins, user entry and token ID-based origins should use the `as` value to interpret the output
76 |
77 | 7. Mappings
78 |
79 | 1. Mappings always have string as the input type and output type
80 | 2. The output from the origin is converted to a string which is used as the key for the mapping
81 | 3. The output value is obtained, as a string
82 |
83 | 8. Syntax
84 |
85 | 1. The syntax stage takes the output from the mapping (which is typed string), if there is one.
86 | 2. The syntax stage takes the output from the origin, with a specific type in the absence of a mapping, as its input
87 | 3. The syntax stage converts the input to the output with a type based on the syntax:
88 |
89 | * Directory String, IA5 String => "string" (and JavaScript string)
90 | * Generalised Time => GeneralisedTime internally (and our standard Javascript GeneralisedTime type)
91 | * Integer => Big Integer internally (and JavaScript number)
92 | * Boolean => bool internally (and Javascript bool)
93 | * Numeric String => Big Integer internally (and JavaScript string)
94 |
95 | 9. This brings some consistency so we can expand the pipeline to more than 3 stages in the future
96 |
97 | 10. This is also useful when we have multiple origins which different types within the same attribute type
98 |
99 | 11. In ``, I just assume the function is an origin with as="void" (void is only used internally for consistency), so the output (if any) is dropped. In the future if we need to chain function calls (I don't know if we will ever need to), then it's just another pipeline of function origins with non-void as=""
100 |
101 | 12. Note while we say the input and output types are typed, TokenScript clients can still hold them internally as strings as long as it knows and can enforce the types they represent. That's an implementation detail. But such a case (assuming `getStreet()` returns a string) should not be permitted:
102 |
103 | ```
104 |
105 |
106 |
107 |
108 | Another Street
109 |
110 |
111 |
112 | ```
113 |
114 | But this is valid:
115 |
116 | ```
117 |
118 |
119 |
120 |
121 | Another Street
122 |
123 |
124 |
125 | ```
126 |
--------------------------------------------------------------------------------
/doc/authenticator.dia:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartTokenLabs/TokenScript/0581e9c0448483c71555139c537cde9c1e99ac28/doc/authenticator.dia
--------------------------------------------------------------------------------
/doc/authenticity+trustworthiness.md:
--------------------------------------------------------------------------------
1 | ## Authenticity and trustworthiness of a TokenScript
2 |
3 | (This document is not about the runtime security of Token Enclave - which will be documented separately. This deals with the authenticity and trustworthiness of a TokenScript on a textual level.)
4 |
5 | A TokenScript file can be signed. A TokenScript can also be trusted. Ideally, both should be done.
6 |
7 | At the moment, TokenScript is trusted through an "Express-of-Trust" transaction from the smart contract deployment key. In the future, a smart contract might be able to return the signing key needed for TokenScript. Both should work towards asserting the relationship between a Smart Contract and a TokenScript, hence establishing trust.
8 |
9 | However, trust coming from smart contract alone isn't sufficient to the end user, since the user has otherwise no way to assert if the smart contract is the one he intends to interact with, or a phishing contract. But when that trust is not available, having the TokenScript signed helps the end-user to ascribe trust by authenticity.
10 |
11 | - If a TokenScript is trusted, through an Express-of-Trust transaction, then the Smart Contract owner has either created or read the TokenScript and recommended the end-users to use it.
12 |
13 | - If a TokenScript is signed, the end-user can ascribe authenticity (the author and integrity), and if that author is known to the end-user, he is likely to trust it without the Express-of-Trust; otherwise, he makes his own decision.
14 |
15 | Or in other words:
16 |
17 | - signing a TokenScript establish authenticity of the TokenScript but not how much the token contract trusts it;
18 |
19 | - the express-of-trust transaction expresses that the token contract author trusts the TokenScript, but nothing about authenticity (who wrote it).
20 |
21 | Or in layman's terms:
22 |
23 | - Signing a TokenScript "connects" it to identity (e.g. a website, an organisation), with no guarantee if that identity is of a trustworthy entity.
24 | - Express-of-trust claims the TokenScript trustworthy, without connecting it to any identity.
25 |
26 | Both have their uses. If you are a token contract author, you can do express-of-trust to a TokenScript; however, there are cases that signed TokenScripts are needed:
27 |
28 | Case 1:
29 |
30 | A token issuer (custodian) want to reassure a user who trusts it by an external (non-blockchain) identity (e.g. website domain name) that he/she is using the correct contract. For example, a token issuer changed its main contract after discovering some security exploitation. It knows that its user trust it by domain name, so it might issue a token script that is signed by the same domain name with expressed trust from both the old and new contract to help the user to migrate.
31 |
32 | Case 2:
33 |
34 | A token issuer discarded his deployment key (or lost it), but still wish to let its user trust the TokenScript they provided by the help of providing authenticity (revealing the authorship).
35 |
36 | Case 3:
37 |
38 | A token issuer did not write a TokenScript, but a 3rd party did it; or that the 3rd party has provided additional features. If the 3rd party gained trust (e.g. through social media or within a community), it can sign and release its own TokenScript, and the users can accept them by the reputation of the 3rd part without the token contract's Express-of-Trust.
39 |
40 | (The cases of "mixed configuration", like when a 3rd party writes a TokenScript providing action in addition to the one written by the token issuer, is not covered in this introductory document. Instead, they are covered in the future modularisation documents.)
41 |
42 | ## Signed
43 |
44 | A signed TokenScript file is a TokenScript file signed through the use of an XML Signature. Any signature signing algorithm supported by XML Signature (including ECDSA supported through XML Signature 1.1) is accepted.
45 |
46 | At this moment, user agents should only accept such XML Signatures if certified by a certificate authority (CA). For convenience, a website certificate will do at this moment. In the years to come, implementations might require certificates from issuers who can validate an organisation or various forms of decentralised certificate issuers.
47 |
48 | When a signed TokenScript is used, the user agent displays the domain name or organisation name of the certificate. It's up to the user if they allow the use of such a TokenScript. We expect users to assert judgement based on whether or not they recognise the CommonName of the certificate.
49 |
50 | Revocation follows the same principles as these certificates normally do.
51 |
52 | ### Signing of external data
53 |
54 | Any data reference - icons, images and language packs - used by the TokenScript must be referred to in the `` section of the XML signature using `` element, or they will be considered not available (TokenScript implementations decide how to treat unavailable data). Each reference is downloaded and its digest verified as part of the TokenScript signature verification process. If any of the references fail to download or the digest doesn't match, the entire XML signature is bad.
55 |
56 | ## Trusted (Ethereum)
57 |
58 | A trusted TokenScript file is one explicitly trusted by the author of a token contract on Ethereum. Such trust is expressed by an Ethereum transaction. Only one signing algorithm, ECDSA (secp256k1), is used in express-of-trust because trust is expressed by an Ethereum transaction.
59 |
60 | Such trust is also revoked by a transaction.
61 |
62 | The transaction consists of a simple To address, with no data attached.
63 |
64 | ### The "from" address
65 |
66 | If the smart contract has no key-management on its own, the transaction should be sent from the smart contracts deployment key. If the smart contract has a key management function, the transaction should be sent from the current administrative key.
67 |
68 | ### The "to" address
69 |
70 | - to express trust, send any amount (e.g. 0Ξ) to a special address that represents the trust from the token contract (𝑡) to the TokenScript.
71 |
72 | - to express revocation, send any amount (e.g. 0Ξ) to another special address that represents the revocation of such trust.
73 |
74 | The express-of-trust special address is calculated in this way:
75 |
76 | TokenScript project's donation address is: `0x000bd52fb4f46f148b0ff0cc651048e283d2d000`. Its public key is *Y*, its value is:
77 |
78 | 0x483d69cc4377d318da81402f2488f588ccae3d22a37be36457a574487d9ca4d9c38cd62d83113e440c7bdc682ced6d05ee739b831c6d5cb01982367f76fc8ce0
79 |
80 | In multiplicative group notation, its value is 𝑔ˣ where 𝑥 is the private key held by TokenScript administration.
81 |
82 | First, we obtain a SHA256 digest 𝑑 from the exclusive canonicalization of the TokenScript. If this TokenScript happens to be signed as well, and the `` used for its root is SHA256 (it usually is), you can find the value encoded in base64 in the `` if it is signed. (Of course, you need to calculate this value if the TokenScript isn't signed.)
83 |
84 | Then compute *h=H(𝑡|"TRUST"|𝑑)* where *H* denotes Keccak. `|` is used to denote concatenation. The text *TRUST* is simply an ASCII encoding of the literal word TRUST.
85 |
86 | Then, we generate the secp256k1 elliptic curve point Yʰ, and hash it to get an address. This is the special address for express-of-trust of this specific TokenScript.
87 |
88 | This address can be independently generated by TokenScript implementations, without the knowledge of 𝑥. Hence trust can be verified independently. In the meanwhile, if an implementation has the TokenScript file, it can calculate the private key of that address by 𝑥·ℎ given that (𝑔ˣ)ʰ = (gʰ)ˣ.
89 |
90 | For revocation, the idea is the same, except the point used for the special address is now *h=H(𝑡|"REVOKE"|s)*.
91 |
92 | ## difference between trusted and signed
93 |
94 | ### Symantec: signing express authorship, not trust
95 |
96 | A signed TokenScript is no more trustworthy than the signer identified by CommonName. It has no cryptographically provable tie to the token itself. For example, we know by reputation that MakerDAO has the stewardship of the DAI token, so a TokenScript for DAI Token signed by MakerDAO.com is probably trustworthy.
97 |
98 | In other words, whether or not a signed TokenScript is trustworthy is the judgement of the user.
99 |
100 | Express-of-trust is stronger and more direct. The key holder which deployed (or manages) the DAI token contract explicitly expressed trust to that TokenScript by sending a transaction. It's time locked in a blockchain.
101 |
102 | It's worth noticing that Express-of-trust isn't authorship - a smart contract author can express trust to a signed TokenScript authored by someone else. While signed a TokenScript implies authorship.
103 |
104 | ### Signing isn't on the file; trust is
105 |
106 | A signed TokenScript is signed by an XML signature which usually is (but not required to) be embedded in an XML file. The cryptographic signature is not in the file; it's in the `` element of the XML Signature. The XML signature is not in the file either, it's on a collection of references which typically contains the root node of the TokenScript.
107 |
108 | ### Signing doesn't use Keccak at all; express of trust only uses Keccak
109 |
110 | Keccak isn't defined as a valid hashing method in XMLSIG11, so it can't be used in an XML Signature without extending the w3 recommendation behind it, which leads to trouble when validating with existing tools. Therefore we restrict the signing of TokenScript to the algorithms allowed in XMLSIG11.
111 |
112 | For the same reason, since developers might be habitually using Keccak in blockchain applications, we use Keccak to hash the TokenScript as well as the express-of-trust.
113 |
114 |
--------------------------------------------------------------------------------
/doc/data+filter.md:
--------------------------------------------------------------------------------
1 | # Data-objects and Tokens
2 |
3 | This article serves to tell the difference between a token (defined with a `` element) and data-objects (defined with a `` element). I will start by giving examples and end with a definition.
4 |
5 | Imagine a token with these attributes:
6 |
7 | {
8 | "objectClass": "CarToken",
9 | "ownerAddress": "0xdecafbad",
10 | "colour": "red",
11 | "rego": "4JHLC",
12 | "VIN": "KL3TA48E9EB541191"
13 | }
14 |
15 | It might be associated with a few types of objects, the owner of the car, lends it to Bob for 3 days, Alice will create an authorisation, which is an artifact with properties:
16 |
17 | {
18 | "objectClass": "AuthorisationToUse",
19 | "car": "rego=4JHLC",
20 | "user": "Bob",
21 | "start": 2019-09-09,
22 | "end": 2019-09-10,
23 | "allow": ["drive", "refuel", "service", "park", "locate"],
24 | "deny": ["collateralise", "sell", "trade", "lease"],
25 | "issuer": 0x809384902...80957FF # this is an Operational property derived from the signature
26 | }
27 |
28 | Let's move to a more advanced scenario of objects derived from the original CarToken. Let's say Alice collateralises it to get a loan, a *CollateralisedDebtObligation* token would be created:
29 |
30 | {
31 | "objectClass": "CollateralisedDebtObligation",
32 | "collateralType": "CarToken",
33 | "collateral": "VIN=KL3TA48E9EB541191",
34 | "value": 35,
35 | "CreateTimeStamp": 2019-09-09,
36 | "maturity": 2020-09-09
37 | }
38 |
39 | The two cases (authorisation and *CollateralisedDebtObligation* token) look alike, but this time the new thing is called a token, not an data-object. There are 2 reasons.
40 |
41 | First, authorisation is an artifact depending on the *CarToken*. It doesn't have to affect the status of the *CarToken*. For example, on Alice's mobile phone, the authorisations can be displayed below the car token in a list. Alice can authorise her entire family to use the car with several authorisations or a multi-user authorisation.
42 |
43 | On the other hand, *CollateralisedDebtObligation*, also depending on the *CarToken*, affects the status of the *CarToken*, since a collateralised car can't be collateralised again, nor can it be sold (without changing the loan). On Alice's mobile phone, the car might be displayed with a "collateralised" tag, together with a *CollateralisedDebtObligation* token to remind her of the payment obligation and allow her to do things like withdrawing from its line of credit. One can imagine that in this case the car token is extended to include its collateralisation. Since json doesn't support namespace, I'll use a comment to denote the extended attribute:
44 |
45 | {
46 | "objectClass": "CarToken",
47 | "ownerAddress": "0xdecafbad",
48 | "colour": "red",
49 | "rego": "4JHLC"
50 | "VIN": "KL3TA48E9EB541191",
51 | "collateralised": TRUE # look up CollateralisedDebtObligation token contract
52 | }
53 |
54 | Therefore it can be used to affect the available actions of a *CarToken*, since the condition for "trade" action might be:
55 |
56 | !(collateralised=TRUE)
57 |
58 | The second difference is that AuthorisationToUse has no actions. For example, it can't be traded. When the user Bob has an authorisation, he didn't see *authorisation* token next to the car token, but just the CarToken, with its permitted actions listed. If Alice sends Bob a second authorisation, maybe because the first is expiring, Bob doesn't see two distinct *AuthorisationToken* each with a *CarToken* in it; instead, Bob sees just one Token, with expiry extended.
59 |
60 | An authorisation would be a token, if it represents a lease. This is the case when the authorisation is obtained through a transaction, that is, Bob paid to obtain a lease of the car. The lease might even be transferrable.
61 |
62 | But not every object derived from a CarToken can be a token. Transfer of ownership, for example, is an event. An event is an artifact too:
63 |
64 | {
65 | "owner": 0xdecafbad,
66 | "newOnwer": 0xbaddecaf,
67 | "EventBlockId": 1234546, # this is an Operational Attribute, not declared in the event's ABI
68 | "EventTransactionId", 0x83480327027503...03082FF # also an Operational Attribute
69 | }
70 |
71 | Even if the Transfer of ownership event has a 1-to-1 relationship with another token, e.g. *StampDuty* token, and that the event's properties coincide with the attributes of that token, the event is still an artifact and the StampDuty still a token, not the same thing. The event data-object only exists in the scope of the token, while the *StampDuty* token has its own scope. (It also does not *have to* inherit the event's properties). This relationship is similar to how a SalesOffer data-object, which has price information, from the view of blockchain, has a 1-to-1 relationship with the SalesContract token, which is created by the buyer sending a transaction with SalesOffer data-object as payload, and every *SalesOffer* data-object property becomes a *SalesContract* token attribute, they are still two different thing.
72 |
73 | Conclusion:
74 | 
75 |
76 | # Filters
77 |
78 | Filters are used to selecting data-objects and tokens. In the above examples, we used filters a few times:
79 |
80 | rego=4JHLC
81 |
82 | VIN=KL3TA48E9EB541191
83 |
84 | !(collateralised=TRUE)
85 |
86 | Unlike structured query language like SQL, a filter does not specify what to do when the filtering is done. For example, when an attribute sources data from an event origin:
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | - the filter `label=${tokenID}` selects data-objects. In this case, only one is expected to be sifted through.
95 | - should there be more than one, name will be a multi-valued (ordered) attribute, like `allowed` shown before.
96 | - find the specified property, in this case `name`, whose value is used for the value of the attribute.
97 |
98 | As you can see, in TokneScript, a filter can be used on events (to filter events), or it can be used as the condition for actions. Or, it can be used as values of properties, in which case it either expresses a search or specifies which token an data-object (signed message or event) is about. By today's NFT convention, you can imagine something like this
99 |
100 | tokenID=0xca6abbe9d7f11422cb6ca7629fbf6fe9efb1c621f71ce8f02b9f2a230097404f
101 |
102 | being the most frequently used filter when it is used as a property (e.g. when someone floats an order to sell a kitty by tokenID).
103 |
104 | ## filtering multi-value attributes
105 |
106 | In TokenScript filter we do not distinguish between the two forms of multi-value expressions (observe the last property):
107 |
108 | {
109 | "objectClass": "AuthorisationToUse",
110 | "car": "rego=4JHLC",
111 | "user": "Bob",
112 | "start": 2019-09-09,
113 | "end": 2019-09-10,
114 | "allow": ["drive", "refuel", "service", "park", "locate"]
115 | }
116 |
117 | and
118 |
119 | {
120 | "objectClass": "AuthorisationToUse",
121 | "car": "rego=4JHLC",
122 | "user": "Bob",
123 | "start": 2019-09-09,
124 | "end": 2019-09-10,
125 | "allow": "drive",
126 | "allow": "refuel",
127 | "allow": "service",
128 | "allow": "park",
129 | "allow": "locate"
130 | }
131 |
132 | For example, this filter matches the data-object:
133 |
134 | allowedAction=drive
135 |
136 | The following filter also matches the data-object:
137 |
138 | (&(allowedAction=drive)(allowedAction=refuel))
139 |
140 | The distinction between a set and an ordered list is incomprehensible to millennium developers and potentially create issues with signed data. Recognising that, multi-valued attributes are always ordered-multi-valued attributes.
141 |
142 | Notice that filters use Polish notation to be parsed into abstract syntax tree with less gas. When data-objects are in the payload, the smart contract has to go through them with either pre-compiled filter or take the filter from another data-object or token attribute value.
143 |
--------------------------------------------------------------------------------
/doc/getting_started.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | The best way to get started is to run through the [tutorial](https://github.com/AlphaWallet/TokenScript-Examples/tree/master/tutorial).
4 |
5 | ## Implicit Attributes
6 |
7 | There are a few implicit attributes available:
8 |
9 | * name
10 | * symbol
11 | * contractAddress
12 | * ownerAddress
13 | * tokenId
14 |
15 | `tokenId` is especially useful for defining attributes with a function origin like this:
16 |
17 | ```
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | ```
28 |
29 | This is written with the assumption that the `getLocality()` smart contract function expects a single `uint256` argument representing the tokenId.
30 |
31 | Here's another example with [ERC721](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md)'s `ownerOf(uint256)`:
32 |
33 | ```
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | ```
44 |
--------------------------------------------------------------------------------
/doc/img/airbnb.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartTokenLabs/TokenScript/0581e9c0448483c71555139c537cde9c1e99ac28/doc/img/airbnb.jpeg
--------------------------------------------------------------------------------
/doc/img/iconified-view.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartTokenLabs/TokenScript/0581e9c0448483c71555139c537cde9c1e99ac28/doc/img/iconified-view.jpeg
--------------------------------------------------------------------------------
/doc/img/readme/share_facebook-btn.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/img/readme/share_linkedin-btn.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/img/readme/share_mail-btn.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/img/readme/share_reddit-btn.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/img/readme/share_telegram-btn.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/img/readme/share_tweet-btn.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/img/readme/tokenscript-stack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartTokenLabs/TokenScript/0581e9c0448483c71555139c537cde9c1e99ac28/doc/img/readme/tokenscript-stack.jpg
--------------------------------------------------------------------------------
/doc/img/regular-view.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartTokenLabs/TokenScript/0581e9c0448483c71555139c537cde9c1e99ac28/doc/img/regular-view.jpeg
--------------------------------------------------------------------------------
/doc/img/token_data.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
233 |
--------------------------------------------------------------------------------
/doc/javascript_api.md:
--------------------------------------------------------------------------------
1 | # API
2 |
3 | ## Intro
4 |
5 | ### Who provides the API
6 |
7 | TokenScript supporting user-agent (Dapp browser), wallet or self-supporting Dapps themselves provides JavaScript API.
8 |
9 | ### For whom to use
10 |
11 | - The JavaScript running in TokenScript
12 | - Javascript running in Dapp websites.
13 |
14 | Both uses the same JavaScript API but with nuances. For example:
15 |
16 | ---
17 |
18 | Difference in the tokens available to be accessed through this API.
19 |
20 | - The tokens available to a Dapp website depends on what token the user has chosen to use on that Dapp, as well as the tokens not owned by the current user, like the token the Dapp offers to transfer to the user (e.g. auction Dapp website) or to be created for the user (e.g. purchasing a new tokenised FIFA Ticket).
21 |
22 | - The tokens available to the Javascript in a TokenScript is typically the current token itself and dependencies. In the TokenView, may also include other tokens that can interact with the current token.
23 |
24 | ---
25 |
26 | The API has 2 parts
27 |
28 | A. The token data.
29 |
30 | B. The callback when the token data changes.
31 |
32 | ## A. Token Data
33 |
34 | ---
35 | The shape of the data is:
36 |
37 | ```
38 | web3.tokens = [
39 | all: [
40 | token,
41 | token,
42 | ...
43 | ],
44 | definition: {
45 | "0xD8e5F58DE3933E1E35f9c65eb72cb188674624F3": tokenDefinition,
46 | "0xf018225735f70a1961B6B8aa07B005e6392072E7": tokenDefinition,
47 | ...
48 | },
49 | dataChanged: function(oldTokens, updatedTokens, tokenCardId)
50 | ]
51 | ```
52 |
53 | For a fungible token, like airline point, the token variable is like this:
54 |
55 | ```
56 | token = {
57 | contractAddress: "0xD8e5F58DE3933E1E35f9c65eb72cb188674624F3",
58 | balance: 98.66250478,
59 | available: 96.6625047,
60 | locked: {"state-channel-0934": 2},
61 | votingRights: 73.929672,
62 | transferrable: 54.6625047,
63 | expiry: {"2018-09-03": 34, "2018-18-04": 10, "never": 54.6625047},
64 | }
65 | ```
66 |
67 | Where attributes like `votingRights` are defined in TokenScript.
68 |
69 | For a non-fungible token, like a ticket to an event:
70 |
71 | ```
72 | token = {
73 | contractAddress: "0xD8e5F58DE3933E1E35f9c65eb72cb188674624F3",
74 | instances: [
75 | instance,
76 | instance,
77 | ...
78 | ]
79 | }
80 |
81 | instance = {
82 | _count: 1,
83 | contractAddress: "0xD8e5F58DE3933E1E35f9c65eb72cb188674624F3",
84 | numero: 11, # sequence of the ticket
85 | section: "22",
86 | building: "Some building",
87 | street: "Some street",
88 | country: "SG",
89 | ...
90 | }
91 |
92 | tokenDefinition = {
93 | attributeType: {
94 | attributeId: attribute,
95 | category: {
96 | name: "Cat",
97 | syntax: "Integer",
98 | single: "true",
99 | },
100 | startTime: {
101 | name: "Event Start Time",
102 | syntax: "BinaryTime",
103 | },
104 | ...
105 | },
106 | grouping: {...},
107 | ordering: {...},
108 | symbol: "TICKET",
109 | name: "Ticket Token"
110 | },
111 |
112 | attribute = {
113 | name: "Cat",
114 | value: "TEST"
115 | }
116 |
117 | ```
118 |
119 | The metadata of a token is available in `web3.tokens.definition` with the contract address in [EIP55](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md) as the key. The metadata is basically a 1:1 map from the relevant parts of the asset definition. Only the localized attribute names (and not grouping, ordering) is available for now.
120 |
121 | `attributeType` contains type information of each attribute, e.g. its name, syntax or whether the attribute type is single-valued. For example, to access the localized attribute name `"countryA"` for the token with contract `"0xD8e5F58DE3933E1E35f9c65eb72cb188674624F3"` use:
122 |
123 | ```
124 | web3.tokens.definition["0xD8e5F58DE3933E1E35f9c65eb72cb188674624F3"].attributeType["countryA"]["name"]
125 | ```
126 |
127 | All attribute types are in the `attributeType` dictionary, even for attributes that are not used in any of the token (for fungible) or tokenInstance (for non-fungible). For example, a user might have a few EventTicket tokens, none of them have `category` attribute because the event doesn't categorise tickets, but `category` can be found in `attributeType` dictionary because it's typed. This is needed in many cases, e.g. when TokenScript is going to create a new ticket with `category` attribute.
128 |
129 | The other elements in a `tokenDefinition`, like `name` and `symbol`, refer to the name and symbol of the token.
130 |
131 | *Only* `web3.tokens.dataChanged` (and not `web3.tokens.all` nor `definition`) is available in AlphaWallet's Android and iOS build at the moment.
132 |
133 | ### Attribute-Value Pair? Not always
134 |
135 | In the previous example, observe that not every attribute of a token is of a primitive type.
136 |
137 |
138 | ```
139 | token = {
140 | contractAddress: "0xD8e5F58DE3933E1E35f9c65eb72cb188674624F3",
141 | balance: 98.66250478,
142 | available: 96.6625047,
143 | locked: {"state-channel-0934": 2},
144 | votingRights: 73.929672,
145 | transferrable: 54.6625047,
146 | expiry: {"2018-09-03": 34, "2018-18-04": 10, "never": 54.6625047},
147 | }
148 | ```
149 |
150 | There are two attributes that are not of a primitive type: `locked`, which represents the balance committed somehow (typically, to a state channel), and `expiry` which is how much the balance will disappear at certain date, typically used as an incentive for users to spend, the opposite incentive of Bitcoin.
151 |
152 | What form of value do we have for each attribute is a result of the attribute-type found in `tokenDefinition`.
153 |
154 | Take time as an example. Typically, blockchain uses `BinaryTime` syntax for gas efficiency, which is just binary encoded UnixTime. When used as the time of an event, there is no ambiguity which point of time it refers to, no matter in which timezone the event happens. In such case, the attribute is a dictionary of a single key:
155 |
156 | ```
157 | instance = {
158 | section: "22",
159 | startTime: {
160 | date: new Date("1985-11-07T02:06:27")
161 | }
162 | ...
163 | }
164 | ```
165 |
166 | Date object is represented by the code with which it would have been created. The key is `date` to inherit the misnaming by JavaScript.
167 |
168 | However, in the case the time relevant to the timezone is important, the token designer would have supplied a [GeneralizedTime](https://en.wikipedia.org/wiki/GeneralizedTime). Take a FIFA football match ticket as an example, `matchTime` attribute is a dictionary of two keys: `date` as a Date object, not containing timezone, and the raw value for GeneralizedTime which has the timezone in it.
169 |
170 | ```
171 | instance = {
172 | section: "22",
173 | matchTime: {
174 | generalizedTime: "19851106210627-0500",
175 | date: new Date("1985-11-07T02:06:27")
176 | }
177 | ...
178 | }
179 | ```
180 |
181 | If a developer intends to find out if an attribute is of `BinaryTime` or `GeneralizedTime`, he can look up the definition (search for `BinaryTime` in the beginning of this document for an example).
182 |
183 | The value of `matchTime.date` would be a normal `Date` object, the time the match starts. As every `Date` object, it doesn't contain the timezone information. But if you want to display a venue-specific time, eg. a soccer game match time at the venue, you need to extract that information from the `generalizedTime` string, like shown in the [example](../examples/ticket/js/generalized-time-test.html).
184 |
185 | ## B. Callback
186 |
187 | TokenScript's JavaScript API is designed to be asynchronous.
188 |
189 | ---
190 |
191 | There are 3 args supplied to the `web3.tokens.dataChanged` callback:
192 |
193 | * old data — this contains the data — token instance and card attribute values — before the change
194 | * updated data — this contains the data — token instance and card attribute values — after the change
195 | * tokenCardId — the CSS ID of the wrapper `
` to place content in
196 |
197 | Developers can use this callback and the arguments to figure out what has changed. We might point them to a good JSON-diff library; but since the purpose here is just to render a static layout, they can just re-render the whole DOM as we do in our examples.
198 |
199 | A simple way to implement that would be:
200 |
201 | ```
202 | web3.tokens.dataChanged = (old, updated, tokenCardId) => {
203 | const data = updated
204 | document.getElementById(tokenCardId).getElementsByClassName("contents")[0].innerHTML = new Token(data).render()
205 | }
206 | ```
207 |
208 | TokenScript will automatically generate a `
` with a unique ID (`tokenCardId`) and wrap the TokenScript view with it. This wrapper `
` will have the CSS class `".token-card` so it can be styled (if desired).
209 |
210 | The snippet assumes the presence of a `
` that has the class name `contents`. Adding this `
` makes it easier to access/replace the contents. Note that developers should *not* do this as the wrapper `
` generated by TokenScript wraps around HTML, CSS and JavaScript provided by the TokenScript view:
211 |
212 | ```
213 | document.getElementById(tokenCardId).innerHTML = replacementDomHtml
214 | ```
215 |
216 | The above-mentioned `Token.render()` function generates a DOM from a dictionary of token attributes.
217 |
218 | Within the `Token` class, the token data can be access like this:
219 |
220 | ```
221 | const tokenAttributeValue = this.props.token.tokenAttribute1
222 | ```
223 |
224 | and the card data like this:
225 |
226 | ```
227 | const cardAttributeValue = this.props.card.tokenAttribute1
228 | ```
229 |
230 | And if we are sure the token and card attribute names don't clash, we can pretend they are in the same namespace with:
231 |
232 | ```
233 | web3.tokens.dataChanged = (old, updated, tokenCardId) => {
234 | const data = Object.assign({}, updated.token, updated.card)
235 | document.getElementById(tokenCardId).getElementsByClassName("contents")[0].innerHTML = new Token(data).render()
236 | }
237 | ```
238 |
239 | Then this is unchanged:
240 |
241 | ```
242 | const attributeValue = this.props.tokenAttribute1 //or this.props.cardAttribute1
243 | ```
244 |
245 | Future
246 | ---
247 | In (A), we can also stuff the entire list of tokens in the user's Ethereum wallet in there (in a future iteration) under the `all` key. We might have to key them by wallet/networks too. Performance is a concern, but this simple approach has quite a number of advantages. Perhaps it can be partially mitigated by adding a permission call that TokenScript developers have to make to make `tokens` accessible, maybe as part of the permission granted via https://eips.ethereum.org/EIPS/eip-1102 (which we should implement anyway) or a new function call.
248 |
249 | The development and debugging experience is a little tedious. With access to the simulator, we can drop updated files and run a web inspector on the simulator's TokenScript webview to look at the console.log output. Without the app's source, we can AirDrop TokenScript files to the app. The developer experience is something we need to look into a bit more.
250 |
251 | Implementing the TokenScript API and Rendering in the TokenScript Clients
252 |
--------------------------------------------------------------------------------
/doc/negotiator.dia:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartTokenLabs/TokenScript/0581e9c0448483c71555139c537cde9c1e99ac28/doc/negotiator.dia
--------------------------------------------------------------------------------
/funding.json:
--------------------------------------------------------------------------------
1 | {
2 | "opRetro": {
3 | "projectId": "0x471f2d9cc373f1c6e025c283a41964440c09bf773c9427c62622948e92620fa0"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/schema/README.md:
--------------------------------------------------------------------------------
1 | # TokenScript Schema
2 |
3 | TokenScript schema serves to check if your TokenScript is with the correct syntax.
4 |
5 | This namespace identifies the current schema:
6 |
7 | http://tokenscript.org/2020/06/tokenscript
8 |
9 | When there is a minor change with the addition of new features and elements, we update the schema without invalidating the old TokenScripts that are already signed and put to use. The namespace identifier remains. This process is slow and normally taking months or years.
10 |
11 | But every few cycles, evolution leaps forward, and we resort to declaring a new namespace with older elements obsoleted and usage-changed.
12 |
13 | The last time it happened was in Jun 2020.
14 |
15 | When the namespace change, existing Tokenscripts has to be migrated and re-signed. We will be providing migration tools should that happen again.
16 |
17 |
18 | ### The schema namespace in this repo is above my version; how can I use an older version?
19 |
20 | If you have a TokenScript file in an older namespace, they can still be checked for validity, except that they will not run on the latest TokenScript engine implementations unless they explicitly supports outdated TokenScript formats.
21 |
22 | If you are the author of such TokenScripts, you should migrate to the current TokenScript namespace. We promise that we make such a change as infrequent as possible.
23 |
24 | Example: `http://tokenscript.org/2019/10/tokenscript` was the prior namespace. Old TokenScripts under that namespace can still be found, for example, here:
25 |
26 | https://repo.tokenscript.org/aw.app/2019/10/
27 |
28 | To make sure the users who didn't upgrade their AlphaWallet can still use the tokens the old way. But they will no longer be updated to include new functions.
29 |
--------------------------------------------------------------------------------
/schema/asnx.xsd:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/schema/data.xsd:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/schema/ethereum.xsd:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/schema/xml.xsd:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
About the XML namespace
11 |
12 |
13 |
14 | This schema document describes the XML namespace, in a form
15 | suitable for import by other schema documents.
16 |
25 | Note that local names in this namespace are intended to be
26 | defined only by the World Wide Web Consortium or its subgroups.
27 | The names currently defined in this namespace are listed below.
28 | They should not be used with conflicting semantics by any Working
29 | Group, specification, or document instance.
30 |
49 | denotes an attribute whose value
50 | is a language code for the natural language of the content of
51 | any element; its value is inherited. This name is reserved
52 | by virtue of its definition in the XML specification.
53 |
54 |
55 |
56 |
Notes
57 |
58 | Attempting to install the relevant ISO 2- and 3-letter
59 | codes as the enumerated possible values is probably never
60 | going to be a realistic possibility.
61 |
95 | denotes an attribute whose
96 | value is a keyword indicating what whitespace processing
97 | discipline is intended for the content of the element; its
98 | value is inherited. This name is reserved by virtue of its
99 | definition in the XML specification.
118 | denotes an attribute whose value
119 | provides a URI to be used as the base for interpreting any
120 | relative URIs in the scope of the element on which it
121 | appears; its value is inherited. This name is reserved
122 | by virtue of its definition in the XML Base specification.
141 | denotes an attribute whose value
142 | should be interpreted as if declared to be of type ID.
143 | This name is reserved by virtue of its definition in the
144 | xml:id specification.
171 | denotes Jon Bosak, the chair of
172 | the original XML Working Group. This name is reserved by
173 | the following decision of the W3C XML Plenary and
174 | XML Coordination groups:
175 |
176 |
177 |
178 | In appreciation for his vision, leadership and
179 | dedication the W3C XML Plenary on this 10th day of
180 | February, 2000, reserves for Jon Bosak in perpetuity
181 | the XML name "xml:Father".
182 |
196 | This schema defines attributes and an attribute group suitable
197 | for use by schemas wishing to allow xml:base,
198 | xml:lang, xml:space or
199 | xml:id attributes on elements they define.
200 |
201 |
202 | To enable this, such a schema must import this schema for
203 | the XML namespace, e.g. as follows:
204 |
242 | In keeping with the XML Schema WG's standard versioning
243 | policy, this schema document will persist at
244 |
245 | http://www.w3.org/2009/01/xml.xsd.
246 |
253 | The schema document at that URI may however change in the future,
254 | in order to remain compatible with the latest version of XML
255 | Schema itself, or with the XML namespace itself. In other words,
256 | if the XML Schema or XML namespaces change, the version of this
257 | document at
258 | http://www.w3.org/2001/xml.xsd
259 |
260 | will change accordingly; the version at
261 |
262 | http://www.w3.org/2009/01/xml.xsd
263 |
264 | will not change.
265 |
266 |
267 | Previous dated (and unchanging) versions of this schema
268 | document are at:
269 |