@openfort/openfort-js 0.8.18 → 0.8.20
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.
- package/dist/index.cjs +277 -51
- package/dist/index.d.ts +1 -0
- package/dist/index.js +277 -51
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3339,7 +3339,7 @@ class KeyPair extends signingKey.SigningKey {
|
|
|
3339
3339
|
}
|
|
3340
3340
|
}
|
|
3341
3341
|
|
|
3342
|
-
const VERSION = '0.8.
|
|
3342
|
+
const VERSION = '0.8.20';
|
|
3343
3343
|
|
|
3344
3344
|
var Event;
|
|
3345
3345
|
(function (Event) {
|
|
@@ -3350,6 +3350,8 @@ var Event;
|
|
|
3350
3350
|
Event["AUTHENTICATION_UPDATED"] = "authentication-updated";
|
|
3351
3351
|
Event["SIGN"] = "sign";
|
|
3352
3352
|
Event["SET_RECOVERY_METHOD"] = "set-recovery-method";
|
|
3353
|
+
Event["SWITCH_CHAIN"] = "switch-chain";
|
|
3354
|
+
Event["CHAIN_SWITCHED"] = "chain-switched";
|
|
3353
3355
|
Event["EXPORT"] = "export";
|
|
3354
3356
|
Event["SIGNED"] = "signed";
|
|
3355
3357
|
Event["LOGOUT"] = "logout";
|
|
@@ -3419,6 +3421,17 @@ class SignRequest {
|
|
|
3419
3421
|
this.requestConfiguration = requestConfiguration;
|
|
3420
3422
|
}
|
|
3421
3423
|
}
|
|
3424
|
+
class SwitchChainRequest {
|
|
3425
|
+
uuid;
|
|
3426
|
+
action = Event.SWITCH_CHAIN;
|
|
3427
|
+
chainId;
|
|
3428
|
+
requestConfiguration;
|
|
3429
|
+
constructor(uuid, chainId, requestConfiguration) {
|
|
3430
|
+
this.uuid = uuid;
|
|
3431
|
+
this.chainId = chainId;
|
|
3432
|
+
this.requestConfiguration = requestConfiguration;
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3422
3435
|
class ExportPrivateKeyRequest {
|
|
3423
3436
|
uuid;
|
|
3424
3437
|
action = Event.EXPORT;
|
|
@@ -3489,6 +3502,27 @@ class ConfigureResponse {
|
|
|
3489
3502
|
this.version = null;
|
|
3490
3503
|
}
|
|
3491
3504
|
}
|
|
3505
|
+
class SwitchChainResponse {
|
|
3506
|
+
uuid;
|
|
3507
|
+
success;
|
|
3508
|
+
deviceID;
|
|
3509
|
+
address;
|
|
3510
|
+
chainId;
|
|
3511
|
+
accountType;
|
|
3512
|
+
ownerAddress;
|
|
3513
|
+
version;
|
|
3514
|
+
action = Event.CHAIN_SWITCHED;
|
|
3515
|
+
constructor(uuid, deviceID, accountType, chainId, address, ownerAddress) {
|
|
3516
|
+
this.success = true;
|
|
3517
|
+
this.deviceID = deviceID;
|
|
3518
|
+
this.uuid = uuid;
|
|
3519
|
+
this.accountType = accountType;
|
|
3520
|
+
this.chainId = chainId;
|
|
3521
|
+
this.address = address;
|
|
3522
|
+
this.ownerAddress = ownerAddress;
|
|
3523
|
+
this.version = null;
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3492
3526
|
class UpdateAuthenticationResponse {
|
|
3493
3527
|
uuid;
|
|
3494
3528
|
success;
|
|
@@ -3659,6 +3693,7 @@ class IframeManager {
|
|
|
3659
3693
|
[Event.AUTHENTICATION_UPDATED]: UpdateAuthenticationResponse,
|
|
3660
3694
|
[Event.CURRENT_DEVICE]: GetCurrentDeviceResponse,
|
|
3661
3695
|
[Event.SIGNED]: SignResponse,
|
|
3696
|
+
[Event.CHAIN_SWITCHED]: SwitchChainResponse,
|
|
3662
3697
|
[Event.LOGGED_OUT]: LogoutResponse,
|
|
3663
3698
|
[Event.SET_RECOVERY_METHOD]: SetRecoveryMethodResponse,
|
|
3664
3699
|
[Event.EXPORT]: ExportPrivateKeyResponse,
|
|
@@ -3756,6 +3791,33 @@ class IframeManager {
|
|
|
3756
3791
|
sessionStorage.setItem('iframe-version', response.version ?? 'undefined');
|
|
3757
3792
|
return response.signature;
|
|
3758
3793
|
}
|
|
3794
|
+
async switchChain(iframeConfiguration, chainId) {
|
|
3795
|
+
await this.waitForIframeLoad();
|
|
3796
|
+
const uuid = this.generateShortUUID();
|
|
3797
|
+
const requestConfiguration = {
|
|
3798
|
+
thirdPartyProvider: iframeConfiguration.thirdPartyProvider ?? undefined,
|
|
3799
|
+
thirdPartyTokenType: iframeConfiguration.thirdPartyTokenType ?? undefined,
|
|
3800
|
+
token: iframeConfiguration.accessToken ?? undefined,
|
|
3801
|
+
publishableKey: this.sdkConfiguration.baseConfiguration.publishableKey,
|
|
3802
|
+
openfortURL: this.sdkConfiguration.backendUrl,
|
|
3803
|
+
};
|
|
3804
|
+
const request = new SwitchChainRequest(uuid, chainId, requestConfiguration);
|
|
3805
|
+
this.iframe?.contentWindow?.postMessage(request, '*');
|
|
3806
|
+
let response;
|
|
3807
|
+
try {
|
|
3808
|
+
response = await this.waitForResponse(uuid);
|
|
3809
|
+
}
|
|
3810
|
+
catch (e) {
|
|
3811
|
+
console.log('switchChain', e);
|
|
3812
|
+
if (e instanceof NotConfiguredError) {
|
|
3813
|
+
await this.configure(iframeConfiguration);
|
|
3814
|
+
return this.switchChain(iframeConfiguration, chainId);
|
|
3815
|
+
}
|
|
3816
|
+
throw e;
|
|
3817
|
+
}
|
|
3818
|
+
sessionStorage.setItem('iframe-version', response.version ?? 'undefined');
|
|
3819
|
+
return response;
|
|
3820
|
+
}
|
|
3759
3821
|
async export(iframeConfiguration) {
|
|
3760
3822
|
await this.waitForIframeLoad();
|
|
3761
3823
|
const uuid = this.generateShortUUID();
|
|
@@ -4004,6 +4066,30 @@ class Recovery {
|
|
|
4004
4066
|
}
|
|
4005
4067
|
}
|
|
4006
4068
|
|
|
4069
|
+
class Account {
|
|
4070
|
+
type;
|
|
4071
|
+
address;
|
|
4072
|
+
ownerAddress;
|
|
4073
|
+
chainId;
|
|
4074
|
+
constructor(type, address, chainId, ownerAddress) {
|
|
4075
|
+
this.type = type;
|
|
4076
|
+
this.address = address;
|
|
4077
|
+
this.chainId = chainId;
|
|
4078
|
+
this.ownerAddress = ownerAddress;
|
|
4079
|
+
}
|
|
4080
|
+
static fromStorage(storage) {
|
|
4081
|
+
const account = storage.get(StorageKeys.ACCOUNT);
|
|
4082
|
+
if (!account) {
|
|
4083
|
+
return null;
|
|
4084
|
+
}
|
|
4085
|
+
const accountObj = JSON.parse(account);
|
|
4086
|
+
return new Account(accountObj.type, accountObj.address, accountObj.chainId, accountObj.ownerAddress);
|
|
4087
|
+
}
|
|
4088
|
+
save(storage) {
|
|
4089
|
+
storage.save(StorageKeys.ACCOUNT, JSON.stringify(this));
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4007
4093
|
class EmbeddedSigner {
|
|
4008
4094
|
iframeManager;
|
|
4009
4095
|
iframeConfiguration;
|
|
@@ -4019,6 +4105,12 @@ class EmbeddedSigner {
|
|
|
4019
4105
|
async export() {
|
|
4020
4106
|
return await this.iframeManager.export(this.iframeConfiguration);
|
|
4021
4107
|
}
|
|
4108
|
+
async switchChain({ chainId }) {
|
|
4109
|
+
const deviceAccount = await this.iframeManager
|
|
4110
|
+
.switchChain(this.iframeConfiguration, chainId);
|
|
4111
|
+
new Account(deviceAccount.accountType, deviceAccount.address, deviceAccount.chainId, deviceAccount.ownerAddress).save(this.storage);
|
|
4112
|
+
SignerManager.storage.save(StorageKeys.SIGNER, JSON.stringify(deviceAccount));
|
|
4113
|
+
}
|
|
4022
4114
|
async setEmbeddedRecovery({ recoveryMethod, recoveryPassword, encryptionSession }) {
|
|
4023
4115
|
await this.iframeManager
|
|
4024
4116
|
.setEmbeddedRecovery(this.iframeConfiguration, recoveryMethod, recoveryPassword, encryptionSession);
|
|
@@ -4088,6 +4180,10 @@ class SessionSigner {
|
|
|
4088
4180
|
updateAuthentication() {
|
|
4089
4181
|
return Promise.resolve();
|
|
4090
4182
|
}
|
|
4183
|
+
// eslint-disable-next-line class-methods-use-this
|
|
4184
|
+
switchChain() {
|
|
4185
|
+
return Promise.resolve();
|
|
4186
|
+
}
|
|
4091
4187
|
async export() {
|
|
4092
4188
|
return this.sessionKey.getPrivateKey();
|
|
4093
4189
|
}
|
|
@@ -4097,30 +4193,6 @@ class SessionSigner {
|
|
|
4097
4193
|
}
|
|
4098
4194
|
}
|
|
4099
4195
|
|
|
4100
|
-
class Account {
|
|
4101
|
-
type;
|
|
4102
|
-
address;
|
|
4103
|
-
ownerAddress;
|
|
4104
|
-
chainId;
|
|
4105
|
-
constructor(type, address, chainId, ownerAddress) {
|
|
4106
|
-
this.type = type;
|
|
4107
|
-
this.address = address;
|
|
4108
|
-
this.chainId = chainId;
|
|
4109
|
-
this.ownerAddress = ownerAddress;
|
|
4110
|
-
}
|
|
4111
|
-
static fromStorage(storage) {
|
|
4112
|
-
const account = storage.get(StorageKeys.ACCOUNT);
|
|
4113
|
-
if (!account) {
|
|
4114
|
-
return null;
|
|
4115
|
-
}
|
|
4116
|
-
const accountObj = JSON.parse(account);
|
|
4117
|
-
return new Account(accountObj.type, accountObj.address, accountObj.chainId, accountObj.ownerAddress);
|
|
4118
|
-
}
|
|
4119
|
-
save(storage) {
|
|
4120
|
-
storage.save(StorageKeys.ACCOUNT, JSON.stringify(this));
|
|
4121
|
-
}
|
|
4122
|
-
}
|
|
4123
|
-
|
|
4124
4196
|
let iframeManagerSingleton = null;
|
|
4125
4197
|
class SignerManager {
|
|
4126
4198
|
static storage = new LocalStorage();
|
|
@@ -4880,6 +4952,7 @@ var BackendTransactionStatus;
|
|
|
4880
4952
|
var ProviderEvent;
|
|
4881
4953
|
(function (ProviderEvent) {
|
|
4882
4954
|
ProviderEvent["ACCOUNTS_CHANGED"] = "accountsChanged";
|
|
4955
|
+
ProviderEvent["ACCOUNTS_CONNECT"] = "connect";
|
|
4883
4956
|
})(ProviderEvent || (ProviderEvent = {}));
|
|
4884
4957
|
|
|
4885
4958
|
/**
|
|
@@ -4948,7 +5021,14 @@ const sendTransaction = async ({ params, signer, account, authentication, backen
|
|
|
4948
5021
|
const openfortTransaction = await buildOpenfortTransactions$4(params, backendClient, account, authentication, policyId);
|
|
4949
5022
|
let response;
|
|
4950
5023
|
if (openfortTransaction?.nextAction?.payload?.signableHash) {
|
|
4951
|
-
|
|
5024
|
+
let signature;
|
|
5025
|
+
// zkSync and Sophon test need a different signature
|
|
5026
|
+
if ([300, 531050104, 324, 50104].includes(account.chainId)) {
|
|
5027
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
|
|
5028
|
+
}
|
|
5029
|
+
else {
|
|
5030
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
|
|
5031
|
+
}
|
|
4952
5032
|
const openfortSignatureResponse = (await backendClient.transactionIntentsApi.signature({
|
|
4953
5033
|
id: openfortTransaction.id,
|
|
4954
5034
|
signatureRequest: { signature },
|
|
@@ -5062,7 +5142,7 @@ class TypedEventEmitter {
|
|
|
5062
5142
|
}
|
|
5063
5143
|
}
|
|
5064
5144
|
|
|
5065
|
-
const chain$
|
|
5145
|
+
const chain$t = {
|
|
5066
5146
|
name: 'ZKsync Sepolia Testnet',
|
|
5067
5147
|
title: 'ZKsync Sepolia Testnet',
|
|
5068
5148
|
chain: 'zksync-sepolia-testnet',
|
|
@@ -5090,6 +5170,34 @@ const chain$s = {
|
|
|
5090
5170
|
slug: 'zksync-sepolia-testnet',
|
|
5091
5171
|
};
|
|
5092
5172
|
|
|
5173
|
+
const chain$s = {
|
|
5174
|
+
name: 'ZKsync Era',
|
|
5175
|
+
title: 'ZKsync Era',
|
|
5176
|
+
chain: 'zksync-era',
|
|
5177
|
+
rpc: ['https://mainnet.era.zksync.io'],
|
|
5178
|
+
nativeCurrency: {
|
|
5179
|
+
name: 'Ether',
|
|
5180
|
+
symbol: 'ETH',
|
|
5181
|
+
decimals: 18,
|
|
5182
|
+
},
|
|
5183
|
+
shortName: 'zksync-era',
|
|
5184
|
+
chainId: 324,
|
|
5185
|
+
explorers: [
|
|
5186
|
+
{
|
|
5187
|
+
name: 'Etherscan',
|
|
5188
|
+
url: 'https://era.zksync.network/',
|
|
5189
|
+
standard: 'EIP3091',
|
|
5190
|
+
},
|
|
5191
|
+
{
|
|
5192
|
+
name: 'ZKsync Explorer',
|
|
5193
|
+
url: 'https://explorer.zksync.io/',
|
|
5194
|
+
standard: 'EIP3091',
|
|
5195
|
+
},
|
|
5196
|
+
],
|
|
5197
|
+
testnet: false,
|
|
5198
|
+
slug: 'zksync-era',
|
|
5199
|
+
};
|
|
5200
|
+
|
|
5093
5201
|
const chain$r = {
|
|
5094
5202
|
chain: 'BSC',
|
|
5095
5203
|
chainId: 56,
|
|
@@ -5476,12 +5584,9 @@ const chain$i = {
|
|
|
5476
5584
|
networkId: 11155111,
|
|
5477
5585
|
redFlags: [],
|
|
5478
5586
|
rpc: [
|
|
5479
|
-
'https://rpc.
|
|
5480
|
-
'https://rpc2.sepolia.org',
|
|
5481
|
-
'https://rpc-sepolia.rockx.com',
|
|
5587
|
+
'https://ethereum-sepolia-rpc.publicnode.com',
|
|
5482
5588
|
'https://rpc.sepolia.ethpandaops.io',
|
|
5483
5589
|
'https://sepolia.gateway.tenderly.co',
|
|
5484
|
-
'https://ethereum-sepolia.publicnode.com',
|
|
5485
5590
|
],
|
|
5486
5591
|
shortName: 'sep',
|
|
5487
5592
|
slug: 'sepolia',
|
|
@@ -6218,6 +6323,29 @@ const sophonTestnet = {
|
|
|
6218
6323
|
slug: 'sophon-testnet',
|
|
6219
6324
|
};
|
|
6220
6325
|
|
|
6326
|
+
const sophonMainnet = {
|
|
6327
|
+
name: 'Sophon',
|
|
6328
|
+
title: 'Sophon',
|
|
6329
|
+
chain: 'sophon',
|
|
6330
|
+
rpc: ['https://rpc.sophon.xyz'],
|
|
6331
|
+
nativeCurrency: {
|
|
6332
|
+
name: 'Sophon',
|
|
6333
|
+
symbol: 'SOPH',
|
|
6334
|
+
decimals: 18,
|
|
6335
|
+
},
|
|
6336
|
+
shortName: 'sophon',
|
|
6337
|
+
chainId: 50104,
|
|
6338
|
+
explorers: [
|
|
6339
|
+
{
|
|
6340
|
+
name: 'Sophon Block Explorer',
|
|
6341
|
+
url: 'https://explorer.sophon.xyz',
|
|
6342
|
+
standard: 'EIP3091',
|
|
6343
|
+
},
|
|
6344
|
+
],
|
|
6345
|
+
testnet: false,
|
|
6346
|
+
slug: 'sophon',
|
|
6347
|
+
};
|
|
6348
|
+
|
|
6221
6349
|
const chain$1 = {
|
|
6222
6350
|
chainId: 2358,
|
|
6223
6351
|
name: 'Kroma Sepolia',
|
|
@@ -6258,7 +6386,9 @@ const chainMap = {
|
|
|
6258
6386
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6259
6387
|
1: chain$j,
|
|
6260
6388
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6261
|
-
300: chain$
|
|
6389
|
+
300: chain$t,
|
|
6390
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6391
|
+
324: chain$s,
|
|
6262
6392
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6263
6393
|
56: chain$r,
|
|
6264
6394
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
@@ -6316,6 +6446,8 @@ const chainMap = {
|
|
|
6316
6446
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6317
6447
|
531050104: sophonTestnet,
|
|
6318
6448
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6449
|
+
50104: sophonMainnet,
|
|
6450
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6319
6451
|
2358: chain$1,
|
|
6320
6452
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6321
6453
|
255: chain,
|
|
@@ -6451,6 +6583,7 @@ const buildOpenfortTransactions$3 = async (params, backendApiClients, account, a
|
|
|
6451
6583
|
const formattedPermissions = param.permissions.map(formatPermissionRequest);
|
|
6452
6584
|
const whitelist = formattedPermissions.filter((p) => p.type === 'contract-call'
|
|
6453
6585
|
|| p.type === 'erc20-token-transfer').map((p) => p.data.address);
|
|
6586
|
+
const limit = formattedPermissions[0].policies.find((p) => p.type === 'usage-limit')?.data?.limit;
|
|
6454
6587
|
if (param.signer && param.signer.type === 'keys') {
|
|
6455
6588
|
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Failed to request permissions - missing session address');
|
|
6456
6589
|
}
|
|
@@ -6458,7 +6591,7 @@ const buildOpenfortTransactions$3 = async (params, backendApiClients, account, a
|
|
|
6458
6591
|
if (!sessionAddress) {
|
|
6459
6592
|
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Failed to request permissions - missing session address');
|
|
6460
6593
|
}
|
|
6461
|
-
const sessionRequest = formatSessionRequest$1(sessionAddress, account.chainId, now, expiry, policyId, false, whitelist, authentication.player);
|
|
6594
|
+
const sessionRequest = formatSessionRequest$1(sessionAddress, account.chainId, now, expiry, policyId, false, whitelist, authentication.player, limit);
|
|
6462
6595
|
const transactionResponse = await backendApiClients.sessionsApi.createSession({
|
|
6463
6596
|
createSessionRequest: sessionRequest,
|
|
6464
6597
|
}, {
|
|
@@ -6497,7 +6630,14 @@ const registerSession = async ({ params, signer, account, authentication, backen
|
|
|
6497
6630
|
const openfortTransaction = await buildOpenfortTransactions$3(params, backendClient, account, authentication, policyId);
|
|
6498
6631
|
let response;
|
|
6499
6632
|
if (openfortTransaction?.nextAction?.payload?.signableHash) {
|
|
6500
|
-
|
|
6633
|
+
let signature;
|
|
6634
|
+
// zkSync and Sophon test need a different signature
|
|
6635
|
+
if ([300, 531050104, 324, 50104].includes(account.chainId)) {
|
|
6636
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
|
|
6637
|
+
}
|
|
6638
|
+
else {
|
|
6639
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
|
|
6640
|
+
}
|
|
6501
6641
|
const openfortSignatureResponse = await backendClient.sessionsApi.signatureSession({
|
|
6502
6642
|
id: openfortTransaction.id,
|
|
6503
6643
|
signatureRequest: { signature },
|
|
@@ -6547,7 +6687,14 @@ const revokeSession = async ({ params, signer, account, authentication, backendC
|
|
|
6547
6687
|
const openfortTransaction = await buildOpenfortTransactions$2(params, backendClient, account, authentication, policyId);
|
|
6548
6688
|
let response;
|
|
6549
6689
|
if (openfortTransaction?.nextAction?.payload?.signableHash) {
|
|
6550
|
-
|
|
6690
|
+
let signature;
|
|
6691
|
+
// zkSync and Sophon test need a different signature
|
|
6692
|
+
if ([300, 531050104, 324, 50104].includes(account.chainId)) {
|
|
6693
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
|
|
6694
|
+
}
|
|
6695
|
+
else {
|
|
6696
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
|
|
6697
|
+
}
|
|
6551
6698
|
const openfortSignatureResponse = await backendClient.sessionsApi.signatureSession({
|
|
6552
6699
|
id: openfortTransaction.id,
|
|
6553
6700
|
signatureRequest: { signature },
|
|
@@ -6601,7 +6748,14 @@ const sendCalls = async ({ params, signer, account, authentication, backendClien
|
|
|
6601
6748
|
const openfortTransaction = await buildOpenfortTransactions$1(params[0].calls, backendClient, account, authentication, policy);
|
|
6602
6749
|
let response;
|
|
6603
6750
|
if (openfortTransaction?.nextAction?.payload?.signableHash) {
|
|
6604
|
-
|
|
6751
|
+
let signature;
|
|
6752
|
+
// zkSync and Sophon test need a different signature
|
|
6753
|
+
if ([300, 531050104, 324, 50104].includes(account.chainId)) {
|
|
6754
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
|
|
6755
|
+
}
|
|
6756
|
+
else {
|
|
6757
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
|
|
6758
|
+
}
|
|
6605
6759
|
const openfortSignatureResponse = (await backendClient.transactionIntentsApi.signature({
|
|
6606
6760
|
id: openfortTransaction.id,
|
|
6607
6761
|
signatureRequest: { signature },
|
|
@@ -6660,16 +6814,38 @@ const getCallStatus = async ({ params, authentication, backendClient, }) => {
|
|
|
6660
6814
|
};
|
|
6661
6815
|
};
|
|
6662
6816
|
|
|
6817
|
+
const personalSign = async ({ params, signer, account, }) => {
|
|
6818
|
+
const message = params[0];
|
|
6819
|
+
const fromAddress = params[1];
|
|
6820
|
+
if (!fromAddress || !message) {
|
|
6821
|
+
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'personal_sign requires an address and a message');
|
|
6822
|
+
}
|
|
6823
|
+
if (fromAddress.toLowerCase() !== account.address.toLowerCase()) {
|
|
6824
|
+
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'personal_sign requires the signer to be the from address');
|
|
6825
|
+
}
|
|
6826
|
+
const signature = await signer.sign(message, false, true);
|
|
6827
|
+
return signature;
|
|
6828
|
+
};
|
|
6829
|
+
|
|
6663
6830
|
class EvmProvider {
|
|
6664
6831
|
#storage;
|
|
6665
6832
|
#policyId;
|
|
6833
|
+
/**
|
|
6834
|
+
* Updates the policy ID for the provider
|
|
6835
|
+
* @param newPolicyId - The new policy ID to use
|
|
6836
|
+
*/
|
|
6837
|
+
updatePolicy(newPolicy) {
|
|
6838
|
+
this.#policyId = newPolicy;
|
|
6839
|
+
}
|
|
6840
|
+
#validateAndRefreshSession;
|
|
6666
6841
|
#eventEmitter;
|
|
6667
6842
|
#rpcProvider; // Used for read
|
|
6668
6843
|
#backendApiClients;
|
|
6669
6844
|
isOpenfort = true;
|
|
6670
|
-
constructor({ storage, backendApiClients, openfortEventEmitter, policyId, }) {
|
|
6845
|
+
constructor({ storage, backendApiClients, openfortEventEmitter, policyId, validateAndRefreshSession, }) {
|
|
6671
6846
|
this.#storage = storage;
|
|
6672
6847
|
this.#policyId = policyId;
|
|
6848
|
+
this.#validateAndRefreshSession = validateAndRefreshSession;
|
|
6673
6849
|
this.#backendApiClients = backendApiClients;
|
|
6674
6850
|
const account = Account.fromStorage(this.#storage);
|
|
6675
6851
|
const chainId = account?.chainId || 8453;
|
|
@@ -6699,6 +6875,7 @@ class EvmProvider {
|
|
|
6699
6875
|
case 'eth_requestAccounts': {
|
|
6700
6876
|
let account = Account.fromStorage(this.#storage);
|
|
6701
6877
|
if (account) {
|
|
6878
|
+
this.#eventEmitter.emit(ProviderEvent.ACCOUNTS_CONNECT, { chainId: bytes.hexlify(account.chainId) });
|
|
6702
6879
|
return [account.address];
|
|
6703
6880
|
}
|
|
6704
6881
|
const signer = SignerManager.fromStorage();
|
|
@@ -6720,6 +6897,8 @@ class EvmProvider {
|
|
|
6720
6897
|
if (!account || !signer || !authentication) {
|
|
6721
6898
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6722
6899
|
}
|
|
6900
|
+
this.#validateAndRefreshSession();
|
|
6901
|
+
console.log(`eth_sendTransaction ${this.#policyId}`);
|
|
6723
6902
|
return await sendTransaction({
|
|
6724
6903
|
params: request.params || [],
|
|
6725
6904
|
signer,
|
|
@@ -6736,6 +6915,7 @@ class EvmProvider {
|
|
|
6736
6915
|
if (!account || !signer) {
|
|
6737
6916
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6738
6917
|
}
|
|
6918
|
+
this.#validateAndRefreshSession();
|
|
6739
6919
|
return await signTypedDataV4({
|
|
6740
6920
|
method: request.method,
|
|
6741
6921
|
params: request.params || [],
|
|
@@ -6744,6 +6924,19 @@ class EvmProvider {
|
|
|
6744
6924
|
rpcProvider: this.#rpcProvider,
|
|
6745
6925
|
});
|
|
6746
6926
|
}
|
|
6927
|
+
case 'personal_sign': {
|
|
6928
|
+
const account = Account.fromStorage(this.#storage);
|
|
6929
|
+
const signer = SignerManager.fromStorage();
|
|
6930
|
+
if (!account || !signer) {
|
|
6931
|
+
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6932
|
+
}
|
|
6933
|
+
this.#validateAndRefreshSession();
|
|
6934
|
+
return await personalSign({
|
|
6935
|
+
params: request.params || [],
|
|
6936
|
+
signer,
|
|
6937
|
+
account,
|
|
6938
|
+
});
|
|
6939
|
+
}
|
|
6747
6940
|
case 'eth_chainId': {
|
|
6748
6941
|
// Call detect network to fetch the chainId so to take advantage of
|
|
6749
6942
|
// the caching layer provided by StaticJsonRpcProvider.
|
|
@@ -6754,6 +6947,25 @@ class EvmProvider {
|
|
|
6754
6947
|
const { chainId } = await this.#rpcProvider.detectNetwork();
|
|
6755
6948
|
return bytes.hexlify(chainId);
|
|
6756
6949
|
}
|
|
6950
|
+
case 'wallet_switchEthereumChain': {
|
|
6951
|
+
const signer = SignerManager.fromStorage();
|
|
6952
|
+
if (!signer) {
|
|
6953
|
+
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - must be authenticated and configured with a signer');
|
|
6954
|
+
}
|
|
6955
|
+
if (!request.params || !Array.isArray(request.params) || request.params.length === 0) {
|
|
6956
|
+
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Invalid parameters for wallet_switchEthereumChain');
|
|
6957
|
+
}
|
|
6958
|
+
this.#validateAndRefreshSession();
|
|
6959
|
+
try {
|
|
6960
|
+
const chainIdNumber = parseInt(request.params[0].chainId, 16);
|
|
6961
|
+
await signer.switchChain({ chainId: chainIdNumber });
|
|
6962
|
+
this.#rpcProvider = new providers.StaticJsonRpcProvider(chainMap[chainIdNumber].rpc[0]);
|
|
6963
|
+
}
|
|
6964
|
+
catch (error) {
|
|
6965
|
+
throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Failed to switch chain');
|
|
6966
|
+
}
|
|
6967
|
+
return null;
|
|
6968
|
+
}
|
|
6757
6969
|
case 'wallet_addEthereumChain': {
|
|
6758
6970
|
const signer = SignerManager.fromStorage();
|
|
6759
6971
|
if (!signer) {
|
|
@@ -6775,6 +6987,7 @@ class EvmProvider {
|
|
|
6775
6987
|
if (!account || !signer || !authentication) {
|
|
6776
6988
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6777
6989
|
}
|
|
6990
|
+
this.#validateAndRefreshSession();
|
|
6778
6991
|
return await getCallStatus({
|
|
6779
6992
|
params: (request.params || {}),
|
|
6780
6993
|
authentication,
|
|
@@ -6789,6 +7002,7 @@ class EvmProvider {
|
|
|
6789
7002
|
if (!account || !signer || !authentication) {
|
|
6790
7003
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6791
7004
|
}
|
|
7005
|
+
this.#validateAndRefreshSession();
|
|
6792
7006
|
return await sendCalls({
|
|
6793
7007
|
params: request.params || [],
|
|
6794
7008
|
signer,
|
|
@@ -6805,6 +7019,7 @@ class EvmProvider {
|
|
|
6805
7019
|
if (!account || !signer || !authentication) {
|
|
6806
7020
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6807
7021
|
}
|
|
7022
|
+
this.#validateAndRefreshSession();
|
|
6808
7023
|
return await registerSession({
|
|
6809
7024
|
params: (request.params || []),
|
|
6810
7025
|
signer,
|
|
@@ -6822,6 +7037,7 @@ class EvmProvider {
|
|
|
6822
7037
|
if (!account || !signer || !authentication) {
|
|
6823
7038
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6824
7039
|
}
|
|
7040
|
+
this.#validateAndRefreshSession();
|
|
6825
7041
|
return await revokeSession({
|
|
6826
7042
|
params: (request.params || {}),
|
|
6827
7043
|
signer,
|
|
@@ -6843,6 +7059,9 @@ class EvmProvider {
|
|
|
6843
7059
|
paymasterService: {
|
|
6844
7060
|
supported: true,
|
|
6845
7061
|
},
|
|
7062
|
+
atomicBatch: {
|
|
7063
|
+
supported: true,
|
|
7064
|
+
},
|
|
6846
7065
|
},
|
|
6847
7066
|
};
|
|
6848
7067
|
return capabilities;
|
|
@@ -6983,6 +7202,7 @@ function announceProvider(detail) {
|
|
|
6983
7202
|
|
|
6984
7203
|
class Openfort {
|
|
6985
7204
|
storage;
|
|
7205
|
+
provider = null;
|
|
6986
7206
|
constructor(sdkConfiguration) {
|
|
6987
7207
|
this.storage = new LocalStorage();
|
|
6988
7208
|
const configuration = new Configuration(sdkConfiguration.baseConfiguration.publishableKey, sdkConfiguration.overrides?.backendUrl || 'https://api.openfort.xyz', sdkConfiguration.shieldConfiguration?.shieldPublishableKey || '', sdkConfiguration.shieldConfiguration?.shieldEncryptionKey || '', sdkConfiguration.overrides?.shieldUrl || 'https://shield.openfort.xyz', sdkConfiguration.overrides?.iframeUrl || 'https://embedded.openfort.xyz', sdkConfiguration.shieldConfiguration?.debug || false);
|
|
@@ -7011,20 +7231,26 @@ class Openfort {
|
|
|
7011
7231
|
const authentication = Authentication.fromStorage(this.storage);
|
|
7012
7232
|
const signer = SignerManager.fromStorage();
|
|
7013
7233
|
const account = Account.fromStorage(this.storage);
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7234
|
+
if (!this.provider) {
|
|
7235
|
+
this.provider = new EvmProvider({
|
|
7236
|
+
storage: this.storage,
|
|
7237
|
+
openfortEventEmitter: new TypedEventEmitter(),
|
|
7238
|
+
signer: signer || undefined,
|
|
7239
|
+
account: account || undefined,
|
|
7240
|
+
authentication: authentication || undefined,
|
|
7241
|
+
backendApiClients: this.backendApiClients,
|
|
7242
|
+
policyId: options.policy,
|
|
7243
|
+
validateAndRefreshSession: this.validateAndRefreshToken.bind(this),
|
|
7244
|
+
});
|
|
7245
|
+
announceProvider({
|
|
7246
|
+
info: { ...openfortProviderInfo, ...options.providerInfo },
|
|
7247
|
+
provider: this.provider,
|
|
7248
|
+
});
|
|
7249
|
+
}
|
|
7250
|
+
else if (this.provider && options.policy) {
|
|
7251
|
+
this.provider.updatePolicy(options.policy);
|
|
7252
|
+
}
|
|
7253
|
+
return this.provider;
|
|
7028
7254
|
}
|
|
7029
7255
|
/**
|
|
7030
7256
|
* Configures a session key and returns the session key details.
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -3316,7 +3316,7 @@ class KeyPair extends SigningKey {
|
|
|
3316
3316
|
}
|
|
3317
3317
|
}
|
|
3318
3318
|
|
|
3319
|
-
const VERSION = '0.8.
|
|
3319
|
+
const VERSION = '0.8.20';
|
|
3320
3320
|
|
|
3321
3321
|
var Event;
|
|
3322
3322
|
(function (Event) {
|
|
@@ -3327,6 +3327,8 @@ var Event;
|
|
|
3327
3327
|
Event["AUTHENTICATION_UPDATED"] = "authentication-updated";
|
|
3328
3328
|
Event["SIGN"] = "sign";
|
|
3329
3329
|
Event["SET_RECOVERY_METHOD"] = "set-recovery-method";
|
|
3330
|
+
Event["SWITCH_CHAIN"] = "switch-chain";
|
|
3331
|
+
Event["CHAIN_SWITCHED"] = "chain-switched";
|
|
3330
3332
|
Event["EXPORT"] = "export";
|
|
3331
3333
|
Event["SIGNED"] = "signed";
|
|
3332
3334
|
Event["LOGOUT"] = "logout";
|
|
@@ -3396,6 +3398,17 @@ class SignRequest {
|
|
|
3396
3398
|
this.requestConfiguration = requestConfiguration;
|
|
3397
3399
|
}
|
|
3398
3400
|
}
|
|
3401
|
+
class SwitchChainRequest {
|
|
3402
|
+
uuid;
|
|
3403
|
+
action = Event.SWITCH_CHAIN;
|
|
3404
|
+
chainId;
|
|
3405
|
+
requestConfiguration;
|
|
3406
|
+
constructor(uuid, chainId, requestConfiguration) {
|
|
3407
|
+
this.uuid = uuid;
|
|
3408
|
+
this.chainId = chainId;
|
|
3409
|
+
this.requestConfiguration = requestConfiguration;
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3399
3412
|
class ExportPrivateKeyRequest {
|
|
3400
3413
|
uuid;
|
|
3401
3414
|
action = Event.EXPORT;
|
|
@@ -3466,6 +3479,27 @@ class ConfigureResponse {
|
|
|
3466
3479
|
this.version = null;
|
|
3467
3480
|
}
|
|
3468
3481
|
}
|
|
3482
|
+
class SwitchChainResponse {
|
|
3483
|
+
uuid;
|
|
3484
|
+
success;
|
|
3485
|
+
deviceID;
|
|
3486
|
+
address;
|
|
3487
|
+
chainId;
|
|
3488
|
+
accountType;
|
|
3489
|
+
ownerAddress;
|
|
3490
|
+
version;
|
|
3491
|
+
action = Event.CHAIN_SWITCHED;
|
|
3492
|
+
constructor(uuid, deviceID, accountType, chainId, address, ownerAddress) {
|
|
3493
|
+
this.success = true;
|
|
3494
|
+
this.deviceID = deviceID;
|
|
3495
|
+
this.uuid = uuid;
|
|
3496
|
+
this.accountType = accountType;
|
|
3497
|
+
this.chainId = chainId;
|
|
3498
|
+
this.address = address;
|
|
3499
|
+
this.ownerAddress = ownerAddress;
|
|
3500
|
+
this.version = null;
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3469
3503
|
class UpdateAuthenticationResponse {
|
|
3470
3504
|
uuid;
|
|
3471
3505
|
success;
|
|
@@ -3636,6 +3670,7 @@ class IframeManager {
|
|
|
3636
3670
|
[Event.AUTHENTICATION_UPDATED]: UpdateAuthenticationResponse,
|
|
3637
3671
|
[Event.CURRENT_DEVICE]: GetCurrentDeviceResponse,
|
|
3638
3672
|
[Event.SIGNED]: SignResponse,
|
|
3673
|
+
[Event.CHAIN_SWITCHED]: SwitchChainResponse,
|
|
3639
3674
|
[Event.LOGGED_OUT]: LogoutResponse,
|
|
3640
3675
|
[Event.SET_RECOVERY_METHOD]: SetRecoveryMethodResponse,
|
|
3641
3676
|
[Event.EXPORT]: ExportPrivateKeyResponse,
|
|
@@ -3733,6 +3768,33 @@ class IframeManager {
|
|
|
3733
3768
|
sessionStorage.setItem('iframe-version', response.version ?? 'undefined');
|
|
3734
3769
|
return response.signature;
|
|
3735
3770
|
}
|
|
3771
|
+
async switchChain(iframeConfiguration, chainId) {
|
|
3772
|
+
await this.waitForIframeLoad();
|
|
3773
|
+
const uuid = this.generateShortUUID();
|
|
3774
|
+
const requestConfiguration = {
|
|
3775
|
+
thirdPartyProvider: iframeConfiguration.thirdPartyProvider ?? undefined,
|
|
3776
|
+
thirdPartyTokenType: iframeConfiguration.thirdPartyTokenType ?? undefined,
|
|
3777
|
+
token: iframeConfiguration.accessToken ?? undefined,
|
|
3778
|
+
publishableKey: this.sdkConfiguration.baseConfiguration.publishableKey,
|
|
3779
|
+
openfortURL: this.sdkConfiguration.backendUrl,
|
|
3780
|
+
};
|
|
3781
|
+
const request = new SwitchChainRequest(uuid, chainId, requestConfiguration);
|
|
3782
|
+
this.iframe?.contentWindow?.postMessage(request, '*');
|
|
3783
|
+
let response;
|
|
3784
|
+
try {
|
|
3785
|
+
response = await this.waitForResponse(uuid);
|
|
3786
|
+
}
|
|
3787
|
+
catch (e) {
|
|
3788
|
+
console.log('switchChain', e);
|
|
3789
|
+
if (e instanceof NotConfiguredError) {
|
|
3790
|
+
await this.configure(iframeConfiguration);
|
|
3791
|
+
return this.switchChain(iframeConfiguration, chainId);
|
|
3792
|
+
}
|
|
3793
|
+
throw e;
|
|
3794
|
+
}
|
|
3795
|
+
sessionStorage.setItem('iframe-version', response.version ?? 'undefined');
|
|
3796
|
+
return response;
|
|
3797
|
+
}
|
|
3736
3798
|
async export(iframeConfiguration) {
|
|
3737
3799
|
await this.waitForIframeLoad();
|
|
3738
3800
|
const uuid = this.generateShortUUID();
|
|
@@ -3981,6 +4043,30 @@ class Recovery {
|
|
|
3981
4043
|
}
|
|
3982
4044
|
}
|
|
3983
4045
|
|
|
4046
|
+
class Account {
|
|
4047
|
+
type;
|
|
4048
|
+
address;
|
|
4049
|
+
ownerAddress;
|
|
4050
|
+
chainId;
|
|
4051
|
+
constructor(type, address, chainId, ownerAddress) {
|
|
4052
|
+
this.type = type;
|
|
4053
|
+
this.address = address;
|
|
4054
|
+
this.chainId = chainId;
|
|
4055
|
+
this.ownerAddress = ownerAddress;
|
|
4056
|
+
}
|
|
4057
|
+
static fromStorage(storage) {
|
|
4058
|
+
const account = storage.get(StorageKeys.ACCOUNT);
|
|
4059
|
+
if (!account) {
|
|
4060
|
+
return null;
|
|
4061
|
+
}
|
|
4062
|
+
const accountObj = JSON.parse(account);
|
|
4063
|
+
return new Account(accountObj.type, accountObj.address, accountObj.chainId, accountObj.ownerAddress);
|
|
4064
|
+
}
|
|
4065
|
+
save(storage) {
|
|
4066
|
+
storage.save(StorageKeys.ACCOUNT, JSON.stringify(this));
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
|
|
3984
4070
|
class EmbeddedSigner {
|
|
3985
4071
|
iframeManager;
|
|
3986
4072
|
iframeConfiguration;
|
|
@@ -3996,6 +4082,12 @@ class EmbeddedSigner {
|
|
|
3996
4082
|
async export() {
|
|
3997
4083
|
return await this.iframeManager.export(this.iframeConfiguration);
|
|
3998
4084
|
}
|
|
4085
|
+
async switchChain({ chainId }) {
|
|
4086
|
+
const deviceAccount = await this.iframeManager
|
|
4087
|
+
.switchChain(this.iframeConfiguration, chainId);
|
|
4088
|
+
new Account(deviceAccount.accountType, deviceAccount.address, deviceAccount.chainId, deviceAccount.ownerAddress).save(this.storage);
|
|
4089
|
+
SignerManager.storage.save(StorageKeys.SIGNER, JSON.stringify(deviceAccount));
|
|
4090
|
+
}
|
|
3999
4091
|
async setEmbeddedRecovery({ recoveryMethod, recoveryPassword, encryptionSession }) {
|
|
4000
4092
|
await this.iframeManager
|
|
4001
4093
|
.setEmbeddedRecovery(this.iframeConfiguration, recoveryMethod, recoveryPassword, encryptionSession);
|
|
@@ -4065,6 +4157,10 @@ class SessionSigner {
|
|
|
4065
4157
|
updateAuthentication() {
|
|
4066
4158
|
return Promise.resolve();
|
|
4067
4159
|
}
|
|
4160
|
+
// eslint-disable-next-line class-methods-use-this
|
|
4161
|
+
switchChain() {
|
|
4162
|
+
return Promise.resolve();
|
|
4163
|
+
}
|
|
4068
4164
|
async export() {
|
|
4069
4165
|
return this.sessionKey.getPrivateKey();
|
|
4070
4166
|
}
|
|
@@ -4074,30 +4170,6 @@ class SessionSigner {
|
|
|
4074
4170
|
}
|
|
4075
4171
|
}
|
|
4076
4172
|
|
|
4077
|
-
class Account {
|
|
4078
|
-
type;
|
|
4079
|
-
address;
|
|
4080
|
-
ownerAddress;
|
|
4081
|
-
chainId;
|
|
4082
|
-
constructor(type, address, chainId, ownerAddress) {
|
|
4083
|
-
this.type = type;
|
|
4084
|
-
this.address = address;
|
|
4085
|
-
this.chainId = chainId;
|
|
4086
|
-
this.ownerAddress = ownerAddress;
|
|
4087
|
-
}
|
|
4088
|
-
static fromStorage(storage) {
|
|
4089
|
-
const account = storage.get(StorageKeys.ACCOUNT);
|
|
4090
|
-
if (!account) {
|
|
4091
|
-
return null;
|
|
4092
|
-
}
|
|
4093
|
-
const accountObj = JSON.parse(account);
|
|
4094
|
-
return new Account(accountObj.type, accountObj.address, accountObj.chainId, accountObj.ownerAddress);
|
|
4095
|
-
}
|
|
4096
|
-
save(storage) {
|
|
4097
|
-
storage.save(StorageKeys.ACCOUNT, JSON.stringify(this));
|
|
4098
|
-
}
|
|
4099
|
-
}
|
|
4100
|
-
|
|
4101
4173
|
let iframeManagerSingleton = null;
|
|
4102
4174
|
class SignerManager {
|
|
4103
4175
|
static storage = new LocalStorage();
|
|
@@ -4857,6 +4929,7 @@ var BackendTransactionStatus;
|
|
|
4857
4929
|
var ProviderEvent;
|
|
4858
4930
|
(function (ProviderEvent) {
|
|
4859
4931
|
ProviderEvent["ACCOUNTS_CHANGED"] = "accountsChanged";
|
|
4932
|
+
ProviderEvent["ACCOUNTS_CONNECT"] = "connect";
|
|
4860
4933
|
})(ProviderEvent || (ProviderEvent = {}));
|
|
4861
4934
|
|
|
4862
4935
|
/**
|
|
@@ -4925,7 +4998,14 @@ const sendTransaction = async ({ params, signer, account, authentication, backen
|
|
|
4925
4998
|
const openfortTransaction = await buildOpenfortTransactions$4(params, backendClient, account, authentication, policyId);
|
|
4926
4999
|
let response;
|
|
4927
5000
|
if (openfortTransaction?.nextAction?.payload?.signableHash) {
|
|
4928
|
-
|
|
5001
|
+
let signature;
|
|
5002
|
+
// zkSync and Sophon test need a different signature
|
|
5003
|
+
if ([300, 531050104, 324, 50104].includes(account.chainId)) {
|
|
5004
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
|
|
5005
|
+
}
|
|
5006
|
+
else {
|
|
5007
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
|
|
5008
|
+
}
|
|
4929
5009
|
const openfortSignatureResponse = (await backendClient.transactionIntentsApi.signature({
|
|
4930
5010
|
id: openfortTransaction.id,
|
|
4931
5011
|
signatureRequest: { signature },
|
|
@@ -5039,7 +5119,7 @@ class TypedEventEmitter {
|
|
|
5039
5119
|
}
|
|
5040
5120
|
}
|
|
5041
5121
|
|
|
5042
|
-
const chain$
|
|
5122
|
+
const chain$t = {
|
|
5043
5123
|
name: 'ZKsync Sepolia Testnet',
|
|
5044
5124
|
title: 'ZKsync Sepolia Testnet',
|
|
5045
5125
|
chain: 'zksync-sepolia-testnet',
|
|
@@ -5067,6 +5147,34 @@ const chain$s = {
|
|
|
5067
5147
|
slug: 'zksync-sepolia-testnet',
|
|
5068
5148
|
};
|
|
5069
5149
|
|
|
5150
|
+
const chain$s = {
|
|
5151
|
+
name: 'ZKsync Era',
|
|
5152
|
+
title: 'ZKsync Era',
|
|
5153
|
+
chain: 'zksync-era',
|
|
5154
|
+
rpc: ['https://mainnet.era.zksync.io'],
|
|
5155
|
+
nativeCurrency: {
|
|
5156
|
+
name: 'Ether',
|
|
5157
|
+
symbol: 'ETH',
|
|
5158
|
+
decimals: 18,
|
|
5159
|
+
},
|
|
5160
|
+
shortName: 'zksync-era',
|
|
5161
|
+
chainId: 324,
|
|
5162
|
+
explorers: [
|
|
5163
|
+
{
|
|
5164
|
+
name: 'Etherscan',
|
|
5165
|
+
url: 'https://era.zksync.network/',
|
|
5166
|
+
standard: 'EIP3091',
|
|
5167
|
+
},
|
|
5168
|
+
{
|
|
5169
|
+
name: 'ZKsync Explorer',
|
|
5170
|
+
url: 'https://explorer.zksync.io/',
|
|
5171
|
+
standard: 'EIP3091',
|
|
5172
|
+
},
|
|
5173
|
+
],
|
|
5174
|
+
testnet: false,
|
|
5175
|
+
slug: 'zksync-era',
|
|
5176
|
+
};
|
|
5177
|
+
|
|
5070
5178
|
const chain$r = {
|
|
5071
5179
|
chain: 'BSC',
|
|
5072
5180
|
chainId: 56,
|
|
@@ -5453,12 +5561,9 @@ const chain$i = {
|
|
|
5453
5561
|
networkId: 11155111,
|
|
5454
5562
|
redFlags: [],
|
|
5455
5563
|
rpc: [
|
|
5456
|
-
'https://rpc.
|
|
5457
|
-
'https://rpc2.sepolia.org',
|
|
5458
|
-
'https://rpc-sepolia.rockx.com',
|
|
5564
|
+
'https://ethereum-sepolia-rpc.publicnode.com',
|
|
5459
5565
|
'https://rpc.sepolia.ethpandaops.io',
|
|
5460
5566
|
'https://sepolia.gateway.tenderly.co',
|
|
5461
|
-
'https://ethereum-sepolia.publicnode.com',
|
|
5462
5567
|
],
|
|
5463
5568
|
shortName: 'sep',
|
|
5464
5569
|
slug: 'sepolia',
|
|
@@ -6195,6 +6300,29 @@ const sophonTestnet = {
|
|
|
6195
6300
|
slug: 'sophon-testnet',
|
|
6196
6301
|
};
|
|
6197
6302
|
|
|
6303
|
+
const sophonMainnet = {
|
|
6304
|
+
name: 'Sophon',
|
|
6305
|
+
title: 'Sophon',
|
|
6306
|
+
chain: 'sophon',
|
|
6307
|
+
rpc: ['https://rpc.sophon.xyz'],
|
|
6308
|
+
nativeCurrency: {
|
|
6309
|
+
name: 'Sophon',
|
|
6310
|
+
symbol: 'SOPH',
|
|
6311
|
+
decimals: 18,
|
|
6312
|
+
},
|
|
6313
|
+
shortName: 'sophon',
|
|
6314
|
+
chainId: 50104,
|
|
6315
|
+
explorers: [
|
|
6316
|
+
{
|
|
6317
|
+
name: 'Sophon Block Explorer',
|
|
6318
|
+
url: 'https://explorer.sophon.xyz',
|
|
6319
|
+
standard: 'EIP3091',
|
|
6320
|
+
},
|
|
6321
|
+
],
|
|
6322
|
+
testnet: false,
|
|
6323
|
+
slug: 'sophon',
|
|
6324
|
+
};
|
|
6325
|
+
|
|
6198
6326
|
const chain$1 = {
|
|
6199
6327
|
chainId: 2358,
|
|
6200
6328
|
name: 'Kroma Sepolia',
|
|
@@ -6235,7 +6363,9 @@ const chainMap = {
|
|
|
6235
6363
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6236
6364
|
1: chain$j,
|
|
6237
6365
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6238
|
-
300: chain$
|
|
6366
|
+
300: chain$t,
|
|
6367
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6368
|
+
324: chain$s,
|
|
6239
6369
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6240
6370
|
56: chain$r,
|
|
6241
6371
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
@@ -6293,6 +6423,8 @@ const chainMap = {
|
|
|
6293
6423
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6294
6424
|
531050104: sophonTestnet,
|
|
6295
6425
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6426
|
+
50104: sophonMainnet,
|
|
6427
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6296
6428
|
2358: chain$1,
|
|
6297
6429
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
6298
6430
|
255: chain,
|
|
@@ -6428,6 +6560,7 @@ const buildOpenfortTransactions$3 = async (params, backendApiClients, account, a
|
|
|
6428
6560
|
const formattedPermissions = param.permissions.map(formatPermissionRequest);
|
|
6429
6561
|
const whitelist = formattedPermissions.filter((p) => p.type === 'contract-call'
|
|
6430
6562
|
|| p.type === 'erc20-token-transfer').map((p) => p.data.address);
|
|
6563
|
+
const limit = formattedPermissions[0].policies.find((p) => p.type === 'usage-limit')?.data?.limit;
|
|
6431
6564
|
if (param.signer && param.signer.type === 'keys') {
|
|
6432
6565
|
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Failed to request permissions - missing session address');
|
|
6433
6566
|
}
|
|
@@ -6435,7 +6568,7 @@ const buildOpenfortTransactions$3 = async (params, backendApiClients, account, a
|
|
|
6435
6568
|
if (!sessionAddress) {
|
|
6436
6569
|
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Failed to request permissions - missing session address');
|
|
6437
6570
|
}
|
|
6438
|
-
const sessionRequest = formatSessionRequest$1(sessionAddress, account.chainId, now, expiry, policyId, false, whitelist, authentication.player);
|
|
6571
|
+
const sessionRequest = formatSessionRequest$1(sessionAddress, account.chainId, now, expiry, policyId, false, whitelist, authentication.player, limit);
|
|
6439
6572
|
const transactionResponse = await backendApiClients.sessionsApi.createSession({
|
|
6440
6573
|
createSessionRequest: sessionRequest,
|
|
6441
6574
|
}, {
|
|
@@ -6474,7 +6607,14 @@ const registerSession = async ({ params, signer, account, authentication, backen
|
|
|
6474
6607
|
const openfortTransaction = await buildOpenfortTransactions$3(params, backendClient, account, authentication, policyId);
|
|
6475
6608
|
let response;
|
|
6476
6609
|
if (openfortTransaction?.nextAction?.payload?.signableHash) {
|
|
6477
|
-
|
|
6610
|
+
let signature;
|
|
6611
|
+
// zkSync and Sophon test need a different signature
|
|
6612
|
+
if ([300, 531050104, 324, 50104].includes(account.chainId)) {
|
|
6613
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
|
|
6614
|
+
}
|
|
6615
|
+
else {
|
|
6616
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
|
|
6617
|
+
}
|
|
6478
6618
|
const openfortSignatureResponse = await backendClient.sessionsApi.signatureSession({
|
|
6479
6619
|
id: openfortTransaction.id,
|
|
6480
6620
|
signatureRequest: { signature },
|
|
@@ -6524,7 +6664,14 @@ const revokeSession = async ({ params, signer, account, authentication, backendC
|
|
|
6524
6664
|
const openfortTransaction = await buildOpenfortTransactions$2(params, backendClient, account, authentication, policyId);
|
|
6525
6665
|
let response;
|
|
6526
6666
|
if (openfortTransaction?.nextAction?.payload?.signableHash) {
|
|
6527
|
-
|
|
6667
|
+
let signature;
|
|
6668
|
+
// zkSync and Sophon test need a different signature
|
|
6669
|
+
if ([300, 531050104, 324, 50104].includes(account.chainId)) {
|
|
6670
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
|
|
6671
|
+
}
|
|
6672
|
+
else {
|
|
6673
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
|
|
6674
|
+
}
|
|
6528
6675
|
const openfortSignatureResponse = await backendClient.sessionsApi.signatureSession({
|
|
6529
6676
|
id: openfortTransaction.id,
|
|
6530
6677
|
signatureRequest: { signature },
|
|
@@ -6578,7 +6725,14 @@ const sendCalls = async ({ params, signer, account, authentication, backendClien
|
|
|
6578
6725
|
const openfortTransaction = await buildOpenfortTransactions$1(params[0].calls, backendClient, account, authentication, policy);
|
|
6579
6726
|
let response;
|
|
6580
6727
|
if (openfortTransaction?.nextAction?.payload?.signableHash) {
|
|
6581
|
-
|
|
6728
|
+
let signature;
|
|
6729
|
+
// zkSync and Sophon test need a different signature
|
|
6730
|
+
if ([300, 531050104, 324, 50104].includes(account.chainId)) {
|
|
6731
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash, false, false);
|
|
6732
|
+
}
|
|
6733
|
+
else {
|
|
6734
|
+
signature = await signer.sign(openfortTransaction.nextAction.payload.signableHash);
|
|
6735
|
+
}
|
|
6582
6736
|
const openfortSignatureResponse = (await backendClient.transactionIntentsApi.signature({
|
|
6583
6737
|
id: openfortTransaction.id,
|
|
6584
6738
|
signatureRequest: { signature },
|
|
@@ -6637,16 +6791,38 @@ const getCallStatus = async ({ params, authentication, backendClient, }) => {
|
|
|
6637
6791
|
};
|
|
6638
6792
|
};
|
|
6639
6793
|
|
|
6794
|
+
const personalSign = async ({ params, signer, account, }) => {
|
|
6795
|
+
const message = params[0];
|
|
6796
|
+
const fromAddress = params[1];
|
|
6797
|
+
if (!fromAddress || !message) {
|
|
6798
|
+
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'personal_sign requires an address and a message');
|
|
6799
|
+
}
|
|
6800
|
+
if (fromAddress.toLowerCase() !== account.address.toLowerCase()) {
|
|
6801
|
+
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'personal_sign requires the signer to be the from address');
|
|
6802
|
+
}
|
|
6803
|
+
const signature = await signer.sign(message, false, true);
|
|
6804
|
+
return signature;
|
|
6805
|
+
};
|
|
6806
|
+
|
|
6640
6807
|
class EvmProvider {
|
|
6641
6808
|
#storage;
|
|
6642
6809
|
#policyId;
|
|
6810
|
+
/**
|
|
6811
|
+
* Updates the policy ID for the provider
|
|
6812
|
+
* @param newPolicyId - The new policy ID to use
|
|
6813
|
+
*/
|
|
6814
|
+
updatePolicy(newPolicy) {
|
|
6815
|
+
this.#policyId = newPolicy;
|
|
6816
|
+
}
|
|
6817
|
+
#validateAndRefreshSession;
|
|
6643
6818
|
#eventEmitter;
|
|
6644
6819
|
#rpcProvider; // Used for read
|
|
6645
6820
|
#backendApiClients;
|
|
6646
6821
|
isOpenfort = true;
|
|
6647
|
-
constructor({ storage, backendApiClients, openfortEventEmitter, policyId, }) {
|
|
6822
|
+
constructor({ storage, backendApiClients, openfortEventEmitter, policyId, validateAndRefreshSession, }) {
|
|
6648
6823
|
this.#storage = storage;
|
|
6649
6824
|
this.#policyId = policyId;
|
|
6825
|
+
this.#validateAndRefreshSession = validateAndRefreshSession;
|
|
6650
6826
|
this.#backendApiClients = backendApiClients;
|
|
6651
6827
|
const account = Account.fromStorage(this.#storage);
|
|
6652
6828
|
const chainId = account?.chainId || 8453;
|
|
@@ -6676,6 +6852,7 @@ class EvmProvider {
|
|
|
6676
6852
|
case 'eth_requestAccounts': {
|
|
6677
6853
|
let account = Account.fromStorage(this.#storage);
|
|
6678
6854
|
if (account) {
|
|
6855
|
+
this.#eventEmitter.emit(ProviderEvent.ACCOUNTS_CONNECT, { chainId: hexlify(account.chainId) });
|
|
6679
6856
|
return [account.address];
|
|
6680
6857
|
}
|
|
6681
6858
|
const signer = SignerManager.fromStorage();
|
|
@@ -6697,6 +6874,8 @@ class EvmProvider {
|
|
|
6697
6874
|
if (!account || !signer || !authentication) {
|
|
6698
6875
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6699
6876
|
}
|
|
6877
|
+
this.#validateAndRefreshSession();
|
|
6878
|
+
console.log(`eth_sendTransaction ${this.#policyId}`);
|
|
6700
6879
|
return await sendTransaction({
|
|
6701
6880
|
params: request.params || [],
|
|
6702
6881
|
signer,
|
|
@@ -6713,6 +6892,7 @@ class EvmProvider {
|
|
|
6713
6892
|
if (!account || !signer) {
|
|
6714
6893
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6715
6894
|
}
|
|
6895
|
+
this.#validateAndRefreshSession();
|
|
6716
6896
|
return await signTypedDataV4({
|
|
6717
6897
|
method: request.method,
|
|
6718
6898
|
params: request.params || [],
|
|
@@ -6721,6 +6901,19 @@ class EvmProvider {
|
|
|
6721
6901
|
rpcProvider: this.#rpcProvider,
|
|
6722
6902
|
});
|
|
6723
6903
|
}
|
|
6904
|
+
case 'personal_sign': {
|
|
6905
|
+
const account = Account.fromStorage(this.#storage);
|
|
6906
|
+
const signer = SignerManager.fromStorage();
|
|
6907
|
+
if (!account || !signer) {
|
|
6908
|
+
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6909
|
+
}
|
|
6910
|
+
this.#validateAndRefreshSession();
|
|
6911
|
+
return await personalSign({
|
|
6912
|
+
params: request.params || [],
|
|
6913
|
+
signer,
|
|
6914
|
+
account,
|
|
6915
|
+
});
|
|
6916
|
+
}
|
|
6724
6917
|
case 'eth_chainId': {
|
|
6725
6918
|
// Call detect network to fetch the chainId so to take advantage of
|
|
6726
6919
|
// the caching layer provided by StaticJsonRpcProvider.
|
|
@@ -6731,6 +6924,25 @@ class EvmProvider {
|
|
|
6731
6924
|
const { chainId } = await this.#rpcProvider.detectNetwork();
|
|
6732
6925
|
return hexlify(chainId);
|
|
6733
6926
|
}
|
|
6927
|
+
case 'wallet_switchEthereumChain': {
|
|
6928
|
+
const signer = SignerManager.fromStorage();
|
|
6929
|
+
if (!signer) {
|
|
6930
|
+
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - must be authenticated and configured with a signer');
|
|
6931
|
+
}
|
|
6932
|
+
if (!request.params || !Array.isArray(request.params) || request.params.length === 0) {
|
|
6933
|
+
throw new JsonRpcError(RpcErrorCode.INVALID_PARAMS, 'Invalid parameters for wallet_switchEthereumChain');
|
|
6934
|
+
}
|
|
6935
|
+
this.#validateAndRefreshSession();
|
|
6936
|
+
try {
|
|
6937
|
+
const chainIdNumber = parseInt(request.params[0].chainId, 16);
|
|
6938
|
+
await signer.switchChain({ chainId: chainIdNumber });
|
|
6939
|
+
this.#rpcProvider = new StaticJsonRpcProvider(chainMap[chainIdNumber].rpc[0]);
|
|
6940
|
+
}
|
|
6941
|
+
catch (error) {
|
|
6942
|
+
throw new JsonRpcError(RpcErrorCode.INTERNAL_ERROR, 'Failed to switch chain');
|
|
6943
|
+
}
|
|
6944
|
+
return null;
|
|
6945
|
+
}
|
|
6734
6946
|
case 'wallet_addEthereumChain': {
|
|
6735
6947
|
const signer = SignerManager.fromStorage();
|
|
6736
6948
|
if (!signer) {
|
|
@@ -6752,6 +6964,7 @@ class EvmProvider {
|
|
|
6752
6964
|
if (!account || !signer || !authentication) {
|
|
6753
6965
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6754
6966
|
}
|
|
6967
|
+
this.#validateAndRefreshSession();
|
|
6755
6968
|
return await getCallStatus({
|
|
6756
6969
|
params: (request.params || {}),
|
|
6757
6970
|
authentication,
|
|
@@ -6766,6 +6979,7 @@ class EvmProvider {
|
|
|
6766
6979
|
if (!account || !signer || !authentication) {
|
|
6767
6980
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6768
6981
|
}
|
|
6982
|
+
this.#validateAndRefreshSession();
|
|
6769
6983
|
return await sendCalls({
|
|
6770
6984
|
params: request.params || [],
|
|
6771
6985
|
signer,
|
|
@@ -6782,6 +6996,7 @@ class EvmProvider {
|
|
|
6782
6996
|
if (!account || !signer || !authentication) {
|
|
6783
6997
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6784
6998
|
}
|
|
6999
|
+
this.#validateAndRefreshSession();
|
|
6785
7000
|
return await registerSession({
|
|
6786
7001
|
params: (request.params || []),
|
|
6787
7002
|
signer,
|
|
@@ -6799,6 +7014,7 @@ class EvmProvider {
|
|
|
6799
7014
|
if (!account || !signer || !authentication) {
|
|
6800
7015
|
throw new JsonRpcError(ProviderErrorCode.UNAUTHORIZED, 'Unauthorized - call eth_requestAccounts first');
|
|
6801
7016
|
}
|
|
7017
|
+
this.#validateAndRefreshSession();
|
|
6802
7018
|
return await revokeSession({
|
|
6803
7019
|
params: (request.params || {}),
|
|
6804
7020
|
signer,
|
|
@@ -6820,6 +7036,9 @@ class EvmProvider {
|
|
|
6820
7036
|
paymasterService: {
|
|
6821
7037
|
supported: true,
|
|
6822
7038
|
},
|
|
7039
|
+
atomicBatch: {
|
|
7040
|
+
supported: true,
|
|
7041
|
+
},
|
|
6823
7042
|
},
|
|
6824
7043
|
};
|
|
6825
7044
|
return capabilities;
|
|
@@ -6960,6 +7179,7 @@ function announceProvider(detail) {
|
|
|
6960
7179
|
|
|
6961
7180
|
class Openfort {
|
|
6962
7181
|
storage;
|
|
7182
|
+
provider = null;
|
|
6963
7183
|
constructor(sdkConfiguration) {
|
|
6964
7184
|
this.storage = new LocalStorage();
|
|
6965
7185
|
const configuration = new Configuration(sdkConfiguration.baseConfiguration.publishableKey, sdkConfiguration.overrides?.backendUrl || 'https://api.openfort.xyz', sdkConfiguration.shieldConfiguration?.shieldPublishableKey || '', sdkConfiguration.shieldConfiguration?.shieldEncryptionKey || '', sdkConfiguration.overrides?.shieldUrl || 'https://shield.openfort.xyz', sdkConfiguration.overrides?.iframeUrl || 'https://embedded.openfort.xyz', sdkConfiguration.shieldConfiguration?.debug || false);
|
|
@@ -6988,20 +7208,26 @@ class Openfort {
|
|
|
6988
7208
|
const authentication = Authentication.fromStorage(this.storage);
|
|
6989
7209
|
const signer = SignerManager.fromStorage();
|
|
6990
7210
|
const account = Account.fromStorage(this.storage);
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7211
|
+
if (!this.provider) {
|
|
7212
|
+
this.provider = new EvmProvider({
|
|
7213
|
+
storage: this.storage,
|
|
7214
|
+
openfortEventEmitter: new TypedEventEmitter(),
|
|
7215
|
+
signer: signer || undefined,
|
|
7216
|
+
account: account || undefined,
|
|
7217
|
+
authentication: authentication || undefined,
|
|
7218
|
+
backendApiClients: this.backendApiClients,
|
|
7219
|
+
policyId: options.policy,
|
|
7220
|
+
validateAndRefreshSession: this.validateAndRefreshToken.bind(this),
|
|
7221
|
+
});
|
|
7222
|
+
announceProvider({
|
|
7223
|
+
info: { ...openfortProviderInfo, ...options.providerInfo },
|
|
7224
|
+
provider: this.provider,
|
|
7225
|
+
});
|
|
7226
|
+
}
|
|
7227
|
+
else if (this.provider && options.policy) {
|
|
7228
|
+
this.provider.updatePolicy(options.policy);
|
|
7229
|
+
}
|
|
7230
|
+
return this.provider;
|
|
7005
7231
|
}
|
|
7006
7232
|
/**
|
|
7007
7233
|
* Configures a session key and returns the session key details.
|
package/package.json
CHANGED