@thirdweb-dev/wallets
Version:
<p align="center"> <br /> <a href="https://thirdweb.com"><img src="https://github.com/thirdweb-dev/js/blob/main/legacy_packages/sdk/logo.svg?raw=true" width="200" alt=""/></a> <br /> </p> <h1 align="center">thirdweb Wallet SDK</h1> <p align="center"> <a h
276 lines (261 loc) • 9.28 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var defineProperty = require('../../../../dist/defineProperty-9051a5d3.cjs.dev.js');
var connector = require('../../../../dist/connector-a63dd9e7.cjs.dev.js');
var ethers = require('ethers');
var safeEthersAdapters = require('@safe-global/safe-ethers-adapters');
var safeCoreSdk = require('@safe-global/safe-core-sdk');
var safeEthersLib = require('@safe-global/safe-ethers-lib');
require('eventemitter3');
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
var safeCoreSdk__default = /*#__PURE__*/_interopDefault(safeCoreSdk);
var safeEthersLib__default = /*#__PURE__*/_interopDefault(safeEthersLib);
// excerpt from https://docs.safe.global/api-supported-networks#safe-transaction-service
const CHAIN_ID_TO_GNOSIS_SERVER_URL = {
// mainnet
1: "https://safe-transaction-mainnet.safe.global",
// Sepolia
11155111: "https://safe-transaction-sepolia.safe.global",
// optimism
10: "https://safe-transaction-optimism.safe.global",
// bsc
56: "https://safe-transaction-bsc.safe.global",
// gnosis
100: "https://safe-transaction-gnosis-chain.safe.global",
// polygon
137: "https://safe-transaction-polygon.safe.global",
// avalanche
43114: "https://safe-transaction-avalanche.safe.global",
// arbitrum
42161: "https://safe-transaction-arbitrum.safe.global",
// celo
42220: "https://safe-transaction-celo.safe.global",
// Base mainnet
8453: "https://safe-transaction-base.safe.global",
// aurora
1313161554: "https://safe-transaction-aurora.safe.global",
// Polygon zkEVM
1101: "https://safe-transaction-zkevm.safe.global",
// ZkSync Mainnet
324: "https://safe-transaction-zksync.safe.global"
};
const CHAIN_ID_TO_SIGN_MESSAGE_LIB_ADDRESS = {
// mainnet
1: "0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2",
// polygon
137: "0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2",
// bsc
56: "0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2",
// arbitrum
42161: "0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2",
// aurora
1313161554: "0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2",
// avalanche
43114: "0x98FFBBF51bb33A056B08ddf711f289936AafF717",
// optimism
10: "0x98FFBBF51bb33A056B08ddf711f289936AafF717",
// celo
42220: "0x98FFBBF51bb33A056B08ddf711f289936AafF717",
// gnosis chain - https://docs.safe.global/smart-account-supported-networks/v1.3.0#gnosis
100: "0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2",
// Sepolia - https://docs.safe.global/smart-account-supported-networks/v1.3.0#sepolia
11155111: "0x98FFBBF51bb33A056B08ddf711f289936AafF717",
// base mainnet - https://docs.safe.global/smart-account-supported-networks/v1.3.0#base
8453: "0x98FFBBF51bb33A056B08ddf711f289936AafF717",
// Polygon zkEVM - https://docs.safe.global/smart-account-supported-networks/v1.3.0#polygon-zkevm
1101: "0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2",
// ZkSync Mainnet - https://docs.safe.global/smart-account-supported-networks/v1.3.0#zksync-mainnet
324: "0x357147caf9C0cCa67DfA0CF5369318d8193c8407"
};
const SIGN_MESSAGE_LIB_ABI = [{
anonymous: false,
inputs: [{
indexed: true,
internalType: "bytes32",
name: "msgHash",
type: "bytes32"
}],
name: "SignMsg",
type: "event"
}, {
inputs: [{
internalType: "bytes",
name: "message",
type: "bytes"
}],
name: "getMessageHash",
outputs: [{
internalType: "bytes32",
name: "",
type: "bytes32"
}],
stateMutability: "view",
type: "function"
}, {
inputs: [{
internalType: "bytes",
name: "_data",
type: "bytes"
}],
name: "signMessage",
outputs: [],
stateMutability: "nonpayable",
type: "function"
}];
const __IS_SERVER__ = typeof window === "undefined";
class SafeConnector extends connector.Connector {
// config
// private options: SafeOptions;
constructor() {
super();
defineProperty._defineProperty(this, "supportedChains", SafeConnector.supportedChains);
defineProperty._defineProperty(this, "id", "safe-wallet");
defineProperty._defineProperty(this, "ready", !__IS_SERVER__);
defineProperty._defineProperty(this, "name", "Safe Wallet");
if (!__IS_SERVER__) {
this.ready = true;
}
}
async connect(args) {
if (!(args.chain.chainId in CHAIN_ID_TO_GNOSIS_SERVER_URL)) {
throw new Error("Chain not supported by Safe");
}
this.safeSigner = await this.createSafeSigner(args);
return await this.getAddress();
}
async createSafeSigner(params) {
this.personalWallet = params.personalWallet;
const signer = await params.personalWallet.getSigner();
const safeAddress = params.safeAddress;
const safeChainId = params.chain.chainId;
if (!signer) {
throw new Error("cannot create Gnosis Safe signer without a personal signer");
}
const signerChainId = await signer.getChainId();
if (signerChainId !== safeChainId) {
throw new Error("chainId of personal signer has to match safe chainId");
}
if (!safeAddress) {
throw new Error("safeAddress is required");
}
if (!safeChainId) {
throw new Error("safeChainId is required");
}
const serverUrl = CHAIN_ID_TO_GNOSIS_SERVER_URL[safeChainId];
const signMessageLibAddress = CHAIN_ID_TO_SIGN_MESSAGE_LIB_ADDRESS[safeChainId];
if (!serverUrl || !signMessageLibAddress) {
throw new Error("Chain not supported");
}
const ethAdapter = new safeEthersLib__default["default"]({
ethers: ethers.ethers,
signerOrProvider: signer
});
const safe = await safeCoreSdk__default["default"].create({
ethAdapter: ethAdapter,
safeAddress
});
const service = new safeEthersAdapters.SafeService(serverUrl);
const safeSigner = new safeEthersAdapters.SafeEthersSigner(safe, service, signer.provider);
safeSigner.signMessage = async message => {
// Encode the request to the signMessage function of the SafeMessageLib
const contract = new ethers.ethers.BaseContract(signMessageLibAddress, SIGN_MESSAGE_LIB_ABI);
const data = contract.interface.encodeFunctionData("signMessage", [ethers.ethers.utils.hashMessage(message)]);
const to = signMessageLibAddress;
const value = "0";
const operation = 1; // 1 indicates a delegatecall
const safeTxGas = 50000;
const baseGas = 50000;
const gasPrice = 0;
const gasToken = ethers.ethers.constants.AddressZero;
const refundReceiver = ethers.ethers.constants.AddressZero;
// Create the safe transaction to approve the signature
const safeTx = await safe.createTransaction({
safeTransactionData: {
to,
value,
operation,
data,
baseGas,
safeTxGas,
gasPrice,
gasToken,
refundReceiver
}
});
// Sign and propose the safe transaction
const safeTxHash = await safe.getTransactionHash(safeTx);
const safeSignature = await safe.signTransactionHash(safeTxHash);
await service.proposeTx(safe.getAddress(), safeTxHash, safeTx, safeSignature);
// Poll while we wait for the safe transaction to reach minimum confirmations
while (true) {
try {
const txDetails = await service.getSafeTxDetails(safeTxHash);
if (txDetails.transactionHash) {
await signer.provider?.waitForTransaction(txDetails.transactionHash);
break;
}
} catch (e) {}
await new Promise(resolve => setTimeout(resolve, 5000));
}
// For on-chain signatures, safe expects just "0x" as the signature
return "0x";
};
// set the personal signer as "previous connector" so that we can re-connect to it later when disconnecting
this.previousConnector = params.personalWallet;
return safeSigner;
}
async disconnect() {
this.safeSigner = undefined;
this.previousConnector = undefined;
return undefined;
}
async getAddress() {
const signer = await this.getSigner();
return await signer.getAddress();
}
async getChainId() {
return (await this.getSigner()).getChainId();
}
async getProvider() {
const provider = (await this.getSigner()).provider;
if (!provider) {
throw new Error("No provider available");
}
return provider;
}
async getSigner() {
if (!this.safeSigner) {
throw new Error("not connected - please call connect() first");
}
return this.safeSigner;
}
async isConnected() {
try {
const account = await this.getAddress();
return !!account;
} catch (e) {
return false;
}
}
onAccountsChanged(accounts) {
if (accounts.length === 0) {
this.emit("disconnect");
} else {
if (accounts[0]) {
this.emit("change", {
account: ethers.ethers.utils.getAddress(accounts[0])
});
}
}
}
onDisconnect() {
this.emit("disconnect");
}
switchChain() {
throw new Error("Safe connector does not support switching chains");
}
updateChains() {}
async setupListeners() {}
}
defineProperty._defineProperty(SafeConnector, "supportedChains", /* @__PURE__ */(() => Object.keys(CHAIN_ID_TO_GNOSIS_SERVER_URL))());
exports.SafeConnector = SafeConnector;