Skip to content

Commit

Permalink
Merge 9ebcc1d into de6aff0
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyar committed Aug 29, 2021
2 parents de6aff0 + 9ebcc1d commit c51f928
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 89 deletions.
103 changes: 49 additions & 54 deletions src/account.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
import * as seed from 'near-seed-phrase'
import * as api from 'near-api-js'
import * as path from 'path'
import * as os from 'os'
import BN from 'bn.js'
import * as connect from './connect'
import * as config from './config'
import * as transaction from './transaction'
import * as provider from 'near-api-js/lib/providers/provider'
import {
KeyPair as APIKeyPair,
} from 'near-api-js/lib/utils/key_pair'
generateSeedPhrase,
parseSeedPhrase,
} from 'near-seed-phrase'
import {
KeyPair as NearKeyPair,
} from 'near-api-js'
import {
Account as NearAccount,
} from 'near-api-js'
import BN from 'bn.js'
import {
PublicKey,
} from 'near-api-js/src/utils/key_pair'
KeyPairEd25519,
} from 'near-api-js/lib/utils'
import {
AccountView,
} from 'near-api-js/lib/providers/provider'
import {
newConnect,
parseNetworkId,
parseAccountId,
parsePrivateKey,
} from './connect'
import {
Environment,
environment,
} from './config'
import {
toYocto,
} from './util'
import {
Outcome,
transactionOutcome,
} from './transaction'

const CREDENTIALS_DIR = '.near-credentials'

export interface KeyPair extends APIKeyPair {
export interface KeyPair extends NearKeyPair {
readonly publicKey: PublicKey
readonly secretKey: string
}
Expand All @@ -30,19 +45,19 @@ export interface AccountNetwork {
keyPair: KeyPair
}

export async function deleteAccount(pruneAccount: AccountNetwork, beneficiary?: AccountNetwork): Promise<transaction.Outcome<boolean>> {
export async function deleteAccount(pruneAccount: AccountNetwork, beneficiary?: AccountNetwork): Promise<Outcome<boolean>> {
beneficiary = beneficiary || parseAccountNetwork()
const account = await accountConnect(pruneAccount)
return account.deleteAccount(beneficiary.accountId)
.then(outcome => transaction.transactionOutcome(outcome))
.then(outcome => transactionOutcome(outcome))
}

export async function accountConnect(account: AccountNetwork): Promise<api.Account> {
const near = await connect.newConnect(account)
export async function accountConnect(account: AccountNetwork): Promise<NearAccount> {
const near = await newConnect(account)
return near.account(account.accountId)
}

export async function stateAccount(accountNetwork: AccountNetwork): Promise<provider.AccountView> {
export async function stateAccount(accountNetwork: AccountNetwork): Promise<AccountView> {
const account = await accountConnect(accountNetwork)
return account.state()
}
Expand All @@ -52,8 +67,7 @@ export async function isExistAccount(accountNetwork: AccountNetwork): Promise<bo
}

export function accountIdBySlug(slug: string, networkId?: string): string {
const environment = config.environment(networkId)
return `${slug}.${environment.helperAccount}`
return `${slug}.${environment(networkId).helperAccount}`
}

export function custodianAccountBySlug(slug: string, custodian?: AccountNetwork): AccountNetwork {
Expand All @@ -69,20 +83,20 @@ export function custodianAccount(accountId: string, custodian?: AccountNetwork):
}
}

export async function createCustodianAccountBySlug(slug: string, amount = '0.05', custodian?: AccountNetwork): Promise<transaction.Outcome<boolean>> {
export async function createCustodianAccountBySlug(slug: string, amount = '0.05', custodian?: AccountNetwork): Promise<Outcome<boolean>> {
return createCustodianAccount(accountIdBySlug(slug), amount, custodian)
}

export async function createCustodianAccount(accountId: string, amount = '0.05', custodian?: AccountNetwork): Promise<transaction.Outcome<boolean>> {
export async function createCustodianAccount(accountId: string, amount = '0.05', custodian?: AccountNetwork): Promise<Outcome<boolean>> {
custodian = custodian || parseAccountNetwork()
const newAccount = custodianAccount(accountId, custodian)
return createAccount(custodian, newAccount, amount)
}

export async function createAccount(creator: AccountNetwork, newAccount: AccountNetwork, amount = '0.05'): Promise<transaction.Outcome<boolean>> {
const near = await connect.newConnect(creator)
export async function createAccount(creator: AccountNetwork, newAccount: AccountNetwork, amount = '0.05'): Promise<Outcome<boolean>> {
const near = await newConnect(creator)
const creatorAccount = await near.account(creator.accountId)
const config = <config.Environment>near.config
const config = <Environment>near.config
const publicKey = newAccount.keyPair.publicKey.toString()
return creatorAccount.functionCall({
contractId: config.helperAccount,
Expand All @@ -93,38 +107,19 @@ export async function createAccount(creator: AccountNetwork, newAccount: Account
},
gas: new BN('300000000000000'),
attachedDeposit: toYocto(amount),
}).then(outcome => transaction.transactionOutcome(outcome))
}

export function credentialsPath(): string {
return path.resolve(process.env.NEAR_CREDENTIALS_PATH || path.join(os.homedir(), CREDENTIALS_DIR))
}).then(outcome => transactionOutcome(outcome))
}

export function parseAccountNetwork(accountId?: string, encodedKey?: string, networkId?: string): AccountNetwork {
const account = <AccountNetwork>{}
account.networkId = connect.parseNetworkId(networkId)
account.accountId = connect.parseAccountId(accountId)
account.keyPair = <api.utils.KeyPairEd25519>api.KeyPair.fromString(connect.parsePrivateKey(encodedKey))
return account
}

export async function readUnencryptedFileSystemKeyStore(accountId: string, networkId?: string): Promise<AccountNetwork> {
const account = <AccountNetwork>{
accountId
}
const keyStore = new api.keyStores.UnencryptedFileSystemKeyStore(credentialsPath())
account.networkId = connect.parseNetworkId(networkId)
account.keyPair = <api.utils.KeyPairEd25519>await keyStore.getKey(account.networkId, account.accountId)
account.networkId = parseNetworkId(networkId)
account.accountId = parseAccountId(accountId)
account.keyPair = <KeyPairEd25519>NearKeyPair.fromString(parsePrivateKey(encodedKey))
return account
}

export async function writeUnencryptedFileSystemKeyStore(account: AccountNetwork): Promise<void> {
const keyStore = new api.keyStores.UnencryptedFileSystemKeyStore(credentialsPath())
return keyStore.setKey(account.networkId, account.accountId, account.keyPair)
}

export function generateMnemonic(entropy?: Buffer): string {
return seed.generateSeedPhrase(entropy).seedPhrase
return generateSeedPhrase(entropy).seedPhrase
}

export function generateAccountByEntropy(entropy?: Buffer, accountId?: string, networkId?: string): AccountNetwork {
Expand All @@ -136,18 +131,18 @@ export function generateAccount(accountId?: string, networkId?: string): Account
}

export function mnemonicToAccount(phrase: string, accountId?: string, networkId?: string): AccountNetwork {
const mnemonic = seed.parseSeedPhrase(phrase)
const mnemonic = parseSeedPhrase(phrase)
return secretKeyToAccount(mnemonic.secretKey, accountId, networkId)
}

export function secretKeyToAccount(encodedKey: string, accountId?: string, networkId?: string): AccountNetwork {
return keyPairToAccount(<KeyPair>api.KeyPair.fromString(encodedKey), accountId, networkId)
return keyPairToAccount(<KeyPair>NearKeyPair.fromString(encodedKey), accountId, networkId)
}

export function keyPairToAccount(keyPair: KeyPair, accountId?: string, networkId?: string): AccountNetwork {
const account = <AccountNetwork>{}
account.keyPair = keyPair
account.networkId = connect.parseNetworkId(networkId)
account.networkId = parseNetworkId(networkId)
if (accountId) {
account.accountId = accountId
} else {
Expand Down
6 changes: 4 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as connect from './connect'
import {
parseNetworkId,
} from './connect'

export interface Environment {
networkId: string,
Expand Down Expand Up @@ -40,7 +42,7 @@ function localEnvironment(port?:EnvironmentPort): Environment {
}

export function environment(name?: string): Environment {
name = connect.parseNetworkId(name)
name = parseNetworkId(name)
switch (name) {
case 'production':
case 'mainnet':
Expand Down
33 changes: 22 additions & 11 deletions src/connect.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import * as api from 'near-api-js'
import * as config from './config'
import * as account from './account'
import {
Near,
ConnectConfig,
connect,
KeyPair as NearKeyPair,
Account,
} from 'near-api-js'
import {
InMemoryKeyStore,
} from 'near-api-js/lib/key_stores'
import {
Action,
} from 'near-api-js/src/transaction'
import {
environment,
} from './config'
import {
AccountNetwork,
} from './account'
import {
Outcome,
transactionOutcome,
} from './transaction'

export interface ConnectParam {
networkId?: string
accountId?: string
Expand All @@ -29,7 +40,7 @@ export function parsePrivateKey(encodedKey?: string): string {
return encodedKey || process.env.NEAR_SENDER_PRIVATE_KEY || ''
}

export async function connectConfigByAccount(account: account.AccountNetwork): Promise<api.ConnectConfig> {
export async function connectConfigByAccount(account: AccountNetwork): Promise<ConnectConfig> {
const param = <ConnectParam>{
networkId: account.networkId,
accountId: account.accountId,
Expand All @@ -38,7 +49,7 @@ export async function connectConfigByAccount(account: account.AccountNetwork): P
return connectConfigByParam(param)
}

export async function connectConfigByParam(param?: ConnectParam): Promise<api.ConnectConfig> {
export async function connectConfigByParam(param?: ConnectParam): Promise<ConnectConfig> {
param = param || <ConnectParam>{}
param.networkId = parseNetworkId(param.networkId)
param.accountId = parseAccountId(param.accountId)
Expand All @@ -47,20 +58,20 @@ export async function connectConfigByParam(param?: ConnectParam): Promise<api.Co
if (!param.encodedKey || !param.accountId) {
throw new Error('Error: empty encodedKey or accountId')
}
const keyStore = new api.keyStores.InMemoryKeyStore()
const keyPair = api.KeyPair.fromString(param.encodedKey)
const keyStore = new InMemoryKeyStore()
const keyPair = NearKeyPair.fromString(param.encodedKey)
await keyStore.setKey(param.networkId, param.accountId, keyPair)
return {
keyStore,
...config.environment(param.networkId),
...environment(param.networkId),
}
}

export async function newConnect(account: account.AccountNetwork): Promise<api.Near> {
return api.connect(await connectConfigByAccount(account))
export async function newConnect(account: AccountNetwork): Promise<Near> {
return connect(await connectConfigByAccount(account))
}

export async function newAccountConnect(account: account.AccountNetwork): Promise<AccountConnect> {
export async function newAccountConnect(account: AccountNetwork): Promise<AccountConnect> {
const near = await newConnect(account)
return new AccountConnect(near.connection, account.accountId)
}
Expand Down
13 changes: 13 additions & 0 deletions src/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,16 @@ test('deploy and init', async () => {
expect(toNear(state.amount)).toBeGreaterThanOrEqual(9)
expect(result.outcome.value).toEqual('')
})

test('deploy enough balance to cover storage', async () => {
const code = await near.fetchContract('contract.paras.near', 'mainnet')
expect(code).toBeTruthy()
const accountId = `contract${+ new Date}`
const contract = near.generateAccount(accountId)
try {
await near.deployContract<boolean>(contract, code)
expect(true).toBe(false)
} catch (e) {
expect(e.message).toContain('wouldn\'t have enough balance to cover storage, required to have 384530000000000000000000 yoctoNEAR more')
}
})
35 changes: 20 additions & 15 deletions src/contract.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as api from 'near-api-js'
import * as config from './config'
import * as util from './util'
import {
toGas,
toYocto,
} from './util'
import * as provider from 'near-api-js/lib/providers/provider'
FunctionCallOptions,
} from 'near-api-js/lib/account'
import {
ContractCodeView,
} from 'near-api-js/lib/providers/provider'
import {
JsonRpcProvider
} from 'near-api-js/lib/providers'
import BN from 'bn.js'
import {
fullAccessKey,
Expand All @@ -16,6 +17,13 @@ import {
functionCall as functionCallAction,
transfer as transferAction,
} from 'near-api-js/lib/transaction'
import {
environment,
} from './config'
import {
toGas,
toYocto,
} from './util'
import {
AccountNetwork,
isExistAccount,
Expand All @@ -27,15 +35,12 @@ import {
Outcome,
transactionOutcome,
} from './index'
import {
FunctionCallOptions,
} from 'near-api-js/lib/account'

const DEFAULT_FUNC_CALL_GAS = new BN('300000000000000')

export async function fetchContract(accountId: string, networkId?: string): Promise<Uint8Array> {
const rpc = new api.providers.JsonRpcProvider(config.environment(networkId).nodeUrl)
const result = await rpc.query<provider.ContractCodeView>({
const rpc = new JsonRpcProvider(environment(networkId).nodeUrl)
const result = await rpc.query<ContractCodeView>({
request_type: 'view_code',
finality: 'final',
account_id: accountId
Expand Down Expand Up @@ -95,7 +100,7 @@ export async function deployContract<Type>(
actionList.push(createAccountAction())
}
if (isNotExistAccount && props.amount) {
const deposit = util.toYocto(props.amount)
const deposit = toYocto(props.amount)
if (deposit.gtn(0)) {
actionList.push(transferAction(deposit))
}
Expand All @@ -120,11 +125,11 @@ export async function deployContract<Type>(
return result
}

function parseGas(terraGas: string): BN {
function parseGas(terraGas?: string): BN {
return (terraGas ? new BN(toGas(terraGas)) : DEFAULT_FUNC_CALL_GAS)
}

function parseDeposit(deposit: string): BN {
function parseDeposit(deposit?: string): BN {
return (deposit ? toYocto(deposit) : new BN(0))
}

Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './transaction'
export * from './contract'
export * from './util'
export * from './standard'
export * from './os'

0 comments on commit c51f928

Please sign in to comment.