From 6b96604be4587a79dcc9cf86c7ee41a5d11808ad Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Fri, 18 Aug 2023 20:54:15 +0000 Subject: [PATCH 01/13] Implement ethers.Signer on account --- packages/account/src/account.ts | 119 ++++++++++++++++-- .../src/transports/wallet-request-handler.ts | 2 +- 2 files changed, 110 insertions(+), 11 deletions(-) diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index bd312e39b..f54cb46bd 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -1,11 +1,11 @@ import { commons, universal } from '@0xsequence/core' import { migrator, defaults, version } from '@0xsequence/migration' -import { NetworkConfig } from '@0xsequence/network' +import { ChainId, NetworkConfig } from '@0xsequence/network' import { FeeOption, FeeQuote, isRelayer, Relayer, RpcRelayer } from '@0xsequence/relayer' import { tracker } from '@0xsequence/sessions' import { Orchestrator } from '@0xsequence/signhub' -import { encodeTypedDataDigest, getDefaultConnectionInfo } from '@0xsequence/utils' -import { Wallet } from '@0xsequence/wallet' +import { Deferrable, encodeTypedDataDigest, getDefaultConnectionInfo } from '@0xsequence/utils' +import { Wallet, resolveArrayProperties } from '@0xsequence/wallet' import { ethers, TypedDataDomain, TypedDataField } from 'ethers' export type AccountStatus = { @@ -82,7 +82,7 @@ class Chain0Reader implements commons.reader.Reader { } } -export class Account { +export class Account implements ethers.Signer { public readonly address: string public readonly networks: NetworkConfig[] @@ -106,6 +106,90 @@ export class Account { this.migrator = new migrator.Migrator(options.tracker, this.migrations, this.contexts) } + // + // start ethers.Signer required methods + // + + _isSigner: boolean = true + + signTransaction(_transaction: ethers.utils.Deferrable): Promise { + throw new Error('Method not implemented.') + } + + connect(_provider: ethers.providers.Provider): ethers.Signer { + throw new Error('Method not implemented.') + } + + getBalance(_blockTag?: ethers.providers.BlockTag | undefined): Promise { + throw new Error('Method not implemented.') + } + + getTransactionCount(_blockTag?: ethers.providers.BlockTag | undefined): Promise { + throw new Error('Method not implemented.') + } + + estimateGas(_transaction: ethers.utils.Deferrable): Promise { + throw new Error('Method not implemented.') + } + + call( + _transaction: ethers.utils.Deferrable, + _blockTag?: ethers.providers.BlockTag | undefined + ): Promise { + throw new Error('Method not implemented.') + } + + getChainId(): Promise { + throw new Error('Method not implemented.') + } + + getGasPrice(): Promise { + throw new Error('Method not implemented.') + } + + getFeeData(): Promise { + throw new Error('Method not implemented.') + } + + private ensProvider() { + return this.networks.find((n) => n.chainId === 1)?.provider + } + + async resolveName(name: string): Promise { + const provider = this.ensProvider() + + if (!provider) { + throw new Error('ENS network not found.') + } + + const result = await provider.resolveName(name) + if (!result) { + throw new Error('Name not resolved.') + } + + return result + } + + checkTransaction( + _transaction: ethers.utils.Deferrable + ): ethers.utils.Deferrable { + throw new Error('Method not implemented.') + } + + populateTransaction( + _transaction: ethers.utils.Deferrable + ): Promise { + throw new Error('Method not implemented.') + } + + _checkProvider(_operation?: string | undefined): void { + throw new Error('Method not implemented.') + } + + // + // start ethers.Signer required methods + // + static async new(options: { config: commons.config.SimpleConfig tracker: tracker.ConfigTracker & migrator.PresignedMigrationTracker @@ -156,6 +240,10 @@ export class Account { } } + get provider() { + return this.providerFor(this.defaultNetwork()) + } + network(chainId: ethers.BigNumberish): NetworkConfig { const tcid = ethers.BigNumber.from(chainId) const found = this.networks.find(n => tcid.eq(n.chainId)) @@ -163,7 +251,11 @@ export class Account { return found } - provider(chainId: ethers.BigNumberish): ethers.providers.Provider { + defaultNetwork(): ChainId { + return this.networks[0].chainId + } + + providerFor(chainId: ethers.BigNumberish): ethers.providers.Provider { const found = this.network(chainId) if (!found.provider && !found.rpcUrl) throw new Error(`Provider not found for chainId ${chainId}`) return ( @@ -180,7 +272,7 @@ export class Account { // TODO: Networks should be able to provide a reader directly // and we should default to the on-chain reader - return new commons.reader.OnChainReader(this.provider(chainId)) + return new commons.reader.OnChainReader(this.providerFor(chainId)) } relayer(chainId: ethers.BigNumberish): Relayer { @@ -599,7 +691,7 @@ export class Account { signMessage( message: ethers.BytesLike, - chainId: ethers.BigNumberish, + chainId: ethers.BigNumberish = this.defaultNetwork(), cantValidateBehavior: 'ignore' | 'eip6492' | 'throw' = 'ignore' ): Promise { return this.signDigest(ethers.utils.keccak256(message), chainId, true, cantValidateBehavior) @@ -784,13 +876,20 @@ export class Account { } async sendTransaction( - txs: commons.transaction.Transactionish, - chainId: ethers.BigNumberish, + txsPromise: Deferrable | commons.transaction.Transactionish, + chainId: ethers.BigNumberish = this.defaultNetwork(), quote?: FeeQuote, skipPreDecorate: boolean = false, callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void ): Promise { - const status = await this.status(chainId) + const [ + status, + txs + ] = await Promise.all([ + this.status(chainId), + resolveArrayProperties(txsPromise) + ]) + const predecorated = skipPreDecorate ? txs : await this.predecorateTransactions(txs, status, chainId) const signed = await this.signTransactions(predecorated, chainId) // TODO: is it safe to pass status again here? diff --git a/packages/provider/src/transports/wallet-request-handler.ts b/packages/provider/src/transports/wallet-request-handler.ts index 0a9cad4c6..4e5072445 100644 --- a/packages/provider/src/transports/wallet-request-handler.ts +++ b/packages/provider/src/transports/wallet-request-handler.ts @@ -253,7 +253,7 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P if (!account) throw new Error('WalletRequestHandler: wallet account is not configured') // fetch the provider for the specific chain, or undefined will select defaultChain - const provider = this.account?.provider(chainId ?? this.defaultChainId()) + const provider = this.account?.providerFor(chainId ?? this.defaultChainId()) if (!provider) throw new Error(`WalletRequestHandler: wallet provider is not configured for chainId ${chainId}`) const jsonRpcProvider = provider instanceof ethers.providers.JsonRpcProvider ? provider : undefined From 984f47deab92a4a5287a089633a94bbe28f36cb5 Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Tue, 22 Aug 2023 19:05:53 +0000 Subject: [PATCH 02/13] Add account signer abstraction --- packages/account/src/account.ts | 21 +- packages/account/src/signer.ts | 215 +++++++++ packages/account/src/utils.ts | 11 + packages/account/tests/account.spec.ts | 8 +- packages/account/tests/signer.spec.ts | 618 +++++++++++++++++++++++++ packages/tests/src/index.ts | 1 + packages/tests/src/tokens/erc20.ts | 323 +++++++++++++ pnpm-lock.yaml | 42 +- 8 files changed, 1198 insertions(+), 41 deletions(-) create mode 100644 packages/account/src/signer.ts create mode 100644 packages/account/src/utils.ts create mode 100644 packages/account/tests/signer.spec.ts create mode 100644 packages/tests/src/tokens/erc20.ts diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index f54cb46bd..937dcd8a8 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -4,9 +4,10 @@ import { ChainId, NetworkConfig } from '@0xsequence/network' import { FeeOption, FeeQuote, isRelayer, Relayer, RpcRelayer } from '@0xsequence/relayer' import { tracker } from '@0xsequence/sessions' import { Orchestrator } from '@0xsequence/signhub' -import { Deferrable, encodeTypedDataDigest, getDefaultConnectionInfo } from '@0xsequence/utils' -import { Wallet, resolveArrayProperties } from '@0xsequence/wallet' +import { encodeTypedDataDigest, getDefaultConnectionInfo } from '@0xsequence/utils' +import { Wallet } from '@0xsequence/wallet' import { ethers, TypedDataDomain, TypedDataField } from 'ethers' +import { AccountSigner, AccountSignerOptions } from './signer' export type AccountStatus = { original: { @@ -82,7 +83,7 @@ class Chain0Reader implements commons.reader.Reader { } } -export class Account implements ethers.Signer { +export class Account { public readonly address: string public readonly networks: NetworkConfig[] @@ -132,6 +133,10 @@ export class Account implements ethers.Signer { throw new Error('Method not implemented.') } + getSigner(chainId: ChainId, options?: AccountSignerOptions): AccountSigner { + return new AccountSigner(this, chainId, options) + } + call( _transaction: ethers.utils.Deferrable, _blockTag?: ethers.providers.BlockTag | undefined @@ -876,19 +881,13 @@ export class Account implements ethers.Signer { } async sendTransaction( - txsPromise: Deferrable | commons.transaction.Transactionish, + txs: commons.transaction.Transactionish, chainId: ethers.BigNumberish = this.defaultNetwork(), quote?: FeeQuote, skipPreDecorate: boolean = false, callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void ): Promise { - const [ - status, - txs - ] = await Promise.all([ - this.status(chainId), - resolveArrayProperties(txsPromise) - ]) + const status = await this.status(chainId) const predecorated = skipPreDecorate ? txs : await this.predecorateTransactions(txs, status, chainId) const signed = await this.signTransactions(predecorated, chainId) diff --git a/packages/account/src/signer.ts b/packages/account/src/signer.ts new file mode 100644 index 000000000..6e0b78ce5 --- /dev/null +++ b/packages/account/src/signer.ts @@ -0,0 +1,215 @@ +import { ChainId } from "@0xsequence/network" +import { Account } from "./account" +import { ethers } from "ethers" +import { commons } from "@0xsequence/core" +import { FeeOption, proto } from "@0xsequence/relayer" +import { isDeferrable } from "./utils" + +export type AccountSignerOptions = { + cantValidateBehavior?: 'ignore' | 'eip6492' | 'throw', + stubSignatureOverrides?: Map, + selectFee?: ( + txs: ethers.utils.Deferrable | commons.transaction.Transactionish, + options: FeeOption[] + ) => Promise +} + +function encodeGasRefundTransaction(option?: FeeOption) { + if (!option) return [] + + const value = ethers.BigNumber.from(option.value) + + switch (option.token.type) { + case proto.FeeTokenType.UNKNOWN: + return [{ + delegateCall: false, + revertOnError: true, + gasLimit: option.gasLimit, + to: option.to, + value: value.toHexString(), + data: [] + }] + + case proto.FeeTokenType.ERC20_TOKEN: + if (!option.token.contractAddress) { + throw new Error(`No contract address for ERC-20 fee option`) + } + + return [{ + delegateCall: false, + revertOnError: true, + gasLimit: option.gasLimit, + to: option.token.contractAddress, + value: 0, + data: new ethers.utils.Interface([{ + "constant": false, + "inputs": [ + {"type": "address"}, + {"type": "uint256"} + ], + "name": "transfer", + "outputs": [], + "type": "function" + }]).encodeFunctionData('transfer', [option.to, value.toHexString()]) + }] + + default: + throw new Error(`Unhandled fee token type ${option.token.type}`) + } +} + +export class AccountSigner implements ethers.Signer { + public readonly _isSigner = true + + constructor ( + public account: Account, + public chainId: ChainId, + public readonly options?: AccountSignerOptions + ) {} + + get provider() { + return this.account.providerFor(this.chainId) + } + + async getAddress(): Promise { + return this.account.address + } + + signMessage( + message: string | ethers.utils.Bytes + ): Promise { + return this.account.signMessage( + message, + this.chainId, + this.options?.cantValidateBehavior ?? 'throw' + ) + } + + private async defaultSelectFee( + _txs: ethers.utils.Deferrable | commons.transaction.Transactionish, + options: FeeOption[] + ): Promise { + // If no options, return undefined + if (options.length === 0) return undefined + + // If there are multiple options, try them one by one + // until we find one that satisfies the balance requirement + const balanceOfAbi = [{ + "constant": true, + "inputs": [{"type": "address"}], + "name": "balanceOf", + "outputs": [{"type": "uint256"}], + "type": "function" + }] + + for (const option of options) { + if (option.token.type === proto.FeeTokenType.UNKNOWN) { + // Native token + const balance = await this.getBalance() + if (balance.gte(ethers.BigNumber.from(option.value))) { + return option + } + } else if (option.token.contractAddress && option.token.type === proto.FeeTokenType.ERC20_TOKEN) { + // ERC20 token + const token = new ethers.Contract(option.token.contractAddress, balanceOfAbi, this.provider) + const balance = await token.balanceOf(this.account.address) + if (balance.gte(ethers.BigNumber.from(option.value))) { + return option + } + } else { + // Unsupported token type + } + } + + throw new Error("No fee option available - not enough balance") + } + + async sendTransaction( + txsPromise: ethers.utils.Deferrable | commons.transaction.Transactionish + ): Promise { + const txs = isDeferrable(txsPromise) ? ( + await ethers.utils.resolveProperties(txsPromise as ethers.utils.Deferrable)) + : txsPromise + + const prepare = await this.account.prepareTransactions({ + txs, + chainId: this.chainId, + stubSignatureOverrides: this.options?.stubSignatureOverrides ?? new Map() + }) + + const selectMethod = this.options?.selectFee ?? this.defaultSelectFee.bind(this) + const feeOption = await selectMethod(txs, prepare.feeOptions) + + const finalTransactions = [ + ...prepare.transactions, + ...encodeGasRefundTransaction(feeOption) + ] + + return this.account.sendTransaction( + finalTransactions, + this.chainId, + prepare.feeQuote + ) + } + + getBalance(blockTag?: ethers.providers.BlockTag | undefined): Promise { + return this.provider.getBalance(this.account.address, blockTag) + } + + call( + transaction: ethers.utils.Deferrable, + blockTag?: ethers.providers.BlockTag | undefined + ): Promise { + return this.provider.call(transaction, blockTag) + } + + async resolveName(name: string): Promise { + const res = await this.provider.resolveName(name) + if (!res) throw new Error(`Could not resolve name ${name}`) + return res + } + + connect(_provider: ethers.providers.Provider): ethers.Signer { + throw new Error("Method not implemented.") + } + + signTransaction( + transaction: ethers.utils.Deferrable + ): Promise { + throw new Error("Method not implemented.") + } + + getTransactionCount(blockTag?: ethers.providers.BlockTag | undefined): Promise { + throw new Error("Method not implemented.") + } + + estimateGas( + transaction: ethers.utils.Deferrable + ): Promise { + throw new Error("Method not implemented.") + } + + getChainId(): Promise { + return Promise.resolve(ethers.BigNumber.from(this.chainId).toNumber()) + } + + getGasPrice(): Promise { + throw new Error("Method not implemented.") + } + + getFeeData(): Promise { + throw new Error("Method not implemented.") + } + + checkTransaction(transaction: ethers.utils.Deferrable): ethers.utils.Deferrable { + throw new Error("Method not implemented.") + } + + populateTransaction(transaction: ethers.utils.Deferrable): Promise { + throw new Error("Method not implemented.") + } + + _checkProvider(operation?: string | undefined): void { + throw new Error("Method not implemented.") + } +} diff --git a/packages/account/src/utils.ts b/packages/account/src/utils.ts new file mode 100644 index 000000000..3b769906a --- /dev/null +++ b/packages/account/src/utils.ts @@ -0,0 +1,11 @@ +import { ethers } from "ethers" +import { isPromise } from "util/types" + +export function isDeferrable(value: any): value is ethers.utils.Deferrable { + // The value is deferrable if any of the properties is a Promises + if (typeof(value) === "object") { + return Object.keys(value).some((key) => isPromise(value[key])) + } + + return false +} diff --git a/packages/account/tests/account.spec.ts b/packages/account/tests/account.spec.ts index b165dcf80..45ccd5184 100644 --- a/packages/account/tests/account.spec.ts +++ b/packages/account/tests/account.spec.ts @@ -1117,7 +1117,7 @@ describe('Account', () => { }) let nowCalls = 0 -function now(): number { +export function now(): number { if (deterministic) { return Date.parse('2023-02-14T00:00:00.000Z') + 1000 * nowCalls++ } else { @@ -1125,17 +1125,17 @@ function now(): number { } } -function randomWallet(entropy: number | string): ethers.Wallet { +export function randomWallet(entropy: number | string): ethers.Wallet { return new ethers.Wallet(randomBytes(32, entropy)) } -function randomFraction(entropy: number | string): number { +export function randomFraction(entropy: number | string): number { const bytes = randomBytes(7, entropy) bytes[0] &= 0x1f return bytes.reduce((sum, byte) => 256 * sum + byte) / Number.MAX_SAFE_INTEGER } -function randomBytes(length: number, entropy: number | string): Uint8Array { +export function randomBytes(length: number, entropy: number | string): Uint8Array { if (deterministic) { let bytes = '' while (bytes.length < 2 * length) { diff --git a/packages/account/tests/signer.spec.ts b/packages/account/tests/signer.spec.ts new file mode 100644 index 000000000..bc536dea0 --- /dev/null +++ b/packages/account/tests/signer.spec.ts @@ -0,0 +1,618 @@ +import { commons, v1, v2 } from '@0xsequence/core' +import { migrator } from '@0xsequence/migration' +import { NetworkConfig } from '@0xsequence/network' +import { FeeOption, FeeQuote, LocalRelayer, LocalRelayerOptions, Relayer, proto } from '@0xsequence/relayer' +import { tracker, trackers } from '@0xsequence/sessions' +import { Orchestrator } from '@0xsequence/signhub' +import * as utils from '@0xsequence/tests' +import { Wallet } from '@0xsequence/wallet' +import * as chai from 'chai' +import chaiAsPromised from 'chai-as-promised' +import { ethers } from 'ethers' +import hardhat from 'hardhat' + +import { Account } from '../src/account' +import { now, randomWallet } from './account.spec' +import { createERC20 } from '@0xsequence/tests/src/tokens/erc20' + +const { expect } = chai.use(chaiAsPromised) + +describe('Account signer', () => { + let provider1: ethers.providers.JsonRpcProvider + let provider2: ethers.providers.JsonRpcProvider + + let signer1: ethers.Signer + let signer2: ethers.Signer + + let contexts: commons.context.VersionedContext + let networks: NetworkConfig[] + + let tracker: tracker.ConfigTracker & migrator.PresignedMigrationTracker + + let defaultArgs: { + contexts: commons.context.VersionedContext + networks: NetworkConfig[] + tracker: tracker.ConfigTracker & migrator.PresignedMigrationTracker + } + + before(async () => { + provider1 = new ethers.providers.Web3Provider(hardhat.network.provider.send) + provider2 = new ethers.providers.JsonRpcProvider('http://127.0.0.1:7048') + + // TODO: Implement migrations on local config tracker + tracker = new trackers.local.LocalConfigTracker(provider1) as any + + networks = [ + { + chainId: 31337, + name: 'hardhat', + provider: provider1, + rpcUrl: '', + relayer: new LocalRelayer(provider1.getSigner()) + }, + { + chainId: 31338, + name: 'hardhat2', + provider: provider2, + rpcUrl: 'http://127.0.0.1:7048', + relayer: new LocalRelayer(provider2.getSigner()) + } + ] + + signer1 = provider1.getSigner() + signer2 = provider2.getSigner() + + contexts = await utils.context.deploySequenceContexts(signer1) + const context2 = await utils.context.deploySequenceContexts(signer2) + + expect(contexts).to.deep.equal(context2) + + defaultArgs = { + contexts, + networks, + tracker + } + }) + + describe('with new account', () => { + var account: Account + var config: any + var accountSigner: ethers.Wallet + + beforeEach(async () => { + accountSigner = randomWallet('Should create a new account') + config = { + threshold: 1, + checkpoint: Math.floor(now() / 1000), + signers: [{ address: accountSigner.address, weight: 1 }] + } + + account = await Account.new({ + ...defaultArgs, + config, + orchestrator: new Orchestrator([accountSigner]) + }) + }) + + ;([ + 31337, + 31338 + ]).map((chainId: number) => { + context(`for chain ${chainId}`, () => { + it('should send transaction', async () => { + const signer = account.getSigner(chainId) + + const res = await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + }) + + it('should send batch transaction', async () => { + const signer = account.getSigner(chainId) + + const res = await signer.sendTransaction([ + { + to: ethers.Wallet.createRandom().address, + }, + { + to: ethers.Wallet.createRandom().address, + }, + ]) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + }) + + it('should send two transactions (one has deploy)', async () => { + const signer = account.getSigner(chainId) + + expect(await signer.provider.getCode(account.address)).to.equal('0x') + + await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(await signer.provider.getCode(account.address)).to.not.equal('0x') + + const res = await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + }) + + it('should fail to sign message because not deployed', async () => { + const signer = account.getSigner(chainId) + + await expect(signer.signMessage(ethers.utils.randomBytes(32))) + .to.be.rejectedWith('Wallet cannot validate onchain') + }) + + it('should sign message after deployment', async () => { + const signer = account.getSigner(chainId) + + await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(await signer.provider.getCode(account.address)).to.not.equal('0x') + + const signature = await signer.signMessage(ethers.utils.randomBytes(32)) + expect(signature).to.exist + expect(signature).to.not.equal('0x') + }) + + it('should sign a message (undeployed) when using EIP6492', async () => { + const signer = account.getSigner(chainId, { cantValidateBehavior: 'eip6492' }) + + const signature = await signer.signMessage(ethers.utils.randomBytes(32)) + expect(signature).to.exist + expect(signature).to.not.equal('0x') + }) + + it('should return account address', async () => { + expect(account.address).to.equal(await account.getSigner(chainId).getAddress()) + }) + + it('should return chainId', async () => { + expect(chainId).to.equal(await account.getSigner(chainId).getChainId()) + }) + + it('should call select fee even if there is no fee', async () => { + let callsToSelectFee = 0 + + const tx = { + to: ethers.Wallet.createRandom().address, + } + + const signer = account.getSigner(chainId, { + selectFee: async (txs: any, options: FeeOption[]) => { + callsToSelectFee++ + expect(txs).to.deep.equal(tx) + expect(options).to.deep.equal([]) + return undefined + } + }) + + const res = await signer.sendTransaction(tx) + + expect(callsToSelectFee).to.equal(1) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + }) + + describe('select fee', () => { + var account: never + var getAccount: (feeOptions: FeeOption[], feeQuote: FeeQuote) => Promise + + beforeEach(async () => { + class LocalRelayerWithFee extends LocalRelayer { + constructor( + options: LocalRelayerOptions | ethers.Signer, + public feeOptions: FeeOption[], + public quote: FeeQuote + ) { + super(options) + } + + async getFeeOptions( + _address: string, + ..._transactions: commons.transaction.Transaction[] + ): Promise<{ options: FeeOption[] }> { + return { options: this.feeOptions, quote: this.quote } as any + } + + async getFeeOptionsRaw( + _entrypoint: string, _data: ethers.utils.BytesLike + ): Promise<{ options: FeeOption[] }> { + return { options: this.feeOptions, quote: this.quote } as any + } + + async gasRefundOptions( + _address: string, + ..._transactions: commons.transaction.Transaction[] + ): Promise { + return this.feeOptions + } + + async relay( + signedTxs: commons.transaction.IntendedTransactionBundle, + quote?: FeeQuote | undefined, + waitForReceipt?: boolean | undefined + ): Promise> { + expect(quote).to.equal(this.quote) + return super.relay(signedTxs, quote, waitForReceipt) + } + } + + getAccount = async (feeOptions: FeeOption[], feeQuote: FeeQuote) => { + return Account.new({ + ...defaultArgs, + networks: defaultArgs.networks.map((n) => { + return { + ...n, + relayer: new LocalRelayerWithFee( + chainId === 31337 ? signer1 : signer2, + feeOptions, + feeQuote + ) + } + }), + config, + orchestrator: new Orchestrator([accountSigner]) + }) + } + }) + + it('should automatically select native fee', async () => { + const feeOptions: FeeOption[] = [{ + token: { + chainId, + name: 'native', + symbol: 'ETH', + type: proto.FeeTokenType.UNKNOWN, + logoURL: '' + }, + to: ethers.Wallet.createRandom().address, + value: '12', + gasLimit: 100000 + }] + + const feeQuote: FeeQuote = { + _tag: 'FeeQuote', + _quote: ethers.utils.randomBytes(99) + } + + const account = await getAccount(feeOptions, feeQuote) + const signer = account.getSigner(chainId) + + await (chainId === 31337 ? signer1 : signer2).sendTransaction({ + to: account.address, + value: 12 + }) + + const res = await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + }) + + it('should reject if balance is not enough', async () => { + const feeOptions: FeeOption[] = [{ + token: { + chainId, + name: 'native', + symbol: 'ETH', + type: proto.FeeTokenType.UNKNOWN, + logoURL: '' + }, + to: ethers.Wallet.createRandom().address, + value: ethers.utils.parseEther('12').toString(), + gasLimit: 100000 + }] + + const feeQuote: FeeQuote = { + _tag: 'FeeQuote', + _quote: ethers.utils.randomBytes(99) + } + + const account = await getAccount(feeOptions, feeQuote) + const signer = account.getSigner(chainId) + + await (chainId === 31337 ? signer1 : signer2).sendTransaction({ + to: account.address, + value: 11 + }) + + const res = signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.be.rejectedWith('No fee option available - not enough balance') + }) + + it('should automatically select ERC20 fee', async () => { + const token = await createERC20( + (chainId === 31337 ? signer1 : signer2), + "Test Token", + "TEST", + 18 + ) + + const recipient = ethers.Wallet.createRandom().address + const feeOptions: FeeOption[] = [{ + token: { + chainId, + name: 'TEST', + symbol: 'TEST', + type: proto.FeeTokenType.ERC20_TOKEN, + logoURL: '', + contractAddress: token.address + }, + to: recipient, + value: ethers.utils.parseEther('250').toString(), + gasLimit: 400000 + }] + + const feeQuote: FeeQuote = { + _tag: 'FeeQuote', + _quote: ethers.utils.randomBytes(99) + } + + const account = await getAccount(feeOptions, feeQuote) + const signer = account.getSigner(chainId) + + await token.mint(account.address, ethers.utils.parseEther('6000')) + + const res = await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + expect(await token.balanceOf(recipient)).to.deep.equal(ethers.utils.parseEther('250')) + }) + + it('should reject ERC20 fee if not enough balance', async () => { + const token = await createERC20( + (chainId === 31337 ? signer1 : signer2), + "Test Token", + "TEST", + 18 + ) + + const recipient = ethers.Wallet.createRandom().address + const feeOptions: FeeOption[] = [{ + token: { + chainId, + name: 'TEST', + symbol: 'TEST', + type: proto.FeeTokenType.ERC20_TOKEN, + logoURL: '', + contractAddress: token.address + }, + to: recipient, + value: ethers.utils.parseEther('250').toString(), + gasLimit: 400000 + }] + + const feeQuote: FeeQuote = { + _tag: 'FeeQuote', + _quote: ethers.utils.randomBytes(99) + } + + const account = await getAccount(feeOptions, feeQuote) + const signer = account.getSigner(chainId) + + const res = signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.be.rejectedWith('No fee option available - not enough balance') + }) + + it('should automatically select ERC20 fee if user has no ETH', async () => { + const token = await createERC20( + (chainId === 31337 ? signer1 : signer2), + "Test Token", + "TEST", + 18 + ) + + const recipient = ethers.Wallet.createRandom().address + const feeOptions: FeeOption[] = [{ + token: { + chainId, + name: 'native', + symbol: 'ETH', + type: proto.FeeTokenType.UNKNOWN, + logoURL: '' + }, + to: recipient, + value: ethers.utils.parseEther('12').toString(), + gasLimit: 100000 + }, { + token: { + chainId, + name: 'TEST', + symbol: 'TEST', + type: proto.FeeTokenType.ERC20_TOKEN, + logoURL: '', + contractAddress: token.address + }, + to: recipient, + value: ethers.utils.parseEther('11').toString(), + gasLimit: 400000 + }] + + const feeQuote: FeeQuote = { + _tag: 'FeeQuote', + _quote: ethers.utils.randomBytes(99) + } + + const account = await getAccount(feeOptions, feeQuote) + const signer = account.getSigner(chainId) + + await token.mint(account.address, ethers.utils.parseEther('11')) + + const res = await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + expect(await token.balanceOf(recipient)).to.deep.equal(ethers.utils.parseEther('11')) + }) + + it('should select fee using callback (first option)', async () => { + const recipient = ethers.Wallet.createRandom().address + + const token = await createERC20( + (chainId === 31337 ? signer1 : signer2), + "Test Token", + "TEST", + 18 + ) + + const feeOptions: FeeOption[] = [{ + token: { + chainId, + name: 'native', + symbol: 'ETH', + type: proto.FeeTokenType.UNKNOWN, + logoURL: '' + }, + to: recipient, + value: '5', + gasLimit: 100000 + }, { + token: { + chainId, + name: 'TEST', + symbol: 'TEST', + type: proto.FeeTokenType.ERC20_TOKEN, + logoURL: '', + contractAddress: token.address + }, + to: recipient, + value: ethers.utils.parseEther('11').toString(), + gasLimit: 400000 + }] + + const feeQuote: FeeQuote = { + _tag: 'FeeQuote', + _quote: ethers.utils.randomBytes(99) + } + + const account = await getAccount(feeOptions, feeQuote) + const signer = account.getSigner(chainId, { + selectFee: async (_txs: any, options: FeeOption[]) => { + expect(options).to.deep.equal(feeOptions) + return options[0] + } + }) + + await (chainId === 31337 ? signer1 : signer2).sendTransaction({ + to: account.address, + value: 5 + }) + + const res = await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + expect(await signer.provider.getBalance(recipient)).to.deep.equal(ethers.BigNumber.from('5')) + expect(await token.balanceOf(recipient)).to.deep.equal(ethers.utils.parseEther('0')) + }) + + it('should select fee using callback (second option)', async () => { + const recipient = ethers.Wallet.createRandom().address + + const token = await createERC20( + (chainId === 31337 ? signer1 : signer2), + "Test Token", + "TEST", + 18 + ) + + const feeOptions: FeeOption[] = [{ + token: { + chainId, + name: 'native', + symbol: 'ETH', + type: proto.FeeTokenType.UNKNOWN, + logoURL: '' + }, + to: recipient, + value: '5', + gasLimit: 100000 + }, { + token: { + chainId, + name: 'TEST', + symbol: 'TEST', + type: proto.FeeTokenType.ERC20_TOKEN, + logoURL: '', + contractAddress: token.address + }, + to: recipient, + value: ethers.utils.parseEther('11').toString(), + gasLimit: 400000 + }] + + const feeQuote: FeeQuote = { + _tag: 'FeeQuote', + _quote: ethers.utils.randomBytes(99) + } + + const account = await getAccount(feeOptions, feeQuote) + const signer = account.getSigner(chainId, { + selectFee: async (_txs: any, options: FeeOption[]) => { + expect(options).to.deep.equal(feeOptions) + return options[1] + } + }) + + await token.mint(account.address, ethers.utils.parseEther('11')) + + const res = await signer.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + + expect(res).to.exist + expect(res.hash).to.exist + + expect(await signer.provider.getTransaction(res.hash)).to.exist + expect(await signer.provider.getBalance(recipient)).to.deep.equal(ethers.BigNumber.from('0')) + expect(await token.balanceOf(recipient)).to.deep.equal(ethers.utils.parseEther('11')) + }) + }) + }) + }) + }) +}) diff --git a/packages/tests/src/index.ts b/packages/tests/src/index.ts index 84ab2305d..37c060faa 100644 --- a/packages/tests/src/index.ts +++ b/packages/tests/src/index.ts @@ -5,3 +5,4 @@ export * as utils from './utils' export * as configs from './configs' export * as singleton from './singletonFactory' +export * as erc20 from './tokens/erc20' diff --git a/packages/tests/src/tokens/erc20.ts b/packages/tests/src/tokens/erc20.ts new file mode 100644 index 000000000..451477b95 --- /dev/null +++ b/packages/tests/src/tokens/erc20.ts @@ -0,0 +1,323 @@ +/* +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.3; + +contract SimpleERC20 { + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + uint256 public totalSupply; + + string public name; + string public symbol; + uint8 public decimals; + + constructor(string memory _name, string memory _symbol, uint8 _decimals) { + name = _name; + symbol = _symbol; + decimals = _decimals; + } + + function mint(address to, uint256 amount) public { + totalSupply += amount; + balanceOf[to] += amount; + emit Transfer(address(0), to, amount); + } + + function transfer(address to, uint256 value) public returns (bool) { + balanceOf[msg.sender] -= value; + balanceOf[to] += value; + emit Transfer(msg.sender, to, value); + return true; + } + + function approve(address spender, uint256 value) public returns (bool) { + allowance[msg.sender][spender] = value; + emit Approval(msg.sender, spender, value); + return true; + } + + function transferFrom(address from, address to, uint256 value) public returns (bool) { + balanceOf[from] -= value; + balanceOf[to] += value; + allowance[from][msg.sender] -= value; + + emit Transfer(from, to, value); + return true; + } + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); +} +*/ + +import { ethers } from "ethers" + +export const TEST_ERC20_ABI = [ + { + "inputs": [ + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "_decimals", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] + +export const TEST_ERC20_BYTECODE = "0x60806040523480156200001157600080fd5b506040516200128b3803806200128b833981810160405281019062000037919062000250565b82600390816200004891906200053b565b5081600490816200005a91906200053b565b5080600560006101000a81548160ff021916908360ff16021790555050505062000622565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620000e8826200009d565b810181811067ffffffffffffffff821117156200010a5762000109620000ae565b5b80604052505050565b60006200011f6200007f565b90506200012d8282620000dd565b919050565b600067ffffffffffffffff82111562000150576200014f620000ae565b5b6200015b826200009d565b9050602081019050919050565b60005b83811015620001885780820151818401526020810190506200016b565b60008484015250505050565b6000620001ab620001a58462000132565b62000113565b905082815260208101848484011115620001ca57620001c962000098565b5b620001d784828562000168565b509392505050565b600082601f830112620001f757620001f662000093565b5b81516200020984826020860162000194565b91505092915050565b600060ff82169050919050565b6200022a8162000212565b81146200023657600080fd5b50565b6000815190506200024a816200021f565b92915050565b6000806000606084860312156200026c576200026b62000089565b5b600084015167ffffffffffffffff8111156200028d576200028c6200008e565b5b6200029b86828701620001df565b935050602084015167ffffffffffffffff811115620002bf57620002be6200008e565b5b620002cd86828701620001df565b9250506040620002e08682870162000239565b9150509250925092565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200033d57607f821691505b602082108103620003535762000352620002f5565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b60008160020a8302905092915050565b600060088302620003c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200037e565b620003cc86836200037e565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600062000419620004136200040d84620003e4565b620003ee565b620003e4565b9050919050565b6000819050919050565b6200043583620003f8565b6200044d620004448262000420565b8484546200038e565b825550505050565b600090565b6200046462000455565b620004718184846200042a565b505050565b5b8181101562000499576200048d6000826200045a565b60018101905062000477565b5050565b601f821115620004e857620004b28162000359565b620004bd846200036e565b81016020851015620004cd578190505b620004e5620004dc856200036e565b83018262000476565b50505b505050565b60008160020a8304905092915050565b60006200051060001984600802620004ed565b1980831691505092915050565b60006200052b8383620004fd565b9150826002028217905092915050565b6200054682620002ea565b67ffffffffffffffff811115620005625762000561620000ae565b5b6200056e825462000324565b6200057b8282856200049d565b600060209050601f831160018114620005b357600084156200059e578287015190505b620005aa85826200051d565b8655506200061a565b601f198416620005c38662000359565b60005b82811015620005ed57848901518255600182019150602085019450602081019050620005c6565b868310156200060d578489015162000609601f891682620004fd565b8355505b6001600288020188555050505b505050505050565b610c5980620006326000396000f3fe608060405234801561001057600080fd5b50600436106100bb576000357c01000000000000000000000000000000000000000000000000000000009004806340c10f191161008357806340c10f191461017a57806370a082311461019657806395d89b41146101c6578063a9059cbb146101e4578063dd62ed3e14610214576100bb565b806306fdde03146100c0578063095ea7b3146100de57806318160ddd1461010e57806323b872dd1461012c578063313ce5671461015c575b600080fd5b6100c8610244565b6040516100d591906108da565b60405180910390f35b6100f860048036038101906100f39190610995565b6102d2565b60405161010591906109f0565b60405180910390f35b6101166103c4565b6040516101239190610a1a565b60405180910390f35b61014660048036038101906101419190610a35565b6103ca565b60405161015391906109f0565b60405180910390f35b610164610579565b6040516101719190610aa4565b60405180910390f35b610194600480360381019061018f9190610995565b61058c565b005b6101b060048036038101906101ab9190610abf565b610664565b6040516101bd9190610a1a565b60405180910390f35b6101ce61067c565b6040516101db91906108da565b60405180910390f35b6101fe60048036038101906101f99190610995565b61070a565b60405161020b91906109f0565b60405180910390f35b61022e60048036038101906102299190610aec565b610825565b60405161023b9190610a1a565b60405180910390f35b6003805461025190610b5b565b80601f016020809104026020016040519081016040528092919081815260200182805461027d90610b5b565b80156102ca5780601f1061029f576101008083540402835291602001916102ca565b820191906000526020600020905b8154815290600101906020018083116102ad57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516103b29190610a1a565b60405180910390a36001905092915050565b60025481565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461041a9190610bbb565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461046f9190610bef565b9250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546105029190610bbb565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516105669190610a1a565b60405180910390a3600190509392505050565b600560009054906101000a900460ff1681565b806002600082825461059e9190610bef565b92505081905550806000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546105f39190610bef565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516106589190610a1a565b60405180910390a35050565b60006020528060005260406000206000915090505481565b6004805461068990610b5b565b80601f01602080910402602001604051908101604052809291908181526020018280546106b590610b5b565b80156107025780601f106106d757610100808354040283529160200191610702565b820191906000526020600020905b8154815290600101906020018083116106e557829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461075a9190610bbb565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546107af9190610bef565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516108139190610a1a565b60405180910390a36001905092915050565b6001602052816000526040600020602052806000526040600020600091509150505481565b600081519050919050565b600082825260208201905092915050565b60005b83811015610884578082015181840152602081019050610869565b60008484015250505050565b6000601f19601f8301169050919050565b60006108ac8261084a565b6108b68185610855565b93506108c6818560208601610866565b6108cf81610890565b840191505092915050565b600060208201905081810360008301526108f481846108a1565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061092c82610901565b9050919050565b61093c81610921565b811461094757600080fd5b50565b60008135905061095981610933565b92915050565b6000819050919050565b6109728161095f565b811461097d57600080fd5b50565b60008135905061098f81610969565b92915050565b600080604083850312156109ac576109ab6108fc565b5b60006109ba8582860161094a565b92505060206109cb85828601610980565b9150509250929050565b60008115159050919050565b6109ea816109d5565b82525050565b6000602082019050610a0560008301846109e1565b92915050565b610a148161095f565b82525050565b6000602082019050610a2f6000830184610a0b565b92915050565b600080600060608486031215610a4e57610a4d6108fc565b5b6000610a5c8682870161094a565b9350506020610a6d8682870161094a565b9250506040610a7e86828701610980565b9150509250925092565b600060ff82169050919050565b610a9e81610a88565b82525050565b6000602082019050610ab96000830184610a95565b92915050565b600060208284031215610ad557610ad46108fc565b5b6000610ae38482850161094a565b91505092915050565b60008060408385031215610b0357610b026108fc565b5b6000610b118582860161094a565b9250506020610b228582860161094a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610b7357607f821691505b602082108103610b8657610b85610b2c565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610bc68261095f565b9150610bd18361095f565b9250828203905081811115610be957610be8610b8c565b5b92915050565b6000610bfa8261095f565b9150610c058361095f565b9250828201905080821115610c1d57610c1c610b8c565b5b9291505056fea2646970667358221220129f37bd61cdb5c232d63f8cc989264602a3f614c75e0376a02d7d2d2d8910a164736f6c63430008150033" + +export function createERC20(signer: ethers.Signer, name: string, symbol: string, decimals: number) { + return new ethers.ContractFactory(TEST_ERC20_ABI, TEST_ERC20_BYTECODE, signer).deploy(name, symbol, decimals) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b4f50eac..697c5cbb8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -394,7 +394,7 @@ importers: version: 2.0.0(hardhat@2.17.1)(web3@1.10.0) '@typechain/ethers-v5': specifier: ^10.1.1 - version: 10.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.1.1)(typescript@5.1.6) + version: 10.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.1.1)(typescript@4.9.4) dotenv: specifier: ^16.0.3 version: 16.0.3 @@ -403,7 +403,7 @@ importers: version: 5.7.2 typechain: specifier: ^8.1.1 - version: 8.1.1(typescript@5.1.6) + version: 8.1.1(typescript@4.9.4) packages/estimator: dependencies: @@ -3765,7 +3765,7 @@ packages: hardhat: ^2.0.0 dependencies: ethers: 5.7.2 - hardhat: 2.17.1(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.17.1(ts-node@10.9.1)(typescript@4.9.4) dev: true /@nomiclabs/hardhat-web3@2.0.0(hardhat@2.17.1)(web3@1.10.0): @@ -3775,7 +3775,7 @@ packages: web3: ^1.0.0-beta.36 dependencies: '@types/bignumber.js': 5.0.0 - hardhat: 2.17.1(ts-node@10.9.1)(typescript@5.1.6) + hardhat: 2.17.1(ts-node@10.9.1)(typescript@4.9.4) web3: 1.10.0 dev: true @@ -4081,7 +4081,7 @@ packages: resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} dev: true - /@typechain/ethers-v5@10.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.1.1)(typescript@5.1.6): + /@typechain/ethers-v5@10.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.1.1)(typescript@4.9.4): resolution: {integrity: sha512-ikaq0N/w9fABM+G01OFmU3U3dNnyRwEahkdvi9mqy1a3XwKiPZaF/lu54OcNaEWnpvEYyhhS0N7buCtLQqC92w==} peerDependencies: '@ethersproject/abi': ^5.0.0 @@ -4096,9 +4096,9 @@ packages: '@ethersproject/providers': 5.7.2 ethers: 5.7.2 lodash: 4.17.21 - ts-essentials: 7.0.3(typescript@5.1.6) - typechain: 8.1.1(typescript@5.1.6) - typescript: 5.1.6 + ts-essentials: 7.0.3(typescript@4.9.4) + typechain: 8.1.1(typescript@4.9.4) + typescript: 4.9.4 dev: true /@types/async-eventemitter@0.2.1: @@ -4257,10 +4257,6 @@ packages: resolution: {integrity: sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==} dev: true - /@types/node@20.4.5: - resolution: {integrity: sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==} - dev: true - /@types/normalize-package-data@2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true @@ -4278,7 +4274,7 @@ packages: /@types/readable-stream@2.3.15: resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} dependencies: - '@types/node': 20.4.5 + '@types/node': 18.16.1 safe-buffer: 5.1.2 dev: true @@ -8978,7 +8974,7 @@ packages: - utf-8-validate dev: true - /hardhat@2.17.1(ts-node@10.9.1)(typescript@5.1.6): + /hardhat@2.17.1(ts-node@10.9.1)(typescript@4.9.4): resolution: {integrity: sha512-1PxRkfjhEzXs/wDxI5YgzYBxNmvzifBTjYzuopwel+vXpAhCudplusJthN5eig0FTs4qbi828DBIITEDh8x9LA==} hasBin: true peerDependencies: @@ -9036,7 +9032,7 @@ packages: stacktrace-parser: 0.1.10 ts-node: 10.9.1(@types/node@18.16.1)(typescript@4.9.4) tsort: 0.0.1 - typescript: 5.1.6 + typescript: 4.9.4 undici: 5.22.1 uuid: 8.3.2 ws: 7.5.9 @@ -13704,12 +13700,12 @@ packages: string-format: 2.0.0 dev: true - /ts-essentials@7.0.3(typescript@5.1.6): + /ts-essentials@7.0.3(typescript@4.9.4): resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} peerDependencies: typescript: '>=3.7.0' dependencies: - typescript: 5.1.6 + typescript: 4.9.4 dev: true /ts-node@10.9.1(@types/node@18.16.1)(typescript@4.9.4): @@ -13886,7 +13882,7 @@ packages: resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} dev: true - /typechain@8.1.1(typescript@5.1.6): + /typechain@8.1.1(typescript@4.9.4): resolution: {integrity: sha512-uF/sUvnXTOVF2FHKhQYnxHk4su4JjZR8vr4mA2mBaRwHTbwh0jIlqARz9XJr1tA0l7afJGvEa1dTSi4zt039LQ==} hasBin: true peerDependencies: @@ -13901,8 +13897,8 @@ packages: mkdirp: 1.0.4 prettier: 2.8.8 ts-command-line-args: 2.3.1 - ts-essentials: 7.0.3(typescript@5.1.6) - typescript: 5.1.6 + ts-essentials: 7.0.3(typescript@4.9.4) + typescript: 4.9.4 transitivePeerDependencies: - supports-color dev: true @@ -13931,12 +13927,6 @@ packages: engines: {node: '>=4.2.0'} dev: true - /typescript@5.1.6: - resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} - engines: {node: '>=14.17'} - hasBin: true - dev: true - /typeson-registry@1.0.0-alpha.39: resolution: {integrity: sha512-NeGDEquhw+yfwNhguLPcZ9Oj0fzbADiX4R0WxvoY8nGhy98IbzQy1sezjoEFWOywOboj/DWehI+/aUlRVrJnnw==} engines: {node: '>=10.0.0'} From 6d71b89478cf4406d68ed091d7487a8a426bc22c Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Thu, 24 Aug 2023 16:29:58 +0000 Subject: [PATCH 03/13] Split service from session and make it optional --- packages/auth/src/services.ts | 333 ++++++++++++++++++++++++ packages/auth/src/session.ts | 383 ++++------------------------ packages/auth/tests/session.spec.ts | 328 ++++++++++++------------ 3 files changed, 539 insertions(+), 505 deletions(-) create mode 100644 packages/auth/src/services.ts diff --git a/packages/auth/src/services.ts b/packages/auth/src/services.ts new file mode 100644 index 000000000..9db2553cf --- /dev/null +++ b/packages/auth/src/services.ts @@ -0,0 +1,333 @@ +import { Account } from "@0xsequence/account" +import { SequenceAPIClient } from "@0xsequence/api" +import { ETHAuth, Proof } from "@0xsequence/ethauth" +import { Indexer, SequenceIndexerClient } from "@0xsequence/indexer" +import { SequenceMetadataClient } from "@0xsequence/metadata" +import { ChainIdLike, findNetworkConfig } from "@0xsequence/network" +import { getDefaultConnectionInfo, jwtDecodeClaims } from "@0xsequence/utils" +import { ethers } from "ethers" + +export type SessionMeta = { + // name of the app requesting the session, used with ETHAuth + name: string + + // expiration in seconds for a session before it expires, used with ETHAuth + expiration?: number +} + +export type ServicesSettings = { + metadata: SessionMeta, + sequenceApiUrl: string, + sequenceApiChainId: ethers.BigNumberish, + sequenceMetadataUrl: string, +} + +export type SessionJWT = { + token: string + expiration: number +} + +type SessionJWTPromise = { + token: Promise + expiration: number +} + +type ProofStringPromise = { + proofString: Promise + expiration: number +} + +function getJWTExpiration(jwt: string): number { + return jwtDecodeClaims<{ exp: number }>(jwt).exp +} + +// Default session expiration of ETHAuth token (1 week) +export const DEFAULT_SESSION_EXPIRATION = 60 * 60 * 24 * 7 + +// Long session expiration of ETHAuth token (~1 year) +export const LONG_SESSION_EXPIRATION = 3e7 + +const EXPIRATION_JWT_MARGIN = 60 // seconds + +export class Services { + _initialAuthRequest: Promise + + // proof strings are indexed by account address and app name, see getProofStringKey() + private readonly proofStrings: Map = new Map() + + private onAuthCallbacks: ((result: PromiseSettledResult) => void)[] = [] + + private apiClient: SequenceAPIClient | undefined + private metadataClient: SequenceMetadataClient | undefined + private indexerClients: Map = new Map() + + constructor( + public readonly account: Account, + public readonly settings: ServicesSettings, + public readonly status: { + jwt?: SessionJWTPromise, + metadata?: SessionMeta + } = {} + ) {} + + private now(): number { + return Math.floor(Date.now() / 1000) + } + + get expiration(): number { + return Math.max( + this.settings.metadata.expiration ?? + DEFAULT_SESSION_EXPIRATION + , 120) + } + + onAuth(cb: (result: PromiseSettledResult) => void) { + this.onAuthCallbacks.push(cb) + } + + async dump(): Promise<{ + jwt?: SessionJWT, + metadata?: SessionMeta + }> { + if (!this.status.jwt) return { metadata: this.settings.metadata } + + return { + jwt: { + token: await this.status.jwt.token, + expiration: this.status.jwt.expiration + }, + metadata: this.status.metadata + } + } + + auth(maxTries: number = 5): Promise { + if (this._initialAuthRequest) return this._initialAuthRequest + + this._initialAuthRequest = (async () => { + const url = this.settings.sequenceApiUrl + if (!url) throw Error('No sequence api url') + + let jwtAuth: string | undefined + for (let i = 0; ; i++) { + try { + jwtAuth = (await this.getJWT(true)).token + break + } catch (error) { + if (i === maxTries - 1) { + console.error(`couldn't authenticate after ${maxTries} attempts`, error) + throw error + } + } + } + + return new SequenceAPIClient(url, jwtAuth) + })() + + return this._initialAuthRequest + } + + private async getJWT(tryAuth: boolean): Promise { + const url = this.settings.sequenceApiUrl + if (!url) throw Error('No sequence api url') + + // check if we already have or are waiting for a token + if (this.status.jwt) { + const jwt = this.status.jwt + const token = await jwt.token + + if (this.now() < jwt.expiration) { + return { token, expiration: jwt.expiration } + } + + // token expired, delete it and get a new one + this.status.jwt = undefined + } + + if (!tryAuth) { + throw new Error('no auth token in memory') + } + + const proofStringKey = this.getProofStringKey() + const { proofString, expiration } = this.getProofString(proofStringKey) + + const jwt = { + token: proofString + .then(async proofString => { + const api = new SequenceAPIClient(url) + + const authResp = await api.getAuthToken({ ewtString: proofString }) + + if (authResp?.status === true && authResp.jwtToken.length !== 0) { + return authResp.jwtToken + } else { + if (!(await this.isProofStringValid(proofString))) { + this.proofStrings.delete(proofStringKey) + } + throw new Error('no auth token from server') + } + }) + .catch(reason => { + this.status.jwt = undefined + throw reason + }), + expiration + } + + this.status.jwt = jwt + + jwt.token + .then(() => { + this.onAuthCallbacks.forEach(cb => { + try { + cb({ status: 'fulfilled', value: undefined }) + } catch {} + }) + }) + .catch((reason: any) => { + this.onAuthCallbacks.forEach(cb => { + try { + cb({ status: 'rejected', reason }) + } catch {} + }) + }) + + const token = await jwt.token + return { token, expiration } + } + + private getProofStringKey(): string { + return `${this.account.address} - ${this.settings.metadata.name}` + } + + private async isProofStringValid(proofString: string): Promise { + try { + const ethAuth = new ETHAuth() + const chainId = ethers.BigNumber.from(this.settings.sequenceApiChainId) + const network = findNetworkConfig(this.account.networks, chainId) + if (!network) throw Error('No network found') + ethAuth.chainId = chainId.toNumber() + + // TODO: Modify ETHAuth so it can take a provider instead of a url + ethAuth.provider = new ethers.providers.StaticJsonRpcProvider( + getDefaultConnectionInfo(network.rpcUrl), { + name: '', + chainId: chainId.toNumber() + }) + + await ethAuth.decodeProof(proofString) + + return true + } catch { + return false + } + } + + + async getAPIClient(tryAuth: boolean = true): Promise { + if (!this.apiClient) { + const url = this.settings.sequenceApiUrl + if (!url) throw Error('No sequence api url') + + const jwtAuth = (await this.getJWT(tryAuth)).token + this.apiClient = new SequenceAPIClient(url, jwtAuth) + } + + return this.apiClient + } + + getMetadataClient(): SequenceMetadataClient { + if (!this.metadataClient) { + this.metadataClient = new SequenceMetadataClient(this.settings.sequenceMetadataUrl) + } + + return this.metadataClient + } + + async getIndexerClient(chainId: ChainIdLike): Promise { + const network = findNetworkConfig(this.account.networks, chainId) + if (!network) { + throw Error(`No network for chain ${chainId}`) + } + + if (!this.indexerClients.has(network.chainId)) { + if (network.indexer) { + this.indexerClients.set(network.chainId, network.indexer) + } else if (network.indexerUrl) { + this.indexerClients.set(network.chainId, new SequenceIndexerClient(network.indexerUrl)) + } else { + throw Error(`No indexer url for chain ${chainId}`) + } + } + + return this.indexerClients.get(network.chainId)! + } + + private getProofString(key: string): ProofStringPromise { + // check if we already have or are waiting for a proof string + if (this.proofStrings.has(key)) { + const proofString = this.proofStrings.get(key)! + + if (this.now() < proofString.expiration) { + return proofString + } + + // proof string expired, delete it and make a new one + this.proofStrings.delete(key) + } + + const proof = new Proof({ + address: this.account.address + }) + + proof.claims.app = this.settings.metadata.name + if (typeof window === 'object') { + proof.claims.ogn = window.location.origin + } + proof.setExpiryIn(this.expiration) + + const ethAuth = new ETHAuth() + const chainId = ethers.BigNumber.from(this.settings.sequenceApiChainId) + const network = findNetworkConfig(this.account.networks, chainId) + if (!network) throw Error('No network found') + ethAuth.chainId = chainId.toNumber() + // TODO: Modify ETHAuth so it can take a provider instead of a url + ethAuth.provider = new ethers.providers.StaticJsonRpcProvider(getDefaultConnectionInfo(network.rpcUrl), { + name: '', + chainId: chainId.toNumber() + }) + + const expiration = this.now() + this.expiration - EXPIRATION_JWT_MARGIN + + const proofString = { + proofString: Promise.resolve( + // NOTICE: TODO: Here we ask the account to sign the message + // using whatever configuration we have ON-CHAIN, this means + // that the account will still use the v1 wallet, even if the migration + // was signed. + // + // This works for Sequence webapp v1 -> v2 because all v1 configurations share the same formula + // (torus + guard), but if we ever decide to allow cross-device login, then it will not work, because + // those other signers may not be part of the configuration. + // + this.account.signDigest( + proof.messageDigest(), + this.settings.sequenceApiChainId, + true, + 'eip6492' + ) + ) + .then(s => { + proof.signature = s + return ethAuth.encodeProof(proof, true) + }) + .catch(reason => { + this.proofStrings.delete(key) + throw reason + }), + expiration + } + + this.proofStrings.set(key, proofString) + return proofString + } +} diff --git a/packages/auth/src/session.ts b/packages/auth/src/session.ts index ab083bb84..8ded20ee0 100644 --- a/packages/auth/src/session.ts +++ b/packages/auth/src/session.ts @@ -1,38 +1,12 @@ -import { NetworkConfig, ChainIdLike, findNetworkConfig } from '@0xsequence/network' -import { getDefaultConnectionInfo, jwtDecodeClaims } from '@0xsequence/utils' +import { NetworkConfig, findNetworkConfig } from '@0xsequence/network' +import { jwtDecodeClaims } from '@0xsequence/utils' import { Account } from '@0xsequence/account' import { ethers } from 'ethers' import { tracker, trackers } from '@0xsequence/sessions' import { Orchestrator } from '@0xsequence/signhub' import { migrator } from '@0xsequence/migration' import { commons, v1 } from '@0xsequence/core' -import { SequenceAPIClient } from '@0xsequence/api' -import { SequenceMetadataClient } from '@0xsequence/metadata' -import { Indexer, SequenceIndexerClient } from '@0xsequence/indexer' -import { ETHAuth, Proof } from '@0xsequence/ethauth' - -export type SessionMeta = { - // name of the app requesting the session, used with ETHAuth - name: string - - // expiration in seconds for a session before it expires, used with ETHAuth - expiration?: number -} - -export type SessionJWT = { - token: string - expiration: number -} - -type SessionJWTPromise = { - token: Promise - expiration: number -} - -type ProofStringPromise = { - proofString: Promise - expiration: number -} +import { Services, ServicesSettings, SessionJWT, SessionMeta } from './services' export interface SessionDumpV1 { config: Omit & { address?: string } @@ -44,7 +18,7 @@ export interface SessionDumpV2 { version: 2 address: string jwt?: SessionJWT - metadata: SessionMeta + metadata?: SessionMeta } export function isSessionDumpV1(obj: any): obj is SessionDumpV1 { @@ -52,314 +26,43 @@ export function isSessionDumpV1(obj: any): obj is SessionDumpV1 { } export function isSessionDumpV2(obj: any): obj is SessionDumpV2 { - return obj.version === 2 && obj.address && obj.metadata + return obj.version === 2 && obj.address } -// Default session expiration of ETHAuth token (1 week) -export const DEFAULT_SESSION_EXPIRATION = 60 * 60 * 24 * 7 - -// Long session expiration of ETHAuth token (~1 year) -export const LONG_SESSION_EXPIRATION = 3e7 - -const EXPIRATION_JWT_MARGIN = 60 // seconds - // These chains are always validated for migrations // if they are not available, the login will fail export const CRITICAL_CHAINS = [1, 137] export type SessionSettings = { + services?: ServicesSettings, contexts: commons.context.VersionedContext - sequenceApiUrl: string - sequenceApiChainId: ethers.BigNumberish - sequenceMetadataUrl: string networks: NetworkConfig[] tracker: tracker.ConfigTracker & migrator.PresignedMigrationTracker orchestrator: Orchestrator } export class Session { - _initialAuthRequest: Promise - _jwt: SessionJWTPromise | undefined - - // proof strings are indexed by account address and app name, see getProofStringKey() - private readonly proofStrings: Map = new Map() - - private onAuthCallbacks: ((result: PromiseSettledResult) => void)[] = [] - - private apiClient: SequenceAPIClient | undefined - private metadataClient: SequenceMetadataClient | undefined - private indexerClients: Map = new Map() - constructor( - public sequenceApiUrl: string, - public sequenceApiChainId: ethers.BigNumberish, - public sequenceMetadataUrl: string, public networks: NetworkConfig[], public contexts: commons.context.VersionedContext, public account: Account, - public metadata: SessionMeta, - jwt?: SessionJWT - ) { - if (jwt) { - this._jwt = { - token: Promise.resolve(jwt.token), - expiration: jwt.expiration ?? getJWTExpiration(jwt.token) - } - } - } - - get name(): string { - return this.metadata.name - } - - get expiration(): number { - return this.metadata.expiration ? Math.max(this.metadata.expiration, 120) : DEFAULT_SESSION_EXPIRATION - } - - onAuth(cb: (result: PromiseSettledResult) => void) { - this.onAuthCallbacks.push(cb) - } - - setAccount(account: Account) { - this.account = account - } - - async auth(maxTries: number = 5): Promise { - const url = this.sequenceApiUrl - if (!url) throw Error('No sequence api url') - - let jwtAuth: string | undefined - for (let i = 0; ; i++) { - try { - jwtAuth = (await this.getJWT(true)).token - break - } catch (error) { - if (i === maxTries - 1) { - console.error(`couldn't authenticate after ${maxTries} attempts`, error) - throw error - } - } - } - - return new SequenceAPIClient(url, jwtAuth) - } - - async getAPIClient(tryAuth: boolean = true): Promise { - if (!this.apiClient) { - const url = this.sequenceApiUrl - if (!url) throw Error('No sequence api url') - - const jwtAuth = (await this.getJWT(tryAuth)).token - this.apiClient = new SequenceAPIClient(url, jwtAuth) - } - - return this.apiClient - } - - getMetadataClient(): SequenceMetadataClient { - if (!this.metadataClient) { - this.metadataClient = new SequenceMetadataClient(this.sequenceMetadataUrl) - } - - return this.metadataClient - } - - async getIndexerClient(chainId: ChainIdLike): Promise { - const network = findNetworkConfig(this.networks, chainId) - if (!network) { - throw Error(`No network for chain ${chainId}`) - } - - if (!this.indexerClients.has(network.chainId)) { - if (network.indexer) { - this.indexerClients.set(network.chainId, network.indexer) - } else if (network.indexerUrl) { - this.indexerClients.set(network.chainId, new SequenceIndexerClient(network.indexerUrl)) - } else { - throw Error(`No indexer url for chain ${chainId}`) - } - } - - return this.indexerClients.get(network.chainId)! - } - - private now(): number { - return Math.floor(Date.now() / 1000) - } - - private async getJWT(tryAuth: boolean): Promise { - const url = this.sequenceApiUrl - if (!url) throw Error('No sequence api url') - - // check if we already have or are waiting for a token - if (this._jwt) { - const jwt = this._jwt - const token = await jwt.token + public services?: Services + ) {} - if (this.now() < jwt.expiration) { - return { token, expiration: jwt.expiration } - } - - // token expired, delete it and get a new one - this._jwt = undefined - } - - if (!tryAuth) { - throw new Error('no auth token in memory') + async dump(): Promise { + const base = { + version: 2 as 2, + address: this.account.address, } - const proofStringKey = this.getProofStringKey() - const { proofString, expiration } = this.getProofString(proofStringKey) - - const jwt = { - token: proofString - .then(async proofString => { - const api = new SequenceAPIClient(url) - - const authResp = await api.getAuthToken({ ewtString: proofString }) - - if (authResp?.status === true && authResp.jwtToken.length !== 0) { - return authResp.jwtToken - } else { - if (!(await this.isProofStringValid(proofString))) { - this.proofStrings.delete(proofStringKey) - } - throw new Error('no auth token from server') - } - }) - .catch(reason => { - this._jwt = undefined - throw reason - }), - expiration - } - this._jwt = jwt - - jwt.token - .then(() => { - this.onAuthCallbacks.forEach(cb => { - try { - cb({ status: 'fulfilled', value: undefined }) - } catch {} - }) - }) - .catch((reason: any) => { - this.onAuthCallbacks.forEach(cb => { - try { - cb({ status: 'rejected', reason }) - } catch {} - }) - }) - - const token = await jwt.token - return { token, expiration } - } - - private getProofString(key: string): ProofStringPromise { - // check if we already have or are waiting for a proof string - if (this.proofStrings.has(key)) { - const proofString = this.proofStrings.get(key)! - - if (this.now() < proofString.expiration) { - return proofString + if (this.services) { + return { + ...base, + ...(await this.services.dump()) } - - // proof string expired, delete it and make a new one - this.proofStrings.delete(key) - } - - const proof = new Proof({ - address: this.account.address - }) - - proof.claims.app = this.name - if (typeof window === 'object') { - proof.claims.ogn = window.location.origin - } - proof.setExpiryIn(this.expiration) - - const ethAuth = new ETHAuth() - const chainId = ethers.BigNumber.from(this.sequenceApiChainId) - const network = this.networks.find(n => chainId.eq(n.chainId)) - if (!network) throw Error('No network found') - ethAuth.chainId = chainId.toNumber() - // TODO: Modify ETHAuth so it can take a provider instead of a url - ethAuth.provider = new ethers.providers.StaticJsonRpcProvider(getDefaultConnectionInfo(network.rpcUrl), { - name: '', - chainId: chainId.toNumber() - }) - - const expiration = this.now() + this.expiration - EXPIRATION_JWT_MARGIN - - const proofString = { - proofString: Promise.resolve( - // NOTICE: TODO: Here we ask the account to sign the message - // using whatever configuration we have ON-CHAIN, this means - // that the account will still use the v1 wallet, even if the migration - // was signed. - // - // This works for Sequence webapp v1 -> v2 because all v1 configurations share the same formula - // (torus + guard), but if we ever decide to allow cross-device login, then it will not work, because - // those other signers may not be part of the configuration. - // - this.account.signDigest(proof.messageDigest(), this.sequenceApiChainId, true, 'eip6492') - ) - .then(s => { - proof.signature = s - return ethAuth.encodeProof(proof, true) - }) - .catch(reason => { - this.proofStrings.delete(key) - throw reason - }), - expiration } - this.proofStrings.set(key, proofString) - return proofString - } - - private getProofStringKey(): string { - return `${this.account.address} - ${this.name}` - } - - private async isProofStringValid(proofString: string): Promise { - try { - const ethAuth = new ETHAuth() - const chainId = ethers.BigNumber.from(this.sequenceApiChainId) - const network = this.networks.find(n => chainId.eq(n.chainId)) - if (!network) throw Error('No network found') - ethAuth.chainId = chainId.toNumber() - - // TODO: Modify ETHAuth so it can take a provider instead of a url - ethAuth.provider = new ethers.providers.StaticJsonRpcProvider(getDefaultConnectionInfo(network.rpcUrl), { - name: '', - chainId: chainId.toNumber() - }) - - await ethAuth.decodeProof(proofString) - - return true - } catch { - return false - } - } - - async dump(): Promise { - let jwt: SessionJWT | undefined - if (this._jwt) { - try { - const expiration = this._jwt.expiration - jwt = { token: await this._jwt.token, expiration } - } catch {} - } - - return { - version: 2, - address: this.account.address, - metadata: this.metadata, - jwt - } + return base } static async open(args: { @@ -367,15 +70,15 @@ export class Session { addSigners: commons.config.SimpleSigner[] referenceSigner: string threshold: ethers.BigNumberish - metadata: SessionMeta selectWallet: (wallets: string[]) => Promise editConfigOnMigration: (config: commons.config.Config) => commons.config.Config onMigration?: (account: Account) => Promise }): Promise { - const { referenceSigner, threshold, metadata, addSigners, selectWallet, settings, editConfigOnMigration, onMigration } = args - const { sequenceApiUrl, sequenceApiChainId, sequenceMetadataUrl, contexts, networks, tracker, orchestrator } = settings + const { referenceSigner, threshold, addSigners, selectWallet, settings, editConfigOnMigration, onMigration } = args + const { contexts, networks, tracker, orchestrator } = settings - const referenceChainId = sequenceApiChainId + // The reference network is mainnet, if mainnet is not available, we use the first network + const referenceChainId = findNetworkConfig(networks, 1)?.chainId ?? networks[0]?.chainId if (!referenceChainId) throw Error('No reference chain found') const foundWallets = await tracker.walletsOfSigner({ signer: referenceSigner }) @@ -484,16 +187,19 @@ export class Session { } } - const session = new Session(sequenceApiUrl, sequenceApiChainId, sequenceMetadataUrl, networks, contexts, account, metadata) + let services: Services | undefined - if (sequenceApiUrl) { - // Fire JWT requests after updating config - session._initialAuthRequest = session.auth() - } else { - session._initialAuthRequest = Promise.reject('no sequence api url') + if (settings.services) { + services = new Services(account, settings.services) + services.auth() // fire and forget } - return session + return new Session( + networks, + contexts, + account, + services + ) } static async load(args: { @@ -503,7 +209,7 @@ export class Session { onMigration?: (account: Account) => Promise }): Promise { const { dump, settings, editConfigOnMigration, onMigration } = args - const { sequenceApiUrl, sequenceApiChainId, sequenceMetadataUrl, contexts, networks, tracker, orchestrator } = settings + const { contexts, networks, tracker, orchestrator } = settings let account: Account @@ -550,19 +256,28 @@ export class Session { throw Error('Invalid dump format') } + let services: Services | undefined + + if (settings.services) { + services = new Services( + account, + settings.services, + dump.jwt && { + jwt: { + token: Promise.resolve(dump.jwt.token), + expiration: dump.jwt.expiration ?? jwtDecodeClaims(dump.jwt.token).exp + }, + metadata: dump.metadata + } + ) + } + return new Session( - sequenceApiUrl, - sequenceApiChainId, - sequenceMetadataUrl, networks, contexts, account, - dump.metadata, - dump.jwt + services ) } } -function getJWTExpiration(jwt: string): number { - return jwtDecodeClaims<{ exp: number }>(jwt).exp -} diff --git a/packages/auth/tests/session.spec.ts b/packages/auth/tests/session.spec.ts index 77e5f6a49..98ec12eec 100644 --- a/packages/auth/tests/session.spec.ts +++ b/packages/auth/tests/session.spec.ts @@ -91,7 +91,8 @@ describe('Wallet integration', function () { chainId, provider: ethnode.provider, isDefaultChain: true, - relayer + relayer, + rpcUrl: '' } ] as NetworkConfig[] @@ -115,13 +116,18 @@ describe('Wallet integration', function () { orchestrator = new Orchestrator([]) simpleSettings = { - sequenceApiUrl: '', - sequenceApiChainId: chainId, - sequenceMetadataUrl: '', contexts, networks, orchestrator, - tracker + tracker, + services: { + metadata: { + name: 'test' + }, + sequenceApiUrl: '', + sequenceApiChainId: chainId, + sequenceMetadataUrl: '', + } } }) @@ -134,9 +140,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async ws => { expect(ws.length).to.equal(0) return undefined @@ -170,9 +173,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async ws => { expect(ws.length).to.equal(0) return undefined @@ -202,9 +202,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async ws => ws[0] ?? undefined, editConfigOnMigration: config => config }) @@ -215,9 +212,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async ws => { expect(ws.length).to.equal(1) return ws[0] @@ -247,9 +241,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -263,9 +254,6 @@ describe('Wallet integration', function () { { address: newSigner.address, weight: 1 } ], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async wallets => { expect(wallets.length).to.equal(1) return undefined @@ -285,9 +273,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -297,9 +282,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 2 }], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -310,9 +292,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async wallets => { expect(wallets.length).to.equal(2) expect(wallets).to.include(oldSession1.account.address) @@ -329,9 +308,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async wallets => { expect(wallets.length).to.equal(2) expect(wallets).to.include(oldSession1.account.address) @@ -366,9 +342,6 @@ describe('Wallet integration', function () { } ], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -382,9 +355,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: signer2.address, weight: 1 }], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async wallets => { expect(wallets.length).to.equal(1) return wallets[0] @@ -445,9 +415,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async wallets => { expect(wallets.length).to.equal(1) return wallets[0] @@ -517,9 +484,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner2.address, weight: 1 }], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async wallets => { expect(wallets.length).to.equal(1) return wallets[0] @@ -572,8 +536,10 @@ describe('Wallet integration', function () { beforeEach(() => { settings = { ...simpleSettings, - sequenceApiUrl, - sequenceMetadataUrl: '' + services: { + ...simpleSettings.services!, + sequenceApiUrl + } } fakeJwt = ethers.utils.hexlify(randomBytes(64, `JWT Auth ${fakeJwtIndex++}`)) @@ -646,16 +612,13 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - await session.auth() + await session.services?.auth() expect(totalCount).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) expect(proofAddress).to.equal(session.account.address) }) @@ -668,9 +631,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -681,18 +641,14 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async ws => ws[0], editConfigOnMigration: config => config }) - await session.auth() - await session._initialAuthRequest + await session.services?.auth() expect(totalCount).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) expect(proofAddress).to.equal(session.account.address) }) @@ -705,19 +661,16 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - await session._initialAuthRequest + await session.services?._initialAuthRequest expect(totalCount).to.equal(1) expect(recoverCount[session.account.address]).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) }) it('Should get JWT during session opening', async () => { @@ -731,14 +684,11 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - await expect(session._initialAuthRequest).to.be.rejected + await expect(session.services?._initialAuthRequest).to.be.rejected const newSigner = randomWallet('Should get JWT during session opening 2') orchestrator.setSigners([referenceSigner, newSigner]) @@ -748,9 +698,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async ws => { expect(ws.length).to.equal(1) return ws[0] @@ -758,12 +705,12 @@ describe('Wallet integration', function () { editConfigOnMigration: config => config }) - await session._initialAuthRequest + await session.services?._initialAuthRequest expect(totalCount).to.equal(1) expect(recoverCount[session.account.address]).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) }) it('Should get API with lazy JWT during first session creation', async () => { @@ -775,26 +722,23 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - const api = await session.getAPIClient() + const api = await session.services?.getAPIClient() expect(totalCount).to.equal(1) expect(recoverCount[session.account.address]).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) server.forPost('/rpc/API/FriendList').thenCallback(async request => { const hasToken = request.headers['authorization']!.includes(fakeJwt) return { statusCode: hasToken ? 200 : 401, body: JSON.stringify({}) } }) - await api.friendList({ page: {} }) + await api!.friendList({ page: {} }) }) it('Should get API with lazy JWT during session opening', async () => { @@ -807,9 +751,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -822,26 +763,23 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async ws => ws[0], editConfigOnMigration: config => config }) - const api = await session.getAPIClient() + const api = await session.services?.getAPIClient() expect(totalCount).to.equal(1) expect(recoverCount[session.account.address]).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) server.forPost('/rpc/API/FriendList').thenCallback(async request => { const hasToken = request.headers['authorization']!.includes(fakeJwt) return { statusCode: hasToken ? 200 : 401, body: JSON.stringify({}) } }) - await api.friendList({ page: {} }) + await api!.friendList({ page: {} }) }) it('Should call callbacks on JWT token', async () => { @@ -853,17 +791,14 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) let calledCallback = 0 - session.onAuth(() => calledCallback++) + session.services?.onAuth(() => calledCallback++) - await session._initialAuthRequest + await session.services?._initialAuthRequest expect(calledCallback).to.equal(1) }) @@ -879,9 +814,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -897,17 +829,14 @@ describe('Wallet integration', function () { { address: newSigner.address, weight: 1 } ], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async ws => ws[0], editConfigOnMigration: config => config }) let calledCallback = 0 - session.onAuth(() => calledCallback++) + session.services?.onAuth(() => calledCallback++) - await session._initialAuthRequest + await session.services?._initialAuthRequest expect(calledCallback).to.equal(1) }) @@ -922,17 +851,14 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) alwaysFail = true - await expect(session.auth()).to.be.rejected + await expect(session.services?.auth()).to.be.rejected expect(totalCount).to.equal(5) - expect(session._jwt).to.be.undefined + expect(session.services?.status.jwt).to.be.undefined }) it('Should get API with JWT already present', async () => { @@ -946,9 +872,6 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -961,29 +884,26 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 2, - metadata: { - name: 'Test' - }, selectWallet: async ws => ws[0], editConfigOnMigration: config => config }) - await session._initialAuthRequest + await session.services?._initialAuthRequest const totalCountBefore = totalCount // This should use the already existing JWT - const api = await session.getAPIClient() + const api = await session.services?.getAPIClient() expect(totalCount).to.equal(totalCountBefore) expect(recoverCount[session.account.address]).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) server.forPost('/rpc/API/FriendList').thenCallback(async request => { const hasToken = request.headers['authorization']!.includes(fakeJwt) return { statusCode: hasToken ? 200 : 401, body: JSON.stringify({}) } }) - await api.friendList({ page: {} }) + await api!.friendList({ page: {} }) }) it('Should fail to get API with false tryAuth and no JWT', async () => { @@ -997,23 +917,20 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - await expect(session._initialAuthRequest).to.be.rejected + await expect(session.services?._initialAuthRequest).to.be.rejected alwaysFail = false - const apiPromise = session.getAPIClient(false) + const apiPromise = session.services?.getAPIClient(false) await expect(apiPromise).to.be.rejected expect(totalCount).to.equal(0) - expect(session._jwt).to.be.undefined + expect(session.services?.status.jwt).to.be.undefined }) it('Should fail to get API without api url', async () => { @@ -1025,19 +942,16 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - const apiPromise = session.getAPIClient() + const apiPromise = session.services?.getAPIClient() await expect(apiPromise).to.be.rejected expect(totalCount).to.equal(0) - expect(session._jwt).to.be.undefined + expect(session.services?.status.jwt?.token).to.be.undefined }) it('Should fail to get JWT with no api configured', async () => { @@ -1049,17 +963,14 @@ describe('Wallet integration', function () { referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - await expect(session.auth()).to.be.rejected + await expect(session.services?.auth()).to.be.rejected expect(totalCount).to.equal(0) - expect(session._jwt).to.be.undefined + expect(session.services?.status.jwt?.token).to.be.undefined }) it('Should reuse outstanding JWT requests', async () => { @@ -1073,9 +984,6 @@ describe('Wallet integration', function () { referenceSigner: await referenceSigner.getAddress(), addSigners: [{ address: await referenceSigner.getAddress(), weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -1085,7 +993,7 @@ describe('Wallet integration', function () { const signingRequestsBefore = referenceSigner.signingRequests - await expect(session._initialAuthRequest).to.be.rejected + await expect(session.services?._initialAuthRequest).to.be.rejected alwaysFail = false totalCount = 0 @@ -1093,7 +1001,7 @@ describe('Wallet integration', function () { // Create a bunch of API clients concurrently const requests: any[] = [] while (requests.length < 10) { - requests.push(session.getAPIClient()) + requests.push(session.services?.getAPIClient()) } await expect(Promise.all(requests)).to.be.fulfilled @@ -1112,9 +1020,6 @@ describe('Wallet integration', function () { referenceSigner: await referenceSigner.getAddress(), addSigners: [{ address: await referenceSigner.getAddress(), weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) @@ -1124,13 +1029,13 @@ describe('Wallet integration', function () { const signingRequestsBefore = referenceSigner.signingRequests - await expect(session._initialAuthRequest).to.be.rejected + await expect(session.services?._initialAuthRequest).to.be.rejected totalCount = 0 // Create a bunch of API clients sequentially for (let i = 0; i < 10; i++) { - await expect(session.getAPIClient()).to.be.rejected + await expect(session.services?.getAPIClient()).to.be.rejected } expect(totalCount).to.equal(10) @@ -1146,16 +1051,13 @@ describe('Wallet integration', function () { referenceSigner: await referenceSigner.getAddress(), addSigners: [{ address: await referenceSigner.getAddress(), weight: 1 }], threshold: 1, - metadata: { - name: 'Test' - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - await session._initialAuthRequest + await session.services?._initialAuthRequest - const api = await session.getAPIClient() + const api = await session.services?.getAPIClient() const okResponses = [true] server.forPost('/rpc/API/FriendList').thenCallback(async () => { @@ -1164,7 +1066,7 @@ describe('Wallet integration', function () { totalCount = 0 - await expect(api.friendList({ page: {} })).to.be.fulfilled + await expect(api!.friendList({ page: {} })).to.be.fulfilled // no re-authentication since it succeeded expect(totalCount).to.equal(0) @@ -1192,23 +1094,28 @@ describe('Wallet integration', function () { orchestrator.setSigners([referenceSigner]) const session = await Session.open({ - settings, + settings: { + ...settings, + services: { + ...settings.services!, + metadata: { + name: 'Test', + expiration: 240 + } + } + }, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test', - expiration: 240 - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - await session._initialAuthRequest + await session.services?._initialAuthRequest expect(totalCount).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) - expect(session._jwt?.expiration).to.equal(baseTime + 240 - 60) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) + expect(session.services?.status.jwt?.expiration).to.equal(baseTime + 240 - 60) // Force expire (1 hour) const newBaseTime = baseTime + 60 * 60 @@ -1216,11 +1123,11 @@ describe('Wallet integration', function () { fakeJwt = ethers.utils.hexlify(randomBytes(96, 'Should request a new JWT after expiration 2')) - await session.getAPIClient() + await session.services?.getAPIClient() expect(totalCount).to.equal(2) - expect(await session._jwt?.token).to.equal(fakeJwt) - expect(session._jwt?.expiration).to.equal(newBaseTime + 240 - 60) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) + expect(session.services?.status.jwt?.expiration).to.equal(newBaseTime + 240 - 60) }) it('Should force min expiration time', async () => { @@ -1231,23 +1138,28 @@ describe('Wallet integration', function () { orchestrator.setSigners([referenceSigner]) const session = await Session.open({ - settings, + settings: { + ...settings, + services: { + ...settings.services!, + metadata: { + name: 'Test', + expiration: 1, + } + } + }, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, - metadata: { - name: 'Test', - expiration: 1 - }, selectWallet: async () => undefined, editConfigOnMigration: config => config }) - await session._initialAuthRequest + await session.services?._initialAuthRequest expect(totalCount).to.equal(1) - expect(await session._jwt?.token).to.equal(fakeJwt) - expect(session._jwt?.expiration).to.equal(baseTime + 120 - 60) + expect(await session.services?.status.jwt?.token).to.equal(fakeJwt) + expect(session.services?.status.jwt?.expiration).to.equal(baseTime + 120 - 60) }) }) }) @@ -1296,6 +1208,80 @@ describe('Wallet integration', function () { expect(ethauth.validateProof(decodedProof)).to.eventually.be.true }) }) + describe('session without services', () => { + let noServiceSettings: SessionSettings + + before(() => { + noServiceSettings = { + ...simpleSettings, + services: undefined + } + }) + + it('should open a session without services', async () => { + const referenceSigner = randomWallet('should open a session without services') + orchestrator.setSigners([referenceSigner]) + + const session = await Session.open({ + settings: noServiceSettings, + referenceSigner: referenceSigner.address, + addSigners: [{ address: referenceSigner.address, weight: 1 }], + threshold: 1, + selectWallet: async () => { + return undefined + }, + editConfigOnMigration: config => config + }) + + expect(session.services).to.be.undefined + }) + + it('should dump a session without services', async () => { + const referenceSigner = randomWallet('should dump a session without services') + orchestrator.setSigners([referenceSigner]) + + const session = await Session.open({ + settings: noServiceSettings, + referenceSigner: referenceSigner.address, + addSigners: [{ address: referenceSigner.address, weight: 1 }], + threshold: 1, + selectWallet: async () => { + return undefined + }, + editConfigOnMigration: config => config + }) + + const dump = await session.dump() + expect(dump).to.not.be.undefined + expect(dump.jwt).to.be.undefined + expect(dump.metadata).to.be.undefined + }) + + it('should load dump without services', async () => { + const referenceSigner = randomWallet('should load dump without services') + orchestrator.setSigners([referenceSigner]) + + const session = await Session.open({ + settings: noServiceSettings, + referenceSigner: referenceSigner.address, + addSigners: [{ address: referenceSigner.address, weight: 1 }], + threshold: 1, + selectWallet: async () => { + return undefined + }, + editConfigOnMigration: config => config + }) + + const dump = await session.dump() + const newSession = await Session.load({ + settings: noServiceSettings, + dump: dump, + editConfigOnMigration: config => config + }) + + expect(newSession.services).to.be.undefined + }) + }) }) let nowCalls = 0 From bfe6416cbc2e07b52f53e050b1789b1a67055d84 Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Thu, 24 Aug 2023 17:46:49 +0000 Subject: [PATCH 04/13] Add defaults to sessions --- packages/auth/src/session.ts | 80 ++++++++++++++++++---------- packages/auth/tests/session.spec.ts | 45 +++++++++++++++- packages/core/src/commons/context.ts | 8 +++ 3 files changed, 104 insertions(+), 29 deletions(-) diff --git a/packages/auth/src/session.ts b/packages/auth/src/session.ts index 8ded20ee0..053236d99 100644 --- a/packages/auth/src/session.ts +++ b/packages/auth/src/session.ts @@ -1,4 +1,4 @@ -import { NetworkConfig, findNetworkConfig } from '@0xsequence/network' +import { NetworkConfig, allNetworks, findNetworkConfig } from '@0xsequence/network' import { jwtDecodeClaims } from '@0xsequence/utils' import { Account } from '@0xsequence/account' import { ethers } from 'ethers' @@ -38,7 +38,12 @@ export type SessionSettings = { contexts: commons.context.VersionedContext networks: NetworkConfig[] tracker: tracker.ConfigTracker & migrator.PresignedMigrationTracker - orchestrator: Orchestrator +} + +export const SessionSettingsDefault: SessionSettings = { + contexts: commons.context.defaultContexts, + networks: allNetworks, + tracker: new trackers.remote.RemoteConfigTracker('https://sessions.sequence.app'), } export class Session { @@ -66,23 +71,24 @@ export class Session { } static async open(args: { - settings: SessionSettings - addSigners: commons.config.SimpleSigner[] + settings?: Partial + orchestrator: Orchestrator + addSigners?: commons.config.SimpleSigner[] referenceSigner: string - threshold: ethers.BigNumberish - selectWallet: (wallets: string[]) => Promise - editConfigOnMigration: (config: commons.config.Config) => commons.config.Config + threshold?: ethers.BigNumberish + selectWallet?: (wallets: string[]) => Promise + editConfigOnMigration?: (config: commons.config.Config) => commons.config.Config onMigration?: (account: Account) => Promise }): Promise { - const { referenceSigner, threshold, addSigners, selectWallet, settings, editConfigOnMigration, onMigration } = args - const { contexts, networks, tracker, orchestrator } = settings + const { referenceSigner, threshold, addSigners, selectWallet, settings, editConfigOnMigration, onMigration, orchestrator } = args + const { contexts, networks, tracker, services } = { ...SessionSettingsDefault, ...settings } // The reference network is mainnet, if mainnet is not available, we use the first network const referenceChainId = findNetworkConfig(networks, 1)?.chainId ?? networks[0]?.chainId if (!referenceChainId) throw Error('No reference chain found') const foundWallets = await tracker.walletsOfSigner({ signer: referenceSigner }) - const selectedWallet = await selectWallet(foundWallets.map(w => w.wallet)) + const selectedWallet = selectWallet ? await selectWallet(foundWallets.map(w => w.wallet)) : foundWallets[0]?.wallet let account: Account @@ -102,7 +108,7 @@ export class Session { // NOTICE: We are performing the wallet update on a single chain, assuming that // all other networks have the same configuration. This is not always true. - if (addSigners.length > 0) { + if (addSigners && addSigners.length > 0) { // New wallets never need migrations // (because we create them on the latest version) let status = await account.status(referenceChainId) @@ -127,7 +133,7 @@ export class Session { throw Error('Migration cancelled, cannot open session') } - const { failedChains } = await account.signAllMigrations(editConfigOnMigration) + const { failedChains } = await account.signAllMigrations(editConfigOnMigration || ((c) => c)) if (failedChains.some(c => CRITICAL_CHAINS.includes(c))) { throw Error(`Failed to sign migrations on ${failedChains.join(', ')}`) } @@ -157,15 +163,32 @@ export class Session { } const prevConfig = status.config - const newConfig = account.coders.config.editConfig(prevConfig, { + const nextConfig = account.coders.config.editConfig(prevConfig, { add: addSigners, - checkpoint: account.coders.config.checkpointOf(prevConfig).add(1), threshold }) - await account.updateConfig(newConfig) + // Only update the onchain config if the imageHash has changed + if ( + account.coders.config.imageHashOf(prevConfig) !== + account.coders.config.imageHashOf(nextConfig) + ) { + const newConfig = account.coders.config.editConfig(nextConfig, { + checkpoint: account.coders.config.checkpointOf(prevConfig).add(1), + }) + + await account.updateConfig(newConfig) + } } } else { + if (!addSigners || addSigners.length === 0) { + throw Error('Cannot create new account without signers') + } + + if (!threshold) { + throw Error('Cannot create new account without threshold') + } + // fresh account account = await Account.new({ config: { threshold, checkpoint: 0, signers: addSigners }, @@ -187,29 +210,30 @@ export class Session { } } - let services: Services | undefined + let servicesObj: Services | undefined - if (settings.services) { - services = new Services(account, settings.services) - services.auth() // fire and forget + if (services) { + servicesObj = new Services(account, services) + servicesObj.auth() // fire and forget } return new Session( networks, contexts, account, - services + servicesObj ) } static async load(args: { - settings: SessionSettings + settings?: Partial + orchestrator: Orchestrator dump: SessionDumpV1 | SessionDumpV2 editConfigOnMigration: (config: commons.config.Config) => commons.config.Config onMigration?: (account: Account) => Promise }): Promise { - const { dump, settings, editConfigOnMigration, onMigration } = args - const { contexts, networks, tracker, orchestrator } = settings + const { dump, settings, editConfigOnMigration, onMigration, orchestrator } = args + const { contexts, networks, tracker, services } = { ...SessionSettingsDefault, ...settings } let account: Account @@ -256,12 +280,12 @@ export class Session { throw Error('Invalid dump format') } - let services: Services | undefined + let servicesObj: Services | undefined - if (settings.services) { - services = new Services( + if (services) { + servicesObj = new Services( account, - settings.services, + services, dump.jwt && { jwt: { token: Promise.resolve(dump.jwt.token), @@ -276,7 +300,7 @@ export class Session { networks, contexts, account, - services + servicesObj ) } } diff --git a/packages/auth/tests/session.spec.ts b/packages/auth/tests/session.spec.ts index 98ec12eec..48e83afa0 100644 --- a/packages/auth/tests/session.spec.ts +++ b/packages/auth/tests/session.spec.ts @@ -118,7 +118,6 @@ describe('Wallet integration', function () { simpleSettings = { contexts, networks, - orchestrator, tracker, services: { metadata: { @@ -136,6 +135,7 @@ describe('Wallet integration', function () { orchestrator.setSigners([referenceSigner]) const session = await Session.open({ + orchestrator, settings: simpleSettings, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], @@ -170,6 +170,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -184,6 +185,7 @@ describe('Wallet integration', function () { const session2 = await Session.load({ settings: simpleSettings, + orchestrator, dump, editConfigOnMigration: config => config }) @@ -199,6 +201,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -209,6 +212,7 @@ describe('Wallet integration', function () { const newSigner = randomWallet('Should open an existing session 2') const session2 = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 2, @@ -238,6 +242,7 @@ describe('Wallet integration', function () { const oldSession = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -248,6 +253,7 @@ describe('Wallet integration', function () { const newSigner = randomWallet('Should create a new account if selectWallet returns undefined 2') const newSession = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [ { address: referenceSigner.address, weight: 1 }, @@ -270,6 +276,7 @@ describe('Wallet integration', function () { const oldSession1 = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -279,6 +286,7 @@ describe('Wallet integration', function () { const oldSession2 = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 2 }], threshold: 2, @@ -289,6 +297,7 @@ describe('Wallet integration', function () { const newSigner = randomWallet('Should select between two wallets using selectWallet 2') const newSession1 = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 1, @@ -305,6 +314,7 @@ describe('Wallet integration', function () { const newSession2 = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 1, @@ -330,6 +340,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [ { @@ -352,6 +363,7 @@ describe('Wallet integration', function () { const newSession = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: signer2.address, weight: 1 }], threshold: 2, @@ -412,6 +424,7 @@ describe('Wallet integration', function () { const newSession = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 1, @@ -433,6 +446,7 @@ describe('Wallet integration', function () { it('Should open and migrate dump', async () => { const newSession = await Session.load({ settings: simpleSettings, + orchestrator, dump: v1SessionDump, editConfigOnMigration: config => config }) @@ -481,6 +495,7 @@ describe('Wallet integration', function () { const newSession = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner2.address, weight: 1 }], threshold: 2, @@ -503,6 +518,7 @@ describe('Wallet integration', function () { it('Should open and migrate dump', async () => { const newSession = await Session.load({ settings: simpleSettings, + orchestrator, dump: v1SessionDump, editConfigOnMigration: config => config }) @@ -609,6 +625,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -628,6 +645,7 @@ describe('Wallet integration', function () { await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -638,6 +656,7 @@ describe('Wallet integration', function () { const newSigner = randomWallet('Should get JWT after updating session 2') const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 1, @@ -658,6 +677,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -681,6 +701,7 @@ describe('Wallet integration', function () { let session = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -695,6 +716,7 @@ describe('Wallet integration', function () { session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 2, @@ -719,6 +741,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -748,6 +771,7 @@ describe('Wallet integration', function () { await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -760,6 +784,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 2, @@ -788,6 +813,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -811,6 +837,7 @@ describe('Wallet integration', function () { await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -823,6 +850,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [ { address: referenceSigner.address, weight: 1 }, @@ -848,6 +876,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -869,6 +898,7 @@ describe('Wallet integration', function () { await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -881,6 +911,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: newSigner.address, weight: 1 }], threshold: 2, @@ -914,6 +945,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -939,6 +971,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -960,6 +993,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: simpleSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -981,6 +1015,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: await referenceSigner.getAddress(), addSigners: [{ address: await referenceSigner.getAddress(), weight: 1 }], threshold: 1, @@ -1017,6 +1052,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: await referenceSigner.getAddress(), addSigners: [{ address: await referenceSigner.getAddress(), weight: 1 }], threshold: 1, @@ -1048,6 +1084,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings, + orchestrator, referenceSigner: await referenceSigner.getAddress(), addSigners: [{ address: await referenceSigner.getAddress(), weight: 1 }], threshold: 1, @@ -1104,6 +1141,7 @@ describe('Wallet integration', function () { } } }, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -1148,6 +1186,7 @@ describe('Wallet integration', function () { } } }, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -1224,6 +1263,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: noServiceSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -1242,6 +1282,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: noServiceSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -1263,6 +1304,7 @@ describe('Wallet integration', function () { const session = await Session.open({ settings: noServiceSettings, + orchestrator, referenceSigner: referenceSigner.address, addSigners: [{ address: referenceSigner.address, weight: 1 }], threshold: 1, @@ -1274,6 +1316,7 @@ describe('Wallet integration', function () { const dump = await session.dump() const newSession = await Session.load({ + orchestrator, settings: noServiceSettings, dump: dump, editConfigOnMigration: config => config diff --git a/packages/core/src/commons/context.ts b/packages/core/src/commons/context.ts index 67e8067ef..9868e42a3 100644 --- a/packages/core/src/commons/context.ts +++ b/packages/core/src/commons/context.ts @@ -1,6 +1,9 @@ import { ethers } from 'ethers' import { allVersions } from '..' +import { DeployedWalletContext as context1 } from '../v1' +import { DeployedWalletContext as context2 } from '../v2' + export type WalletContext = { version: number factory: string @@ -102,3 +105,8 @@ export function latestContext(contexts: VersionedContext): WalletContext { const versions = Object.keys(contexts).length return contexts[versions] } + +export const defaultContexts: VersionedContext = { + 1: context1, + 2: context2 +} From 2d8fd2d25c3816eb4bd3e7918d698e4c8ec30448 Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Thu, 24 Aug 2023 18:04:16 +0000 Subject: [PATCH 05/13] Add single signer helper --- packages/auth/src/session.ts | 26 ++++++++++++ packages/auth/tests/session.spec.ts | 63 +++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/packages/auth/src/session.ts b/packages/auth/src/session.ts index 053236d99..ab2dc81e6 100644 --- a/packages/auth/src/session.ts +++ b/packages/auth/src/session.ts @@ -70,6 +70,32 @@ export class Session { return base } + static async singleSigner(args: { + settings?: Partial, + signer: ethers.Signer, + selectWallet?: (wallets: string[]) => Promise, + onMigration?: (account: Account) => Promise, + editConfigOnMigration?: (config: commons.config.Config) => commons.config.Config, + }): Promise { + const { signer } = args + + const orchestrator = new Orchestrator([signer]) + const referenceSigner = await signer.getAddress() + const threshold = 1 + const addSigners = [{ + weight: 1, + address: referenceSigner + }] + + return Session.open({ + ...args, + orchestrator, + referenceSigner, + threshold, + addSigners + }) + } + static async open(args: { settings?: Partial orchestrator: Orchestrator diff --git a/packages/auth/tests/session.spec.ts b/packages/auth/tests/session.spec.ts index 48e83afa0..5ebdb49e9 100644 --- a/packages/auth/tests/session.spec.ts +++ b/packages/auth/tests/session.spec.ts @@ -1325,6 +1325,69 @@ describe('Wallet integration', function () { expect(newSession.services).to.be.undefined }) }) + + describe('single signer session', () => { + it('should create a new single signer session', async () => { + const signer = randomWallet('should create a new single signer session') + + const session = await Session.singleSigner({ + settings: simpleSettings, + signer: signer + }) + + expect(session.account.address).to.not.be.undefined + + const status = await session.account.status(networks[0].chainId) + const config = status.config as v2.config.WalletConfig + + expect(config.threshold).to.equal(1) + expect(v2.config.isSignerLeaf(config.tree)).to.be.true + expect(config.tree as v2.config.SignerLeaf).to.deep.equal({ + weight: 1, + address: signer.address + }) + }) + + it('should open same single signer session twice', async () => { + const signer = randomWallet('should open same single signer session twice') + + const session1 = await Session.singleSigner({ + settings: simpleSettings, + signer: signer + }) + + const address1 = session1.account.address + const status1 = await session1.account.status(networks[0].chainId) + + const session2 = await Session.singleSigner({ + settings: simpleSettings, + signer: signer + }) + + const address2 = session2.account.address + const status2 = await session2.account.status(networks[0].chainId) + + expect(address1).to.equal(address2) + + // should not change the config! + expect(status1.config).to.deep.equal(status2.config) + }) + + it('should send a transaction from a single signer session', async () => { + const signer = randomWallet('should send a transaction from a single signer session') + + const session = await Session.singleSigner({ + settings: simpleSettings, + signer: signer + }) + + const receipt = await session.account.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }, networks[0].chainId) + + expect(receipt.hash).to.not.be.undefined + }) + }) }) let nowCalls = 0 From 7ff56ed03caea5a3ae8d25c2e829ffa0e406a511 Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Thu, 24 Aug 2023 18:13:58 +0000 Subject: [PATCH 06/13] Fix build --- packages/account/src/utils.ts | 5 ++++- packages/auth/src/authorization.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/account/src/utils.ts b/packages/account/src/utils.ts index 3b769906a..48174b7c9 100644 --- a/packages/account/src/utils.ts +++ b/packages/account/src/utils.ts @@ -1,5 +1,8 @@ import { ethers } from "ethers" -import { isPromise } from "util/types" + +function isPromise(value: any): value is Promise { + return !!value && typeof value.then === 'function' +} export function isDeferrable(value: any): value is ethers.utils.Deferrable { // The value is deferrable if any of the properties is a Promises diff --git a/packages/auth/src/authorization.ts b/packages/auth/src/authorization.ts index e31023979..8bd2c0741 100644 --- a/packages/auth/src/authorization.ts +++ b/packages/auth/src/authorization.ts @@ -3,8 +3,8 @@ import { ETHAuth, Proof } from '@0xsequence/ethauth' import { ChainIdLike, toChainIdNumber } from '@0xsequence/network' import { TypedData } from '@0xsequence/utils' import { Signer } from '@0xsequence/wallet' -import { DEFAULT_SESSION_EXPIRATION } from './session' import { Account } from '@0xsequence/account' +import { DEFAULT_SESSION_EXPIRATION } from './services' export interface AuthorizationOptions { // app name string, ie 'Skyweaver' From 578209996dbdb9d66c6ab855a5aeff72c04843ab Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Thu, 24 Aug 2023 18:19:33 +0000 Subject: [PATCH 07/13] Fix lint --- packages/auth/src/session.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/src/session.ts b/packages/auth/src/session.ts index ab2dc81e6..44d2f18da 100644 --- a/packages/auth/src/session.ts +++ b/packages/auth/src/session.ts @@ -56,7 +56,7 @@ export class Session { async dump(): Promise { const base = { - version: 2 as 2, + version: 2 as const, address: this.account.address, } From 6d2be81401ee4e268b062358cdd625e536b47ad5 Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Thu, 24 Aug 2023 18:44:27 +0000 Subject: [PATCH 08/13] Remove ethers.Signer methods from account --- packages/account/src/account.ts | 96 +-------------------------------- 1 file changed, 2 insertions(+), 94 deletions(-) diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index 937dcd8a8..34354467f 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -107,94 +107,10 @@ export class Account { this.migrator = new migrator.Migrator(options.tracker, this.migrations, this.contexts) } - // - // start ethers.Signer required methods - // - - _isSigner: boolean = true - - signTransaction(_transaction: ethers.utils.Deferrable): Promise { - throw new Error('Method not implemented.') - } - - connect(_provider: ethers.providers.Provider): ethers.Signer { - throw new Error('Method not implemented.') - } - - getBalance(_blockTag?: ethers.providers.BlockTag | undefined): Promise { - throw new Error('Method not implemented.') - } - - getTransactionCount(_blockTag?: ethers.providers.BlockTag | undefined): Promise { - throw new Error('Method not implemented.') - } - - estimateGas(_transaction: ethers.utils.Deferrable): Promise { - throw new Error('Method not implemented.') - } - getSigner(chainId: ChainId, options?: AccountSignerOptions): AccountSigner { return new AccountSigner(this, chainId, options) } - call( - _transaction: ethers.utils.Deferrable, - _blockTag?: ethers.providers.BlockTag | undefined - ): Promise { - throw new Error('Method not implemented.') - } - - getChainId(): Promise { - throw new Error('Method not implemented.') - } - - getGasPrice(): Promise { - throw new Error('Method not implemented.') - } - - getFeeData(): Promise { - throw new Error('Method not implemented.') - } - - private ensProvider() { - return this.networks.find((n) => n.chainId === 1)?.provider - } - - async resolveName(name: string): Promise { - const provider = this.ensProvider() - - if (!provider) { - throw new Error('ENS network not found.') - } - - const result = await provider.resolveName(name) - if (!result) { - throw new Error('Name not resolved.') - } - - return result - } - - checkTransaction( - _transaction: ethers.utils.Deferrable - ): ethers.utils.Deferrable { - throw new Error('Method not implemented.') - } - - populateTransaction( - _transaction: ethers.utils.Deferrable - ): Promise { - throw new Error('Method not implemented.') - } - - _checkProvider(_operation?: string | undefined): void { - throw new Error('Method not implemented.') - } - - // - // start ethers.Signer required methods - // - static async new(options: { config: commons.config.SimpleConfig tracker: tracker.ConfigTracker & migrator.PresignedMigrationTracker @@ -245,10 +161,6 @@ export class Account { } } - get provider() { - return this.providerFor(this.defaultNetwork()) - } - network(chainId: ethers.BigNumberish): NetworkConfig { const tcid = ethers.BigNumber.from(chainId) const found = this.networks.find(n => tcid.eq(n.chainId)) @@ -256,10 +168,6 @@ export class Account { return found } - defaultNetwork(): ChainId { - return this.networks[0].chainId - } - providerFor(chainId: ethers.BigNumberish): ethers.providers.Provider { const found = this.network(chainId) if (!found.provider && !found.rpcUrl) throw new Error(`Provider not found for chainId ${chainId}`) @@ -696,7 +604,7 @@ export class Account { signMessage( message: ethers.BytesLike, - chainId: ethers.BigNumberish = this.defaultNetwork(), + chainId: ethers.BigNumberish, cantValidateBehavior: 'ignore' | 'eip6492' | 'throw' = 'ignore' ): Promise { return this.signDigest(ethers.utils.keccak256(message), chainId, true, cantValidateBehavior) @@ -882,7 +790,7 @@ export class Account { async sendTransaction( txs: commons.transaction.Transactionish, - chainId: ethers.BigNumberish = this.defaultNetwork(), + chainId: ethers.BigNumberish, quote?: FeeQuote, skipPreDecorate: boolean = false, callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void From 832703dfea1cdbd1ab14406a8891537af06eae62 Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Fri, 25 Aug 2023 12:32:33 +0000 Subject: [PATCH 09/13] Safer select wallet --- packages/auth/src/session.ts | 37 ++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/packages/auth/src/session.ts b/packages/auth/src/session.ts index 44d2f18da..0492447fd 100644 --- a/packages/auth/src/session.ts +++ b/packages/auth/src/session.ts @@ -5,7 +5,7 @@ import { ethers } from 'ethers' import { tracker, trackers } from '@0xsequence/sessions' import { Orchestrator } from '@0xsequence/signhub' import { migrator } from '@0xsequence/migration' -import { commons, v1 } from '@0xsequence/core' +import { commons, universal, v1 } from '@0xsequence/core' import { Services, ServicesSettings, SessionJWT, SessionMeta } from './services' export interface SessionDumpV1 { @@ -87,12 +87,41 @@ export class Session { address: referenceSigner }] + const selectWallet = args.selectWallet || (async (wallets: string[]) => { + if (wallets.length === 0) return undefined + + // Find a wallet that was originally created + // as a 1/1 of the reference signer + const tracker = args.settings?.tracker ?? SessionSettingsDefault.tracker + + const configs = await Promise.all(wallets.map(async (wallet) => { + const imageHash = await tracker.imageHashOfCounterfactualWallet({ wallet }) + + return { + wallet, + config: imageHash && await tracker.configOfImageHash({ imageHash: imageHash.imageHash }) + } + })) + + for (const config of configs) { + const coder = config.config && universal.genericCoderFor(config.config.version) + const signers = coder && config.config && coder.config.signersOf(config.config) + + if (signers && signers.length === 1 && signers[0].address === referenceSigner) { + return config.wallet + } + } + + return undefined + }) + return Session.open({ ...args, orchestrator, referenceSigner, threshold, - addSigners + addSigners, + selectWallet }) } @@ -102,7 +131,7 @@ export class Session { addSigners?: commons.config.SimpleSigner[] referenceSigner: string threshold?: ethers.BigNumberish - selectWallet?: (wallets: string[]) => Promise + selectWallet: (wallets: string[]) => Promise editConfigOnMigration?: (config: commons.config.Config) => commons.config.Config onMigration?: (account: Account) => Promise }): Promise { @@ -114,7 +143,7 @@ export class Session { if (!referenceChainId) throw Error('No reference chain found') const foundWallets = await tracker.walletsOfSigner({ signer: referenceSigner }) - const selectedWallet = selectWallet ? await selectWallet(foundWallets.map(w => w.wallet)) : foundWallets[0]?.wallet + const selectedWallet = await selectWallet(foundWallets.map(w => w.wallet)) let account: Account From f8da5a43fd1cc977f5c1a4f1d592578c2246188b Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Fri, 25 Aug 2023 14:39:06 +0000 Subject: [PATCH 10/13] changelog: Simpler support for sessions --- packages/0xsequence/CHANGELOG.md | 27 +++++++++++++++++++++++++++ packages/0xsequence/package.json | 2 +- packages/abi/CHANGELOG.md | 6 ++++++ packages/abi/package.json | 2 +- packages/account/CHANGELOG.md | 17 +++++++++++++++++ packages/account/package.json | 2 +- packages/api/CHANGELOG.md | 6 ++++++ packages/api/package.json | 2 +- packages/auth/CHANGELOG.md | 22 ++++++++++++++++++++++ packages/auth/package.json | 2 +- packages/core/CHANGELOG.md | 11 +++++++++++ packages/core/package.json | 2 +- packages/deployer/CHANGELOG.md | 11 +++++++++++ packages/deployer/package.json | 2 +- packages/estimator/CHANGELOG.md | 13 +++++++++++++ packages/estimator/package.json | 2 +- packages/guard/CHANGELOG.md | 12 ++++++++++++ packages/guard/package.json | 2 +- packages/indexer/CHANGELOG.md | 6 ++++++ packages/indexer/package.json | 2 +- packages/metadata/CHANGELOG.md | 6 ++++++ packages/metadata/package.json | 2 +- packages/migration/CHANGELOG.md | 13 +++++++++++++ packages/migration/package.json | 2 +- packages/multicall/CHANGELOG.md | 13 +++++++++++++ packages/multicall/package.json | 2 +- packages/network/CHANGELOG.md | 14 ++++++++++++++ packages/network/package.json | 2 +- packages/provider/CHANGELOG.md | 19 +++++++++++++++++++ packages/provider/package.json | 2 +- packages/relayer/CHANGELOG.md | 13 +++++++++++++ packages/relayer/package.json | 2 +- packages/replacer/CHANGELOG.md | 12 ++++++++++++ packages/replacer/package.json | 2 +- packages/sessions/CHANGELOG.md | 13 +++++++++++++ packages/sessions/package.json | 2 +- packages/signhub/CHANGELOG.md | 6 ++++++ packages/signhub/package.json | 2 +- packages/simulator/CHANGELOG.md | 11 +++++++++++ packages/simulator/package.json | 2 +- packages/tests/CHANGELOG.md | 11 +++++++++++ packages/tests/package.json | 2 +- packages/utils/CHANGELOG.md | 6 ++++++ packages/utils/package.json | 2 +- packages/wallet/CHANGELOG.md | 16 ++++++++++++++++ packages/wallet/package.json | 2 +- 46 files changed, 307 insertions(+), 23 deletions(-) diff --git a/packages/0xsequence/CHANGELOG.md b/packages/0xsequence/CHANGELOG.md index 955ce6e20..956f6a720 100644 --- a/packages/0xsequence/CHANGELOG.md +++ b/packages/0xsequence/CHANGELOG.md @@ -1,5 +1,32 @@ # 0xsequence +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825081759 + - @0xsequence/multicall@0.0.0-20230825081759 + - @0xsequence/metadata@0.0.0-20230825081759 + - @0xsequence/provider@0.0.0-20230825081759 + - @0xsequence/sessions@0.0.0-20230825081759 + - @0xsequence/account@0.0.0-20230825081759 + - @0xsequence/indexer@0.0.0-20230825081759 + - @0xsequence/network@0.0.0-20230825081759 + - @0xsequence/relayer@0.0.0-20230825081759 + - @0xsequence/signhub@0.0.0-20230825081759 + - @0xsequence/wallet@0.0.0-20230825081759 + - @0xsequence/guard@0.0.0-20230825081759 + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/auth@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + - @0xsequence/api@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/0xsequence/package.json b/packages/0xsequence/package.json index e92908b8b..7f9b4fe1c 100644 --- a/packages/0xsequence/package.json +++ b/packages/0xsequence/package.json @@ -1,6 +1,6 @@ { "name": "0xsequence", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "Sequence: a modular web3 stack and smart wallet for Ethereum chains", "repository": "https://github.com/0xsequence/sequence.js", "source": "src/index.ts", diff --git a/packages/abi/CHANGELOG.md b/packages/abi/CHANGELOG.md index 654be202a..a0c7d3f3c 100644 --- a/packages/abi/CHANGELOG.md +++ b/packages/abi/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/abi +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + ## 1.1.12 ### Patch Changes diff --git a/packages/abi/package.json b/packages/abi/package.json index eec8f6ff9..68e41ef59 100644 --- a/packages/abi/package.json +++ b/packages/abi/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/abi", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "abi sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/abi", "source": "src/index.ts", diff --git a/packages/account/CHANGELOG.md b/packages/account/CHANGELOG.md index 0f435c454..467b74d97 100644 --- a/packages/account/CHANGELOG.md +++ b/packages/account/CHANGELOG.md @@ -1,5 +1,22 @@ # @0xsequence/account +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825081759 + - @0xsequence/sessions@0.0.0-20230825081759 + - @0xsequence/network@0.0.0-20230825081759 + - @0xsequence/relayer@0.0.0-20230825081759 + - @0xsequence/wallet@0.0.0-20230825081759 + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/account/package.json b/packages/account/package.json index a555ee69d..2f2582097 100644 --- a/packages/account/package.json +++ b/packages/account/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/account", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "tools for migrating sequence wallets to new versions", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/account", "source": "src/index.ts", diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index 1079833c0..66afcc380 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/api +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + ## 1.1.12 ### Patch Changes diff --git a/packages/api/package.json b/packages/api/package.json index b990509f2..680f7e7cf 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/api", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "api sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/api", "source": "src/index.ts", diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index 766741900..5f1386ef1 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,5 +1,27 @@ # @0xsequence/auth +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825081759 + - @0xsequence/metadata@0.0.0-20230825081759 + - @0xsequence/sessions@0.0.0-20230825081759 + - @0xsequence/account@0.0.0-20230825081759 + - @0xsequence/indexer@0.0.0-20230825081759 + - @0xsequence/network@0.0.0-20230825081759 + - @0xsequence/signhub@0.0.0-20230825081759 + - @0xsequence/wallet@0.0.0-20230825081759 + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + - @0xsequence/api@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/auth/package.json b/packages/auth/package.json index 3e0333ccb..90d9daefe 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/auth", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "auth sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/auth", "source": "src/index.ts", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 6b328d4cd..13e6950c5 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,16 @@ # @0xsequence/core +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/abi@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index 28e24e374..bfab0a32d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/core", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "core primitives for interacting with the sequence wallet contracts", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/core", "source": "src/index.ts", diff --git a/packages/deployer/CHANGELOG.md b/packages/deployer/CHANGELOG.md index 8347faba7..2f57c500e 100644 --- a/packages/deployer/CHANGELOG.md +++ b/packages/deployer/CHANGELOG.md @@ -1,5 +1,16 @@ # @0xsequence/deployer +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/utils@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/deployer/package.json b/packages/deployer/package.json index a2a9e92d5..d92673957 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/deployer", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "deployer sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/deployer", "source": "src/index.ts", diff --git a/packages/estimator/CHANGELOG.md b/packages/estimator/CHANGELOG.md index 64bed1f30..704373af0 100644 --- a/packages/estimator/CHANGELOG.md +++ b/packages/estimator/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/estimator +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/estimator/package.json b/packages/estimator/package.json index a941d5ee5..9125c3610 100644 --- a/packages/estimator/package.json +++ b/packages/estimator/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/estimator", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "estimator sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/estimator", "source": "src/index.ts", diff --git a/packages/guard/CHANGELOG.md b/packages/guard/CHANGELOG.md index 96519d986..14ed9e750 100644 --- a/packages/guard/CHANGELOG.md +++ b/packages/guard/CHANGELOG.md @@ -1,5 +1,17 @@ # @0xsequence/guard +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/signhub@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/guard/package.json b/packages/guard/package.json index a8bed13f6..c47ec7617 100644 --- a/packages/guard/package.json +++ b/packages/guard/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/guard", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "guard sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/guard", "source": "src/index.ts", diff --git a/packages/indexer/CHANGELOG.md b/packages/indexer/CHANGELOG.md index 004f8159a..337f9cb75 100644 --- a/packages/indexer/CHANGELOG.md +++ b/packages/indexer/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/indexer +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + ## 1.1.12 ### Patch Changes diff --git a/packages/indexer/package.json b/packages/indexer/package.json index 13a53d86d..44449c940 100644 --- a/packages/indexer/package.json +++ b/packages/indexer/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/indexer", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "indexer sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/indexer", "source": "src/index.ts", diff --git a/packages/metadata/CHANGELOG.md b/packages/metadata/CHANGELOG.md index b70bc01eb..bde90dc13 100644 --- a/packages/metadata/CHANGELOG.md +++ b/packages/metadata/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/metadata +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + ## 1.1.12 ### Patch Changes diff --git a/packages/metadata/package.json b/packages/metadata/package.json index 45975b616..658be4fd0 100644 --- a/packages/metadata/package.json +++ b/packages/metadata/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/metadata", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "metadata sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/metadata", "source": "src/index.ts", diff --git a/packages/migration/CHANGELOG.md b/packages/migration/CHANGELOG.md index 27078074d..057f4ae5b 100644 --- a/packages/migration/CHANGELOG.md +++ b/packages/migration/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/migration +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/wallet@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/migration/package.json b/packages/migration/package.json index 8fcff26fe..34ae426ff 100644 --- a/packages/migration/package.json +++ b/packages/migration/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/migration", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "tools for migrating sequence wallets to new versions", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/migration", "source": "src/index.ts", diff --git a/packages/multicall/CHANGELOG.md b/packages/multicall/CHANGELOG.md index b19a65ea6..851b873c6 100644 --- a/packages/multicall/CHANGELOG.md +++ b/packages/multicall/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/multicall +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/network@0.0.0-20230825081759 + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/multicall/package.json b/packages/multicall/package.json index bb1b03fa3..cc51762f8 100644 --- a/packages/multicall/package.json +++ b/packages/multicall/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/multicall", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "multicall sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/multicall", "source": "src/index.ts", diff --git a/packages/network/CHANGELOG.md b/packages/network/CHANGELOG.md index 8a69f81ee..cd06a36a4 100644 --- a/packages/network/CHANGELOG.md +++ b/packages/network/CHANGELOG.md @@ -1,5 +1,19 @@ # @0xsequence/network +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/indexer@0.0.0-20230825081759 + - @0xsequence/relayer@0.0.0-20230825081759 + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/network/package.json b/packages/network/package.json index 2ea46a378..8908af013 100644 --- a/packages/network/package.json +++ b/packages/network/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/network", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "network sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/network", "source": "src/index.ts", diff --git a/packages/provider/CHANGELOG.md b/packages/provider/CHANGELOG.md index 30428ca98..06717e712 100644 --- a/packages/provider/CHANGELOG.md +++ b/packages/provider/CHANGELOG.md @@ -1,5 +1,24 @@ # @0xsequence/provider +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825081759 + - @0xsequence/account@0.0.0-20230825081759 + - @0xsequence/network@0.0.0-20230825081759 + - @0xsequence/relayer@0.0.0-20230825081759 + - @0xsequence/wallet@0.0.0-20230825081759 + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/auth@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/provider/package.json b/packages/provider/package.json index c9fce114a..994157b00 100644 --- a/packages/provider/package.json +++ b/packages/provider/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/provider", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "provider sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/provider", "source": "src/index.ts", diff --git a/packages/relayer/CHANGELOG.md b/packages/relayer/CHANGELOG.md index 728716950..4eeeaf520 100644 --- a/packages/relayer/CHANGELOG.md +++ b/packages/relayer/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/relayer +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/relayer/package.json b/packages/relayer/package.json index 81aa9ebd3..77e91b614 100644 --- a/packages/relayer/package.json +++ b/packages/relayer/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/relayer", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "relayer sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/relayer", "source": "src/index.ts", diff --git a/packages/replacer/CHANGELOG.md b/packages/replacer/CHANGELOG.md index a9b512219..b1b1b4d0e 100644 --- a/packages/replacer/CHANGELOG.md +++ b/packages/replacer/CHANGELOG.md @@ -1,5 +1,17 @@ # @0xsequence/replacer +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/core@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/replacer/package.json b/packages/replacer/package.json index 40145329a..4ed324b17 100644 --- a/packages/replacer/package.json +++ b/packages/replacer/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/replacer", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "EIP-5719 client implementation", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/replacer", "source": "src/index.ts", diff --git a/packages/sessions/CHANGELOG.md b/packages/sessions/CHANGELOG.md index c7679e784..1b3e47a95 100644 --- a/packages/sessions/CHANGELOG.md +++ b/packages/sessions/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/sessions +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825081759 + - @0xsequence/replacer@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/sessions/package.json b/packages/sessions/package.json index db10d34c7..0193b351e 100644 --- a/packages/sessions/package.json +++ b/packages/sessions/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/sessions", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "tools for migrating sequence wallets to new versions", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/sessions", "source": "src/index.ts", diff --git a/packages/signhub/CHANGELOG.md b/packages/signhub/CHANGELOG.md index abe064d81..8098752c2 100644 --- a/packages/signhub/CHANGELOG.md +++ b/packages/signhub/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/signhub +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + ## 1.1.12 ### Patch Changes diff --git a/packages/signhub/package.json b/packages/signhub/package.json index c1fe2e983..9740f4300 100644 --- a/packages/signhub/package.json +++ b/packages/signhub/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/signhub", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "orchestrates a series of signers, provides visibility into the signing process, and to the signers themselves", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/signhub", "source": "src/index.ts", diff --git a/packages/simulator/CHANGELOG.md b/packages/simulator/CHANGELOG.md index f21c8b072..ec761a7f8 100644 --- a/packages/simulator/CHANGELOG.md +++ b/packages/simulator/CHANGELOG.md @@ -1,5 +1,16 @@ # @0xsequence/simulator +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/core@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/simulator/package.json b/packages/simulator/package.json index aed8bb79b..7f8de5c9a 100644 --- a/packages/simulator/package.json +++ b/packages/simulator/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/simulator", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "simulator sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/simulator", "source": "src/index.ts", diff --git a/packages/tests/CHANGELOG.md b/packages/tests/CHANGELOG.md index bd396141a..f85340868 100644 --- a/packages/tests/CHANGELOG.md +++ b/packages/tests/CHANGELOG.md @@ -1,5 +1,16 @@ # @0xsequence/tests +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/core@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/tests/package.json b/packages/tests/package.json index 60b59ddca..b61f6b343 100644 --- a/packages/tests/package.json +++ b/packages/tests/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/tests", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "test tools for sequence.js", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/tests", "source": "src/index.ts", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 8bccb567c..9b2673b25 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/utils +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + ## 1.1.12 ### Patch Changes diff --git a/packages/utils/package.json b/packages/utils/package.json index 6f006720c..7745f7a88 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/utils", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "utils sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/utils", "source": "src/index.ts", diff --git a/packages/wallet/CHANGELOG.md b/packages/wallet/CHANGELOG.md index b9d7800ea..107b3caf1 100644 --- a/packages/wallet/CHANGELOG.md +++ b/packages/wallet/CHANGELOG.md @@ -1,5 +1,21 @@ # @0xsequence/wallet +## 0.0.0-20230825081759 + +### Minor Changes + +- Simpler support for sessions + +### Patch Changes + +- Updated dependencies + - @0xsequence/network@0.0.0-20230825081759 + - @0xsequence/relayer@0.0.0-20230825081759 + - @0xsequence/signhub@0.0.0-20230825081759 + - @0xsequence/utils@0.0.0-20230825081759 + - @0xsequence/core@0.0.0-20230825081759 + - @0xsequence/abi@0.0.0-20230825081759 + ## 1.1.12 ### Patch Changes diff --git a/packages/wallet/package.json b/packages/wallet/package.json index e0d739a9a..7c5881552 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/wallet", - "version": "1.1.12", + "version": "0.0.0-20230825081759", "description": "wallet sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/wallet", "source": "src/index.ts", From 2b16ffbcb549ddd6f0c1f6c79b895d8d15988139 Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Fri, 25 Aug 2023 15:05:18 +0000 Subject: [PATCH 11/13] Add support for custom nonce space --- packages/account/src/account.ts | 14 +++- packages/account/src/signer.ts | 8 +- packages/account/tests/signer.spec.ts | 110 ++++++++++++++++++++++++++ packages/wallet/src/wallet.ts | 27 +++++-- 4 files changed, 147 insertions(+), 12 deletions(-) diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index 34354467f..8b6f8e90c 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -613,13 +613,16 @@ export class Account { async signTransactions( txs: commons.transaction.Transactionish, chainId: ethers.BigNumberish, - pstatus?: AccountStatus + pstatus?: AccountStatus, + options?: { + nonceSpace?: ethers.BigNumberish + } ): Promise { const status = pstatus || (await this.status(chainId)) this.mustBeFullyMigrated(status) const wallet = this.walletForStatus(chainId, status) - const signed = await wallet.signTransactions(txs) + const signed = await wallet.signTransactions(txs, options?.nonceSpace && { space: options?.nonceSpace }) return { ...signed, @@ -793,12 +796,15 @@ export class Account { chainId: ethers.BigNumberish, quote?: FeeQuote, skipPreDecorate: boolean = false, - callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void + callback?: (bundle: commons.transaction.IntendedTransactionBundle) => void, + options?: { + nonceSpace?: ethers.BigNumberish + } ): Promise { const status = await this.status(chainId) const predecorated = skipPreDecorate ? txs : await this.predecorateTransactions(txs, status, chainId) - const signed = await this.signTransactions(predecorated, chainId) + const signed = await this.signTransactions(predecorated, chainId, undefined, options) // TODO: is it safe to pass status again here? return this.sendSignedTransactions(signed, chainId, quote, undefined, callback) } diff --git a/packages/account/src/signer.ts b/packages/account/src/signer.ts index 6e0b78ce5..6aa8a0304 100644 --- a/packages/account/src/signer.ts +++ b/packages/account/src/signer.ts @@ -6,6 +6,7 @@ import { FeeOption, proto } from "@0xsequence/relayer" import { isDeferrable } from "./utils" export type AccountSignerOptions = { + nonceSpace?: ethers.BigNumberish, cantValidateBehavior?: 'ignore' | 'eip6492' | 'throw', stubSignatureOverrides?: Map, selectFee?: ( @@ -148,7 +149,12 @@ export class AccountSigner implements ethers.Signer { return this.account.sendTransaction( finalTransactions, this.chainId, - prepare.feeQuote + prepare.feeQuote, + undefined, + undefined, + this.options?.nonceSpace ? { + nonceSpace: this.options.nonceSpace + } : undefined ) } diff --git a/packages/account/tests/signer.spec.ts b/packages/account/tests/signer.spec.ts index bc536dea0..2057e5907 100644 --- a/packages/account/tests/signer.spec.ts +++ b/packages/account/tests/signer.spec.ts @@ -613,6 +613,116 @@ describe('Account signer', () => { }) }) }) + + describe('multiple nonce spaces', async () => { + it('should send transactions on multiple nonce spaces at once', async () => { + const signer1 = account.getSigner(chainId, { nonceSpace: '0x01' }) + const signer2 = account.getSigner(chainId, { nonceSpace: 2 }) + const signer3 = account.getSigner(chainId, { nonceSpace: ethers.BigNumber.from(ethers.utils.hexlify(ethers.utils.randomBytes(20))) }) + const signer4 = account.getSigner(chainId, { nonceSpace: '0x04' }) + const signer5 = account.getSigner(chainId, { nonceSpace: '0xffffffffffffffffffffffffffffffffffffffff' }) + + const results = await Promise.all([ + signer1.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer2.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer3.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer4.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer5.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + ]) + + expect(results).to.have.lengthOf(5) + expect(results[0]).to.exist + expect(results[0].hash).to.exist + expect(results[1]).to.exist + expect(results[1].hash).to.exist + expect(results[2]).to.exist + expect(results[2].hash).to.exist + expect(results[3]).to.exist + expect(results[3].hash).to.exist + expect(results[4]).to.exist + expect(results[4].hash).to.exist + + // hashes should be different + for (let i = 0; i < results.length; i++) { + for (let j = i + 1; j < results.length; j++) { + expect(results[i].hash).to.not.equal(results[j].hash) + } + } + }) + + it('should send multiple transactions on multiple nonce spaces at once', async () => { + const signer1 = account.getSigner(chainId, { nonceSpace: '0x01' }) + const signer2 = account.getSigner(chainId, { nonceSpace: 2 }) + const signer3 = account.getSigner(chainId, { nonceSpace: ethers.BigNumber.from(ethers.utils.hexlify(ethers.utils.randomBytes(20))) }) + const signer4 = account.getSigner(chainId, { nonceSpace: '0x04' }) + const signer5 = account.getSigner(chainId, { nonceSpace: '0xffffffffffffffffffffffffffffffffffffffff' }) + + await Promise.all([ + signer1.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer2.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer3.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer4.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer5.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + ]) + + const results = await Promise.all([ + signer1.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer2.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer3.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer4.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }), + signer5.sendTransaction({ + to: ethers.Wallet.createRandom().address, + }) + ]) + + expect(results).to.have.lengthOf(5) + expect(results[0]).to.exist + expect(results[0].hash).to.exist + expect(results[1]).to.exist + expect(results[1].hash).to.exist + expect(results[2]).to.exist + expect(results[2].hash).to.exist + expect(results[3]).to.exist + expect(results[3].hash).to.exist + expect(results[4]).to.exist + expect(results[4].hash).to.exist + + // hashes should be different + for (let i = 0; i < results.length; i++) { + for (let j = i + 1; j < results.length; j++) { + expect(results[i].hash).to.not.equal(results[j].hash) + } + } + }) + }) }) }) }) diff --git a/packages/wallet/src/wallet.ts b/packages/wallet/src/wallet.ts index 9ccef251b..09a5b7962 100644 --- a/packages/wallet/src/wallet.ts +++ b/packages/wallet/src/wallet.ts @@ -276,9 +276,27 @@ export class Wallet< return this.signTransactions(bundle.transactions, bundle.nonce) } + async nonceFor( + nonce?: ethers.BigNumberish | { space: ethers.BigNumberish } + ): Promise { + let spaceValue + + if (nonce && (nonce as any).space) { + spaceValue = ethers.BigNumber.from((nonce as any).space) + } else if (nonce === undefined) { + spaceValue = 0 + } else { + return nonce as ethers.BigNumberish + } + + const resultNonce = await this.reader().nonce(this.address, spaceValue) + if (resultNonce === undefined) throw new Error('Unable to determine nonce') + return commons.transaction.encodeNonce(spaceValue, resultNonce) + } + async signTransactions( txs: Deferrable, - nonce?: ethers.BigNumberish + nonce?: ethers.BigNumberish | { space: ethers.BigNumberish } ): Promise { const transaction = await resolveArrayProperties(txs) const transactions = commons.transaction.fromTransactionish(this.address, transaction) @@ -297,12 +315,7 @@ export class Wallet< }) } - let defaultedNonce = nonce - if (defaultedNonce === undefined) { - defaultedNonce = await this.reader().nonce(this.address, 0) - if (defaultedNonce === undefined) throw new Error('Unable to determine nonce') - } - + const defaultedNonce = await this.nonceFor(nonce) const digest = commons.transaction.digestOfTransactions(defaultedNonce, transactions) const signature = await this.signDigest(digest, { transactions }) From f2db8bb211314f58be17487bc69ba3c2d267a30d Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Fri, 25 Aug 2023 16:16:53 +0000 Subject: [PATCH 12/13] changelog: Add support for custom nonce space --- packages/0xsequence/CHANGELOG.md | 27 +++++++++++++++++++++++++++ packages/0xsequence/package.json | 2 +- packages/abi/CHANGELOG.md | 6 ++++++ packages/abi/package.json | 2 +- packages/account/CHANGELOG.md | 17 +++++++++++++++++ packages/account/package.json | 2 +- packages/api/CHANGELOG.md | 6 ++++++ packages/api/package.json | 2 +- packages/auth/CHANGELOG.md | 22 ++++++++++++++++++++++ packages/auth/package.json | 2 +- packages/core/CHANGELOG.md | 11 +++++++++++ packages/core/package.json | 2 +- packages/deployer/CHANGELOG.md | 11 +++++++++++ packages/deployer/package.json | 2 +- packages/estimator/CHANGELOG.md | 13 +++++++++++++ packages/estimator/package.json | 2 +- packages/guard/CHANGELOG.md | 12 ++++++++++++ packages/guard/package.json | 2 +- packages/indexer/CHANGELOG.md | 6 ++++++ packages/indexer/package.json | 2 +- packages/metadata/CHANGELOG.md | 6 ++++++ packages/metadata/package.json | 2 +- packages/migration/CHANGELOG.md | 13 +++++++++++++ packages/migration/package.json | 2 +- packages/multicall/CHANGELOG.md | 13 +++++++++++++ packages/multicall/package.json | 2 +- packages/network/CHANGELOG.md | 14 ++++++++++++++ packages/network/package.json | 2 +- packages/provider/CHANGELOG.md | 19 +++++++++++++++++++ packages/provider/package.json | 2 +- packages/relayer/CHANGELOG.md | 13 +++++++++++++ packages/relayer/package.json | 2 +- packages/replacer/CHANGELOG.md | 12 ++++++++++++ packages/replacer/package.json | 2 +- packages/sessions/CHANGELOG.md | 13 +++++++++++++ packages/sessions/package.json | 2 +- packages/signhub/CHANGELOG.md | 6 ++++++ packages/signhub/package.json | 2 +- packages/simulator/CHANGELOG.md | 11 +++++++++++ packages/simulator/package.json | 2 +- packages/tests/CHANGELOG.md | 11 +++++++++++ packages/tests/package.json | 2 +- packages/utils/CHANGELOG.md | 6 ++++++ packages/utils/package.json | 2 +- packages/wallet/CHANGELOG.md | 16 ++++++++++++++++ packages/wallet/package.json | 2 +- 46 files changed, 307 insertions(+), 23 deletions(-) diff --git a/packages/0xsequence/CHANGELOG.md b/packages/0xsequence/CHANGELOG.md index 956f6a720..2e41783c3 100644 --- a/packages/0xsequence/CHANGELOG.md +++ b/packages/0xsequence/CHANGELOG.md @@ -1,5 +1,32 @@ # 0xsequence +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825151821 + - @0xsequence/multicall@0.0.0-20230825151821 + - @0xsequence/metadata@0.0.0-20230825151821 + - @0xsequence/provider@0.0.0-20230825151821 + - @0xsequence/sessions@0.0.0-20230825151821 + - @0xsequence/account@0.0.0-20230825151821 + - @0xsequence/indexer@0.0.0-20230825151821 + - @0xsequence/network@0.0.0-20230825151821 + - @0xsequence/relayer@0.0.0-20230825151821 + - @0xsequence/signhub@0.0.0-20230825151821 + - @0xsequence/wallet@0.0.0-20230825151821 + - @0xsequence/guard@0.0.0-20230825151821 + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/auth@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + - @0xsequence/api@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/0xsequence/package.json b/packages/0xsequence/package.json index 7f9b4fe1c..98f6ed366 100644 --- a/packages/0xsequence/package.json +++ b/packages/0xsequence/package.json @@ -1,6 +1,6 @@ { "name": "0xsequence", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "Sequence: a modular web3 stack and smart wallet for Ethereum chains", "repository": "https://github.com/0xsequence/sequence.js", "source": "src/index.ts", diff --git a/packages/abi/CHANGELOG.md b/packages/abi/CHANGELOG.md index a0c7d3f3c..284e73f88 100644 --- a/packages/abi/CHANGELOG.md +++ b/packages/abi/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/abi +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/abi/package.json b/packages/abi/package.json index 68e41ef59..4884af3ca 100644 --- a/packages/abi/package.json +++ b/packages/abi/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/abi", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "abi sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/abi", "source": "src/index.ts", diff --git a/packages/account/CHANGELOG.md b/packages/account/CHANGELOG.md index 467b74d97..d53f03041 100644 --- a/packages/account/CHANGELOG.md +++ b/packages/account/CHANGELOG.md @@ -1,5 +1,22 @@ # @0xsequence/account +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825151821 + - @0xsequence/sessions@0.0.0-20230825151821 + - @0xsequence/network@0.0.0-20230825151821 + - @0xsequence/relayer@0.0.0-20230825151821 + - @0xsequence/wallet@0.0.0-20230825151821 + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/account/package.json b/packages/account/package.json index 2f2582097..48a5c5598 100644 --- a/packages/account/package.json +++ b/packages/account/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/account", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "tools for migrating sequence wallets to new versions", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/account", "source": "src/index.ts", diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index 66afcc380..60bb387a0 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/api +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/api/package.json b/packages/api/package.json index 680f7e7cf..d1a9cd64c 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/api", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "api sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/api", "source": "src/index.ts", diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index 5f1386ef1..696f9cd7d 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,5 +1,27 @@ # @0xsequence/auth +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825151821 + - @0xsequence/metadata@0.0.0-20230825151821 + - @0xsequence/sessions@0.0.0-20230825151821 + - @0xsequence/account@0.0.0-20230825151821 + - @0xsequence/indexer@0.0.0-20230825151821 + - @0xsequence/network@0.0.0-20230825151821 + - @0xsequence/signhub@0.0.0-20230825151821 + - @0xsequence/wallet@0.0.0-20230825151821 + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + - @0xsequence/api@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/auth/package.json b/packages/auth/package.json index 90d9daefe..967cd4bf6 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/auth", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "auth sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/auth", "source": "src/index.ts", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 13e6950c5..193b0d4a5 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,16 @@ # @0xsequence/core +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/abi@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index bfab0a32d..f225d94d3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/core", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "core primitives for interacting with the sequence wallet contracts", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/core", "source": "src/index.ts", diff --git a/packages/deployer/CHANGELOG.md b/packages/deployer/CHANGELOG.md index 2f57c500e..117a227e7 100644 --- a/packages/deployer/CHANGELOG.md +++ b/packages/deployer/CHANGELOG.md @@ -1,5 +1,16 @@ # @0xsequence/deployer +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/utils@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/deployer/package.json b/packages/deployer/package.json index d92673957..830fde283 100644 --- a/packages/deployer/package.json +++ b/packages/deployer/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/deployer", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "deployer sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/deployer", "source": "src/index.ts", diff --git a/packages/estimator/CHANGELOG.md b/packages/estimator/CHANGELOG.md index 704373af0..14e9c719e 100644 --- a/packages/estimator/CHANGELOG.md +++ b/packages/estimator/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/estimator +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/estimator/package.json b/packages/estimator/package.json index 9125c3610..ee31a018b 100644 --- a/packages/estimator/package.json +++ b/packages/estimator/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/estimator", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "estimator sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/estimator", "source": "src/index.ts", diff --git a/packages/guard/CHANGELOG.md b/packages/guard/CHANGELOG.md index 14ed9e750..5920bb04e 100644 --- a/packages/guard/CHANGELOG.md +++ b/packages/guard/CHANGELOG.md @@ -1,5 +1,17 @@ # @0xsequence/guard +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/signhub@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/guard/package.json b/packages/guard/package.json index c47ec7617..005e7c09a 100644 --- a/packages/guard/package.json +++ b/packages/guard/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/guard", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "guard sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/guard", "source": "src/index.ts", diff --git a/packages/indexer/CHANGELOG.md b/packages/indexer/CHANGELOG.md index 337f9cb75..0976beb9a 100644 --- a/packages/indexer/CHANGELOG.md +++ b/packages/indexer/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/indexer +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/indexer/package.json b/packages/indexer/package.json index 44449c940..35868a77b 100644 --- a/packages/indexer/package.json +++ b/packages/indexer/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/indexer", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "indexer sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/indexer", "source": "src/index.ts", diff --git a/packages/metadata/CHANGELOG.md b/packages/metadata/CHANGELOG.md index bde90dc13..c8bd9d18e 100644 --- a/packages/metadata/CHANGELOG.md +++ b/packages/metadata/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/metadata +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/metadata/package.json b/packages/metadata/package.json index 658be4fd0..602a46b69 100644 --- a/packages/metadata/package.json +++ b/packages/metadata/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/metadata", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "metadata sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/metadata", "source": "src/index.ts", diff --git a/packages/migration/CHANGELOG.md b/packages/migration/CHANGELOG.md index 057f4ae5b..01ede10ae 100644 --- a/packages/migration/CHANGELOG.md +++ b/packages/migration/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/migration +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/wallet@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/migration/package.json b/packages/migration/package.json index 34ae426ff..5af3c6a7a 100644 --- a/packages/migration/package.json +++ b/packages/migration/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/migration", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "tools for migrating sequence wallets to new versions", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/migration", "source": "src/index.ts", diff --git a/packages/multicall/CHANGELOG.md b/packages/multicall/CHANGELOG.md index 851b873c6..de7160d5f 100644 --- a/packages/multicall/CHANGELOG.md +++ b/packages/multicall/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/multicall +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/network@0.0.0-20230825151821 + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/multicall/package.json b/packages/multicall/package.json index cc51762f8..acf59fc71 100644 --- a/packages/multicall/package.json +++ b/packages/multicall/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/multicall", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "multicall sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/multicall", "source": "src/index.ts", diff --git a/packages/network/CHANGELOG.md b/packages/network/CHANGELOG.md index cd06a36a4..161bf485d 100644 --- a/packages/network/CHANGELOG.md +++ b/packages/network/CHANGELOG.md @@ -1,5 +1,19 @@ # @0xsequence/network +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/indexer@0.0.0-20230825151821 + - @0xsequence/relayer@0.0.0-20230825151821 + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/network/package.json b/packages/network/package.json index 8908af013..201bf2b19 100644 --- a/packages/network/package.json +++ b/packages/network/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/network", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "network sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/network", "source": "src/index.ts", diff --git a/packages/provider/CHANGELOG.md b/packages/provider/CHANGELOG.md index 06717e712..0f5bad3f7 100644 --- a/packages/provider/CHANGELOG.md +++ b/packages/provider/CHANGELOG.md @@ -1,5 +1,24 @@ # @0xsequence/provider +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825151821 + - @0xsequence/account@0.0.0-20230825151821 + - @0xsequence/network@0.0.0-20230825151821 + - @0xsequence/relayer@0.0.0-20230825151821 + - @0xsequence/wallet@0.0.0-20230825151821 + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/auth@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/provider/package.json b/packages/provider/package.json index 994157b00..9351d9a1e 100644 --- a/packages/provider/package.json +++ b/packages/provider/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/provider", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "provider sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/provider", "source": "src/index.ts", diff --git a/packages/relayer/CHANGELOG.md b/packages/relayer/CHANGELOG.md index 4eeeaf520..0773d627b 100644 --- a/packages/relayer/CHANGELOG.md +++ b/packages/relayer/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/relayer +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/relayer/package.json b/packages/relayer/package.json index 77e91b614..d791b885c 100644 --- a/packages/relayer/package.json +++ b/packages/relayer/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/relayer", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "relayer sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/relayer", "source": "src/index.ts", diff --git a/packages/replacer/CHANGELOG.md b/packages/replacer/CHANGELOG.md index b1b1b4d0e..e1644c225 100644 --- a/packages/replacer/CHANGELOG.md +++ b/packages/replacer/CHANGELOG.md @@ -1,5 +1,17 @@ # @0xsequence/replacer +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/core@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/replacer/package.json b/packages/replacer/package.json index 4ed324b17..a5bfb2169 100644 --- a/packages/replacer/package.json +++ b/packages/replacer/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/replacer", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "EIP-5719 client implementation", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/replacer", "source": "src/index.ts", diff --git a/packages/sessions/CHANGELOG.md b/packages/sessions/CHANGELOG.md index 1b3e47a95..de4ea2d8b 100644 --- a/packages/sessions/CHANGELOG.md +++ b/packages/sessions/CHANGELOG.md @@ -1,5 +1,18 @@ # @0xsequence/sessions +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/migration@0.0.0-20230825151821 + - @0xsequence/replacer@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/sessions/package.json b/packages/sessions/package.json index 0193b351e..7bf763942 100644 --- a/packages/sessions/package.json +++ b/packages/sessions/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/sessions", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "tools for migrating sequence wallets to new versions", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/sessions", "source": "src/index.ts", diff --git a/packages/signhub/CHANGELOG.md b/packages/signhub/CHANGELOG.md index 8098752c2..f09fe8bed 100644 --- a/packages/signhub/CHANGELOG.md +++ b/packages/signhub/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/signhub +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/signhub/package.json b/packages/signhub/package.json index 9740f4300..6da1af7fe 100644 --- a/packages/signhub/package.json +++ b/packages/signhub/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/signhub", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "orchestrates a series of signers, provides visibility into the signing process, and to the signers themselves", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/signhub", "source": "src/index.ts", diff --git a/packages/simulator/CHANGELOG.md b/packages/simulator/CHANGELOG.md index ec761a7f8..2cda02bc0 100644 --- a/packages/simulator/CHANGELOG.md +++ b/packages/simulator/CHANGELOG.md @@ -1,5 +1,16 @@ # @0xsequence/simulator +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/core@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/simulator/package.json b/packages/simulator/package.json index 7f8de5c9a..a75e489fa 100644 --- a/packages/simulator/package.json +++ b/packages/simulator/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/simulator", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "simulator sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/simulator", "source": "src/index.ts", diff --git a/packages/tests/CHANGELOG.md b/packages/tests/CHANGELOG.md index f85340868..c830fe97b 100644 --- a/packages/tests/CHANGELOG.md +++ b/packages/tests/CHANGELOG.md @@ -1,5 +1,16 @@ # @0xsequence/tests +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/core@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/tests/package.json b/packages/tests/package.json index b61f6b343..2163a2f87 100644 --- a/packages/tests/package.json +++ b/packages/tests/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/tests", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "test tools for sequence.js", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/tests", "source": "src/index.ts", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 9b2673b25..c4dddb675 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @0xsequence/utils +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/utils/package.json b/packages/utils/package.json index 7745f7a88..08e41e174 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/utils", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "utils sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/utils", "source": "src/index.ts", diff --git a/packages/wallet/CHANGELOG.md b/packages/wallet/CHANGELOG.md index 107b3caf1..6bfd02f2e 100644 --- a/packages/wallet/CHANGELOG.md +++ b/packages/wallet/CHANGELOG.md @@ -1,5 +1,21 @@ # @0xsequence/wallet +## 0.0.0-20230825151821 + +### Minor Changes + +- Add support for custom nonce space + +### Patch Changes + +- Updated dependencies + - @0xsequence/network@0.0.0-20230825151821 + - @0xsequence/relayer@0.0.0-20230825151821 + - @0xsequence/signhub@0.0.0-20230825151821 + - @0xsequence/utils@0.0.0-20230825151821 + - @0xsequence/core@0.0.0-20230825151821 + - @0xsequence/abi@0.0.0-20230825151821 + ## 0.0.0-20230825081759 ### Minor Changes diff --git a/packages/wallet/package.json b/packages/wallet/package.json index 7c5881552..dcaadb861 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/wallet", - "version": "0.0.0-20230825081759", + "version": "0.0.0-20230825151821", "description": "wallet sub-package for Sequence", "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/wallet", "source": "src/index.ts", From 043a4a18e2c78cfd32d89c2a511b0367da2eb614 Mon Sep 17 00:00:00 2001 From: Agusx1211 Date: Fri, 1 Sep 2023 17:38:00 +0000 Subject: [PATCH 13/13] Michael's changes --- packages/auth/src/services.ts | 13 +++++-------- packages/auth/src/session.ts | 10 +++++++--- packages/wallet/src/wallet.ts | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/auth/src/services.ts b/packages/auth/src/services.ts index 9db2553cf..ee4915430 100644 --- a/packages/auth/src/services.ts +++ b/packages/auth/src/services.ts @@ -27,20 +27,16 @@ export type SessionJWT = { expiration: number } -type SessionJWTPromise = { +export type SessionJWTPromise = { token: Promise expiration: number } -type ProofStringPromise = { +export type ProofStringPromise = { proofString: Promise expiration: number } -function getJWTExpiration(jwt: string): number { - return jwtDecodeClaims<{ exp: number }>(jwt).exp -} - // Default session expiration of ETHAuth token (1 week) export const DEFAULT_SESSION_EXPIRATION = 60 * 60 * 24 * 7 @@ -83,6 +79,7 @@ export class Services { onAuth(cb: (result: PromiseSettledResult) => void) { this.onAuthCallbacks.push(cb) + return () => this.onAuthCallbacks = this.onAuthCallbacks.filter(c => c !== cb) } async dump(): Promise<{ @@ -108,12 +105,12 @@ export class Services { if (!url) throw Error('No sequence api url') let jwtAuth: string | undefined - for (let i = 0; ; i++) { + for (let i = 1; ; i++) { try { jwtAuth = (await this.getJWT(true)).token break } catch (error) { - if (i === maxTries - 1) { + if (i === maxTries) { console.error(`couldn't authenticate after ${maxTries} attempts`, error) throw error } diff --git a/packages/auth/src/session.ts b/packages/auth/src/session.ts index 0492447fd..e1adb962b 100644 --- a/packages/auth/src/session.ts +++ b/packages/auth/src/session.ts @@ -104,10 +104,14 @@ export class Session { })) for (const config of configs) { - const coder = config.config && universal.genericCoderFor(config.config.version) - const signers = coder && config.config && coder.config.signersOf(config.config) + if (!config.config) { + continue + } - if (signers && signers.length === 1 && signers[0].address === referenceSigner) { + const coder = universal.genericCoderFor(config.config.version) + const signers = coder.config.signersOf(config.config) + + if (signers.length === 1 && signers[0].address === referenceSigner) { return config.wallet } } diff --git a/packages/wallet/src/wallet.ts b/packages/wallet/src/wallet.ts index 09a5b7962..89363a035 100644 --- a/packages/wallet/src/wallet.ts +++ b/packages/wallet/src/wallet.ts @@ -276,7 +276,7 @@ export class Wallet< return this.signTransactions(bundle.transactions, bundle.nonce) } - async nonceFor( + async fetchNonceOrSpace( nonce?: ethers.BigNumberish | { space: ethers.BigNumberish } ): Promise { let spaceValue @@ -315,7 +315,7 @@ export class Wallet< }) } - const defaultedNonce = await this.nonceFor(nonce) + const defaultedNonce = await this.fetchNonceOrSpace(nonce) const digest = commons.transaction.digestOfTransactions(defaultedNonce, transactions) const signature = await this.signDigest(digest, { transactions })