diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..36bf9b4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing to svelte-web3 + +Thanks for your interest in improving svelte-web3! We welcome +contributions of all kinds: from discussion to documentation to +bugfixes to feature improvements. + +Please review this document to help to streamline the process and save +everyone's precious time. + +## Issues + +No software is bug-free. So, if you got an issue, follow these steps: + +- Search the [issue list](https://github.com/clbrge/svelte-web3/issues) for current and old issues. + - If you find an existing issue, please UPVOTE the issue by adding a "thumbs-up reaction". We use this to help prioritize issues! +- If none of that is helping, create an issue with the following information: + - Clear title (shorter is better). + - Describe the issue in clear language. + - Share error logs, screenshots and etc. + - To speed up the issue fixing process, send us a sample repo with the issue you faced: + +## Pull Requests (PRs) + +We welcome all contributions. There are many ways you can help us. This is few of those ways: diff --git a/README.md b/README.md index 87f6452..f44c3e2 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,19 @@ ---- # svelte-web3 Use the [web3.js library](https://web3js.readthedocs.io/) as a -collection of [readable svelte stores](https://svelte.dev/tutorial/readable-stores) -for Svelte, Sapper or Sveltekit. +collection of [readable Svelte stores](https://svelte.dev/tutorial/readable-stores) +for Svelte, Sapper or SvelteKit. + +If you prefer to use the [ethers.js +library](https://docs.ethers.io/v5/) to intereact with EVM, you may be +interested by our sister package +[svelte-ethers-store](https://www.npmjs.com/package/svelte-ethers-store). + +### Community + +For additional help or discussion, join us [in our +Discord](https://discord.gg/7yXuwDwaHF). ## Installation @@ -20,93 +29,147 @@ npm i svelte-web3 ``` -## Basic usage (defaultstore connected to one chain) +This step is necessary for now because the Web3.js library doesn't +play well with bundlers (webpack, vite, snowpack, etc), thus we cannot +simply add a dependency in package.json. + + +## Basic usage (default stores connected to one chain) + +### Derived stores + +This library creates a set of readable Svelte stores that are +automatically updated when a new connection happens, or when the chain +or the selected account change. You can import them directly in any +Svelte or JavaScript files : + +```js +import { connected, web3, selectedAccount, chainId, chainData } from 'svelte-web3' +``` + + * connected: store value is true a connection has been set up. + * web3: store value is a Web3.js instance when connected. + * selectedAccount: store value is the current selected account (when connected). + * chainId: store value is the current chainId when connected. + * chainData: store value is the current blokchain CAIP-2 data (when connected), see below. -Import the `defaultChainStore` main connection helper and needed derived Svelte stores (see list below): +For these stores to be useful in your Svelte application, a connection to an EVM +blockchain first need to established . The abstract helper +`defaultEvmStores` can be used to initiate the connection and automatically +instanciate all stores. ```js -import { defaultChainStore, web3, selectedAccount, connected, chainData } from 'svelte-web3' +import { defaultEvmStores } from 'svelte-web3' ``` -:exclamation: `defaultChainStore` was named before `ethStore`. The +:exclamation: `defaultEvmStores` was named before `defaultChainStore`. The former naming still works but will be removed in later versions of `svelte-web3` package. Please update your code! -### Connection with the browser provider (wallets like metamask) +### Connection with the browser provider (eg wallets like Metamask) -To enable a connection with the current window provider: +To enable a connection with the current window provider, simply call +`setBrowserProvider` on the library abstract helper: ```js -defaultChainStore.setBrowserProvider() +defaultEvmStores.setBrowserProvider() ``` -Please note that your code need to be in browser context when -`setBrowserProvider` is running. So you may want to use `onMount` when -using Sapper or Sveltekit. Similarly, you cannot use -`setBrowserProvider` in SSR context. +Please note that `setBrowserProvider` can only to be executed in a browser +context. So you may want to use `onMount` when using Sapper or +SvelteKit. Similarly, you cannot use `setBrowserProvider` in SSR +context. ```js onMount( () => { // add a test to return in SSR context - defaultChainStore.setBrowserProvider() + defaultEvmStores.setBrowserProvider() } ) ``` ### Connection with other providers (ws, http, Web3Modal, Walletconnect, etc) -To enable connection using an url string or a valid provider object -(as returned by web3Modal or WalletConnect for example): +To enable connection using an URL string or a valid provider object +(for example as returned by web3Modal or WalletConnect): ```js -defaultChainStore.setProvider() +defaultEvmStores.setProvider() ``` Please check `examples/svelte-app-template-web3/src/Web3Modal.svelte` in github. +### Using the stores -### Forcing a disconnect (and event subscriptions from a provider) +After a connection has been established, you may import the stores +anywhere in your application. Most of the time, you should use the `$` +prefix Svelte notation to access the stores values. -Simply call the function `close` directly on the store. For example with the default store: -```js -defaultChainStore.close() +```html + + +{#if !$connected} + +

My application is not yet connected

+ +{:else} + +

Connected to chain with id {$chainId}

+ +{/if} ``` -### Using the Web3 instance $web3 after the connection +### Using the Web3 API -If a connection is successful, you can access the instantiated web3.js -using the `$` svelte store syntax : +Likewise use the `$` prefix Svelte notation to access its instance and +use the full Web3.js API. (beware, in the Web3.js library +documentation, instances are always noted as `web3`, without `$`, but +in the context of `svelte-web3`, `web3` is the Svelte store itself, +not it's value). ```js -$web3.eth.getBalance() + import { web3, selectedAccount } from 'svelte-web3' + + // ... + + const { name, chainId } = await $web3.eth.getChainId() + + const balance = await $web3.eth.getBalance('0x0000000000000000000000000000000000000000') : '' ``` -The whole Web3.js API is now usable in the ` + +

balance = + +``` + ## Simultaneous multi chain usage You can also using the library to create several stores, each @@ -185,15 +266,15 @@ connection to the same chain througth the browser wallet and simultaneously with Infura; or many stores each connected to a different chains at the same time. -In this case, use the `makeChainStore` factory function as below : +In this case, use the `makeEvmStores` factory function as below : ```js - import { makeChainStore } from 'svelte-web3' + import { makeEvmStores } from 'svelte-web3' - let ethStore, web3, connected, selectedAccount, chainId, chainData - ({ web3, connected, selectedAccount, chainId, chainData, ...ethStore } = makeChainStore('')) + let evmStores, web3, connected, selectedAccount, chainId, chainData + ({ web3, connected, selectedAccount, chainId, chainData, ...evmStores } = makeEvmStores('')) - ethStore.setProvider('https://rpc.slock.it/goerli') + evmStores.setProvider('https://rpc.slock.it/goerli') ``` `` can be an arbitrary name to be able to retrieve the store with the function `getChainStore` @@ -203,21 +284,21 @@ without reinitializing the conection: ```js import { getChainStore } from 'svelte-web3' - let ethStore, web3, connected, selectedAccount, chainId, chainData - ({ web3, connected, selectedAccount, chainId, chainData, ...ethStore } = getChainStore('')) + let evmStores, web3, connected, selectedAccount, chainId, chainData + ({ web3, connected, selectedAccount, chainId, chainData, ...evmStores } = getChainStore('')) ``` The `web3` store and all other derived stores will work the same way as with the default store. -If you want to use the different chain stores in the same svelte file +If you want to use the different chain stores in the same Svelte file (not advised, it's better to use subcomponents), you may renamed the stores this way : ```js - let ethStore_A, web3_A, ethStore_B, web3_B + let evmStores_A, web3_A, evmStores_B, web3_B - ({ web3: web3_A, ...ethStore_A } = makeChainStore('')) - ({ web3: web3_B, ...ethStore_B } = makeChainStore('')) + ({ web3: web3_A, ...evmStores_A } = makeEvmStores('')) + ({ web3: web3_B, ...evmStores_B } = makeEvmStores('')) ``` ## Examples @@ -225,20 +306,29 @@ stores this way : If you are using `svelte-web3` to build an open source Dapp, let us know if you want to be listed in this section. + ### Svelte basic example (based on rollup template) -Please check `examples/svelte-app-template-web3` in github. +Please check [`examples/svelte-app-template-web3` in github] +(https://github.com/clbrge/svelte-web3/tree/master/examples/svelte-app-template-web3). + +Contains demos to use the default store and multi stores. + +### SvelteKit basic example -Contain both sub-examples to use the default store and multi stores. +Please check [`examples/sveltekit-app-template-web3` in github] +(https://github.com/clbrge/svelte-web3/tree/master/examples/sveltekit-app-template-web3). ### Sapper basic example (based on webpack template) -Please check `examples/sapper-app-template-web3` in github. +Please check [`examples/sapper-app-template-web3` in github] +(https://github.com/clbrge/svelte-web3/tree/master/examples/sapper-app-template-web3). +Please check `examples/sapper-app-template-web3` in github. ### tradingstrategy.ai presented at EthLisbon 2021 -A website presented in EthLisbon 2021, used svelte-web3 for building the frontend. : +A website presented in EthLisbon 2021, used svelte-web3 (version 2) for building the frontend. : * The page is live here: https://tradingstrategy.ai/strategy/ethlisbon * Source code : https://github.com/tradingstrategy-ai/frontend/blob/master/src/lib/web3/Investor.svelte diff --git a/examples/sapper-app-template-web3/README.md b/examples/sapper-app-template-web3/README.md index 8dc7474..ce25b7c 100644 --- a/examples/sapper-app-template-web3/README.md +++ b/examples/sapper-app-template-web3/README.md @@ -2,9 +2,11 @@ The default template for setting up a [Sapper](https://github.com/sveltejs/sapper) project. Can use either Rollup or webpack as bundler. +## Please note -## Getting started +Sapper is no longer being actively developed. You may be interested in using Sapper's succesor, [SvelteKit](https://kit.svelte.dev/) for new projects. +## Getting started ### Using `degit` diff --git a/examples/sapper-app-template-web3/package.json b/examples/sapper-app-template-web3/package.json index 63e324f..d52eebd 100644 --- a/examples/sapper-app-template-web3/package.json +++ b/examples/sapper-app-template-web3/package.json @@ -11,15 +11,15 @@ "dependencies": { "compression": "^1.7.1", "polka": "next", - "sirv": "^1.0.0", - "svelte-web3": "^1.3.4" + "sirv": "^1.0.0" }, "devDependencies": { - "file-loader": "^6.0.0", + "svelte-web3": "file:../../", "sapper": "^0.28.0", "svelte": "^3.17.3", - "svelte-loader": "^2.9.0", - "webpack": "^4.7.0", + "file-loader": "^6.0.0", + "svelte-loader": "^3.0.0", + "webpack": "^4.46.0", "webpack-modules": "^1.0.0" } } diff --git a/examples/sapper-app-template-web3/scripts/setupTypeScript.js b/examples/sapper-app-template-web3/scripts/setupTypeScript.js index 68e5b56..fb5cbdf 100644 --- a/examples/sapper-app-template-web3/scripts/setupTypeScript.js +++ b/examples/sapper-app-template-web3/scripts/setupTypeScript.js @@ -194,12 +194,10 @@ function updateWebpackConfig() { /entry: config\.serviceworker\.entry\(\)/, `entry: { 'service-worker': config.serviceworker.entry()['service-worker'].replace(/\\.js$/, '.ts') }` ], - // Add preprocess to the svelte config, this is tricky because there's no easy signifier. - // Instead we look for 'hydratable: true,' [ - /hydratable: true(?!,\n\s*preprocess)/g, - 'hydratable: true,\n\t\t\t\t\t\t\tpreprocess: sveltePreprocess({ sourceMap: dev })' - ], + /loader: 'svelte-loader',\n\t\t\t\t\t\toptions: {/g, + 'loader: \'svelte-loader\',\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tpreprocess: sveltePreprocess({ sourceMap: dev }),' + ], // Add TypeScript rules for client and server [ /module: {\n\s*rules: \[\n\s*(?!{\n\s*test: \/\\\.ts\$\/)/g, diff --git a/examples/sapper-app-template-web3/src/ambient.d.ts b/examples/sapper-app-template-web3/src/ambient.d.ts index ec71cae..a26164d 100644 --- a/examples/sapper-app-template-web3/src/ambient.d.ts +++ b/examples/sapper-app-template-web3/src/ambient.d.ts @@ -10,30 +10,30 @@ */ declare module "*.gif" { const value: string; - export = value; + export default value; } declare module "*.jpg" { const value: string; - export = value; + export default value; } declare module "*.jpeg" { const value: string; - export = value; + export default value; } declare module "*.png" { const value: string; - export = value; + export default value; } declare module "*.svg" { const value: string; - export = value; + export default value; } declare module "*.webp" { const value: string; - export = value; + export default value; } diff --git a/examples/sapper-app-template-web3/src/routes/web3test.svelte b/examples/sapper-app-template-web3/src/routes/web3test.svelte index f0cb7dd..1a50574 100644 --- a/examples/sapper-app-template-web3/src/routes/web3test.svelte +++ b/examples/sapper-app-template-web3/src/routes/web3test.svelte @@ -1,13 +1,13 @@ + + + + + + diff --git a/examples/sveltekit-app-template-web3/src/lib/header/svelte-logo.svg b/examples/sveltekit-app-template-web3/src/lib/header/svelte-logo.svg new file mode 100644 index 0000000..49492a8 --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/lib/header/svelte-logo.svg @@ -0,0 +1 @@ +svelte-logo \ No newline at end of file diff --git a/examples/sveltekit-app-template-web3/src/routes/__layout.svelte b/examples/sveltekit-app-template-web3/src/routes/__layout.svelte new file mode 100644 index 0000000..51316ff --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/routes/__layout.svelte @@ -0,0 +1,45 @@ + + +

+ +
+ +
+ + + + diff --git a/examples/sveltekit-app-template-web3/src/routes/about.svelte b/examples/sveltekit-app-template-web3/src/routes/about.svelte new file mode 100644 index 0000000..569d3e1 --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/routes/about.svelte @@ -0,0 +1,50 @@ + + + + About + + +
+

About this app

+ +

+ This is a SvelteKit app. You can make your own by typing the + following into your command line and following the prompts: +

+ + +
npm init svelte@next
+ +

+ The page you're looking at is purely static HTML, with no client-side interactivity needed. + Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening + the devtools network panel and reloading. +

+ +

+ The TODOs page illustrates SvelteKit's data loading and form handling. Try using + it with JavaScript disabled! +

+
+ + diff --git a/examples/sveltekit-app-template-web3/src/routes/index.svelte b/examples/sveltekit-app-template-web3/src/routes/index.svelte new file mode 100644 index 0000000..1b2cea1 --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/routes/index.svelte @@ -0,0 +1,59 @@ + + + + + + Home + + +
+

+
+ + + Welcome + +
+ + to your new
SvelteKit app +

+ +

+ try editing src/routes/index.svelte +

+ + +
+ + diff --git a/examples/sveltekit-app-template-web3/src/routes/todos/[uid].json.js b/examples/sveltekit-app-template-web3/src/routes/todos/[uid].json.js new file mode 100644 index 0000000..4373f20 --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/routes/todos/[uid].json.js @@ -0,0 +1,14 @@ +import { api } from './_api'; + +// PATCH /todos/:uid.json +export const patch = async (request) => { + return api(request, `todos/${request.locals.userid}/${request.params.uid}`, { + text: request.body.get('text'), + done: request.body.has('done') ? !!request.body.get('done') : undefined + }); +}; + +// DELETE /todos/:uid.json +export const del = async (request) => { + return api(request, `todos/${request.locals.userid}/${request.params.uid}`); +}; diff --git a/examples/sveltekit-app-template-web3/src/routes/todos/_api.js b/examples/sveltekit-app-template-web3/src/routes/todos/_api.js new file mode 100644 index 0000000..9dc73ad --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/routes/todos/_api.js @@ -0,0 +1,45 @@ +/* + This module is used by the /todos.json and /todos/[uid].json + endpoints to make calls to api.svelte.dev, which stores todos + for each user. The leading underscore indicates that this is + a private module, _not_ an endpoint — visiting /todos/_api + will net you a 404 response. + + (The data on the todo app will expire periodically; no + guarantees are made. Don't use it to organise your life.) +*/ + +const base = 'https://api.svelte.dev'; + +export async function api(request, resource, data) { + // user must have a cookie set + if (!request.locals.userid) { + return { status: 401 }; + } + + const res = await fetch(`${base}/${resource}`, { + method: request.method, + headers: { + 'content-type': 'application/json' + }, + body: data && JSON.stringify(data) + }); + + // if the request came from a
submission, the browser's default + // behaviour is to show the URL corresponding to the form's "action" + // attribute. in those cases, we want to redirect them back to the + // /todos page, rather than showing the response + if (res.ok && request.method !== 'GET' && request.headers.accept !== 'application/json') { + return { + status: 303, + headers: { + location: '/todos' + } + }; + } + + return { + status: res.status, + body: await res.json() + }; +} diff --git a/examples/sveltekit-app-template-web3/src/routes/todos/index.json.js b/examples/sveltekit-app-template-web3/src/routes/todos/index.json.js new file mode 100644 index 0000000..ae2df4e --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/routes/todos/index.json.js @@ -0,0 +1,28 @@ +import { api } from './_api'; + +// GET /todos.json +export const get = async (request) => { + // request.locals.userid comes from src/hooks.js + const response = await api(request, `todos/${request.locals.userid}`); + + if (response.status === 404) { + // user hasn't created a todo list. + // start with an empty array + return { body: [] }; + } + + return response; +}; + +// POST /todos.json +export const post = async (request) => { + const response = await api(request, `todos/${request.locals.userid}`, { + // because index.svelte posts a FormData object, + // request.body is _also_ a (readonly) FormData + // object, which allows us to get form data + // with the `body.get(key)` method + text: request.body.get('text') + }); + + return response; +}; diff --git a/examples/sveltekit-app-template-web3/src/routes/todos/index.svelte b/examples/sveltekit-app-template-web3/src/routes/todos/index.svelte new file mode 100644 index 0000000..bdf12af --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/routes/todos/index.svelte @@ -0,0 +1,220 @@ + + + + + + Todos + + +
+

Todos

+ + { + const created = await res.json(); + todos = [...todos, created]; + + form.reset(); + } + }} + > + + + + {#each todos as todo (todo.uid)} +
+
{ + todo.done = !!data.get('done'); + }, + result: patch + }} + > + +
+ {/each} +
+ + diff --git a/examples/sveltekit-app-template-web3/src/routes/web3.svelte b/examples/sveltekit-app-template-web3/src/routes/web3.svelte new file mode 100644 index 0000000..1a50574 --- /dev/null +++ b/examples/sveltekit-app-template-web3/src/routes/web3.svelte @@ -0,0 +1,111 @@ + + + + svelte-web3 test + + +
+ +

Visit the Web3.js documentation to learn how to use Web3.js library.

+ +

{message}

+ + {#if $web3.version} +

+ +

+ +

+ (eg Metamask) +

+ {:else} +

Please check that web3 as been added in Sapper src/template.html with the line:

+
+      <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
+  
+ {/if} + + {#if $connected} +

+ Connected chain: chainId = {$chainId} +

+

+ chainData = {JSON.stringify($chainData)} +

+

+ Selected account: {$selectedAccount || 'not defined'} +

+ +

+ {checkAccount} Balance on {$chainData.name}: + {#await balance} + waiting... + {:then value} + {value} + {/await} {$chainData.nativeCurrency.symbol} +

+ + {#if false && $selectedAccount} +

+ {/if} + + {/if} + +
+ + diff --git a/examples/sveltekit-app-template-web3/static/favicon.png b/examples/sveltekit-app-template-web3/static/favicon.png new file mode 100644 index 0000000..825b9e6 Binary files /dev/null and b/examples/sveltekit-app-template-web3/static/favicon.png differ diff --git a/examples/sveltekit-app-template-web3/static/robots.txt b/examples/sveltekit-app-template-web3/static/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/examples/sveltekit-app-template-web3/static/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/examples/sveltekit-app-template-web3/static/svelte-welcome.png b/examples/sveltekit-app-template-web3/static/svelte-welcome.png new file mode 100644 index 0000000..fe7d2d6 Binary files /dev/null and b/examples/sveltekit-app-template-web3/static/svelte-welcome.png differ diff --git a/examples/sveltekit-app-template-web3/static/svelte-welcome.webp b/examples/sveltekit-app-template-web3/static/svelte-welcome.webp new file mode 100644 index 0000000..6ec1a28 Binary files /dev/null and b/examples/sveltekit-app-template-web3/static/svelte-welcome.webp differ diff --git a/examples/sveltekit-app-template-web3/svelte.config.js b/examples/sveltekit-app-template-web3/svelte.config.js new file mode 100644 index 0000000..6ccba57 --- /dev/null +++ b/examples/sveltekit-app-template-web3/svelte.config.js @@ -0,0 +1,13 @@ +import adapter from '@sveltejs/adapter-auto'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: { + adapter: adapter(), + + // hydrate the
element in src/app.html + target: '#svelte' + } +}; + +export default config; diff --git a/package-lock.json b/package-lock.json index 7e51208..0d2d9aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,36 +1,37 @@ { "name": "svelte-web3", - "version": "2.3.5", + "version": "3.0.0-5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "svelte-web3", - "version": "2.3.5", + "version": "3.0.0-5", "license": "MIT", "dependencies": { - "svelte": "^3.0.0" + "svelte": "^3.0.0", + "svelte-proxied-store": "^0.2.0" }, "devDependencies": { "eslint-plugin-svelte3": "^3.2.1", "release-it": "^14.11.8", - "rollup": "^2.61.1", + "rollup": "^2.62.0", "rollup-plugin-babel": "^4.4.0", - "rollup-plugin-dts": "^4.0.1", + "rollup-plugin-dts": "^4.1.0", "rollup-plugin-livereload": "^2.0.5", "rollup-plugin-svelte": "^7.1.0", - "sirv-cli": "^1.0.14", + "sirv-cli": "^2.0.1", "svelte": "^3.44.3", "web3": "1.6.1" } }, "node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -49,21 +50,21 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -719,9 +720,9 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.20", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.20.tgz", - "integrity": "sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q==", + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, "node_modules/@sindresorhus/is": { @@ -4586,9 +4587,9 @@ } }, "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", + "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", "dev": true, "engines": { "node": ">=6" @@ -4901,18 +4902,6 @@ "miller-rabin": "bin/miller-rabin" } }, - "node_modules/mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/mime-db": { "version": "1.51.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", @@ -5050,6 +5039,15 @@ "node": ">=4" } }, + "node_modules/mrmime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", + "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -6493,9 +6491,9 @@ "dev": true }, "node_modules/rollup": { - "version": "2.61.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.61.1.tgz", - "integrity": "sha512-BbTXlEvB8d+XFbK/7E5doIcRtxWPRiqr0eb5vQ0+2paMM04Ye4PZY5nHOQef2ix24l/L0SpLd5hwcH15QHPdvA==", + "version": "2.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.62.0.tgz", + "integrity": "sha512-cJEQq2gwB0GWMD3rYImefQTSjrPYaC6s4J9pYqnstVLJ1CHa/aZNVkD4Epuvg4iLeMA4KRiq7UM7awKK6j7jcw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -6518,25 +6516,25 @@ } }, "node_modules/rollup-plugin-dts": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-4.0.1.tgz", - "integrity": "sha512-DNv5F8pro/r0Hkx3JWKRtJZocDnqXfgypoajeiaNq134rYaFcEIl/oas5PogD1qexMadVijsHyVko1Chig0OOQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-4.1.0.tgz", + "integrity": "sha512-rriXIm3jdUiYeiAAd1Fv+x2AxK6Kq6IybB2Z/IdoAW95fb4uRUurYsEYKa8L1seedezDeJhy8cfo8FEL9aZzqg==", "dev": true, "dependencies": { "magic-string": "^0.25.7" }, "engines": { - "node": ">=v12.22.6" + "node": ">=v12.22.7" }, "funding": { "url": "https://github.com/sponsors/Swatinem" }, "optionalDependencies": { - "@babel/code-frame": "^7.14.5" + "@babel/code-frame": "^7.16.0" }, "peerDependencies": { - "rollup": "^2.56.3", - "typescript": "^4.4.2" + "rollup": "^2.55", + "typescript": "~4.1 || ~4.2 || ~4.3 || ~4.4 || ~4.5" } }, "node_modules/rollup-plugin-livereload": { @@ -6925,32 +6923,32 @@ } }, "node_modules/sirv": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.17.tgz", - "integrity": "sha512-qx9go5yraB7ekT7bCMqUHJ5jEaOC/GXBxUWv+jeWnb7WzHUFdcQPGWk7YmAwFBaQBrogpuSqd/azbC2lZRqqmw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.0.tgz", + "integrity": "sha512-TT+4+zSM9LR8soWT5/4gOYHfB5a5XEOSV2LtmBRN5MUxi8kh7BSRGuoRYjeBaqhR4w+yx+k6t0OibDNgoLfF7w==", "dev": true, "dependencies": { "@polka/url": "^1.0.0-next.20", - "mime": "^2.3.1", - "totalist": "^1.0.0" + "mrmime": "^1.0.0", + "totalist": "^2.0.0" }, "engines": { "node": ">= 10" } }, "node_modules/sirv-cli": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-1.0.14.tgz", - "integrity": "sha512-yyUTNr984ANKDloqepkYbBSqvx3buwYg2sQKPWjSU+IBia5loaoka2If8N9CMwt8AfP179cdEl7kYJ//iWJHjQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-2.0.1.tgz", + "integrity": "sha512-QuPr005HRybjSJxTBz0kFLNme3qSoged8cfb+fvXhpZieDPNWWqKm8ApYUM0r0VtieG+92dfdHm1Ip9CCoZECw==", "dev": true, "dependencies": { "console-clear": "^1.1.0", "get-port": "^3.2.0", - "kleur": "^3.0.0", + "kleur": "^4.1.4", "local-access": "^1.0.1", "sade": "^1.6.0", "semiver": "^1.0.0", - "sirv": "^1.0.13", + "sirv": "^2.0.0", "tinydate": "^1.0.0" }, "bin": { @@ -7201,6 +7199,11 @@ "node": ">= 8" } }, + "node_modules/svelte-proxied-store": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/svelte-proxied-store/-/svelte-proxied-store-0.2.0.tgz", + "integrity": "sha512-VFYiLvL0qOD5zyqHMg80gLnVWSwH8aNtO3gJ1k6wPNhNUqzqkyRpuUoaw0VpQnMxP6z1zki/PNW5A04KIQWk0g==" + }, "node_modules/swarm-js": { "version": "0.1.40", "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.40.tgz", @@ -7439,9 +7442,9 @@ } }, "node_modules/totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-2.0.0.tgz", + "integrity": "sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ==", "dev": true, "engines": { "node": ">=6" @@ -8626,12 +8629,12 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.16.7" } }, "@babel/helper-module-imports": { @@ -8644,18 +8647,18 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true }, "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } @@ -9102,9 +9105,9 @@ } }, "@polka/url": { - "version": "1.0.0-next.20", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.20.tgz", - "integrity": "sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q==", + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, "@sindresorhus/is": { @@ -12217,9 +12220,9 @@ } }, "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", + "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", "dev": true }, "latest-version": { @@ -12461,12 +12464,6 @@ "brorand": "^1.0.1" } }, - "mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", - "dev": true - }, "mime-db": { "version": "1.51.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", @@ -12576,6 +12573,12 @@ "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", "dev": true }, + "mrmime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", + "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -13683,9 +13686,9 @@ } }, "rollup": { - "version": "2.61.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.61.1.tgz", - "integrity": "sha512-BbTXlEvB8d+XFbK/7E5doIcRtxWPRiqr0eb5vQ0+2paMM04Ye4PZY5nHOQef2ix24l/L0SpLd5hwcH15QHPdvA==", + "version": "2.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.62.0.tgz", + "integrity": "sha512-cJEQq2gwB0GWMD3rYImefQTSjrPYaC6s4J9pYqnstVLJ1CHa/aZNVkD4Epuvg4iLeMA4KRiq7UM7awKK6j7jcw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -13711,12 +13714,12 @@ } }, "rollup-plugin-dts": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-4.0.1.tgz", - "integrity": "sha512-DNv5F8pro/r0Hkx3JWKRtJZocDnqXfgypoajeiaNq134rYaFcEIl/oas5PogD1qexMadVijsHyVko1Chig0OOQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-4.1.0.tgz", + "integrity": "sha512-rriXIm3jdUiYeiAAd1Fv+x2AxK6Kq6IybB2Z/IdoAW95fb4uRUurYsEYKa8L1seedezDeJhy8cfo8FEL9aZzqg==", "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", + "@babel/code-frame": "^7.16.0", "magic-string": "^0.25.7" } }, @@ -13999,29 +14002,29 @@ } }, "sirv": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.17.tgz", - "integrity": "sha512-qx9go5yraB7ekT7bCMqUHJ5jEaOC/GXBxUWv+jeWnb7WzHUFdcQPGWk7YmAwFBaQBrogpuSqd/azbC2lZRqqmw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.0.tgz", + "integrity": "sha512-TT+4+zSM9LR8soWT5/4gOYHfB5a5XEOSV2LtmBRN5MUxi8kh7BSRGuoRYjeBaqhR4w+yx+k6t0OibDNgoLfF7w==", "dev": true, "requires": { "@polka/url": "^1.0.0-next.20", - "mime": "^2.3.1", - "totalist": "^1.0.0" + "mrmime": "^1.0.0", + "totalist": "^2.0.0" } }, "sirv-cli": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-1.0.14.tgz", - "integrity": "sha512-yyUTNr984ANKDloqepkYbBSqvx3buwYg2sQKPWjSU+IBia5loaoka2If8N9CMwt8AfP179cdEl7kYJ//iWJHjQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-2.0.1.tgz", + "integrity": "sha512-QuPr005HRybjSJxTBz0kFLNme3qSoged8cfb+fvXhpZieDPNWWqKm8ApYUM0r0VtieG+92dfdHm1Ip9CCoZECw==", "dev": true, "requires": { "console-clear": "^1.1.0", "get-port": "^3.2.0", - "kleur": "^3.0.0", + "kleur": "^4.1.4", "local-access": "^1.0.1", "sade": "^1.6.0", "semiver": "^1.0.0", - "sirv": "^1.0.13", + "sirv": "^2.0.0", "tinydate": "^1.0.0" } }, @@ -14205,6 +14208,11 @@ "integrity": "sha512-aGgrNCip5PQFNfq9e9tmm7EYxWLVHoFsEsmKrtOeRD8dmoGDdyTQ+21xd7qgFd8MNdKGSYvg7F9dr+Tc0yDymg==", "dev": true }, + "svelte-proxied-store": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/svelte-proxied-store/-/svelte-proxied-store-0.2.0.tgz", + "integrity": "sha512-VFYiLvL0qOD5zyqHMg80gLnVWSwH8aNtO3gJ1k6wPNhNUqzqkyRpuUoaw0VpQnMxP6z1zki/PNW5A04KIQWk0g==" + }, "swarm-js": { "version": "0.1.40", "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.40.tgz", @@ -14400,9 +14408,9 @@ "dev": true }, "totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-2.0.0.tgz", + "integrity": "sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ==", "dev": true }, "tough-cookie": { diff --git a/package.json b/package.json index 75855f3..88ea8ce 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,47 @@ { "name": "svelte-web3", - "version": "2.3.5", + "version": "3.0.0-5", "description": "web3.js as a collection of stores for Svelte, Sapper or SvelteKit.", - "main": "dist/index.js", - "module": "dist/index.mjs", - "svelte": "src/web3-store.js", - "types": "dist/svelte-web3.d.ts", "license": "MIT", "repository": "clbrge/svelte-web3", "author": { "name": "Christophe Le Bars", "email": "" }, + "main": "dist/index.js", + "module": "dist/index.mjs", + "svelte": "src/stores.js", + "types": "dist/svelte-web3.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "svelte": "./src/stores.js", + "types": "./dist/svelte-web3.d.ts" + }, + "./components": { + "import": "./src/components/index.js", + "svelte": "./src/components/index.js" + } + }, "scripts": { "update-chains": "node ./scripts/update-chains.js", "build": "rollup -c" }, "dependencies": { - "svelte": "^3.0.0" + "svelte": "^3.0.0", + "svelte-proxied-store": "^0.2.0" }, "devDependencies": { "eslint-plugin-svelte3": "^3.2.1", "release-it": "^14.11.8", - "rollup": "^2.61.1", + "rollup": "^2.62.0", "rollup-plugin-babel": "^4.4.0", - "rollup-plugin-dts": "^4.0.1", + "rollup-plugin-dts": "^4.1.0", "rollup-plugin-livereload": "^2.0.5", "rollup-plugin-svelte": "^7.1.0", - "sirv-cli": "^1.0.14", + "sirv-cli": "^2.0.1", "svelte": "^3.44.3", "web3": "1.6.1" }, diff --git a/rollup.config.js b/rollup.config.js index cce7798..eeb580b 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -2,7 +2,7 @@ import dts from "rollup-plugin-dts"; export default [ { - input: "./src/web3-store.js", + input: "./src/stores.js", output: [ { file: "dist/index.mjs", format: "es" }, { file: "dist/index.js", format: "umd", name: "web3store" }, diff --git a/src/chains.js b/src/chains.js index 5447c23..71528cf 100644 --- a/src/chains.js +++ b/src/chains.js @@ -288,8 +288,13 @@ const chains = [ name: 'Songbird Canary-Network', chain: 'SGB', network: 'songbird', - rpc: [ 'https://songbird.towolabs.com/rpc' ], - faucets: [ 'https://free-online-app.com/faucet-for-eth-evm-chains/' ], + rpc: [ + 'https://songbird.towolabs.com/rpc', + 'https://sgb.ftso.com.au/ext/bc/C/rpc', + 'https://sgb.lightft.so/rpc', + 'https://sgb-rpc.ftso.eu' + ], + faucets: [], nativeCurrency: { name: 'Songbird', symbol: 'SGB', decimals: 18 }, infoURL: 'https://flare.xyz', shortName: 'sgb', @@ -351,6 +356,19 @@ const chains = [ chainId: 23, networkId: 23 }, + { + name: 'Dithereum Mainnet', + chain: 'DTH', + network: 'mainnet', + icon: 'dithereum', + rpc: [ 'https://node-mainnet.dithereum.io' ], + faucets: [ 'https://faucet.dithereum.org' ], + nativeCurrency: { name: 'Dither', symbol: 'DTH', decimals: 18 }, + infoURL: 'https://dithereum.org', + shortName: 'dthmainnet', + chainId: 24, + networkId: 24 + }, { name: 'Cronos Mainnet Beta', chain: 'CRO', @@ -1249,8 +1267,8 @@ const chains = [ ] }, { - name: 'xDAI Chain', - chain: 'XDAI', + name: 'Gnosis Chain (formerly xDai)', + chain: 'Gnosis', network: 'mainnet', rpc: [ 'https://rpc.xdaichain.com', @@ -1262,19 +1280,20 @@ const chains = [ 'ws://xdai.poanetwork.dev:8546' ], faucets: [ - 'https://free-online-app.com/faucet-for-eth-evm-chains/', - 'https://xdai-app.herokuapp.com/faucet' + 'https://xdai-app.herokuapp.com/faucet', + 'https://stakely.io/faucet/xdai-chain', + 'https://faucet.prussia.dev/xdai' ], nativeCurrency: { name: 'xDAI', symbol: 'xDAI', decimals: 18 }, - infoURL: 'https://forum.poa.network/c/xdai-chain', - shortName: 'xdai', + infoURL: 'https://www.xdaichain.com/', + shortName: 'gno', chainId: 100, networkId: 100, slip44: 700, explorers: [ { name: 'blockscout', - url: 'https://blockscout.com/poa/xdai', + url: 'https://blockscout.com/xdai/mainnet', standard: 'EIP3091' } ] @@ -2274,7 +2293,7 @@ const chains = [ name: 'Klaytn Testnet Baobab', chain: 'KLAY', network: 'baobab', - rpc: [ 'https://node-api.klaytnapi.com/v1/klaytn' ], + rpc: [ 'https://api.baobab.klaytn.net:8651' ], faucets: [ 'https://baobab.wallet.klaytn.com/access?next=faucet' ], nativeCurrency: { name: 'KLAY', symbol: 'KLAY', decimals: 18 }, infoURL: 'https://www.klaytn.com/', @@ -2540,8 +2559,8 @@ const chains = [ chain: 'MOON', network: 'moonbase', rpc: [ - 'https://rpc.testnet.moonbeam.network', - 'wss://wss.testnet.moonbeam.network' + 'https://rpc.api.moonbase.moonbeam.network', + 'wss://wss.api.moonbase.moonbeam.network' ], faucets: [], nativeCurrency: { name: 'Dev', symbol: 'DEV', decimals: 18 }, @@ -2671,6 +2690,7 @@ const chains = [ name: 'Rangers Protocol Mainnet', chain: 'Rangers', network: 'mainnet', + icon: 'rangers', rpc: [ 'https://mainnet.rangersprotocol.com/api/jsonrpc' ], faucets: [], nativeCurrency: { name: 'Rangers Protocol Gas', symbol: 'RPG', decimals: 18 }, @@ -2752,13 +2772,13 @@ const chains = [ }, { name: 'Bittex Mainnet', - chain: 'BTTX', + chain: 'BTX', network: 'mainnet', rpc: [ 'https://rpc1.bittexscan.info', 'https://rpc2.bittexscan.info' ], faucets: [], - nativeCurrency: { name: 'Bittex', symbol: 'BTTX', decimals: 18 }, + nativeCurrency: { name: 'Bittex', symbol: 'BTX', decimals: 18 }, infoURL: 'https://bittexscan.com', - shortName: 'bttx', + shortName: 'btx', chainId: 3690, networkId: 3690, icon: 'ethereum', @@ -2992,7 +3012,7 @@ const chains = [ name: 'Klaytn Mainnet Cypress', chain: 'KLAY', network: 'cypress', - rpc: [ 'https://api.cypress.ozys.net:8651' ], + rpc: [ 'https://public-node-api.klaytnapi.com/v1/cypress' ], faucets: [], nativeCurrency: { name: 'KLAY', symbol: 'KLAY', decimals: 18 }, infoURL: 'https://www.klaytn.com/', @@ -3108,6 +3128,42 @@ const chains = [ } ] }, + { + name: 'Evmos', + chain: 'Evmos', + network: 'mainnet', + rpc: [ 'https://ethereum.rpc.evmos.org' ], + faucets: [], + nativeCurrency: { name: 'Evmos', symbol: 'EVMOS', decimals: 18 }, + infoURL: 'https://evmos.org', + shortName: 'evmos', + chainId: 9001, + networkId: 9001, + explorers: [ + { + name: 'Evmos EVM Explorer (Blockscout)', + url: 'https://evm.evmos.org', + standard: 'none' + }, + { + name: 'Evmos Cosmos Explorer (Big Dipper)', + url: 'https://explorer.evmos.org', + standard: 'none' + } + ] + }, + { + name: 'Genesis Coin', + chain: 'Genesis', + network: 'Genesis Coin', + rpc: [ 'https://genesis-gn.com', 'wss://genesis-gn.com' ], + faucets: [], + nativeCurrency: { name: 'GN Coin', symbol: 'GNC', decimals: 18 }, + infoURL: 'https://genesis-gn.com', + shortName: 'GENEC', + chainId: 9100, + networkId: 9100 + }, { name: 'Rangers Protocol Testnet Robin', chain: 'Rangers', @@ -3418,6 +3474,49 @@ const chains = [ } ] }, + { + name: 'Emerald Paratime Testnet', + chain: 'Emerald', + network: 'testnet', + icon: 'oasis', + rpc: [ + 'https://testnet.emerald.oasis.dev/', + 'wss://testnet.emerald.oasis.dev/ws' + ], + faucets: [], + nativeCurrency: { name: 'Emerald Rose', symbol: 'ROSE', decimals: 18 }, + infoURL: 'https://docs.oasis.dev/general/developer-resources/overview', + shortName: 'emerald', + chainId: 42261, + networkId: 42261, + explorers: [ + { + name: 'Emerald Paratime Testnet Explorer', + url: 'https://testnet.explorer.emerald.oasis.dev/', + standard: 'EIP3091' + } + ] + }, + { + name: 'Emerald Paratime Mainnet', + chain: 'Emerald', + network: 'Mainnet', + icon: 'oasis', + rpc: [ 'https://emerald.oasis.dev', 'wss://emerald.oasis.dev/ws' ], + faucets: [], + nativeCurrency: { name: 'Emerald Rose', symbol: 'ROSE', decimals: 18 }, + infoURL: 'https://docs.oasis.dev/general/developer-resources/overview', + shortName: 'oasis', + chainId: 42262, + networkId: 42262, + explorers: [ + { + name: 'Emerald Paratime Mainnet Explorer', + url: 'https://explorer.emerald.oasis.dev/', + standard: 'EIP3091' + } + ] + }, { name: 'Athereum', chain: 'ATH', diff --git a/src/components/Balance.svelte b/src/components/Balance.svelte new file mode 100644 index 0000000..ef0d924 --- /dev/null +++ b/src/components/Balance.svelte @@ -0,0 +1,12 @@ + + +{#if address}{#await balance}{pending}{:then value}{value}{/await}{/if} diff --git a/src/components/index.js b/src/components/index.js new file mode 100644 index 0000000..a5e0f63 --- /dev/null +++ b/src/components/index.js @@ -0,0 +1,3 @@ +import Balance from './Balance.svelte' + +export { Balance } diff --git a/src/stores.js b/src/stores.js new file mode 100644 index 0000000..59ed199 --- /dev/null +++ b/src/stores.js @@ -0,0 +1,209 @@ + +import { proxied } from 'svelte-proxied-store' +import { derived } from 'svelte/store' + +import chains from './chains.js' + +const getGlobalObject = () => { + if (typeof globalThis !== 'undefined') { return globalThis } + if (typeof self !== 'undefined') { return self } + if (typeof window !== 'undefined') { return window } + if (typeof global !== 'undefined') { return global } + throw new Error('cannot find the global object') +} + +export let Web3 = {} + +export const loadWeb3 = () => { + if (Web3.version) return + try { + Web3 = getGlobalObject().Web3 || {} + } catch (err) { + console.error('no globalThis.Web3 object') + } +} + +const getWindowEthereum = () => { + try { + if (getGlobalObject().ethereum) return getGlobalObject().ethereum + } catch (err) { + console.error('no globalThis.ethereum object') + } +} + +export const createStore = () => { + + const { emit, get, subscribe, assign, deleteAll } = proxied() + + const init = () => { + loadWeb3() + if (!Web3.version) throw new Error('[svelte-web3] Cannot find Web3') + if (getWindowEthereum()) getWindowEthereum().autoRefreshOnNetworkChange = false + deleteAll() + assign({ + connected: false, + evmProviderType: '', + accounts: [] + }) + } + + const setProvider = async (evmProvider, callback) => { + init() + const web3 = new Web3(evmProvider) + const chainId = await web3.eth.getChainId() + // no account with ganache use try catch ? + const accounts = /127/.test(evmProvider) ? [] : await web3.eth.getAccounts() + if (callback) { + web3._provider.removeListener('accountsChanged', () => setProvider(evmProvider, true)) + web3._provider.removeListener('chainChanged', () => setProvider(evmProvider, true)) + } else { + if (web3._provider && web3._provider.on) { + web3._provider.on('accountsChanged', () => setProvider(evmProvider, true)) + web3._provider.on('chainChanged', () => setProvider(evmProvider, true)) + } + } + assign({ + web3, + selectedAccount: accounts.length ? accounts[0] : null, + connected: true, + chainId, + evmProvider: web3._provider, + evmProviderType: typeof evmProvider === 'string' ? 'RPC' : 'Web3', + accounts + }) + emit() + } + + const setBrowserProvider = async () => { + init() + if (!getWindowEthereum()) throw new Error('[svelte-web3] Please authorize browser extension (Metamask or similar)') + const accounts = await getWindowEthereum().request({ method: 'eth_requestAccounts' }) + getWindowEthereum().on('accountsChanged', setBrowserProvider) + getWindowEthereum().on('chainChanged', setBrowserProvider) + const web3 = new Web3(getWindowEthereum()) + const chainId = await web3.eth.getChainId() + assign({ + web3, + selectedAccount: accounts.length ? accounts[0] : null, + connected: true, + chainId, + evmProvider: getWindowEthereum(), + evmProviderType: 'Browser', + accounts + }) + emit() + } + + const disconnect = async (evmProvider) => { + if(evmProvider && evmProvider.disconnect) { + await evmProvider.disconnect() + } + init() + emit() + } + + return { + setBrowserProvider, + setProvider, + disconnect, + close: disconnect, + subscribe, + get + } +} + +const allStores = {} + +const noData = { rpc: [], faucets: [], nativeCurrency: {} } + +const getData = id => { + if (!id || !Web3.utils) return noData + if (Web3.utils.isHexStrict(id)) id = Web3.utils.hexToNumber(id) + for (const data of chains) { + if (data.chainId === id) return data + } + return noData +} + +const subStoreNames = [ 'web3', 'selectedAccount', 'connected', 'chainId', ] + +export const makeEvmStores = name => { + + const evmStore = allStores[name] = createStore() + + allStores[name].web3 = derived( + evmStore, + $evmStore => { + if (!$evmStore.web3) return { utils: Web3.utils, version: Web3.version } + return $evmStore.web3 + } + ) + + allStores[name].selectedAccount = derived(evmStore, $evmStore => $evmStore.selectedAccount) + + allStores[name].connected = derived(evmStore, $evmStore => $evmStore.connected) + allStores[name].chainId = derived(evmStore, $evmStore => $evmStore.chainId) + allStores[name].chainData = derived( + evmStore, + $evmStore => $evmStore.chainId ? getData($evmStore.chainId) : {} + ) + + allStores[name].evmProviderType = derived(evmStore, $evmStore => $evmStore.evmProviderType) + allStores[name].walletType = derived(evmStore, $evmStore => { + if (!$evmStore.provider) return null + if (typeof $evmStore.provider === 'string') return $evmStore.provider + if ($evmStore.provider.isMetaMask) return 'MetaMask (or compatible)' + if ($evmStore.provider.isNiftyWallet) return 'Nifty' + if ($evmStore.provider.isTrust) return 'Trust' + return 'Unknown' + }) + + return new Proxy(allStores[name], { + get: function (internal, property) { + if (/^\$/.test(property)) { + // TODO forbid deconstruction ! + property = property.slice(1) + if (subStoreNames.includes(property)) return allStores[name].get(property) + throw new Error(`[svelte-web3] no value for store named ${property}`) + } + if (['subscribe', 'get', 'setBrowserProvider', 'setProvider', 'evmProviderType', 'chainData', 'walletType', 'close', 'disconnect', ...subStoreNames].includes(property)) + return Reflect.get(internal, property) + throw new Error(`[svelte-web3] no store named ${property}`) + } + }) +} + +export const getChainStore = name => { + if (!allStores[name]) throw new Error(`[svelte-web3] chain store ${name} does not exist`) + return allStores[name] +} + +export const makeContractStore = (abi, address, defaults = {}) => derived( + [web3, connected], + ([$web3, $connected]) => { + if ($connected && $web3.eth) { + return new $web3.eth.Contract(abi, address, defaults) + } + return null + } +) + +loadWeb3() + +export { chains as allChainsData } + +export const defaultEvmStores = makeEvmStores('default') + +export const connected = allStores.default.connected +export const chainId = allStores.default.chainId +export const evmProviderType = allStores.default.evmProviderType +export const selectedAccount = allStores.default.selectedAccount +export const web3 = allStores.default.web3 +export const chainData = allStores.default.chainData + +// TODO spin off dectector +export const walletType = allStores.default.walletType + +// legacy naming + +export const defaultChainStore = defaultEvmStores diff --git a/src/web3-store.js b/src/web3-store.js deleted file mode 100644 index 0a0bd60..0000000 --- a/src/web3-store.js +++ /dev/null @@ -1,187 +0,0 @@ - -import chains from './chains.js' -import { derived, writable } from 'svelte/store' - -const getGlobalObject = () => { - if (typeof globalThis !== 'undefined') { return globalThis } - if (typeof self !== 'undefined') { return self } - if (typeof window !== 'undefined') { return window } - if (typeof global !== 'undefined') { return global } - throw new Error('cannot find the global object') -} - -export let Web3 = {} - -export const loadWeb3 = () => { - if (Web3.version) return - try { - Web3 = getGlobalObject().Web3 || {} - } catch (err) { - console.error('no globalThis.Web3 object') - } -} - -const getWindowEthereum = () => { - try { - if (getGlobalObject().ethereum) return getGlobalObject().ethereum - } catch (err) { - console.error('no globalThis.ethereum object') - } -} - -export const createStore = () => { - const { subscribe, update, set } = writable({ - connected: false, - accounts: [] - }) - - const init = () => { - loadWeb3() - if (!Web3.version) throw new Error('Cannot find Web3') - if (getWindowEthereum()) getWindowEthereum().autoRefreshOnNetworkChange = false - } - - const setProvider = async (provider, callback) => { - init() - const instance = new Web3(provider) - const chainId = await instance.eth.getChainId() - // no account with ganache - const accounts = /127/.test(provider) ? [] : await instance.eth.getAccounts() - if (callback) { - instance._provider.removeListener('accountsChanged', () => setProvider(provider, true)) - instance._provider.removeListener('chainChanged', () => setProvider(provider, true)) - } else { - if (instance._provider && instance._provider.on) { - instance._provider.on('accountsChanged', () => setProvider(provider, true)) - instance._provider.on('chainChanged', () => setProvider(provider, true)) - } - } - update(() => ({ - provider, - providerType: 'String', - connected: true, - chainId, - accounts, - instance - })) - } - - const setBrowserProvider = async () => { - init() - if (!getWindowEthereum()) throw new Error('Please authorize browser extension (Metamask or similar)') - const res = await getWindowEthereum().request({ method: 'eth_requestAccounts' }) - getWindowEthereum().on('accountsChanged', setBrowserProvider) - getWindowEthereum().on('chainChanged', setBrowserProvider) - const instance = new Web3(getWindowEthereum()) - const chainId = await instance.eth.getChainId() - update(() => ({ - provider: getWindowEthereum(), - providerType: 'Browser', - connected: true, - chainId, - accounts: res, - instance - })) - } - - const close = async (provider) => { - if(provider && provider.disconnect) { - await provider.disconnect() - } - update(() => ({ - connected: false, - accounts: [] - })) - } - - return { - setBrowserProvider, - setProvider, - close, - subscribe - } -} - -const allStores = {} - -const noData = { rpc: [], faucets: [], nativeCurrency: {} } - -const getData = id => { - if (!id || !Web3.utils) return noData - if (Web3.utils.isHexStrict(id)) id = Web3.utils.hexToNumber(id) - for (const data of chains) { - if (data.chainId === id) return data - } - return noData -} - -export const makeChainStore = name => { - - const ethStore = allStores[name] = createStore() - - allStores[name].connected = derived(ethStore, $ethStore => $ethStore.connected) - allStores[name].chainId = derived(ethStore, $ethStore => $ethStore.chainId) - allStores[name].providerType = derived(ethStore, $ethStore => $ethStore.providerType) - allStores[name].selectedAccount = derived( - ethStore, - $ethStore => { - if ($ethStore.connected) return $ethStore.accounts.length ? $ethStore.accounts[0] : null - return null - } - ) - - allStores[name].walletType = derived(ethStore, $ethStore => { - if (!$ethStore.provider) return null - if (typeof $ethStore.provider === 'string') return $ethStore.provider - if ($ethStore.provider.isMetaMask) return 'MetaMask (or compatible)' - if ($ethStore.provider.isNiftyWallet) return 'Nifty' - if ($ethStore.provider.isTrust) return 'Trust' - return 'Unknown' - }) - - allStores[name].web3 = derived( - ethStore, - $ethStore => { - if (!$ethStore.instance) return { utils: Web3.utils, version: Web3.version } - return $ethStore.instance - } - ) - - allStores[name].chainData = derived( - ethStore, - $ethStore => $ethStore.chainId ? getData($ethStore.chainId) : {} - ) - - return allStores[name] -} - -export const getChainStore = name => { - if (!allStores[name]) throw new Error(`chain store ${name} does not exist`) - return allStores[name] -} - -export const makeContractStore = (abi, address, defaults = {}) => derived( - [web3, connected], - ([$web3, $connected]) => { - if ($connected && $web3.eth) { - return new $web3.eth.Contract(abi, address, defaults) - } - return null - } -) - -loadWeb3() - -export { chains as allChainsData } - -export const defaultChainStore = makeChainStore('default') -export const connected = allStores.default.connected -export const chainId = allStores.default.chainId -export const providerType = allStores.default.providerType -export const selectedAccount = allStores.default.selectedAccount -export const walletType = allStores.default.walletType -export const web3 = allStores.default.web3 -export const chainData = allStores.default.chainData - -export const ethStore = defaultChainStore -