@0xsequence/provider 0.0.0-20230726193528 → 0.0.0-20230801185244

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2107,6 +2107,25 @@ function fromExtended(transaction) {
2107
2107
  return [transaction, ...(transaction.auxiliary || [])];
2108
2108
  }
2109
2109
 
2110
+ function validateTransactionRequest(wallet, transaction) {
2111
+ const transactions = core.commons.transaction.fromTransactionish(wallet, transaction);
2112
+ const unwound = core.commons.transaction.unwind(wallet, transactions);
2113
+ unwound.forEach(transaction => validateTransaction(wallet, transaction));
2114
+ }
2115
+ function validateTransaction(wallet, transaction) {
2116
+ if (transaction.to.toLowerCase() === wallet.toLowerCase()) {
2117
+ if (transaction.data) {
2118
+ const data = ethers.ethers.utils.arrayify(transaction.data);
2119
+ if (data.length >= 4) {
2120
+ throw new Error('self calls are forbidden');
2121
+ }
2122
+ }
2123
+ }
2124
+ if (transaction.delegateCall) {
2125
+ throw new Error('delegate calls are forbidden');
2126
+ }
2127
+ }
2128
+
2110
2129
  const SIGNER_READY_TIMEOUT = 10000;
2111
2130
  class WalletRequestHandler {
2112
2131
  constructor(_account, prompter, networks) {
@@ -2297,6 +2316,7 @@ class WalletRequestHandler {
2297
2316
  }
2298
2317
  return tx;
2299
2318
  });
2319
+ validateTransactionRequest(account.address, transactionParams);
2300
2320
  let txnHash = '';
2301
2321
  if (_this.prompter === null) {
2302
2322
  // prompter is null, so we'll send from here
@@ -2322,6 +2342,7 @@ class WalletRequestHandler {
2322
2342
  if (sender !== account.address) {
2323
2343
  throw new Error('sender address does not match wallet');
2324
2344
  }
2345
+ validateTransactionRequest(account.address, transaction);
2325
2346
  if (_this.prompter === null) {
2326
2347
  // The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
2327
2348
  // this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.
@@ -3101,20 +3122,36 @@ class WalletUtils {
3101
3122
 
3102
3123
  class SequenceProvider extends ethers.ethers.providers.BaseProvider {
3103
3124
  constructor(client, providerFor, networks = network.allNetworks) {
3104
- var _this;
3105
3125
  // We support a lot of networks
3106
3126
  // but we start with the default one
3107
3127
  super(client.getChainId());
3108
- _this = this;
3128
+
3129
+ // Emit events as defined by EIP-1193
3109
3130
  this.singleNetworkProviders = {};
3110
3131
  this._isSequenceProvider = true;
3111
3132
  this.client = client;
3112
3133
  this.providerFor = providerFor;
3113
3134
  this.networks = networks;
3114
- client.onDefaultChainIdChanged(async function (chainId) {
3115
- // TODO: Maybe we should emit more events here
3116
- _this.emit('chainChanged', chainId);
3135
+ client.onConnect(details => {
3136
+ this.emit('connect', details);
3117
3137
  });
3138
+ client.onDisconnect(error => {
3139
+ this.emit('disconnect', error);
3140
+ });
3141
+ client.onDefaultChainIdChanged(chainId => {
3142
+ this.emit('chainChanged', chainId);
3143
+ });
3144
+ client.onAccountsChanged(accounts => {
3145
+ this.emit('accountsChanged', accounts);
3146
+ });
3147
+
3148
+ // NOTICE: We don't emit 'open' and 'close' events
3149
+ // because these are handled by the library, and they
3150
+ // are not part of EIP-1193
3151
+
3152
+ // devs can still access them using
3153
+ // client.onOpen()
3154
+ // client.onClose()
3118
3155
 
3119
3156
  // Create a Sequence signer too
3120
3157
  this.signer = new SequenceSigner(this.client, this);
@@ -3238,7 +3275,7 @@ class SequenceProvider extends ethers.ethers.providers.BaseProvider {
3238
3275
  var _provider$prepareRequ;
3239
3276
  // First we check if the method should be handled by the client
3240
3277
  if (method === 'eth_chainId') {
3241
- return this.useChainId();
3278
+ return `0x${(await this.useChainId()).toString(16)}`;
3242
3279
  }
3243
3280
  if (method === 'eth_accounts') {
3244
3281
  return [this.client.getAddress()];
@@ -3549,31 +3586,48 @@ class SequenceClient {
3549
3586
  this.session = new SequenceClientSession(store);
3550
3587
  this.defaultChainId = new DefaultChainIdTracker(store, defaultChainId);
3551
3588
  this.transport.on('accountsChanged', accounts => {
3552
- var _this$callbacks$onAcc;
3589
+ var _this$callbacks$accou;
3553
3590
  if (accounts.length > 1) {
3554
3591
  console.warn('SequenceClient: wallet-webapp returned more than one account');
3555
3592
  }
3556
- (_this$callbacks$onAcc = this.callbacks.onAccountsChanged) == null ? void 0 : _this$callbacks$onAcc.forEach(cb => cb(accounts));
3593
+ (_this$callbacks$accou = this.callbacks.accountsChanged) == null ? void 0 : _this$callbacks$accou.forEach(cb => cb(accounts));
3594
+ });
3595
+ this.transport.on('connect', response => {
3596
+ var _this$callbacks$conne;
3597
+ const chainIdHex = ethers.ethers.BigNumber.from(this.getChainId()).toHexString();
3598
+ (_this$callbacks$conne = this.callbacks.connect) == null ? void 0 : _this$callbacks$conne.forEach(cb => cb(_extends({}, response, {
3599
+ // Ignore the full connect response
3600
+ // use the chainId defined locally
3601
+ chainId: chainIdHex
3602
+ })));
3603
+ });
3604
+ this.transport.on('disconnect', error => {
3605
+ var _this$callbacks$disco;
3606
+ (_this$callbacks$disco = this.callbacks.disconnect) == null ? void 0 : _this$callbacks$disco.forEach(cb => cb(error));
3557
3607
  });
3558
3608
  this.transport.on('networks', networks => {
3559
- var _this$callbacks$onNet;
3560
- (_this$callbacks$onNet = this.callbacks.onNetworks) == null ? void 0 : _this$callbacks$onNet.forEach(cb => cb(networks));
3609
+ var _this$callbacks$netwo;
3610
+ (_this$callbacks$netwo = this.callbacks.networks) == null ? void 0 : _this$callbacks$netwo.forEach(cb => cb(networks));
3561
3611
  });
3562
3612
  this.transport.on('walletContext', context => {
3563
- var _this$callbacks$onWal;
3564
- (_this$callbacks$onWal = this.callbacks.onWalletContext) == null ? void 0 : _this$callbacks$onWal.forEach(cb => cb(context));
3613
+ var _this$callbacks$walle;
3614
+ (_this$callbacks$walle = this.callbacks.walletContext) == null ? void 0 : _this$callbacks$walle.forEach(cb => cb(context));
3565
3615
  });
3566
- this.transport.on('open', () => {
3567
- var _this$callbacks$onOpe;
3568
- (_this$callbacks$onOpe = this.callbacks.onOpen) == null ? void 0 : _this$callbacks$onOpe.forEach(cb => cb());
3616
+ this.transport.on('open', info => {
3617
+ var _this$callbacks$open;
3618
+ (_this$callbacks$open = this.callbacks.open) == null ? void 0 : _this$callbacks$open.forEach(cb => cb(info));
3569
3619
  });
3570
3620
  this.transport.on('close', () => {
3571
- var _this$callbacks$onClo;
3572
- (_this$callbacks$onClo = this.callbacks.onClose) == null ? void 0 : _this$callbacks$onClo.forEach(cb => cb());
3621
+ var _this$callbacks$close;
3622
+ (_this$callbacks$close = this.callbacks.close) == null ? void 0 : _this$callbacks$close.forEach(cb => cb());
3573
3623
  });
3624
+
3625
+ // We don't listen for the transport chainChanged event
3626
+ // instead we handle it locally, so we listen for changes in the store
3574
3627
  this.defaultChainId.onDefaultChainIdChanged(chainId => {
3575
- var _this$callbacks$onDef;
3576
- (_this$callbacks$onDef = this.callbacks.onDefaultChainIdChanged) == null ? void 0 : _this$callbacks$onDef.forEach(cb => cb(chainId));
3628
+ var _this$callbacks$chain;
3629
+ const chainIdHex = ethers.ethers.BigNumber.from(chainId).toHexString();
3630
+ (_this$callbacks$chain = this.callbacks.chainChanged) == null ? void 0 : _this$callbacks$chain.forEach(cb => cb(chainIdHex));
3577
3631
  });
3578
3632
  }
3579
3633
 
@@ -3592,24 +3646,30 @@ class SequenceClient {
3592
3646
  // Individual callbacks lead to more idiomatic code
3593
3647
 
3594
3648
  onOpen(callback) {
3595
- return this.registerCallback('onOpen', callback);
3649
+ return this.registerCallback('open', callback);
3596
3650
  }
3597
3651
  onClose(callback) {
3598
- return this.registerCallback('onClose', callback);
3652
+ return this.registerCallback('close', callback);
3653
+ }
3654
+ onConnect(callback) {
3655
+ return this.registerCallback('connect', callback);
3656
+ }
3657
+ onDisconnect(callback) {
3658
+ return this.registerCallback('disconnect', callback);
3599
3659
  }
3600
3660
  onNetworks(callback) {
3601
- return this.registerCallback('onNetworks', callback);
3661
+ return this.registerCallback('networks', callback);
3602
3662
  }
3603
3663
  onAccountsChanged(callback) {
3604
- return this.registerCallback('onAccountsChanged', callback);
3664
+ return this.registerCallback('accountsChanged', callback);
3605
3665
  }
3606
3666
 
3607
3667
  // @deprecated
3608
3668
  onWalletContext(callback) {
3609
- return this.registerCallback('onWalletContext', callback);
3669
+ return this.registerCallback('walletContext', callback);
3610
3670
  }
3611
3671
  onDefaultChainIdChanged(callback) {
3612
- return this.registerCallback('onDefaultChainIdChanged', callback);
3672
+ return this.registerCallback('chainChanged', callback);
3613
3673
  }
3614
3674
  getChainId() {
3615
3675
  return this.defaultChainId.getDefaultChainId();
@@ -2107,6 +2107,25 @@ function fromExtended(transaction) {
2107
2107
  return [transaction, ...(transaction.auxiliary || [])];
2108
2108
  }
2109
2109
 
2110
+ function validateTransactionRequest(wallet, transaction) {
2111
+ const transactions = core.commons.transaction.fromTransactionish(wallet, transaction);
2112
+ const unwound = core.commons.transaction.unwind(wallet, transactions);
2113
+ unwound.forEach(transaction => validateTransaction(wallet, transaction));
2114
+ }
2115
+ function validateTransaction(wallet, transaction) {
2116
+ if (transaction.to.toLowerCase() === wallet.toLowerCase()) {
2117
+ if (transaction.data) {
2118
+ const data = ethers.ethers.utils.arrayify(transaction.data);
2119
+ if (data.length >= 4) {
2120
+ throw new Error('self calls are forbidden');
2121
+ }
2122
+ }
2123
+ }
2124
+ if (transaction.delegateCall) {
2125
+ throw new Error('delegate calls are forbidden');
2126
+ }
2127
+ }
2128
+
2110
2129
  const SIGNER_READY_TIMEOUT = 10000;
2111
2130
  class WalletRequestHandler {
2112
2131
  constructor(_account, prompter, networks) {
@@ -2297,6 +2316,7 @@ class WalletRequestHandler {
2297
2316
  }
2298
2317
  return tx;
2299
2318
  });
2319
+ validateTransactionRequest(account.address, transactionParams);
2300
2320
  let txnHash = '';
2301
2321
  if (_this.prompter === null) {
2302
2322
  // prompter is null, so we'll send from here
@@ -2322,6 +2342,7 @@ class WalletRequestHandler {
2322
2342
  if (sender !== account.address) {
2323
2343
  throw new Error('sender address does not match wallet');
2324
2344
  }
2345
+ validateTransactionRequest(account.address, transaction);
2325
2346
  if (_this.prompter === null) {
2326
2347
  // The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
2327
2348
  // this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.
@@ -3101,20 +3122,36 @@ class WalletUtils {
3101
3122
 
3102
3123
  class SequenceProvider extends ethers.ethers.providers.BaseProvider {
3103
3124
  constructor(client, providerFor, networks = network.allNetworks) {
3104
- var _this;
3105
3125
  // We support a lot of networks
3106
3126
  // but we start with the default one
3107
3127
  super(client.getChainId());
3108
- _this = this;
3128
+
3129
+ // Emit events as defined by EIP-1193
3109
3130
  this.singleNetworkProviders = {};
3110
3131
  this._isSequenceProvider = true;
3111
3132
  this.client = client;
3112
3133
  this.providerFor = providerFor;
3113
3134
  this.networks = networks;
3114
- client.onDefaultChainIdChanged(async function (chainId) {
3115
- // TODO: Maybe we should emit more events here
3116
- _this.emit('chainChanged', chainId);
3135
+ client.onConnect(details => {
3136
+ this.emit('connect', details);
3117
3137
  });
3138
+ client.onDisconnect(error => {
3139
+ this.emit('disconnect', error);
3140
+ });
3141
+ client.onDefaultChainIdChanged(chainId => {
3142
+ this.emit('chainChanged', chainId);
3143
+ });
3144
+ client.onAccountsChanged(accounts => {
3145
+ this.emit('accountsChanged', accounts);
3146
+ });
3147
+
3148
+ // NOTICE: We don't emit 'open' and 'close' events
3149
+ // because these are handled by the library, and they
3150
+ // are not part of EIP-1193
3151
+
3152
+ // devs can still access them using
3153
+ // client.onOpen()
3154
+ // client.onClose()
3118
3155
 
3119
3156
  // Create a Sequence signer too
3120
3157
  this.signer = new SequenceSigner(this.client, this);
@@ -3238,7 +3275,7 @@ class SequenceProvider extends ethers.ethers.providers.BaseProvider {
3238
3275
  var _provider$prepareRequ;
3239
3276
  // First we check if the method should be handled by the client
3240
3277
  if (method === 'eth_chainId') {
3241
- return this.useChainId();
3278
+ return `0x${(await this.useChainId()).toString(16)}`;
3242
3279
  }
3243
3280
  if (method === 'eth_accounts') {
3244
3281
  return [this.client.getAddress()];
@@ -3549,31 +3586,48 @@ class SequenceClient {
3549
3586
  this.session = new SequenceClientSession(store);
3550
3587
  this.defaultChainId = new DefaultChainIdTracker(store, defaultChainId);
3551
3588
  this.transport.on('accountsChanged', accounts => {
3552
- var _this$callbacks$onAcc;
3589
+ var _this$callbacks$accou;
3553
3590
  if (accounts.length > 1) {
3554
3591
  console.warn('SequenceClient: wallet-webapp returned more than one account');
3555
3592
  }
3556
- (_this$callbacks$onAcc = this.callbacks.onAccountsChanged) == null ? void 0 : _this$callbacks$onAcc.forEach(cb => cb(accounts));
3593
+ (_this$callbacks$accou = this.callbacks.accountsChanged) == null ? void 0 : _this$callbacks$accou.forEach(cb => cb(accounts));
3594
+ });
3595
+ this.transport.on('connect', response => {
3596
+ var _this$callbacks$conne;
3597
+ const chainIdHex = ethers.ethers.BigNumber.from(this.getChainId()).toHexString();
3598
+ (_this$callbacks$conne = this.callbacks.connect) == null ? void 0 : _this$callbacks$conne.forEach(cb => cb(_extends({}, response, {
3599
+ // Ignore the full connect response
3600
+ // use the chainId defined locally
3601
+ chainId: chainIdHex
3602
+ })));
3603
+ });
3604
+ this.transport.on('disconnect', error => {
3605
+ var _this$callbacks$disco;
3606
+ (_this$callbacks$disco = this.callbacks.disconnect) == null ? void 0 : _this$callbacks$disco.forEach(cb => cb(error));
3557
3607
  });
3558
3608
  this.transport.on('networks', networks => {
3559
- var _this$callbacks$onNet;
3560
- (_this$callbacks$onNet = this.callbacks.onNetworks) == null ? void 0 : _this$callbacks$onNet.forEach(cb => cb(networks));
3609
+ var _this$callbacks$netwo;
3610
+ (_this$callbacks$netwo = this.callbacks.networks) == null ? void 0 : _this$callbacks$netwo.forEach(cb => cb(networks));
3561
3611
  });
3562
3612
  this.transport.on('walletContext', context => {
3563
- var _this$callbacks$onWal;
3564
- (_this$callbacks$onWal = this.callbacks.onWalletContext) == null ? void 0 : _this$callbacks$onWal.forEach(cb => cb(context));
3613
+ var _this$callbacks$walle;
3614
+ (_this$callbacks$walle = this.callbacks.walletContext) == null ? void 0 : _this$callbacks$walle.forEach(cb => cb(context));
3565
3615
  });
3566
- this.transport.on('open', () => {
3567
- var _this$callbacks$onOpe;
3568
- (_this$callbacks$onOpe = this.callbacks.onOpen) == null ? void 0 : _this$callbacks$onOpe.forEach(cb => cb());
3616
+ this.transport.on('open', info => {
3617
+ var _this$callbacks$open;
3618
+ (_this$callbacks$open = this.callbacks.open) == null ? void 0 : _this$callbacks$open.forEach(cb => cb(info));
3569
3619
  });
3570
3620
  this.transport.on('close', () => {
3571
- var _this$callbacks$onClo;
3572
- (_this$callbacks$onClo = this.callbacks.onClose) == null ? void 0 : _this$callbacks$onClo.forEach(cb => cb());
3621
+ var _this$callbacks$close;
3622
+ (_this$callbacks$close = this.callbacks.close) == null ? void 0 : _this$callbacks$close.forEach(cb => cb());
3573
3623
  });
3624
+
3625
+ // We don't listen for the transport chainChanged event
3626
+ // instead we handle it locally, so we listen for changes in the store
3574
3627
  this.defaultChainId.onDefaultChainIdChanged(chainId => {
3575
- var _this$callbacks$onDef;
3576
- (_this$callbacks$onDef = this.callbacks.onDefaultChainIdChanged) == null ? void 0 : _this$callbacks$onDef.forEach(cb => cb(chainId));
3628
+ var _this$callbacks$chain;
3629
+ const chainIdHex = ethers.ethers.BigNumber.from(chainId).toHexString();
3630
+ (_this$callbacks$chain = this.callbacks.chainChanged) == null ? void 0 : _this$callbacks$chain.forEach(cb => cb(chainIdHex));
3577
3631
  });
3578
3632
  }
3579
3633
 
@@ -3592,24 +3646,30 @@ class SequenceClient {
3592
3646
  // Individual callbacks lead to more idiomatic code
3593
3647
 
3594
3648
  onOpen(callback) {
3595
- return this.registerCallback('onOpen', callback);
3649
+ return this.registerCallback('open', callback);
3596
3650
  }
3597
3651
  onClose(callback) {
3598
- return this.registerCallback('onClose', callback);
3652
+ return this.registerCallback('close', callback);
3653
+ }
3654
+ onConnect(callback) {
3655
+ return this.registerCallback('connect', callback);
3656
+ }
3657
+ onDisconnect(callback) {
3658
+ return this.registerCallback('disconnect', callback);
3599
3659
  }
3600
3660
  onNetworks(callback) {
3601
- return this.registerCallback('onNetworks', callback);
3661
+ return this.registerCallback('networks', callback);
3602
3662
  }
3603
3663
  onAccountsChanged(callback) {
3604
- return this.registerCallback('onAccountsChanged', callback);
3664
+ return this.registerCallback('accountsChanged', callback);
3605
3665
  }
3606
3666
 
3607
3667
  // @deprecated
3608
3668
  onWalletContext(callback) {
3609
- return this.registerCallback('onWalletContext', callback);
3669
+ return this.registerCallback('walletContext', callback);
3610
3670
  }
3611
3671
  onDefaultChainIdChanged(callback) {
3612
- return this.registerCallback('onDefaultChainIdChanged', callback);
3672
+ return this.registerCallback('chainChanged', callback);
3613
3673
  }
3614
3674
  getChainId() {
3615
3675
  return this.defaultChainId.getDefaultChainId();
@@ -2103,6 +2103,25 @@ function fromExtended(transaction) {
2103
2103
  return [transaction, ...(transaction.auxiliary || [])];
2104
2104
  }
2105
2105
 
2106
+ function validateTransactionRequest(wallet, transaction) {
2107
+ const transactions = commons.transaction.fromTransactionish(wallet, transaction);
2108
+ const unwound = commons.transaction.unwind(wallet, transactions);
2109
+ unwound.forEach(transaction => validateTransaction(wallet, transaction));
2110
+ }
2111
+ function validateTransaction(wallet, transaction) {
2112
+ if (transaction.to.toLowerCase() === wallet.toLowerCase()) {
2113
+ if (transaction.data) {
2114
+ const data = ethers.utils.arrayify(transaction.data);
2115
+ if (data.length >= 4) {
2116
+ throw new Error('self calls are forbidden');
2117
+ }
2118
+ }
2119
+ }
2120
+ if (transaction.delegateCall) {
2121
+ throw new Error('delegate calls are forbidden');
2122
+ }
2123
+ }
2124
+
2106
2125
  const SIGNER_READY_TIMEOUT = 10000;
2107
2126
  class WalletRequestHandler {
2108
2127
  constructor(_account, prompter, networks) {
@@ -2293,6 +2312,7 @@ class WalletRequestHandler {
2293
2312
  }
2294
2313
  return tx;
2295
2314
  });
2315
+ validateTransactionRequest(account.address, transactionParams);
2296
2316
  let txnHash = '';
2297
2317
  if (_this.prompter === null) {
2298
2318
  // prompter is null, so we'll send from here
@@ -2318,6 +2338,7 @@ class WalletRequestHandler {
2318
2338
  if (sender !== account.address) {
2319
2339
  throw new Error('sender address does not match wallet');
2320
2340
  }
2341
+ validateTransactionRequest(account.address, transaction);
2321
2342
  if (_this.prompter === null) {
2322
2343
  // The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
2323
2344
  // this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.
@@ -3097,20 +3118,36 @@ class WalletUtils {
3097
3118
 
3098
3119
  class SequenceProvider extends ethers.providers.BaseProvider {
3099
3120
  constructor(client, providerFor, networks = allNetworks) {
3100
- var _this;
3101
3121
  // We support a lot of networks
3102
3122
  // but we start with the default one
3103
3123
  super(client.getChainId());
3104
- _this = this;
3124
+
3125
+ // Emit events as defined by EIP-1193
3105
3126
  this.singleNetworkProviders = {};
3106
3127
  this._isSequenceProvider = true;
3107
3128
  this.client = client;
3108
3129
  this.providerFor = providerFor;
3109
3130
  this.networks = networks;
3110
- client.onDefaultChainIdChanged(async function (chainId) {
3111
- // TODO: Maybe we should emit more events here
3112
- _this.emit('chainChanged', chainId);
3131
+ client.onConnect(details => {
3132
+ this.emit('connect', details);
3113
3133
  });
3134
+ client.onDisconnect(error => {
3135
+ this.emit('disconnect', error);
3136
+ });
3137
+ client.onDefaultChainIdChanged(chainId => {
3138
+ this.emit('chainChanged', chainId);
3139
+ });
3140
+ client.onAccountsChanged(accounts => {
3141
+ this.emit('accountsChanged', accounts);
3142
+ });
3143
+
3144
+ // NOTICE: We don't emit 'open' and 'close' events
3145
+ // because these are handled by the library, and they
3146
+ // are not part of EIP-1193
3147
+
3148
+ // devs can still access them using
3149
+ // client.onOpen()
3150
+ // client.onClose()
3114
3151
 
3115
3152
  // Create a Sequence signer too
3116
3153
  this.signer = new SequenceSigner(this.client, this);
@@ -3234,7 +3271,7 @@ class SequenceProvider extends ethers.providers.BaseProvider {
3234
3271
  var _provider$prepareRequ;
3235
3272
  // First we check if the method should be handled by the client
3236
3273
  if (method === 'eth_chainId') {
3237
- return this.useChainId();
3274
+ return `0x${(await this.useChainId()).toString(16)}`;
3238
3275
  }
3239
3276
  if (method === 'eth_accounts') {
3240
3277
  return [this.client.getAddress()];
@@ -3545,31 +3582,48 @@ class SequenceClient {
3545
3582
  this.session = new SequenceClientSession(store);
3546
3583
  this.defaultChainId = new DefaultChainIdTracker(store, defaultChainId);
3547
3584
  this.transport.on('accountsChanged', accounts => {
3548
- var _this$callbacks$onAcc;
3585
+ var _this$callbacks$accou;
3549
3586
  if (accounts.length > 1) {
3550
3587
  console.warn('SequenceClient: wallet-webapp returned more than one account');
3551
3588
  }
3552
- (_this$callbacks$onAcc = this.callbacks.onAccountsChanged) == null ? void 0 : _this$callbacks$onAcc.forEach(cb => cb(accounts));
3589
+ (_this$callbacks$accou = this.callbacks.accountsChanged) == null ? void 0 : _this$callbacks$accou.forEach(cb => cb(accounts));
3590
+ });
3591
+ this.transport.on('connect', response => {
3592
+ var _this$callbacks$conne;
3593
+ const chainIdHex = ethers.BigNumber.from(this.getChainId()).toHexString();
3594
+ (_this$callbacks$conne = this.callbacks.connect) == null ? void 0 : _this$callbacks$conne.forEach(cb => cb(_extends({}, response, {
3595
+ // Ignore the full connect response
3596
+ // use the chainId defined locally
3597
+ chainId: chainIdHex
3598
+ })));
3599
+ });
3600
+ this.transport.on('disconnect', error => {
3601
+ var _this$callbacks$disco;
3602
+ (_this$callbacks$disco = this.callbacks.disconnect) == null ? void 0 : _this$callbacks$disco.forEach(cb => cb(error));
3553
3603
  });
3554
3604
  this.transport.on('networks', networks => {
3555
- var _this$callbacks$onNet;
3556
- (_this$callbacks$onNet = this.callbacks.onNetworks) == null ? void 0 : _this$callbacks$onNet.forEach(cb => cb(networks));
3605
+ var _this$callbacks$netwo;
3606
+ (_this$callbacks$netwo = this.callbacks.networks) == null ? void 0 : _this$callbacks$netwo.forEach(cb => cb(networks));
3557
3607
  });
3558
3608
  this.transport.on('walletContext', context => {
3559
- var _this$callbacks$onWal;
3560
- (_this$callbacks$onWal = this.callbacks.onWalletContext) == null ? void 0 : _this$callbacks$onWal.forEach(cb => cb(context));
3609
+ var _this$callbacks$walle;
3610
+ (_this$callbacks$walle = this.callbacks.walletContext) == null ? void 0 : _this$callbacks$walle.forEach(cb => cb(context));
3561
3611
  });
3562
- this.transport.on('open', () => {
3563
- var _this$callbacks$onOpe;
3564
- (_this$callbacks$onOpe = this.callbacks.onOpen) == null ? void 0 : _this$callbacks$onOpe.forEach(cb => cb());
3612
+ this.transport.on('open', info => {
3613
+ var _this$callbacks$open;
3614
+ (_this$callbacks$open = this.callbacks.open) == null ? void 0 : _this$callbacks$open.forEach(cb => cb(info));
3565
3615
  });
3566
3616
  this.transport.on('close', () => {
3567
- var _this$callbacks$onClo;
3568
- (_this$callbacks$onClo = this.callbacks.onClose) == null ? void 0 : _this$callbacks$onClo.forEach(cb => cb());
3617
+ var _this$callbacks$close;
3618
+ (_this$callbacks$close = this.callbacks.close) == null ? void 0 : _this$callbacks$close.forEach(cb => cb());
3569
3619
  });
3620
+
3621
+ // We don't listen for the transport chainChanged event
3622
+ // instead we handle it locally, so we listen for changes in the store
3570
3623
  this.defaultChainId.onDefaultChainIdChanged(chainId => {
3571
- var _this$callbacks$onDef;
3572
- (_this$callbacks$onDef = this.callbacks.onDefaultChainIdChanged) == null ? void 0 : _this$callbacks$onDef.forEach(cb => cb(chainId));
3624
+ var _this$callbacks$chain;
3625
+ const chainIdHex = ethers.BigNumber.from(chainId).toHexString();
3626
+ (_this$callbacks$chain = this.callbacks.chainChanged) == null ? void 0 : _this$callbacks$chain.forEach(cb => cb(chainIdHex));
3573
3627
  });
3574
3628
  }
3575
3629
 
@@ -3588,24 +3642,30 @@ class SequenceClient {
3588
3642
  // Individual callbacks lead to more idiomatic code
3589
3643
 
3590
3644
  onOpen(callback) {
3591
- return this.registerCallback('onOpen', callback);
3645
+ return this.registerCallback('open', callback);
3592
3646
  }
3593
3647
  onClose(callback) {
3594
- return this.registerCallback('onClose', callback);
3648
+ return this.registerCallback('close', callback);
3649
+ }
3650
+ onConnect(callback) {
3651
+ return this.registerCallback('connect', callback);
3652
+ }
3653
+ onDisconnect(callback) {
3654
+ return this.registerCallback('disconnect', callback);
3595
3655
  }
3596
3656
  onNetworks(callback) {
3597
- return this.registerCallback('onNetworks', callback);
3657
+ return this.registerCallback('networks', callback);
3598
3658
  }
3599
3659
  onAccountsChanged(callback) {
3600
- return this.registerCallback('onAccountsChanged', callback);
3660
+ return this.registerCallback('accountsChanged', callback);
3601
3661
  }
3602
3662
 
3603
3663
  // @deprecated
3604
3664
  onWalletContext(callback) {
3605
- return this.registerCallback('onWalletContext', callback);
3665
+ return this.registerCallback('walletContext', callback);
3606
3666
  }
3607
3667
  onDefaultChainIdChanged(callback) {
3608
- return this.registerCallback('onDefaultChainIdChanged', callback);
3668
+ return this.registerCallback('chainChanged', callback);
3609
3669
  }
3610
3670
  getChainId() {
3611
3671
  return this.defaultChainId.getDefaultChainId();
@@ -1,16 +1,8 @@
1
1
  import { JsonRpcRequest, NetworkConfig } from "@0xsequence/network";
2
- import { ConnectDetails, ConnectOptions, ItemStore, MuxTransportTemplate, OpenWalletIntent, OptionalChainId, OptionalEIP6492, ProviderTransport, WalletSession } from "./index.js";
2
+ import { ConnectDetails, ConnectOptions, ItemStore, MuxTransportTemplate, OpenWalletIntent, OptionalChainId, OptionalEIP6492, ProviderTransport, WalletEventTypes, WalletSession } from "./index.js";
3
3
  import { commons } from "@0xsequence/core";
4
4
  import { TypedData } from "@0xsequence/utils";
5
5
  import { ethers } from "ethers";
6
- type Callbacks = {
7
- onOpen: () => void;
8
- onClose: () => void;
9
- onNetworks: (networks: NetworkConfig[]) => void;
10
- onAccountsChanged: (accounts: string[]) => void;
11
- onWalletContext: (context: commons.context.VersionedContext) => void;
12
- onDefaultChainIdChanged: (chainId: number) => void;
13
- };
14
6
  /**
15
7
  * This session class is meant to persist the state of the wallet connection
16
8
  * whitin the dapp. This enables the client to retain the wallet address (and some more)
@@ -53,13 +45,15 @@ export declare class SequenceClient {
53
45
  private readonly callbacks;
54
46
  readonly transport: ProviderTransport;
55
47
  constructor(transport: ProviderTransport | MuxTransportTemplate, store: ItemStore, defaultChainId?: number);
56
- registerCallback<K extends keyof Callbacks>(eventName: K, callback: Callbacks[K]): () => void;
57
- onOpen(callback: Callbacks['onOpen']): () => void;
58
- onClose(callback: Callbacks['onClose']): () => void;
59
- onNetworks(callback: Callbacks['onNetworks']): () => void;
60
- onAccountsChanged(callback: Callbacks['onAccountsChanged']): () => void;
61
- onWalletContext(callback: Callbacks['onWalletContext']): () => void;
62
- onDefaultChainIdChanged(callback: (chainId: number) => void): () => void;
48
+ registerCallback<K extends keyof WalletEventTypes>(eventName: K, callback: WalletEventTypes[K]): () => void;
49
+ onOpen(callback: WalletEventTypes['open']): () => void;
50
+ onClose(callback: WalletEventTypes['close']): () => void;
51
+ onConnect(callback: WalletEventTypes['connect']): () => void;
52
+ onDisconnect(callback: WalletEventTypes['disconnect']): () => void;
53
+ onNetworks(callback: WalletEventTypes['networks']): () => void;
54
+ onAccountsChanged(callback: WalletEventTypes['accountsChanged']): () => void;
55
+ onWalletContext(callback: WalletEventTypes['walletContext']): () => void;
56
+ onDefaultChainIdChanged(callback: WalletEventTypes['chainChanged']): () => void;
63
57
  getChainId(): number;
64
58
  setDefaultChainId(chainId: number): void;
65
59
  openWallet(path?: string, intent?: OpenWalletIntent): Promise<boolean>;
@@ -78,4 +72,3 @@ export declare class SequenceClient {
78
72
  getWalletContext(): Promise<commons.context.VersionedContext>;
79
73
  getOnchainWalletConfig(options?: OptionalChainId): Promise<commons.config.Config>;
80
74
  }
81
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xsequence/provider",
3
- "version": "0.0.0-20230726193528",
3
+ "version": "0.0.0-20230801185244",
4
4
  "description": "provider sub-package for Sequence",
5
5
  "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/provider",
6
6
  "source": "src/index.ts",
@@ -11,15 +11,15 @@
11
11
  "dependencies": {
12
12
  "eventemitter2": "^6.4.5",
13
13
  "webextension-polyfill": "^0.10.0",
14
- "@0xsequence/abi": "0.0.0-20230726193528",
15
- "@0xsequence/account": "0.0.0-20230726193528",
16
- "@0xsequence/migration": "0.0.0-20230726193528",
17
- "@0xsequence/auth": "0.0.0-20230726193528",
18
- "@0xsequence/core": "0.0.0-20230726193528",
19
- "@0xsequence/network": "0.0.0-20230726193528",
20
- "@0xsequence/relayer": "0.0.0-20230726193528",
21
- "@0xsequence/utils": "0.0.0-20230726193528",
22
- "@0xsequence/wallet": "0.0.0-20230726193528"
14
+ "@0xsequence/account": "0.0.0-20230801185244",
15
+ "@0xsequence/abi": "0.0.0-20230801185244",
16
+ "@0xsequence/core": "0.0.0-20230801185244",
17
+ "@0xsequence/auth": "0.0.0-20230801185244",
18
+ "@0xsequence/migration": "0.0.0-20230801185244",
19
+ "@0xsequence/network": "0.0.0-20230801185244",
20
+ "@0xsequence/relayer": "0.0.0-20230801185244",
21
+ "@0xsequence/utils": "0.0.0-20230801185244",
22
+ "@0xsequence/wallet": "0.0.0-20230801185244"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "ethers": ">=5.5 < 6"
package/src/client.ts CHANGED
@@ -1,18 +1,10 @@
1
1
  import { JsonRpcRequest, JsonRpcResponse, NetworkConfig } from "@0xsequence/network"
2
- import { ConnectDetails, ConnectOptions, ItemStore, MuxMessageProvider, MuxTransportTemplate, OpenWalletIntent, OptionalChainId, OptionalEIP6492, ProviderTransport, WalletSession, isMuxTransportTemplate, isProviderTransport } from "."
2
+ import { ConnectDetails, ConnectOptions, ItemStore, MuxMessageProvider, MuxTransportTemplate, OpenWalletIntent, OptionalChainId, OptionalEIP6492, ProviderTransport, WalletEventTypes, WalletSession, isMuxTransportTemplate, isProviderTransport } from "."
3
3
  import { commons } from "@0xsequence/core"
4
4
  import { TypedData } from "@0xsequence/utils"
5
5
  import { toExtended } from "./extended"
6
6
  import { ethers } from "ethers"
7
7
 
8
- type Callbacks = {
9
- onOpen: () => void
10
- onClose: () => void
11
- onNetworks: (networks: NetworkConfig[]) => void
12
- onAccountsChanged: (accounts: string[]) => void
13
- onWalletContext: (context: commons.context.VersionedContext) => void
14
- onDefaultChainIdChanged: (chainId: number) => void
15
- }
16
8
 
17
9
  /**
18
10
  * This session class is meant to persist the state of the wallet connection
@@ -123,7 +115,7 @@ export class DefaultChainIdTracker {
123
115
  export class SequenceClient {
124
116
  private readonly session: SequenceClientSession
125
117
  private readonly defaultChainId: DefaultChainIdTracker
126
- private readonly callbacks: { [K in keyof Callbacks]?: Callbacks[K][] } = {}
118
+ private readonly callbacks: { [K in keyof WalletEventTypes]?: WalletEventTypes[K][] } = {}
127
119
 
128
120
  public readonly transport: ProviderTransport
129
121
 
@@ -148,33 +140,50 @@ export class SequenceClient {
148
140
  console.warn('SequenceClient: wallet-webapp returned more than one account')
149
141
  }
150
142
 
151
- this.callbacks.onAccountsChanged?.forEach(cb => cb(accounts))
143
+ this.callbacks.accountsChanged?.forEach(cb => cb(accounts))
144
+ })
145
+
146
+ this.transport.on('connect', (response: ConnectDetails) => {
147
+ const chainIdHex = ethers.BigNumber.from(this.getChainId()).toHexString()
148
+ this.callbacks.connect?.forEach(cb => cb({
149
+ ...response,
150
+ // Ignore the full connect response
151
+ // use the chainId defined locally
152
+ chainId: chainIdHex
153
+ }))
154
+ })
155
+
156
+ this.transport.on('disconnect', (error) => {
157
+ this.callbacks.disconnect?.forEach(cb => cb(error))
152
158
  })
153
159
 
154
- this.transport.on('networks', (networks: NetworkConfig[]) => {
155
- this.callbacks.onNetworks?.forEach(cb => cb(networks))
160
+ this.transport.on('networks', (networks) => {
161
+ this.callbacks.networks?.forEach(cb => cb(networks))
156
162
  })
157
163
 
158
- this.transport.on('walletContext', (context: commons.context.VersionedContext) => {
159
- this.callbacks.onWalletContext?.forEach(cb => cb(context))
164
+ this.transport.on('walletContext', (context) => {
165
+ this.callbacks.walletContext?.forEach(cb => cb(context))
160
166
  })
161
167
 
162
- this.transport.on('open', () => {
163
- this.callbacks.onOpen?.forEach(cb => cb())
168
+ this.transport.on('open', (info) => {
169
+ this.callbacks.open?.forEach(cb => cb(info))
164
170
  })
165
171
 
166
172
  this.transport.on('close', () => {
167
- this.callbacks.onClose?.forEach(cb => cb())
173
+ this.callbacks.close?.forEach(cb => cb())
168
174
  })
169
175
 
176
+ // We don't listen for the transport chainChanged event
177
+ // instead we handle it locally, so we listen for changes in the store
170
178
  this.defaultChainId.onDefaultChainIdChanged((chainId: number) => {
171
- this.callbacks.onDefaultChainIdChanged?.forEach(cb => cb(chainId))
179
+ const chainIdHex = ethers.BigNumber.from(chainId).toHexString()
180
+ this.callbacks.chainChanged?.forEach(cb => cb(chainIdHex))
172
181
  })
173
182
  }
174
183
 
175
184
  // Callbacks
176
185
 
177
- registerCallback<K extends keyof Callbacks>(eventName: K, callback: Callbacks[K]) {
186
+ registerCallback<K extends keyof WalletEventTypes>(eventName: K, callback: WalletEventTypes[K]) {
178
187
  if (!this.callbacks[eventName]) {
179
188
  this.callbacks[eventName] = []
180
189
  }
@@ -188,29 +197,37 @@ export class SequenceClient {
188
197
 
189
198
  // Individual callbacks lead to more idiomatic code
190
199
 
191
- onOpen(callback: Callbacks['onOpen']) {
192
- return this.registerCallback('onOpen', callback)
200
+ onOpen(callback: WalletEventTypes['open']) {
201
+ return this.registerCallback('open', callback)
193
202
  }
194
203
 
195
- onClose(callback: Callbacks['onClose']) {
196
- return this.registerCallback('onClose', callback)
204
+ onClose(callback: WalletEventTypes['close']) {
205
+ return this.registerCallback('close', callback)
206
+ }
207
+
208
+ onConnect(callback: WalletEventTypes['connect']) {
209
+ return this.registerCallback('connect', callback)
210
+ }
211
+
212
+ onDisconnect(callback: WalletEventTypes['disconnect']) {
213
+ return this.registerCallback('disconnect', callback)
197
214
  }
198
215
 
199
- onNetworks(callback: Callbacks['onNetworks']) {
200
- return this.registerCallback('onNetworks', callback)
216
+ onNetworks(callback: WalletEventTypes['networks']) {
217
+ return this.registerCallback('networks', callback)
201
218
  }
202
219
 
203
- onAccountsChanged(callback: Callbacks['onAccountsChanged']) {
204
- return this.registerCallback('onAccountsChanged', callback)
220
+ onAccountsChanged(callback: WalletEventTypes['accountsChanged']) {
221
+ return this.registerCallback('accountsChanged', callback)
205
222
  }
206
223
 
207
224
  // @deprecated
208
- onWalletContext(callback: Callbacks['onWalletContext']) {
209
- return this.registerCallback('onWalletContext', callback)
225
+ onWalletContext(callback: WalletEventTypes['walletContext']) {
226
+ return this.registerCallback('walletContext', callback)
210
227
  }
211
228
 
212
- onDefaultChainIdChanged(callback: (chainId: number) => void) {
213
- return this.registerCallback('onDefaultChainIdChanged', callback)
229
+ onDefaultChainIdChanged(callback: WalletEventTypes['chainChanged']) {
230
+ return this.registerCallback('chainChanged', callback)
214
231
  }
215
232
 
216
233
  getChainId(): number {
package/src/provider.ts CHANGED
@@ -63,11 +63,32 @@ export class SequenceProvider extends ethers.providers.BaseProvider implements I
63
63
  // We support a lot of networks
64
64
  // but we start with the default one
65
65
  super(client.getChainId())
66
- client.onDefaultChainIdChanged(async (chainId) => {
67
- // TODO: Maybe we should emit more events here
66
+
67
+ // Emit events as defined by EIP-1193
68
+ client.onConnect((details) => {
69
+ this.emit('connect', details)
70
+ })
71
+
72
+ client.onDisconnect((error) => {
73
+ this.emit('disconnect', error)
74
+ })
75
+
76
+ client.onDefaultChainIdChanged((chainId) => {
68
77
  this.emit('chainChanged', chainId)
69
78
  })
70
79
 
80
+ client.onAccountsChanged((accounts) => {
81
+ this.emit('accountsChanged', accounts)
82
+ })
83
+
84
+ // NOTICE: We don't emit 'open' and 'close' events
85
+ // because these are handled by the library, and they
86
+ // are not part of EIP-1193
87
+
88
+ // devs can still access them using
89
+ // client.onOpen()
90
+ // client.onClose()
91
+
71
92
  // Create a Sequence signer too
72
93
  this.signer = new SequenceSigner(this.client, this)
73
94
 
@@ -226,7 +247,7 @@ export class SequenceProvider extends ethers.providers.BaseProvider implements I
226
247
  async perform(method: string, params: any): Promise<any> {
227
248
  // First we check if the method should be handled by the client
228
249
  if (method === 'eth_chainId') {
229
- return this.useChainId()
250
+ return `0x${(await this.useChainId()).toString(16)}`
230
251
  }
231
252
 
232
253
  if (method === 'eth_accounts') {
@@ -0,0 +1,23 @@
1
+ import { commons } from '@0xsequence/core'
2
+ import { ethers } from 'ethers'
3
+
4
+ export function validateTransactionRequest(wallet: string, transaction: commons.transaction.Transactionish) {
5
+ const transactions = commons.transaction.fromTransactionish(wallet, transaction)
6
+ const unwound = commons.transaction.unwind(wallet, transactions)
7
+ unwound.forEach(transaction => validateTransaction(wallet, transaction))
8
+ }
9
+
10
+ function validateTransaction(wallet: string, transaction: commons.transaction.Transaction) {
11
+ if (transaction.to.toLowerCase() === wallet.toLowerCase()) {
12
+ if (transaction.data) {
13
+ const data = ethers.utils.arrayify(transaction.data)
14
+ if (data.length >= 4) {
15
+ throw new Error('self calls are forbidden')
16
+ }
17
+ }
18
+ }
19
+
20
+ if (transaction.delegateCall) {
21
+ throw new Error('delegate calls are forbidden')
22
+ }
23
+ }
@@ -7,6 +7,7 @@ import { BigNumber, ethers, providers } from 'ethers'
7
7
  import { EventEmitter2 as EventEmitter } from 'eventemitter2'
8
8
 
9
9
  import { fromExtended } from '../extended'
10
+ import { validateTransactionRequest } from '../transactions'
10
11
  import {
11
12
  ProviderMessageRequest,
12
13
  ProviderMessageResponse,
@@ -393,6 +394,8 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P
393
394
  return tx
394
395
  })
395
396
 
397
+ validateTransactionRequest(account.address, transactionParams)
398
+
396
399
  let txnHash = ''
397
400
  if (this.prompter === null) {
398
401
  // prompter is null, so we'll send from here
@@ -421,6 +424,8 @@ export class WalletRequestHandler implements ExternalProvider, JsonRpcHandler, P
421
424
  throw new Error('sender address does not match wallet')
422
425
  }
423
426
 
427
+ validateTransactionRequest(account.address, transaction)
428
+
424
429
  if (this.prompter === null) {
425
430
  // The eth_signTransaction method expects a `string` return value we instead return a `SignedTransactions` object,
426
431
  // this can only be broadcasted using an RPC provider with support for signed Sequence transactions, like this one.