Compare commits

..
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
26367c04f3 Version Packages (#1483)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-08-11 16:07:25 -07:00
Joaquim VergesandGitHub 39e2af6f2f [Wallets] correct gas estimation for polygon/mumbai (#1484) 2023-08-11 22:16:29 +00:00
Joaquim VergesandGitHub a5ba9e4fbf [SDK] Separate Account and AccountPermissions extensions (#1480) 2023-08-11 20:31:54 +00:00
25 changed files with 992 additions and 519 deletions
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/auth
## 3.2.31
### Patch Changes
- Updated dependencies [[`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74)]:
- @thirdweb-dev/wallets@1.1.14
## 3.2.30
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.2.30",
"version": "3.2.31",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+29
View File
@@ -0,0 +1,29 @@
import type { Chain } from "../src/types";
export default {
"name": "Japan Open Chain Testnet",
"chain": "JOCT",
"rpc": [
"https://japan-open-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-1.testnet.japanopenchain.org:8545",
"https://rpc-2.testnet.japanopenchain.org:8545"
],
"faucets": [],
"nativeCurrency": {
"name": "Japan Open Chain Testnet Token",
"symbol": "JOCT",
"decimals": 18
},
"infoURL": "https://www.japanopenchain.org/",
"shortName": "joct",
"chainId": 10081,
"networkId": 10081,
"explorers": [
{
"name": "Testnet Block Explorer",
"url": "https://explorer.testnet.japanopenchain.org",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "japan-open-chain-testnet"
} as const satisfies Chain;
+7
View File
@@ -1,5 +1,12 @@
# thirdweb
## 0.11.14
### Patch Changes
- Updated dependencies [[`a5ba9e4f`](https://github.com/thirdweb-dev/js/commit/a5ba9e4fbfee228e5b9ac27cd0157187e3a50117), [`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74)]:
- @thirdweb-dev/sdk@3.10.50
## 0.11.13
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.11.13",
"version": "0.11.14",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/react-core
## 3.14.31
### Patch Changes
- Updated dependencies [[`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74), [`a5ba9e4f`](https://github.com/thirdweb-dev/js/commit/a5ba9e4fbfee228e5b9ac27cd0157187e3a50117), [`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74)]:
- @thirdweb-dev/wallets@1.1.14
- @thirdweb-dev/sdk@3.10.50
- @thirdweb-dev/auth@3.2.31
## 3.14.30
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "3.14.30",
"version": "3.14.31",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -1,5 +1,7 @@
# @thirdweb-dev/react-native-compat
## 0.2.50
## 0.2.49
## 0.2.48
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.2.49",
"version": "0.2.50",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/react-native
## 0.2.50
### Patch Changes
- Updated dependencies [[`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74), [`a5ba9e4f`](https://github.com/thirdweb-dev/js/commit/a5ba9e4fbfee228e5b9ac27cd0157187e3a50117), [`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74)]:
- @thirdweb-dev/wallets@1.1.14
- @thirdweb-dev/sdk@3.10.50
- @thirdweb-dev/react-core@3.14.31
## 0.2.49
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.2.49",
"version": "0.2.50",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/react
## 3.14.31
### Patch Changes
- Updated dependencies [[`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74), [`a5ba9e4f`](https://github.com/thirdweb-dev/js/commit/a5ba9e4fbfee228e5b9ac27cd0157187e3a50117), [`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74)]:
- @thirdweb-dev/wallets@1.1.14
- @thirdweb-dev/sdk@3.10.50
- @thirdweb-dev/react-core@3.14.31
## 3.14.30
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.14.30",
"version": "3.14.31",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+8
View File
@@ -1,5 +1,13 @@
# @thirdweb-dev/sdk
## 3.10.50
### Patch Changes
- [#1480](https://github.com/thirdweb-dev/js/pull/1480) [`a5ba9e4f`](https://github.com/thirdweb-dev/js/commit/a5ba9e4fbfee228e5b9ac27cd0157187e3a50117) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Separate Account and AccountPermissions extensions
- [#1484](https://github.com/thirdweb-dev/js/pull/1484) [`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose getPolygonGasPriorityFee()
## 3.10.49
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "3.10.49",
"version": "3.10.50",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0",
+1
View File
@@ -2,6 +2,7 @@ export * from "./error";
export * from "./snapshots";
export * from "./role";
export * from "./metadata-resolver";
export * from "./gas-price";
// feature detection
export * from "./feature-detection/matchesPrebuiltAbi";
@@ -67,6 +67,7 @@ import {
FEATURE_EXTENSION_ROUTER,
FEATURE_ACCOUNT,
FEATURE_ACCOUNT_FACTORY,
FEATURE_ACCOUNT_PERMISSIONS,
} from "./thirdweb-features";
/**
@@ -134,6 +135,7 @@ export type Feature =
| typeof FEATURE_ENGLISH_AUCTIONS
| typeof FEATURE_OFFERS
| typeof FEATURE_ACCOUNT
| typeof FEATURE_ACCOUNT_PERMISSIONS
| typeof FEATURE_ACCOUNT_FACTORY;
export type Extension = Feature;
@@ -12,7 +12,8 @@ import IThirdwebPrimarySaleAbi from "@thirdweb-dev/contracts-js/dist/abis/IPrima
import IThirdwebRoyaltyAbi from "@thirdweb-dev/contracts-js/dist/abis/IRoyalty.json";
import IOwnableAbi from "@thirdweb-dev/contracts-js/dist/abis/Ownable.json";
import IAccountFactory from "@thirdweb-dev/contracts-js/dist/abis/IAccountFactory.json";
import IAccountCore from "@thirdweb-dev/contracts-js/dist/abis/IAccountCore.json";
import IAccountPermissions from "@thirdweb-dev/contracts-js/dist/abis/IAccountPermissions.json";
import IAccount from "@thirdweb-dev/contracts-js/dist/abis/IAccount.json";
export const getAllPluginsAbi = [
{
@@ -291,6 +292,18 @@ export const FEATURE_ACCOUNT_FACTORY = {
features: {},
} as const;
export const FEATURE_ACCOUNT_PERMISSIONS = {
name: "AccountPermissions",
namespace: "accountPermissions",
docLinks: {
// TODO
sdk: "sdk.account",
contracts: "",
},
abis: [IAccountPermissions],
features: {},
} as const;
export const FEATURE_ACCOUNT = {
name: "Account",
namespace: "account",
@@ -299,6 +312,6 @@ export const FEATURE_ACCOUNT = {
sdk: "sdk.account",
contracts: "",
},
abis: [IAccountCore],
features: {},
abis: [IAccount],
features: { [FEATURE_ACCOUNT_PERMISSIONS.name]: FEATURE_ACCOUNT_PERMISSIONS },
} as const;
@@ -0,0 +1,727 @@
import { DetectableFeature } from "../interfaces/DetectableFeature";
import { ContractWrapper } from "./contract-wrapper";
import { FEATURE_ACCOUNT_PERMISSIONS } from "../../constants/thirdweb-features";
import { utils, BigNumber } from "ethers";
import { Transaction } from "./transactions";
import type {
IAccountCore,
IAccountPermissions,
} from "@thirdweb-dev/contracts-js";
import {
SignedSignerPermissionsPayload,
SignerPermissionsOutput,
SignerWithPermissions,
SignerPermissions,
SignerPermissionsInput,
SignerPermissionRequest,
SignerPermissionsSchema,
PermissionSnapshotInput,
PermissionSnapshotSchema,
PermissionSnapshotOutput,
} from "../../types";
import invariant from "tiny-invariant";
import { buildTransactionFunction } from "../../common/transactions";
import { resolveOrGenerateId } from "../../common/signature-minting";
import { AddressOrEns } from "../../schema";
import { resolveAddress } from "../../common";
export class AccountPermissions implements DetectableFeature {
featureName = FEATURE_ACCOUNT_PERMISSIONS.name;
private contractWrapper: ContractWrapper<IAccountCore>;
constructor(contractWrapper: ContractWrapper<IAccountCore>) {
this.contractWrapper = contractWrapper;
}
getAddress(): string {
return this.contractWrapper.readContract.address;
}
/*********************************
* HELPER FUNCTIONS
********************************/
private hasDuplicateSigners(snapshot: PermissionSnapshotOutput): boolean {
const checkedSigner: Record<string, boolean> = {};
const signers = snapshot.map((item) => item.signer);
for (const signer of signers) {
if (!checkedSigner[signer]) {
checkedSigner[signer] = true;
} else {
return true;
}
}
return false;
}
/**
* Format the access restrictions for a given role
*
* @param restrictions - The access restrictions for a given role
* @returns formatted role restrictions
*
*/
private parseSignerPermissionsStruct(
permissions: IAccountPermissions.SignerPermissionsStruct,
): SignerPermissions {
return {
startDate: new Date(
parseInt(permissions.startTimestamp.toString()) * 1000,
),
expirationDate: new Date(
parseInt(permissions.endTimestamp.toString()) * 1000,
),
nativeTokenLimitPerTransaction: BigNumber.from(
permissions.nativeTokenLimitPerTransaction,
),
approvedCallTargets: permissions.approvedTargets,
};
}
private async sendSignerPermissionRequest(
signerAddress: string,
permissions: SignerPermissionsOutput,
): Promise<Transaction> {
const { payload, signature } = await this.generatePayload(
signerAddress,
permissions,
);
const { success } =
await this.contractWrapper.readContract.verifySignerPermissionRequest(
payload,
signature,
);
if (!success) {
throw new Error(`Invalid signature.`);
}
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "setPermissionsForSigner",
args: [payload, signature],
});
}
private async buildSignerPermissionRequest(
signerAddress: string,
permissions: SignerPermissionsOutput,
): Promise<string> {
const { payload, signature } = await this.generatePayload(
signerAddress,
permissions,
);
const isValidSigner =
await this.contractWrapper.readContract.verifySignerPermissionRequest(
payload,
signature,
);
if (!isValidSigner) {
throw new Error(`Invalid signature.`);
}
return this.contractWrapper.writeContract.interface.encodeFunctionData(
"setPermissionsForSigner",
[payload, signature],
);
}
/**
* Generate and sign a payload to grant or revoke a signer's access to the account.
*
* @param signer - The address of the signer
* @param roleAction - The address of the signer
* @returns The generated payload and signature produced on signing that payload.
*
*/
private async generatePayload(
signerAddress: string,
permissions: SignerPermissionsOutput,
): Promise<SignedSignerPermissionsPayload> {
// Get payload struct.
const payload: IAccountPermissions.SignerPermissionRequestStruct = {
signer: signerAddress,
approvedTargets: permissions.approvedCallTargets,
nativeTokenLimitPerTransaction: utils.parseEther(
permissions.nativeTokenLimitPerTransaction,
),
permissionStartTimestamp: permissions.startDate,
permissionEndTimestamp: permissions.expirationDate,
reqValidityStartTimestamp: 0,
// Req validity ends 10 years from now.
reqValidityEndTimestamp: BigNumber.from(
Math.floor(
new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 10).getTime() /
1000,
),
),
uid: resolveOrGenerateId(undefined),
};
// Generate signature
const chainId = await this.contractWrapper.getChainID();
const connectedSigner = this.contractWrapper.getSigner();
invariant(connectedSigner, "No signer available");
const signature = await this.contractWrapper.signTypedData(
connectedSigner,
{
name: "Account",
version: "1",
chainId,
verifyingContract: this.getAddress(),
},
{ SignerPermissionRequest },
payload,
);
return { payload, signature };
}
/*********************************
* READ FUNCTIONS
********************************/
/**
* Get whether a signer is an admin on the account.
*
* @example
* ```javascript
* const isAdmin = await contract.account.isAdmin(signer);
* ```
* @param signer - The address of a signer of the account.
* @returns whether a signer is an admin on the account.
*
* @twfeature AccountPermissions
*/
public async isAdmin(signerAddress: AddressOrEns): Promise<boolean> {
const resolvedSignerAddress = await resolveAddress(signerAddress);
return await this.contractWrapper.readContract.isAdmin(
resolvedSignerAddress,
);
}
/**
* Get whether a signer has permissions to use the account.
*
* @example
* ```javascript
* const isAdmin = await contract.account.isSigner(signer);
* ```
* @param signer - The address of a signer of the account.
* @returns whether a signer has permissions to use the account.
*
* @twfeature AccountPermissions
*/
public async isSigner(signerAddress: AddressOrEns): Promise<boolean> {
const resolvedSignerAddress = await resolveAddress(signerAddress);
return await this.contractWrapper.readContract.isActiveSigner(
resolvedSignerAddress,
);
}
/**
* Get all admins of the account.
*
* @example
* ```javascript
* const allAdmins = await contract.account.getAllAdmins();
* ```
*
* @returns all admins of the account.
*
* @twfeature AccountPermissions
*/
public async getAllAdmins(): Promise<string[]> {
return await this.contractWrapper.readContract.getAllAdmins();
}
/**
* Get all (non-admin) signers with permissions to use the account.
*
* @example
* ```javascript
* const allSigners = await contract.account.getAllSigners();
* ```
*
* @returns all (non-admin) signers with permissions to use the account.
*
* @twfeature AccountPermissions
*/
public async getAllSigners(): Promise<SignerWithPermissions[]> {
const activeSignersWithPerms: IAccountPermissions.SignerPermissionsStruct[] =
await this.contractWrapper.readContract.getAllActiveSigners();
return await Promise.all(
activeSignersWithPerms.map(async (signerWithPermissions) => {
const signer = signerWithPermissions.signer;
const permissions = this.parseSignerPermissionsStruct(
signerWithPermissions,
);
return { signer, permissions };
}),
);
}
/**
* Get all admins and non-admin signers with permissions to use the account.
*
* @example
* ```javascript
* const allAdminsAndSigners = await contract.account.getAllAdminsAndSigners();
* ```
*
* @returns all admins and non-admin signers with permissions to use the account.
*
* @twfeature AccountPermissions
*/
public async getAllAdminsAndSigners(): Promise<SignerWithPermissions[]> {
const allAdmins = await this.getAllAdmins();
const transformedAdmins: SignerWithPermissions[] = allAdmins.map(
(admin) => {
return {
isAdmin: true,
signer: admin,
permissions: {
startDate: new Date(0),
expirationDate: new Date(0),
nativeTokenLimitPerTransaction: BigNumber.from(0),
approvedCallTargets: [],
},
};
},
);
const allSigners = await this.getAllSigners();
return [...transformedAdmins, ...allSigners];
}
/*********************************
* WRITE FUNCTIONS
********************************/
/**
* Grant an address admin access to the account.
*
* @remarks Grants an address admin access to the account. The admin will have complete authority over the account.
*
* @param signer - The address to be granted admin access to the account.
*
* @example
* ```javascript
* const tx = await contract.account.grantAdminAccess(signer);
* const receipt = tx.receipt();
* ```
*
* @twfeature AccountPermissions
*/
grantAdminPermissions = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "setAdmin",
args: [resolvedSignerAddress, true],
});
},
);
/**
* Revoke an address' admin access to the account.
*
* @remarks Revokes an address' admin access to the account.
*
* @param signer - The address of an admin of the account.
*
* @example
* ```javascript
* const tx = await contract.account.revokeAdminAccess(signer);
* const receipt = tx.receipt();
* ```
*
* @twfeature AccountPermissions
*/
revokeAdminPermissions = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "setAdmin",
args: [resolvedSignerAddress, false],
});
},
);
/**
* Grant a signer permissions to use the account.
*
* @remarks Grants a signer permissions to use the account.
*
* @param signer - The signer to be granted permissions to use the account.
* @param permissions - The permissions to be applied to the signer's use of the account.
*
* @example
* ```javascript
* const tx = await contract.account.grantPermissions(signer, permissions);
* const receipt = tx.receipt();
* ```
*
* @twfeature AccountPermissions
*/
grantPermissions = /* @__PURE__ */ buildTransactionFunction(
async (
signerAddress: AddressOrEns,
permissions: SignerPermissionsInput,
): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
const resolvedPermissions = await SignerPermissionsSchema.parseAsync(
permissions,
);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot grant permissions to an existing admin.",
);
}
if (await this.isSigner(resolvedSignerAddress)) {
throw new Error(
"Signer already has permissions. Cannot grant permissions to an existing signer. You can update permissions using `updatePermissions`.",
);
}
return await this.sendSignerPermissionRequest(
resolvedSignerAddress,
resolvedPermissions,
);
},
);
/**
* Update the permissions of a signer for using the account.
*
* @remarks Updates the permissions of a signer for using the account.
*
* @param signer - The signer whose permissions to use the account are to be updated.
* @param permissions - The permissions to be applied to the signer's use of the account.
*
* @example
* ```javascript
* const tx = await contract.account.updateAccess(signer, restrictions);
* const receipt = tx.receipt();
* ```
*
* @twfeature AccountPermissions
*/
updatePermissions = /* @__PURE__ */ buildTransactionFunction(
async (
signerAddress: AddressOrEns,
permissions: SignerPermissionsInput,
): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
const resolvedPermissions = await SignerPermissionsSchema.parseAsync(
permissions,
);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot update permissions of an existing admin.",
);
}
if (!(await this.isSigner(resolvedSignerAddress))) {
throw new Error(
"Signer does not already have permissions. You can grant permissions using `grantPermissions`.",
);
}
return await this.sendSignerPermissionRequest(
resolvedSignerAddress,
resolvedPermissions,
);
},
);
/**
* Revoke a scoped access address to the account
*
* @remarks Revokes an address' access to the account.
*
* @param signer - The address whose access to the account is to be revoked.
*
* @example
* ```javascript
* const tx = await contract.account.revokeAccess(signer);
* const receipt = tx.receipt();
* ```
*
* @twfeature AccountPermissions
*/
revokeAccess = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot revoke permissions of an admin.",
);
}
if (!(await this.isSigner(resolvedSignerAddress))) {
throw new Error(
"Signer does not already have permissions. You can grant permissions using `grantPermissions`.",
);
}
return await this.sendSignerPermissionRequest(resolvedSignerAddress, {
startDate: BigNumber.from(0),
expirationDate: BigNumber.from(0),
approvedCallTargets: [],
nativeTokenLimitPerTransaction: "0",
});
},
);
/**
* Approve an address as a call target for a given signer on the account
*
* @remarks Approves an address as a call target for a given signer on the account.
*
* @param signer - A signer with restricted access to the account.
* @param target - The address to approve as a call target for the signer.
*
* @example
* ```javascript
* const tx = await contract.account.approveTargetForSigner(signer, target);
* const receipt = tx.receipt();
* ```
*
* @twfeature AccountPermissions
*/
approveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
async (
signerAddress: AddressOrEns,
target: AddressOrEns,
): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
const resolvedTarget = await resolveAddress(target);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot approve targets for an admin.",
);
}
if (!(await this.isSigner(resolvedSignerAddress))) {
throw new Error(
"Signer does not already have permissions. You can grant permissions using `grantPermissions`.",
);
}
const permissions: IAccountPermissions.SignerPermissionsStruct =
await this.contractWrapper.readContract.getPermissionsForSigner(
resolvedSignerAddress,
);
if (permissions.approvedTargets.includes(target)) {
throw new Error("Target is already approved");
}
const newTargets = [...permissions.approvedTargets, resolvedTarget];
return await this.sendSignerPermissionRequest(resolvedSignerAddress, {
startDate: BigNumber.from(permissions.startTimestamp),
expirationDate: BigNumber.from(permissions.endTimestamp),
approvedCallTargets: newTargets,
nativeTokenLimitPerTransaction:
permissions.nativeTokenLimitPerTransaction.toString(),
});
},
);
/**
* Disapprove an address as a call target for a given signer on the account
*
* @remarks Disapprove an address as a call target for a given signer on the account.
*
* @param signer - A signer with restricted access to the account.
* @param target - The address to disapprove as a call target for the signer.
*
* @example
* ```javascript
* const tx = await contract.account.disapproveTargetForSigner(signer, target);
* const receipt = tx.receipt();
* ```
*
* @twfeature AccountPermissions
*/
disapproveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
async (
signerAddress: AddressOrEns,
target: AddressOrEns,
): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
const resolvedTarget = await resolveAddress(target);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot approve targets for an admin.",
);
}
if (!(await this.isSigner(resolvedSignerAddress))) {
throw new Error(
"Signer does not already have permissions. You can grant permissions using `grantPermissions`.",
);
}
const permissions: IAccountPermissions.SignerPermissionsStruct =
await this.contractWrapper.readContract.getPermissionsForSigner(
resolvedSignerAddress,
);
if (!permissions.approvedTargets.includes(resolvedTarget)) {
throw new Error("Target is currently not approved");
}
const newTargets = permissions.approvedTargets.filter(
(approvedTarget) =>
utils.getAddress(approvedTarget) !== utils.getAddress(resolvedTarget),
);
return await this.sendSignerPermissionRequest(resolvedSignerAddress, {
startDate: BigNumber.from(permissions.startTimestamp),
expirationDate: BigNumber.from(permissions.endTimestamp),
approvedCallTargets: newTargets,
nativeTokenLimitPerTransaction:
permissions.nativeTokenLimitPerTransaction.toString(),
});
},
);
/**
* Set the account's entire snapshot of permissions.
*
* @remarks Sets the account's entire snapshot of permissions.
*
* @param permissionSnapshot - the snapshot to set as the account's entire permission snapshot.
*
* @example
* ```javascript
* const tx = await contract.account.setAccess(permissionSnapshot);
* const receipt = tx.receipt();
* ```
*
* @twfeature AccountPermissions
*/
resetAllPermissions = /* @__PURE__ */ buildTransactionFunction(
async (
permissionSnapshot: PermissionSnapshotInput,
): Promise<Transaction> => {
const resolvedSnapshot = await PermissionSnapshotSchema.parseAsync(
permissionSnapshot,
);
/**
* All cases
*
* - Add new admin :check:
* - Remove current admin :check:
* - Add new scoped :check:
* - Remove current scoped :check:
* - Update current scoped :check:
* - Current admin -> new scoped :check:
* - Current scoped -> new admin :check:
**/
// No duplicate signers in input!
if (this.hasDuplicateSigners(resolvedSnapshot)) {
throw new Error("Duplicate signers found in input.");
}
const addAdminData: string[] = [];
const removeAdminData: string[] = [];
const addOrUpdateSignerData: string[] = [];
const removeSignerData: string[] = [];
// Remove all existing admins not included in the passed snapshot.
const allAdmins = await this.getAllAdmins();
const allToMakeAdmin = resolvedSnapshot
.filter((item) => item.makeAdmin)
.map((item) => item.signer);
allAdmins.forEach((admin) => {
if (!allToMakeAdmin.includes(admin)) {
removeAdminData.push(
this.contractWrapper.writeContract.interface.encodeFunctionData(
"setAdmin",
[admin, false],
),
);
}
});
// Remove all existing signers not included in the passed snapshot.
const allSigners = await this.getAllSigners();
const allToMakeSigners = resolvedSnapshot
.filter((item) => {
return !item.makeAdmin;
})
.map((item) => item.signer);
await Promise.all(
allSigners.map(async (item) => {
if (!allToMakeSigners.includes(item.signer)) {
const data = await this.buildSignerPermissionRequest(item.signer, {
startDate: BigNumber.from(0),
expirationDate: BigNumber.from(0),
approvedCallTargets: [],
nativeTokenLimitPerTransaction: "0",
});
removeSignerData.push(data);
}
}),
);
for (const member of resolvedSnapshot) {
// Add new admin
if (member.makeAdmin) {
addAdminData.push(
this.contractWrapper.writeContract.interface.encodeFunctionData(
"setAdmin",
[member.signer, true],
),
);
} else {
// Add new scoped
const data = await this.buildSignerPermissionRequest(
member.signer,
member.permissions,
);
addOrUpdateSignerData.push(data);
}
}
const data: string[] = [];
removeAdminData.forEach((item) => {
data.push(item);
});
removeSignerData.forEach((item) => {
data.push(item);
});
addOrUpdateSignerData.forEach((item) => {
data.push(item);
});
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "multicall",
args: [data],
});
},
);
}
+117 -504
View File
@@ -1,190 +1,48 @@
import { DetectableFeature } from "../interfaces/DetectableFeature";
import { ContractWrapper } from "./contract-wrapper";
import { FEATURE_ACCOUNT } from "../../constants/thirdweb-features";
import { utils, BigNumber } from "ethers";
import { Transaction } from "./transactions";
import type {
IAccountCore,
IAccountPermissions,
} from "@thirdweb-dev/contracts-js";
import {
SignedSignerPermissionsPayload,
SignerPermissionsOutput,
FEATURE_ACCOUNT,
FEATURE_ACCOUNT_PERMISSIONS,
} from "../../constants/thirdweb-features";
import type { IAccountCore } from "@thirdweb-dev/contracts-js";
import {
SignerWithPermissions,
SignerPermissions,
SignerPermissionsInput,
SignerPermissionRequest,
SignerPermissionsSchema,
PermissionSnapshotInput,
PermissionSnapshotSchema,
PermissionSnapshotOutput,
} from "../../types";
import invariant from "tiny-invariant";
import { buildTransactionFunction } from "../../common/transactions";
import { resolveOrGenerateId } from "../../common/signature-minting";
import { AddressOrEns } from "../../schema";
import { resolveAddress } from "../../common";
import { assertEnabled, detectContractFeature } from "../../common";
import { AccountPermissions } from "./account-permissions";
export class Account<TContract extends IAccountCore>
implements DetectableFeature
{
featureName = FEATURE_ACCOUNT.name;
private contractWrapper: ContractWrapper<IAccountCore>;
private accountPermissions: AccountPermissions | undefined;
constructor(contractWrapper: ContractWrapper<TContract>) {
this.contractWrapper = contractWrapper;
this.accountPermissions = this.detectAccountPermissions();
}
private detectAccountPermissions(): AccountPermissions | undefined {
if (
detectContractFeature<IAccountCore>(
this.contractWrapper,
"AccountPermissions",
)
) {
return new AccountPermissions(this.contractWrapper);
}
return undefined;
}
getAddress(): string {
return this.contractWrapper.readContract.address;
}
/*********************************
* HELPER FUNCTIONS
********************************/
private hasDuplicateSigners(snapshot: PermissionSnapshotOutput): boolean {
const checkedSigner: Record<string, boolean> = {};
const signers = snapshot.map((item) => item.signer);
for (const signer of signers) {
if (!checkedSigner[signer]) {
checkedSigner[signer] = true;
} else {
return true;
}
}
return false;
}
/**
* Format the access restrictions for a given role
*
* @param restrictions - The access restrictions for a given role
* @returns formatted role restrictions
*
*/
private parseSignerPermissionsStruct(
permissions: IAccountPermissions.SignerPermissionsStruct,
): SignerPermissions {
return {
startDate: new Date(
parseInt(permissions.startTimestamp.toString()) * 1000,
),
expirationDate: new Date(
parseInt(permissions.endTimestamp.toString()) * 1000,
),
nativeTokenLimitPerTransaction: BigNumber.from(
permissions.nativeTokenLimitPerTransaction,
),
approvedCallTargets: permissions.approvedTargets,
};
}
private async sendSignerPermissionRequest(
signerAddress: string,
permissions: SignerPermissionsOutput,
): Promise<Transaction> {
const { payload, signature } = await this.generatePayload(
signerAddress,
permissions,
);
const { success } =
await this.contractWrapper.readContract.verifySignerPermissionRequest(
payload,
signature,
);
if (!success) {
throw new Error(`Invalid signature.`);
}
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "setPermissionsForSigner",
args: [payload, signature],
});
}
private async buildSignerPermissionRequest(
signerAddress: string,
permissions: SignerPermissionsOutput,
): Promise<string> {
const { payload, signature } = await this.generatePayload(
signerAddress,
permissions,
);
const isValidSigner =
await this.contractWrapper.readContract.verifySignerPermissionRequest(
payload,
signature,
);
if (!isValidSigner) {
throw new Error(`Invalid signature.`);
}
return this.contractWrapper.writeContract.interface.encodeFunctionData(
"setPermissionsForSigner",
[payload, signature],
);
}
/**
* Generate and sign a payload to grant or revoke a signer's access to the account.
*
* @param signer - The address of the signer
* @param roleAction - The address of the signer
* @returns The generated payload and signature produced on signing that payload.
*
*/
private async generatePayload(
signerAddress: string,
permissions: SignerPermissionsOutput,
): Promise<SignedSignerPermissionsPayload> {
// Get payload struct.
const payload: IAccountPermissions.SignerPermissionRequestStruct = {
signer: signerAddress,
approvedTargets: permissions.approvedCallTargets,
nativeTokenLimitPerTransaction: utils.parseEther(
permissions.nativeTokenLimitPerTransaction,
),
permissionStartTimestamp: permissions.startDate,
permissionEndTimestamp: permissions.expirationDate,
reqValidityStartTimestamp: 0,
// Req validity ends 10 years from now.
reqValidityEndTimestamp: BigNumber.from(
Math.floor(
new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 10).getTime() /
1000,
),
),
uid: resolveOrGenerateId(undefined),
};
// Generate signature
const chainId = await this.contractWrapper.getChainID();
const connectedSigner = this.contractWrapper.getSigner();
invariant(connectedSigner, "No signer available");
const signature = await this.contractWrapper.signTypedData(
connectedSigner,
{
name: "Account",
version: "1",
chainId,
verifyingContract: this.getAddress(),
},
{ SignerPermissionRequest },
payload,
);
return { payload, signature };
}
/*********************************
* READ FUNCTIONS
********************************/
@@ -199,13 +57,13 @@ export class Account<TContract extends IAccountCore>
* @param signer - The address of a signer of the account.
* @returns whether a signer is an admin on the account.
*
* @twfeature Account
* @twfeature AccountPermissions
*/
public async isAdmin(signerAddress: AddressOrEns): Promise<boolean> {
const resolvedSignerAddress = await resolveAddress(signerAddress);
return await this.contractWrapper.readContract.isAdmin(
resolvedSignerAddress,
);
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).isAdmin(signerAddress);
}
/**
@@ -218,13 +76,13 @@ export class Account<TContract extends IAccountCore>
* @param signer - The address of a signer of the account.
* @returns whether a signer has permissions to use the account.
*
* @twfeature Account
* @twfeature AccountPermissions
*/
public async isSigner(signerAddress: AddressOrEns): Promise<boolean> {
const resolvedSignerAddress = await resolveAddress(signerAddress);
return await this.contractWrapper.readContract.isActiveSigner(
resolvedSignerAddress,
);
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).isSigner(signerAddress);
}
/**
@@ -237,10 +95,13 @@ export class Account<TContract extends IAccountCore>
*
* @returns all admins of the account.
*
* @twfeature Account
* @twfeature AccountPermissions
*/
public async getAllAdmins(): Promise<string[]> {
return await this.contractWrapper.readContract.getAllAdmins();
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).getAllAdmins();
}
/**
@@ -253,21 +114,13 @@ export class Account<TContract extends IAccountCore>
*
* @returns all (non-admin) signers with permissions to use the account.
*
* @twfeature Account
* @twfeature AccountPermissions
*/
public async getAllSigners(): Promise<SignerWithPermissions[]> {
const activeSignersWithPerms: IAccountPermissions.SignerPermissionsStruct[] =
await this.contractWrapper.readContract.getAllActiveSigners();
return await Promise.all(
activeSignersWithPerms.map(async (signerWithPermissions) => {
const signer = signerWithPermissions.signer;
const permissions = this.parseSignerPermissionsStruct(
signerWithPermissions,
);
return { signer, permissions };
}),
);
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).getAllSigners();
}
/**
@@ -280,27 +133,13 @@ export class Account<TContract extends IAccountCore>
*
* @returns all admins and non-admin signers with permissions to use the account.
*
* @twfeature Account
* @twfeature AccountPermissions
*/
public async getAllAdminsAndSigners(): Promise<SignerWithPermissions[]> {
const allAdmins = await this.getAllAdmins();
const transformedAdmins: SignerWithPermissions[] = allAdmins.map(
(admin) => {
return {
isAdmin: true,
signer: admin,
permissions: {
startDate: new Date(0),
expirationDate: new Date(0),
nativeTokenLimitPerTransaction: BigNumber.from(0),
approvedCallTargets: [],
},
};
},
);
const allSigners = await this.getAllSigners();
return [...transformedAdmins, ...allSigners];
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).getAllAdminsAndSigners();
}
/*********************************
@@ -320,18 +159,14 @@ export class Account<TContract extends IAccountCore>
* const receipt = tx.receipt();
* ```
*
* @twfeature Account
* @twfeature AccountPermissions
*/
grantAdminPermissions = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "setAdmin",
args: [resolvedSignerAddress, true],
});
},
);
public async grantAdminPermissions(signerAddress: AddressOrEns) {
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).grantAdminPermissions(signerAddress);
}
/**
* Revoke an address' admin access to the account.
@@ -346,18 +181,14 @@ export class Account<TContract extends IAccountCore>
* const receipt = tx.receipt();
* ```
*
* @twfeature Account
* @twfeature AccountPermissions
*/
revokeAdminPermissions = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "setAdmin",
args: [resolvedSignerAddress, false],
});
},
);
public async revokeAdminPermissions(signerAddress: AddressOrEns) {
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).revokeAdminPermissions(signerAddress);
}
/**
* Grant a signer permissions to use the account.
@@ -373,36 +204,17 @@ export class Account<TContract extends IAccountCore>
* const receipt = tx.receipt();
* ```
*
* @twfeature Account
* @twfeature AccountPermissions
*/
grantPermissions = /* @__PURE__ */ buildTransactionFunction(
async (
signerAddress: AddressOrEns,
permissions: SignerPermissionsInput,
): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
const resolvedPermissions = await SignerPermissionsSchema.parseAsync(
permissions,
);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot grant permissions to an existing admin.",
);
}
if (await this.isSigner(resolvedSignerAddress)) {
throw new Error(
"Signer already has permissions. Cannot grant permissions to an existing signer. You can update permissions using `updatePermissions`.",
);
}
return await this.sendSignerPermissionRequest(
resolvedSignerAddress,
resolvedPermissions,
);
},
);
public async grantPermissions(
signerAddress: AddressOrEns,
permissions: SignerPermissionsInput,
) {
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).grantPermissions(signerAddress, permissions);
}
/**
* Update the permissions of a signer for using the account.
@@ -418,36 +230,17 @@ export class Account<TContract extends IAccountCore>
* const receipt = tx.receipt();
* ```
*
* @twfeature Account
* @twfeature AccountPermissions
*/
updatePermissions = /* @__PURE__ */ buildTransactionFunction(
async (
signerAddress: AddressOrEns,
permissions: SignerPermissionsInput,
): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
const resolvedPermissions = await SignerPermissionsSchema.parseAsync(
permissions,
);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot update permissions of an existing admin.",
);
}
if (!(await this.isSigner(resolvedSignerAddress))) {
throw new Error(
"Signer does not already have permissions. You can grant permissions using `grantPermissions`.",
);
}
return await this.sendSignerPermissionRequest(
resolvedSignerAddress,
resolvedPermissions,
);
},
);
public async updatePermissions(
signerAddress: AddressOrEns,
permissions: SignerPermissionsInput,
) {
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).updatePermissions(signerAddress, permissions);
}
/**
* Revoke a scoped access address to the account
@@ -462,32 +255,14 @@ export class Account<TContract extends IAccountCore>
* const receipt = tx.receipt();
* ```
*
* @twfeature Account
* @twfeature AccountPermissions
*/
revokeAccess = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot revoke permissions of an admin.",
);
}
if (!(await this.isSigner(resolvedSignerAddress))) {
throw new Error(
"Signer does not already have permissions. You can grant permissions using `grantPermissions`.",
);
}
return await this.sendSignerPermissionRequest(resolvedSignerAddress, {
startDate: BigNumber.from(0),
expirationDate: BigNumber.from(0),
approvedCallTargets: [],
nativeTokenLimitPerTransaction: "0",
});
},
);
public async revokeAccess(signerAddress: AddressOrEns) {
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).revokeAccess(signerAddress);
}
/**
* Approve an address as a call target for a given signer on the account
@@ -503,48 +278,17 @@ export class Account<TContract extends IAccountCore>
* const receipt = tx.receipt();
* ```
*
* @twfeature Account
* @twfeature AccountPermissions
*/
approveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
async (
signerAddress: AddressOrEns,
target: AddressOrEns,
): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
const resolvedTarget = await resolveAddress(target);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot approve targets for an admin.",
);
}
if (!(await this.isSigner(resolvedSignerAddress))) {
throw new Error(
"Signer does not already have permissions. You can grant permissions using `grantPermissions`.",
);
}
const permissions: IAccountPermissions.SignerPermissionsStruct =
await this.contractWrapper.readContract.getPermissionsForSigner(
resolvedSignerAddress,
);
if (permissions.approvedTargets.includes(target)) {
throw new Error("Target is already approved");
}
const newTargets = [...permissions.approvedTargets, resolvedTarget];
return await this.sendSignerPermissionRequest(resolvedSignerAddress, {
startDate: BigNumber.from(permissions.startTimestamp),
expirationDate: BigNumber.from(permissions.endTimestamp),
approvedCallTargets: newTargets,
nativeTokenLimitPerTransaction:
permissions.nativeTokenLimitPerTransaction.toString(),
});
},
);
public async approveTargetForSigner(
signerAddress: AddressOrEns,
target: AddressOrEns,
) {
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).approveTargetForSigner(signerAddress, target);
}
/**
* Disapprove an address as a call target for a given signer on the account
@@ -560,51 +304,17 @@ export class Account<TContract extends IAccountCore>
* const receipt = tx.receipt();
* ```
*
* @twfeature Account
* @twfeature AccountPermissions
*/
disapproveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
async (
signerAddress: AddressOrEns,
target: AddressOrEns,
): Promise<Transaction> => {
const resolvedSignerAddress = await resolveAddress(signerAddress);
const resolvedTarget = await resolveAddress(target);
if (await this.isAdmin(resolvedSignerAddress)) {
throw new Error(
"Signer is already an admin. Cannot approve targets for an admin.",
);
}
if (!(await this.isSigner(resolvedSignerAddress))) {
throw new Error(
"Signer does not already have permissions. You can grant permissions using `grantPermissions`.",
);
}
const permissions: IAccountPermissions.SignerPermissionsStruct =
await this.contractWrapper.readContract.getPermissionsForSigner(
resolvedSignerAddress,
);
if (!permissions.approvedTargets.includes(resolvedTarget)) {
throw new Error("Target is currently not approved");
}
const newTargets = permissions.approvedTargets.filter(
(approvedTarget) =>
utils.getAddress(approvedTarget) !== utils.getAddress(resolvedTarget),
);
return await this.sendSignerPermissionRequest(resolvedSignerAddress, {
startDate: BigNumber.from(permissions.startTimestamp),
expirationDate: BigNumber.from(permissions.endTimestamp),
approvedCallTargets: newTargets,
nativeTokenLimitPerTransaction:
permissions.nativeTokenLimitPerTransaction.toString(),
});
},
);
public async disapproveTargetForSigner(
signerAddress: AddressOrEns,
target: AddressOrEns,
) {
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).disapproveTargetForSigner(signerAddress, target);
}
/**
* Set the account's entire snapshot of permissions.
@@ -619,111 +329,14 @@ export class Account<TContract extends IAccountCore>
* const receipt = tx.receipt();
* ```
*
* @twfeature Account
* @twfeature AccountPermissions
*/
resetAllPermissions = /* @__PURE__ */ buildTransactionFunction(
async (
permissionSnapshot: PermissionSnapshotInput,
): Promise<Transaction> => {
const resolvedSnapshot = await PermissionSnapshotSchema.parseAsync(
permissionSnapshot,
);
/**
* All cases
*
* - Add new admin :check:
* - Remove current admin :check:
* - Add new scoped :check:
* - Remove current scoped :check:
* - Update current scoped :check:
* - Current admin -> new scoped :check:
* - Current scoped -> new admin :check:
**/
// No duplicate signers in input!
if (this.hasDuplicateSigners(resolvedSnapshot)) {
throw new Error("Duplicate signers found in input.");
}
const addAdminData: string[] = [];
const removeAdminData: string[] = [];
const addOrUpdateSignerData: string[] = [];
const removeSignerData: string[] = [];
// Remove all existing admins not included in the passed snapshot.
const allAdmins = await this.getAllAdmins();
const allToMakeAdmin = resolvedSnapshot
.filter((item) => item.makeAdmin)
.map((item) => item.signer);
allAdmins.forEach((admin) => {
if (!allToMakeAdmin.includes(admin)) {
removeAdminData.push(
this.contractWrapper.writeContract.interface.encodeFunctionData(
"setAdmin",
[admin, false],
),
);
}
});
// Remove all existing signers not included in the passed snapshot.
const allSigners = await this.getAllSigners();
const allToMakeSigners = resolvedSnapshot
.filter((item) => {
return !item.makeAdmin;
})
.map((item) => item.signer);
await Promise.all(
allSigners.map(async (item) => {
if (!allToMakeSigners.includes(item.signer)) {
const data = await this.buildSignerPermissionRequest(item.signer, {
startDate: BigNumber.from(0),
expirationDate: BigNumber.from(0),
approvedCallTargets: [],
nativeTokenLimitPerTransaction: "0",
});
removeSignerData.push(data);
}
}),
);
for (const member of resolvedSnapshot) {
// Add new admin
if (member.makeAdmin) {
addAdminData.push(
this.contractWrapper.writeContract.interface.encodeFunctionData(
"setAdmin",
[member.signer, true],
),
);
} else {
// Add new scoped
const data = await this.buildSignerPermissionRequest(
member.signer,
member.permissions,
);
addOrUpdateSignerData.push(data);
}
}
const data: string[] = [];
removeAdminData.forEach((item) => {
data.push(item);
});
removeSignerData.forEach((item) => {
data.push(item);
});
addOrUpdateSignerData.forEach((item) => {
data.push(item);
});
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "multicall",
args: [data],
});
},
);
public async resetAllPermissions(
permissionSnapshot: PermissionSnapshotInput,
) {
return assertEnabled(
this.accountPermissions,
FEATURE_ACCOUNT_PERMISSIONS,
).resetAllPermissions(permissionSnapshot);
}
}
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/unity-js-bridge
## 0.2.68
### Patch Changes
- Updated dependencies [[`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74), [`a5ba9e4f`](https://github.com/thirdweb-dev/js/commit/a5ba9e4fbfee228e5b9ac27cd0157187e3a50117), [`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74)]:
- @thirdweb-dev/wallets@1.1.14
- @thirdweb-dev/sdk@3.10.50
- @thirdweb-dev/auth@3.2.31
## 0.2.67
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/unity-js-bridge",
"version": "0.2.67",
"version": "0.2.68",
"main": "dist/thirdweb-unity-bridge.js",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
"license": "Apache-2.0",
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/wallets
## 1.1.14
### Patch Changes
- [#1484](https://github.com/thirdweb-dev/js/pull/1484) [`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Correct gas estimation for polygon/mumbai
- Updated dependencies [[`a5ba9e4f`](https://github.com/thirdweb-dev/js/commit/a5ba9e4fbfee228e5b9ac27cd0157187e3a50117), [`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74)]:
- @thirdweb-dev/sdk@3.10.50
## 1.1.13
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/wallets",
"version": "1.1.13",
"version": "1.1.14",
"main": "dist/thirdweb-dev-wallets.cjs.js",
"module": "dist/thirdweb-dev-wallets.esm.js",
"types": "dist/thirdweb-dev-wallets.cjs.d.ts",
@@ -18,7 +18,10 @@ import {
CeloAlfajoresTestnet,
CeloBaklavaTestnet,
Celo,
Mumbai,
Polygon,
} from "@thirdweb-dev/chains";
import { getPolygonGasPriorityFee } from "@thirdweb-dev/sdk";
export interface BaseApiParams {
provider: providers.Provider;
@@ -291,6 +294,9 @@ export abstract class BaseAccountAPI {
let { maxFeePerGas, maxPriorityFeePerGas } = info;
if (!maxFeePerGas || !maxPriorityFeePerGas) {
const feeData = await this.provider.getFeeData();
if (!maxPriorityFeePerGas) {
maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? undefined;
}
if (!maxFeePerGas) {
maxFeePerGas = feeData.maxFeePerGas ?? undefined;
const network = await this.provider.getNetwork();
@@ -303,9 +309,22 @@ export abstract class BaseAccountAPI {
) {
maxPriorityFeePerGas = maxFeePerGas;
}
}
if (!maxPriorityFeePerGas) {
maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? undefined;
if (
maxPriorityFeePerGas &&
(chainId === Mumbai.chainId || chainId === Polygon.chainId)
) {
// for polygon/mumbai, override fee data from gas station
const block = await this.provider.getBlock("latest");
const baseBlockFee =
block && block.baseFeePerGas
? block.baseFeePerGas
: utils.parseUnits("1", "gwei");
maxPriorityFeePerGas = await getPolygonGasPriorityFee(chainId);
// See: https://eips.ethereum.org/EIPS/eip-1559 for formula
const baseMaxFeePerGas = baseBlockFee.mul(2);
maxFeePerGas = baseMaxFeePerGas.add(maxPriorityFeePerGas);
}
}
}