Skip to content

Commit 7d3d2b5

Browse files
authored
Merge pull request #12 from sh3nk/ethers-adapter-update
Ethers adapter update + some fixes
2 parents eee8c3f + 445c371 commit 7d3d2b5

File tree

16 files changed

+216
-47
lines changed

16 files changed

+216
-47
lines changed

apps/js-test/src/ethers5.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ async function start() {
77
// Wait for wallet SDK and account to initialize
88
await new Promise<void>(resolve => {
99
const clear = setInterval(() => {
10-
if (window.embeddedWallet && !!window.embeddedWallet.lastAccount.address) {
10+
if (window.embeddedWallet && !!window.embeddedWallet.lastAccount.contractAddress) {
1111
clearInterval(clear);
1212
resolve();
1313
}

apps/js-test/src/ethers6.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ async function start() {
77
// Wait for wallet SDK and account to initialize
88
await new Promise<void>(resolve => {
99
const clear = setInterval(() => {
10-
if (window.embeddedWallet && !!window.embeddedWallet.lastAccount.address) {
10+
if (window.embeddedWallet && !!window.embeddedWallet.lastAccount.contractAddress) {
1111
clearInterval(clear);
1212
resolve();
1313
}

apps/js-test/src/viem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ async function start() {
1515
// Wait for wallet SDK and account to initialize
1616
await new Promise<void>(resolve => {
1717
const clear = setInterval(() => {
18-
if (window.embeddedWallet && !!window.embeddedWallet.lastAccount.address) {
18+
if (window.embeddedWallet && !!window.embeddedWallet.lastAccount.contractAddress) {
1919
clearInterval(clear);
2020
resolve();
2121
}

apps/vue-test/src/TestSdk.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ async function transferNativeBalance() {
2828
const res = await sendTransaction({
2929
to: '0x700cebAA997ecAd7B0797f8f359C621604Cce6Bf',
3030
value: '10000000',
31-
chainId: 1287,
31+
// chainId: 1287,
3232
});
3333
console.log(res);
3434
}

packages/gateway/src/contexts/global.context.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ function GlobalProvider({ children }: { children: ReactNode }) {
3333
const urlParams = new URLSearchParams(window.location.search);
3434

3535
if (!wallet) {
36-
setWallet(
37-
EmbeddedWalletSDK({ clientId: urlParams.get('clientId') || '', noPasskeyIframe: true })
38-
);
36+
setWallet(EmbeddedWalletSDK({ clientId: urlParams.get('clientId') || '' }));
3937
}
4038

4139
const referrer = urlParams.get('ref');

packages/sdk/README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Embedded App Wallet
22

3-
Apillon Embedded Wallet JS SDK
3+
Apillon Embedded Wallet JS SDK.
4+
5+
More info can be found [in the Apillon wiki](https://wiki.apillon.io/build/12-embedded-wallets-integration.html).
46

57
## Stack
68

@@ -34,6 +36,11 @@ defaultNetworkId?: number;
3436
* Configuration of available networks. Oasis Sapphire is always included (ids 23294 and 23295)
3537
*/
3638
networks?: Network[];
39+
40+
/**
41+
* Method for authenticating with passkey to make it global.
42+
*/
43+
passkeyAuthMode: 'redirect' | 'popup' | 'tab_process' | 'tab_form' = 'redirect';
3744
```
3845

3946
The class instance is then available on window (`embeddedWallet`) and can be obtained with the `getEmbeddedWallet()` utility.
@@ -85,6 +92,18 @@ wallet.events.on('txSubmitted', tx => {
8592

8693
- `getAccountBalance`
8794

95+
- `getAccountPrivateKey`
96+
97+
### Wallet accounts methods
98+
99+
- `getAccountWallets`
100+
Get all wallets added on user's account. Requires authentication.
101+
102+
- `addAccountWallet`
103+
Add new wallet or import from privateKey.
104+
105+
- `updateAccountWalletTitle`
106+
88107
### Transaction methods
89108

90109
- `signMessage`
@@ -96,13 +115,21 @@ wallet.events.on('txSubmitted', tx => {
96115
Send raw transaction data to network.
97116
If chainId is provided, the transaction is sent to that network (cross-chain).
98117

118+
- `submitTransaction`
119+
Prepare transaction and emit `txSubmitted` event (to show tx in tx history in UI e.g.).
120+
To be used after sending transaction through anything else than `broadcastTransaction`.
121+
Doesn't do anything by itself, just for logging/parsing transactions.
122+
99123
- `signContractWrite`
100124
Get signed tx for making a contract write call.
101125

102126
- `contractRead`
103127
Get result of contract read.
104128
Utility function, this has nothing to do with Oasis.
105129

130+
- `processGaslessMethod`
131+
Call a contract method with a gasless transaction (app owner pays for the transaction fees instead of user).
132+
106133
### mustConfirm
107134

108135
This parameter can be used for wallet actions that require user confirmation. If set to `true`, the event `signatureRequest`/`txApprove` will be emitted with `resolve()` method passed in payload. Once resolve is called, the action continues. This can be used to display tx confirmation UI e.g.

packages/sdk/lib/adapters/ethers.ts

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import { abort, getEmbeddedWallet } from '../utils';
33
import EmbeddedWallet from '..';
44

55
class EmbeddedEthersSigner extends ethers.AbstractSigner<ethers.JsonRpcProvider> {
6-
address = '';
76
wallet: EmbeddedWallet;
8-
// override provider: ethers.JsonRpcProvider;
7+
internalSigner: InternalEmbeddedEthersSignerextends;
98

109
constructor(provider?: ethers.JsonRpcProvider) {
1110
const w = getEmbeddedWallet();
@@ -16,8 +15,94 @@ class EmbeddedEthersSigner extends ethers.AbstractSigner<ethers.JsonRpcProvider>
1615

1716
super(provider || w.getRpcProviderForChainId(w.defaultNetworkId));
1817

18+
this.internalSigner = new InternalEmbeddedEthersSignerextends(
19+
provider || w.getRpcProviderForChainId(w.defaultNetworkId),
20+
w
21+
);
22+
1923
this.wallet = w!;
20-
// this.provider = provider;
24+
25+
/**
26+
* Reinitialize signer with new provider when chain changes
27+
*/
28+
w.events.on('dataUpdated', ({ name, newValue }) => {
29+
if (name === 'defaultNetworkId') {
30+
this.internalSigner = new InternalEmbeddedEthersSignerextends(
31+
w.getRpcProviderForChainId(newValue),
32+
this.wallet
33+
);
34+
}
35+
});
36+
}
37+
38+
override connect(): ethers.Signer {
39+
return this.internalSigner;
40+
}
41+
42+
override async getAddress(): Promise<string> {
43+
const a = await this.wallet.getAccountAddress();
44+
return a || '';
45+
}
46+
47+
override async signTransaction(
48+
tx: ethers.TransactionRequest,
49+
mustConfirm = true
50+
): Promise<string> {
51+
return this.internalSigner.signTransaction(tx, mustConfirm);
52+
}
53+
54+
override async signMessage(message: string | Uint8Array, mustConfirm = true): Promise<string> {
55+
return this.internalSigner.signMessage(message, mustConfirm);
56+
}
57+
58+
override async sendTransaction(
59+
tx: ethers.TransactionRequest
60+
): Promise<ethers.TransactionResponse> {
61+
return this.internalSigner.sendTransaction(tx);
62+
}
63+
64+
/**
65+
* NOT implemented
66+
*/
67+
override async signTypedData(
68+
domain: ethers.TypedDataDomain,
69+
types: Record<string, ethers.TypedDataField[]>,
70+
value: Record<string, any>
71+
): Promise<string> {
72+
console.error('EmbeddedEthersSigner#signTypedData Not implemented', { domain, types, value });
73+
return '';
74+
}
75+
76+
/**
77+
* @deprecated v5 signer properties
78+
*/
79+
_isSigner = true;
80+
async getBalance(blockTag?: ethers.BlockTag) {
81+
return this.internalSigner.getBalance(blockTag);
82+
}
83+
async getTransactionCount(blockTag?: ethers.BlockTag) {
84+
return this.internalSigner.getTransactionCount(blockTag);
85+
}
86+
async getChainId() {
87+
return this.internalSigner.getChainId();
88+
}
89+
async getGasPrice() {
90+
return this.internalSigner.getGasPrice();
91+
}
92+
async getFeeData() {
93+
return this.internalSigner.getFeeData();
94+
}
95+
}
96+
97+
class InternalEmbeddedEthersSignerextends extends ethers.AbstractSigner<ethers.JsonRpcProvider> {
98+
// address = '';
99+
// override provider: ethers.JsonRpcProvider;
100+
101+
constructor(
102+
provider: ethers.JsonRpcProvider,
103+
private wallet: EmbeddedWallet
104+
) {
105+
super(provider);
21106
}
22107

23108
override connect(): ethers.Signer {

packages/sdk/lib/index.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ class EmbeddedWallet {
495495
funcDataTypes = 'tuple(bytes32 hashedUsername, bytes32 digest, bytes data)';
496496
}
497497

498-
const res = await this.gaslessTx({
498+
const res = await this.processGaslessMethod({
499499
label: 'Add new account',
500500
strategy: params.strategy,
501501
authData: params.authData,
@@ -1028,6 +1028,35 @@ class EmbeddedWallet {
10281028
// return receipt;
10291029
}
10301030

1031+
/**
1032+
* Prepare tx and emit `txSubmitted` event (to show tx in tx history in UI e.g.)
1033+
*/
1034+
submitTransaction(
1035+
txHash: string,
1036+
signedTxData?: ethers.BytesLike,
1037+
chainId?: number,
1038+
label = 'Transaction',
1039+
internalLabel?: string
1040+
) {
1041+
const txItem = {
1042+
hash: txHash,
1043+
label,
1044+
rawData: signedTxData || '',
1045+
owner: this.lastAccount.wallets[this.lastAccount.walletIndex].address || 'none',
1046+
status: 'pending' as const,
1047+
chainId: chainId || this.defaultNetworkId,
1048+
explorerUrl: this.explorerUrls[chainId || this.defaultNetworkId]
1049+
? `${this.explorerUrls[chainId || this.defaultNetworkId]}/tx/${txHash}`
1050+
: '',
1051+
createdAt: Date.now(),
1052+
internalLabel,
1053+
} as TransactionItem;
1054+
1055+
this.events.emit('txSubmitted', txItem);
1056+
1057+
return txItem;
1058+
}
1059+
10311060
/**
10321061
* Get signed tx for making a contract write call.
10331062
*/
@@ -1164,7 +1193,17 @@ class EmbeddedWallet {
11641193
}
11651194
}
11661195

1167-
async gaslessTx(params: {
1196+
/**
1197+
* Call an `Account Manager` contract method with a gasless transaction.
1198+
* This means that app owner (clientId) pays for the transaction fees instead of user.
1199+
* These methods must be supported by `generateGaslessTx` method on the contract.
1200+
* Supported methods are defined by `GaslessTxType`.
1201+
* About
1202+
* - get & confirm credentials
1203+
* - calculate and format tx data (according to `funcDataTypes` and `funcDataValuesFormatter` params)
1204+
* - broadcast the tx (marked with `label` from params)
1205+
*/
1206+
async processGaslessMethod(params: {
11681207
strategy: AuthStrategyName;
11691208
authData: AuthData;
11701209
data: any;

packages/sdk/lib/types.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ export type Network = {
1414
id: number;
1515
rpcUrl: string;
1616
explorerUrl: string;
17-
imageUrl?: string;
18-
currencySymbol?: string;
19-
currencDecimals?: number;
17+
imageUrl?: string; // Icon of the chain for display in UI
18+
currencySymbol?: string; // Symbol of the native currency (default is 'ETH')
19+
currencyDecimals?: number; // Number of decimals of the native currency (default is 18)
2020
};
2121

2222
export type SignatureCallback = (
@@ -52,14 +52,9 @@ export type AppParams = {
5252
networks?: Network[];
5353

5454
/**
55-
* Use a new window for creating and authenticating with a passkey
55+
* Method for authenticating with passkey to make it global.
5656
*/
5757
passkeyAuthMode?: AuthPasskeyMode;
58-
59-
/**
60-
* Iframe uses same wallet code. Set this to prevent implosion.
61-
*/
62-
noPasskeyIframe?: boolean;
6358
};
6459

6560
export type AuthData = {

packages/ui/README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@ This package provides default UI for showing the state of connected account and
44

55
Use `EmbeddedWalletUI()` to initialize SDK and the UI. The UI is done with React and HeadlessUI (tailwind).
66

7-
There are some UI specific options in addition to all SDK options.
7+
There are some UI specific options in addition to all the SDK options.
88

99
```ts
10-
// Supported networks info, for showing names and links to explorer.
11-
networks?: { name: string; id: number; rpcUrl: string; explorerUrl: string }[];
12-
1310
/**
1411
* Automatically broadcast with SDK after confirming a transaction.
1512
*

0 commit comments

Comments
 (0)