Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66b9bf3c6b | ||
|
|
cf22c23b45 |
@@ -1,5 +1,12 @@
|
||||
# @thirdweb-dev/nebula
|
||||
|
||||
## 0.2.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`cf22c23`](https://github.com/thirdweb-dev/js/commit/cf22c23b45e86adbe50a2b7b40e7a283f5222941)]:
|
||||
- thirdweb@5.105.20
|
||||
|
||||
## 0.2.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -57,5 +57,5 @@
|
||||
"type": "module",
|
||||
"types": "./dist/types/exports/thirdweb.d.ts",
|
||||
"typings": "./dist/types/exports/thirdweb.d.ts",
|
||||
"version": "0.2.19"
|
||||
"version": "0.2.20"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# thirdweb
|
||||
|
||||
## 5.105.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#7693](https://github.com/thirdweb-dev/js/pull/7693) [`cf22c23`](https://github.com/thirdweb-dev/js/commit/cf22c23b45e86adbe50a2b7b40e7a283f5222941) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Optimize 4337 signature performance
|
||||
|
||||
## 5.105.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -404,5 +404,5 @@
|
||||
}
|
||||
},
|
||||
"typings": "./dist/types/exports/thirdweb.d.ts",
|
||||
"version": "5.105.19"
|
||||
"version": "5.105.20"
|
||||
}
|
||||
|
||||
@@ -300,14 +300,14 @@ export async function getBuyWithCryptoQuote(
|
||||
Number(
|
||||
Value.format(quote.originAmount, firstStep.originToken.decimals),
|
||||
) *
|
||||
(firstStep.originToken.prices["USD"] || 0) *
|
||||
(firstStep.originToken.prices.USD || 0) *
|
||||
100,
|
||||
amountWei: quote.originAmount.toString(),
|
||||
token: {
|
||||
chainId: firstStep.originToken.chainId,
|
||||
decimals: firstStep.originToken.decimals,
|
||||
name: firstStep.originToken.name,
|
||||
priceUSDCents: (firstStep.originToken.prices["USD"] || 0) * 100,
|
||||
priceUSDCents: (firstStep.originToken.prices.USD || 0) * 100,
|
||||
symbol: firstStep.originToken.symbol,
|
||||
tokenAddress: firstStep.originToken.address,
|
||||
},
|
||||
@@ -323,7 +323,7 @@ export async function getBuyWithCryptoQuote(
|
||||
chainId: firstStep.originToken.chainId,
|
||||
decimals: firstStep.originToken.decimals,
|
||||
name: firstStep.originToken.name,
|
||||
priceUSDCents: (firstStep.originToken.prices["USD"] || 0) * 100,
|
||||
priceUSDCents: (firstStep.originToken.prices.USD || 0) * 100,
|
||||
symbol: firstStep.originToken.symbol,
|
||||
tokenAddress: firstStep.originToken.address,
|
||||
},
|
||||
@@ -337,7 +337,7 @@ export async function getBuyWithCryptoQuote(
|
||||
Number(
|
||||
Value.format(quote.originAmount, firstStep.originToken.decimals),
|
||||
) *
|
||||
(firstStep.originToken.prices["USD"] || 0) *
|
||||
(firstStep.originToken.prices.USD || 0) *
|
||||
100,
|
||||
gasCostUSDCents: 0,
|
||||
slippageBPS: 0,
|
||||
@@ -348,7 +348,7 @@ export async function getBuyWithCryptoQuote(
|
||||
firstStep.destinationToken.decimals,
|
||||
),
|
||||
) *
|
||||
(firstStep.destinationToken.prices["USD"] || 0) *
|
||||
(firstStep.destinationToken.prices.USD || 0) *
|
||||
100,
|
||||
toAmountUSDCents:
|
||||
Number(
|
||||
@@ -357,7 +357,7 @@ export async function getBuyWithCryptoQuote(
|
||||
firstStep.destinationToken.decimals,
|
||||
),
|
||||
) *
|
||||
(firstStep.destinationToken.prices["USD"] || 0) *
|
||||
(firstStep.destinationToken.prices.USD || 0) *
|
||||
100,
|
||||
},
|
||||
fromAddress: quote.intent.sender,
|
||||
@@ -372,7 +372,7 @@ export async function getBuyWithCryptoQuote(
|
||||
chainId: firstStep.originToken.chainId,
|
||||
decimals: firstStep.originToken.decimals,
|
||||
name: firstStep.originToken.name,
|
||||
priceUSDCents: (firstStep.originToken.prices["USD"] || 0) * 100,
|
||||
priceUSDCents: (firstStep.originToken.prices.USD || 0) * 100,
|
||||
symbol: firstStep.originToken.symbol,
|
||||
tokenAddress: firstStep.originToken.address,
|
||||
},
|
||||
@@ -395,7 +395,7 @@ export async function getBuyWithCryptoQuote(
|
||||
chainId: firstStep.destinationToken.chainId,
|
||||
decimals: firstStep.destinationToken.decimals,
|
||||
name: firstStep.destinationToken.name,
|
||||
priceUSDCents: (firstStep.destinationToken.prices["USD"] || 0) * 100,
|
||||
priceUSDCents: (firstStep.destinationToken.prices.USD || 0) * 100,
|
||||
symbol: firstStep.destinationToken.symbol,
|
||||
tokenAddress: firstStep.destinationToken.address,
|
||||
},
|
||||
|
||||
@@ -198,14 +198,14 @@ export async function getBuyWithCryptoTransfer(
|
||||
Number(
|
||||
Value.format(quote.originAmount, firstStep.originToken.decimals),
|
||||
) *
|
||||
(firstStep.originToken.prices["USD"] || 0) *
|
||||
(firstStep.originToken.prices.USD || 0) *
|
||||
100,
|
||||
amountWei: quote.originAmount.toString(),
|
||||
token: {
|
||||
chainId: firstStep.originToken.chainId,
|
||||
decimals: firstStep.originToken.decimals,
|
||||
name: firstStep.originToken.name,
|
||||
priceUSDCents: (firstStep.originToken.prices["USD"] || 0) * 100,
|
||||
priceUSDCents: (firstStep.originToken.prices.USD || 0) * 100,
|
||||
symbol: firstStep.originToken.symbol,
|
||||
tokenAddress: firstStep.originToken.address,
|
||||
},
|
||||
@@ -226,7 +226,7 @@ export async function getBuyWithCryptoTransfer(
|
||||
firstStep.originToken.decimals,
|
||||
),
|
||||
) *
|
||||
(firstStep.originToken.prices["USD"] || 0) *
|
||||
(firstStep.originToken.prices.USD || 0) *
|
||||
100
|
||||
: 0,
|
||||
amountWei:
|
||||
@@ -237,7 +237,7 @@ export async function getBuyWithCryptoTransfer(
|
||||
chainId: firstStep.originToken.chainId,
|
||||
decimals: firstStep.originToken.decimals,
|
||||
name: firstStep.originToken.name,
|
||||
priceUSDCents: (firstStep.originToken.prices["USD"] || 0) * 100,
|
||||
priceUSDCents: (firstStep.originToken.prices.USD || 0) * 100,
|
||||
symbol: firstStep.originToken.symbol,
|
||||
tokenAddress: firstStep.originToken.address,
|
||||
},
|
||||
|
||||
@@ -372,7 +372,7 @@ export async function getBuyWithFiatQuote(
|
||||
chainId: token.chainId,
|
||||
decimals: token.decimals,
|
||||
name: token.name,
|
||||
priceUSDCents: Math.round((token.prices["USD"] || 0) * 100),
|
||||
priceUSDCents: Math.round((token.prices.USD || 0) * 100),
|
||||
symbol: token.symbol,
|
||||
tokenAddress: token.address,
|
||||
});
|
||||
@@ -408,7 +408,7 @@ export async function getBuyWithFiatQuote(
|
||||
const onRampTokenObject = {
|
||||
amount: onRampTokenAmount,
|
||||
amountUSDCents: Math.round(
|
||||
Number(onRampTokenAmount) * (onRampTokenRaw.prices["USD"] || 0) * 100,
|
||||
Number(onRampTokenAmount) * (onRampTokenRaw.prices.USD || 0) * 100,
|
||||
),
|
||||
amountWei: onRampTokenAmountWei.toString(),
|
||||
token: tokenToPayTokenInfo(onRampTokenRaw),
|
||||
@@ -434,7 +434,7 @@ export async function getBuyWithFiatQuote(
|
||||
routingTokenObject = {
|
||||
amount: routingAmount,
|
||||
amountUSDCents: Math.round(
|
||||
Number(routingAmount) * (routingTokenRaw.prices["USD"] || 0) * 100,
|
||||
Number(routingAmount) * (routingTokenRaw.prices.USD || 0) * 100,
|
||||
),
|
||||
amountWei: routingAmountWei.toString(),
|
||||
token: tokenToPayTokenInfo(routingTokenRaw),
|
||||
|
||||
@@ -240,10 +240,10 @@ export function usePaymentMethods(options: {
|
||||
validOwnedTokens.sort((a, b) => {
|
||||
const aDollarBalance =
|
||||
Number.parseFloat(toTokens(a.balance, a.originToken.decimals)) *
|
||||
(a.originToken.prices["USD"] || 0);
|
||||
(a.originToken.prices.USD || 0);
|
||||
const bDollarBalance =
|
||||
Number.parseFloat(toTokens(b.balance, b.originToken.decimals)) *
|
||||
(b.originToken.prices["USD"] || 0);
|
||||
(b.originToken.prices.USD || 0);
|
||||
return bDollarBalance - aDollarBalance;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
import type * as ox__TypedData from "ox/TypedData";
|
||||
import { serializeErc6492Signature } from "../../../auth/serialize-erc6492-signature.js";
|
||||
import {
|
||||
verifyEip1271Signature,
|
||||
verifyHash,
|
||||
} from "../../../auth/verify-hash.js";
|
||||
import { verifyEip1271Signature } from "../../../auth/verify-hash.js";
|
||||
import type { Chain } from "../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../client/client.js";
|
||||
import {
|
||||
getContract,
|
||||
type ThirdwebContract,
|
||||
} from "../../../contract/contract.js";
|
||||
import type { ThirdwebContract } from "../../../contract/contract.js";
|
||||
import { encode } from "../../../transaction/actions/encode.js";
|
||||
import { readContract } from "../../../transaction/read-contract.js";
|
||||
import { encodeAbiParameters } from "../../../utils/abi/encodeAbiParameters.js";
|
||||
import { isContractDeployed } from "../../../utils/bytecode/is-contract-deployed.js";
|
||||
import type { Hex } from "../../../utils/encoding/hex.js";
|
||||
import { hashMessage } from "../../../utils/hashing/hashMessage.js";
|
||||
import { hashTypedData } from "../../../utils/hashing/hashTypedData.js";
|
||||
import type { SignableMessage } from "../../../utils/types.js";
|
||||
@@ -40,33 +32,24 @@ export async function smartAccountSignMessage({
|
||||
message: SignableMessage;
|
||||
}) {
|
||||
const originalMsgHash = hashMessage(message);
|
||||
const is712Factory = await checkFor712Factory({
|
||||
accountContract,
|
||||
factoryContract,
|
||||
originalMsgHash,
|
||||
});
|
||||
|
||||
let sig: `0x${string}`;
|
||||
if (is712Factory) {
|
||||
const wrappedMessageHash = encodeAbiParameters(
|
||||
[{ type: "bytes32" }],
|
||||
[originalMsgHash],
|
||||
);
|
||||
const wrappedMessageHash = encodeAbiParameters(
|
||||
[{ type: "bytes32" }],
|
||||
[originalMsgHash],
|
||||
);
|
||||
|
||||
sig = await options.personalAccount.signTypedData({
|
||||
domain: {
|
||||
chainId: options.chain.id,
|
||||
name: "Account",
|
||||
verifyingContract: accountContract.address,
|
||||
version: "1",
|
||||
},
|
||||
message: { message: wrappedMessageHash },
|
||||
primaryType: "AccountMessage",
|
||||
types: { AccountMessage: [{ name: "message", type: "bytes" }] },
|
||||
});
|
||||
} else {
|
||||
sig = await options.personalAccount.signMessage({ message });
|
||||
}
|
||||
sig = await options.personalAccount.signTypedData({
|
||||
domain: {
|
||||
chainId: options.chain.id,
|
||||
name: "Account",
|
||||
verifyingContract: accountContract.address,
|
||||
version: "1",
|
||||
},
|
||||
message: { message: wrappedMessageHash },
|
||||
primaryType: "AccountMessage",
|
||||
types: { AccountMessage: [{ name: "message", type: "bytes" }] },
|
||||
});
|
||||
|
||||
const isDeployed = await isContractDeployed(accountContract);
|
||||
if (isDeployed) {
|
||||
@@ -96,19 +79,7 @@ export async function smartAccountSignMessage({
|
||||
signature: sig,
|
||||
});
|
||||
|
||||
// check if the signature is valid
|
||||
const isValid = await verifyHash({
|
||||
address: accountContract.address,
|
||||
chain: accountContract.chain,
|
||||
client: accountContract.client,
|
||||
hash: originalMsgHash,
|
||||
signature: erc6492Sig,
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
return erc6492Sig;
|
||||
}
|
||||
throw new Error("Unable to verify ERC-6492 signature after signing.");
|
||||
return erc6492Sig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,33 +109,23 @@ export async function smartAccountSignTypedData<
|
||||
}
|
||||
|
||||
const originalMsgHash = hashTypedData(typedData);
|
||||
// check if the account contract supports EIP721 domain separator based signing
|
||||
const is712Factory = await checkFor712Factory({
|
||||
accountContract,
|
||||
factoryContract,
|
||||
originalMsgHash,
|
||||
});
|
||||
|
||||
let sig: `0x${string}`;
|
||||
if (is712Factory) {
|
||||
const wrappedMessageHash = encodeAbiParameters(
|
||||
[{ type: "bytes32" }],
|
||||
[originalMsgHash],
|
||||
);
|
||||
sig = await options.personalAccount.signTypedData({
|
||||
domain: {
|
||||
chainId: options.chain.id,
|
||||
name: "Account",
|
||||
verifyingContract: accountContract.address,
|
||||
version: "1",
|
||||
},
|
||||
message: { message: wrappedMessageHash },
|
||||
primaryType: "AccountMessage",
|
||||
types: { AccountMessage: [{ name: "message", type: "bytes" }] },
|
||||
});
|
||||
} else {
|
||||
sig = await options.personalAccount.signTypedData(typedData);
|
||||
}
|
||||
const wrappedMessageHash = encodeAbiParameters(
|
||||
[{ type: "bytes32" }],
|
||||
[originalMsgHash],
|
||||
);
|
||||
sig = await options.personalAccount.signTypedData({
|
||||
domain: {
|
||||
chainId: options.chain.id,
|
||||
name: "Account",
|
||||
verifyingContract: accountContract.address,
|
||||
version: "1",
|
||||
},
|
||||
message: { message: wrappedMessageHash },
|
||||
primaryType: "AccountMessage",
|
||||
types: { AccountMessage: [{ name: "message", type: "bytes" }] },
|
||||
});
|
||||
|
||||
const isDeployed = await isContractDeployed(accountContract);
|
||||
if (isDeployed) {
|
||||
@@ -194,21 +155,7 @@ export async function smartAccountSignTypedData<
|
||||
signature: sig,
|
||||
});
|
||||
|
||||
// check if the signature is valid
|
||||
const isValid = await verifyHash({
|
||||
address: accountContract.address,
|
||||
chain: accountContract.chain,
|
||||
client: accountContract.client,
|
||||
hash: originalMsgHash,
|
||||
signature: erc6492Sig,
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
return erc6492Sig;
|
||||
}
|
||||
throw new Error(
|
||||
"Unable to verify signature on smart account, please make sure the admin wallet has permissions and the signature is valid.",
|
||||
);
|
||||
return erc6492Sig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,40 +180,6 @@ export async function confirmContractDeployment(args: {
|
||||
}
|
||||
}
|
||||
|
||||
async function checkFor712Factory({
|
||||
factoryContract,
|
||||
accountContract,
|
||||
originalMsgHash,
|
||||
}: {
|
||||
factoryContract: ThirdwebContract;
|
||||
accountContract: ThirdwebContract;
|
||||
originalMsgHash: Hex;
|
||||
}) {
|
||||
try {
|
||||
const implementationAccount = await readContract({
|
||||
contract: factoryContract,
|
||||
method: "function accountImplementation() public view returns (address)",
|
||||
});
|
||||
// check if the account contract supports EIP721 domain separator or modular based signing
|
||||
const is712Factory = await readContract({
|
||||
contract: getContract({
|
||||
address: implementationAccount,
|
||||
chain: accountContract.chain,
|
||||
client: accountContract.client,
|
||||
}),
|
||||
method:
|
||||
"function getMessageHash(bytes32 _hash) public view returns (bytes32)",
|
||||
params: [originalMsgHash],
|
||||
})
|
||||
.then((res) => res !== "0x")
|
||||
.catch(() => false);
|
||||
|
||||
return is712Factory;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deployes a smart account via a dummy transaction. If the account is already deployed, this will do nothing.
|
||||
*
|
||||
|
||||
@@ -47,7 +47,6 @@ const contract = getContract({
|
||||
chain,
|
||||
client,
|
||||
});
|
||||
const factoryAddress = "0x564cf6453a1b0FF8DB603E92EA4BbD410dea45F3"; // pre 712
|
||||
|
||||
describe.runIf(process.env.TW_SECRET_KEY).sequential(
|
||||
"SmartWallet core tests",
|
||||
@@ -301,79 +300,6 @@ describe.runIf(process.env.TW_SECRET_KEY).sequential(
|
||||
expect(logs.some((l) => l.args.isAdmin)).toBe(true);
|
||||
});
|
||||
|
||||
it("can use a different factory without replay protection", async () => {
|
||||
const wallet = smartWallet({
|
||||
chain,
|
||||
factoryAddress: factoryAddress,
|
||||
gasless: true,
|
||||
});
|
||||
|
||||
// should not be able to switch chains before connecting
|
||||
await expect(
|
||||
wallet.switchChain(baseSepolia),
|
||||
).rejects.toMatchInlineSnapshot(
|
||||
"[Error: Cannot switch chain without a previous connection]",
|
||||
);
|
||||
|
||||
const newAccount = await wallet.connect({ client, personalAccount });
|
||||
const message = "hello world";
|
||||
const signature = await newAccount.signMessage({ message });
|
||||
const isValidV1 = await verifySignature({
|
||||
address: newAccount.address,
|
||||
chain,
|
||||
client,
|
||||
message,
|
||||
signature,
|
||||
});
|
||||
expect(isValidV1).toEqual(true);
|
||||
|
||||
// sign typed data
|
||||
const signatureTyped = await newAccount.signTypedData({
|
||||
...typedData.basic,
|
||||
primaryType: "Mail",
|
||||
});
|
||||
const isValidV2 = await verifyTypedData({
|
||||
address: newAccount.address,
|
||||
chain,
|
||||
client,
|
||||
signature: signatureTyped,
|
||||
...typedData.basic,
|
||||
});
|
||||
expect(isValidV2).toEqual(true);
|
||||
|
||||
// add admin pre-deployment
|
||||
const newAdmin = await generateAccount({ client });
|
||||
const receipt = await sendAndConfirmTransaction({
|
||||
account: newAccount,
|
||||
transaction: addAdmin({
|
||||
account: newAccount,
|
||||
adminAddress: newAdmin.address,
|
||||
contract: getContract({
|
||||
address: newAccount.address,
|
||||
chain,
|
||||
client,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
const logs = parseEventLogs({
|
||||
events: [adminUpdatedEvent()],
|
||||
logs: receipt.logs,
|
||||
});
|
||||
expect(logs.map((l) => l.args.signer)).toContain(newAdmin.address);
|
||||
expect(logs.map((l) => l.args.isAdmin)).toContain(true);
|
||||
|
||||
// should not be able to switch chains since factory not deployed elsewhere
|
||||
await expect(
|
||||
wallet.switchChain(baseSepolia),
|
||||
).rejects.toMatchInlineSnapshot(
|
||||
"[Error: Factory contract not deployed on chain: 84532]",
|
||||
);
|
||||
|
||||
// check can disconnnect
|
||||
await wallet.disconnect();
|
||||
expect(wallet.getAccount()).toBeUndefined();
|
||||
});
|
||||
|
||||
it("can switch chains", async () => {
|
||||
await wallet.switchChain(baseSepolia);
|
||||
expect(wallet.getChain()?.id).toEqual(baseSepolia.id);
|
||||
@@ -424,7 +350,7 @@ describe.runIf(process.env.TW_SECRET_KEY).sequential(
|
||||
tokenId: 0n,
|
||||
}),
|
||||
}),
|
||||
sleep(1000).then(() =>
|
||||
sleep(1500).then(() =>
|
||||
sendAndConfirmTransaction({
|
||||
account: newSmartAccount,
|
||||
transaction: claimTo({
|
||||
@@ -453,7 +379,6 @@ describe.runIf(process.env.TW_SECRET_KEY).sequential(
|
||||
it("can use a different paymaster", async () => {
|
||||
const wallet = smartWallet({
|
||||
chain,
|
||||
factoryAddress: factoryAddress,
|
||||
gasless: true,
|
||||
overrides: {
|
||||
paymaster: async () => {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# @thirdweb-dev/wagmi-adapter
|
||||
|
||||
## 0.2.117
|
||||
|
||||
## 0.2.116
|
||||
|
||||
## 0.2.115
|
||||
|
||||
@@ -55,5 +55,5 @@
|
||||
"type": "module",
|
||||
"types": "./dist/types/exports/thirdweb.d.ts",
|
||||
"typings": "./dist/types/exports/thirdweb.d.ts",
|
||||
"version": "0.2.116"
|
||||
"version": "0.2.117"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user