diff --git a/packages/sdk/examples/node/custom.ts b/packages/sdk/examples/node/custom.ts index 094d5921d..7d3a41ec0 100644 --- a/packages/sdk/examples/node/custom.ts +++ b/packages/sdk/examples/node/custom.ts @@ -15,9 +15,9 @@ const provider = new providers.JsonRpcProvider(ColonyRpcEndpoint.ArbitrumOne); const start = async () => { const colonyNetwork = new ColonyNetwork(provider); const usdc = new CustomContract( - colonyNetwork, '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', erc20Abi, + colonyNetwork.config, ); const metaColonyAddress = await colonyNetwork .getInternalNetworkContract() diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 699f56274..5603cc3d0 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -51,12 +51,12 @@ "@colony/core": "^2.3.0", "@colony/events": "^3.0.0", "@colony/tokens": "^0.3.0", + "@ethersproject/abstract-provider": "^5.7.0", "abitype": "^1.0.6" }, "devDependencies": { "@colony/contractor": "^2.2.0", "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@picocss/pico": "^1.5.7", diff --git a/packages/sdk/src/ColonyNetwork/Colony.ts b/packages/sdk/src/ColonyNetwork/Colony.ts index b9c8b3f5a..c79758e20 100644 --- a/packages/sdk/src/ColonyNetwork/Colony.ts +++ b/packages/sdk/src/ColonyNetwork/Colony.ts @@ -54,6 +54,7 @@ import { type ColonyNetwork } from './ColonyNetwork.js'; import { OneTxPayment } from './OneTxPayment.js'; import { ERC20Token, type Token, getToken } from './tokens/index.js'; import { VotingReputation } from './VotingReputation.js'; +import { type ContractConfig } from '../ContractConfig.js'; export type SupportedColonyContract = | ColonyContract11 @@ -108,7 +109,7 @@ export class Colony { static async connect(colonyNetwork: ColonyNetwork, address: string) { const version = (await getContractVersion( address, - colonyNetwork.signerOrProvider, + colonyNetwork.config.signerOrProvider, )) as ColonyVersion; const Factory = Colony.supportedVersions.find( @@ -123,7 +124,7 @@ export class Colony { const colonyContract = Factory.connect( address, - colonyNetwork.signerOrProvider, + colonyNetwork.config.signerOrProvider, ); const tokenAddress = await colonyContract.getToken(); @@ -152,6 +153,11 @@ export class Colony { */ address: string; + /** + * The colony's contract config (taken from ColonyNetwork) + */ + config: ContractConfig; + /** * A shortcut to the {@link ColonyNetwork} instance */ @@ -212,6 +218,7 @@ export class Colony { ) { this.colony = colony; this.colonyNetwork = colonyNetwork; + this.config = colonyNetwork.config; this.address = colony.address; this.ext = {}; this.reputation = new ReputationClient( @@ -252,7 +259,7 @@ export class Colony { ) { return new ColonyTxCreator({ colony: this, - colonyNetwork: this.colonyNetwork, + config: this.colonyNetwork.config, contract, method, args, @@ -292,7 +299,7 @@ export class Colony { ) { return new ColonyTxCreator({ colony: this, - colonyNetwork: this.colonyNetwork, + config: this.colonyNetwork.config, contract, method, args, @@ -428,7 +435,7 @@ export class Colony { if (typeof metadata == 'string') { cid = metadata; } else { - cid = await this.colonyNetwork.ipfs.uploadMetadata( + cid = await this.config.ipfs.uploadMetadata( MetadataType.Colony, metadata, ); @@ -569,7 +576,7 @@ export class Colony { if (typeof metadata == 'string') { cid = metadata; } else { - cid = await this.colonyNetwork.ipfs.uploadMetadata( + cid = await this.config.ipfs.uploadMetadata( MetadataType.Domain, metadata, ); @@ -654,7 +661,7 @@ export class Colony { if (typeof metadata == 'string') { cid = metadata; } else { - cid = await this.colonyNetwork.ipfs.uploadMetadata( + cid = await this.config.ipfs.uploadMetadata( MetadataType.Domain, metadata, ); @@ -1056,7 +1063,7 @@ export class Colony { if (typeof metadata == 'string') { cid = metadata; } else { - cid = await this.colonyNetwork.ipfs.uploadMetadata( + cid = await this.config.ipfs.uploadMetadata( MetadataType.Annotation, metadata, ); diff --git a/packages/sdk/src/ColonyNetwork/ColonyNetwork.ts b/packages/sdk/src/ColonyNetwork/ColonyNetwork.ts index bd5c8d267..a21498624 100644 --- a/packages/sdk/src/ColonyNetwork/ColonyNetwork.ts +++ b/packages/sdk/src/ColonyNetwork/ColonyNetwork.ts @@ -3,15 +3,11 @@ import { type ContractReceipt, constants, utils, - Signer, } from 'ethers'; import { type SignerOrProvider, ColonyLabelSuffix, - MetaTxBroadCasterEndpoint, - Network, UserLabelSuffix, - ReputationOracleEndpoint, ColonyNetworkAddress, } from '@colony/core'; import { type ERC2612Token as ERC2612TokenType } from '@colony/tokens'; @@ -19,8 +15,6 @@ import { type ColonyData, type ColonyEvents, type ColonyNetworkEvents, - type IpfsAdapter, - IpfsMetadata, MetadataType, } from '@colony/events'; @@ -40,30 +34,11 @@ import { type Expand, type Parameters } from '../types.js'; import { extractEvent } from '../utils.js'; import { EIP2612TxCreator } from '../TxCreator/EIP2612TxCreator.js'; import { TokenLocking } from './TokenLocking.js'; +import { ContractConfig, type ContractOptions } from '../ContractConfig.js'; const { namehash } = utils; const { AddressZero } = constants; -/** Additional options for the {@link ColonyNetwork} */ -export interface ColonyNetworkOptions { - /** A custom address for ColonyNetwork's EtherRouter contract. Useful only in manual deployments */ - customNetworkAddress?: string; - /** Provide a custom {@link IpfsAdapter} */ - ipfsAdapter?: IpfsAdapter; - /** The Network to connect to. See {@link Network} for supported networks */ - network?: Network; - /** Provide a custom metatransaction broadcaster endpoint */ - metaTxBroadcasterEndpoint?: string; - /** A custom endpoiunt for ColonyNetwork's Reputation Oracle. Useful only in manual deployments */ - reputationOracleEndpoint?: string; -} - -/** @internal */ -export interface ColonyNetworkConfig { - metaTxBroadcasterEndpoint: string; - reputationOracleEndpoint: string; -} - /** ERC20 Token information */ export interface TokenData { /** The token's name (e.g. Colony Network Token) */ @@ -75,26 +50,13 @@ export interface TokenData { } export class ColonyNetwork { - private networkContract: IColonyNetwork; + private contract: IColonyNetwork; private locking?: TokenLocking; /** Configuration of the ColonyNetwork for later use */ /** @internal */ - config: ColonyNetworkConfig; - - /** The IPFS adapter for Metadata. Defaults to a read-only adapter */ - ipfs: IpfsMetadata; - - /** The network the client is connected to. Defaults to Arbitrum One */ - network: Network; - - /** - * An ethers.js [Signer](https://docs.ethers.org/v5/api/signer/#Signer) or [Provider](https://docs.ethers.org/v5/api/providers/). - * - * E.g. a [Wallet](https://docs.ethers.org/v5/api/signer/#Wallet) or a [Web3Provider](https://docs.ethers.org/v5/api/providers/other/#Web3Provider) (MetaMask) - */ - signerOrProvider: SignerOrProvider; + config: ContractConfig; /** * Creates a new instance of the ColonyNetwork @@ -118,39 +80,13 @@ export class ColonyNetwork { * @param options - Optional custom {@link ColonyNetworkOptions} * @returns A ColonyNetwork abstraction instance */ - constructor( - signerOrProvider: SignerOrProvider, - options?: ColonyNetworkOptions, - ) { - this.network = options?.network || Network.ArbitrumOne; - this.ipfs = new IpfsMetadata(options?.ipfsAdapter); - // TODO: for validation: if network is Custom, metaTxBroadcaster and reputationOracleEndpoint have to be set - this.config = { - metaTxBroadcasterEndpoint: - options?.metaTxBroadcasterEndpoint || - MetaTxBroadCasterEndpoint[this.network], - reputationOracleEndpoint: - options?.reputationOracleEndpoint || - ReputationOracleEndpoint[this.network], - }; - this.networkContract = IColonyNetworkFactory.connect( - options?.customNetworkAddress || ColonyNetworkAddress[this.network], + constructor(signerOrProvider: SignerOrProvider, options?: ContractOptions) { + this.config = new ContractConfig(signerOrProvider, options); + this.contract = IColonyNetworkFactory.connect( + options?.customNetworkAddress || + ColonyNetworkAddress[this.config.network], signerOrProvider, ); - this.signerOrProvider = signerOrProvider; - } - - /** - * Get the signer that was provided when the ColonyNetwork was instantiated. - * Throws if the Signer is only a (read-only) Provider - * - * @returns An Ethers.js compatible Signer instance - */ - getSigner(): Signer { - if (!(this.signerOrProvider instanceof Signer)) { - throw new Error('Need a signer to create a transaction'); - } - return this.signerOrProvider; } /** @@ -160,7 +96,7 @@ export class ColonyNetwork { */ async getTokenLocking(): Promise { if (!this.locking) { - const address = await this.networkContract.getTokenLocking(); + const address = await this.contract.getTokenLocking(); this.locking = new TokenLocking(this, address); } return this.locking; @@ -173,7 +109,7 @@ export class ColonyNetwork { * @returns The internally used ethers Contract */ getInternalNetworkContract(): IColonyNetwork { - return this.networkContract; + return this.contract; } /** @@ -205,7 +141,7 @@ export class ColonyNetwork { txConfig?: TxConfig, ) { return new TxCreator({ - colonyNetwork: this, + config: this.config, contract, method, args, @@ -243,7 +179,7 @@ export class ColonyNetwork { txConfig?: TxConfig, ) { return new MetaTxCreator({ - colonyNetwork: this, + config: this.config, contract, method, args, @@ -277,7 +213,7 @@ export class ColonyNetwork { txConfig?: TxConfig, ) { return new EIP2612TxCreator({ - colonyNetwork: this, + config: this.config, contract, method, args, @@ -469,7 +405,7 @@ export class ColonyNetwork { if (!metadata) { return this.createMetaTxCreator( - this.networkContract, + this.contract, 'createColonyForFrontend', prepareArgs, async (receipt) => ({ @@ -491,14 +427,14 @@ export class ColonyNetwork { } return this.createMetaTxCreator( - this.networkContract, + this.contract, 'createColonyForFrontend', async () => { const args = await prepareArgs(); if (typeof metadata == 'string') { args[6] = metadata; } else { - args[6] = await this.ipfs.uploadMetadata( + args[6] = await this.config.ipfs.uploadMetadata( MetadataType.Colony, metadata, ); @@ -548,7 +484,7 @@ export class ColonyNetwork { * @returns A Colony abstaction instance of the MetaColony */ async getMetaColony(): Promise { - const colonyAddress = await this.networkContract.getMetaColony(); + const colonyAddress = await this.contract.getMetaColony(); return this.getColony(colonyAddress); } @@ -561,11 +497,9 @@ export class ColonyNetwork { * @returns The colony's ENS label */ async getColonyLabel(address: string) { - const ensName = await this.networkContract.lookupRegisteredENSDomain( - address, - ); + const ensName = await this.contract.lookupRegisteredENSDomain(address); if (ensName) { - return ensName.replace(ColonyLabelSuffix[this.network], ''); + return ensName.replace(ColonyLabelSuffix[this.config.network], ''); } return null; } @@ -579,8 +513,8 @@ export class ColonyNetwork { * @returns The colony's address */ async getColonyAddress(label: string) { - const hash = namehash(`${label}${ColonyLabelSuffix[this.network]}`); - const address = await this.networkContract.addr(hash); + const hash = namehash(`${label}${ColonyLabelSuffix[this.config.network]}`); + const address = await this.contract.addr(hash); if (address !== AddressZero) { return address; } @@ -596,11 +530,9 @@ export class ColonyNetwork { * @returns The user's username */ async getUsername(address: string) { - const ensName = await this.networkContract.lookupRegisteredENSDomain( - address, - ); + const ensName = await this.contract.lookupRegisteredENSDomain(address); if (ensName) { - return ensName.replace(UserLabelSuffix[this.network], ''); + return ensName.replace(UserLabelSuffix[this.config.network], ''); } return null; } @@ -614,8 +546,8 @@ export class ColonyNetwork { * @returns The user's address */ async getUserAddress(username: string) { - const hash = namehash(`${username}${UserLabelSuffix[this.network]}`); - const address = await this.networkContract.addr(hash); + const hash = namehash(`${username}${UserLabelSuffix[this.config.network]}`); + const address = await this.contract.addr(hash); if (address !== AddressZero) { return address; } @@ -639,7 +571,7 @@ export class ColonyNetwork { return [username, ''] as [string, string]; }; return this.createMetaTxCreator( - this.networkContract, + this.contract, 'registerUserLabel', checkUsername, async (receipt) => ({ @@ -665,7 +597,7 @@ export class ColonyNetwork { */ deployToken(name: string, symbol: string, decimals = 18) { return this.createMetaTxCreator( - this.networkContract, + this.contract, 'deployTokenViaNetwork', [name, symbol, decimals], async (receipt) => ({ diff --git a/packages/sdk/src/ColonyNetwork/CustomColonyNetwork.ts b/packages/sdk/src/ColonyNetwork/CustomColonyNetwork.ts index 682edd2b7..a857b682f 100644 --- a/packages/sdk/src/ColonyNetwork/CustomColonyNetwork.ts +++ b/packages/sdk/src/ColonyNetwork/CustomColonyNetwork.ts @@ -1,35 +1,15 @@ -import { - ColonyNetworkAddress, - MetaTxBroadCasterEndpoint, - ReputationOracleEndpoint, -} from '@colony/core'; -import { type ContractInterface, Contract, Signer } from 'ethers'; -import { IpfsMetadata, Network, type SignerOrProvider } from '../index.js'; -import { - type ColonyNetworkConfig, - type ColonyNetworkOptions, -} from './ColonyNetwork.js'; +import { ColonyNetworkAddress } from '@colony/core'; +import { type ContractInterface, Contract } from 'ethers'; +import { type SignerOrProvider } from '../index.js'; import { type IColonyNetwork } from '../contracts/IColonyNetwork.js'; +import { ContractConfig, type ContractOptions } from '../ContractConfig.js'; export class CustomColonyNetwork { - private networkContract: IColonyNetwork; + private contract: IColonyNetwork; /** Configuration of the ColonyNetwork for later use */ /** @internal */ - config: ColonyNetworkConfig; - - /** The IPFS adapter for Metadata. Defaults to a read-only adapter */ - ipfs: IpfsMetadata; - - /** The network the client is connected to. Defaults to Gnosis chain */ - network: Network; - - /** - * An ethers.js [Signer](https://docs.ethers.org/v5/api/signer/#Signer) or [Provider](https://docs.ethers.org/v5/api/providers/). - * - * E.g. a [Wallet](https://docs.ethers.org/v5/api/signer/#Wallet) or a [Web3Provider](https://docs.ethers.org/v5/api/providers/other/#Web3Provider) (MetaMask) - */ - signerOrProvider: SignerOrProvider; + config: ContractConfig; /** * Creates a new custom instance of the custom ColonyNetwork @@ -42,36 +22,19 @@ export class CustomColonyNetwork { constructor( signerOrProvider: SignerOrProvider, abi: ContractInterface, - options?: ColonyNetworkOptions, + options?: ContractOptions, ) { - this.network = options?.network || Network.Gnosis; - this.ipfs = new IpfsMetadata(options?.ipfsAdapter); - this.config = { - metaTxBroadcasterEndpoint: - options?.metaTxBroadcasterEndpoint || - MetaTxBroadCasterEndpoint[this.network], - reputationOracleEndpoint: - options?.reputationOracleEndpoint || - ReputationOracleEndpoint[this.network], - }; - // Here we need to create the contract with ethers - this.networkContract = new Contract( - options?.customNetworkAddress || ColonyNetworkAddress[this.network], + this.config = new ContractConfig(signerOrProvider, options); + this.contract = new Contract( + options?.customNetworkAddress || + ColonyNetworkAddress[this.config.network], abi, signerOrProvider, ) as IColonyNetwork; - this.signerOrProvider = signerOrProvider; - } - - getSigner(): Signer { - if (!(this.signerOrProvider instanceof Signer)) { - throw new Error('Need a signer to create a transaction'); - } - return this.signerOrProvider; } getInternalNetworkContract() { - return this.networkContract; + return this.contract; } } diff --git a/packages/sdk/src/ColonyNetwork/CustomContract.ts b/packages/sdk/src/ColonyNetwork/CustomContract.ts index bbd165a48..30edd53af 100644 --- a/packages/sdk/src/ColonyNetwork/CustomContract.ts +++ b/packages/sdk/src/ColonyNetwork/CustomContract.ts @@ -7,50 +7,45 @@ import { } from 'abitype'; import { Contract, type ContractInterface } from 'ethers'; import { - type ColonyNetwork, type ContractReceipt, type EventData, type MetaTxBaseContract, type TxConfig, } from '../index.js'; -import type CustomColonyNetwork from './CustomColonyNetwork.js'; import CustomTxCreator from '../TxCreator/CustomTxCreator.js'; +import { type ContractConfig } from '../ContractConfig.js'; export class CustomContract { private abi: A; - private colonyNetwork: ColonyNetwork | CustomColonyNetwork; - private contract: MetaTxBaseContract; address: Address; + config: ContractConfig; + /** * Creates a new instance of a custom contract * * This is your main entry point to talk to the Colony Network Smart Contracts. * From here you should be able to instantiate all the required instances for Colonies and their extensions. * - * @param colonyNetwork - {@link ColonyNetwork} instance * @param address - Address of the deployed contract * @param abi - JSON ABI of the contract + * @param config - An instance of a ContractConfig (mind: _not_ ContractOptions!) * @returns A CustomContract instance */ - constructor( - colonyNetwork: ColonyNetwork | CustomColonyNetwork, - address: Address, - abi: A, - ) { - this.address = address; + constructor(address: Address, abi: A, config: ContractConfig) { this.abi = abi; + this.address = address; + this.config = config; // We do a little bit of casting to make ethers happy with the abitype types this.contract = new Contract( address, this.abi as unknown as ContractInterface, - colonyNetwork.signerOrProvider, + this.config.signerOrProvider, ) as unknown as MetaTxBaseContract; - this.colonyNetwork = colonyNetwork; } /** @@ -75,7 +70,7 @@ export class CustomContract { txConfig?: TxConfig, ) { return new CustomTxCreator({ - colonyNetwork: this.colonyNetwork, + config: this.config, contract: this.contract, method, args, diff --git a/packages/sdk/src/ColonyNetwork/OneTxPayment.ts b/packages/sdk/src/ColonyNetwork/OneTxPayment.ts index f2519dd24..975c477f2 100644 --- a/packages/sdk/src/ColonyNetwork/OneTxPayment.ts +++ b/packages/sdk/src/ColonyNetwork/OneTxPayment.ts @@ -83,7 +83,7 @@ export class OneTxPayment { const version = (await getContractVersion( address, - colony.colonyNetwork.signerOrProvider, + colony.config.signerOrProvider, )) as OneTxPaymentVersion; if ( @@ -110,7 +110,7 @@ export class OneTxPayment { const oneTxPaymentContract = Factory.connect( address, - colony.colonyNetwork.signerOrProvider, + colony.config.signerOrProvider, ); return new OneTxPayment(colony, oneTxPaymentContract, version); diff --git a/packages/sdk/src/ColonyNetwork/TokenLocking.ts b/packages/sdk/src/ColonyNetwork/TokenLocking.ts index e0b484787..3a815d8ce 100644 --- a/packages/sdk/src/ColonyNetwork/TokenLocking.ts +++ b/packages/sdk/src/ColonyNetwork/TokenLocking.ts @@ -18,7 +18,7 @@ export class TokenLocking { this.colonyNetwork = colonyNetwork; this.tokenLockingContract = getTokenLockingClient( this.address, - colonyNetwork.signerOrProvider, + colonyNetwork.config.signerOrProvider, ); } diff --git a/packages/sdk/src/ColonyNetwork/VotingReputation.ts b/packages/sdk/src/ColonyNetwork/VotingReputation.ts index 6c76b8997..6298acacc 100644 --- a/packages/sdk/src/ColonyNetwork/VotingReputation.ts +++ b/packages/sdk/src/ColonyNetwork/VotingReputation.ts @@ -183,7 +183,7 @@ export class VotingReputation { const version = (await getContractVersion( address, - colony.colonyNetwork.signerOrProvider, + colony.config.signerOrProvider, )) as VotingReputationVersion; if ( @@ -210,7 +210,7 @@ export class VotingReputation { const oneTxPaymentContract = Factory.connect( address, - colony.colonyNetwork.signerOrProvider, + colony.config.signerOrProvider, ); return new VotingReputation(colony, oneTxPaymentContract, version); @@ -716,7 +716,7 @@ export class VotingReputation { if (typeof metadata == 'string') { cid = metadata; } else { - cid = await this.colony.colonyNetwork.ipfs.uploadMetadata( + cid = await this.colony.config.ipfs.uploadMetadata( MetadataType.Decision, metadata, ); @@ -814,9 +814,7 @@ export class VotingReputation { */ stakeMotion(motionId: BigNumberish, vote: Vote, amount: BigNumberish) { const getArgs = async () => { - const userAddress = await this.colony.colonyNetwork - .getSigner() - .getAddress(); + const userAddress = await this.colony.config.getSigner().getAddress(); const motionState = await this.votingReputationContract.getMotionState( motionId, @@ -965,9 +963,7 @@ export class VotingReputation { const { domainId, rootHash } = await this.getMotion(motionId); const { skillId } = await this.colony.getTeam(domainId); - const userAddress = await this.colony.colonyNetwork - .getSigner() - .getAddress(); + const userAddress = await this.colony.config.getSigner().getAddress(); const { key, value, branchMask, siblings } = await this.colony.reputation.getReputationWithProofs( @@ -1036,9 +1032,7 @@ export class VotingReputation { const { domainId, rootHash } = await this.getMotion(motionId); const { skillId } = await this.colony.getTeam(domainId); - const userAddress = await this.colony.colonyNetwork - .getSigner() - .getAddress(); + const userAddress = await this.colony.config.getSigner().getAddress(); const reputation = await this.colony.reputation.getReputationWithProofs( skillId, @@ -1113,9 +1107,7 @@ export class VotingReputation { const { domainId, rootHash } = await this.getMotion(motionId); const { skillId } = await this.colony.getTeam(newTeamId); - const userAddress = await this.colony.colonyNetwork - .getSigner() - .getAddress(); + const userAddress = await this.colony.config.getSigner().getAddress(); const childIndex = await getChildIndex( this.colony.colonyNetwork.getInternalNetworkContract(), diff --git a/packages/sdk/src/ColonyNetwork/index.ts b/packages/sdk/src/ColonyNetwork/index.ts index 4eaff2cec..93d232517 100644 --- a/packages/sdk/src/ColonyNetwork/index.ts +++ b/packages/sdk/src/ColonyNetwork/index.ts @@ -1,8 +1,4 @@ -export { - ColonyNetwork, - type ColonyNetworkOptions, - type TokenData, -} from './ColonyNetwork.js'; +export { ColonyNetwork, type TokenData } from './ColonyNetwork.js'; export { Colony, type Domain, diff --git a/packages/sdk/src/ColonyNetwork/tokens/ColonyToken.ts b/packages/sdk/src/ColonyNetwork/tokens/ColonyToken.ts index 57180f948..75678910e 100644 --- a/packages/sdk/src/ColonyNetwork/tokens/ColonyToken.ts +++ b/packages/sdk/src/ColonyNetwork/tokens/ColonyToken.ts @@ -27,7 +27,7 @@ export class ColonyToken extends ERC20Token { if (typeof token == 'string') { this.tokenClient = ColonyTokenFactory.connect( token, - colonyNetwork.signerOrProvider, + colonyNetwork.config.signerOrProvider, ); } else { this.tokenClient = token; diff --git a/packages/sdk/src/ColonyNetwork/tokens/ERC20Token.ts b/packages/sdk/src/ColonyNetwork/tokens/ERC20Token.ts index 7bffcecdc..4d93b79fc 100644 --- a/packages/sdk/src/ColonyNetwork/tokens/ERC20Token.ts +++ b/packages/sdk/src/ColonyNetwork/tokens/ERC20Token.ts @@ -30,7 +30,7 @@ export class ERC20Token { if (typeof token == 'string') { this.tokenClient = ERC20TokenFactory.connect( token, - colonyNetwork.signerOrProvider, + colonyNetwork.config.signerOrProvider, ); } else { this.tokenClient = token; diff --git a/packages/sdk/src/ColonyNetwork/tokens/ERC2612Token.ts b/packages/sdk/src/ColonyNetwork/tokens/ERC2612Token.ts index 07b480a83..9270f6877 100644 --- a/packages/sdk/src/ColonyNetwork/tokens/ERC2612Token.ts +++ b/packages/sdk/src/ColonyNetwork/tokens/ERC2612Token.ts @@ -28,7 +28,7 @@ export class ERC2612Token extends ERC20Token { if (typeof token == 'string') { this.tokenClient = ERC2612TokenFactory.connect( token, - colonyNetwork.signerOrProvider, + colonyNetwork.config.signerOrProvider, ); } else { this.tokenClient = token; diff --git a/packages/sdk/src/ColonyNetwork/tokens/index.ts b/packages/sdk/src/ColonyNetwork/tokens/index.ts index 485eff809..51b661945 100644 --- a/packages/sdk/src/ColonyNetwork/tokens/index.ts +++ b/packages/sdk/src/ColonyNetwork/tokens/index.ts @@ -28,7 +28,7 @@ export const getToken = async ( ) => { const tokenClient = await getTokenClient( address, - colonyNetwork.signerOrProvider, + colonyNetwork.config.signerOrProvider, ); switch (tokenClient.tokenClientType) { case TokenClientType.Colony: { diff --git a/packages/sdk/src/ContractConfig.ts b/packages/sdk/src/ContractConfig.ts new file mode 100644 index 000000000..d8bae3d03 --- /dev/null +++ b/packages/sdk/src/ContractConfig.ts @@ -0,0 +1,71 @@ +import { + type SignerOrProvider, + Network, + MetaTxBroadCasterEndpoint, + ReputationOracleEndpoint, +} from '@colony/core'; +import { type IpfsAdapter, IpfsMetadata } from '@colony/events'; +import { Signer } from 'ethers'; + +/** Additional options for instatiating Contracts within the Colony Network */ +export interface ContractOptions { + /** A custom address for ColonyNetwork's EtherRouter contract. Useful only in manual deployments */ + customNetworkAddress?: string; + /** Provide a custom {@link IpfsAdapter} */ + ipfsAdapter?: IpfsAdapter; + /** The Network to connect to. See {@link Network} for supported networks */ + network?: Network; + /** Provide a custom metatransaction broadcaster endpoint */ + metaTxBroadcasterEndpoint?: string; + /** A custom endpoiunt for ColonyNetwork's Reputation Oracle. Useful only in manual deployments */ + reputationOracleEndpoint?: string; +} + +/** + * @internal + * Used to store auxiliare contract information and helpers + */ +export class ContractConfig { + /** The IPFS adapter for Metadata. Defaults to a read-only adapter */ + ipfs: IpfsMetadata; + + metaTxBroadcasterEndpoint: string; + + /** The network the client is connected to. Defaults to Arbitrum One */ + network: Network; + + /** A custom endpoiunt for ColonyNetwork's Reputation Oracle. Useful only in manual deployments */ + reputationOracleEndpoint: string; + + /** + * An ethers.js [Signer](https://docs.ethers.org/v5/api/signer/#Signer) or [Provider](https://docs.ethers.org/v5/api/providers/). + * + * E.g. a [Wallet](https://docs.ethers.org/v5/api/signer/#Wallet) or a [Web3Provider](https://docs.ethers.org/v5/api/providers/other/#Web3Provider) (MetaMask) + */ + signerOrProvider: SignerOrProvider; + + constructor(signerOrProvider: SignerOrProvider, options?: ContractOptions) { + const network = options?.network || Network.ArbitrumOne; + // TODO: for validation: if network is Custom, metaTxBroadcaster and reputationOracleEndpoint have to be set + this.metaTxBroadcasterEndpoint = + options?.metaTxBroadcasterEndpoint || MetaTxBroadCasterEndpoint[network]; + this.ipfs = new IpfsMetadata(options?.ipfsAdapter); + this.network = network; + this.reputationOracleEndpoint = + options?.reputationOracleEndpoint || ReputationOracleEndpoint[network]; + this.signerOrProvider = signerOrProvider; + } + + /** + * Get the signer that was provided when the ColonyNetwork was instantiated. + * Throws if the Signer is only a (read-only) Provider + * + * @returns An Ethers.js compatible Signer instance + */ + getSigner(): Signer { + if (!(this.signerOrProvider instanceof Signer)) { + throw new Error('Need a signer to create a transaction'); + } + return this.signerOrProvider; + } +} diff --git a/packages/sdk/src/TxCreator/ColonyTxCreator.ts b/packages/sdk/src/TxCreator/ColonyTxCreator.ts index da4be8230..945de6e84 100644 --- a/packages/sdk/src/TxCreator/ColonyTxCreator.ts +++ b/packages/sdk/src/TxCreator/ColonyTxCreator.ts @@ -92,7 +92,7 @@ export class ColonyTxCreator< const { actionCid, key, value, branchMask, siblings } = await getCreateMotionProofs( - this.colonyNetwork.getInternalNetworkContract(), + this.colony.colonyNetwork.getInternalNetworkContract(), this.colony.getInternalColonyContract(), this.colony.reputation, this.colony.ext.motions.getInternalVotingReputationContract(), @@ -158,7 +158,7 @@ export class ColonyTxCreator< const { actionCid, key, value, branchMask, siblings } = await getCreateMotionProofs( - this.colonyNetwork.getInternalNetworkContract(), + this.colony.colonyNetwork.getInternalNetworkContract(), this.colony.getInternalColonyContract(), this.colony.reputation, this.colony.ext.motions.getInternalVotingReputationContract(), @@ -219,7 +219,7 @@ export class ColonyTxCreator< ); } const [permissionDomainId, childSkillIndex] = await getPermissionProofs( - this.colonyNetwork.getInternalNetworkContract(), + this.colony.colonyNetwork.getInternalNetworkContract(), this.colony.getInternalColonyContract(), this.permissionConfig.domain, this.permissionConfig.roles, diff --git a/packages/sdk/src/TxCreator/CustomTxCreator.ts b/packages/sdk/src/TxCreator/CustomTxCreator.ts index 8b3e9ec16..ec5e953ba 100644 --- a/packages/sdk/src/TxCreator/CustomTxCreator.ts +++ b/packages/sdk/src/TxCreator/CustomTxCreator.ts @@ -8,12 +8,8 @@ import { import { type ContractReceipt } from 'ethers'; import { type EventData, type TxConfig } from './TxCreator.js'; -import type CustomColonyNetwork from '../ColonyNetwork/CustomColonyNetwork.js'; -import { - type ColonyNetwork, - type MetaTxBaseContract, - MetaTxCreator, -} from '../index.js'; +import { type MetaTxBaseContract, MetaTxCreator } from '../index.js'; +import { type ContractConfig } from '../ContractConfig.js'; /** * Create transactions for custom contracts @@ -32,15 +28,15 @@ class CustomTxCreator< E extends EventData, > extends MetaTxCreator { constructor({ - colonyNetwork, contract, + config, method, args, eventData, txConfig, }: { - colonyNetwork: ColonyNetwork | CustomColonyNetwork; contract: MetaTxBaseContract; + config: ContractConfig; method: M; args: AbiParametersToPrimitiveTypes< ExtractAbiFunction['inputs'], @@ -51,8 +47,8 @@ class CustomTxCreator< }) { const customArgs = args as unknown[]; super({ - colonyNetwork, contract, + config, method, args: customArgs, eventData, diff --git a/packages/sdk/src/TxCreator/EIP2612TxCreator.ts b/packages/sdk/src/TxCreator/EIP2612TxCreator.ts index 644be8e05..f38fb349e 100644 --- a/packages/sdk/src/TxCreator/EIP2612TxCreator.ts +++ b/packages/sdk/src/TxCreator/EIP2612TxCreator.ts @@ -51,13 +51,13 @@ export class EIP2612TxCreator< target: string, [spender, amount]: [string, BigNumberish], ): Promise { - if (!this.colonyNetwork.config.metaTxBroadcasterEndpoint) { + if (!this.config.metaTxBroadcasterEndpoint) { throw new Error( - `No metatransaction broadcaster endpoint found for network ${this.colonyNetwork.network}`, + `No metatransaction broadcaster endpoint found for network ${this.config.network}`, ); } - const signer = this.colonyNetwork.getSigner() as TDSigner; + const signer = this.contract.signer as TDSigner; const { provider } = signer; if (!provider) { @@ -66,7 +66,7 @@ export class EIP2612TxCreator< let chainId: number; - if (this.colonyNetwork.network === Network.Custom) { + if (this.config.network === Network.Custom) { chainId = 1; } else { const networkInfo = await provider.getNetwork(); diff --git a/packages/sdk/src/TxCreator/MetaTxCreator.ts b/packages/sdk/src/TxCreator/MetaTxCreator.ts index 923ae990c..6b2c02078 100644 --- a/packages/sdk/src/TxCreator/MetaTxCreator.ts +++ b/packages/sdk/src/TxCreator/MetaTxCreator.ts @@ -54,13 +54,13 @@ export class MetaTxCreator< encodedTransaction: string, target: string, ): Promise { - if (!this.colonyNetwork.config.metaTxBroadcasterEndpoint) { + if (!this.config.metaTxBroadcasterEndpoint) { throw new Error( - `No metatransaction broadcaster endpoint found for network ${this.colonyNetwork.network}`, + `No metatransaction broadcaster endpoint found for network ${this.config.network}`, ); } - const signer = this.colonyNetwork.getSigner(); + const signer = this.config.getSigner(); const { provider } = signer; if (!provider) { @@ -69,7 +69,7 @@ export class MetaTxCreator< let chainId: number; - if (this.colonyNetwork.network === Network.Custom) { + if (this.config.network === Network.Custom) { chainId = 1; } else { const networkInfo = await provider.getNetwork(); diff --git a/packages/sdk/src/TxCreator/TxCreator.ts b/packages/sdk/src/TxCreator/TxCreator.ts index c54af001f..aaeda9657 100644 --- a/packages/sdk/src/TxCreator/TxCreator.ts +++ b/packages/sdk/src/TxCreator/TxCreator.ts @@ -14,10 +14,7 @@ import { } from '@colony/events'; import { type ParsedLogTransactionReceipt } from '../types.js'; -import { - type ColonyNetwork, - type CustomColonyNetwork, -} from '../ColonyNetwork/index.js'; +import { type ContractConfig } from '../ContractConfig.js'; export interface TxConfig { metadataType?: M; @@ -28,8 +25,8 @@ export interface EventData { } export interface TxCreatorConfig { - colonyNetwork: ColonyNetwork; contract: C; + config: ContractConfig; method: M; args: unknown[] | (() => Promise); eventData?: (receipt: ContractReceipt) => Promise; @@ -161,10 +158,10 @@ export class TxCreator< E extends EventData, MD extends MetadataType, > { - protected colonyNetwork: ColonyNetwork | CustomColonyNetwork; - protected contract: C; + protected config: ContractConfig; + protected method: string; protected args: unknown[] | (() => Promise); @@ -174,22 +171,22 @@ export class TxCreator< protected txConfig?: TxConfig; constructor({ - colonyNetwork, contract, + config, method, args, eventData, txConfig, }: { - colonyNetwork: ColonyNetwork | CustomColonyNetwork; contract: C; + config: ContractConfig; method: M; args: unknown[] | (() => Promise); eventData?: (receipt: ContractReceipt) => Promise; metadataType?: MD; txConfig?: TxConfig; }) { - this.colonyNetwork = colonyNetwork; + this.config = config; this.contract = contract; this.method = method as string; this.args = args; @@ -230,8 +227,8 @@ export class TxCreator< const data = await this.eventData(receipt); if (this.txConfig?.metadataType && data.metadata) { - const getMetadata = this.colonyNetwork.ipfs.getMetadataForEvent.bind( - this.colonyNetwork.ipfs, + const getMetadata = this.config.ipfs.getMetadataForEvent.bind( + this.config.ipfs, IpfsMetadataEvents[this.txConfig.metadataType], data.metadata, ) as () => Promise; @@ -246,15 +243,14 @@ export class TxCreator< } protected async broadcastMetaTx(broadcastData: Record) { - const signer = this.colonyNetwork.getSigner(); - const { provider } = signer; + const { provider } = this.config.getSigner(); if (!provider) { throw new Error('No provider found'); } const res = await fetch( - `${this.colonyNetwork.config.metaTxBroadcasterEndpoint}/broadcast`, + `${this.config.metaTxBroadcasterEndpoint}/broadcast`, { method: 'POST', headers: { diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index cf92d9d95..62328f5b1 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -1,7 +1,6 @@ export type { ContractReceipt, ContractTransaction } from 'ethers'; -// This is a type and only used for TypeScript compilation -// eslint-disable-next-line import/no-extraneous-dependencies export type { TransactionResponse } from '@ethersproject/abstract-provider'; +export type { Abi } from 'abitype'; export { type AnnotationData, @@ -42,6 +41,6 @@ export { } from '@colony/tokens'; export * from './ColonyNetwork/index.js'; +export type { ContractOptions } from './ContractConfig.js'; export * from './TxCreator/index.js'; - export type { ParsedLogTransactionReceipt } from './types.js'; diff --git a/packages/sdk/src/types.ts b/packages/sdk/src/types.ts index 45301d6fc..876906c50 100644 --- a/packages/sdk/src/types.ts +++ b/packages/sdk/src/types.ts @@ -1,5 +1,5 @@ -import type { TransactionReceipt } from '@ethersproject/abstract-provider'; import type { LogDescription } from '@ethersproject/abi'; +import type { TransactionReceipt } from '@ethersproject/abstract-provider'; /** * Custom Transaction receipt for when we manually have to parse logs (metatransactions)