Skip to content

Commit

Permalink
feat(evmconnector): magic link
Browse files Browse the repository at this point in the history
* feat(evmconnector): magic link

magic link connector package

* add all possible options

* fix lint error

* WIP

* perf(evmConnector): make package as small as possible

* remove exposed email

* add cdn build compatibility

* add cdn test

* use evmProvider datatype

* remove unused code

* change output name

* proper implementation of abstract connector

* fix magic build issue

* fix cjs build magic-sdk

* magic-sdk build issue

Co-authored-by: Erno <[email protected]>
  • Loading branch information
sogunshola and ErnoW authored Jul 13, 2022
1 parent 55f54e1 commit 108a8db
Show file tree
Hide file tree
Showing 22 changed files with 634 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-lobsters-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@moralisweb3/evm-magic-link-connector': major
---

This package gives the ability to connect to EVM using magic link
3 changes: 2 additions & 1 deletion demos/test-app-all/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
REACT_APP_SERVER_URL = ""
REACT_APP_APP_ID = ""
REACT_APP_API_KEY = ""
REACT_APP_MORALIS_SECRET = ""
REACT_APP_MORALIS_SECRET = ""
REACT_APP_MAGIC_LINK_KEY = ""
1 change: 1 addition & 0 deletions demos/test-app-all/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"moralis": "^2.0.0-alpha.1",
"@moralisweb3/server": "^2.0.0-alpha.1",
"@moralisweb3/evm-wallet-connect-connector": "^2.0.0-alpha.1",
"@moralisweb3/evm-magic-link-connector": "^2.0.0-alpha.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-scripts": "^4",
Expand Down
3 changes: 3 additions & 0 deletions demos/test-app-all/src/Evm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import Moralis from 'moralis';
import { Erc20Value, EvmNative } from '@moralisweb3/core';
import WalletConnectConnector from '@moralisweb3/evm-wallet-connect-connector';
import MetamaskConnector from '@moralisweb3/evm-metamask-connector';
import MagiclinkConnector from '@moralisweb3/evm-magic-link-connector';

// Register connector connect connector
Moralis.Evm.connectors.register(WalletConnectConnector);
Moralis.Evm.connectors.register(MagiclinkConnector);
// Moralis.Evm.connectors.remove('wallet-connect');

export const Evm = () => {
return (
<div>
<h2>EVM</h2>
<button onClick={() => Moralis.Evm.connect('metamask', { silent: false })}>Connect via metamask</button>
<button onClick={() => Moralis.Evm.connect('magic-link', { email: '[email protected]', apiKey: process.env.REACT_APP_MAGIC_LINK_KEY, chainId: 3, newSession: true })}>Connect via magiclink</button>
<button onClick={() => Moralis.Evm.connect('wallet-connect', { newSession: true })}>
Connect via walletconnect
</button>
Expand Down
3 changes: 3 additions & 0 deletions demos/test-cdn/public/demo.esm.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@
"@moralisweb3/evm-connector-utils": "../../../packages/evmConnectors/EvmConnectorUtils/dist/index.esm.js",
"@moralisweb3/evm-metamask-connector": "../../../packages/evmConnectors/EvmMetamaskConnector/dist/index.esm.js",
"@moralisweb3/evm-wallet-connect-connector": "../../../packages/evmConnectors/EvmWalletconnectConnector/dist/index.esm.js",
"@moralisweb3/evm-magic-link-connector": "../../../packages/evmConnectors/EvmMagiclinkConnector/dist/index.esm.js",
"moralis": "../../../packages/moralis/dist/index.esm.js"
}
}
</script>
<script type="module">
import Moralis from 'moralis';
import WalletConnectConnector from '@moralisweb3/evm-wallet-connect-connector';
import MagiclinkConnector from '@moralisweb3/evm-magic-link-connector';
window.Moralis = Moralis;
window.WalletConnectConnector = WalletConnectConnector;
window.MagiclinkConnector = MagiclinkConnector;
</script>
<script src="./env.js"></script>
<script src="./demo.js"></script>
Expand Down
5 changes: 5 additions & 0 deletions demos/test-cdn/public/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

function initMoralis() {
Moralis.Evm.connectors.register(WalletConnectConnector);
Moralis.Evm.connectors.register(MagiclinkConnector);

Moralis.start({
serverUrl: MORALIS_SERVER_URL,
Expand Down Expand Up @@ -33,6 +34,10 @@ function initDemo() {
return Moralis.Evm.connect('wallet-connect', {});
});

appendButton('Evm.connect / Magiclink', () => {
return Moralis.Evm.connect('magic-link', { email: '[email protected]', apiKey: MAGIC_LINK_KEY, chainId: 3 });
});

appendButton('Evm.transferNative', () => {
return Moralis.Evm.transferNative({
to: '0x295522b61890c3672D12eFbFf4358a6411CE996F',
Expand Down
41 changes: 22 additions & 19 deletions demos/test-cdn/public/demo.umd.html
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>🔵 UMD Demo - Moralis Test CDN</title>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>🔵 UMD Demo - Moralis Test CDN</title>
<script src="../../../packages/moralis/dist/index.umd.js"></script>
<script src="../../../packages/evmConnectors/EvmWalletconnectConnector/dist/index.umd.js"></script>
<script src="../../../packages/evmConnectors/EvmMagiclinkConnector/dist/index.umd.js"></script>
<script src="./env.js"></script>
<script src="./demo.js"></script>

<script src="../../../packages/moralis/dist/index.umd.js"></script>
<script src="../../../packages/evmConnectors/EvmWalletconnectConnector/dist/index.umd.js"></script>
<script src="./env.js"></script>
<script src="./demo.js"></script>
<style>
body {
font: 14px/1.4em Arial, Verdana, Serif;
}
button {
margin: 5px;
}
</style>
</head>

<style>
body {font: 14px/1.4em Arial, Verdana, Serif;}
button {margin: 5px;}
</style>
</head>

<body>
<h1>Demo UMD - Moralis CDN</h1>

<div id="demo"></div>
</body>
<body>
<h1>Demo UMD - Moralis CDN</h1>

<div id="demo"></div>
</body>
</html>
1 change: 1 addition & 0 deletions demos/test-cdn/public/env.example.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

window.MORALIS_SERVER_URL = 'replace_me';
window.MORALIS_APP_ID = 'replace_me';
window.MAGIC_LINK_KEY = 'replace_me';
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.3.0",
"@rollup/plugin-replace": "^4.0.0",
"@typescript-eslint/eslint-plugin": "^5.30.0",
"@typescript-eslint/parser": "^5.30.0",
"eslint": "^8.19.0",
"eslint-plugin-jest": "^26.5.3",
"@types/estree": "^0.0.51",
"@types/jest": "^27.4.0",
"@typescript-eslint/eslint-plugin": "^5.30.0",
"@typescript-eslint/parser": "^5.30.0",
"add": "^2.0.6",
"cross-env": "^7.0.3",
"eslint": "^8.19.0",
"eslint-plugin-jest": "^26.5.3",
"jest": "28",
"msw": "^0.43.0",
"nx": "14.1.7",
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/sharedTypes/evmConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type SolBaseConnectOptions = Record<string, unknown>;
export type EvmConnect = {
(connector: 'metamask', options?: EvmMetamaskConnectorConnectOptions): Promise<EvmConnectionData>;
(connector: 'walletconnect', options?: EvmWalletConnectConnectorOptions): Promise<EvmConnectionData>;
(connector: 'magiclink', options?: EvmMagicLinkConnectorOptions): Promise<EvmConnectionData>;
(connector: string, options?: EvmBaseConnectOptions): Promise<EvmConnectionData>;
};

Expand Down Expand Up @@ -41,6 +42,17 @@ export interface EvmWalletConnectConnectorOptions extends EvmBaseConnectOptions
newSession?: boolean;
}

export interface EvmMagicLinkConnectorOptions extends EvmBaseConnectOptions {
// Prefered chainId, if supported by the connector
chainId?: InputChainId;
// the publishable api-key that you can get in your Magic dashboard
apiKey: string;
// Email to sign in with
email: string;
// Weather to reuse the same session (if available), or to force a new session
newSession?: boolean;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AnyConnector = any;

Expand Down
Empty file.
8 changes: 8 additions & 0 deletions packages/evmConnectors/EvmMagiclinkConnector/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CHANGELOG.md

# Output folders
lib/**/*
dist
coverage/
lib.esm
node_modules
3 changes: 3 additions & 0 deletions packages/evmConnectors/EvmMagiclinkConnector/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
...require('../../../.prettierrc'),
};
1 change: 1 addition & 0 deletions packages/evmConnectors/EvmMagiclinkConnector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# @moralisweb3/evm-magic-link-connector
28 changes: 28 additions & 0 deletions packages/evmConnectors/EvmMagiclinkConnector/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@moralisweb3/evm-magic-link-connector",
"author": "Moralis",
"version": "2.0.0-alpha.1",
"license": "MIT",
"private": false,
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"sideEffects": false,
"scripts": {
"format": "prettier . '**/*.+(js|ts|json)' --write",
"format:check": "prettier . '**/*.+(js|ts|json)' --check",
"lint": "eslint . --ext .js,.ts,.tsx,jsx",
"clean": "rm -rf lib && rm -rf lib.esm && rm -rf tsconfig.tsbuildinfo",
"build": "rollup -c",
"dev": "rollup -c --watch"
},
"devDependencies": {
"eslint": "^8.7.0",
"prettier": "^2.5.1",
"typescript": "^4.5.5"
},
"dependencies": {
"@moralisweb3/core": "^2.0.0-alpha.1",
"@moralisweb3/evm-connector-utils": "^2.0.0-alpha.1",
"magic-sdk": "7.0.0"
}
}
9 changes: 9 additions & 0 deletions packages/evmConnectors/EvmMagiclinkConnector/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import packageJson from './package.json';
import { commonJs, esm, umd } from '../../../rollup.config';

const umdExternalMap = {
'@moralisweb3/core': 'Moralis.CoreLib',
'@moralisweb3/evm-connector-utils': 'Moralis.EvmConnectorUtilsLib',
};

export default [commonJs(packageJson), esm(packageJson), umd('MagiclinkConnector', packageJson, umdExternalMap)];
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import core, {
EvmAddress,
EvmChain,
EvmConnection,
EvmMagicLinkConnectorOptions,
EvmProvider,
MoralisCore,
MoralisNetworkConnectorError,
NetworkConnectorErrorCode,
} from '@moralisweb3/core';
import { EvmAbstractConnector } from '@moralisweb3/evm-connector-utils';
import { EthNetworkConfiguration, Magic } from 'magic-sdk';

const DEFAULT_OPTIONS = {
chainId: '0x1',
};

export interface EvmMagiclinkConnectorConfig {
core: MoralisCore;
}

/**
* Connector for WalletConnect v1
*/
export class EvmMagiclinkConnector extends EvmAbstractConnector<EvmProvider, EvmMagicLinkConnectorOptions> {
constructor(config: EvmMagiclinkConnectorConfig) {
super({
name: 'magic-link',
core: config.core,
});
}

protected async createProvider(options: EvmMagicLinkConnectorOptions): Promise<EvmProvider> {
const magic = new Magic(options.apiKey, {
network: EvmChain.create(options.chainId!).name as EthNetworkConfiguration,
});

// Log out of any previous sessions
if (options.newSession) {
await this.cleanup(magic);
}

await magic.auth.loginWithMagicLink({
email: options.email,
});

const provider = magic.rpcProvider;

if (!provider) {
throw new MoralisNetworkConnectorError({
code: NetworkConnectorErrorCode.NO_PROVIDER,
message: 'Failed to create provider',
});
}

return provider;
}

protected async createConnection(_options: EvmMagicLinkConnectorOptions): Promise<EvmConnection> {
const options = { ...DEFAULT_OPTIONS, ..._options };

this.logger.verbose('Connecting', { providedOptions: _options, options });

const provider = await this.getProvider(options);

const [accounts, chainId] = await Promise.all([
provider.request({ method: 'eth_accounts' }) as Promise<string[]>,
provider.request({ method: 'eth_chainId' }) as Promise<string>,
]);

return {
provider: provider,
chain: new EvmChain(chainId),
account: accounts[0] ? new EvmAddress(accounts[0]) : null,
};
}

async cleanup(magic: Magic): Promise<void> {
if (magic.user) {
try {
await magic.user.logout();
} catch (error) {
this.logger.verbose('Failed to logout', { error });
}
}
}
}

const evmMagicLinkConnector = new EvmMagiclinkConnector({ core });
export default evmMagicLinkConnector;
3 changes: 3 additions & 0 deletions packages/evmConnectors/EvmMagiclinkConnector/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import EvmMagiclinkConnector from './EvmMagicLinkConnector';

export default EvmMagiclinkConnector;
9 changes: 9 additions & 0 deletions packages/evmConnectors/EvmMagiclinkConnector/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../../tsconfig.package.json",
"compilerOptions": {
"outDir": "./lib/",
"declarationDir": "./lib/",
"rootDir": "./src"
},
"include": ["src/**/*", "types/**/*"]
}
8 changes: 5 additions & 3 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import globals from 'rollup-plugin-node-globals';
import babel from '@rollup/plugin-babel';
import { uglify } from 'rollup-plugin-uglify';

const isDev = (process.env.dev === 'true');
const isDev = process.env.dev === 'true';

function uglifyIfProd() {
return isDev ? undefined : uglify();
Expand Down Expand Up @@ -38,7 +38,9 @@ export function commonJs(packageJson) {
}

export function esm(packageJson, internal) {
const external = Object.keys(packageJson.dependencies).filter(d => d.startsWith('@moralisweb3/') && (!internal || !internal.includes(d)));
const external = Object.keys(packageJson.dependencies).filter(
(d) => d.startsWith('@moralisweb3/') && (!internal || !internal.includes(d)),
);

return {
input: 'src/index.ts',
Expand Down Expand Up @@ -73,7 +75,7 @@ export function esm(packageJson, internal) {
}

export function umd(outputName, packageJson, externanMap) {
const external = Object.keys(packageJson.dependencies).filter(d => externanMap[d]);
const external = Object.keys(packageJson.dependencies).filter((d) => externanMap[d]);
const outputGlobals = external.reduce((v, d) => {
v[d] = externanMap[d];
return v;
Expand Down
1 change: 1 addition & 0 deletions run_scripts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ yarn --cwd packages/evmConnectors/EvmConnectorUtils $1
yarn --cwd packages/evmConnectors/EvmMetamaskConnector $1
yarn --cwd packages/evmConnectors/EvmWalletconnectConnector $1
yarn --cwd packages/evmConnectors/EvmMetamaskConnector $1
yarn --cwd packages/evmConnectors/EvmMagiclinkConnector $1

yarn --cwd packages/evm $1
yarn --cwd packages/evmApi $1
Expand Down
Loading

0 comments on commit 108a8db

Please sign in to comment.