Browse Source

fix browser issues for good hopefully

master
nitowa 1 month ago
parent
commit
96e423c151
7 changed files with 1040 additions and 4338 deletions
  1. 889
    4277
      package-lock.json
  2. 7
    4
      package.json
  3. 41
    48
      src/RJSVM/framework/rjsvm.ts
  4. 2
    1
      src/main.ts
  5. 1
    0
      test/Test.ts
  6. 96
    0
      test/index.html
  7. 4
    8
      webpack.js

+ 889
- 4277
package-lock.json
File diff suppressed because it is too large
View File


+ 7
- 4
package.json View File

1
 {
1
 {
2
   "name": "rjsvm",
2
   "name": "rjsvm",
3
-  "version": "0.3.2",
3
+  "version": "0.4.1",
4
   "description": "",
4
   "description": "",
5
   "main": "lib/src/main.js",
5
   "main": "lib/src/main.js",
6
   "scripts": {
6
   "scripts": {
16
   "license": "ISC",
16
   "license": "ISC",
17
   "dependencies": {
17
   "dependencies": {
18
     "axios": "^1.7.7",
18
     "axios": "^1.7.7",
19
-    "stream-http": "^3.2.0",
20
-    "url": "^0.11.3",
21
-    "xrpio": "^0.3.0",
19
+    "rjsvm": "^0.4.0",
20
+    "xrpio": "^0.4.0",
22
     "xrpl": "^4.0.0",
21
     "xrpl": "^4.0.0",
23
     "zod": "^3.21.4"
22
     "zod": "^3.21.4"
24
   },
23
   },
25
   "devDependencies": {
24
   "devDependencies": {
25
+    "node-polyfill-webpack-plugin": "^4.0.0",
26
+    "stream-http": "^3.2.0",
27
+    "url": "^0.11.3",
28
+
26
     "@types/chai": "^4.3.6",
29
     "@types/chai": "^4.3.6",
27
     "@types/expect": "^1.20.4",
30
     "@types/expect": "^1.20.4",
28
     "@types/mocha": "^5.2.7",
31
     "@types/mocha": "^5.2.7",

+ 41
- 48
src/RJSVM/framework/rjsvm.ts View File

1
 import { PaymentTx_T, ParameterizedFunction, Payload, RJSVM, RJSVM_Config, RJSVM_Implementations, Function_Map, Endpoints_Of, State_Of, Generic_Ctor_ReturnType, RJSVM_Endpoint } from "./types"
1
 import { PaymentTx_T, ParameterizedFunction, Payload, RJSVM, RJSVM_Config, RJSVM_Implementations, Function_Map, Endpoints_Of, State_Of, Generic_Ctor_ReturnType, RJSVM_Endpoint } from "./types"
2
-import { AccountTxTransaction, Client as Xrpl } from 'xrpl';
2
+import { Client as Xrpl } from 'xrpl';
3
 import { xrpIO } from 'xrpio';
3
 import { xrpIO } from 'xrpio';
4
 import { DataParser } from "../../util/dataparser";
4
 import { DataParser } from "../../util/dataparser";
5
 import { XRP_ADDRESS } from "../../util/protocol.constants";
5
 import { XRP_ADDRESS } from "../../util/protocol.constants";
13
         Impl extends RJSVM_Implementations<any, Endpoints_T>,
13
         Impl extends RJSVM_Implementations<any, Endpoints_T>,
14
         Endpoints_T extends Function_Map = Endpoints_Of<Generic_Ctor_ReturnType<Base_Ctor>>,
14
         Endpoints_T extends Function_Map = Endpoints_Of<Generic_Ctor_ReturnType<Base_Ctor>>,
15
         State_T = State_Of<Generic_Ctor_ReturnType<Base_Ctor>>
15
         State_T = State_Of<Generic_Ctor_ReturnType<Base_Ctor>>
16
-    >(Base: Base_Ctor, defs: Impl): (new (config: RJSVM_Config) => RJSVM<State_T, Endpoints_T>){
17
-        return <any> class RJSVM_Runnable extends (Base as any){
16
+    >(Base: Base_Ctor, defs: Impl): (new (config: RJSVM_Config) => RJSVM<State_T, Endpoints_T>) {
17
+        return <any>class RJSVM_Runnable extends (Base as any) {
18
 
18
 
19
             sync_block_height = -1
19
             sync_block_height = -1
20
 
20
 
30
                 public readonly config: RJSVM_Config
30
                 public readonly config: RJSVM_Config
31
             ) {
31
             ) {
32
                 super()
32
                 super()
33
-                
34
-                if(!XRP_ADDRESS.test(this.owner)){
33
+
34
+                if (!XRP_ADDRESS.test(this.owner)) {
35
                     const err = new Error(`Inavlid owner address ${this.owner}`)
35
                     const err = new Error(`Inavlid owner address ${this.owner}`)
36
                     this.emit('error', err)
36
                     this.emit('error', err)
37
                     throw err
37
                     throw err
38
                 }
38
                 }
39
-                
39
+
40
                 this.definitions = Object.freeze(defs)
40
                 this.definitions = Object.freeze(defs)
41
                 Object.entries(this.definitions).forEach(([k, v]) => {
41
                 Object.entries(this.definitions).forEach(([k, v]) => {
42
                     this[k] = (env: PaymentTx_T, ...args: any) => (v.implementation as ParameterizedFunction).apply(this as any, [env, ...args])
42
                     this[k] = (env: PaymentTx_T, ...args: any) => (v.implementation as ParameterizedFunction).apply(this as any, [env, ...args])
47
                 this.rippleApi = new Xrpl(this.config.rippleNode)
47
                 this.rippleApi = new Xrpl(this.config.rippleNode)
48
                 await this.rippleApi.connect()
48
                 await this.rippleApi.connect()
49
 
49
 
50
-                this.xrpIO = new xrpIO(this.config.rippleNode);
50
+                this.xrpIO = new xrpIO(this.config.rippleNode, { readFreshApi: false });
51
                 await this.xrpIO.connect()
51
                 await this.xrpIO.connect()
52
                 await this.sync()
52
                 await this.sync()
53
 
53
 
71
             }
71
             }
72
 
72
 
73
             public disconnect = async () => {
73
             public disconnect = async () => {
74
-                if(this.syncTimeout){
74
+                if (this.syncTimeout) {
75
                     clearTimeout(this.syncTimeout)
75
                     clearTimeout(this.syncTimeout)
76
                     this.syncTimeout = undefined
76
                     this.syncTimeout = undefined
77
                 }
77
                 }
78
-                if(this.xrpIO){
78
+                if (this.xrpIO) {
79
                     await this.xrpIO.disconnect()
79
                     await this.xrpIO.disconnect()
80
                     this.xrpIO = undefined
80
                     this.xrpIO = undefined
81
                 }
81
                 }
82
-                if(this.rippleApi){
82
+                if (this.rippleApi) {
83
                     await this.rippleApi.disconnect()
83
                     await this.rippleApi.disconnect()
84
                     this.rippleApi = undefined
84
                     this.rippleApi = undefined
85
                 }
85
                 }
90
 
90
 
91
             public on = (event: string, handler: ParameterizedFunction) => {
91
             public on = (event: string, handler: ParameterizedFunction) => {
92
                 const availableEvents = ['error', ...Object.keys(this.definitions)]
92
                 const availableEvents = ['error', ...Object.keys(this.definitions)]
93
-                if(!availableEvents.includes(event))
93
+                if (!availableEvents.includes(event))
94
                     return
94
                     return
95
-                
96
-                if(!this.subscribers[event])
95
+
96
+                if (!this.subscribers[event])
97
                     this.subscribers[event] = []
97
                     this.subscribers[event] = []
98
 
98
 
99
                 this.subscribers[event].push(handler)
99
                 this.subscribers[event].push(handler)
101
 
101
 
102
             public once = (event: string, handler: ParameterizedFunction) => {
102
             public once = (event: string, handler: ParameterizedFunction) => {
103
                 const availableEvents = ['error', ...Object.keys(this.definitions)]
103
                 const availableEvents = ['error', ...Object.keys(this.definitions)]
104
-                if(!availableEvents.includes(event))
104
+                if (!availableEvents.includes(event))
105
                     return
105
                     return
106
-                
107
-                if(!this.onceSubscribers[event])
106
+
107
+                if (!this.onceSubscribers[event])
108
                     this.onceSubscribers[event] = []
108
                     this.onceSubscribers[event] = []
109
 
109
 
110
                 this.onceSubscribers[event].push(handler)
110
                 this.onceSubscribers[event].push(handler)
111
             }
111
             }
112
 
112
 
113
             private emit = (event: string, payload: any) => {
113
             private emit = (event: string, payload: any) => {
114
-                if(this.subscribers[event])
114
+                if (this.subscribers[event])
115
                     this.subscribers[event].forEach(handler => handler(payload))
115
                     this.subscribers[event].forEach(handler => handler(payload))
116
-                
117
-                if(this.onceSubscribers[event]){
116
+
117
+                if (this.onceSubscribers[event]) {
118
                     this.onceSubscribers[event].forEach(handler => handler(payload))
118
                     this.onceSubscribers[event].forEach(handler => handler(payload))
119
                     this.onceSubscribers[event] = []
119
                     this.onceSubscribers[event] = []
120
                 }
120
                 }
127
 
127
 
128
                 const endpointDef: RJSVM_Endpoint<RJSVM, any> = this.definitions[payload.endpoint]
128
                 const endpointDef: RJSVM_Endpoint<RJSVM, any> = this.definitions[payload.endpoint]
129
 
129
 
130
-                if(endpointDef.visibility === 'owner' && tx.Account !== this.owner){
130
+                if (endpointDef.visibility === 'owner' && tx.Account !== this.owner) {
131
                     const err = new RestrictedAccessError(payload.endpoint, tx.hash, tx.Account, this.owner)
131
                     const err = new RestrictedAccessError(payload.endpoint, tx.hash, tx.Account, this.owner)
132
                     this.emit('error', err)
132
                     this.emit('error', err)
133
                     return
133
                     return
134
                 }
134
                 }
135
 
135
 
136
-                if(endpointDef.fee && Number(tx.Amount) < endpointDef.fee){
136
+                if (endpointDef.fee && Number(tx.Amount) < endpointDef.fee) {
137
                     const err = new InsufficientFeeError(tx.hash, Number(endpointDef.fee), Number(tx.Amount))
137
                     const err = new InsufficientFeeError(tx.hash, Number(endpointDef.fee), Number(tx.Amount))
138
                     this.emit('error', err)
138
                     this.emit('error', err)
139
                     return
139
                     return
140
                 }
140
                 }
141
-                
141
+
142
                 try {
142
                 try {
143
                     const data = await this.xrpIO.treeRead([payload.data], tx.Account)
143
                     const data = await this.xrpIO.treeRead([payload.data], tx.Account)
144
                     const jsonData = JSON.parse(data)
144
                     const jsonData = JSON.parse(data)
151
                 }
151
                 }
152
             }
152
             }
153
 
153
 
154
-            private parseMemos = async (tx:PaymentTx_T) => {
154
+            private parseMemos = async (tx: PaymentTx_T) => {
155
                 const memos = tx.Memos
155
                 const memos = tx.Memos
156
                 memos
156
                 memos
157
                     .map((memo: any) => {
157
                     .map((memo: any) => {
186
                 const resp = await this.rippleApi.request({
186
                 const resp = await this.rippleApi.request({
187
                     command: "account_tx",
187
                     command: "account_tx",
188
                     account: this.config.listeningAddress,
188
                     account: this.config.listeningAddress,
189
-                    forward: true, 
189
+                    forward: true,
190
                     ledger_index_min: this.sync_block_height,
190
                     ledger_index_min: this.sync_block_height,
191
                     marker: marker,
191
                     marker: marker,
192
                 })
192
                 })
193
 
193
 
194
-                //results may not be ordered, so sort them
195
-                const raw_txs = await Promise.all(
196
-                    resp.result.transactions
197
-                        .filter(tx => tx.tx_json.TransactionType === "Payment")
198
-                        .sort((a,b) => a.tx_json.ledger_index - b.tx_json.ledger_index)
199
-                        .map((tx) => this.xrpIO.getTransaction(tx.hash))
200
-                )
201
-
202
-                //XRPL API update adaption
194
+                const full_txs = resp.result.transactions
195
+                    .filter(tx => !!tx.tx_json.Memos)
196
+                    .map(tx => {
197
+                        return ({
198
+                            ...tx.tx_json,
199
+                            hash: tx.hash,
200
+                            Amount: tx.tx_json["DeliverMax"],
201
+                            inLedger: tx.tx_json['ledger_index']
202
+                        } as PaymentTx_T)
203
+                    })
204
+                
203
                 await Promise.all(
205
                 await Promise.all(
204
-                    raw_txs
205
-                        .filter(tx => !!tx.result.tx_json.Memos)
206
-                        .map(tx => {
207
-                            return({
208
-                                ...tx.result.tx_json,
209
-                                hash: tx.result.hash,
210
-                                Amount: tx.result.tx_json["DeliverMax"],
211
-                                inLedger: tx.result.tx_json['ledger_index']
212
-                            } as PaymentTx_T)
213
-                        })
206
+                    full_txs
214
                         .map(tx => this.parseMemos(tx))
207
                         .map(tx => this.parseMemos(tx))
215
-                    )
216
-                
208
+                )
209
+
217
                 //if marker is present the result is paginated.
210
                 //if marker is present the result is paginated.
218
                 //re-run the same request with the marker included
211
                 //re-run the same request with the marker included
219
-                if(resp.result.marker){
212
+                if (resp.result.marker) {
220
                     await this.sync(resp.result.marker)
213
                     await this.sync(resp.result.marker)
221
-                }else{
214
+                } else {
222
                     //presence of no marker means we caught up to current block height
215
                     //presence of no marker means we caught up to current block height
223
                     this.sync_block_height = resp.result.ledger_index_max + 1
216
                     this.sync_block_height = resp.result.ledger_index_max + 1
224
                     //schedule the next sync
217
                     //schedule the next sync
225
-                    this.syncTimeout = setTimeout(this.sync, 10000)
218
+                    this.syncTimeout = setTimeout(this.sync, 5000)
226
                 }
219
                 }
227
             }
220
             }
228
         }
221
         }

+ 2
- 1
src/main.ts View File

1
 export * from "./RJSVM/framework/rjsvm"
1
 export * from "./RJSVM/framework/rjsvm"
2
 export * from "./RJSVM/datawriter/datawriter"
2
 export * from "./RJSVM/datawriter/datawriter"
3
 export * from "./RJSVM/framework/types"
3
 export * from "./RJSVM/framework/types"
4
-export * from "./util/dataparser"
4
+export * from "./util/dataparser"
5
+export * from "zod"

+ 1
- 0
test/Test.ts View File

142
     await rjsvm.connect()
142
     await rjsvm.connect()
143
 }
143
 }
144
 
144
 
145
+
145
 describe('RJSVM basic functions', () => {
146
 describe('RJSVM basic functions', () => {
146
 
147
 
147
     before(async function () {
148
     before(async function () {

+ 96
- 0
test/index.html View File

1
+<!doctype html>
2
+<html lang="en">
3
+
4
+<head>
5
+    <script src="../lib/browser/rjsvm.browser.js"></script>
6
+</head>
7
+
8
+<body>
9
+    <div style="text-align: center;"></div>
10
+    <script>
11
+
12
+        const xrpNode = "wss://s.altnet.rippletest.net:51233"
13
+        const listeningAddress = "rMBYWyxGx1b5zEjJKF18TTwF5X3vP2WyjR"
14
+
15
+        const drainWallet = {
16
+            address: "rLNEG2ubbW3HUHYL7QCunNX96QrZzq2Udo",
17
+            secret: "sEd7FusyxBpT1JLQjS76nnn4JABredu"
18
+        }
19
+
20
+        const sendWallet = {
21
+            address: "rnNuTh8catLz5T12e1fwbxH3FWvUZCYYTw",
22
+            secret: "sEdSqxN99gFoZ2s8ru7RNCvEXFBmVYa"
23
+        }
24
+
25
+        this.dataWriter = new Datawriter({
26
+            receiveAddress: drainWallet.address,
27
+            sendWallet: sendWallet,
28
+            xrpNode: xrpNode,
29
+            contractAddress: listeningAddress
30
+        })
31
+
32
+        const shoutSchema = z.object({
33
+            title: z.string(),
34
+            body: z.string(),
35
+            from: z.string(),
36
+            hash: z.optional(z.string()),
37
+            date: z.optional(z.string()),
38
+            id: z.optional(z.string())
39
+        })
40
+
41
+
42
+        // #########################
43
+        // Define endpoints
44
+        // #########################
45
+
46
+
47
+        // #########################
48
+        // Define init state
49
+        // #########################
50
+
51
+        class RJSVM_Base
52
+            extends RJSVM {
53
+
54
+            owner = sendWallet.address
55
+
56
+            state = {}
57
+        }
58
+
59
+        // #########################
60
+        // Implement logic
61
+        // #########################
62
+
63
+        const RJSVM_Contract = {
64
+            submit: {
65
+                implementation: function (env, shout) {
66
+                    shout.hash = env.hash;
67
+                    const d = new Date("2000-01-01");
68
+                    d.setSeconds(d.getSeconds() + env.date)
69
+                    shout.date = d.toLocaleString("de-DE")
70
+                },
71
+                visibility: 'public',
72
+                fee: 10,
73
+                parameterSchema: shoutSchema
74
+            }
75
+        }
76
+
77
+        // #########################
78
+        // Build and connect
79
+        // #########################
80
+
81
+        const Rjsvm = RJSVM_Builder.from(RJSVM_Base, RJSVM_Contract);
82
+
83
+        const conf = {
84
+            listeningAddress: listeningAddress,
85
+            rippleNode: xrpNode
86
+        }
87
+
88
+        const rjsvm = new Rjsvm(conf)
89
+        rjsvm.connect()
90
+
91
+        rjsvm.on('error', console.log)
92
+        rjsvm.on('submit', console.log)
93
+    </script>
94
+</body>
95
+
96
+</html>

+ 4
- 8
webpack.js View File

1
 const path = require('path');
1
 const path = require('path');
2
 const webpack = require('webpack');
2
 const webpack = require('webpack');
3
 const BomPlugin = require('webpack-utf8-bom');
3
 const BomPlugin = require('webpack-utf8-bom');
4
+const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
5
+
4
 
6
 
5
 module.exports = {
7
 module.exports = {
6
   mode: 'production',
8
   mode: 'production',
14
   resolve: {
16
   resolve: {
15
     extensions: [".ts", ".tsx", ".js"],
17
     extensions: [".ts", ".tsx", ".js"],
16
     fallback: {
18
     fallback: {
17
-      "zlib": require.resolve("browserify-zlib"),
18
-      "http": require.resolve("stream-http"),
19
-      "https": require.resolve("https-browserify"),
20
-      "stream": require.resolve("stream-browserify") ,
21
-      "buffer": require.resolve('buffer/'),
22
-      "Buffer": require.resolve('buffer/'),
23
-      "url": require.resolve('url/'),
24
-      "crypto": require.resolve('crypto-browserify'),
19
+      buffer: require.resolve('buffer/'),
25
     }
20
     }
26
   },
21
   },
27
   module: {
22
   module: {
33
     minimize: true,
28
     minimize: true,
34
   },
29
   },
35
   plugins: [
30
   plugins: [
31
+    new NodePolyfillPlugin(),
36
     new webpack.ProvidePlugin({
32
     new webpack.ProvidePlugin({
37
       Buffer: ['buffer', 'Buffer'],
33
       Buffer: ['buffer', 'Buffer'],
38
     }),
34
     }),

Loading…
Cancel
Save