From e4065ad2c51a92d18d5705c0c12e5a617507b49a Mon Sep 17 00:00:00 2001 From: 0xGabi Date: Wed, 1 Dec 2021 20:54:45 -0300 Subject: [PATCH 1/2] Core: add configuration to support radspec helprs and functions --- packages/connect-core/src/entities/App.ts | 2 +- .../src/entities/ForwardingPath.ts | 13 +++++------ .../connect-core/src/entities/Organization.ts | 10 +++------ packages/connect-core/src/types.ts | 6 +++++ .../src/utils/descriptor/describe.ts | 21 ++++++++++-------- packages/connect-core/src/utils/forwarding.ts | 10 ++++++--- packages/connect-core/src/utils/intent.ts | 10 ++++----- packages/connect-core/src/utils/ipfs.ts | 5 +---- packages/connect-core/src/utils/misc.ts | 2 +- .../src/utils/path/calculatePath.ts | 22 +++++++++---------- .../src/utils/path/getACLForwardingPath.ts | 8 +++---- .../src/utils/path/getForwardingPath.ts | 8 +++---- .../connect-core/src/utils/radspec/index.ts | 9 +++++--- .../connect-core/src/utils/transactions.ts | 20 ++++++++++++----- packages/connect/src/connect.ts | 2 ++ packages/connect/src/types.ts | 6 +++++ 16 files changed, 89 insertions(+), 65 deletions(-) diff --git a/packages/connect-core/src/entities/App.ts b/packages/connect-core/src/entities/App.ts index 4eac0f70..26d8df40 100644 --- a/packages/connect-core/src/entities/App.ts +++ b/packages/connect-core/src/entities/App.ts @@ -144,7 +144,7 @@ export default class App { methodSignature, params, installedApps, - this.provider + this.organization.connection ) } } diff --git a/packages/connect-core/src/entities/ForwardingPath.ts b/packages/connect-core/src/entities/ForwardingPath.ts index cb664a26..be0cf8c4 100644 --- a/packages/connect-core/src/entities/ForwardingPath.ts +++ b/packages/connect-core/src/entities/ForwardingPath.ts @@ -1,5 +1,3 @@ -import { Provider } from '@ethersproject/providers' - import { buildApprovePreTransactions } from '../utils/transactions' import { ForwardingPathData, @@ -12,6 +10,7 @@ import ForwardingPathDescription, { } from '../utils/descriptor/index' import App from './App' import Transaction from './Transaction' +import { ConnectionContext } from '..' const normalizePreTransactions = ( preTransactions: (Transaction | TransactionData)[] @@ -25,7 +24,7 @@ const normalizePreTransactions = ( export default class ForwardingPath { #installedApps: App[] - #provider: Provider + #connection: ConnectionContext readonly destination: App readonly path: Transaction[] readonly transactions: Transaction[] @@ -33,10 +32,10 @@ export default class ForwardingPath { constructor( data: ForwardingPathData, installedApps: App[], - provider: Provider + connection: ConnectionContext ) { this.#installedApps = installedApps - this.#provider = provider + this.#connection = connection this.destination = data.destination this.path = data.path this.transactions = data.transactions @@ -59,7 +58,7 @@ export default class ForwardingPath { description = await describePath( this.path, this.#installedApps, - this.#provider + this.#connection ) // eslint-disable-next-line no-empty } catch (_) {} @@ -75,7 +74,7 @@ export default class ForwardingPath { return buildApprovePreTransactions( this.transactions[0], tokenData, - this.#provider + this.#connection ) } diff --git a/packages/connect-core/src/entities/Organization.ts b/packages/connect-core/src/entities/Organization.ts index 6dfceb5d..0a239176 100644 --- a/packages/connect-core/src/entities/Organization.ts +++ b/packages/connect-core/src/entities/Organization.ts @@ -68,7 +68,7 @@ export default class Organization { this.connection = connection } - get location() { + get location(): string { return this.connection.orgLocation } @@ -169,7 +169,7 @@ export default class Organization { const describedSteps = await describePath( decodeForwardingPath(script), installedApps, - this.connection.ethersProvider + this.connection ) return new ForwardingPathDescription(describedSteps, installedApps) @@ -179,10 +179,6 @@ export default class Organization { async describeTransaction( transaction: Transaction ): Promise { - return describeTransaction( - transaction, - await this.apps(), - this.connection.ethersProvider - ) + return describeTransaction(transaction, await this.apps(), this.connection) } } diff --git a/packages/connect-core/src/types.ts b/packages/connect-core/src/types.ts index 37e83add..533dbe0d 100644 --- a/packages/connect-core/src/types.ts +++ b/packages/connect-core/src/types.ts @@ -255,6 +255,11 @@ export type IpfsResolver = { json: (cid: string, path?: string) => Promise } +export type RadspecOptions = { + userFunctions?: Record + userHelpers?: Record +} + export type ConnectionContext = { actAs: Address | null ethereumProvider: object | null @@ -264,6 +269,7 @@ export type ConnectionContext = { orgAddress: Address orgConnector: IOrganizationConnector orgLocation: string + radspec?: RadspecOptions verbose: boolean } diff --git a/packages/connect-core/src/utils/descriptor/describe.ts b/packages/connect-core/src/utils/descriptor/describe.ts index ce960d0b..227968fd 100644 --- a/packages/connect-core/src/utils/descriptor/describe.ts +++ b/packages/connect-core/src/utils/descriptor/describe.ts @@ -1,20 +1,19 @@ /* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable no-empty */ -import { Provider } from '@ethersproject/providers' - import { tryEvaluatingRadspec, tryDescribingUpdateAppIntent, postprocessRadspecDescription, } from '../radspec/index' import { StepDecoded, StepDescribed, PostProcessDescription } from '../../types' +import { ConnectionContext } from '../..' import App from '../../entities/App' import Transaction from '../../entities/Transaction' export async function describeStep( step: StepDecoded, installedApps: App[], - provider: Provider + connection: ConnectionContext ): Promise { let decoratedStep // TODO: Add intent Basket support @@ -28,7 +27,11 @@ export async function describeStep( // Finally, if the step wasn't handled yet, evaluate via radspec normally if (!decoratedStep) { try { - decoratedStep = await tryEvaluatingRadspec(step, installedApps, provider) + decoratedStep = await tryEvaluatingRadspec( + step, + installedApps, + connection + ) } catch (err) {} } @@ -49,7 +52,7 @@ export async function describeStep( decoratedStep.children = await describePath( decoratedStep.children, installedApps, - provider + connection ) } @@ -63,17 +66,17 @@ export async function describeStep( export async function describePath( path: StepDecoded[], installedApps: App[], - provider: Provider + connection: ConnectionContext ): Promise { return Promise.all( - path.map(async (step) => describeStep(step, installedApps, provider)) + path.map(async (step) => describeStep(step, installedApps, connection)) ) } export async function describeTransaction( transaction: Transaction, installedApps: App[], - provider: Provider + connection: ConnectionContext ): Promise { if (!transaction.to) { throw new Error(`Could not describe transaction: missing 'to'`) @@ -87,7 +90,7 @@ export async function describeTransaction( description = await tryEvaluatingRadspec( transaction, installedApps, - provider + connection ) if (description) { diff --git a/packages/connect-core/src/utils/forwarding.ts b/packages/connect-core/src/utils/forwarding.ts index 12f12946..6afb7809 100644 --- a/packages/connect-core/src/utils/forwarding.ts +++ b/packages/connect-core/src/utils/forwarding.ts @@ -1,5 +1,5 @@ import { Contract } from '@ethersproject/contracts' -import { Provider } from '@ethersproject/providers' +import { ConnectionContext } from '..' import { forwarderAbi } from './abis' export const FORWARD_SIG = '0xd948d468' // function forward(bytes) @@ -58,10 +58,14 @@ export function canForward( forwarderAddress: string, sender: string, script: string, - provider: Provider + connection: ConnectionContext ): Promise { // Check if a token approval pretransaction is needed due to the forwarder requiring a fee - const forwarder = new Contract(forwarderAddress, forwarderAbi, provider) + const forwarder = new Contract( + forwarderAddress, + forwarderAbi, + connection.ethersProvider + ) return forwarder.canForward(sender, script).catch(() => false) } diff --git a/packages/connect-core/src/utils/intent.ts b/packages/connect-core/src/utils/intent.ts index c1922a6d..58c9e31e 100644 --- a/packages/connect-core/src/utils/intent.ts +++ b/packages/connect-core/src/utils/intent.ts @@ -1,6 +1,5 @@ import type { Address } from '@1hive/connect-types' import { Result } from '@ethersproject/abi' -import { Provider } from '@ethersproject/providers' import { addressesEqual } from './address' import { @@ -12,6 +11,7 @@ import { getForwardingPath, getACLForwardingPath } from './path/index' import { StepDecoded } from '../types' import App from '../entities/App' import ForwardingPath from '../entities/ForwardingPath' +import { ConnectionContext } from '..' export async function appIntent( sender: Address, @@ -19,7 +19,7 @@ export async function appIntent( methodSignature: string, params: any[], installedApps: App[], - provider: Provider + connection: ConnectionContext ): Promise { const acl = installedApps.find((app) => app.name === 'acl') @@ -31,7 +31,7 @@ export async function appIntent( methodSignature, params, installedApps, - provider + connection ) } catch (_) { // emtpy path @@ -42,7 +42,7 @@ export async function appIntent( transactions: [], }, installedApps, - provider + connection ) } } @@ -53,7 +53,7 @@ export async function appIntent( methodSignature, params, installedApps, - provider + connection ) } diff --git a/packages/connect-core/src/utils/ipfs.ts b/packages/connect-core/src/utils/ipfs.ts index a36bc0c8..1cbf6c92 100644 --- a/packages/connect-core/src/utils/ipfs.ts +++ b/packages/connect-core/src/utils/ipfs.ts @@ -2,10 +2,7 @@ import { IpfsResolver } from '../types' import { ErrorConnection, ErrorUnexpectedResult } from '../errors' import { createCacheStore } from './cache-store' -export function ipfsResolver( - urlTemplate: string, - cache: number = 0 -): IpfsResolver { +export function ipfsResolver(urlTemplate: string, cache = 0): IpfsResolver { const cacheStore = cache === 0 ? null : createCacheStore(cache) return { diff --git a/packages/connect-core/src/utils/misc.ts b/packages/connect-core/src/utils/misc.ts index b1289b09..65818e55 100644 --- a/packages/connect-core/src/utils/misc.ts +++ b/packages/connect-core/src/utils/misc.ts @@ -29,7 +29,7 @@ export function normalizeFiltersAndCallback( const warned = new Map() -export function warn(messages: any | any[], once: boolean = true) { +export function warn(messages: any | any[], once = true) { if (process.env.NODE_ENV !== 'development') { return } diff --git a/packages/connect-core/src/utils/path/calculatePath.ts b/packages/connect-core/src/utils/path/calculatePath.ts index cba8833d..58347c61 100644 --- a/packages/connect-core/src/utils/path/calculatePath.ts +++ b/packages/connect-core/src/utils/path/calculatePath.ts @@ -1,6 +1,5 @@ import { isAddress } from '@ethersproject/address' import { id } from '@ethersproject/hash' -import { Provider } from '@ethersproject/providers' import { ErrorInvalid } from '../../errors' import { TransactionPath } from '../../types' @@ -15,6 +14,7 @@ import { createForwarderTransactionBuilder, buildForwardingFeePreTransactions, } from '../transactions' +import { ConnectionContext } from '../..' /** * Calculate the forwarding path for a transaction to `destination` @@ -26,7 +26,7 @@ async function calculateForwardingPath( directTransaction: Transaction, forwardersWithPermission: string[], forwarders: string[], - provider: Provider + connection: ConnectionContext ): Promise { // No forwarders can perform the requested action if (forwardersWithPermission.length === 0) { @@ -42,7 +42,7 @@ async function calculateForwardingPath( forwarder: string, script: string, path: Transaction[], - provider: Provider + connection: ConnectionContext ): Promise => { const transaction = createForwarderTransaction(forwarder, script) @@ -50,7 +50,7 @@ async function calculateForwardingPath( // as it's the only one that will be executed by the user try { const forwardingFeePreTransactions = - await buildForwardingFeePreTransactions(transaction, provider) + await buildForwardingFeePreTransactions(transaction, connection) // If that happens, we give up as we should've been able to perform the action with this // forwarding path return { @@ -66,12 +66,12 @@ async function calculateForwardingPath( // with `sig` on `address` can forward for us directly for (const forwarder of forwardersWithPermission) { const script = encodeCallScript([directTransaction]) - if (await canForward(forwarder, sender, script, provider)) { + if (await canForward(forwarder, sender, script, connection)) { return buildForwardingPath( forwarder, script, [directTransaction], - provider + connection ) } } @@ -119,11 +119,11 @@ async function calculateForwardingPath( // Encode the previous transaction into an EVM callscript const script = encodeCallScript([path[0]]) - if (await canForward(previousForwarder, forwarder, script, provider)) { - if (await canForward(forwarder, sender, script, provider)) { + if (await canForward(previousForwarder, forwarder, script, connection)) { + if (await canForward(forwarder, sender, script, connection)) { // The previous forwarder can forward a transaction for this forwarder, // and this forwarder can forward for our address, so we have found a path - return buildForwardingPath(forwarder, script, path, provider) + return buildForwardingPath(forwarder, script, path, connection) } else { // The previous forwarder can forward a transaction for this forwarder, // but this forwarder can not forward for our address, so we add it as a @@ -157,7 +157,7 @@ export async function calculateTransactionPath( methodSignature: string, params: any[], apps: App[], - provider: Provider, + connection: ConnectionContext, finalForwarder?: string //Address of the final forwarder that can perfom the action. Needed for actions that aren't in the ACL but whose execution depends on other factors ): Promise { // The direct transaction we eventually want to perform @@ -253,6 +253,6 @@ export async function calculateTransactionPath( directTransaction, forwardersWithPermission, forwarders, - provider + connection ) } diff --git a/packages/connect-core/src/utils/path/getACLForwardingPath.ts b/packages/connect-core/src/utils/path/getACLForwardingPath.ts index 8ca3bd03..37d2299e 100644 --- a/packages/connect-core/src/utils/path/getACLForwardingPath.ts +++ b/packages/connect-core/src/utils/path/getACLForwardingPath.ts @@ -1,11 +1,11 @@ import type { Address } from '@1hive/connect-types' -import { Provider } from '@ethersproject/providers' import { getForwardingPath } from './getForwardingPath' import { findMethodAbiFragment } from '../abi' import { findAppMethodFromSignature } from '../app' import App from '../../entities/App' import ForwardingPath from '../../entities/ForwardingPath' +import { ConnectionContext } from '../..' /** * Get the permission manager for an `app`'s and `role`. @@ -38,7 +38,7 @@ export async function getACLForwardingPath( methodSignature: string, params: any[], installedApps: App[], - provider: Provider + connection: ConnectionContext ): Promise { const method = findAppMethodFromSignature(acl, methodSignature, { allowDeprecated: false, @@ -55,7 +55,7 @@ export async function getACLForwardingPath( methodSignature, params, installedApps, - provider + connection ) } else { // Some ACL functions don't have a role and are instead protected by a manager @@ -88,7 +88,7 @@ export async function getACLForwardingPath( methodSignature, params, installedApps, - provider, + connection, manager ) } diff --git a/packages/connect-core/src/utils/path/getForwardingPath.ts b/packages/connect-core/src/utils/path/getForwardingPath.ts index 588b2777..4f0f8d3d 100644 --- a/packages/connect-core/src/utils/path/getForwardingPath.ts +++ b/packages/connect-core/src/utils/path/getForwardingPath.ts @@ -1,9 +1,9 @@ import type { Address } from '@1hive/connect-types' -import { Provider } from '@ethersproject/providers' import { calculateTransactionPath } from './calculatePath' import App from '../../entities/App' import ForwardingPath from '../../entities/ForwardingPath' +import { ConnectionContext } from '../..' /** * Calculate the transaction path for a transaction to `destination` @@ -21,7 +21,7 @@ export async function getForwardingPath( methodSignature: string, params: any[], installedApps: App[], - provider: Provider, + connection: ConnectionContext, finalForwarder?: Address ): Promise { const { path, transactions } = await calculateTransactionPath( @@ -30,7 +30,7 @@ export async function getForwardingPath( methodSignature, params, installedApps, - provider, + connection, finalForwarder ) @@ -41,6 +41,6 @@ export async function getForwardingPath( transactions, }, installedApps, - provider + connection ) } diff --git a/packages/connect-core/src/utils/radspec/index.ts b/packages/connect-core/src/utils/radspec/index.ts index d90a23e7..1d17e58e 100644 --- a/packages/connect-core/src/utils/radspec/index.ts +++ b/packages/connect-core/src/utils/radspec/index.ts @@ -1,11 +1,11 @@ import * as radspec from '@1hive/radspec' -import { Provider } from '@ethersproject/providers' import { addressesEqual } from '../address' import { findAppMethodFromData } from '../app' import { filterAndDecodeAppUpgradeIntents } from '../intent' import { Abi, AppMethod, StepDecoded, StepDescribed } from '../../types' import App from '../../entities/App' +import { ConnectionContext } from '../..' interface FoundMethod { method?: AppMethod @@ -18,7 +18,7 @@ interface FoundMethod { export async function tryEvaluatingRadspec( intent: StepDecoded, installedApps: App[], - provider: Provider // Decorated intent with description, if one could be made + connection: ConnectionContext // Decorated intent with description, if one could be made ): Promise { const app = installedApps.find((app) => addressesEqual(app.address, intent.to) @@ -58,7 +58,10 @@ export async function tryEvaluatingRadspec( abi, transaction: intent, }, - { provider: provider } + { + ...connection.radspec, + provider: connection.ethersProvider, + } ) } catch (err) { console.error( diff --git a/packages/connect-core/src/utils/transactions.ts b/packages/connect-core/src/utils/transactions.ts index 0e2cbc84..cadc961a 100644 --- a/packages/connect-core/src/utils/transactions.ts +++ b/packages/connect-core/src/utils/transactions.ts @@ -1,13 +1,13 @@ import type { Address } from '@1hive/connect-types' import { Interface, Fragment, FunctionFragment } from '@ethersproject/abi' import { Contract } from '@ethersproject/contracts' -import { Provider } from '@ethersproject/providers' import { ErrorInvalid, ErrorUnsufficientBalance } from '../errors' import { erc20ABI, forwarderAbi, forwarderFeeAbi } from './abis' import { findMethodAbiFragment } from './abi' import { TokenData } from '../types' import App from '../entities/App' import Transaction from '../entities/Transaction' +import { ConnectionContext } from '..' export async function createDirectTransaction( sender: Address, @@ -79,13 +79,17 @@ export function createForwarderTransactionBuilder( export async function buildApprovePreTransactions( transaction: Transaction, tokenData: TokenData, - provider: Provider + connection: ConnectionContext ): Promise { // Token allowance pre-transaction const { from, to } = transaction const { address: tokenAddress, value: tokenValue, spender } = tokenData - const tokenContract = new Contract(tokenAddress, erc20ABI, provider) + const tokenContract = new Contract( + tokenAddress, + erc20ABI, + connection.ethersProvider + ) const balance = await tokenContract.balanceOf(from) const tokenValueBN = BigInt(tokenValue.toString()) @@ -133,11 +137,15 @@ export async function buildApprovePreTransactions( export async function buildForwardingFeePreTransactions( forwardingTransaction: Transaction, - provider: Provider + connection: ConnectionContext ): Promise { const { to: forwarderAddress, from } = forwardingTransaction - const forwarderFee = new Contract(forwarderAddress, forwarderFeeAbi, provider) + const forwarderFee = new Contract( + forwarderAddress, + forwarderFeeAbi, + connection.ethersProvider + ) const feeDetails = { amount: BigInt(0), tokenAddress: '' } try { @@ -163,7 +171,7 @@ export async function buildForwardingFeePreTransactions( return buildApprovePreTransactions( forwardingTransaction, tokenData, - provider + connection ) } return [] diff --git a/packages/connect/src/connect.ts b/packages/connect/src/connect.ts index f7a87e14..43ae8706 100644 --- a/packages/connect/src/connect.ts +++ b/packages/connect/src/connect.ts @@ -14,6 +14,7 @@ async function connect( ethereum: ethereumProvider, ipfs, network, + radspec, verbose, }: ConnectOptions = {} ): Promise { @@ -33,6 +34,7 @@ async function connect( orgAddress, orgConnector, orgLocation: location, + radspec: radspec, verbose: verbose ?? false, } diff --git a/packages/connect/src/types.ts b/packages/connect/src/types.ts index 3e43328c..71909a6c 100644 --- a/packages/connect/src/types.ts +++ b/packages/connect/src/types.ts @@ -17,11 +17,17 @@ export type IpfsResolverDeclaration = | IpfsResolverDeclarationObject | string +export type RadspecOptions = { + userFunctions?: Record + userHelpers?: Record +} + export type ConnectOptions = { actAs?: string ethereum?: object ipfs?: IpfsResolverDeclaration network?: Networkish + radspec?: RadspecOptions verbose?: boolean } From 9e53bec9c5d26b256bed2fc45d1a6068b4bb42e5 Mon Sep 17 00:00:00 2001 From: 0xGabi Date: Wed, 1 Dec 2021 20:55:19 -0300 Subject: [PATCH 2/2] Example: update describe example --- examples/nodejs/src/describe-script.ts | 77 ++------------------------ 1 file changed, 4 insertions(+), 73 deletions(-) diff --git a/examples/nodejs/src/describe-script.ts b/examples/nodejs/src/describe-script.ts index 2d9d76f4..9778ed40 100644 --- a/examples/nodejs/src/describe-script.ts +++ b/examples/nodejs/src/describe-script.ts @@ -6,81 +6,12 @@ const NETWORK = 100 async function main() { const org = await connect(ORG_ADDRESS, 'thegraph', { network: NETWORK }) - const [apps, apps2, apps3, apps4, apps5, apps6] = await Promise.all([ - org.apps(), - org.apps(), - org.apps(), - org.apps(), - org.apps(), - org.apps(), - ]) - // const apps = await org.apps() + const script = + '0x00000001a377585abed3e943e58174b55558a2482894ce2000000064beabacc80000000000000000000000003a97704a1b25f08aa230ae53b352e2e72ef528430000000000000000000000006626528de0c75ccc7a0d24f2d24b99060f74edee00000000000000000000000000000000000000000000001b1ae4d6e2ef500000' - // const script = - // '0x00000001a377585abed3e943e58174b55558a2482894ce2000000064beabacc80000000000000000000000003a97704a1b25f08aa230ae53b352e2e72ef528430000000000000000000000006626528de0c75ccc7a0d24f2d24b99060f74edee00000000000000000000000000000000000000000000001b1ae4d6e2ef500000' + const description = await org.describeScript(script) - // const apps2 = await org.apps() - // const apps3 = await org.apps() - // const apps4 = await org.apps() - // const apps5 = await org.apps() - // const apps6 = await org.apps() - - // const description = await org.describeScript(script) - - console.log( - 'First: ', - apps.map((app) => { - return { - name: app.name, - artifactName: app.artifact.appName, - } - }) - ) - console.log( - 'Second: ', - apps2.map((app) => { - return { - name: app.name, - artifactName: app.artifact.appName, - } - }) - ) - console.log( - 'Second: ', - apps3.map((app) => { - return { - name: app.name, - artifactName: app.artifact.appName, - } - }) - ) - console.log( - 'Second: ', - apps4.map((app) => { - return { - name: app.name, - artifactName: app.artifact.appName, - } - }) - ) - console.log( - 'Second: ', - apps5.map((app) => { - return { - name: app.name, - artifactName: app.artifact.appName, - } - }) - ) - console.log( - 'Second: ', - apps6.map((app) => { - return { - name: app.name, - artifactName: app.artifact.appName, - } - }) - ) + console.log(JSON.stringify(description, null, 2)) } main()