(
33 | reducers,
34 | {},
35 | applyMiddleware(
36 | createReduxSdkMiddleware(sdk),
37 | ),
38 | );
39 | ```
40 |
--------------------------------------------------------------------------------
/docs/sdk/configuration.md:
--------------------------------------------------------------------------------
1 | # Configuration
2 |
3 | ## Setup SDK Environment
4 |
5 | ### Predefined Environments
6 | ```typescript
7 | import { SdkEnvironmentNames, getSdkEnvironment } from '@archanova/sdk';
8 |
9 | const sdkEnv = getSdkEnvironment(SdkEnvironmentNames.Main);
10 | ```
11 |
12 | ### Extending Environment
13 |
14 | ```typescript
15 | import { SdkEnvironmentNames, getSdkEnvironment } from '@archanova/sdk';
16 | import Ws from 'ws';
17 |
18 | const sdkEnv = getSdkEnvironment(SdkEnvironmentNames.Rinkeby)
19 | .setConfig('storageAdapter', sessionStorage)
20 | .setConfig('apiWebSocketConstructor', Ws) // for nodejs env
21 | .extendConfig('ensOptions', {
22 | supportedRootNames: ['smartsafe.test'],
23 | });
24 | ```
25 |
26 | ## Create SDK Instance
27 |
28 | ```typescript
29 | const sdk = createSdk(sdkEnv);
30 | ```
31 |
32 | ## Initialize SDK Instance
33 | ```typescript
34 | await sdk.initialize();
35 | ```
36 |
--------------------------------------------------------------------------------
/packages/sdk/src/redux/reducers.ts:
--------------------------------------------------------------------------------
1 | import { combineReducers, Reducer } from 'redux';
2 | import { ReduxSdkActionTypes } from './actions';
3 | import { createReducer } from './helpers';
4 |
5 | export const reduxSdkReducer = combineReducers({
6 | initialized: createReducer(ReduxSdkActionTypes.SetInitialized),
7 | connected: createReducer(ReduxSdkActionTypes.SetConnected),
8 | authenticated: createReducer(ReduxSdkActionTypes.SetAuthenticated),
9 | account: createReducer(ReduxSdkActionTypes.SetAccount),
10 | accountDevice: createReducer(ReduxSdkActionTypes.SetAccountDevice),
11 | accountFriendRecovery: createReducer(ReduxSdkActionTypes.SetAccountFriendRecovery),
12 | device: createReducer(ReduxSdkActionTypes.SetDevice),
13 | ens: createReducer(ReduxSdkActionTypes.SetEns),
14 | eth: createReducer(ReduxSdkActionTypes.SetEth),
15 | incomingAction: createReducer(ReduxSdkActionTypes.SetIncomingAction),
16 | }) as any as Reducer;
17 |
--------------------------------------------------------------------------------
/packages/cli/src/context/ContextComponent.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Subscription } from 'rxjs';
3 | import { IContextProps } from './interfaces';
4 | import { context } from './context';
5 |
6 | export abstract class ContextComponent extends React.Component
{
7 | public static contextType = context;
8 |
9 | public context: IContextProps;
10 | private subscriptions: Subscription[] = [];
11 |
12 | public abstract render(): any;
13 |
14 | public componentWillUnmount(): void {
15 | for (const subscription of this.subscriptions) {
16 | subscription.unsubscribe();
17 | }
18 | }
19 |
20 | protected wrapAsync(fun: () => Promise): void {
21 | fun().catch(err => console.error(err));
22 | }
23 |
24 | protected addSubscriptions(...subscriptions: Subscription[]): void {
25 | this.subscriptions = [
26 | ...this.subscriptions,
27 | ...subscriptions,
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/sdk-playground/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Archanova SDK Playground
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/packages/cli/README.md:
--------------------------------------------------------------------------------
1 | # Archanova CLI
2 |
3 | [![NPM version][npm-image]][npm-url]
4 |
5 | ## Installation
6 |
7 | ```bash
8 | $ npm i @archanova/cli -g
9 | ```
10 |
11 | ## Usage
12 |
13 | ```bash
14 | $ archanova-cli [action] [options] [workingPath]
15 | ```
16 |
17 | **Actions:**
18 | * `auth` - authentication
19 | * `init` - initialize application
20 | * `develop` - develop application
21 | * `deploy` - deploy application
22 |
23 | **Options:**
24 | * `--help, -h` - print help
25 | * `--global, -g` - use global storage
26 | * `--env, -e ` - environment [main,ropsten,rinkeby,kovan,sokol,xdai,local] (default: main)
27 | * `--local-env-host ` - local environment host
28 | * `--local-env-port ` - local environment port
29 | * `--private-key ` - device private key
30 |
31 |
32 | ## License
33 |
34 | The MIT License
35 |
36 | [npm-image]: https://badge.fury.io/js/%40archanova%2Fcli.svg
37 | [npm-url]: https://npmjs.org/package/@archanova/cli
38 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/shared/ContextComponent.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { IContextProps } from './interfaces';
3 | import { context } from './context';
4 |
5 | export abstract class ContextComponent extends React.Component
{
6 | public static contextType = context;
7 |
8 | public context: IContextProps;
9 |
10 | public get config(): IContextProps['config'] {
11 | return this.context ?
12 | this.context.config
13 | : null;
14 | }
15 |
16 | public get logger(): IContextProps['logger'] {
17 | return this.context ?
18 | this.context.logger
19 | : null;
20 | }
21 |
22 | public get sdk(): IContextProps['sdk'] {
23 | return this.context ?
24 | this.context.sdk
25 | : null;
26 | }
27 |
28 | public get help(): IContextProps['help'] {
29 | return this.context ?
30 | this.context.help
31 | : null;
32 | }
33 |
34 | public abstract render(): any;
35 | }
36 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/Preloader.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Subscription } from 'rxjs';
3 | import { ContextComponent } from '../shared';
4 | import styles from './Preloader.module.scss';
5 |
6 | interface IState {
7 | show: boolean;
8 | }
9 |
10 | export default class Preloader extends ContextComponent<{}, IState> {
11 | public state = {
12 | show: false,
13 | };
14 |
15 | private subscription: Subscription = null;
16 |
17 | public componentWillMount(): void {
18 | this.subscription = this
19 | .logger
20 | .pending$
21 | .subscribe(show => this.setState({ show }));
22 | }
23 |
24 | public componentWillUnmount(): void {
25 | this.subscription.unsubscribe();
26 | }
27 |
28 | public render() {
29 | const { show } = this.state;
30 |
31 | return !show ? null : (
32 |
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/action/AcceptIncomingAction.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen } from '../../components';
3 |
4 | const code = () => `
5 | sdk.acceptIncomingAction();
6 |
7 | console.log('action accepted');
8 | `;
9 |
10 | export class AcceptIncomingAction extends Screen {
11 | public componentWillMount(): void {
12 | this.run = this.run.bind(this);
13 | }
14 |
15 | public renderContent(): any {
16 | const { enabled } = this.props;
17 | return (
18 |
19 |
25 |
26 | );
27 | }
28 |
29 | private run(): void {
30 | this
31 | .logger
32 | .wrapSync('sdk.acceptIncomingAction', async (console) => {
33 | this.sdk.acceptIncomingAction();
34 |
35 | console.log('action accepted');
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/action/DismissIncomingAction.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen } from '../../components';
3 |
4 | const code = () => `
5 | sdk.dismissIncomingAction();
6 |
7 | console.log('action dismissed');
8 | `;
9 |
10 | export class DismissIncomingAction extends Screen {
11 | public componentWillMount(): void {
12 | this.run = this.run.bind(this);
13 | }
14 |
15 | public renderContent(): any {
16 | const { enabled } = this.props;
17 | return (
18 |
19 |
25 |
26 | );
27 | }
28 |
29 | private run(): void {
30 | this
31 | .logger
32 | .wrapSync('sdk.dismissIncomingAction', async (console) => {
33 | this.sdk.dismissIncomingAction();
34 | console.log('action dismissed');
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/Console.module.scss:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | position: fixed;
3 | bottom: 0;
4 | left: 250px;
5 | right: 0;
6 | max-height: 250px;
7 | min-height: 70px;
8 | display: flex;
9 | flex-direction: column;
10 | background: white;
11 | padding: 10px 0;
12 | box-shadow: 10px 0 10px rgba(0, 0, 0, 0.2);
13 | }
14 |
15 | .tabs {
16 | position: absolute;
17 | top: 0;
18 | left: 0;
19 | height: 30px;
20 | display: flex;
21 | flex-direction: row;
22 |
23 | button {
24 | cursor: pointer;
25 | border-width: 0;
26 | padding: 0 15px;
27 | background-color: white;
28 |
29 | &.active {
30 | font-weight: bold;
31 | }
32 | }
33 | }
34 |
35 | .content {
36 | display: flex;
37 | flex-direction: column;
38 | flex: 1;
39 | overflow-y: auto;
40 | padding-top: 30px;
41 |
42 | > div {
43 | padding: 10px;
44 | border-bottom: 1px solid #E8E8E8;
45 |
46 | &:last-child {
47 | border-bottom: 0;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/Help.module.scss:
--------------------------------------------------------------------------------
1 | .content {
2 | position: fixed;
3 | background-color: white;
4 | padding: 15px;
5 | z-index: 10;
6 |
7 | &.statusBar {
8 | left: 250px;
9 | top: 50px;
10 | right: 0;
11 | box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2);
12 | }
13 |
14 | &.menu {
15 | left: 250px;
16 | top: 0;
17 | bottom: 0;
18 | min-width: 250px;
19 | box-shadow: 10px 0 10px rgba(0, 0, 0, 0.2);
20 | }
21 |
22 | h1 {
23 | font-size: 14px;
24 | color: #6024FC;
25 | }
26 |
27 | h1, h2, h3, h4 {
28 | padding-bottom: 10px;
29 | border-bottom: 1px solid #eeeeee;
30 | }
31 |
32 | ul, li {
33 | margin: 0;
34 | padding: 0;
35 | }
36 |
37 | li {
38 | padding: 5px;
39 | margin-left: 15px;
40 | list-style: disc;
41 | }
42 |
43 | code {
44 | background-color: rgba(27,31,35,.05);
45 | border-radius: 3px;
46 | font-size: 85%;
47 | margin: 0;
48 | padding: .2em .4em;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/account/DisconnectAccount.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen } from '../../components';
3 |
4 | const code = () => `
5 | sdk
6 | .disconnectAccount()
7 | .then(() => console.log('disconnected'))
8 | .catch(console.error);
9 | `;
10 |
11 | export class DisconnectAccount extends Screen {
12 |
13 | public componentWillMount(): void {
14 | this.run = this.run.bind(this);
15 | }
16 |
17 | public renderContent(): any {
18 | const { enabled } = this.props;
19 | return (
20 |
21 |
27 |
28 | );
29 | }
30 |
31 | private run(): void {
32 | this
33 | .logger
34 | .wrapSync('sdk.disconnectAccount', async (console) => {
35 | await this.sdk.disconnectAccount();
36 | console.log('disconnected');
37 | });
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/MenuOption.module.scss:
--------------------------------------------------------------------------------
1 | .checkbox {
2 | $color: #cf9eff;
3 | height: 17px;
4 | display: block;
5 | position: relative;
6 | padding-top: 4px;
7 | padding-left: 27px;
8 | cursor: pointer;
9 | font-size: 11px;
10 |
11 | input {
12 | position: absolute;
13 | top: 0;
14 | left: 0;
15 | opacity: 0;
16 | }
17 |
18 | .overlay {
19 | position: absolute;
20 | top: 0;
21 | left: 0;
22 | height: 15px;
23 | width: 15px;
24 | background-color: transparent;
25 | border-radius: 3px;
26 | border: 2px solid $color;
27 | transform: rotate(-90deg);
28 | transition: all 0.3s;
29 | }
30 |
31 | .icon {
32 | color: white;
33 | display: none;
34 | }
35 |
36 | input:checked ~ .overlay {
37 | background-color: $color;
38 | border-radius: 3px;
39 | transform: rotate(0deg);
40 | opacity: 1;
41 | border: 2px solid $color;
42 | }
43 |
44 | input:checked ~ .overlay .icon {
45 | display: block;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountFriendRecovery/SubmitAccountFriendRecovery.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen } from '../../components';
3 |
4 | const code = () => `
5 | sdk
6 | .submitAccountFriendRecovery()
7 | .then(hash => console.log('hash', hash))
8 | .catch(console.error);
9 | `;
10 |
11 | export class SubmitAccountFriendRecovery extends Screen {
12 | public componentWillMount(): void {
13 | this.run = this.run.bind(this);
14 | }
15 |
16 | public renderContent(): any {
17 | const { enabled } = this.props;
18 | return (
19 |
20 |
26 |
27 | );
28 | }
29 |
30 | private run(): void {
31 | this
32 | .logger
33 | .wrapSync('sdk.submitAccountFriendRecovery', async (console) => {
34 | console.log('hash', await this.sdk.submitAccountFriendRecovery());
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/Example.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Button } from './Button';
3 | import { Code } from './Code';
4 | import styles from './Example.module.scss';
5 |
6 | interface IProps {
7 | title?: string;
8 | code: string;
9 | enabled: boolean;
10 | run: () => any;
11 | }
12 |
13 | export class Example extends React.Component {
14 |
15 | public render(): any {
16 | const { title, code, run, enabled, children } = this.props;
17 | return (
18 |
19 | {!title ? null : (
20 |
{title}
21 | )}
22 | {children ? (
23 |
24 | PARAMETERS
25 |
26 | {children}
27 |
28 |
29 | ) : null}
30 |
CODE
31 |
32 |
33 | {code}
34 |
35 |
36 |
37 |
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/Url.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import QrCode from 'qrcode.react';
3 | import { Button } from './Button';
4 | import styles from './Url.module.scss';
5 |
6 | interface IProps {
7 | mobile?: string;
8 | redirect?: string;
9 | }
10 |
11 | export class Url extends React.Component {
12 | public componentWillMount(): void {
13 | this.clickHandler = this.clickHandler.bind(this);
14 | }
15 |
16 | public render(): any {
17 | const { mobile, redirect } = this.props;
18 | return (
19 |
20 |
21 |
SCAN USING SMARTSAFE APP
22 |
23 |
24 |
25 |
26 | {!redirect ? null : (
27 |
28 |
29 |
30 | )}
31 |
32 | );
33 | }
34 |
35 | private clickHandler(): void {
36 | const { redirect } = this.props;
37 | document.location = redirect as any;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/InputCheckBox.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './InputCheckBox.module.scss';
3 |
4 | interface IProps {
5 | label: string;
6 | checked: boolean;
7 | onChange?: (checked: boolean) => any;
8 | }
9 |
10 | export class InputCheckBox extends React.Component {
11 |
12 | componentWillMount(): void {
13 | this.onChangeHandler = this.onChangeHandler.bind(this);
14 | }
15 |
16 | public render(): any {
17 | const { label, checked } = this.props;
18 |
19 | return (
20 |
21 |
29 |
30 | );
31 | }
32 |
33 | private onChangeHandler(event: React.SyntheticEvent): void {
34 | const { onChange } = this.props;
35 |
36 | if (onChange) {
37 | const { checked } = event.currentTarget;
38 | onChange(checked);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountFriendRecovery/CancelAccountFriendRecovery.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen } from '../../components';
3 |
4 | const code = () => `
5 | sdk
6 | .cancelAccountFriendRecovery()
7 | .then(() => console.log('account friend recovery canceled'))
8 | .catch(console.error);
9 | `;
10 |
11 | export class CancelAccountFriendRecovery extends Screen {
12 | public componentWillMount(): void {
13 | this.run = this.run.bind(this);
14 | }
15 |
16 | public renderContent(): any {
17 | const { enabled } = this.props;
18 | return (
19 |
20 |
26 |
27 | );
28 | }
29 |
30 | private run(): void {
31 | this
32 | .logger
33 | .wrapSync('sdk.cancelAccountFriendRecovery', async (console) => {
34 | await this.sdk.cancelAccountFriendRecovery();
35 | console.log('account friend recovery canceled');
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/InputGasPriceStrategy.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { sdkConstants } from '@archanova/sdk';
3 | import { InputSelect } from './InputSelect';
4 |
5 | interface IProps {
6 | selected: any;
7 | onChange?: (value: any) => any;
8 | }
9 |
10 | export class InputGasPriceStrategy extends React.Component {
11 | public static selectedToText(selected: any): string {
12 | let result: string = null;
13 |
14 | if (selected === sdkConstants.GasPriceStrategies.Fast) {
15 | result = 'sdkConstants.GasPriceStrategies.Fast';
16 | }
17 |
18 | return result;
19 | }
20 |
21 | private static values: string[] = [
22 | sdkConstants.GasPriceStrategies.Avg,
23 | sdkConstants.GasPriceStrategies.Fast,
24 | ];
25 |
26 | public render(): any {
27 | const { selected, onChange } = this.props;
28 |
29 | return (
30 |
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountFriendRecovery/GetConnectedAccountFriendRecoveryExtension.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen } from '../../components';
3 |
4 | const code = () => `
5 | sdk
6 | .getConnectedAccountFriendRecoveryExtension()
7 | .then(extension => console.log('extension', extension))
8 | .catch(console.error);
9 | `;
10 |
11 | export class GetConnectedAccountFriendRecoveryExtension extends Screen {
12 | public componentWillMount(): void {
13 | this.run = this.run.bind(this);
14 | }
15 |
16 | public renderContent(): any {
17 | const { enabled } = this.props;
18 | return (
19 |
20 |
26 |
27 | );
28 | }
29 |
30 | private run(): void {
31 | this
32 | .logger
33 | .wrapSync('sdk.getConnectedAccountFriendRecoveryExtension', async (console) => {
34 | console.log('extension', await this.sdk.getConnectedAccountFriendRecoveryExtension());
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/cli/src/components/QrCode.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Box, BoxProps } from 'ink';
3 | import { generate } from 'qrcode-terminal';
4 |
5 | export interface IProps extends BoxProps {
6 | url: string;
7 | small?: boolean;
8 | }
9 |
10 | export interface IState {
11 | data: string;
12 | }
13 |
14 | export class QrCode extends React.Component {
15 | public static defaultProps: Partial = {
16 | small: false,
17 | };
18 |
19 | public state = {
20 | data: '',
21 | };
22 |
23 | public componentWillReceiveProps(nextProps: Readonly): void {
24 | this.generateFromProps(nextProps);
25 | }
26 |
27 | public componentWillMount(): void {
28 | this.generateFromProps(this.props);
29 | }
30 |
31 | public render(): any {
32 | const { data } = this.state;
33 | const { url, small, ...props } = this.props;
34 |
35 | return (
36 |
37 | {data}
38 |
39 | );
40 | }
41 |
42 | private generateFromProps({ url, small }: IProps): void {
43 | generate(url, { small }, (data) => {
44 | this.setState({
45 | data,
46 | });
47 | });
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/Code.tsx:
--------------------------------------------------------------------------------
1 | import 'highlight.js/styles/a11y-light.css';
2 | import 'highlight.js/lib/languages/javascript';
3 | import 'highlight.js/lib/languages/json';
4 |
5 | import React from 'react';
6 | import Highlight from 'react-highlight';
7 | import styles from './Code.module.scss';
8 |
9 | interface IProps {
10 | language: 'javascript' | 'json';
11 | children: string;
12 | }
13 |
14 | export class Code extends React.Component {
15 | public render(): any {
16 | const { language, children } = this.props;
17 |
18 | let empty = false;
19 | const code = children
20 | .trim()
21 | .split('\n')
22 | .filter((line) => {
23 | let result = true;
24 | if (!line.trim()) {
25 | if (empty) {
26 | result = false;
27 | } else {
28 | empty = true;
29 | }
30 | } else {
31 | empty = false;
32 | }
33 | return result;
34 | })
35 | .join('\n');
36 |
37 | return (
38 |
39 |
40 | {code}
41 |
42 |
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/packages/cli/template/src/handlers.js:
--------------------------------------------------------------------------------
1 | /**
2 | * GET /
3 | * @returns {IGetResponse}
4 | */
5 | function get() {
6 | return {
7 | name: '${app.name}',
8 | alias: '${app.alias}',
9 | version: '0.0.1',
10 | };
11 | }
12 |
13 | /**
14 | * POST /
15 | * @param body IPostBody
16 | * @returns {Promise}
17 | */
18 | async function post(body) {
19 | const {
20 | player,
21 | nextData,
22 | nextTime,
23 | previousData,
24 | previousTime,
25 | now,
26 | } = body;
27 |
28 | let whoseTurn = null;
29 | let winner = null;
30 |
31 | // initial move
32 | if (!player) {
33 | whoseTurn = 'Opponent';
34 | } else {
35 |
36 | switch (player) {
37 | case 'Creator':
38 | if (nextData === '0x01') {
39 | winner = 'Creator';
40 | } else {
41 | whoseTurn = 'Opponent';
42 | }
43 | break;
44 |
45 | case 'Opponent':
46 | if (nextData === '0x01') {
47 | winner = 'Opponent';
48 | } else {
49 | whoseTurn = 'Creator';
50 | }
51 | break;
52 | }
53 | }
54 |
55 | return {
56 | whoseTurn,
57 | winner,
58 | };
59 | }
60 |
61 | module.exports = {
62 | get,
63 | post,
64 | };
65 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/MenuOption.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './MenuOption.module.scss';
3 |
4 | interface IProps {
5 | checked: boolean;
6 | onToggle: () => any;
7 | children: string;
8 | }
9 |
10 | export class MenuOption extends React.Component {
11 | public render() {
12 | const { checked, onToggle, children } = this.props;
13 | return (
14 |
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/sdk/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@archanova/sdk",
3 | "version": "1.1.2",
4 | "main": "./build/index.js",
5 | "types": "./build/index.d.ts",
6 | "license": "MIT",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/netgum/archanova.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/netgum/archanova/issues"
13 | },
14 | "description": "Archanova SDK",
15 | "scripts": {
16 | "clean": "rimraf ./build",
17 | "compile": "tsc --project ./tsconfig.build.json --rootDir ./src",
18 | "compile:watch": "npm run compile -- --watch --preserveWatchOutput",
19 | "prebuild": "npm run clean",
20 | "build": "npm run compile"
21 | },
22 | "dependencies": {
23 | "@archanova/contracts": "^1.0.0",
24 | "@babel/runtime": "^7.4.4",
25 | "@netgum/types": "^0.1.8",
26 | "@netgum/utils": "^0.1.3",
27 | "@types/node": "^12.0.0",
28 | "@types/webpack-env": "^1.13.9",
29 | "bn.js": "^4.11.8",
30 | "cross-fetch": "^3.0.2",
31 | "deep-equal-extended": "^0.0.2",
32 | "ethjs": "^0.4.0",
33 | "ethjs-abi": "^0.2.1",
34 | "redux": "^4.0.1",
35 | "rxjs": "6.4.0",
36 | "rxjs-addons": "^0.0.4"
37 | },
38 | "devDependencies": {
39 | "rimraf": "^2.6.3"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/docs/sdk/state.md:
--------------------------------------------------------------------------------
1 | # State
2 |
3 | Sdk `state` is available in `sdk.state`, it's a combination of `getters` and `rxjs` `Subjects`.
4 |
5 | ```typescript
6 | import { Subject } from 'rxjs';
7 | import { sdkModules, sdkInterfaces } from '@archanova/sdk';
8 |
9 | interface IState {
10 | initialized$: Subject;
11 | connected$: Subject;
12 | authenticated$: Subject;
13 | account$: Subject;
14 | accountDevice$: Subject;
15 | accountFriendRecovery$: Subject;
16 | device$: Subject;
17 | ens$: Subject;
18 | eth$: Subject;
19 | session$: Subject;
20 | incomingAction$: Subject;
21 |
22 | initialized: boolean;
23 | connected: boolean;
24 | authenticated: boolean;
25 | account: sdkInterfaces.IAccount;
26 | accountAddress: string;
27 | accountDevice: sdkInterfaces.IAccountDevice;
28 | accountFriendRecovery: sdkInterfaces.IAccountFriendRecovery;
29 | device: sdkInterfaces.IDevice;
30 | deviceAddress: string;
31 | ens: sdkModules.State.IEns;
32 | eth: sdkModules.State.IEth;
33 | session: sdkModules.State.ISession;
34 | sessionToken: string;
35 | incomingAction: sdkModules.Action.IAction;
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/InputSelect.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './InputSelect.module.scss';
3 |
4 | interface IProps {
5 | label: string;
6 | selected: string;
7 | values: string[];
8 | onChange?: (value: any) => any;
9 | }
10 |
11 | export class InputSelect extends React.Component {
12 | componentWillMount(): void {
13 | this.onChangeHandler = this.onChangeHandler.bind(this);
14 | }
15 |
16 | public render(): any {
17 | const { label, values, selected } = this.props;
18 |
19 | return (
20 |
21 |
{label}
22 |
35 |
36 | );
37 | }
38 |
39 | private onChangeHandler(event: React.SyntheticEvent): void {
40 | const { onChange, values } = this.props;
41 | if (onChange) {
42 | const { selectedIndex } = event.currentTarget;
43 | if (values[selectedIndex]) {
44 | onChange(values[selectedIndex]);
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/configure.ts:
--------------------------------------------------------------------------------
1 | import {
2 | createSdk,
3 | Sdk,
4 | reduxSdkReducer,
5 | createReduxSdkMiddleware,
6 | } from '@archanova/sdk';
7 | import { applyMiddleware, createStore, Store, combineReducers } from 'redux';
8 | import { composeWithDevTools } from 'redux-devtools-extension';
9 | import { filter } from 'rxjs/operators';
10 | import { ILogger, buildSdkEnv } from './shared';
11 | import { config } from './config';
12 |
13 | export function configureSdk(logger: ILogger): Sdk {
14 | const sdk = createSdk(
15 | buildSdkEnv(config.sdkEnv),
16 | );
17 |
18 | sdk
19 | .event$
20 | .pipe(filter(value => !!value))
21 | .subscribe(event => console.log('sdk.event$', event));
22 |
23 | sdk
24 | .error$
25 | .pipe(filter(value => !!value))
26 | .subscribe(err => console.error('sdk.error$', err));
27 |
28 | if (config.autoInitializeSdk) {
29 | logger
30 | .wrapSync('sdk.initialize', async (console) => {
31 | await sdk.initialize();
32 | console.log('initialized');
33 | });
34 | }
35 |
36 | return sdk;
37 | }
38 |
39 | export function configureStore(sdk: Sdk): Store {
40 | return createStore(
41 | combineReducers({
42 | sdk: reduxSdkReducer,
43 | }),
44 | {},
45 | composeWithDevTools(applyMiddleware(
46 | createReduxSdkMiddleware(sdk),
47 | )),
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "archanova",
3 | "version": "0.0.0",
4 | "private": true,
5 | "description": "Archanova monorepo",
6 | "license": "MIT",
7 | "main": "./index.js",
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/netgum/archanova.git"
11 | },
12 | "scripts": {
13 | "lint": "tslint --project ./tsconfig.json --exclude ./packages/**/*.d.ts ./packages/**/*.ts",
14 | "bootstrap": "lerna bootstrap -- --no-package-lock",
15 | "clean": "lerna clean --yes && lerna run clean --stream",
16 | "prebuild": "npm run bootstrap",
17 | "build": "lerna run --stream build --ignore \"@archanova/sdk-playground\"",
18 | "compile": "lerna run compile --stream",
19 | "precompile:watch": "npm run compile",
20 | "compile:watch": "lerna run compile:watch --parallel",
21 | "test": "npm run lint",
22 | "start:sdk:playground": "lerna run --stream --scope \"@archanova/sdk-playground\" start",
23 | "build:sdk:playground": "lerna run --stream --scope \"@archanova/sdk-playground\" build",
24 | "deploy:sdk:playground": "lerna run --stream --scope \"@archanova/sdk-playground\" deploy"
25 | },
26 | "dependencies": {
27 | "cross-env": "^5.2.0",
28 | "lerna": "^3.15.0",
29 | "tslint": "^5.16.0",
30 | "tslint-config-airbnb": "^5.11.1",
31 | "tsutils": "^3.10.0",
32 | "typescript": "^3.4.5"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/packages/cli/template/src/main.js:
--------------------------------------------------------------------------------
1 | const { createServer } = require('http');
2 | const express = require('express');
3 | const bodyParser = require('body-parser');
4 | const config = require('./config');
5 | const logger = require('./logger');
6 | const { get, post } = require('./handlers');
7 |
8 | const app = express();
9 | const server = createServer(app);
10 |
11 | app.get('/', (req, res, next) => {
12 | try {
13 | const data = get();
14 | res.send(data);
15 | } catch (err) {
16 | next(err);
17 | }
18 | });
19 | app.post('/', bodyParser.json({}), (req, res, next) => {
20 | try {
21 | post(req.body)
22 | .then((data) => {
23 | if (!data) {
24 | res.status(400);
25 | res.send({
26 | error: 'bad request',
27 | });
28 | } else {
29 | res.send(data);
30 | }
31 | })
32 | .catch(next);
33 | } catch (err) {
34 | next(err);
35 | }
36 | });
37 |
38 | app.use((err, req, res, next) => {
39 | logger.error('request error', err);
40 |
41 | res.status(500);
42 | res.send({
43 | error: 'internal server error',
44 | });
45 | });
46 |
47 | server.listen(config.server.port, (err) => {
48 | if (err) {
49 | logger.error('server error', err);
50 | } else {
51 | const { port } = server.address();
52 |
53 | logger.info('listening on port:', port);
54 | }
55 | });
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/packages/sdk/src/errors.ts:
--------------------------------------------------------------------------------
1 | import { SdkError } from './SdkError';
2 |
3 | export const ERR_SDK_NOT_INITIALIZED = SdkError.fromAny('sdk not initialized');
4 | export const ERR_SDK_ALREADY_INITIALIZED = SdkError.fromAny('sdk already initialized');
5 | export const ERR_ACCOUNT_DISCONNECTED = SdkError.fromAny('account disconnected');
6 | export const ERR_ACCOUNT_ALREADY_CONNECTED = SdkError.fromAny('account already connected');
7 | export const ERR_INVALID_ACCOUNT_STATE = SdkError.fromAny('invalid account state');
8 | export const ERR_INVALID_ACCOUNT_DEVICE_STATE = SdkError.fromAny('invalid account device state');
9 | export const ERR_INVALID_ACCOUNT_DEVICE_TYPE = SdkError.fromAny('invalid account device type');
10 | export const ERR_WRONG_NUMBER_OF_ARGUMENTS = SdkError.fromAny('wrong number of arguments');
11 | export const ERR_INVALID_GAME_CREATOR = SdkError.fromAny('invalid game creator');
12 | export const ERR_INVALID_GAME_STATE = SdkError.fromAny('invalid game state');
13 | export const ERR_EXTENSION_ALREADY_ADDED = SdkError.fromAny('extension already added');
14 | export const ERR_EXTENSION_NOT_ADDED = SdkError.fromAny('extension not added');
15 | export const ERR_ADDING_EXTENSION_IN_PROGRESS = SdkError.fromAny('adding extension in progress');
16 | export const ERR_NOT_ENOUGH_REAL_FUNDS = SdkError.fromAny('not enough real funds');
17 | export const ERR_NOT_ENOUGH_VIRTUAL_FUNDS = SdkError.fromAny('not enough virtual funds');
18 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/ApiError.ts:
--------------------------------------------------------------------------------
1 | export class ApiError extends Error {
2 | public static isApiError(err: any, type: ApiError.Types = null): boolean {
3 | let result = (
4 | typeof err === 'object' &&
5 | err &&
6 | err instanceof this
7 | );
8 |
9 | if (result && type) {
10 | result = err.type === type;
11 | }
12 |
13 | return result;
14 | }
15 |
16 | public error: string = null;
17 |
18 | public errors: { [key: string]: string } = {};
19 |
20 | constructor(
21 | public type: ApiError.Types,
22 | response: {
23 | error?: string;
24 | errors?: {
25 | type: string;
26 | path: string;
27 | }[];
28 | } = null,
29 | ) {
30 | super(type);
31 |
32 | if (response) {
33 | if (response.error) {
34 | this.error = response.error;
35 | } else if (response.errors) {
36 | this.errors = response.errors.reduce(
37 | (result, error) => {
38 | return {
39 | ...result,
40 | [error.path]: error.type,
41 | };
42 | },
43 | {},
44 | );
45 | }
46 | }
47 | }
48 | }
49 |
50 | export namespace ApiError {
51 | export enum Types {
52 | BadRequest = 'bad request',
53 | Unauthorized = 'unauthorized',
54 | Forbidden = 'forbidden',
55 | NotFound = 'not found',
56 | Failed = 'failed',
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountVirtualBalance/GetConnectedAccountVirtualPendingBalances.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen } from '../../components';
3 |
4 | const code = () => `
5 | sdk
6 | .getConnectedAccountVirtualPendingBalances()
7 | .then(accountVirtualPendingBalances => console.log('accountVirtualPendingBalances', accountVirtualPendingBalances))
8 | .catch(console.error);
9 | `;
10 |
11 | interface IState {
12 | page: string;
13 | pageParsed: number;
14 | }
15 |
16 | export class GetConnectedAccountVirtualPendingBalances extends Screen {
17 | public state = {
18 | page: '0',
19 | pageParsed: 0,
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 | }
25 |
26 | public renderContent(): any {
27 | const { enabled } = this.props;
28 | return (
29 |
30 |
36 |
37 | );
38 | }
39 |
40 | private run(): void {
41 | this
42 | .logger
43 | .wrapSync('sdk.getConnectedAccountVirtualPendingBalances', async (console) => {
44 | console.log('accountVirtualPendingBalances', await this.sdk.getConnectedAccountVirtualPendingBalances());
45 | });
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/shared/logger.ts:
--------------------------------------------------------------------------------
1 | import { BehaviorSubject } from 'rxjs';
2 | import { ILogger, ILoggerConsole, ILoggerEvent } from './interfaces';
3 |
4 | const pending$ = new BehaviorSubject(false);
5 | const stream$ = new BehaviorSubject(null);
6 | const wrappedConsole: Partial = {
7 | info(...args: any[]): void {
8 | console.log(...args);
9 | stream$.next({
10 | args,
11 | type: 'info',
12 | });
13 | },
14 | error(...args: any[]): void {
15 | console.error(...args);
16 | stream$.next({
17 | args,
18 | type: 'error',
19 | });
20 | },
21 | };
22 |
23 | const wrapSync: ILogger['wrapSync'] = (label, fun) => {
24 | pending$.next(true);
25 | console.info(`// ${label}`);
26 |
27 | const log: ILoggerConsole['log'] = (key, data) => {
28 | if (data || data === null) {
29 | wrappedConsole.info(key, data);
30 | } else {
31 | wrappedConsole.info(key);
32 | }
33 | return data;
34 | };
35 |
36 | const error: ILoggerConsole['error'] = (err) => {
37 | wrappedConsole.error(err);
38 | };
39 |
40 | const wrapper = async () => {
41 | return Promise.resolve(fun({
42 | log,
43 | error,
44 | }));
45 | };
46 |
47 | wrapper()
48 | .finally(() => pending$.next(false))
49 | .catch(error);
50 | };
51 |
52 | export const logger: ILogger = {
53 | stream$,
54 | pending$,
55 | wrapSync,
56 | };
57 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/url/CreateRequestSignSecureCodeUrl.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, Url } from '../../components';
3 |
4 | const code = () => `
5 | sdk
6 | .createRequestSignSecureCodeUrl()
7 | .then(mobileUrl => console.log('mobileUrl', mobileUrl))
8 | .catch(console.error);
9 | `;
10 |
11 | interface IState {
12 | mobileUrl: string;
13 | }
14 |
15 | export class CreateRequestSignSecureCodeUrl extends Screen {
16 | public state = {
17 | mobileUrl: '',
18 | };
19 |
20 | public componentWillMount(): void {
21 | this.run = this.run.bind(this);
22 | }
23 |
24 | public renderContent(): any {
25 | const { enabled } = this.props;
26 | const { mobileUrl } = this.state;
27 | return (
28 |
29 |
35 | {enabled && mobileUrl && (
36 |
37 | )}
38 |
39 | );
40 | }
41 |
42 | private run(): void {
43 | this
44 | .logger
45 | .wrapSync('sdk.createRequestSignSecureCodeUrl', async (console) => {
46 | const mobileUrl = await this.sdk.createRequestSignSecureCodeUrl();
47 |
48 | console.log('mobileUrl', mobileUrl);
49 |
50 | this.setState({
51 | mobileUrl,
52 | });
53 | });
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/sdk/src/constants.ts:
--------------------------------------------------------------------------------
1 | export enum AccountStates {
2 | Created = 'Created',
3 | Deployed = 'Deployed',
4 | }
5 |
6 | export enum AccountTypes {
7 | Developer = 'Developer',
8 | Admin = 'Admin',
9 | }
10 |
11 | export enum AccountDeviceStates {
12 | Created = 'Created',
13 | Deployed = 'Deployed',
14 | }
15 |
16 | export enum AccountDeviceTypes {
17 | Owner = 'Owner',
18 | Delegate = 'Delegate',
19 | Extension = 'Extension',
20 | }
21 |
22 | export enum AccountGameStates {
23 | Open = 'Open',
24 | Opened = 'Opened',
25 | Started = 'Started',
26 | Finished = 'Finished',
27 | }
28 |
29 | export enum AccountGamePlayers {
30 | Creator = 'Creator',
31 | Opponent = 'Opponent',
32 | }
33 |
34 | export enum AccountTransactionTypes {
35 | CreateAccount = 'CreateAccount',
36 | AddDevice = 'AddDevice',
37 | RemoveDevice = 'RemoveDevice',
38 | ExecuteTransaction = 'ExecuteTransaction',
39 | }
40 |
41 | export enum AccountTransactionStates {
42 | Created = 'Created',
43 | Completed = 'Completed',
44 | }
45 |
46 | export enum AccountPaymentStates {
47 | Reserved = 'Reserved',
48 | Locked = 'Locked',
49 | Created = 'Created',
50 | Signed = 'Signed',
51 | Completed = 'Completed',
52 | Processed = 'Processed',
53 | }
54 |
55 | export enum AppStates {
56 | Accepted = 'Accepted',
57 | Rejected = 'Rejected',
58 | }
59 |
60 | export enum TokenTypes {
61 | ERC20 = 'ERC20',
62 | }
63 |
64 | export enum GasPriceStrategies {
65 | Avg = 'Avg',
66 | Fast = 'Fast',
67 | }
68 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/AccountTransaction.ts:
--------------------------------------------------------------------------------
1 | import { abiEncodePacked } from '@netgum/utils';
2 | import { IEstimatedAccountProxyTransaction } from '../interfaces';
3 | import { ApiMethods } from './ApiMethods';
4 | import { Contract } from './Contract';
5 | import { Device } from './Device';
6 | import { State } from './State';
7 |
8 | export class AccountTransaction {
9 | constructor(
10 | private apiMethods: ApiMethods,
11 | private contract: Contract,
12 | private device: Device,
13 | private state: State,
14 | ) {
15 | //
16 | }
17 |
18 | public async submitAccountProxyTransaction({ nonce, data, fixedGas, gasPrice, guardianSignature }: IEstimatedAccountProxyTransaction): Promise {
19 | const { accountAddress } = this.state;
20 | const { accountProxy } = this.contract;
21 |
22 | const message = abiEncodePacked(
23 | 'address',
24 | 'bytes',
25 | 'address',
26 | 'uint256',
27 | 'bytes',
28 | 'uint256',
29 | 'uint256',
30 | )(
31 | accountProxy.address,
32 | accountProxy.getMethodSignature('forwardAccountOwnerCall'),
33 | accountAddress,
34 | nonce,
35 | data.map((value, index) => index ? value.substr(2) : value).join(''),
36 | fixedGas,
37 | gasPrice,
38 | );
39 |
40 | const signature = this.device.signPersonalMessage(message);
41 |
42 | return this.apiMethods.submitAccountProxyTransaction(accountAddress, data, signature, gasPrice, guardianSignature);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/Environment.ts:
--------------------------------------------------------------------------------
1 | import { Action } from './Action';
2 | import { Api } from './Api';
3 | import { Ens } from './Ens';
4 | import { Eth } from './Eth';
5 | import { Storage } from './Storage';
6 | import { Url } from './Url';
7 |
8 | export class Environment {
9 | constructor(private configs: Environment.IConfigs) {
10 | //
11 | }
12 |
13 | public getConfig(
14 | key: K,
15 | ): Environment.IConfigs[K] {
16 | return this.configs[key] || null;
17 | }
18 |
19 | public setConfig(
20 | key: K,
21 | config: Environment.IConfigs[K],
22 | ): this {
23 | this.configs[key] = config;
24 | return this;
25 | }
26 |
27 | public extendConfig(
28 | key: K,
29 | config: Partial,
30 | ): this {
31 | this.configs[key] = {
32 | ...(this.configs[key] as object),
33 | ...(config as object),
34 | };
35 | return this;
36 | }
37 | }
38 |
39 | export namespace Environment {
40 | export type TKeys = keyof IConfigs;
41 |
42 | export interface IConfigs {
43 | actionOptions?: Action.IOptions;
44 | apiOptions: Api.IOptions;
45 | apiWebSocketConstructor?: Api.IWebSocketConstructor;
46 | ensOptions: Ens.IOptions;
47 | ethOptions: Eth.IOptions;
48 | storageOptions: Storage.IOptions;
49 | storageAdapter?: Storage.IAdapter;
50 | urlOptions?: Url.IOptions;
51 | urlAdapter?: Url.IAdapter;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/packages/cli/src/bin.tsx:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { createLocalSdkEnvironment, getSdkEnvironment, SdkEnvironmentNames, sdkModules } from '@archanova/sdk';
4 | import { render } from 'ink';
5 | import React from 'react';
6 | import Ws from 'ws';
7 | import { getCliConfig } from './cli';
8 | import context from './context';
9 | import { Main } from './Main';
10 | import { SdkService, ServerService, StorageService, TemplateService } from './services';
11 |
12 | const config = getCliConfig();
13 |
14 | let sdkEnv: sdkModules.Environment;
15 |
16 | if (config.env === 'local') {
17 | sdkEnv = createLocalSdkEnvironment({
18 | ...config.localEnv,
19 | });
20 | }
21 |
22 | if (!sdkEnv) {
23 | sdkEnv = getSdkEnvironment(config.env as any) || getSdkEnvironment(SdkEnvironmentNames.Main);
24 | }
25 |
26 | const storageService = new StorageService({
27 | scope: config.scope,
28 | workingPath: config.workingPath,
29 | });
30 |
31 | storageService.setNamespace(sdkEnv.getConfig('storageOptions').namespace);
32 |
33 | const sdkService = new SdkService(
34 | sdkEnv
35 | .setConfig('storageAdapter', storageService.toSdkAdapter())
36 | .setConfig('apiWebSocketConstructor', Ws),
37 | );
38 |
39 | const serverService = new ServerService(config.workingPath);
40 | const templateService = new TemplateService(config.workingPath);
41 |
42 | render(
43 |
52 |
53 | ,
54 | );
55 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/url/ProcessIncomingUrl.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 |
4 | const code = (url: string) => `
5 | const url = ${url ? `"${url}"` : 'null'};
6 |
7 | sdk.processIncomingUrl(url);
8 | `;
9 |
10 | interface IState {
11 | url: string;
12 | }
13 |
14 | export class ProcessIncomingUrl extends Screen {
15 | public state = {
16 | url: '',
17 | };
18 |
19 | public componentWillMount(): void {
20 | this.run = this.run.bind(this);
21 |
22 | this.urlChanged = this.urlChanged.bind(this);
23 | }
24 |
25 | public renderContent(): any {
26 | const { enabled } = this.props;
27 | const { url } = this.state;
28 | return (
29 |
30 |
36 |
42 |
43 |
44 | );
45 | }
46 |
47 | private urlChanged(url: string): void {
48 | this.setState({
49 | url,
50 | });
51 | }
52 |
53 | private run(): void {
54 | const { url } = this.state;
55 | this
56 | .logger
57 | .wrapSync('sdk.processIncomingUrl', async () => {
58 | this.sdk.processIncomingUrl(url);
59 | this.setState({
60 | url: '',
61 | });
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/app/GetApp.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (alias: string) => `
5 | const alias = ${alias ? `"${alias}"` : 'null'};
6 |
7 | sdk
8 | .getApp(alias)
9 | .then(app => console.log('app', alias))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | alias: string;
15 | }
16 |
17 | export class GetApp extends Screen {
18 | public state = {
19 | alias: 'tictactoe',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.aliasChanged = this.aliasChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { alias } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private aliasChanged(alias: string): void {
51 | this.setState({
52 | alias,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { alias } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.getApp', async (console) => {
61 | console.log('app', await this.sdk.getApp(alias));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/cli/src/containers/Help.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Box } from 'ink';
3 | import chalk from 'chalk';
4 | import { ContextComponent } from '../context';
5 | import { Actions } from '../constants';
6 |
7 | const HELP_OPTIONS = chalk`
8 | {magenta Options}
9 | {cyan --help, -h } print help
10 | {cyan --global, -g } use global scope
11 | {cyan --env, -e } environment [main,ropsten,rinkeby,kovan,sokol,xdai,local] (default: main)
12 | {cyan --local-env-host } local environment host
13 | {cyan --local-env-port } local environment port
14 | {cyan --private-key } device private key`;
15 |
16 | const defaultHelp = chalk`
17 | {magenta Usage} {cyan archanova-cli} [action] [options] [workingPath]
18 |
19 | ${chalk.magenta('Actions')}
20 | {cyan ${Actions.Auth}} authentication
21 | {cyan ${Actions.Init}} initialize application
22 | {cyan ${Actions.Develop}} develop application
23 | {cyan ${Actions.Deploy}} deploy application
24 | ${HELP_OPTIONS}
25 | `;
26 |
27 | function buildActionHelp(action: Actions): string {
28 | return chalk`
29 | {magenta Usage} {cyan archanova-cli} {cyanBright ${action}} [options] [workingPath]
30 | ${HELP_OPTIONS}
31 | `;
32 | }
33 |
34 | export class Help extends ContextComponent {
35 | public render(): any {
36 | const { config: { action } } = this.context;
37 | let help: string = null;
38 |
39 | if (!action) {
40 | help = defaultHelp;
41 | } else {
42 | help = buildActionHelp(action);
43 | }
44 |
45 | return (
46 |
47 | {help.trim()}
48 |
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/Ens.ts:
--------------------------------------------------------------------------------
1 | import { getEnsNameHash, getEnsNameInfo, normalizeEnsName } from '@netgum/utils';
2 | import { Eth } from './Eth';
3 | import { State } from './State';
4 |
5 | export class Ens {
6 | constructor(private options: Ens.IOptions, private eth: Eth, private state: State) {
7 | this.state.ens$.next(this.buildState());
8 | }
9 |
10 | public buildName(label: string, rootName: string = null): string {
11 | let result: string = null;
12 |
13 | if (label) {
14 | const { supportedRoots } = this.state.ens;
15 |
16 | if (supportedRoots.length) {
17 | if (!rootName) {
18 | ({ name: rootName } = supportedRoots[0]);
19 | }
20 | const nameInfo = getEnsNameInfo(label, rootName);
21 |
22 | if (
23 | nameInfo &&
24 | nameInfo.rootNode &&
25 | supportedRoots.find(({ name }) => name === nameInfo.rootNode.name)
26 | ) {
27 | result = nameInfo.name;
28 | }
29 | }
30 | }
31 |
32 | return result;
33 | }
34 |
35 | private buildState(): State.IEns {
36 | const { supportedRootNames } = this.options;
37 | return {
38 | supportedRoots: supportedRootNames ?
39 | supportedRootNames
40 | .map((domain) => {
41 | const name = normalizeEnsName(domain);
42 | const nameHash = getEnsNameHash(name);
43 |
44 | return {
45 | name,
46 | nameHash,
47 | };
48 | })
49 | : [],
50 | };
51 | }
52 | }
53 |
54 | export namespace Ens {
55 | export interface IOptions {
56 | supportedRootNames: string[];
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountPayment/CancelAccountPayment.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (hash: string) => `
5 | const hash = ${hash ? `"${hash}"` : 'null'};
6 |
7 | sdk
8 | .cancelAccountPayment(hash)
9 | .then(success => console.log('success', success))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | hash: string;
15 | }
16 |
17 | export class CancelAccountPayment extends Screen {
18 | public state = {
19 | hash: '',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.hashChanged = this.hashChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { hash } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private hashChanged(hash: string): void {
51 | this.setState({
52 | hash,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { hash } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.cancelAccountPayment', async (console) => {
61 | console.log('success', await this.sdk.cancelAccountPayment(hash));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountPayment/SignAccountPayment.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (hash: string) => `
5 | const hash = ${hash ? `"${hash}"` : 'null'};
6 |
7 | sdk
8 | .signAccountPayment(hash)
9 | .then(accountPayment => console.log('accountPayment', accountPayment))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | hash: string;
15 | }
16 |
17 | export class SignAccountPayment extends Screen {
18 | public state = {
19 | hash: '',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.hashChanged = this.hashChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { hash } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private hashChanged(hash: string): void {
51 | this.setState({
52 | hash,
53 | });
54 | }
55 |
56 |
57 | private run(): void {
58 | const { hash } = this.state;
59 | this
60 | .logger
61 | .wrapSync('sdk.signAccountPayment', async (console) => {
62 | console.log('accountPayment', await this.sdk.signAccountPayment(hash));
63 | });
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/utils/GetTransactionDetails.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 | const code = (hash: string) => `
4 | const hash = ${hash ? `"${hash}"` : 'null'};
5 |
6 | sdk
7 | .getTransactionDetails(hash)
8 | .then(transactionDetails => console.log('transactionDetails', transactionDetails))
9 | .catch(console.error);
10 | `;
11 |
12 | interface IState {
13 | hash: string;
14 | }
15 |
16 | export class GetTransactionDetails extends Screen {
17 | public state = {
18 | hash: '',
19 | };
20 |
21 | public componentWillMount(): void {
22 | this.run = this.run.bind(this);
23 |
24 | this.hashChanged = this.hashChanged.bind(this);
25 | }
26 |
27 | public renderContent(): any {
28 | const { enabled } = this.props;
29 | const { hash } = this.state;
30 | return (
31 |
32 |
38 |
44 |
45 |
46 | );
47 | }
48 |
49 | private hashChanged(hash: string): void {
50 | this.setState({
51 | hash,
52 | });
53 | }
54 |
55 | private run(): void {
56 | const { hash } = this.state;
57 | this
58 | .logger
59 | .wrapSync('sdk.getTransactionDetails', async (console) => {
60 | console.log('transactionDetails', await this.sdk.getTransactionDetails(hash));
61 | });
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountGame/GetAccountGame.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (id: number) => `
5 | const gameId = ${id ? id : 'null'};
6 |
7 | sdk
8 | .getAccountGame(gameId)
9 | .then(game => console.log('game', game))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | id: string;
15 | idParsed: number;
16 | }
17 |
18 | export class GetAccountGame extends Screen {
19 | public state = {
20 | id: '0',
21 | idParsed: 0,
22 | };
23 |
24 | public componentWillMount(): void {
25 | this.run = this.run.bind(this);
26 |
27 | this.idChanged = this.idChanged.bind(this);
28 | }
29 |
30 | public renderContent(): any {
31 | const { enabled } = this.props;
32 | const { id, idParsed } = this.state;
33 | return (
34 |
35 |
41 |
47 |
48 |
49 | );
50 | }
51 |
52 | private idChanged(id: string, idParsed: number): void {
53 | this.setState({
54 | id,
55 | idParsed,
56 | });
57 | }
58 |
59 | private run(): void {
60 | const { idParsed } = this.state;
61 | this
62 | .logger
63 | .wrapSync('sdk.createAccountGame', async (console) => {
64 | console.log('game', await this.sdk.getAccountGame(idParsed));
65 | });
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/packages/cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@archanova/cli",
3 | "version": "1.1.2",
4 | "license": "MIT",
5 | "repository": {
6 | "type": "git",
7 | "url": "git+https://github.com/netgum/archanova.git"
8 | },
9 | "bugs": {
10 | "url": "https://github.com/netgum/archanova/issues"
11 | },
12 | "bin": {
13 | "archanova-cli": "./build/bin.js"
14 | },
15 | "description": "Archanova CLI",
16 | "scripts": {
17 | "clean": "rimraf ./build",
18 | "compile": "tsc --project ./tsconfig.build.json --rootDir ./src",
19 | "compile:watch": "npm run compile -- --watch --preserveWatchOutput",
20 | "prebuild": "npm run clean",
21 | "build": "npm run compile"
22 | },
23 | "dependencies": {
24 | "@archanova/sdk": "^1.1.2",
25 | "@netgum/types": "^0.1.8",
26 | "@netgum/utils": "^0.1.3",
27 | "@types/body-parser": "^1.17.0",
28 | "@types/chalk": "^2.2.0",
29 | "@types/node": "^12.0.10",
30 | "@types/express": "^4.17.0",
31 | "@types/fs-extra": "^8.0.0",
32 | "@types/react": "^16.8.22",
33 | "@types/webpack-env": "^1.13.9",
34 | "@types/ws": "^6.0.1",
35 | "body-parser": "^1.19.0",
36 | "bn.js": "^4.11.8",
37 | "chalk": "^2.4.2",
38 | "express": "^4.17.1",
39 | "fs-extra": "^8.0.1",
40 | "ink": "^2.3.0",
41 | "ink-box": "^1.0.0",
42 | "ink-link": "^1.0.0",
43 | "ink-spinner": "^3.0.1",
44 | "ink-text-input": "^3.1.1",
45 | "meow": "^5.0.0",
46 | "ngrok": "^3.2.1",
47 | "qrcode-terminal": "^0.12.0",
48 | "react": "^16.8.6",
49 | "react-dom": "^16.8.6",
50 | "rxjs": "6.4.0",
51 | "rxjs-addons": "^0.0.4",
52 | "ws": "^7.0.1"
53 | },
54 | "devDependencies": {
55 | "rimraf": "^2.6.3"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountDevice/RemoveAccountDevice.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (address: string) => `
5 | const deviceAddress = ${address ? `"${address}"` : 'null'};
6 |
7 | sdk
8 | .removeAccountDevice(deviceAddress)
9 | .then(success => console.log('success', success))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | address: string;
15 | }
16 |
17 | export class RemoveAccountDevice extends Screen {
18 | public state = {
19 | address: '',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.addressChanged = this.addressChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { address } = this.state;
31 | return (
32 |
33 |
39 |
44 |
45 |
46 | );
47 | }
48 |
49 | private addressChanged(address: string): void {
50 | this.setState({
51 | address,
52 | });
53 | }
54 |
55 | private run(): void {
56 | const { address } = this.state;
57 | this
58 | .logger
59 | .wrapSync('sdk.removeAccountDevice', async (console) => {
60 | console.log('success', await this.sdk.removeAccountDevice(address));
61 | });
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountGame/JoinAccountGame.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (id: number) => `
5 | const gameId = ${id ? id : 'null'};
6 |
7 | sdk
8 | .joinAccountGame(gameId)
9 | .then(game => console.log('game', game))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | id: string;
15 | idParsed: number;
16 | }
17 |
18 | export class JoinAccountGame extends Screen {
19 | public state = {
20 | id: '0',
21 | idParsed: 0,
22 | };
23 |
24 | public componentWillMount(): void {
25 | this.run = this.run.bind(this);
26 |
27 | this.idChanged = this.idChanged.bind(this);
28 | }
29 |
30 | public renderContent(): any {
31 | const { enabled } = this.props;
32 | const { id, idParsed } = this.state;
33 | return (
34 |
35 |
41 |
47 |
48 |
49 | );
50 | }
51 |
52 | private idChanged(id: string, idParsed: number): void {
53 | this.setState({
54 | id,
55 | idParsed,
56 | });
57 | }
58 |
59 | private run(): void {
60 | const { idParsed } = this.state;
61 | this
62 | .logger
63 | .wrapSync('sdk.joinAccountGame', async (console) => {
64 | console.log('game', await this.sdk.joinAccountGame(idParsed));
65 | });
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountGame/StartAccountGame.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (id: number) => `
5 | const gameId = ${id ? id : 'null'};
6 |
7 | sdk
8 | .startAccountGame(gameId)
9 | .then(game => console.log('game', game))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | id: string;
15 | idParsed: number;
16 | }
17 |
18 | export class StartAccountGame extends Screen {
19 | public state = {
20 | id: '0',
21 | idParsed: 0,
22 | };
23 |
24 | public componentWillMount(): void {
25 | this.run = this.run.bind(this);
26 |
27 | this.idChanged = this.idChanged.bind(this);
28 | }
29 |
30 | public renderContent(): any {
31 | const { enabled } = this.props;
32 | const { id, idParsed } = this.state;
33 | return (
34 |
35 |
41 |
47 |
48 |
49 | );
50 | }
51 |
52 | private idChanged(id: string, idParsed: number): void {
53 | this.setState({
54 | id,
55 | idParsed,
56 | });
57 | }
58 |
59 | private run(): void {
60 | const { idParsed } = this.state;
61 | this
62 | .logger
63 | .wrapSync('sdk.startAccountGame', async (console) => {
64 | console.log('game', await this.sdk.startAccountGame(idParsed));
65 | });
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountPayment/GetConnectedAccountPayment.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (hash: string) => `
5 | const hash = ${hash ? `"${hash}"` : 'null'};
6 |
7 | sdk
8 | .getConnectedAccountPayment(hash)
9 | .then(accountPayment => console.log('accountPayment', accountPayment))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | hash: string;
15 | }
16 |
17 | export class GetConnectedAccountPayment extends Screen {
18 | public state = {
19 | hash: '',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.hashChanged = this.hashChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { hash } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private hashChanged(hash: string): void {
51 | this.setState({
52 | hash,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { hash } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.getConnectedAccountPayment', async (console) => {
61 | console.log('accountPayment', await this.sdk.getConnectedAccountPayment(hash));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountGame/CancelAccountGame.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (id: number) => `
5 | const gameId = ${id ? id : 'null'};
6 |
7 | sdk
8 | .cancelAccountGame(gameId)
9 | .then(success => console.log('success', success))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | id: string;
15 | idParsed: number;
16 | }
17 |
18 | export class CancelAccountGame extends Screen {
19 | public state = {
20 | id: '0',
21 | idParsed: 0,
22 | };
23 |
24 | public componentWillMount(): void {
25 | this.run = this.run.bind(this);
26 |
27 | this.idChanged = this.idChanged.bind(this);
28 | }
29 |
30 | public renderContent(): any {
31 | const { enabled } = this.props;
32 | const { id, idParsed } = this.state;
33 | return (
34 |
35 |
41 |
47 |
48 |
49 | );
50 | }
51 |
52 | private idChanged(id: string, idParsed: number): void {
53 | this.setState({
54 | id,
55 | idParsed,
56 | });
57 | }
58 |
59 | private run(): void {
60 | const { idParsed } = this.state;
61 | this
62 | .logger
63 | .wrapSync('sdk.cancelAccountGame', async (console) => {
64 | console.log('success', await this.sdk.cancelAccountGame(idParsed));
65 | });
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/app/GetApps.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 | import { mergeMethodArgs } from '../../shared';
4 |
5 | const code = (page = 0) => `
6 | ${page ? `const page = ${page};` : ''}
7 |
8 | sdk
9 | .getApps(${mergeMethodArgs(page && 'page')})
10 | .then(apps => console.log('apps', apps))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | page: string;
16 | pageParsed: number;
17 | }
18 |
19 | export class GetApps extends Screen {
20 | public state = {
21 | page: '0',
22 | pageParsed: 0,
23 | };
24 |
25 | public componentWillMount(): void {
26 | this.run = this.run.bind(this);
27 |
28 | this.pageChanged = this.pageChanged.bind(this);
29 | }
30 |
31 | public renderContent(): any {
32 | const { enabled } = this.props;
33 | const { page, pageParsed } = this.state;
34 | return (
35 |
36 |
42 |
48 |
49 |
50 | );
51 | }
52 |
53 | private pageChanged(page: string, pageParsed: number) {
54 | this.setState({
55 | page,
56 | pageParsed,
57 | });
58 | }
59 |
60 | private run(): void {
61 | const { pageParsed } = this.state;
62 | this
63 | .logger
64 | .wrapSync('sdk.getApps', async (console) => {
65 | console.log('apps', await this.sdk.getApps(pageParsed));
66 | });
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/packages/sdk/src/redux/middleware.ts:
--------------------------------------------------------------------------------
1 | import { merge } from 'rxjs';
2 | import { map } from 'rxjs/operators';
3 | import { Middleware, Store } from 'redux';
4 | import { Sdk } from '../Sdk';
5 | import { ReduxSdkActionTypes } from './actions';
6 | import { createActionCreator } from './helpers';
7 |
8 | export function createReduxSdkMiddleware(sdk: Sdk): Middleware {
9 | const {
10 | initialized$,
11 | connected$,
12 | authenticated$,
13 | account$,
14 | accountDevice$,
15 | accountFriendRecovery$,
16 | device$,
17 | ens$,
18 | eth$,
19 | incomingAction$,
20 | } = sdk.state;
21 |
22 | return (store: Store) => {
23 | setTimeout(
24 | () => {
25 | merge(
26 | initialized$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetInitialized))),
27 | connected$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetConnected))),
28 | account$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetAccount))),
29 | accountDevice$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetAccountDevice))),
30 | accountFriendRecovery$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetAccountFriendRecovery))),
31 | device$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetDevice))),
32 | ens$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetEns))),
33 | eth$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetEth))),
34 | incomingAction$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetIncomingAction))),
35 | authenticated$.pipe(map(createActionCreator(ReduxSdkActionTypes.SetAuthenticated))),
36 | )
37 | .subscribe(store.dispatch);
38 | },
39 | 0,
40 | );
41 |
42 | return next => action => next(action);
43 | };
44 | }
45 |
--------------------------------------------------------------------------------
/packages/sdk-playground/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@archanova/sdk-playground",
3 | "version": "1.1.2",
4 | "private": true,
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/netgum/archanova.git"
9 | },
10 | "bugs": {
11 | "url": "https://github.com/netgum/archanova/issues"
12 | },
13 | "description": "Archanova Tutorial",
14 | "dependencies": {
15 | "@archanova/contracts": "^1.0.0",
16 | "@archanova/sdk": "^1.1.2",
17 | "@netgum/types": "^0.1.8",
18 | "@netgum/utils": "^0.1.3",
19 | "@types/react": "^16.8.17",
20 | "@types/react-dom": "^16.8.4",
21 | "@types/react-redux": "^7.0.9",
22 | "@types/markdown-it": "^0.0.7",
23 | "@types/node": "^12.0.0",
24 | "@types/webpack-env": "^1.13.9",
25 | "bn.js": "^4.11.8",
26 | "highlight.js": "^9.15.6",
27 | "markdown-it": "^8.4.2",
28 | "qrcode.react": "^0.9.3",
29 | "react": "^16.8.6",
30 | "react-dom": "^16.8.6",
31 | "react-highlight": "^0.12.0",
32 | "react-scripts": "3.0.1",
33 | "react-redux": "^7.0.3",
34 | "redux": "^4.0.1",
35 | "redux-devtools-extension": "^2.13.8",
36 | "react-inspector": "^3.0.2",
37 | "rxjs": "6.4.0",
38 | "node-sass": "^4.11.0",
39 | "normalize-scss": "^7.0.1",
40 | "webpack": "4.29.6"
41 | },
42 | "scripts": {
43 | "start": "react-scripts start",
44 | "build": "./scripts/build.sh",
45 | "predeploy": "npm run build",
46 | "deploy": "./scripts/deploy.sh"
47 | },
48 | "browserslist": {
49 | "production": [
50 | ">0.2%",
51 | "not dead",
52 | "not op_mini all"
53 | ],
54 | "development": [
55 | "last 1 chrome version",
56 | "last 1 firefox version",
57 | "last 1 safari version"
58 | ]
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountDevice/GetConnectedAccountDevice.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (address: string) => `
5 | const address = ${address ? `"${address}"` : 'null'};
6 |
7 | sdk
8 | .getConnectedAccountDevice(address)
9 | .then(accountDevice => console.log('accountDevice', accountDevice))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | address: string;
15 | }
16 |
17 | export class GetConnectedAccountDevice extends Screen {
18 | public state = {
19 | address: '',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.addressChanged = this.addressChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { address } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private addressChanged(address: string): void {
51 | this.setState({
52 | address,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { address } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.getConnectedAccountDevice', async (console) => {
61 | console.log('accountDevice', await this.sdk.getConnectedAccountDevice(address));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/token/GetTokens.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 | import { mergeMethodArgs } from '../../shared';
4 |
5 | const code = (page = 0) => `
6 | ${page ? `const page = ${page};` : ''}
7 |
8 | sdk
9 | .getTokens(${mergeMethodArgs(page && 'page')})
10 | .then(tokens => console.log('tokens', tokens))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | page: string;
16 | pageParsed: number;
17 | }
18 |
19 | export class GetTokens extends Screen {
20 | public state = {
21 | page: '0',
22 | pageParsed: 0,
23 | };
24 |
25 | public componentWillMount(): void {
26 | this.run = this.run.bind(this);
27 |
28 | this.pageChanged = this.pageChanged.bind(this);
29 | }
30 |
31 | public renderContent(): any {
32 | const { enabled } = this.props;
33 | const { page, pageParsed } = this.state;
34 | return (
35 |
36 |
42 |
48 |
49 |
50 | );
51 | }
52 |
53 | private pageChanged(page: string, pageParsed: number) {
54 | this.setState({
55 | page,
56 | pageParsed,
57 | });
58 | }
59 |
60 | private run(): void {
61 | const { pageParsed } = this.state;
62 | this
63 | .logger
64 | .wrapSync('sdk.getTokens', async (console) => {
65 | console.log('tokens', await this.sdk.getTokens(pageParsed));
66 | });
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/token/GetToken.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (symbolOrAddress: string) => `
5 | const symbolOrAddress = ${symbolOrAddress ? `"${symbolOrAddress}"` : 'null'};
6 |
7 | sdk
8 | .getToken(symbolOrAddress)
9 | .then(token => console.log('token', token))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | symbolOrAddress: string;
15 | }
16 |
17 | export class GetToken extends Screen {
18 | public state = {
19 | symbolOrAddress: 'ETK',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.symbolOrAddressChanged = this.symbolOrAddressChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { symbolOrAddress } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private symbolOrAddressChanged(symbolOrAddress: string): void {
51 | this.setState({
52 | symbolOrAddress,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { symbolOrAddress } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.getToken', async (console) => {
61 | console.log('token', await this.sdk.getToken(symbolOrAddress));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/cli/src/containers/InitAction.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { SdkError } from '@archanova/sdk';
3 | import { Box } from 'ink';
4 | import { Form } from '../components';
5 | import { ContextComponent } from '../context';
6 |
7 | interface IState {
8 | errors: { [key: string]: any };
9 | }
10 |
11 | export class InitAction extends ContextComponent<{}, IState> {
12 | public state: IState = {
13 | errors: {},
14 | };
15 |
16 | public componentWillMount(): void {
17 | this.formSubmitted = this.formSubmitted.bind(this);
18 | }
19 |
20 | public componentWillUnmount(): void {
21 | //
22 | }
23 |
24 | public render(): any {
25 | const { errors } = this.state;
26 |
27 | return (
28 |
29 |
41 |
42 | );
43 | }
44 |
45 | private formSubmitted(values: any): void {
46 | const { sdkService, templateService } = this.context;
47 |
48 | this.wrapAsync(async () => {
49 | try {
50 | const app = await sdkService.createDeveloperApp(values);
51 | if (!await templateService.templateExists()) {
52 | await templateService.createTemplate(app);
53 | }
54 | } catch (err) {
55 | if (
56 | SdkError.isSdkError(err) &&
57 | err.type === SdkError.Types.Http &&
58 | err.data
59 | ) {
60 | this.setState({
61 | errors: err.data,
62 | });
63 | }
64 | }
65 | });
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountFriendRecovery/GetAccountFriendRecovery.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (address: string) => `
5 | const accountAddress = ${address ? `"${address}"` : 'null'};
6 |
7 | sdk
8 | .getAccountFriendRecovery(accountAddress)
9 | .then(accountFriendRecovery => console.log('accountFriendRecovery', accountFriendRecovery))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | address: string;
15 | }
16 |
17 | export class GetAccountFriendRecovery extends Screen {
18 | public state = {
19 | address: '',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.addressChanged = this.addressChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { address } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private addressChanged(address: string): void {
51 | this.setState({
52 | address,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { address } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.getAccountFriendRecovery', async (console) => {
61 | console.log('accountFriendRecovery', await this.sdk.getAccountFriendRecovery(address));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/AccountPayment.ts:
--------------------------------------------------------------------------------
1 | import BN from 'bn.js';
2 | import { abiEncodePacked, ZERO_ADDRESS } from '@netgum/utils';
3 | import { IAccountPayment } from '../interfaces';
4 | import { ApiMethods } from './ApiMethods';
5 | import { Contract } from './Contract';
6 | import { Device } from './Device';
7 | import { State } from './State';
8 |
9 | export class AccountPayment {
10 | constructor(
11 | private apiMethods: ApiMethods,
12 | private contract: Contract,
13 | private device: Device,
14 | private state: State,
15 | ) {
16 | //
17 | }
18 |
19 | public async createAccountPayment(
20 | recipient: string,
21 | token: string,
22 | value: number | string | BN,
23 | ): Promise {
24 | const { accountAddress } = this.state;
25 | let payment = await this.apiMethods.createAccountPayment(accountAddress, recipient, token, value);
26 |
27 | if (payment && recipient) {
28 | payment = await this.signAccountPayment(payment);
29 | }
30 |
31 | return payment;
32 | }
33 |
34 | public async signAccountPayment(payment: IAccountPayment): Promise {
35 | const { accountAddress } = this.state;
36 | const { hash, value, recipient, token } = payment;
37 | const { address } = this.contract.virtualPaymentManager;
38 | const message = abiEncodePacked(
39 | 'address',
40 | 'address',
41 | 'address',
42 | 'address',
43 | 'bytes',
44 | 'uint256',
45 | )(
46 | address,
47 | accountAddress,
48 | recipient.address || recipient.account.address,
49 | token && token.address ? token.address : ZERO_ADDRESS,
50 | hash,
51 | value,
52 | );
53 |
54 | const signature = this.device.signPersonalMessage(message);
55 |
56 | return this.apiMethods.signAccountPayment(accountAddress, hash, signature);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/token/GetTokenBalance.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (symbolOrAddress: string) => `
5 | const symbolOrAddress = ${symbolOrAddress ? `"${symbolOrAddress}"` : 'null'};
6 |
7 | sdk
8 | .getTokenBalance(symbolOrAddress)
9 | .then(tokenBalance => console.log('tokenBalance', tokenBalance))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | symbolOrAddress: string;
15 | }
16 |
17 | export class GetTokenBalance extends Screen {
18 | public state = {
19 | symbolOrAddress: 'ETK',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.symbolOrAddressChanged = this.symbolOrAddressChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { symbolOrAddress } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private symbolOrAddressChanged(symbolOrAddress: string): void {
51 | this.setState({
52 | symbolOrAddress,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { symbolOrAddress } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.getTokenBalance', async (console) => {
61 | console.log('tokenBalance', await this.sdk.getTokenBalance(symbolOrAddress));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountDevice/GetConnectedAccountDevices.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 | import { mergeMethodArgs } from '../../shared';
4 |
5 | const code = (page = 0) => `
6 | ${page ? `const page = ${page};` : ''}
7 |
8 | sdk
9 | .getConnectedAccountDevices(${mergeMethodArgs(page && 'page')})
10 | .then(accountDevices => console.log('accountDevices', accountDevices))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | page: string;
16 | pageParsed: number;
17 | }
18 |
19 | export class GetConnectedAccountDevices extends Screen {
20 | public state = {
21 | page: '0',
22 | pageParsed: 0,
23 | };
24 |
25 | public componentWillMount(): void {
26 | this.run = this.run.bind(this);
27 |
28 | this.pageChanged = this.pageChanged.bind(this);
29 | }
30 |
31 | public renderContent(): any {
32 | const { enabled } = this.props;
33 | const { page, pageParsed } = this.state;
34 | return (
35 |
36 |
42 |
48 |
49 |
50 | );
51 | }
52 |
53 | private pageChanged(page: string, pageParsed: number) {
54 | this.setState({
55 | page,
56 | pageParsed,
57 | });
58 | }
59 |
60 | private run(): void {
61 | const { pageParsed } = this.state;
62 | this
63 | .logger
64 | .wrapSync('sdk.getConnectedAccountDevices', async (console) => {
65 | console.log('accountDevices', await this.sdk.getConnectedAccountDevices(pageParsed));
66 | });
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountFriendRecovery/StartAccountFriendRecovery.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (accountAddress: string) => `
5 | const accountAddress = ${accountAddress ? `"${accountAddress}"` : 'null'};
6 |
7 | sdk
8 | .startAccountFriendRecovery(accountAddress)
9 | .then(accountFriendRecovery => console.log('accountFriendRecovery', accountFriendRecovery))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | accountAddress: string;
15 | }
16 |
17 | export class StartAccountFriendRecovery extends Screen {
18 | public state = {
19 | accountAddress: '',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.accountAddressChanged = this.accountAddressChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { accountAddress } = this.state;
31 | return (
32 |
33 |
39 |
44 |
45 |
46 | );
47 | }
48 |
49 | private accountAddressChanged(accountAddress: string): void {
50 | this.setState({
51 | accountAddress,
52 | });
53 | }
54 |
55 | private run(): void {
56 | const { accountAddress } = this.state;
57 | this
58 | .logger
59 | .wrapSync('sdk.startAccountFriendRecovery', async (console) => {
60 | console.log('accountFriendRecovery', await this.sdk.startAccountFriendRecovery(accountAddress));
61 | });
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/Device.ts:
--------------------------------------------------------------------------------
1 | import { generateRandomPrivateKey, privateKeyToAddress, signPersonalMessage, anyToBuffer, verifyPrivateKey } from '@netgum/utils';
2 | import { State } from './State';
3 | import { Storage } from './Storage';
4 |
5 | export class Device {
6 | private privateKey: Buffer = null;
7 |
8 | constructor(
9 | private state: State,
10 | private storage: Storage,
11 | ) {
12 | //
13 | }
14 |
15 | public async setup(options: Device.ISetupOptions = {}): Promise {
16 | if (options.privateKey) {
17 | const privateKey = anyToBuffer(options.privateKey, { defaults: null });
18 | if (verifyPrivateKey(privateKey)) {
19 | this.privateKey = privateKey;
20 |
21 | await this.storage.setItem(Device.StorageKeys.PrivateKey, this.privateKey);
22 | }
23 | }
24 |
25 | if (!this.privateKey) {
26 | this.privateKey = await this.storage.getItem(Device.StorageKeys.PrivateKey);
27 | }
28 |
29 | if (!this.privateKey) {
30 | await this.generatePrivateKey();
31 | }
32 |
33 | this.emitState();
34 | }
35 |
36 | public async reset(): Promise {
37 | await this.generatePrivateKey();
38 |
39 | this.emitState();
40 | }
41 |
42 | public signPersonalMessage(message: string | Buffer): Buffer {
43 | return signPersonalMessage(message, this.privateKey);
44 | }
45 |
46 | private async generatePrivateKey(): Promise {
47 | this.privateKey = generateRandomPrivateKey();
48 |
49 | await this.storage.setItem(Device.StorageKeys.PrivateKey, this.privateKey);
50 | }
51 |
52 | private emitState(): void {
53 | const address = privateKeyToAddress(this.privateKey);
54 |
55 | this.state.device$.next({
56 | address,
57 | });
58 | }
59 | }
60 |
61 | export namespace Device {
62 | export enum StorageKeys {
63 | PrivateKey = 'private_key',
64 | }
65 |
66 | export interface ISetupOptions {
67 | privateKey?: string | Buffer;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/utils/SignPersonalMessage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { randomBytes } from 'crypto';
3 | import { anyToHex } from '@netgum/utils';
4 | import { Example, Screen, InputText } from '../../components';
5 |
6 | const code = (message: string) => `
7 | const message = ${message ? `"${message}"` : 'null'};
8 |
9 | console.log('signature', sdk.signPersonalMessage(message));
10 | `;
11 |
12 | interface IState {
13 | message: string;
14 | }
15 |
16 | export class SignPersonalMessage extends Screen {
17 | public state = {
18 | message: '',
19 | };
20 |
21 | public componentWillMount(): void {
22 | this.run = this.run.bind(this);
23 |
24 | this.messageChanged = this.messageChanged.bind(this);
25 | this.generateMessage = this.generateMessage.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { message } = this.state;
31 | return (
32 |
33 |
39 |
46 |
47 |
48 | );
49 | }
50 |
51 | private messageChanged(message: string): void {
52 | this.setState({
53 | message,
54 | });
55 | }
56 |
57 | private generateMessage(): void {
58 | this.setState({
59 | message: anyToHex(randomBytes(15), { add0x: true }),
60 | });
61 | }
62 |
63 | private run(): void {
64 | const { message } = this.state;
65 | this
66 | .logger
67 | .wrapSync('sdk.signPersonalMessage', async (console) => {
68 | console.log('signature', this.sdk.signPersonalMessage(message));
69 | });
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/components/InputText.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './InputText.module.scss';
3 | import { Button } from './Button';
4 |
5 | interface IProps {
6 | label: string;
7 | value: string;
8 | readOnly?: boolean;
9 | type?: 'text' | 'number';
10 | decimal?: boolean;
11 | onChange?: (value: string, valueParsed: any) => any;
12 | onRandomClick?: () => any;
13 | }
14 |
15 | export class InputText extends React.Component {
16 | public static defaultProps: Partial = {
17 | type: 'text',
18 | };
19 |
20 | componentWillMount(): void {
21 | this.onChangeHandler = this.onChangeHandler.bind(this);
22 | }
23 |
24 | public render(): any {
25 | const { label, value, type, readOnly, onRandomClick } = this.props;
26 |
27 | return (
28 |
29 |
{label}
30 |
36 | {!onRandomClick ? null : (
37 |
38 | )}
39 |
40 | );
41 | }
42 |
43 | private onChangeHandler(event: React.SyntheticEvent): void {
44 | const { onChange, type, decimal } = this.props;
45 |
46 | if (onChange) {
47 | const { value } = event.currentTarget;
48 | let valueParsed: any = null;
49 |
50 | switch (type) {
51 | case 'number':
52 | if (decimal) {
53 | valueParsed = parseFloat(value) || 0;
54 | } else {
55 | valueParsed = parseInt(value, 10) || 0;
56 | }
57 | if (valueParsed < 0) {
58 | valueParsed = 0;
59 | }
60 | break;
61 | case 'text':
62 | valueParsed = value;
63 | break;
64 | }
65 |
66 | onChange(
67 | value || '',
68 | valueParsed,
69 | );
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountVirtualBalance/GetConnectedAccountVirtualBalances.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 | import { mergeMethodArgs } from '../../shared';
4 |
5 | const code = (page = 0) => `
6 | ${page ? `const page = ${page};` : ''}
7 |
8 | sdk
9 | .getConnectedAccountVirtualBalances(${mergeMethodArgs(page && 'page')})
10 | .then(accountVirtualBalances => console.log('accountVirtualBalances', accountVirtualBalances))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | page: string;
16 | pageParsed: number;
17 | }
18 |
19 | export class GetConnectedAccountVirtualBalances extends Screen {
20 | public state = {
21 | page: '0',
22 | pageParsed: 0,
23 | };
24 |
25 | public componentWillMount(): void {
26 | this.run = this.run.bind(this);
27 |
28 | this.pageChanged = this.pageChanged.bind(this);
29 | }
30 |
31 | public renderContent(): any {
32 | const { enabled } = this.props;
33 | const { page, pageParsed } = this.state;
34 | return (
35 |
36 |
42 |
48 |
49 |
50 | );
51 | }
52 |
53 | private pageChanged(page: string, pageParsed: number) {
54 | this.setState({
55 | page,
56 | pageParsed,
57 | });
58 | }
59 |
60 | private run(): void {
61 | const { pageParsed } = this.state;
62 | this
63 | .logger
64 | .wrapSync('sdk.getConnectedAccountVirtualBalances', async (console) => {
65 | console.log('accountVirtualBalances', await this.sdk.getConnectedAccountVirtualBalances(pageParsed));
66 | });
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/account/UpdateAccount.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 | import { generateRandomEnsLabel } from '../../shared';
4 |
5 | const code = (ensLabel: string) => `
6 | const ensLabel = ${ensLabel ? `"${ensLabel}"` : 'null'};
7 |
8 | sdk
9 | .updateAccount(ensLabel)
10 | .then(account => console.log('account', account))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | ensLabel: string;
16 | }
17 |
18 | export class UpdateAccount extends Screen {
19 | public state = {
20 | ensLabel: generateRandomEnsLabel(),
21 | };
22 |
23 | public componentWillMount(): void {
24 | this.run = this.run.bind(this);
25 |
26 | this.ensLabelChanged = this.ensLabelChanged.bind(this);
27 | this.generateEnsLabel = this.generateEnsLabel.bind(this);
28 | }
29 |
30 | public renderContent(): any {
31 | const { enabled } = this.props;
32 | const { ensLabel } = this.state;
33 | return (
34 |
35 |
41 |
47 |
48 |
49 | );
50 | }
51 |
52 | private ensLabelChanged(ensLabel: string): void {
53 | this.setState({
54 | ensLabel,
55 | });
56 | }
57 |
58 | private generateEnsLabel(): void {
59 | this.setState({
60 | ensLabel: generateRandomEnsLabel(),
61 | });
62 | }
63 |
64 | private run(): void {
65 | const { ensLabel } = this.state;
66 | this
67 | .logger
68 | .wrapSync('sdk.updateAccount', async (console) => {
69 | console.log('account', await this.sdk.updateAccount(ensLabel));
70 | });
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountVirtualBalance/GetConnectedAccountVirtualBalance.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (symbolOrAddress: string) => `
5 | const symbolOrAddress = ${symbolOrAddress ? `"${symbolOrAddress}"` : 'null'};
6 |
7 | sdk
8 | .getConnectedAccountVirtualBalance(symbolOrAddress)
9 | .then(accountVirtualBalance => console.log('accountVirtualBalance', accountVirtualBalance))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | symbolOrAddress: string;
15 | }
16 |
17 | export class GetConnectedAccountVirtualBalance extends Screen {
18 | public state = {
19 | symbolOrAddress: 'ETK',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.symbolOrAddressChanged = this.symbolOrAddressChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { symbolOrAddress } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private symbolOrAddressChanged(symbolOrAddress: string): void {
51 | this.setState({
52 | symbolOrAddress,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { symbolOrAddress } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.getConnectedAccountVirtualBalance', async (console) => {
61 | console.log('accountVirtualBalance', await this.sdk.getConnectedAccountVirtualBalance(symbolOrAddress));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/account/CreateAccount.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 | import { generateRandomEnsLabel, mergeMethodArgs } from '../../shared';
4 |
5 | const code = (ensLabel: string) => `
6 | ${ensLabel ? `const ensLabel = "${ensLabel}";` : ''}
7 |
8 | sdk
9 | .createAccount(${mergeMethodArgs(ensLabel && 'ensLabel')})
10 | .then(account => console.log('account', account))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | ensLabel: string;
16 | }
17 |
18 | export class CreateAccount extends Screen {
19 | public state = {
20 | ensLabel: '',
21 | };
22 |
23 | public componentWillMount(): void {
24 | this.run = this.run.bind(this);
25 |
26 | this.ensLabelChanged = this.ensLabelChanged.bind(this);
27 | this.generateEnsLabel = this.generateEnsLabel.bind(this);
28 | }
29 |
30 | public renderContent(): any {
31 | const { enabled } = this.props;
32 | const { ensLabel } = this.state;
33 | return (
34 |
35 |
41 |
47 |
48 |
49 | );
50 | }
51 |
52 | private ensLabelChanged(ensLabel: string): void {
53 | this.setState({
54 | ensLabel,
55 | });
56 | }
57 |
58 | private generateEnsLabel(): void {
59 | this.setState({
60 | ensLabel: generateRandomEnsLabel(),
61 | });
62 | }
63 |
64 | private run(): void {
65 | const { ensLabel } = this.state;
66 | this
67 | .logger
68 | .wrapSync('sdk.createAccount', async (console) => {
69 | console.log('account', await this.sdk.createAccount(ensLabel || null));
70 | });
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountDevice/CreateAccountDevice.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 | import { generateRandomAddress } from '../../shared';
4 |
5 | const code = (address: string) => `
6 | const deviceAddress = ${address ? `"${address}"` : 'null'};
7 |
8 | sdk
9 | .createAccountDevice(deviceAddress)
10 | .then(accountDevice => console.log('accountDevice', accountDevice))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | address: string;
16 | }
17 |
18 | export class CreateAccountDevice extends Screen {
19 | public state = {
20 | address: '',
21 | };
22 |
23 | public componentWillMount(): void {
24 | this.run = this.run.bind(this);
25 |
26 | this.addressChanged = this.addressChanged.bind(this);
27 | this.generateAddress = this.generateAddress.bind(this);
28 | }
29 |
30 | public renderContent(): any {
31 | const { enabled } = this.props;
32 | const { address } = this.state;
33 | return (
34 |
35 |
41 |
47 |
48 |
49 | );
50 | }
51 |
52 | private addressChanged(address: string): void {
53 | this.setState({
54 | address,
55 | });
56 | }
57 |
58 | private generateAddress(): void {
59 | this.setState({
60 | address: generateRandomAddress(),
61 | });
62 | }
63 |
64 | private run(): void {
65 | const { address } = this.state;
66 | this
67 | .logger
68 | .wrapSync('sdk.createAccount', async (console) => {
69 | console.log('accountDevice', await this.sdk.createAccountDevice(address));
70 | });
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/Eth.ts:
--------------------------------------------------------------------------------
1 | import EthJs from 'ethjs';
2 | import { ContractNames, getContractAddress } from '@archanova/contracts';
3 | import { Api } from './Api';
4 | import { State } from './State';
5 | import { EthError } from './EthError';
6 |
7 | export class Eth extends EthJs {
8 | constructor(
9 | private options: Eth.IOptions,
10 | api: Api,
11 | state: State,
12 | ) {
13 | super(api.toEthProvider(EthError));
14 |
15 | state.eth$.next(this.buildState());
16 | }
17 |
18 | public getNetworkId(): string {
19 | const { networkId } = this.options;
20 | return networkId;
21 | }
22 |
23 | public getContractAddress(contractName: ContractNames): string {
24 | let result: string = null;
25 | const { networkId, contractAddresses } = this.options;
26 | if (
27 | contractAddresses &&
28 | contractAddresses[contractName]
29 | ) {
30 | result = contractAddresses[contractName];
31 | }
32 |
33 | if (!result) {
34 | result = getContractAddress(contractName, networkId);
35 | }
36 |
37 | return result;
38 | }
39 |
40 | private buildState(): State.IEth {
41 | const { networkId } = this.options;
42 | let networkName: string = 'Unknown';
43 |
44 | switch (networkId) {
45 | case '1':
46 | networkName = 'Main';
47 | break;
48 |
49 | case '3':
50 | networkName = 'Ropsten';
51 | break;
52 |
53 | case '4':
54 | networkName = 'Rinkeby';
55 | break;
56 |
57 | case '42':
58 | networkName = 'Kovan';
59 | break;
60 |
61 | case '77':
62 | networkName = 'Sokol';
63 | break;
64 |
65 | case '100':
66 | networkName = 'xDai';
67 | break;
68 |
69 | default:
70 | networkName = 'Local';
71 | }
72 |
73 | return {
74 | networkId,
75 | networkName,
76 | };
77 | }
78 | }
79 |
80 | export namespace Eth {
81 | export interface IOptions {
82 | networkId: string;
83 | gasPrice?: string;
84 | contractAddresses?: { [key: string]: string };
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountVirtualBalance/GetConnectedAccountVirtualPendingBalance.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (symbolOrAddress: string) => `
5 | const symbolOrAddress = ${symbolOrAddress ? `"${symbolOrAddress}"` : 'null'};
6 |
7 | sdk
8 | .getConnectedAccountVirtualPendingBalance(symbolOrAddress)
9 | .then(accountVirtualPendingBalance => console.log('accountVirtualPendingBalance', accountVirtualPendingBalance))
10 | .catch(console.error);
11 | `;
12 |
13 | interface IState {
14 | symbolOrAddress: string;
15 | }
16 |
17 | export class GetConnectedAccountVirtualPendingBalance extends Screen {
18 | public state = {
19 | symbolOrAddress: 'ETK',
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.run = this.run.bind(this);
24 |
25 | this.symbolOrAddressChanged = this.symbolOrAddressChanged.bind(this);
26 | }
27 |
28 | public renderContent(): any {
29 | const { enabled } = this.props;
30 | const { symbolOrAddress } = this.state;
31 | return (
32 |
33 |
39 |
45 |
46 |
47 | );
48 | }
49 |
50 | private symbolOrAddressChanged(symbolOrAddress: string): void {
51 | this.setState({
52 | symbolOrAddress,
53 | });
54 | }
55 |
56 | private run(): void {
57 | const { symbolOrAddress } = this.state;
58 | this
59 | .logger
60 | .wrapSync('sdk.getConnectedAccountVirtualPendingBalance', async (console) => {
61 | console.log('accountVirtualPendingBalance', await this.sdk.getConnectedAccountVirtualPendingBalance(symbolOrAddress));
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/AccountGame.ts:
--------------------------------------------------------------------------------
1 | import { abiEncodePacked, ZERO_ADDRESS } from '@netgum/utils';
2 | import { IAccountGame } from '../interfaces';
3 | import { ApiMethods } from './ApiMethods';
4 | import { Contract } from './Contract';
5 | import { Device } from './Device';
6 | import { State } from './State';
7 |
8 | export class AccountGame {
9 | constructor(
10 | private apiMethods: ApiMethods,
11 | private contract: Contract,
12 | private device: Device,
13 | private state: State,
14 | ) {
15 | //
16 | }
17 |
18 | public joinAccountGame(accountGame: IAccountGame): Promise {
19 | const { accountAddress } = this.state;
20 | const { id, deposit, creator: { account, payment } } = accountGame;
21 | const { address } = this.contract.virtualPaymentManager;
22 |
23 | const message = abiEncodePacked(
24 | 'address',
25 | 'address',
26 | 'address',
27 | 'address',
28 | 'bytes',
29 | 'uint256',
30 | )(
31 | address,
32 | accountAddress,
33 | account.address,
34 | deposit.token ? deposit.token.address : ZERO_ADDRESS,
35 | payment.hash,
36 | deposit.value,
37 | );
38 |
39 | const signature = this.device.signPersonalMessage(message);
40 |
41 | return this.apiMethods.joinAccountGame(accountAddress, id, signature);
42 | }
43 |
44 | public startAccountGame(accountGame: IAccountGame): Promise {
45 | const { accountAddress } = this.state;
46 | const { id, deposit, opponent: { account, payment } } = accountGame;
47 | const { address } = this.contract.virtualPaymentManager;
48 |
49 | const message = abiEncodePacked(
50 | 'address',
51 | 'address',
52 | 'address',
53 | 'address',
54 | 'bytes',
55 | 'uint256',
56 | )(
57 | address,
58 | accountAddress,
59 | account.address,
60 | deposit.token ? deposit.token.address : ZERO_ADDRESS,
61 | payment.hash,
62 | deposit.value,
63 | );
64 |
65 | const signature = this.device.signPersonalMessage(message);
66 |
67 | return this.apiMethods.startAccountGame(accountAddress, id, signature);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/Action.ts:
--------------------------------------------------------------------------------
1 | import { Subscription } from 'rxjs';
2 | import { UniqueBehaviorSubject } from 'rxjs-addons';
3 | import { filter, tap } from 'rxjs/operators';
4 |
5 | export class Action {
6 | public static createAction(type: Action.Types, payload: T): Action.IAction {
7 | return {
8 | type,
9 | payload,
10 | timestamp: Date.now(),
11 | };
12 | }
13 |
14 | public $incoming = new UniqueBehaviorSubject(null);
15 | public $accepted = new UniqueBehaviorSubject(null);
16 |
17 | constructor(private options: Action.IOptions) {
18 | //
19 | }
20 |
21 | public setup(): Subscription {
22 | return this.options && this.options.autoAccept
23 | ? this
24 | .$incoming
25 | .pipe(
26 | filter(action => !!action),
27 | tap(() => this.acceptAction()),
28 | )
29 | .subscribe()
30 | : null;
31 | }
32 |
33 | public acceptAction(action: Action.IAction = null): void {
34 | if (!action) {
35 | action = this.$incoming.value;
36 | if (action) {
37 | this.$incoming.next(null);
38 | }
39 | }
40 |
41 | if (action) {
42 | this.$accepted.next(action);
43 | }
44 | }
45 |
46 | public dismissAction(): void {
47 | this.$incoming.next(null);
48 | this.$accepted.next(null);
49 | }
50 | }
51 |
52 | export namespace Action {
53 | export interface IOptions {
54 | autoAccept?: boolean;
55 | }
56 |
57 | export enum Types {
58 | RequestAddAccountDevice = 'RequestAddAccountDevice',
59 | AccountDeviceAdded = 'AccountDeviceAdded',
60 | RequestSignSecureCode = 'RequestSignSecureCode',
61 | }
62 |
63 | export interface IAction {
64 | type: Types;
65 | payload: T;
66 | timestamp: number;
67 | }
68 |
69 | export interface IRequestAddAccountDevicePayload {
70 | account?: string;
71 | device: string;
72 | callbackEndpoint?: string;
73 | }
74 |
75 | export interface IAccountDeviceAddedPayload {
76 | account: string;
77 | }
78 |
79 | export interface IRequestSignSecureCodePayload {
80 | code: string;
81 | creator: string;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/Help.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Subscription } from 'rxjs';
3 | import MarkdownIt from 'markdown-it';
4 | import { ContextComponent } from '../shared';
5 | import styles from './Help.module.scss';
6 | import help from '../help';
7 |
8 | interface IState {
9 | alias: string;
10 | visible: boolean;
11 | }
12 |
13 | export default class Help extends ContextComponent<{}, IState> {
14 | public state = {
15 | alias: null,
16 | visible: false,
17 | };
18 |
19 | private markdownIt: MarkdownIt = null;
20 | private subscriptions: Subscription[] = [];
21 |
22 | public componentWillMount(): void {
23 | this.markdownIt = new MarkdownIt();
24 | this.subscriptions = [
25 | this
26 | .config
27 | .showHelp$
28 | .subscribe(visible => this.setState({
29 | visible,
30 | })),
31 | this
32 | .help
33 | .stream$
34 | .subscribe(alias => this.setState({
35 | alias,
36 | })),
37 | ];
38 | this.setState({
39 | visible: this.context.config.showHelp,
40 | });
41 | }
42 |
43 | public componentWillUnmount(): void {
44 | for (const subscription of this.subscriptions) {
45 | subscription.unsubscribe();
46 | }
47 | }
48 |
49 | public render() {
50 | const { alias, visible } = this.state;
51 |
52 | if (
53 | !visible ||
54 | !alias ||
55 | !help[alias]
56 | ) {
57 | return null;
58 | }
59 |
60 | const classNames: string[] = [
61 | styles.content,
62 | ];
63 |
64 | switch (this.prefix) {
65 | case 'menu':
66 | classNames.push(styles.menu);
67 | break;
68 | case 'statusBar':
69 | classNames.push(styles.statusBar);
70 | break;
71 | }
72 |
73 | const html = this.markdownIt.render(help[alias].trim());
74 |
75 | return (
76 |
80 | );
81 | }
82 |
83 | private get prefix(): string {
84 | const { alias } = this.state;
85 |
86 | return alias
87 | ? alias.split('.')[0]
88 | : null;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/account/SearchAccount.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (ensName: string, address: string) => `
5 | const options = {
6 | ${address ? `address: "${address}"` : `ensName: ${ensName ? `"${ensName}"` : 'null'}`},
7 | };
8 |
9 | sdk
10 | .searchAccount(options)
11 | .then(account => console.log('account', account))
12 | .catch(console.error);
13 | `;
14 |
15 | interface IState {
16 | ensName: string;
17 | address: string;
18 | }
19 |
20 | export class SearchAccount extends Screen {
21 | public state = {
22 | ensName: '',
23 | address: '',
24 | };
25 |
26 | public componentWillMount(): void {
27 | this.run = this.run.bind(this);
28 |
29 | this.ensNameChanged = this.ensNameChanged.bind(this);
30 | this.addressChanged = this.addressChanged.bind(this);
31 | }
32 |
33 | public renderContent(): any {
34 | const { enabled } = this.props;
35 | const { ensName, address } = this.state;
36 | return (
37 |
38 |
44 |
49 |
54 |
55 |
56 | );
57 | }
58 |
59 | private ensNameChanged(ensName: string): void {
60 | this.setState({
61 | ensName,
62 | });
63 | }
64 |
65 | private addressChanged(address: string): void {
66 | this.setState({
67 | address,
68 | });
69 | }
70 |
71 | private run(): void {
72 | const { ensName, address } = this.state;
73 | this
74 | .logger
75 | .wrapSync('sdk.createAccount', async (console) => {
76 | console.log('account', await this.sdk.searchAccount({
77 | ensName,
78 | address,
79 | }));
80 | });
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountGame/UpdateAccountGame.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (id: number, data: string) => `
5 | const gameId = ${id ? id : 'null'};
6 | const data = ${data ? `'${data}'` : 'null'};
7 |
8 | sdk
9 | .updateAccountGame(gameId, data)
10 | .then(game => console.log('game', game))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | id: string;
16 | idParsed: number;
17 | data: string;
18 | }
19 |
20 | export class UpdateAccountGame extends Screen {
21 | public state = {
22 | id: '0',
23 | idParsed: 0,
24 | data: '',
25 | };
26 |
27 | public componentWillMount(): void {
28 | this.run = this.run.bind(this);
29 |
30 | this.idChanged = this.idChanged.bind(this);
31 | this.dataChanged = this.dataChanged.bind(this);
32 | }
33 |
34 | public renderContent(): any {
35 | const { enabled } = this.props;
36 | const { id, idParsed, data } = this.state;
37 | return (
38 |
39 |
45 |
51 |
56 |
57 |
58 | );
59 | }
60 |
61 | private idChanged(id: string, idParsed: number): void {
62 | this.setState({
63 | id,
64 | idParsed,
65 | });
66 | }
67 |
68 | private dataChanged(data: string): void {
69 | this.setState({
70 | data,
71 | });
72 | }
73 |
74 | private run(): void {
75 | const { idParsed, data } = this.state;
76 | this
77 | .logger
78 | .wrapSync('sdk.updateAccountGame', async (console) => {
79 | console.log('game', await this.sdk.updateAccountGame(idParsed, data));
80 |
81 | this.setState({
82 | data: '',
83 | });
84 | });
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/packages/sdk/src/environments/utils.ts:
--------------------------------------------------------------------------------
1 | import { ContractNames } from '@archanova/contracts';
2 | import { Environment } from '../modules';
3 | import {
4 | SdkEnvironmentNames,
5 | main,
6 | ropsten,
7 | rinkeby,
8 | kovan,
9 | sokol,
10 | xdai,
11 | } from './constants';
12 |
13 | /**
14 | * gets sdk environment by name
15 | * @param name
16 | */
17 | export function getSdkEnvironment(name: SdkEnvironmentNames): Environment {
18 | let result: Environment = null;
19 |
20 | switch (name) {
21 | case SdkEnvironmentNames.Main:
22 | result = main;
23 | break;
24 |
25 | case SdkEnvironmentNames.Ropsten:
26 | result = ropsten;
27 | break;
28 |
29 | case SdkEnvironmentNames.Rinkeby:
30 | result = rinkeby;
31 | break;
32 |
33 | case SdkEnvironmentNames.Kovan:
34 | result = kovan;
35 | break;
36 |
37 | case SdkEnvironmentNames.Sokol:
38 | result = sokol;
39 | break;
40 |
41 | case SdkEnvironmentNames.Xdai:
42 | result = xdai;
43 | break;
44 | }
45 |
46 | return result;
47 | }
48 |
49 | /**
50 | * creates local sdk environment
51 | * @param options
52 | */
53 | export function createLocalSdkEnvironment(options: { host?: string, port?: number } = {}): Environment {
54 | return new Environment({
55 | apiOptions: {
56 | host: options.host || 'localhost',
57 | port: options.port || 8880,
58 | ssl: false,
59 | reconnectTimeout: 3000,
60 | },
61 | ensOptions: {
62 | supportedRootNames: ['archanova.local'],
63 | },
64 | ethOptions: {
65 | networkId: '65280',
66 | gasPrice: '0x77359400',
67 | contractAddresses: {
68 | [ContractNames.AccountProvider]: '0xf254E687aD631A681cC895Dbdca37230D4a6f06C',
69 | [ContractNames.AccountProxy]: '0x12939a4d566e460B7024d38b0A54535c8B282484',
70 | [ContractNames.AccountFriendRecovery]: '0x63636CABbabaDD86D2675110cD469e77Bc87B36A',
71 | [ContractNames.ENSRegistry]: '0xC5dFc16D722a4fa6afA59d94439c74537A4Ee70E',
72 | [ContractNames.VirtualPaymentManager]: '0x5E2355b6522F29D3f0096cA9F4343DB23c243586',
73 | },
74 | },
75 | apiWebSocketConstructor: null,
76 | storageOptions: {
77 | namespace: '@archanova:local',
78 | },
79 | storageAdapter: null,
80 | });
81 | }
82 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/app/GetAppOpenGames.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 | import { mergeMethodArgs } from '../../shared';
4 |
5 | const code = (alias: string, page = 0) => `
6 | const alias = ${alias ? `"${alias}"` : 'null'};
7 | ${page ? `const page = ${page};` : ''}
8 |
9 | sdk
10 | .getAppOpenGames(${mergeMethodArgs('alias', page && 'page')})
11 | .then(games => console.log('games', games))
12 | .catch(console.error);
13 | `;
14 |
15 | interface IState {
16 | alias: string;
17 | page: string;
18 | pageParsed: number;
19 | }
20 |
21 | export class GetAppOpenGames extends Screen {
22 | public state = {
23 | alias: 'tictactoe',
24 | page: '0',
25 | pageParsed: 0,
26 | };
27 |
28 | public componentWillMount(): void {
29 | this.run = this.run.bind(this);
30 |
31 | this.aliasChanged = this.aliasChanged.bind(this);
32 | this.pageChanged = this.pageChanged.bind(this);
33 | }
34 |
35 | public renderContent(): any {
36 | const { enabled } = this.props;
37 | const { alias, page, pageParsed } = this.state;
38 | return (
39 |
40 |
46 |
52 |
58 |
59 |
60 | );
61 | }
62 |
63 | private aliasChanged(alias: string) {
64 | this.setState({
65 | alias,
66 | });
67 | }
68 |
69 | private pageChanged(page: string, pageParsed: number) {
70 | this.setState({
71 | page,
72 | pageParsed,
73 | });
74 | }
75 |
76 | private run(): void {
77 | const { alias, pageParsed } = this.state;
78 | this
79 | .logger
80 | .wrapSync('sdk.getAppOpenGames', async (console) => {
81 | console.log('games', await this.sdk.getAppOpenGames(alias, pageParsed));
82 | });
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/packages/cli/src/containers/DevelopAction.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Box, Color } from 'ink';
3 | import { ContextComponent } from '../context';
4 | import { Spinner } from '../components';
5 | import { SdkService } from '../services';
6 | import Link from 'ink-link';
7 |
8 | interface IState {
9 | app: SdkService.IApp;
10 | oldCallbackUrl: string;
11 | }
12 |
13 | export class DevelopAction extends ContextComponent<{}, IState> {
14 | public state: IState = {
15 | app: null,
16 | oldCallbackUrl: null,
17 | };
18 |
19 | public componentWillMount(): void {
20 | this.exitHandler = this.exitHandler.bind(this);
21 |
22 | const { sdkService, templateService, serverService } = this.context;
23 | let { app } = sdkService.state;
24 | const { callbackUrl: oldCallbackUrl } = app;
25 |
26 | this.wrapAsync(async () => {
27 |
28 | if (!await templateService.templateExists()) {
29 | await templateService.createTemplate(app);
30 | }
31 |
32 | const callbackUrl = await serverService.start();
33 |
34 | app = await sdkService.updateDeveloperApp({
35 | callbackUrl,
36 | });
37 |
38 | this.setState({
39 | app,
40 | oldCallbackUrl,
41 | });
42 |
43 | process.on('SIGINT', this.exitHandler);
44 | });
45 | }
46 |
47 | public componentWillUnmount(): void {
48 | process.removeListener('SIGINT', this.exitHandler);
49 | }
50 |
51 | public render(): any {
52 | const { app } = this.state;
53 | return app
54 | ? (
55 |
56 | Temporary Callback URL
57 | {app.callbackUrl}
58 |
59 | )
60 | : (
61 | Starting Local Server...
62 | );
63 | }
64 |
65 | private exitHandler(): void {
66 | const { sdkService, serverService } = this.context;
67 | const { oldCallbackUrl: callbackUrl } = this.state;
68 |
69 | this.wrapAsync(async () => {
70 |
71 | try {
72 | await sdkService.updateDeveloperApp({
73 | callbackUrl,
74 | });
75 |
76 | await serverService.stop();
77 | } catch (err) {
78 | //
79 | }
80 |
81 | setTimeout(() => {
82 | process.exit();
83 | }, 500);
84 | });
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/packages/cli/src/containers/Summary.tsx:
--------------------------------------------------------------------------------
1 | import { sdkInterfaces, sdkConstants } from '@archanova/sdk';
2 | import { Box, Color } from 'ink';
3 | import React from 'react';
4 | import { ContextComponent } from '../context';
5 | import { SdkService } from '../services';
6 |
7 | interface IState {
8 | account: sdkInterfaces.IAccount;
9 | app: SdkService.IApp;
10 | device: sdkInterfaces.IDevice;
11 | }
12 |
13 | export class Summary extends ContextComponent<{}, IState> {
14 | public state: IState = {
15 | account: null,
16 | app: null,
17 | device: null,
18 | };
19 |
20 | public componentWillMount(): void {
21 | const { sdkService: { state: { app$, account$, device$ } } } = this.context;
22 |
23 | this.addSubscriptions(
24 | app$
25 | .subscribe(app => this.setState({
26 | app,
27 | })),
28 | account$
29 | .subscribe(account => this.setState({
30 | account,
31 | })),
32 | device$
33 | .subscribe(device => this.setState({
34 | device,
35 | })),
36 | );
37 | }
38 |
39 | public componentWillUnmount(): void {
40 | super.componentWillUnmount();
41 | }
42 |
43 | public render(): any {
44 | const { app, account, device } = this.state;
45 |
46 | return (
47 |
48 | {!device ? null : (
49 |
50 |
51 | {'Device '}
52 |
53 | {device.address}
54 |
55 | )}
56 | {!account ? null : (
57 |
58 |
59 | {'Account '}
60 |
61 | {account.address}
62 | {account.type === sdkConstants.AccountTypes.Developer ? null : (
63 |
64 | {' (Non-Developer)'}
65 |
66 | )}
67 |
68 | )}
69 | {!app ? null : (
70 |
71 |
72 | {'Application '}
73 |
74 | {app.name}
75 |
76 | {` (${app.alias})`}
77 |
78 |
79 | )}
80 |
81 | );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/global/Reset.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputCheckBox } from '../../components';
3 |
4 | const code1 = () => `
5 | sdk
6 | .reset()
7 | .then(() => console.log('reseted'))
8 | .catch(console.error);
9 | `;
10 |
11 | const code2 = (device: boolean, session: boolean) => `
12 | const options = {
13 | ${`
14 | ${device ? 'device: true,' : ''}
15 | ${session ? ' session: true,' : ''}
16 | `.trim()}
17 | };
18 |
19 | sdk
20 | .reset(options)
21 | .then(() => console.log('reseted'))
22 | .catch(console.error);
23 | `;
24 |
25 | interface IState {
26 | device: boolean;
27 | session: boolean;
28 | }
29 |
30 | export class Reset extends Screen {
31 | public state = {
32 | device: false,
33 | session: false,
34 | };
35 |
36 | public componentWillMount(): void {
37 | this.run = this.run.bind(this);
38 |
39 | this.deviceChanged = this.deviceChanged.bind(this);
40 | this.sessionChanged = this.sessionChanged.bind(this);
41 | }
42 |
43 | public renderContent(): any {
44 | const { enabled } = this.props;
45 | const { device, session } = this.state;
46 | return (
47 |
48 |
57 |
62 |
67 |
68 |
69 | );
70 | }
71 |
72 | private deviceChanged(device: boolean): void {
73 | this.setState({
74 | device,
75 | });
76 | }
77 |
78 | private sessionChanged(session: boolean): void {
79 | this.setState({
80 | session,
81 | });
82 | }
83 |
84 | private run(): void {
85 | const { device, session } = this.state;
86 | this
87 | .logger
88 | .wrapSync('sdk.reset', async (console) => {
89 | await this.sdk.reset({
90 | device,
91 | session,
92 | });
93 |
94 | console.log('reseted');
95 | });
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/packages/cli/src/containers/DeployAction.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { SdkError } from '@archanova/sdk';
3 | import { Box } from 'ink';
4 | import { Form } from '../components';
5 | import { ContextComponent } from '../context';
6 | import { SdkService } from '../services';
7 | import { Completed } from './Completed';
8 |
9 | interface IState {
10 | app: SdkService.IApp;
11 | errors: { [key: string]: any };
12 | completed: boolean;
13 | }
14 |
15 | export class DeployAction extends ContextComponent<{}, IState> {
16 | public state: IState = {
17 | errors: {},
18 | app: null,
19 | completed: false,
20 | };
21 |
22 | public componentWillMount(): void {
23 | this.formSubmitted = this.formSubmitted.bind(this);
24 |
25 | const { sdkService: { state: { app } } } = this.context;
26 |
27 | this.setState({
28 | app,
29 | });
30 | }
31 |
32 | public render(): any {
33 | let result: React.ReactNode = null;
34 | const { app, completed, errors } = this.state;
35 |
36 | if (completed) {
37 | result = (
38 |
39 | );
40 | } else if (app) {
41 | result = (
42 |
43 |
58 |
59 | );
60 | }
61 |
62 | return result;
63 | }
64 |
65 | private formSubmitted(values: any): void {
66 | const { sdkService } = this.context;
67 |
68 | this.wrapAsync(async () => {
69 | try {
70 | const app = await sdkService.updateDeveloperApp(values);
71 |
72 | this.setState({
73 | app,
74 | completed: true,
75 | });
76 | } catch (err) {
77 | if (
78 | SdkError.isSdkError(err) &&
79 | err.type === SdkError.Types.Http &&
80 | err.data
81 | ) {
82 | this.setState({
83 | errors: err.data,
84 | });
85 | }
86 | }
87 | });
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountGame/GetConnectedAccountGames.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 | import { mergeMethodArgs } from '../../shared';
4 |
5 | const code = (appAlias: string, page = 0) => `
6 | const appAlias = ${appAlias ? `"${appAlias}"` : 'null'};
7 | ${page ? `const page = ${page};` : ''}
8 |
9 | sdk
10 | .getConnectedAccountGames(${mergeMethodArgs('appAlias', page && 'page')})
11 | .then(games => console.log('games', games))
12 | .catch(console.error);
13 | `;
14 |
15 | interface IState {
16 | appAlias: string;
17 | page: string;
18 | pageParsed: number;
19 | }
20 |
21 | export class GetConnectedAccountGames extends Screen {
22 | public state = {
23 | appAlias: 'tictactoe',
24 | page: '0',
25 | pageParsed: 0,
26 | };
27 |
28 | public componentWillMount(): void {
29 | this.run = this.run.bind(this);
30 |
31 | this.appAliasChanged = this.appAliasChanged.bind(this);
32 | this.pageChanged = this.pageChanged.bind(this);
33 | }
34 |
35 | public renderContent(): any {
36 | const { enabled } = this.props;
37 | const { appAlias, page, pageParsed } = this.state;
38 | return (
39 |
40 |
46 |
52 |
58 |
59 |
60 | );
61 | }
62 |
63 | private appAliasChanged(appAlias: string) {
64 | this.setState({
65 | appAlias,
66 | });
67 | }
68 |
69 | private pageChanged(page: string, pageParsed: number) {
70 | this.setState({
71 | page,
72 | pageParsed,
73 | });
74 | }
75 |
76 | private run(): void {
77 | const { appAlias, pageParsed } = this.state;
78 | this
79 | .logger
80 | .wrapSync('sdk.getConnectedAccountGames', async (console) => {
81 | console.log('games', await this.sdk.getConnectedAccountGames(appAlias, pageParsed));
82 | });
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/packages/cli/src/containers/AuthAction.tsx:
--------------------------------------------------------------------------------
1 | import { sdkInterfaces, sdkConstants } from '@archanova/sdk';
2 | import React from 'react';
3 | import { Box, Color } from 'ink';
4 | import TextInput from 'ink-text-input';
5 | import { QrCode } from '../components';
6 | import { ContextComponent } from '../context';
7 |
8 | interface IState {
9 | account: sdkInterfaces.IAccount;
10 | url: string;
11 | code: string;
12 | }
13 |
14 | export class AuthAction extends ContextComponent<{}, IState> {
15 | public state: IState = {
16 | account: null,
17 | url: null,
18 | code: '',
19 | };
20 |
21 | public componentWillMount(): void {
22 | const { sdkService } = this.context;
23 |
24 | this.addSubscriptions(
25 | sdkService
26 | .state
27 | .account$
28 | .subscribe(account => this.setState({
29 | account,
30 | url: account ? null : sdkService.createRequestAddAccountDeviceUrl(),
31 | })),
32 | );
33 |
34 | this.codeChanged = this.codeChanged.bind(this);
35 | this.codeSubmitted = this.codeSubmitted.bind(this);
36 | }
37 |
38 | public componentWillUnmount(): void {
39 | super.componentWillUnmount();
40 | }
41 |
42 | public render(): any {
43 | let result: React.ReactNode = null;
44 |
45 | const { url, account, code } = this.state;
46 |
47 | if (account && account.type !== sdkConstants.AccountTypes.Developer) {
48 | result = (
49 |
50 |
51 | Developer Program Invitation Code
52 |
53 |
58 |
59 | );
60 | } else if (url) {
61 | result = (
62 |
63 |
64 |
65 | );
66 | }
67 |
68 | return result;
69 | }
70 |
71 | private codeChanged(code: string): void {
72 | this.setState({
73 | code,
74 | });
75 | }
76 |
77 | private codeSubmitted(): void {
78 | const { code } = this.state;
79 | const { sdkService } = this.context;
80 |
81 | if (!code) {
82 | return;
83 | }
84 |
85 | this.setState({
86 | code: '',
87 | }, () => this.wrapAsync(async () => {
88 | await sdkService.becomeDeveloper(code);
89 | }));
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/shared/utils.ts:
--------------------------------------------------------------------------------
1 | import BN from 'bn.js';
2 | import { createLocalSdkEnvironment, getSdkEnvironment, SdkEnvironmentNames, sdkModules } from '@archanova/sdk';
3 | import { anyToHex, generateRandomPrivateKey, privateKeyToAddress, weiToEth } from '@netgum/utils';
4 | import { config } from '../config';
5 |
6 | export function buildSdkEnv(name: string): sdkModules.Environment {
7 | let result: sdkModules.Environment;
8 |
9 | if (name === 'local') {
10 | result = createLocalSdkEnvironment({
11 | port: config.localSdkEnvPort,
12 | });
13 | } else {
14 | result = getSdkEnvironment(name as SdkEnvironmentNames);
15 | }
16 |
17 | return result
18 | .setConfig('storageAdapter', localStorage as sdkModules.Storage.IAdapter)
19 | .setConfig('urlAdapter', {
20 | open(url: string): any {
21 | document.location = url as any;
22 | },
23 | addListener(listener: (url: string) => any): void {
24 | listener(document.location.toString());
25 | },
26 | })
27 | .extendConfig('actionOptions', {
28 | autoAccept: config.autoAcceptSdkActions,
29 | });
30 | }
31 |
32 | export function generateRandomAddress() {
33 | return privateKeyToAddress(
34 | generateRandomPrivateKey(),
35 | );
36 | }
37 |
38 | export function generateRandomEnsLabel() {
39 | const hash1 = Date.now().toString(32);
40 | const hash2 = Math.floor(Math.random() * 100000).toString(32);
41 | return (
42 | `playground${hash1}${hash2}`
43 | );
44 | }
45 |
46 | export function getCurrentEndpoint() {
47 | return document.location.origin;
48 | }
49 |
50 | export function formatBalance(balance: BN): string {
51 | return balance
52 | ? `${weiToEth(balance).toFixed(6)} ETH`
53 | : '-';
54 | }
55 |
56 | export function mergeMethodArgs(...args: any[]): string {
57 | return args
58 | .filter(arg => !!arg)
59 | .map(arg => `${arg}`)
60 | .join(', ');
61 | }
62 |
63 | function jsonReplacer(key: string, value: any): any {
64 | const data = this[key];
65 |
66 | if (
67 | Buffer.isBuffer(data) ||
68 | BN.isBN(data)
69 | ) {
70 | const hash = anyToHex(data, {
71 | add0x: true,
72 | });
73 | const label = Buffer.isBuffer(data) ? 'Buffer' : 'BN';
74 |
75 | value = `${label}: ${hash}`;
76 | }
77 |
78 | return value;
79 | }
80 |
81 | export function toRawObject(data: any): any {
82 | return JSON.parse(
83 | JSON.stringify(data, jsonReplacer),
84 | );
85 | }
86 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountTransaction/GetConnectedAccountTransactions.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, InputText, Screen } from '../../components';
3 | import { mergeMethodArgs } from '../../shared';
4 |
5 | const code = (page = 0, hash: string) => `
6 | const hash = ${hash ? `"${hash}"` : 'null'};
7 | ${page ? `const page = ${page};` : ''}
8 |
9 |
10 | sdk
11 | .getConnectedAccountTransactions(${mergeMethodArgs('hash', page && 'page')})
12 | .then(accountTransactions => console.log('accountTransactions', accountTransactions))
13 | .catch(console.error);
14 | `;
15 |
16 | interface IState {
17 | page: string;
18 | pageParsed: number;
19 | hash: string;
20 | }
21 |
22 | export class GetConnectedAccountTransactions extends Screen {
23 | public state = {
24 | hash: '',
25 | page: '0',
26 | pageParsed: 0,
27 | };
28 |
29 | public componentWillMount(): void {
30 | this.run = this.run.bind(this);
31 |
32 | this.hashChanged = this.hashChanged.bind(this);
33 | this.pageChanged = this.pageChanged.bind(this);
34 | }
35 |
36 | public renderContent(): any {
37 | const { enabled } = this.props;
38 | const { page, hash, pageParsed } = this.state;
39 | return (
40 |
41 |
47 |
53 |
59 |
60 |
61 | );
62 | }
63 |
64 | private hashChanged(hash: string): void {
65 | this.setState({
66 | hash,
67 | });
68 | }
69 |
70 | private pageChanged(page: string, pageParsed: number) {
71 | this.setState({
72 | page,
73 | pageParsed,
74 | });
75 | }
76 |
77 | private run(): void {
78 | const { hash, pageParsed } = this.state;
79 | this
80 | .logger
81 | .wrapSync('sdk.getConnectedAccountTransactions', async (console) => {
82 | console.log('accountTransactions', await this.sdk.getConnectedAccountTransactions(hash, pageParsed));
83 | });
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountTransaction/GetConnectedAccountTransaction.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 | import { mergeMethodArgs } from '../../shared';
4 |
5 | const code = (hash: string, index = 0) => `
6 | const hash = ${hash ? `"${hash}"` : 'null'};
7 | ${index ? `const index = ${index};` : ''}
8 |
9 | sdk
10 | .getConnectedAccountTransaction(${mergeMethodArgs('hash', index && 'index')})
11 | .then(accountTransaction => console.log('accountTransaction', accountTransaction))
12 | .catch(console.error);
13 | `;
14 |
15 | interface IState {
16 | hash: string;
17 | index: string;
18 | indexParsed: number;
19 | }
20 |
21 | export class GetConnectedAccountTransaction extends Screen {
22 | public state = {
23 | hash: '',
24 | index: '0',
25 | indexParsed: 0,
26 | };
27 |
28 | public componentWillMount(): void {
29 | this.run = this.run.bind(this);
30 |
31 | this.hashChanged = this.hashChanged.bind(this);
32 | this.indexChanged = this.indexChanged.bind(this);
33 | }
34 |
35 | public renderContent(): any {
36 | const { enabled } = this.props;
37 | const { hash, index, indexParsed } = this.state;
38 | return (
39 |
40 |
46 |
52 |
58 |
59 |
60 | );
61 | }
62 |
63 | private hashChanged(hash: string): void {
64 | this.setState({
65 | hash,
66 | });
67 | }
68 | private indexChanged(index: string, indexParsed: number) {
69 | this.setState({
70 | index,
71 | indexParsed,
72 | });
73 | }
74 |
75 | private run(): void {
76 | const { hash, indexParsed } = this.state;
77 | this
78 | .logger
79 | .wrapSync('sdk.getConnectedAccountTransaction', async (console) => {
80 | console.log('accountTransaction', await this.sdk.getConnectedAccountTransaction(hash, indexParsed));
81 | });
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/packages/sdk/src/modules/Storage.ts:
--------------------------------------------------------------------------------
1 | import { jsonReviver, jsonReplacer } from '@netgum/utils';
2 |
3 | export class Storage {
4 | static SEPARATOR = ':';
5 |
6 | constructor(
7 | private options: Storage.IOptions,
8 | private adapter: Storage.IAdapter = null,
9 | ) {
10 | //
11 | }
12 |
13 | public createChild(namespace: string): Storage {
14 | return new Storage({
15 | namespace: this.prepareKey(namespace),
16 | }, this.adapter);
17 | }
18 |
19 | public async getItem(key: string | string[]): Promise {
20 | let result: T = null;
21 |
22 | if (this.adapter) {
23 | try {
24 | const adapterKey = this.prepareKey(key);
25 | const raw: string = await Promise.resolve(this.adapter.getItem(adapterKey));
26 |
27 | if (raw) {
28 | result = JSON.parse(raw, jsonReviver);
29 | }
30 | } catch (err) {
31 | result = null;
32 | }
33 | }
34 |
35 | return result || null;
36 | }
37 |
38 | public async setItem(key: string | string[], item: T): Promise {
39 | if (!item) {
40 | return this.removeItem(key);
41 | }
42 |
43 | if (this.adapter) {
44 | try {
45 | const adapterKey = this.prepareKey(key);
46 | const raw = JSON.stringify(item, jsonReplacer);
47 | await Promise.resolve(this.adapter.setItem(adapterKey, raw));
48 | } catch (err) {
49 | //
50 | }
51 | }
52 | }
53 |
54 | public async removeItem(key: string | string[]): Promise {
55 | if (this.adapter) {
56 | try {
57 | const adapterKey = this.prepareKey(key);
58 | await Promise.resolve(this.adapter.removeItem(adapterKey));
59 | } catch (err) {
60 | //
61 | }
62 | }
63 | }
64 |
65 | private prepareKey(key: string | string[]): string {
66 | const { namespace } = this.options;
67 |
68 | let parts: string[] = Array.isArray(key)
69 | ? key
70 | : [key];
71 |
72 | if (namespace) {
73 | parts = [
74 | namespace,
75 | ...parts,
76 | ];
77 | }
78 |
79 | return parts.join(Storage.SEPARATOR);
80 | }
81 | }
82 |
83 | export namespace Storage {
84 | export interface IOptions {
85 | namespace?: string;
86 | }
87 |
88 | export interface IAdapter {
89 | getItem(key: string): string | Promise;
90 |
91 | setItem(key: string, value: string): void | Promise;
92 |
93 | removeItem(key: string): void | Promise;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/packages/cli/src/services/TemplateService.ts:
--------------------------------------------------------------------------------
1 | import { resolve, join } from 'path';
2 | import { readdir, readFile, writeFile, stat, ensureDir, pathExists } from 'fs-extra';
3 | import { SdkService } from './SdkService';
4 |
5 | export class TemplateService {
6 | private static SRC_DIR = resolve(__dirname, '../../template');
7 |
8 | constructor(private workingPath: string) {
9 | //
10 | }
11 |
12 | public templateExists(): Promise {
13 | return pathExists(
14 | join(this.workingPath, 'package.json'),
15 | );
16 | }
17 |
18 | public async createTemplate(app: SdkService.IApp): Promise {
19 | const fileNames = await readdir(TemplateService.SRC_DIR);
20 | const copyMap: {
21 | src: string;
22 | dest: string;
23 | }[] = [];
24 |
25 | for (const fileName of fileNames) {
26 | const filePath = join(TemplateService.SRC_DIR, fileName);
27 | const fileStat = await stat(filePath);
28 |
29 | if (fileStat.isDirectory()) {
30 | const subFileNames = await readdir(filePath);
31 |
32 | await ensureDir(join(this.workingPath, fileName));
33 |
34 | for (const subFileName of subFileNames) {
35 | const subFilePath = join(filePath, subFileName);
36 | const subFileStat = await stat(subFilePath);
37 |
38 | if (!subFileStat.isDirectory()) {
39 | copyMap.push({
40 | src: subFilePath,
41 | dest: join(this.workingPath, fileName, subFileName),
42 | });
43 | }
44 | }
45 | } else {
46 | copyMap.push({
47 | src: filePath,
48 | dest: join(this.workingPath, fileName),
49 | });
50 | }
51 | }
52 |
53 | for (const { src, dest } of copyMap) {
54 | let content = await readFile(src, 'utf8');
55 |
56 | if (app) {
57 | content = content.replace(
58 | new RegExp('\\$\\{([a-zA-Z\\.]+)\\}', 'ig'),
59 | (result: string, found: string) => {
60 | switch (found) {
61 | case 'app.name':
62 | result = app.name;
63 | break;
64 |
65 | case 'app.description':
66 | result = app.description || '';
67 | break;
68 |
69 | case 'app.alias':
70 | result = app.alias;
71 | break;
72 | }
73 |
74 | return result;
75 | },
76 | );
77 | }
78 |
79 | await writeFile(dest, content, 'utf8');
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountDevice/GetAccountDevice.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (accountAddress: string, deviceAddress: string) => `
5 | const accountAddress = ${accountAddress ? `"${accountAddress}"` : 'null'};
6 | const deviceAddress = ${deviceAddress ? `"${deviceAddress}"` : 'null'};
7 |
8 | sdk
9 | .getAccountDevice(accountAddress, deviceAddress)
10 | .then(accountDevice => console.log('accountDevice', accountDevice))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | accountAddress: string;
16 | deviceAddress: string;
17 | }
18 |
19 | export class GetAccountDevice extends Screen {
20 | public state = {
21 | accountAddress: '',
22 | deviceAddress: '',
23 | };
24 |
25 | public componentWillMount(): void {
26 | this.run = this.run.bind(this);
27 |
28 | this.accountAddressChanged = this.accountAddressChanged.bind(this);
29 | this.deviceAddressChanged = this.deviceAddressChanged.bind(this);
30 | }
31 |
32 | public renderContent(): any {
33 | const { enabled } = this.props;
34 | const { accountAddress, deviceAddress } = this.state;
35 | return (
36 |
37 |
43 |
49 |
55 |
56 |
57 | );
58 | }
59 |
60 | private accountAddressChanged(accountAddress: string): void {
61 | this.setState({
62 | accountAddress,
63 | });
64 | }
65 | private deviceAddressChanged(deviceAddress: string): void {
66 | this.setState({
67 | deviceAddress,
68 | });
69 | }
70 |
71 | private run(): void {
72 | const { accountAddress, deviceAddress } = this.state;
73 | this
74 | .logger
75 | .wrapSync('sdk.getAccountDevice', async (console) => {
76 | console.log('accountDevice', await this.sdk.getAccountDevice(
77 | accountAddress,
78 | deviceAddress,
79 | ));
80 | });
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/packages/cli/src/cli.ts:
--------------------------------------------------------------------------------
1 | import { SdkEnvironmentNames } from '@archanova/sdk';
2 | import { anyToBuffer, verifyPrivateKey } from '@netgum/utils';
3 | import meow from 'meow';
4 | import { resolve } from 'path';
5 | import { Actions, Scopes } from './constants';
6 | import { IConfig } from './interfaces';
7 |
8 | const { input: inputs, flags }: {
9 | input: string[];
10 | flags: {
11 | env: SdkEnvironmentNames | 'local';
12 | global: boolean;
13 | help: boolean;
14 | localEnvHost: string;
15 | localEnvPort: string;
16 | privateKey: string;
17 | };
18 | } = meow({
19 | booleanDefault: false,
20 | autoHelp: false,
21 | autoVersion: false,
22 | flags: {
23 | env: {
24 | type: 'string',
25 | alias: 'e',
26 | default: SdkEnvironmentNames.Main,
27 | },
28 | global: {
29 | type: 'boolean',
30 | alias: 'g',
31 | },
32 | help: {
33 | type: 'boolean',
34 | alias: 'h',
35 | },
36 | localEnvHost: {
37 | type: 'string',
38 | default: null,
39 | },
40 | localEnvPort: {
41 | type: 'string',
42 | default: null,
43 | },
44 | privateKey: {
45 | type: 'string',
46 | default: null,
47 | },
48 | },
49 | });
50 |
51 | const supportedEnvs = [...Object.values(SdkEnvironmentNames), 'local'];
52 | const supportedActions = Object.values(Actions);
53 |
54 | /**
55 | * gets cli config
56 | * @return IConfig
57 | */
58 | export function getCliConfig(): IConfig {
59 | const privateKey: Buffer = anyToBuffer(flags.privateKey, { defaults: null });
60 | let action: Actions = null;
61 | let workingPath = process.cwd();
62 |
63 | for (const input of inputs) {
64 | if (supportedActions.includes(input)) {
65 | action = input as any;
66 | } else {
67 | if (
68 | input.startsWith('/') ||
69 | input.startsWith('.')
70 | ) {
71 | workingPath = resolve(input);
72 | }
73 | break;
74 | }
75 | }
76 |
77 | if (!supportedEnvs.includes(flags.env)) {
78 | throw new Error('Unsupported env'); // TODO: add error handler
79 | }
80 |
81 | if (privateKey && !verifyPrivateKey(privateKey)) {
82 | throw new Error('Invalid private key'); // TODO: add error handler
83 | }
84 |
85 | return {
86 | action,
87 | privateKey,
88 | workingPath,
89 | scope: flags.global ? Scopes.Global : Scopes.Local,
90 | env: flags.env,
91 | localEnv: {
92 | host: flags.localEnvHost,
93 | port: parseInt(flags.localEnvPort, 10) || null,
94 | },
95 | showHelp: !action || flags.help,
96 | };
97 | }
98 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountPayment/GrabAccountPayment.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 | import { generateRandomAddress, mergeMethodArgs } from '../../shared';
4 |
5 | const code = (hash: string, recipient: string) => `
6 | const hash = ${hash ? `"${hash}"` : 'null'};
7 | ${recipient ? `const recipient = "${recipient}";` : ''}
8 |
9 | sdk
10 | .grabAccountPayment(${mergeMethodArgs('hash', recipient && 'recipient')})
11 | .then(accountPayment => console.log('accountPayment', accountPayment))
12 | .catch(console.error);
13 | `;
14 |
15 | interface IState {
16 | hash: string;
17 | recipient: string;
18 | }
19 |
20 | export class GrabAccountPayment extends Screen {
21 | public state = {
22 | hash: '',
23 | recipient: '',
24 | };
25 |
26 | public componentWillMount(): void {
27 | this.run = this.run.bind(this);
28 |
29 | this.hashChanged = this.hashChanged.bind(this);
30 | this.recipientChanged = this.recipientChanged.bind(this);
31 | this.generateRecipient = this.generateRecipient.bind(this);
32 | }
33 |
34 | public renderContent(): any {
35 | const { enabled } = this.props;
36 | const { hash, recipient } = this.state;
37 | return (
38 |
39 |
45 |
51 |
58 |
59 |
60 | );
61 | }
62 |
63 | private hashChanged(hash: string): void {
64 | this.setState({
65 | hash,
66 | });
67 | }
68 |
69 | private recipientChanged(recipient: string): void {
70 | this.setState({
71 | recipient,
72 | });
73 | }
74 |
75 | private generateRecipient(): void {
76 | this.setState({
77 | recipient: generateRandomAddress(),
78 | });
79 | }
80 |
81 | private run(): void {
82 | const { hash, recipient } = this.state;
83 | this
84 | .logger
85 | .wrapSync('sdk.grabAccountPayment', async (console) => {
86 | console.log('accountPayment', await this.sdk.grabAccountPayment(hash, recipient || null));
87 | });
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/StatusBar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ISdkReduxState } from '@archanova/sdk';
3 | import { connect } from 'react-redux';
4 | import { HelpTrigger } from '../components';
5 | import { formatBalance } from '../shared';
6 | import styles from './StatusBar.module.scss';
7 |
8 | interface IProps {
9 | sdk: ISdkReduxState;
10 | }
11 |
12 | class StatusBar extends React.Component {
13 | public render() {
14 | const { sdk: { account, accountDevice, device, eth } } = this.props;
15 | const network = eth && eth.networkName ? eth.networkName : 'Unknown';
16 |
17 | return (
18 |
19 |
20 | Network
21 | {network}
22 |
23 | {!account || !accountDevice ? null : (
24 |
25 |
26 | Account Address
27 | {account ? account.address : 'Unknown'}
28 |
29 |
30 | Account State
31 | {account ? account.state : 'Unknown'}
32 |
33 |
34 | Account Balance (real)
35 |
36 | {formatBalance(account && account.balance.real ? account.balance.real : null)}
37 |
38 |
39 |
40 | Account Balance (virtual)
41 |
42 | {formatBalance(account && account.balance.virtual ? account.balance.virtual : null)}
43 |
44 |
45 |
46 | Account Device State
47 | {accountDevice ? accountDevice.state : 'None'}
48 |
49 |
50 | )}
51 |
52 | Device Address
53 | {device ? device.address : 'Unknown'}
54 |
55 |
56 | );
57 | }
58 | }
59 |
60 | export default connect(
61 | state => state,
62 | )(StatusBar);
63 |
--------------------------------------------------------------------------------
/packages/sdk-playground/src/containers/accountFriendRecovery/CollectAccountFriendSignature.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Example, Screen, InputText } from '../../components';
3 |
4 | const code = (friendAddress: string, friendSignature: string) => `
5 | const friendAddress = ${friendAddress ? `"${friendAddress}"` : 'null'};
6 | const friendSignature = ${friendSignature ? `"${friendSignature}"` : 'null'};
7 |
8 | sdk
9 | .collectAccountFriendSignature(friendAddress, friendSignature)
10 | .then(accountFriendRecovery => console.log('accountFriendRecovery', accountFriendRecovery))
11 | .catch(console.error);
12 | `;
13 |
14 | interface IState {
15 | friendAddress: string;
16 | friendSignature: string;
17 | }
18 |
19 | export class CollectAccountFriendSignature extends Screen {
20 | public state = {
21 | friendAddress: '',
22 | friendSignature: '',
23 | };
24 |
25 | public componentWillMount(): void {
26 | this.run = this.run.bind(this);
27 |
28 | this.friendAddressChanged = this.friendAddressChanged.bind(this);
29 | this.friendSignatureChanged = this.friendSignatureChanged.bind(this);
30 | }
31 |
32 | public renderContent(): any {
33 | const { enabled } = this.props;
34 | const { friendAddress, friendSignature } = this.state;
35 | return (
36 |
37 |
43 |
49 |
55 |
56 |
57 | );
58 | }
59 |
60 | private friendAddressChanged(friendAddress: string): void {
61 | this.setState({
62 | friendAddress,
63 | });
64 | }
65 |
66 | private friendSignatureChanged(friendSignature: string): void {
67 | this.setState({
68 | friendSignature,
69 | });
70 | }
71 |
72 | private run(): void {
73 | const { friendAddress, friendSignature } = this.state;
74 | this
75 | .logger
76 | .wrapSync('sdk.collectAccountFriendSignature', async (console) => {
77 | console.log('accountFriendRecovery', await this.sdk.collectAccountFriendSignature(
78 | friendAddress,
79 | friendSignature,
80 | ));
81 | });
82 | }
83 | }
84 |
--------------------------------------------------------------------------------