Skip to content

Commit

Permalink
working through flow on loops
Browse files Browse the repository at this point in the history
  • Loading branch information
TrevorJTClarke committed Apr 9, 2021
1 parent 8c25b31 commit 1349e5e
Show file tree
Hide file tree
Showing 9 changed files with 3,091 additions and 12 deletions.
4 changes: 4 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
NODE_ENV=development
NEAR_ENV=testnet

AGENT_ACCOUNT_ID=crond-agent

WAIT_INTERVAL_MS=500
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@
# IDEs
.idea
.idea/
.vscode/
.vscode/
node_modules

dist
.cache
1 change: 1 addition & 0 deletions nodemon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"watch": ["src"]}
20 changes: 19 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"description": "Cron.near CLI and Agent Runner",
"main": "src/index.js",
"scripts": {
"build": "babel src -d dist",
"start": "npm run build && node dist",
"restart": "rimraf dist && npm run start",
"dev": "nodemon --exec npm run restart",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
Expand All @@ -20,5 +24,19 @@
"bugs": {
"url": "https://github.com/Cron-Near/crond-js/issues"
},
"homepage": "https://github.com/Cron-Near/crond-js#readme"
"homepage": "https://github.com/Cron-Near/crond-js#readme",
"dependencies": {
"core-js": "^3.10.1",
"dotenv": "^8.2.0",
"near-api-js": "^0.39.0",
"regenerator-runtime": "^0.13.7"
},
"devDependencies": {
"@babel/cli": "^7.13.14",
"@babel/core": "^7.13.15",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/preset-env": "^7.13.15",
"nodemon": "^2.0.7",
"rimraf": "^3.0.2"
}
}
1 change: 1 addition & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function getConfigByType(networkId, config) {
}

export default function getConfig(env, options = {}) {
console.log('env, options', env, options);
switch (env) {
case 'production':
case 'mainnet':
Expand Down
76 changes: 75 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,75 @@
console.log('HERE')
require('dotenv').config()
const contractAbi = require('../src/contract_abi.json')
import NearProvider from './near'

const env = process.env.NODE_ENV || 'development'
const WAIT_INTERVAL_MS = process.env.WAIT_INTERVAL_MS || 500
const AGENT_ACCOUNT_ID = process.env.AGENT_ACCOUNT_ID || 'crond-agent'
const BASE_GAS_FEE = 300000000000000
const BASE_ATTACHED_PAYMENT = 0

const Near = new NearProvider({
networkId: env === 'production' ? 'mainnet' : 'testnet',
accountId: AGENT_ACCOUNT_ID,
})
let cronManager = null
let agentAccount = null

async function getCronManager() {
if (cronManager) return cronManager
const abi = contractAbi.abis.manager
const contractId = contractAbi[env].manager
cronManager = await Near.getContractInstance(contractId, abi)
return cronManager
}

async function registerAgent() {
const manager = await getCronManager()

// NOTE: Optional "payable_account_id" here
const res = await manager.register_agent({}, BASE_GAS_FEE, BASE_ATTACHED_PAYMENT)
console.log('registerAgent res', res);
}

async function getAgent() {
const manager = await getCronManager()
return manager.get_agent({ pk: agentAccount })
}

async function runAgentTick() {
const manager = await getCronManager()

// 1. Check for tasks
const tasks = await manager.get_tasks()
console.log('tasks', tasks);

// 2. Sign tasks and submit to chain
const res = await manager.proxy_call({}, BASE_GAS_FEE, BASE_ATTACHED_PAYMENT)
console.log('runAgentTick res', res);

// Wait, then loop again.
setTimeout(runAgentTick, WAIT_INTERVAL_MS)
}

// Cron Agent Task Loop
(async () => {
await Near.getNearConnection()

// 1. Check for local signing keys, if none - generate new and halt until funded
agentAccount = await Near.getAccountCredentials(AGENT_ACCOUNT_ID)

// 2. Check for balance, if enough to execute txns, start main tasks
const balance = await Near.getAccountBalance()
console.log('balance', balance);

// 3. Check if agent is registered, if not register immediately before proceeding
try {
const agent = await getAgent()
console.log('agent', agent);
} catch (error) {
await registerAgent()
}

// MAIN AGENT LOOP
runAgentTick()
})()
50 changes: 41 additions & 9 deletions src/near.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { connect, KeyPair, keyStores, utils } from 'near-api-js'
import fs from 'fs'
import "core-js/stable"
import "regenerator-runtime/runtime"
import { connect, KeyPair, keyStores, Contract, WalletConnection, WalletAccount } from 'near-api-js'
// import fs from 'fs'
import path from 'path'
import { homedir } from 'os'
import getConfig from './config'
Expand All @@ -10,38 +12,68 @@ const credentialsPath = path.join(homedir(), CREDENTIALS_DIR)
class NearProvider {

constructor(config = {}) {
this.config = getConfig(config.networkId || process.env.NEAR_ENV || 'testnet')
this.credentials = getAccountCredentials(config.accountId)
this.client = this.getNearConnection()
this.config = getConfig(config.networkId || 'testnet')
console.log('this.config', this.config);
this.credentials = null
this.client = null

return this
}

async getAccountCredentials(accountId) {
const keyStore = new keyStores.UnencryptedFileSystemKeyStore(credentialsPath)

const existingKey = await keyStore.getKey(this.config.networkId, accountId)
if (existingKey) {
console.log(`Key pair with ${existingKey.publicKey} public key for an account "${accountId}"`)
console.log(`AGENT: "${accountId}", Public Key ${existingKey.publicKey}`)
return existingKey.publicKey
}

const keyPair = KeyPair.fromRandom('ed25519')
const publicKey = keyPair.publicKey.toString()
const id = accountId || implicitAccountId(publicKey)
await keyStore.setKey(this.config.networkId, id, keyPair)
console.log(`Key pair with ${publicKey} public key for an account "${id}"`)
console.log(`NEW AGENT CREATED: "${id}", Public Key ${publicKey}\n Requires funds to start processing tasks.`)
return publicKey
}

async getNearConnection() {
if (this.client) return this.client
const keyStore = new keyStores.UnencryptedFileSystemKeyStore(credentialsPath)
console.log('keyStore', keyStore);
this.client = await connect(Object.assign({ deps: { keyStore } }, this.config))
return this.client
}

async getAccountBalance() {
const account = await this.client.account(this.config.accountId)
return account.getAccountBalance()
const account = await this.loadAccount()
if (!account) return 0
const balances = await account.getAccountBalance()
return balances && balances.available ? balances.available : 0
}

async loadAccount() {
if (!this.client) return
const user = await this.client.account(this.client.accountId)
console.log('user', user.accountId);

return user
}

async getContractInstance(contract_id, abiMethods) {
const account = await this.loadAccount()
const abi = {
changeMethods: [],
viewMethods: [],
...abiMethods,
}

// Sender is the account ID to initialize transactions.
return new Contract(
account,
contract_id,
{ ...abi, sender: account.accountId }
)
}
}

Expand Down
Loading

0 comments on commit 1349e5e

Please sign in to comment.