Skip to content

Commit

Permalink
Made private keys optional in Accounts. Added a ContractLoader so you…
Browse files Browse the repository at this point in the history
… can get a reference to an already deployed contract. Made EOS Manager more configurable so you can connect to other endpoints and chains.
  • Loading branch information
thekevinbrown committed May 17, 2019
1 parent bdebc8d commit 8adf7ce
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 32 deletions.
25 changes: 14 additions & 11 deletions src/accounts/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,28 @@ export class Account {
/** EOSIO account name */
public name: string;
/** EOSIO account public key */
public publicKey: string;
public publicKey?: string;
/** EOSIO account private key */
public privateKey: string;
public privateKey?: string;
/** EOSIO account permissions */
public permissions: Permissions;

constructor(name: string, privateKey: string, publicKey?: string) {
constructor(name: string, privateKey?: string, publicKey?: string) {
// Store references
this.name = name;
this.privateKey = privateKey;

this.publicKey = ecc.privateToPublic(privateKey);
if (privateKey) {
this.privateKey = privateKey;

if (publicKey && publicKey !== this.publicKey) {
throw new Error(
`Supplied public key does not match private key. Supplied key: ${publicKey} Expected key: ${ecc.privateToPublic(
privateKey
)} This is usually caused by using the legacy key format vs the new style key format.`
);
this.publicKey = ecc.privateToPublic(privateKey);

if (publicKey && publicKey !== this.publicKey) {
throw new Error(
`Supplied public key does not match private key. Supplied key: ${publicKey} Expected key: ${ecc.privateToPublic(
privateKey
)} This is usually caused by using the legacy key format vs the new style key format.`
);
}
}

// Set default permissions
Expand Down
27 changes: 15 additions & 12 deletions src/contracts/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ export interface ContractActionOptions {
from?: Account;
}

export interface ContractConstructorArgs {
eos: Api;
identifier?: string;
account: Account;
abi: Abi;
actions: Map<string, Type>;
types: Map<string, Type>;
}

/**
* Adds additional functionality to the EOSJS `Contract` class
*/
Expand All @@ -22,8 +31,9 @@ export class Contract implements EOSJSContract {
private _eos: Api;
/** @hidden Current contract account */
private _account: Account;
/** @hidden Contract identifier. Typically the contract file name minus the extension */
private _identifier: string;
/** @hidden Contract identifier. Typically the contract file name minus the extension.
* Can be undefined when the contract is loaded as already deployed and we're never given an indentifier to map it back to. */
private _identifier?: string;
/** @hidden Current contract ABI */
private _abi: Abi;
/** Deployed contract actions */
Expand All @@ -36,7 +46,7 @@ export class Contract implements EOSJSContract {
* @author Kevin Brown <github.com/thekevinbrown>
* @returns Current contract account
*/
public get account(): Account {
public get account() {
return this._account;
}

Expand All @@ -45,18 +55,11 @@ export class Contract implements EOSJSContract {
* @author Kevin Brown <github.com/thekevinbrown>
* @returns Contract identifier
*/
public get identifier(): string {
public get identifier() {
return this._identifier;
}

constructor(
eos: Api,
identifier: string,
account: Account,
abi: Abi,
actions: Map<string, Type>,
types: Map<string, Type>
) {
constructor({ eos, identifier, account, abi, actions, types }: ContractConstructorArgs) {
// Store contract arguments
this._eos = eos;
this._identifier = identifier;
Expand Down
17 changes: 12 additions & 5 deletions src/contracts/contractDeployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Contract } from './contract';
import { Account, AccountManager } from '../accounts';
import { EOSManager } from '../eosManager';
import { ConfigManager } from '../configManager';
import { ContractLoader } from './contractLoader';

/**
* Provides a set of methods to manage contract deployment
Expand Down Expand Up @@ -89,10 +90,8 @@ export class ContractDeployer {
},
],
});
// Fetch the contract actions and types
const { actions, types } = await EOSManager.api.getContract(account.name);
// Return our newly deployed contract instance
return new Contract(EOSManager.api, contractIdentifier, account, abi, actions, types) as T;

return await ContractLoader.at<T>(account);
}

/**
Expand Down Expand Up @@ -122,7 +121,7 @@ export class ContractDeployer {
* ContractDeployer.deployWithName<MyContractTypeDef>('mycontract', 'mycontractname');
* ```
*
* @note Generating a random private key is not safe in the cryptographic sense. It can be used for testing.
* @note Generating a pseudorandom private key is not safe in the cryptographic sense. It can be used for testing.
* @author Mitch Pierias <github.com/MitchPierias>
* @param contractIdentifier Contract identifier, typically the contract filename minus the extension
* @param accountName Account name
Expand All @@ -137,8 +136,16 @@ export class ContractDeployer {

// Initialize account with name
const account = new Account(accountName, privateKey);

console.log('Created account:');
console.log(`Name: ${accountName}`);
console.log(`Private Key: ${privateKey}`);

console.log('Setting up account');
await AccountManager.setupAccount(account);

console.log('Success');

// Call the deployToAccount method with the account
return await ContractDeployer.deployToAccount<T>(contractIdentifier, account);
}
Expand Down
37 changes: 37 additions & 0 deletions src/contracts/contractLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Contract } from './contract';
import { Account } from '../accounts';
import { EOSManager } from '../eosManager';

/**
* Provides a set of methods to create contract references for already existing contracts
*/
export class ContractLoader {
/**
* Loads a contract instance for a contract which is already deployed to the blockchain.
*
* ```typescript
* ContractLoader.at<MyContractTypeDef>('mycontract');
* ```
* @author Kevin Brown <github.com/thekevinbrown>
* @param accountName The account name where the contract is already deployed.
* @returns Contract instance
*/
public static async at<T extends Contract>(account: Account) {
// Load the ABI from the blockchain.
const { abi } = await EOSManager.rpc.get_abi(account.name);

if (!abi) throw new Error(`Could not load ABI for contract at '${account.name}'.`);

// Fetch the contract actions and types
const { actions, types } = await EOSManager.api.getContract(account.name);

// Return our newly deployed contract instance
return new Contract({
eos: EOSManager.api,
account,
abi,
actions,
types,
}) as T;
}
}
1 change: 1 addition & 0 deletions src/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './contract';
export * from './contractDeployer';
export * from './contractLoader';
export * from './tableRowsResult';
export * from './typeGenerator';
36 changes: 32 additions & 4 deletions src/eosManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig';
import { Account } from './accounts';
import { ConfigManager } from './configManager';

interface InitArgs {
adminAccount: Account;
chainId?: string;
httpEndpoint: string;
}

/**
* Manages client connection and communication with a local EOSIO node
*/
Expand All @@ -25,14 +31,36 @@ export class EOSManager {
*/
static initWithDefaults = () => {
// Create eosio account and configure signature provider
const adminPrivateKey = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3';
EOSManager.adminAccount = new Account('eosio', adminPrivateKey);
EOSManager.signatureProvider = new JsSignatureProvider([adminPrivateKey]);
// NOTE: This is a known EOS development key used in the EOS docs. It is
// UNSAFE to use this key on any public network.
const adminAccount = new Account(
'eosio',
'5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3'
);

EOSManager.init({ httpEndpoint: 'http://127.0.0.1:8888', adminAccount });
};
/**
* Initializes a connection to any EOSIO node and sets the administration keys which
* Lamington uses to deploy contracts, create accounts, etc.
* @author Kevin Brown <github.com/thekevinbrown>
* @example
*/
static init = ({ httpEndpoint, adminAccount, chainId }: InitArgs) => {
// Create eosio account and configure signature provider
EOSManager.adminAccount = adminAccount;

// If we have a key to sign with, go ahead and hook it up.
if (adminAccount.privateKey) {
EOSManager.signatureProvider = new JsSignatureProvider([adminAccount.privateKey]);
}

// Typecasting as any here to prevent a problem with the types disagreeing for fetch,
// when this is actually following the getting started docs on EOSJS.
EOSManager.rpc = new JsonRpc('http://127.0.0.1:8888', { fetch: fetch as any });
EOSManager.rpc = new JsonRpc(httpEndpoint, { fetch: fetch as any });
EOSManager.api = new Api({
rpc: EOSManager.rpc,
chainId,
signatureProvider: EOSManager.signatureProvider,
// Same deal here, type mismatch when there really shouldn't be.
textDecoder: new TextDecoder() as any,
Expand Down

0 comments on commit 8adf7ce

Please sign in to comment.